From 823fd1f4c8f40e58fe46772daef4821642759259 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 15 Feb 2023 00:42:50 +0800 Subject: [PATCH 001/498] WIPIP rebase changes from older root Original: a3325710f2597e8dea6e9d93edf6fc731ca85e47 --- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 3 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 134 ++++++++++++++++-- shared/src/main/scala/mlscript/Typer.scala | 17 ++- .../main/scala/mlscript/TyperDatatypes.scala | 86 ++++++++++- shared/src/main/scala/mlscript/helpers.scala | 6 +- shared/src/main/scala/mlscript/syntax.scala | 7 +- shared/src/test/diff/nu/MutualRec.mls | 45 ++++++ .../src/test/scala/mlscript/DiffTests.scala | 75 +++++++--- 9 files changed, 339 insertions(+), 35 deletions(-) create mode 100644 shared/src/test/diff/nu/MutualRec.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index f31370fc7d..016c2084ba 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -249,6 +249,7 @@ object NewLexer { "mut", "class", "trait", + "mixin", "interface", "new", "namespace", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 881be57181..fa6879f66a 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -244,11 +244,12 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (SPACE, _) :: _ => consume; block case c => val t = c match { - case (KEYWORD(k @ ("class" | "trait" | "type" | "namespace")), l0) :: c => + case (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace")), l0) :: c => consume val kind = k match { case "class" => Cls case "trait" => Trt + case "mixin" => Mxn case "type" => Als case "namespace" => Nms case _ => die diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8e72534c27..dc74b36558 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -12,26 +12,134 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => import TypeProvenance.{apply => tp} + sealed abstract class NuDeclInfo + + case class FunInfo() extends NuDeclInfo + case class TypeDefInfo() extends NuDeclInfo + + // * For now these are just unused stubs to be completed and used later - case class TypedNuTypeDef( - kind: TypeDefKind, - nme: TypeName, - tparamsargs: List[(TypeName, TypeVariable)], - bodyTy: SimpleType, - baseClasses: Set[TypeName], - toLoc: Opt[Loc], - ) + sealed abstract class TypedNuDecl { + def name: Str + } + + sealed trait TypedNuTermDef extends TypedNuDecl { + override def toString: String = this match { + case _ => ??? + } + } + + sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { + def nme: TypeName + } + // case class TypedNuTypeDef( + // kind: TypeDefKind, + // nme: TypeName, + // tparamsargs: List[(TypeName, TypeVariable)], + // bodyTy: SimpleType, + // baseClasses: Set[TypeName], + // toLoc: Opt[Loc], + // ) + + case class TypedNuAls(nme: TypeName) extends TypedNuTypeDef(Als) { + def name: Str = nme.name + } + + // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { + case class TypedNuCls(td: NuTypeDef, ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { + // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { + def nme: TypeName = td.nme + def name: Str = nme.name + } + + case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { + def nme: TypeName = td.nme + def name: Str = nme.name + } - def typeTypingUnit(tu: TypingUnit)(implicit ctx: Ctx, raise: Raise): SimpleType = { - // tu.entities - ??? + case class TypedNuFun(fd: NuFunDef, ty: PolymorphicType) extends TypedNuDecl with TypedNuTermDef { + def name: Str = fd.nme.name } - class TypedTypingUnit(tu: TypingUnit)(implicit ctx: Ctx, raise: Raise) { - + case class TypedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) + + def typeTypingUnit(tu: TypingUnit, allowPure: Bool)(implicit ctx: Ctx, raise: Raise): TypedTypingUnit = { + // val named = mutable.Map.empty[Str, LazyTypeInfo[TypedNuTermDef]] + val named = mutable.Map.empty[Str, LazyTypeInfo] + // val namedTerms = mutable.Map.empty[Var, LazyTypeInfo[TypedNuTypeDef]] + // val namedTypes = mutable.Map.empty[TypeName, LazyTypeInfo[TypedNuTypeDef]] + // val namedTerms = mutable.Map.empty[Str, LazyTypeInfo[ST]] + // val namedTypes = mutable.Map.empty[Str, LazyTypeInfo[TypedNuTypeDef]] + // val infos = tu.entities.collect { + // case fd: NuFunDef => fd.nme.name -> new LazyTypeInfo(lvl, fd) + // case td: NuTypeDef => td.nme.name -> new LazyTypeInfo(lvl, td) + // } + val infos = tu.entities.collect { + case decl: NuDecl => + val lti = new LazyTypeInfo(lvl, decl) + // def registerTerm = + named.updateWith(decl.name) { + case sv @ S(v) => + ??? + case N => + S(lti) + } + decl.name -> lti + // decl match { + // case fd: NuFunDef => + // registerTerm + // fd.nme.name -> lti + // case td: NuTypeDef => + // registerTerm + // td.nme.name -> new LazyTypeInfo(lvl, td) + // } + } + ctx ++= infos + def go(stmts: Ls[Statement])(implicit ctx: Ctx): Opt[ST] = stmts match { + case s :: stmts => + val res_ty = s match { + // case NuFunDef(isLetRec, nme, targs, rhs) => + // case fd: NuFunDef => + // ??? + // case td: NuTypeDef => + // ??? + case decl: NuDecl => + val lti = named.getOrElse(decl.name, die) + // completeTypeInfo() + lti.complete() + // UnitType + N + // case ds: DesugaredStatement => + // val (poly_ty, bindings) = typeStatement(ds, allowPure) + // poly_ty.instantiate + case s: Statement => + val (diags, dss) = s.desugared + diags.foreach(raise) + // typeStatement(desug, allowPure) + // go(dss ::: stmts) + S(typeTerms(dss, false, Nil)(ctx, raise, TypeProvenance(s.toLoc, s match { + case trm: Term => trm.describe + case s => ??? + }), Map.empty, genLambdas = false)) + } + stmts match { + case Nil => res_ty + case stmts => + // TODO check discarded non-unit values + go(stmts) + } + // case Nil => UnitType + case Nil => N + } + val res_ty = go(tu.entities) + // TypedTypingUnit(infos.unzip._2.map(_.complete()), S(res_ty)) + TypedTypingUnit(infos.unzip._2.map(_.complete()), res_ty) } + // class TypedTypingUnit(tu: TypingUnit)(implicit ctx: Ctx, raise: Raise) { + // } + } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 61063b71c0..683fc89018 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -32,6 +32,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) var irregularTypes: Boolean = false var constrainedTypes: Boolean = false + var newDefs: Bool = false + var recordProvenances: Boolean = true type Raise = Diagnostic => Unit @@ -699,6 +701,13 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) ) ) case VarSymbol(ty, _) => ty + case ti: LazyTypeInfo => + // ti.complete() match { + // case cls: TypedNuCls => + // cls.ctorSignature + // case TypedNuFun(fd, ty) => ??? + // } + ti.typeSignature } mkProxy(ty, prov) // ^ TODO maybe use a description passed in param? @@ -915,7 +924,13 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // case Blk(s :: stmts) => // val (newCtx, ty) = typeStatement(s) // typeTerm(Blk(stmts))(newCtx, lvl, raise) - case Blk(stmts) => typeTerms(stmts, false, Nil)(ctx.nest, raise, prov, vars, genLambdas) + case Blk(stmts) => + if (newDefs) { + val ttu = typeTypingUnit(TypingUnit(stmts), allowPure = false) + // TODO check unused defs + // ttu.res + ttu.result.getOrElse(UnitType) + } else typeTerms(stmts, false, Nil)(ctx.nest, raise, prov, vars, genLambdas) case Bind(l, r) => val l_ty = typeMonomorphicTerm(l) val newCtx = ctx.nest // so the pattern's context don't merge with the outer context! diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index f2478d15d9..f811fad3e8 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -23,13 +23,97 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => type TP = TypeProvenance sealed abstract class TypeInfo - + /** A type for abstract classes that is used to check and throw * errors if the abstract class is being instantiated */ case class AbstractConstructor(absMths: Set[Var], isTraitWithMethods: Bool) extends TypeInfo case class VarSymbol(ty: ST, definingVar: Var) extends TypeInfo + class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx) extends TypeInfo { + // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { + var isComputing: Bool = false + var result: Opt[TypedNuTermDef] = N + // var result: Opt[A] = N + val tv: TV = freshVar( + TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), + N, + S(decl.name))(level) + def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { + if (isComputing) lastWords(s"TODO cyclic defn") + else { + isComputing = true + // var res: ST = errType + try { + // res = + decl match { + case fd: NuFunDef => + assert(fd.isLetRec.isEmpty) + implicit val prov = noProv // TODO + val res_ty = fd.rhs match { + case R(PolyType(tps, ty)) => + // val body_ty = typeType(ty)(ctx.nextLevel, raise, + // vars = tps.map(tp => tp.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) + val body_ty = ctx.nextLevel { implicit ctx: Ctx => + typeType(ty)(ctx, raise, + vars = tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) + } + // TODO check against `tv` + TypedNuFun(fd, PolymorphicType(ctx.lvl, body_ty)) + case L(body) => + implicit val vars: Map[Str, SimpleType] = Map.empty + implicit val gl: GenLambdas = true + val body_ty = typeLetRhs(isrec = true, fd.nme.name, body) + // implicit val prov: TP = noProv // TODO + // subsume(body_ty, PolymorphicType(level, tv)) // TODO + TypedNuFun(fd, body_ty) + } + // subsume(res_ty, tv) + res_ty + case td: NuTypeDef => + td.kind match { + case Cls => + val ttu = typeTypingUnit(td.body, allowPure = false) + // TODO check against `tv` + TypedNuCls(td, ttu) + case Mxn => + implicit val prov = noProv // TODO + ctx.nextLevel { newCtx => + val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) + val superTV = freshVar(noProv/*FIXME*/, N, S("super")) + newCtx += "this" -> VarSymbol(thisTV, Var("this")) + newCtx += "super" -> VarSymbol(superTV, Var("super")) + newCtx |> { implicit ctx => + val ttu = typeTypingUnit(td.body, allowPure = false) + TypedNuMxn(td, thisTV, superTV, ttu) + } + } + case _ => ??? + } + } + + // } finally { result = S(res); isComputing = false } + } finally { /* result = S(res); */ isComputing = false } + } + } + def typeSignature(implicit raise: Raise): ST = if (isComputing) tv else complete() match { + case cls: TypedNuCls => + // ??? + // TODO + errType + case TypedNuFun(fd, ty) => ??? + } + override def toString: String = + s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" + } + + // /** A type that potentially contains universally quantified type variables, + // * and which can be isntantiated to a given level. */ + // sealed abstract class TypeScheme { + // def uninstantiatedBody: SimpleType + // def instantiate(implicit lvl: Int): SimpleType + // } + /** A type with universally quantified type variables * (by convention, those variables of level greater than `level` are considered quantified). */ case class PolymorphicType(polymLevel: Level, body: SimpleType) extends SimpleType { // TODO add own prov? diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 888b997599..b8fccb2487 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -300,6 +300,10 @@ trait DeclImpl extends Located { self: Decl => trait NuDeclImpl extends Located { self: NuDecl => val body: Located + val name: Str = self match { + case td: NuTypeDef => td.nme.name + case fd: NuFunDef => fd.nme.name + } def showBody: Str = this match { case NuFunDef(_, _, _, rhs) => rhs.fold(_.toString, _.show) case td: NuTypeDef => td.body.show @@ -753,10 +757,10 @@ trait StatementImpl extends Located { self: Statement => case d @ NuFunDef(_, v, ts, rhs) => v :: ts ::: d.body :: Nil case TyApp(lhs, targs) => lhs :: targs case New(base, bod) => base.toList.flatMap(ab => ab._1 :: ab._2 :: Nil) ::: bod :: Nil - case NuTypeDef(_, _, _, _, _, _) => ??? case Where(bod, wh) => bod :: wh case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil + case NuTypeDef(k, nme, tps, ps, pars, bod) => nme :: tps ::: ps :: pars ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 6ef71bce9c..b3e1ee67b8 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -43,16 +43,19 @@ final case class MethodDef[RHS <: Term \/ Type]( val children: Ls[Located] = nme :: body :: Nil } +sealed trait NameRef extends Located { val name: Str } + sealed abstract class TypeDefKind(val str: Str) sealed trait ObjDefKind case object Cls extends TypeDefKind("class") with ObjDefKind case object Trt extends TypeDefKind("trait") with ObjDefKind +case object Mxn extends TypeDefKind("mixin") case object Als extends TypeDefKind("type alias") case object Nms extends TypeDefKind("namespace") sealed abstract class Term extends Terms with TermImpl sealed abstract class Lit extends SimpleTerm with LitImpl -final case class Var(name: Str) extends SimpleTerm with VarImpl +final case class Var(name: Str) extends SimpleTerm with VarImpl with NameRef final case class Lam(lhs: Term, rhs: Term) extends Term final case class App(lhs: Term, rhs: Term) extends Term final case class Tup(fields: Ls[Opt[Var] -> Fld]) extends Term @@ -145,7 +148,7 @@ case object Bot extends NullaryType final case class Literal(lit: Lit) extends NullaryType /** Reference to an existing type with the given name. */ -final case class TypeName(name: Str) extends NullaryType with NamedType with TypeNameImpl +final case class TypeName(name: Str) extends NullaryType with NamedType with TypeNameImpl with NameRef final case class TypeTag (name: Str) extends NullaryType final case class TypeVar(val identifier: Int \/ Str, nameHint: Opt[Str]) extends NullaryType with TypeVarImpl { diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls new file mode 100644 index 0000000000..3e9b461877 --- /dev/null +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -0,0 +1,45 @@ +:NewParser +:NewDefs + + +class Foo() +123 +//│ class Foo +//│ Typed: 123 + +Foo +//│ Typed: error + +fun fooo(x) = + class C(y, z) + C(0, x) +//│ fun fooo: anything -> error +//│ (fun) fooo: ‹∀ 0. fooo28'#› +//│ fooo28'# := (α29' -> α31') +//│ α31' :> error<> +//│ Code generation encountered an error: +//│ unsupported definitions in blocks + + +:ns +mixin Foo { + fun test(x) = super.x + 1 +} +//│ mixin Foo +//│ this: this51 +//│ super: super52 +//│ super52 <: {x: x62_63} & {x: x56_57} +//│ x56_57 <: int +//│ x62_63 <: int +//│ fun test: forall 'a 'test 'b. 'test +//│ where +//│ 'test := 'b -> 'a +//│ 'a :> int +//│ (fun) test: ‹∀ 1. test60''#› +//│ test60''# := (α61'' -> α65'') +//│ α65'' :> int +//│ Code generation crashed: +//│ scala.MatchError: mixin Foo() {fun test = (x,) => + ((super).x,) (1,)} (of class mlscript.NuTypeDef) + + + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 280bce0030..64fa1952ae 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -180,6 +180,8 @@ class DiffTests var generalizeArguments = false var newParser = basePath.headOption.contains("parser") || basePath.headOption.contains("compiler") + var newDefs = false + val backend = new JSTestBackend() val host = ReplHost() val codeGenTestHelpers = new CodeGenTestHelpers(file, output) @@ -211,6 +213,7 @@ class DiffTests case "AllowRuntimeErrors" => allowRuntimeErrors = true; mode case "ShowRelativeLineNums" => showRelativeLineNums = true; mode case "NewParser" => newParser = true; mode + case "NewDefs" => newDefs = true; mode case "NoJS" => noJavaScript = true; mode case "NoProvs" => noProvs = true; mode case "GeneralizeCurriedFunctions" => generalizeCurriedFunctions = true; mode @@ -391,7 +394,7 @@ class DiffTests // try to parse block of text into mlscript ast val ans = try { - if (newParser || basePath.headOption.contains("compiler")) { + if (newParser) { val origin = Origin(testName, globalStartLineNum, fph) val lexer = new NewLexer(origin, raise, dbg = mode.dbgParsing) @@ -441,6 +444,7 @@ class DiffTests if (mode.stats) typer.resetStats() typer.dbg = mode.dbg typer.dbgUCS = mode.dbgUCS + typer.newDefs = newDefs // typer.recordProvenances = !noProvs typer.recordProvenances = !noProvs && !mode.dbg && !mode.dbgSimplif || mode.explainErrors typer.generalizeCurriedFunctions = generalizeCurriedFunctions @@ -456,22 +460,7 @@ class DiffTests stdout = mode.stdout typer.preciselyTypeRecursion = mode.preciselyTypeRecursion - val (diags, (typeDefs, stmts)) = p.desugared - report(diags) - - if (mode.showParse) { - typeDefs.foreach(td => output("Desugared: " + td)) - stmts.foreach { s => - output("Desugared: " + s) - output("AST: " + mlscript.codegen.Helpers.inspect(s)) - } - } - val oldCtx = ctx - ctx = - // if (newParser) typer.typeTypingUnit(tu) - // else - typer.processTypeDefs(typeDefs)(ctx, raise) def getType(ty: typer.SimpleType): Type = { if (mode.isDebugging) output(s"⬤ Typed as: $ty") @@ -499,6 +488,60 @@ class DiffTests } } } + + val (typeDefs, stmts) = if (newDefs) { + + val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise) + + def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { + val indStr = " " * ind + ttu.entities.foreach { + case tc: typer.TypedNuCls => + output(s"${indStr}class ${tc.name}") + case tm: typer.TypedNuMxn => + output(s"${indStr}mixin ${tm.name}") + output(s"${indStr} this: ${tm.thisTV} ${tm.thisTV.showBounds}") + output(s"${indStr} super: ${tm.superTV} ${tm.superTV.showBounds}") + // tm.ttu.entities.foreach { } + showTTU(tm.ttu, ind + 1) + case tf: typer.TypedNuFun => + val exp = getType(tf.ty) + output(s"${indStr}fun ${tf.name}: ${exp.show}") + output(s"${indStr}(fun) ${tf.name}: ${tf.ty} ${tf.ty.body.showBounds}") + } + } + showTTU(tpd, 0) + + // val exp = getType(typer.PolymorphicType(0, res_ty)) + // output(s"Typed: ${exp}") + tpd.result.foreach { res_ty => + val exp = getType(typer.PolymorphicType(0, res_ty)) + output(s"Typed: ${exp.show}") + } + + (Nil, Nil) + + } else { + + val (diags, (typeDefs, stmts)) = p.desugared + report(diags) + + if (mode.showParse) { + typeDefs.foreach(td => output("Desugared: " + td)) + stmts.foreach { s => + output("Desugared: " + s) + output("AST: " + mlscript.codegen.Helpers.inspect(s)) + } + } + + ctx = + // if (newParser) typer.typeTypingUnit(tu) + // else + typer.processTypeDefs(typeDefs)(ctx, raise) + + (typeDefs, stmts) + } + // initialize ts typegen code builder and // declare all type definitions for current block val tsTypegenCodeBuilder = new TsTypegenCodeBuilder() From 940741d29fadaf5a3750978e7e7c5479f68ce259 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 15 Feb 2023 17:22:12 +0800 Subject: [PATCH 002/498] Minor --- .../src/main/scala/mlscript/NuTypeDefs.scala | 5 +- .../main/scala/mlscript/TyperDatatypes.scala | 10 ++-- .../main/scala/mlscript/utils/package.scala | 4 ++ shared/src/test/diff/nu/MutualRec.mls | 54 +++++++++++-------- .../src/test/scala/mlscript/DiffTests.scala | 11 ++-- 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index dc74b36558..cdf56aac65 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -64,7 +64,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) - def typeTypingUnit(tu: TypingUnit, allowPure: Bool)(implicit ctx: Ctx, raise: Raise): TypedTypingUnit = { + def typeTypingUnit(tu: TypingUnit, allowPure: Bool)(implicit ctx: Ctx, raise: Raise): TypedTypingUnit = + trace(s"${ctx.lvl}. Typing $tu") { // val named = mutable.Map.empty[Str, LazyTypeInfo[TypedNuTermDef]] val named = mutable.Map.empty[Str, LazyTypeInfo] // val namedTerms = mutable.Map.empty[Var, LazyTypeInfo[TypedNuTypeDef]] @@ -135,7 +136,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val res_ty = go(tu.entities) // TypedTypingUnit(infos.unzip._2.map(_.complete()), S(res_ty)) TypedTypingUnit(infos.unzip._2.map(_.complete()), res_ty) - } + }() // class TypedTypingUnit(tu: TypingUnit)(implicit ctx: Ctx, raise: Raise) { // } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index f811fad3e8..5049e7e0e0 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -32,7 +32,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { - var isComputing: Bool = false + var isComputing: Bool = false // TODO replace by a Ctx entry var result: Opt[TypedNuTermDef] = N // var result: Opt[A] = N val tv: TV = freshVar( @@ -42,9 +42,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { if (isComputing) lastWords(s"TODO cyclic defn") else { - isComputing = true // var res: ST = errType - try { + val res = try { + isComputing = true // res = decl match { case fd: NuFunDef => @@ -94,6 +94,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // } finally { result = S(res); isComputing = false } } finally { /* result = S(res); */ isComputing = false } + + result = S(res) + res + } } def typeSignature(implicit raise: Raise): ST = if (isComputing) tv else complete() match { diff --git a/shared/src/main/scala/mlscript/utils/package.scala b/shared/src/main/scala/mlscript/utils/package.scala index 9bf6486056..9af874e91f 100644 --- a/shared/src/main/scala/mlscript/utils/package.scala +++ b/shared/src/main/scala/mlscript/utils/package.scala @@ -30,6 +30,10 @@ package object utils { def mapLines(f: String => String): String = splitSane('\n') map f mkString "\n" def indent(pre: String): String = mapLines(pre + _) def indent: String = indent("\t") + def indentNewLines(pre: String = "\t"): String = splitSane('\n').toList match { + case head :: (rest @ _ :: _) => head + "\n" + rest.map(pre + _).mkString("\n") + case _ => self + } def truncate(maxChars: Int, replace: String): String = { val newStr = self.take(maxChars) if (newStr.length < self.length) newStr + replace diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 3e9b461877..b28024a406 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -1,5 +1,6 @@ :NewParser :NewDefs +:NoJS class Foo() @@ -13,33 +14,40 @@ Foo fun fooo(x) = class C(y, z) C(0, x) -//│ fun fooo: anything -> error -//│ (fun) fooo: ‹∀ 0. fooo28'#› -//│ fooo28'# := (α29' -> α31') -//│ α31' :> error<> -//│ Code generation encountered an error: -//│ unsupported definitions in blocks +//│ fun fooo: ‹∀ 0. fooo24'#› where +//│ | fooo24'# := (α25' -> α27') +//│ | α27' :> error<> +//│ [pretty-printed] fooo: anything -> error - -:ns +// :d mixin Foo { - fun test(x) = super.x + 1 + fun test = super.base } //│ mixin Foo -//│ this: this51 -//│ super: super52 -//│ super52 <: {x: x62_63} & {x: x56_57} -//│ x56_57 <: int -//│ x62_63 <: int -//│ fun test: forall 'a 'test 'b. 'test -//│ where -//│ 'test := 'b -> 'a -//│ 'a :> int -//│ (fun) test: ‹∀ 1. test60''#› -//│ test60''# := (α61'' -> α65'') -//│ α65'' :> int -//│ Code generation crashed: -//│ scala.MatchError: mixin Foo() {fun test = (x,) => + ((super).x,) (1,)} (of class mlscript.NuTypeDef) +//│ this: this32 +//│ super: super33 +//│ | super33 <: {base: base36_37} +//│ fun test: ‹∀ 1. test35''#› where +//│ | test35''# := base36'' +//│ | base36'' :> base36_37 <: test35''# +//│ [pretty-printed] test: nothing + +// :ns +mixin Foo { + fun test(x) = [super.base + x, x, super.misc] +} +//│ mixin Foo +//│ this: this42 +//│ super: super43 +//│ | super43 <: {misc: misc51_52} & {base: base47_48} +//│ | base47_48 <: int +//│ fun test: ‹∀ 1. test45''#› where +//│ | test45''# := (α46'' -> (α50'', α46'', misc51'',)) +//│ | α46'' <: int +//│ | α50'' :> int +//│ | misc51'' :> misc51_52 +//│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 64fa1952ae..56fc753631 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -500,14 +500,17 @@ class DiffTests output(s"${indStr}class ${tc.name}") case tm: typer.TypedNuMxn => output(s"${indStr}mixin ${tm.name}") - output(s"${indStr} this: ${tm.thisTV} ${tm.thisTV.showBounds}") - output(s"${indStr} super: ${tm.superTV} ${tm.superTV.showBounds}") + output(s"${indStr} this: ${tm.thisTV} ${tm.thisTV.showBounds + .indentNewLines(indStr+" |")}") + output(s"${indStr} super: ${tm.superTV} ${tm.superTV.showBounds + .indentNewLines(indStr+" |")}") // tm.ttu.entities.foreach { } showTTU(tm.ttu, ind + 1) case tf: typer.TypedNuFun => val exp = getType(tf.ty) - output(s"${indStr}fun ${tf.name}: ${exp.show}") - output(s"${indStr}(fun) ${tf.name}: ${tf.ty} ${tf.ty.body.showBounds}") + output(s"${indStr}fun ${tf.name}: ${tf.ty} where ${tf.ty.body.showBounds + .indentNewLines(indStr+"|")}") + output(s"${indStr}[pretty-printed] ${tf.name}: ${exp.show.indentNewLines(indStr+"|")}") } } showTTU(tpd, 0) From 67e9a3353dda1b5a392e2327e4492552b09b6daa Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 15 Feb 2023 18:02:56 +0800 Subject: [PATCH 003/498] WIP --- .../src/main/scala/mlscript/NuTypeDefs.scala | 21 +++- shared/src/main/scala/mlscript/Typer.scala | 1 + .../main/scala/mlscript/TyperDatatypes.scala | 90 +++++++++++++++-- shared/src/test/diff/nu/BasicMixins.mls | 99 +++++++++++++++++++ shared/src/test/diff/nu/MutualRec.mls | 35 +------ .../src/test/scala/mlscript/DiffTests.scala | 2 +- 6 files changed, 204 insertions(+), 44 deletions(-) create mode 100644 shared/src/test/diff/nu/BasicMixins.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index cdf56aac65..3c577f6d09 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -22,6 +22,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed abstract class TypedNuDecl { def name: Str + def freshen(implicit ctx: Ctx): TypedNuDecl = this match { + case m @ TypedNuMxn(td, thisTV, superTV, ttu) => + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify = false)) + case _ => ??? + } } sealed trait TypedNuTermDef extends TypedNuDecl { @@ -54,18 +61,27 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { + def level = thisTV.level - 1 // TODO cleaner def nme: TypeName = td.nme def name: Str = nme.name + // def freshen(implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, } - case class TypedNuFun(fd: NuFunDef, ty: PolymorphicType) extends TypedNuDecl with TypedNuTermDef { + case class TypedNuFun(fd: NuFunDef, ty: ST) extends TypedNuDecl with TypedNuTermDef { def name: Str = fd.nme.name } - case class TypedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) + case class TypedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) { + // def freshen(implicit ctx: Ctx): TypedTypingUnit = ??? + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + : TypedTypingUnit = + TypedTypingUnit(entities, result.map(_.freshenAbove(lim, rigidify))) + } def typeTypingUnit(tu: TypingUnit, allowPure: Bool)(implicit ctx: Ctx, raise: Raise): TypedTypingUnit = trace(s"${ctx.lvl}. Typing $tu") { + // trace(s"${ctx.lvl}. Typing $tu") { ctx.nextLevel { implicit ctx: Ctx => // val named = mutable.Map.empty[Str, LazyTypeInfo[TypedNuTermDef]] val named = mutable.Map.empty[Str, LazyTypeInfo] // val namedTerms = mutable.Map.empty[Var, LazyTypeInfo[TypedNuTypeDef]] @@ -137,6 +153,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TypedTypingUnit(infos.unzip._2.map(_.complete()), S(res_ty)) TypedTypingUnit(infos.unzip._2.map(_.complete()), res_ty) }() + // }(raise, noProv/*TODO*/)}() // class TypedTypingUnit(tu: TypingUnit)(implicit ctx: Ctx, raise: Raise) { // } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 683fc89018..eefe3b5149 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -176,6 +176,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) override def toString: Str = "[NO PROV]" } def noProv: TypeProvenance = NoProv + def provTODO: TypeProvenance = noProv def noTyProv: TypeProvenance = TypeProvenance(N, "type", isType = true) val TopType: ExtrType = ExtrType(false)(noTyProv) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 5049e7e0e0..9716abcafe 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -30,6 +30,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case class VarSymbol(ty: ST, definingVar: Var) extends TypeInfo + // TODO rm level? already in ctx class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { var isComputing: Bool = false // TODO replace by a Ctx entry @@ -63,7 +64,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case L(body) => implicit val vars: Map[Str, SimpleType] = Map.empty implicit val gl: GenLambdas = true - val body_ty = typeLetRhs(isrec = true, fd.nme.name, body) + val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) // implicit val prov: TP = noProv // TODO // subsume(body_ty, PolymorphicType(level, tv)) // TODO TypedNuFun(fd, body_ty) @@ -75,18 +76,89 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case Cls => val ttu = typeTypingUnit(td.body, allowPure = false) // TODO check against `tv` + println(td.tparams) + println(td.params) + println(td.parents) + implicit val prov: TP = + TypeProvenance(decl.toLoc, decl.describe) + val finalType = freshVar(noProv/*TODO*/, N, S("this")) + // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { + def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl]): Unit = parents match { + case p :: ps => + val newMembs = trace(s"Inheriting from $p") { + p match { + case Var(nme) => + ctx.get(nme) match { + case S(lti: LazyTypeInfo) => + lti.complete().freshen match { + case mxn: TypedNuMxn => + // mxn.thisTV + // mxn.ttu.entities + // ??? + // val fresh = mxn.freshen + // println(fresh) + constrain(superType, mxn.superTV) + constrain(finalType, mxn.thisTV) + mxn.ttu.entities.map { + case fun @ TypedNuFun(fd, ty) => + fun + case _ => ??? + } + case cls: TypedNuCls => + ??? + case als: TypedNuAls => + // TODO dealias first? + err(msg"Cannot inherit from a type alias", p.toLoc) + Nil + case cls: TypedNuFun => + ??? + } + case S(_) => + err(msg"Cannot inherit from this", p.toLoc) + Nil + case N => + err(msg"Could not find definition `${nme}`", p.toLoc) + Nil + } + case _ => + err(msg"Illegal parent specification", p.toLoc) + Nil + } + }() + val newSuperType = superType + inherit(ps, superType, newMembs) + case Nil => + } + val typedParams = td.params.fields.map { + case (S(nme), Fld(mut, spec, value)) => + assert(!mut && !spec, "TODO") // TODO + value.toType match { + case R(tpe) => + implicit val vars: Map[Str, SimpleType] = Map.empty // TODO type params + implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? + val ty = typeType(tpe) + nme -> FieldType(N, ty)(provTODO) + case _ => ??? + } + case (N, Fld(mut, spec, nme: Var)) => + assert(!mut && !spec, "TODO") // TODO + nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) + case _ => ??? + } + val baseType = RecordType(typedParams)(provTODO) + inherit(td.parents, baseType, Nil) TypedNuCls(td, ttu) case Mxn => - implicit val prov = noProv // TODO - ctx.nextLevel { newCtx => + implicit val prov: TP = noProv // TODO + ctx.nextLevel { implicit ctx => val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) val superTV = freshVar(noProv/*FIXME*/, N, S("super")) - newCtx += "this" -> VarSymbol(thisTV, Var("this")) - newCtx += "super" -> VarSymbol(superTV, Var("super")) - newCtx |> { implicit ctx => - val ttu = typeTypingUnit(td.body, allowPure = false) - TypedNuMxn(td, thisTV, superTV, ttu) - } + ctx += "this" -> VarSymbol(thisTV, Var("this")) + ctx += "super" -> VarSymbol(superTV, Var("super")) + // ctx |> { implicit ctx => + val ttu = typeTypingUnit(td.body, allowPure = false) + TypedNuMxn(td, thisTV, superTV, ttu) + // } } case _ => ??? } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls new file mode 100644 index 0000000000..fb7f50c42f --- /dev/null +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -0,0 +1,99 @@ +:NewParser +:NewDefs +:NoJS + + +// :d +mixin BaseTest { + fun test = super.base +} +//│ mixin BaseTest +//│ this: this23' +//│ super: super24' +//│ | super24' <: {base: base27_28'} +//│ fun test: ‹∀ 1. test26''#› where +//│ | test26''# := base27'' +//│ | base27'' :> base27_28' <: test26''# +//│ [pretty-printed] test: nothing + +mixin BaseInc { + fun test = super.base + 1 +} +//│ mixin BaseInc +//│ this: this33' +//│ super: super34' +//│ | super34' <: {base: base37_38'} +//│ | base37_38' <: int +//│ fun test: ‹∀ 1. test36''#› where +//│ | test36''# := α40'' +//│ | α40'' :> int <: test36''# +//│ [pretty-printed] test: int + +:d +class Base1(base: int): BaseTest +//│ 0. Typing TypingUnit(List(class Base1(base: int,): BaseTest {})) +//│ | 0. Typing TypingUnit(List()) +//│ | List() +//│ | base: int, +//│ | List(BaseTest) +//│ | Typing type int +//│ | | vars=Map() newDefsInfo=Map() +//│ | | 0. type int +//│ | | => Int +//│ | => Int ——— +//│ | Inheriting from BaseTest +//│ | | CONSTRAIN {base: Int} +//│ fun test: ‹∀ 1. test55''#› where +//│ | test55''# := (α56'' -> (α60'', α56'', misc61'',)) +//│ | α56'' <: int +//│ | α60'' :> int +//│ | misc61'' :> misc61_62' +//│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) + diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index b28024a406..b8fc5ebbc5 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -14,40 +14,11 @@ Foo fun fooo(x) = class C(y, z) C(0, x) -//│ fun fooo: ‹∀ 0. fooo24'#› where -//│ | fooo24'# := (α25' -> α27') -//│ | α27' :> error<> +//│ fun fooo: ‹∀ 0. fooo25'#› where +//│ | fooo25'# := (α26' -> α31') +//│ | α31' :> error<> //│ [pretty-printed] fooo: anything -> error -// :d -mixin Foo { - fun test = super.base -} -//│ mixin Foo -//│ this: this32 -//│ super: super33 -//│ | super33 <: {base: base36_37} -//│ fun test: ‹∀ 1. test35''#› where -//│ | test35''# := base36'' -//│ | base36'' :> base36_37 <: test35''# -//│ [pretty-printed] test: nothing - -// :ns -mixin Foo { - fun test(x) = [super.base + x, x, super.misc] -} -//│ mixin Foo -//│ this: this42 -//│ super: super43 -//│ | super43 <: {misc: misc51_52} & {base: base47_48} -//│ | base47_48 <: int -//│ fun test: ‹∀ 1. test45''#› where -//│ | test45''# := (α46'' -> (α50'', α46'', misc51'',)) -//│ | α46'' <: int -//│ | α50'' :> int -//│ | misc51'' :> misc51_52 -//│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) - diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 56fc753631..cfcb0abf09 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -508,7 +508,7 @@ class DiffTests showTTU(tm.ttu, ind + 1) case tf: typer.TypedNuFun => val exp = getType(tf.ty) - output(s"${indStr}fun ${tf.name}: ${tf.ty} where ${tf.ty.body.showBounds + output(s"${indStr}fun ${tf.name}: ${tf.ty} where ${tf.ty.showBounds .indentNewLines(indStr+"|")}") output(s"${indStr}[pretty-printed] ${tf.name}: ${exp.show.indentNewLines(indStr+"|")}") } From d71face116fc0ff1b18b803e6712deb104ee5e6f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 15 Feb 2023 23:12:10 +0800 Subject: [PATCH 004/498] WIP --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 16 ++++---- shared/src/test/diff/nu/BasicMixins.mls | 39 +++++++++++++------ shared/src/test/diff/nu/MutualRec.mls | 27 ++++++++++--- 5 files changed, 61 insertions(+), 27 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 3c577f6d09..754e913fbd 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -54,7 +54,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { - case class TypedNuCls(td: NuTypeDef, ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { + case class TypedNuCls(td: NuTypeDef, ttu: TypedTypingUnit, params: Ls[Var -> FieldType]) extends TypedNuTypeDef(Cls) with TypedNuTermDef { // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { def nme: TypeName = td.nme def name: Str = nme.name diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index eefe3b5149..2c0ff30973 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -160,8 +160,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) implicit def lvl(implicit ctx: Ctx): Int = ctx.lvl import TypeProvenance.{apply => tp} - def ttp(trm: Term, desc: Str = ""): TypeProvenance = - TypeProvenance(trm.toLoc, if (desc === "") trm.describe else desc) + def ttp(trm: Term, desc: Str = "", isType: Bool = false): TypeProvenance = + TypeProvenance(trm.toLoc, if (desc === "") trm.describe else desc, isType = isType) def originProv(loco: Opt[Loc], desc: Str, name: Str): TypeProvenance = { tp(loco, desc, S(name), isType = true) // ^ If we did not treat "origin provenances" differently, diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 9716abcafe..c8b75d158d 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -74,7 +74,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case td: NuTypeDef => td.kind match { case Cls => - val ttu = typeTypingUnit(td.body, allowPure = false) + val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use // TODO check against `tv` println(td.tparams) println(td.params) @@ -126,8 +126,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } }() val newSuperType = superType - inherit(ps, superType, newMembs) + inherit(ps, newSuperType, newMembs) case Nil => + constrain(superType, finalType) } val typedParams = td.params.fields.map { case (S(nme), Fld(mut, spec, value)) => @@ -145,9 +146,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) case _ => ??? } - val baseType = RecordType(typedParams)(provTODO) + val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) inherit(td.parents, baseType, Nil) - TypedNuCls(td, ttu) + TypedNuCls(td, ttu, typedParams) case Mxn => implicit val prov: TP = noProv // TODO ctx.nextLevel { implicit ctx => @@ -174,9 +175,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } def typeSignature(implicit raise: Raise): ST = if (isComputing) tv else complete() match { case cls: TypedNuCls => - // ??? - // TODO - errType + FunctionType( + TupleType(cls.params.mapKeys(some))(provTODO), + ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) + )(provTODO) case TypedNuFun(fd, ty) => ??? } override def toString: String = diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index fb7f50c42f..ac147b3459 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -58,17 +58,31 @@ class Base1(base: int): BaseTest //│ | | where //│ | | 0. C this44 Base1 + +// TODO +Base1 +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Base1 + class Base1(base): BaseTest //│ class Base1 :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.66: class Base1(x): BaseTest +//│ ║ l.79: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `{x: ?x}` does not have field 'base' +//│ ╟── type `{x: ?x}` does not have field 'base' +//│ ║ l.79: class Base1(x): BaseTest +//│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base //│ ║ ^^^^^^^^^^ @@ -77,8 +91,9 @@ class Base1(x): BaseTest //│ ╙── ^^^^^ //│ class Base1 +// TODO Base1 -//│ Typed: error +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Base1 // :ns @@ -86,14 +101,14 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo -//│ this: this52' -//│ super: super53' -//│ | super53' <: {misc: misc61_62'} & {base: base57_58'} -//│ | base57_58' <: int -//│ fun test: ‹∀ 1. test55''#› where -//│ | test55''# := (α56'' -> (α60'', α56'', misc61'',)) -//│ | α56'' <: int -//│ | α60'' :> int -//│ | misc61'' :> misc61_62' +//│ this: this53' +//│ super: super54' +//│ | super54' <: {misc: misc62_63'} & {base: base58_59'} +//│ | base58_59' <: int +//│ fun test: ‹∀ 1. test56''#› where +//│ | test56''# := (α57'' -> (α61'', α57'', misc62'',)) +//│ | α57'' <: int +//│ | α61'' :> int +//│ | misc62'' :> misc62_63' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index b8fc5ebbc5..d1949e175a 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -9,15 +9,32 @@ class Foo() //│ Typed: 123 Foo -//│ Typed: error +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Foo +//│ at: scala.collection.immutable.BitmapIndexedMapNode.apply(HashMap.scala:631) +//│ at: scala.collection.immutable.HashMap.apply(HashMap.scala:132) +//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$9(TypeSimplifier.scala:191) +//│ at: mlscript.NormalForms$Conjunct.toTypeWith(NormalForms.scala:399) +//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$6(TypeSimplifier.scala:324) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.TypeSimplifier.helper$1(TypeSimplifier.scala:162) +//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$82(TypeSimplifier.scala:340) +//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) +//│ at: mlscript.TypeSimplifier.go$1(TypeSimplifier.scala:346) fun fooo(x) = class C(y, z) C(0, x) -//│ fun fooo: ‹∀ 0. fooo25'#› where -//│ | fooo25'# := (α26' -> α31') -//│ | α31' :> error<> -//│ [pretty-printed] fooo: anything -> error +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: C +//│ at: scala.collection.immutable.BitmapIndexedMapNode.apply(HashMap.scala:631) +//│ at: scala.collection.immutable.HashMap.apply(HashMap.scala:132) +//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$9(TypeSimplifier.scala:191) +//│ at: mlscript.NormalForms$Conjunct.toTypeWith(NormalForms.scala:399) +//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$6(TypeSimplifier.scala:324) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.TypeSimplifier.helper$1(TypeSimplifier.scala:162) +//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$82(TypeSimplifier.scala:340) +//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) +//│ at: mlscript.TypeSimplifier.go$1(TypeSimplifier.scala:346) From 2c61dcc6452b26209ee177997ea16773754be50a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 13:44:54 +0800 Subject: [PATCH 005/498] Minor --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- .../main/scala/mlscript/TypeSimplifier.scala | 10 +++-- .../main/scala/mlscript/TyperDatatypes.scala | 4 +- shared/src/test/diff/nu/BasicClasses.mls | 37 +++++++++++++++++++ shared/src/test/diff/nu/BasicMixins.mls | 14 ++----- shared/src/test/diff/nu/MutualRec.mls | 28 +++----------- 6 files changed, 56 insertions(+), 39 deletions(-) create mode 100644 shared/src/test/diff/nu/BasicClasses.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 754e913fbd..d33a3e79e4 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -61,7 +61,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { - def level = thisTV.level - 1 // TODO cleaner + def level: Level = thisTV.level - 1 // TODO cleaner def nme: TypeName = td.nme def name: Str = nme.name // def freshen(implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index b67ac22b31..74e7a18a02 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -185,9 +185,13 @@ trait TypeSimplifier { self: Typer => tts.iterator.collect{ case TraitTag(Var(tagNme)) => tagNme.capitalize }.toSet bo match { - case S(cls @ ClassTag(Var(tagNme), ps)) if !primitiveTypes.contains(tagNme) => - val clsNme = tagNme.capitalize - val clsTyNme = TypeName(tagNme.capitalize) + case S(cls @ ClassTag(Var(tagNme), ps)) + if !primitiveTypes.contains(tagNme) + && ctx.tyDefs.contains(tagNme.capitalize) + && !tagNme.isCapitalized // currently capitalization characterizes nudefs + => + val clsNme = tagNme.capitalize // TODO rm capitalize + val clsTyNme = TypeName(clsNme) val td = ctx.tyDefs(clsNme) val rcdMap = rcd.fields.toMap diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c8b75d158d..193c50b225 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -49,8 +49,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // res = decl match { case fd: NuFunDef => - assert(fd.isLetRec.isEmpty) - implicit val prov = noProv // TODO + // assert(fd.isLetRec.isEmpty, fd.isLetRec) + implicit val prov: TP = noProv // TODO val res_ty = fd.rhs match { case R(PolyType(tps, ty)) => // val body_ty = typeType(ty)(ctx.nextLevel, raise, diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls new file mode 100644 index 0000000000..01f113ae5a --- /dev/null +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -0,0 +1,37 @@ +:NewParser +:NewDefs +:NoJS + + +class Base1(base: int) +//│ class Base1 + +Base1 +//│ Typed: (base: int,) -> Base1 + +let b = Base1(1) +//│ fun b: ‹∀ 0. b25'#› where +//│ | b25'# := α26' +//│ | α26' :> Base1<> <: b25'# +//│ [pretty-printed] b: Base1 + +// TODO +b.base +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.19: b.base +//│ ║ ^^^^^^ +//│ ╟── application of type `Base1` does not have field 'base' +//│ ║ l.12: let b = Base1(1) +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into reference with expected type `{base: ?base}` +//│ ║ l.19: b.base +//│ ╙── ^ +//│ Typed: error + +// TODO +b : Base1 +//│ ╔══[ERROR] type identifier not found: Base1 +//│ ║ l.32: b : Base1 +//│ ╙── ^^^^^ +//│ Typed: error + diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index ac147b3459..2be32afcbf 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -64,13 +64,6 @@ class Base1(base: int): BaseTest //│ | | NEW this44 LB (0) //│ class Base1 -:ns -Base1 -//│ Typed: (base: int,) -> Base1 - -// TODO -Base1 -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Base1 class Base1(base): BaseTest //│ class Base1 @@ -78,10 +71,10 @@ class Base1(base): BaseTest :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.79: class Base1(x): BaseTest +//│ ║ l.72: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.79: class Base1(x): BaseTest +//│ ║ l.72: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -91,9 +84,8 @@ class Base1(x): BaseTest //│ ╙── ^^^^^ //│ class Base1 -// TODO Base1 -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Base1 +//│ Typed: (x: anything,) -> Base1 // :ns diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index d1949e175a..2896a795ad 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -9,32 +9,16 @@ class Foo() //│ Typed: 123 Foo -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Foo -//│ at: scala.collection.immutable.BitmapIndexedMapNode.apply(HashMap.scala:631) -//│ at: scala.collection.immutable.HashMap.apply(HashMap.scala:132) -//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$9(TypeSimplifier.scala:191) -//│ at: mlscript.NormalForms$Conjunct.toTypeWith(NormalForms.scala:399) -//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$6(TypeSimplifier.scala:324) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.TypeSimplifier.helper$1(TypeSimplifier.scala:162) -//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$82(TypeSimplifier.scala:340) -//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) -//│ at: mlscript.TypeSimplifier.go$1(TypeSimplifier.scala:346) +//│ Typed: () -> Foo fun fooo(x) = class C(y, z) C(0, x) -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: C -//│ at: scala.collection.immutable.BitmapIndexedMapNode.apply(HashMap.scala:631) -//│ at: scala.collection.immutable.HashMap.apply(HashMap.scala:132) -//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$9(TypeSimplifier.scala:191) -//│ at: mlscript.NormalForms$Conjunct.toTypeWith(NormalForms.scala:399) -//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$6(TypeSimplifier.scala:324) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.TypeSimplifier.helper$1(TypeSimplifier.scala:162) -//│ at: mlscript.TypeSimplifier.$anonfun$normalizeTypes_$bang$82(TypeSimplifier.scala:340) -//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) -//│ at: mlscript.TypeSimplifier.go$1(TypeSimplifier.scala:346) +//│ fun fooo: ‹∀ 0. fooo25'#› where +//│ | fooo25'# := (α26' -> α31') +//│ | α26' <: z30' +//│ | α31' :> C<> +//│ [pretty-printed] fooo: anything -> C From f0ac62ccaba4899943c433258a123e6b75f6b884 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 14:27:31 +0800 Subject: [PATCH 006/498] WIP --- .../scala/mlscript/ConstraintSolver.scala | 27 +++++++++ .../src/main/scala/mlscript/NuTypeDefs.scala | 26 +++++++- shared/src/main/scala/mlscript/TypeDefs.scala | 6 ++ shared/src/main/scala/mlscript/Typer.scala | 13 ++++ .../main/scala/mlscript/TyperDatatypes.scala | 60 +++++++++++++++---- shared/src/test/diff/nu/BasicClasses.mls | 54 +++++++++++------ 6 files changed, 151 insertions(+), 35 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 2ff64d2815..24410a047a 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -556,6 +556,33 @@ class ConstraintSolver extends NormalForms { self: Typer => case (_: TypeTag, _: TypeTag) if lhs === rhs => () case (NegType(lhs), NegType(rhs)) => rec(rhs, lhs, true) + case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => + def lookupNuTypeDef(clsNme: Str): TypedNuCls = { + ctx.tyDefs2(clsNme).complete() match { + case td: TypedNuCls => td + case _ => ??? + } + } + def lookupNuTypeDefField(cls: TypedNuCls, rfnt: Map[Var, Field], fld: Var): FieldType = { + println(fld.name, cls.members) + cls.members.get(fld.name) match { + case S(d: TypedNuFun) => + ??? + case S(p: NuParam) => + p.ty + case N => + err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", + // ttp(fld)) + fld.toLoc).toUpper(noProv) + // case _ => ??? + } + } + rt.fields.foreach { case (fldNme, fldTy) => + val fty = lookupNuTypeDefField(lookupNuTypeDef(nme), Map.empty, fldNme) + rec(fty.ub, fldTy.ub, false) + recLb(fldTy, fty) + } + // * Note: at this point, it could be that a polymorphic type could be distribbed // * out of `r1`, but this would likely not result in something useful, since the // * LHS is a normal non-polymorphic function type... diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index d33a3e79e4..cc1c0236e8 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -20,7 +20,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * For now these are just unused stubs to be completed and used later - sealed abstract class TypedNuDecl { + + sealed trait NuMember { + def name: Str + } + + + case class NuParam(nme: Var, ty: FieldType) extends NuMember { + def name: Str = nme.name + } + + + sealed abstract class TypedNuDecl extends NuMember { def name: Str def freshen(implicit ctx: Ctx): TypedNuDecl = this match { case m @ TypedNuMxn(td, thisTV, superTV, ttu) => @@ -31,7 +42,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - sealed trait TypedNuTermDef extends TypedNuDecl { + sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { override def toString: String = this match { case _ => ??? } @@ -39,6 +50,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { def nme: TypeName + val tparams: Ls[TN -> TV] = Nil // TODO } // case class TypedNuTypeDef( // kind: TypeDefKind, @@ -54,7 +66,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { - case class TypedNuCls(td: NuTypeDef, ttu: TypedTypingUnit, params: Ls[Var -> FieldType]) extends TypedNuTypeDef(Cls) with TypedNuTermDef { + case class TypedNuCls(td: NuTypeDef, ttu: TypedTypingUnit, params: Ls[Var -> FieldType], + // members: Map[Str, LazyTypeInfo]) + members: Map[Str, NuMember]) + extends TypedNuTypeDef(Cls) with TypedNuTermDef { // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { def nme: TypeName = td.nme def name: Str = nme.name @@ -95,6 +110,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val infos = tu.entities.collect { case decl: NuDecl => val lti = new LazyTypeInfo(lvl, decl) + decl match { + case td: NuTypeDef => + ctx.tyDefs2 += td.nme.name -> lti + case _: NuFunDef => + } // def registerTerm = named.updateWith(decl.name) { case sv @ S(v) => diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 3229df01f8..7cc56984ad 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -12,6 +12,12 @@ class TypeDefs extends NuTypeDefs { self: Typer => import TypeProvenance.{apply => tp} + trait AnyTypeDef { + // val kind: TypeDefKind + // val nme: TypeName + // val tparamsargs: List[(TypeName, TypeVariable)] + } + /** * TypeDef holds information about declarations like classes, interfaces, and type aliases * diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 2c0ff30973..ba0a79810d 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -66,6 +66,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) lvl: Int, inPattern: Bool, tyDefs: Map[Str, TypeDef], + // tyDefs2: MutMap[Str, NuTypeDef], + tyDefs2: MutMap[Str, LazyTypeInfo], inRecursiveDef: Opt[Var], nuTyDefs: Map[Str, TypedNuTypeDef], extrCtx: ExtrCtx, @@ -151,6 +153,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) lvl = MinLevel, inPattern = false, tyDefs = Map.from(builtinTypes.map(t => t.nme.name -> t)), + tyDefs2 = MutMap.empty, inRecursiveDef = N, nuTyDefs = Map.empty, MutMap.empty, @@ -329,6 +332,16 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def typeNamed(loc: Opt[Loc], name: Str): (() => ST) \/ (TypeDefKind, Int) = newDefsInfo.get(name) .orElse(ctx.tyDefs.get(name).map(td => (td.kind, td.tparamsargs.size))) + .orElse(ctx.get(name).flatMap { + case ti: LazyTypeInfo => + // ti.complete() + ti.decl match { + case NuTypeDef(Cls, _, tps, _, _, _) => + S(Cls, tps.size) + case _ => ??? + } + case _ => N + }) .toRight(() => err("type identifier not found: " + name, loc)(raise)) val localVars = mutable.Map.empty[TypeVar, TypeVariable] def tyTp(loco: Opt[Loc], desc: Str, originName: Opt[Str] = N) = diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 193c50b225..ac3fad8296 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -33,6 +33,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // TODO rm level? already in ctx class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { + val tparams: Ls[TN -> TV] = Nil // TODO var isComputing: Bool = false // TODO replace by a Ctx entry var result: Opt[TypedNuTermDef] = N // var result: Opt[A] = N @@ -83,7 +84,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => TypeProvenance(decl.toLoc, decl.describe) val finalType = freshVar(noProv/*TODO*/, N, S("this")) // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { - def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl]): Unit = parents match { + def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { case p :: ps => val newMembs = trace(s"Inheriting from $p") { p match { @@ -126,9 +127,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } }() val newSuperType = superType - inherit(ps, newSuperType, newMembs) + inherit(ps, newSuperType, members ++ newMembs) case Nil => constrain(superType, finalType) + members } val typedParams = td.params.fields.map { case (S(nme), Fld(mut, spec, value)) => @@ -147,8 +149,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case _ => ??? } val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) - inherit(td.parents, baseType, Nil) - TypedNuCls(td, ttu, typedParams) + val paramMems = typedParams.map(f => NuParam(f._1, f._2)) + val baseMems = inherit(td.parents, baseType, Nil) + val mems = baseMems ++ paramMems + TypedNuCls(td, ttu, typedParams, mems.map(d => d.name -> d).toMap) case Mxn => implicit val prov: TP = noProv // TODO ctx.nextLevel { implicit ctx => @@ -525,7 +529,15 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]): TypeRef = TypeRef(defn, targs.map(_.freshenAbove(lim, rigidify)))(prov) def expand(implicit ctx: Ctx): SimpleType = expandWith(paramTags = true) - def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = { + def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = //if (defn.name.isCapitalized) { + ctx.tyDefs2.get(defn.name).map(_.decl match { + case td: NuTypeDef if td.kind is Cls => + ClassTag(Var(td.nme.name).withLocOf(td.nme), + Set.empty//TODO + )(provTODO) + case _ => ??? + } + ).getOrElse { val td = ctx.tyDefs(defn.name) require(targs.size === td.tparamsargs.size) lazy val tparamTags = @@ -553,10 +565,22 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => res } def mapTargs[R](pol: Opt[Bool])(f: (Opt[Bool], ST) => R)(implicit ctx: Ctx): Ls[R] = { - val td = ctx.tyDefs(defn.name) - td.tvarVariances.fold(targs.map(f(N, _))) { tvv => - assert(td.tparamsargs.sizeCompare(targs) === 0) - (td.tparamsargs lazyZip targs).map { case ((_, tv), ta) => + // val td = ctx.tyDefs(defn.name) + // td.tvarVariances.fold(targs.map(f(N, _))) { tvv => + // assert(td.tparamsargs.sizeCompare(targs) === 0) + // (td.tparamsargs lazyZip targs).map { case ((_, tv), ta) => + + // TODO factor w/ below + val (tvarVariances, tparamsargs) = ctx.tyDefs.get(defn.name) match { + case S(td) => + (td.tvarVariances, td.tparamsargs) + case N => + val td = ctx.tyDefs2(defn.name) + (N, td.tparams) + } + tvarVariances.fold(targs.map(f(N, _))) { tvv => + assert(tparamsargs.sizeCompare(targs) === 0) + (tparamsargs lazyZip targs).map { case ((_, tv), ta) => tvv(tv) match { case VarianceInfo(true, true) => f(N, TypeBounds(BotType, TopType)(noProv)) @@ -567,10 +591,20 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } // TODO dedup w/ above def mapTargs[R](pol: PolMap)(f: (PolMap, ST) => R)(implicit ctx: Ctx): Ls[R] = { - val td = ctx.tyDefs(defn.name) - td.tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => - assert(td.tparamsargs.sizeCompare(targs) === 0) - (td.tparamsargs lazyZip targs).map { case ((_, tv), ta) => + // val td = ctx.tyDefs.getOrElse(defn.name, ctx.tyDefs2(defn.name)) + // td.tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => + // assert(td.tparamsargs.sizeCompare(targs) === 0) + // (td.tparamsargs lazyZip targs).map { case ((_, tv), ta) => + val (tvarVariances, tparamsargs) = ctx.tyDefs.get(defn.name) match { + case S(td) => + (td.tvarVariances, td.tparamsargs) + case N => + val td = ctx.tyDefs2(defn.name) + (N, td.tparams) + } + tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => + assert(tparamsargs.sizeCompare(targs) === 0) + (tparamsargs lazyZip targs).map { case ((_, tv), ta) => tvv(tv) match { case VarianceInfo(true, true) => f(pol.invar, TypeBounds(BotType, TopType)(noProv)) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 01f113ae5a..2e008486b3 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -3,35 +3,51 @@ :NoJS -class Base1(base: int) +class Base1(base: int) { + fun getBase1(x) = base + fun getBase2(x) = this.base + fun foo(x) = this.base + x +} +//│ ╔══[ERROR] identifier not found: base +//│ ║ l.7: fun getBase1(x) = base +//│ ╙── ^^^^ +//│ ╔══[ERROR] identifier not found: this +//│ ║ l.8: fun getBase2(x) = this.base +//│ ╙── ^^^^ +//│ ╔══[ERROR] identifier not found: this +//│ ║ l.9: fun foo(x) = this.base + x +//│ ╙── ^^^^ //│ class Base1 Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b25'#› where -//│ | b25'# := α26' -//│ | α26' :> Base1<> <: b25'# +//│ fun b: ‹∀ 0. b38'#› where +//│ | b38'# := α39' +//│ | α39' :> Base1<> <: b38'# //│ [pretty-printed] b: Base1 -// TODO b.base -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.19: b.base -//│ ║ ^^^^^^ -//│ ╟── application of type `Base1` does not have field 'base' -//│ ║ l.12: let b = Base1(1) -//│ ║ ^^^^^^^^ -//│ ╟── but it flows into reference with expected type `{base: ?base}` -//│ ║ l.19: b.base -//│ ╙── ^ -//│ Typed: error +//│ Typed: int // TODO -b : Base1 -//│ ╔══[ERROR] type identifier not found: Base1 -//│ ║ l.32: b : Base1 -//│ ╙── ^^^^^ +// :d +b.getBase1 +//│ ╔══[ERROR] class `Base1` does not contain member `getBase1` +//│ ║ l.36: b.getBase1 +//│ ╙── ^^^^^^^^^ +//│ Typed: error + +:e +b.getBaseTypo +//│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` +//│ ║ l.43: b.getBaseTypo +//│ ╙── ^^^^^^^^^^^^ //│ Typed: error + +b : Base1 +//│ Typed: Base1 + + From a530d9073af0f4b9015984d4baf1d37a65381e60 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 16:04:43 +0800 Subject: [PATCH 007/498] WIP --- .../main/scala/mlscript/TyperDatatypes.scala | 45 ++++++++++++------- shared/src/test/diff/nu/BasicClasses.mls | 14 +++--- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index ac3fad8296..472a8a925c 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -75,7 +75,33 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case td: NuTypeDef => td.kind match { case Cls => + val typedParams = td.params.fields.map { + case (S(nme), Fld(mut, spec, value)) => + assert(!mut && !spec, "TODO") // TODO + value.toType match { + case R(tpe) => + implicit val vars: Map[Str, SimpleType] = Map.empty // TODO type params + implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? + val ty = typeType(tpe) + nme -> FieldType(N, ty)(provTODO) + case _ => ??? + } + case (N, Fld(mut, spec, nme: Var)) => + assert(!mut && !spec, "TODO") // TODO + nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) + case _ => ??? + } + // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) + ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use + + // val ttu.entities.map { + // case fun @ TypedNuFun(fd, ty) => + // fun + // case _ => ??? + // } + // TODO check against `tv` println(td.tparams) println(td.params) @@ -85,6 +111,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val finalType = freshVar(noProv/*TODO*/, N, S("this")) // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { + // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { + // case R(p) :: ps => ??? + // case L(p) :: ps => case p :: ps => val newMembs = trace(s"Inheriting from $p") { p match { @@ -132,22 +161,6 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => constrain(superType, finalType) members } - val typedParams = td.params.fields.map { - case (S(nme), Fld(mut, spec, value)) => - assert(!mut && !spec, "TODO") // TODO - value.toType match { - case R(tpe) => - implicit val vars: Map[Str, SimpleType] = Map.empty // TODO type params - implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? - val ty = typeType(tpe) - nme -> FieldType(N, ty)(provTODO) - case _ => ??? - } - case (N, Fld(mut, spec, nme: Var)) => - assert(!mut && !spec, "TODO") // TODO - nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) - case _ => ??? - } val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) val paramMems = typedParams.map(f => NuParam(f._1, f._2)) val baseMems = inherit(td.parents, baseType, Nil) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 2e008486b3..cdea95b4da 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -3,20 +3,18 @@ :NoJS +// :d class Base1(base: int) { fun getBase1(x) = base fun getBase2(x) = this.base fun foo(x) = this.base + x } -//│ ╔══[ERROR] identifier not found: base -//│ ║ l.7: fun getBase1(x) = base -//│ ╙── ^^^^ //│ ╔══[ERROR] identifier not found: this -//│ ║ l.8: fun getBase2(x) = this.base +//│ ║ l.9: fun getBase2(x) = this.base //│ ╙── ^^^^ //│ ╔══[ERROR] identifier not found: this -//│ ║ l.9: fun foo(x) = this.base + x -//│ ╙── ^^^^ +//│ ║ l.10: fun foo(x) = this.base + x +//│ ╙── ^^^^ //│ class Base1 Base1 @@ -35,14 +33,14 @@ b.base // :d b.getBase1 //│ ╔══[ERROR] class `Base1` does not contain member `getBase1` -//│ ║ l.36: b.getBase1 +//│ ║ l.34: b.getBase1 //│ ╙── ^^^^^^^^^ //│ Typed: error :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.43: b.getBaseTypo +//│ ║ l.41: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error From 32481a5e4f20773abe450aa992e14e25e8ef349e Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 16:28:46 +0800 Subject: [PATCH 008/498] WIP --- .../main/scala/mlscript/TyperDatatypes.scala | 8 +- shared/src/test/diff/nu/BasicClasses.mls | 38 +++++++-- shared/src/test/diff/nu/BasicMixins.mls | 8 +- shared/src/test/diff/nu/MutualRec.mls | 85 ++++++++++++++++++- .../src/test/scala/mlscript/DiffTests.scala | 1 + 5 files changed, 124 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 472a8a925c..dab92c64ec 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -74,7 +74,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => res_ty case td: NuTypeDef => td.kind match { - case Cls => + case Cls | Nms => val typedParams = td.params.fields.map { case (S(nme), Fld(mut, spec, value)) => assert(!mut && !spec, "TODO") // TODO @@ -191,12 +191,16 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } } def typeSignature(implicit raise: Raise): ST = if (isComputing) tv else complete() match { + case cls: TypedNuCls if cls.td.kind is Nms => + ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) case cls: TypedNuCls => FunctionType( TupleType(cls.params.mapKeys(some))(provTODO), ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) )(provTODO) - case TypedNuFun(fd, ty) => ??? + case TypedNuFun(fd, ty) => + println(fd, ty) + ??? } override def toString: String = s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index cdea95b4da..9695e6b345 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -5,25 +5,37 @@ // :d class Base1(base: int) { - fun getBase1(x) = base - fun getBase2(x) = this.base + fun getBase1 = base + fun getBase2 = this.base fun foo(x) = this.base + x } //│ ╔══[ERROR] identifier not found: this -//│ ║ l.9: fun getBase2(x) = this.base -//│ ╙── ^^^^ +//│ ║ l.9: fun getBase2 = this.base +//│ ╙── ^^^^ //│ ╔══[ERROR] identifier not found: this //│ ║ l.10: fun foo(x) = this.base + x //│ ╙── ^^^^ //│ class Base1 +//│ fun getBase1: ‹∀ 0. getBase126'#› where +//│ | getBase126'# := Int +//│ [pretty-printed] getBase1: int +//│ fun getBase2: ‹∀ 0. getBase227'#› where +//│ | getBase227'# := base28' +//│ | base28' :> error<> <: getBase227'# +//│ [pretty-printed] getBase2: error +//│ fun foo: ‹∀ 0. foo29'#› where +//│ | foo29'# := (α30' -> α33') +//│ | α30' <: int +//│ | α33' :> int +//│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b38'#› where -//│ | b38'# := α39' -//│ | α39' :> Base1<> <: b38'# +//│ fun b: ‹∀ 0. b42'#› where +//│ | b42'# := α43' +//│ | α43' :> Base1<> <: b42'# //│ [pretty-printed] b: Base1 b.base @@ -33,14 +45,14 @@ b.base // :d b.getBase1 //│ ╔══[ERROR] class `Base1` does not contain member `getBase1` -//│ ║ l.34: b.getBase1 +//│ ║ l.46: b.getBase1 //│ ╙── ^^^^^^^^^ //│ Typed: error :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.41: b.getBaseTypo +//│ ║ l.53: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -49,3 +61,11 @@ b : Base1 //│ Typed: Base1 +// TODO treat `a: int` as a signature +class Annots(base: 0 | 1) { + a: int + fun a = base +} +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 2be32afcbf..27a686e957 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -32,15 +32,15 @@ mixin BaseInc { :d class Base1(base: int): BaseTest //│ 0. Typing TypingUnit(List(class Base1(base: int,): BaseTest {})) -//│ | 0. Typing TypingUnit(List()) -//│ | List() -//│ | base: int, -//│ | List(BaseTest) //│ | Typing type int //│ | | vars=Map() newDefsInfo=Map() //│ | | 0. type int //│ | | => Int //│ | => Int ——— +//│ | 0. Typing TypingUnit(List()) +//│ | List() +//│ | base: int, +//│ | List(BaseTest) //│ | Inheriting from BaseTest //│ | | CONSTRAIN {base: Int} α31') -//│ | α26' <: z30' +//│ | α26' <: z29' //│ | α31' :> C<> //│ [pretty-printed] fooo: anything -> C +// :d +namespace Test0_1 { + fun a = Test0_2.b +} +namespace Test0_2 { + fun a = 123 +} +//│ ╔══[ERROR] namespace `Test0_2` does not contain member `b` +//│ ║ l.27: fun a = Test0_2.b +//│ ╙── ^^ +//│ class Test0_1 +//│ fun a: ‹∀ 0. a39'#› where +//│ | a39'# := b43' +//│ | b43' :> error<> | error<> <: a39'# +//│ [pretty-printed] a: error +//│ class Test0_2 +//│ fun a: ‹∀ 0. a41'#› where +//│ | a41'# := 123 +//│ [pretty-printed] a: 123 + +// :d +namespace Test1_1 { + fun a = Test1_2.b +} +namespace Test1_2 { + fun a = Test1_1.a +} +//│ ╔══[ERROR] namespace `Test1_2` does not contain member `b` +//│ ║ l.47: fun a = Test1_2.b +//│ ╙── ^^ +//│ class Test1_1 +//│ fun a: ‹∀ 0. a51'#› where +//│ | a51'# := b57' +//│ | b57' :> error<> | error<> <: a51'# +//│ [pretty-printed] a: error +//│ class Test1_2 +//│ fun a: ‹∀ 0. a53'#› where +//│ | a53'# := a54' +//│ | a54' :> a54_55 <: a53'# +//│ [pretty-printed] a: nothing + + +namespace Test2_1 { + fun t2 = Test2_2 + fun a = Test2_2.b + fun d = Test2_2.e +} +namespace Test2_2 { + fun b = 123 + fun c = Test2_1.a + fun e = Test2_1.d +} +//│ ╔══[ERROR] namespace `Test2_2` does not contain member `b` +//│ ║ l.69: fun a = Test2_2.b +//│ ╙── ^^ +//│ ╔══[ERROR] namespace `Test2_2` does not contain member `e` +//│ ║ l.70: fun d = Test2_2.e +//│ ╙── ^^ +//│ class Test2_1 +//│ fun t2: ‹∀ 0. t269'#› where +//│ | t269'# := Test2_2<> +//│ [pretty-printed] t2: Test2_2 +//│ fun a: ‹∀ 0. a81'#› where +//│ | a81'# := b82' +//│ | b82' :> error<> | error<> <: a81'# +//│ [pretty-printed] a: error +//│ fun d: ‹∀ 0. d83'#› where +//│ | d83'# := e84' +//│ | e84' :> error<> | error<> <: d83'# +//│ [pretty-printed] d: error +//│ class Test2_2 +//│ fun b: ‹∀ 0. b73'#› where +//│ | b73'# := 123 +//│ [pretty-printed] b: 123 +//│ fun c: ‹∀ 0. c74'#› where +//│ | c74'# := a75' +//│ | a75' :> a75_76 <: c74'# +//│ [pretty-printed] c: nothing +//│ fun e: ‹∀ 0. e77'#› where +//│ | e77'# := d78' +//│ | d78' :> d78_79 <: e77'# +//│ [pretty-printed] e: nothing + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index cfcb0abf09..362572b30a 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -498,6 +498,7 @@ class DiffTests ttu.entities.foreach { case tc: typer.TypedNuCls => output(s"${indStr}class ${tc.name}") + showTTU(tc.ttu, ind + 1) case tm: typer.TypedNuMxn => output(s"${indStr}mixin ${tm.name}") output(s"${indStr} this: ${tm.thisTV} ${tm.thisTV.showBounds From 2de28d1721b47639778911b4faecc4ee960eea91 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 16:31:10 +0800 Subject: [PATCH 009/498] WIP --- .../main/scala/mlscript/TyperDatatypes.scala | 182 +++++++++--------- shared/src/test/diff/nu/BasicClasses.mls | 18 +- shared/src/test/diff/nu/BasicMixins.mls | 38 ++-- shared/src/test/diff/nu/MutualRec.mls | 63 +++--- 4 files changed, 154 insertions(+), 147 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index dab92c64ec..b258ad9b83 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -75,97 +75,101 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case td: NuTypeDef => td.kind match { case Cls | Nms => - val typedParams = td.params.fields.map { - case (S(nme), Fld(mut, spec, value)) => - assert(!mut && !spec, "TODO") // TODO - value.toType match { - case R(tpe) => - implicit val vars: Map[Str, SimpleType] = Map.empty // TODO type params - implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? - val ty = typeType(tpe) - nme -> FieldType(N, ty)(provTODO) - case _ => ??? - } - case (N, Fld(mut, spec, nme: Var)) => - assert(!mut && !spec, "TODO") // TODO - nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) - case _ => ??? - } - // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) - ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) - - val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use - - // val ttu.entities.map { - // case fun @ TypedNuFun(fd, ty) => - // fun - // case _ => ??? - // } - - // TODO check against `tv` - println(td.tparams) - println(td.params) - println(td.parents) - implicit val prov: TP = - TypeProvenance(decl.toLoc, decl.describe) - val finalType = freshVar(noProv/*TODO*/, N, S("this")) - // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { - def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { - // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { - // case R(p) :: ps => ??? - // case L(p) :: ps => - case p :: ps => - val newMembs = trace(s"Inheriting from $p") { - p match { - case Var(nme) => - ctx.get(nme) match { - case S(lti: LazyTypeInfo) => - lti.complete().freshen match { - case mxn: TypedNuMxn => - // mxn.thisTV - // mxn.ttu.entities - // ??? - // val fresh = mxn.freshen - // println(fresh) - constrain(superType, mxn.superTV) - constrain(finalType, mxn.thisTV) - mxn.ttu.entities.map { - case fun @ TypedNuFun(fd, ty) => - fun - case _ => ??? - } - case cls: TypedNuCls => - ??? - case als: TypedNuAls => - // TODO dealias first? - err(msg"Cannot inherit from a type alias", p.toLoc) - Nil - case cls: TypedNuFun => - ??? - } - case S(_) => - err(msg"Cannot inherit from this", p.toLoc) - Nil - case N => - err(msg"Could not find definition `${nme}`", p.toLoc) - Nil - } - case _ => - err(msg"Illegal parent specification", p.toLoc) - Nil + implicit val prov: TP = noProv // TODO + ctx.nextLevel { implicit ctx => + + val typedParams = td.params.fields.map { + case (S(nme), Fld(mut, spec, value)) => + assert(!mut && !spec, "TODO") // TODO + value.toType match { + case R(tpe) => + implicit val vars: Map[Str, SimpleType] = Map.empty // TODO type params + implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? + val ty = typeType(tpe) + nme -> FieldType(N, ty)(provTODO) + case _ => ??? } - }() - val newSuperType = superType - inherit(ps, newSuperType, members ++ newMembs) - case Nil => - constrain(superType, finalType) - members + case (N, Fld(mut, spec, nme: Var)) => + assert(!mut && !spec, "TODO") // TODO + nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) + case _ => ??? + } + // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) + ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + + val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use + + // val ttu.entities.map { + // case fun @ TypedNuFun(fd, ty) => + // fun + // case _ => ??? + // } + + // TODO check against `tv` + println(td.tparams) + println(td.params) + println(td.parents) + implicit val prov: TP = + TypeProvenance(decl.toLoc, decl.describe) + val finalType = freshVar(noProv/*TODO*/, N, S("this")) + // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { + def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { + // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { + // case R(p) :: ps => ??? + // case L(p) :: ps => + case p :: ps => + val newMembs = trace(s"Inheriting from $p") { + p match { + case Var(nme) => + ctx.get(nme) match { + case S(lti: LazyTypeInfo) => + lti.complete().freshen match { + case mxn: TypedNuMxn => + // mxn.thisTV + // mxn.ttu.entities + // ??? + // val fresh = mxn.freshen + // println(fresh) + constrain(superType, mxn.superTV) + constrain(finalType, mxn.thisTV) + mxn.ttu.entities.map { + case fun @ TypedNuFun(fd, ty) => + fun + case _ => ??? + } + case cls: TypedNuCls => + ??? + case als: TypedNuAls => + // TODO dealias first? + err(msg"Cannot inherit from a type alias", p.toLoc) + Nil + case cls: TypedNuFun => + ??? + } + case S(_) => + err(msg"Cannot inherit from this", p.toLoc) + Nil + case N => + err(msg"Could not find definition `${nme}`", p.toLoc) + Nil + } + case _ => + err(msg"Illegal parent specification", p.toLoc) + Nil + } + }() + val newSuperType = superType + inherit(ps, newSuperType, members ++ newMembs) + case Nil => + constrain(superType, finalType) + members + } + val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) + val paramMems = typedParams.map(f => NuParam(f._1, f._2)) + val baseMems = inherit(td.parents, baseType, Nil) + val mems = baseMems ++ paramMems + TypedNuCls(td, ttu, typedParams, mems.map(d => d.name -> d).toMap) } - val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) - val paramMems = typedParams.map(f => NuParam(f._1, f._2)) - val baseMems = inherit(td.parents, baseType, Nil) - val mems = baseMems ++ paramMems - TypedNuCls(td, ttu, typedParams, mems.map(d => d.name -> d).toMap) case Mxn => implicit val prov: TP = noProv // TODO ctx.nextLevel { implicit ctx => diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 9695e6b345..41606afea9 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -16,17 +16,17 @@ class Base1(base: int) { //│ ║ l.10: fun foo(x) = this.base + x //│ ╙── ^^^^ //│ class Base1 -//│ fun getBase1: ‹∀ 0. getBase126'#› where -//│ | getBase126'# := Int +//│ fun getBase1: ‹∀ 1. getBase126''#› where +//│ | getBase126''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 0. getBase227'#› where -//│ | getBase227'# := base28' -//│ | base28' :> error<> <: getBase227'# +//│ fun getBase2: ‹∀ 1. getBase227''#› where +//│ | getBase227''# := base28'' +//│ | base28'' :> error<> <: getBase227''# //│ [pretty-printed] getBase2: error -//│ fun foo: ‹∀ 0. foo29'#› where -//│ | foo29'# := (α30' -> α33') -//│ | α30' <: int -//│ | α33' :> int +//│ fun foo: ‹∀ 1. foo29''#› where +//│ | foo29''# := (α30'' -> α33'') +//│ | α30'' <: int +//│ | α33'' :> int //│ [pretty-printed] foo: int -> int Base1 diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 27a686e957..4649211e04 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -34,10 +34,10 @@ class Base1(base: int): BaseTest //│ 0. Typing TypingUnit(List(class Base1(base: int,): BaseTest {})) //│ | Typing type int //│ | | vars=Map() newDefsInfo=Map() -//│ | | 0. type int +//│ | | 1. type int //│ | | => Int //│ | => Int ——— -//│ | 0. Typing TypingUnit(List()) +//│ | 1. Typing TypingUnit(List()) //│ | List() //│ | base: int, //│ | List(BaseTest) @@ -45,23 +45,27 @@ class Base1(base: int): BaseTest //│ | | CONSTRAIN {base: Int} α31') -//│ | α26' <: z29' //│ | α31' :> C<> //│ [pretty-printed] fooo: anything -> C @@ -30,16 +29,16 @@ namespace Test0_2 { fun a = 123 } //│ ╔══[ERROR] namespace `Test0_2` does not contain member `b` -//│ ║ l.27: fun a = Test0_2.b +//│ ║ l.26: fun a = Test0_2.b //│ ╙── ^^ //│ class Test0_1 -//│ fun a: ‹∀ 0. a39'#› where -//│ | a39'# := b43' -//│ | b43' :> error<> | error<> <: a39'# +//│ fun a: ‹∀ 1. a38''#› where +//│ | a38''# := b42'' +//│ | b42'' :> error<> | error<> <: a38''# //│ [pretty-printed] a: error //│ class Test0_2 -//│ fun a: ‹∀ 0. a41'#› where -//│ | a41'# := 123 +//│ fun a: ‹∀ 1. a40''#› where +//│ | a40''# := 123 //│ [pretty-printed] a: 123 // :d @@ -50,17 +49,17 @@ namespace Test1_2 { fun a = Test1_1.a } //│ ╔══[ERROR] namespace `Test1_2` does not contain member `b` -//│ ║ l.47: fun a = Test1_2.b +//│ ║ l.46: fun a = Test1_2.b //│ ╙── ^^ //│ class Test1_1 -//│ fun a: ‹∀ 0. a51'#› where -//│ | a51'# := b57' -//│ | b57' :> error<> | error<> <: a51'# +//│ fun a: ‹∀ 1. a50''#› where +//│ | a50''# := b56'' +//│ | b56'' :> error<> | error<> <: a50''# //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun a: ‹∀ 0. a53'#› where -//│ | a53'# := a54' -//│ | a54' :> a54_55 <: a53'# +//│ fun a: ‹∀ 1. a52''#› where +//│ | a52''# := a53'' +//│ | a53'' :> a53_54 <: a52''# //│ [pretty-printed] a: nothing @@ -75,34 +74,34 @@ namespace Test2_2 { fun e = Test2_1.d } //│ ╔══[ERROR] namespace `Test2_2` does not contain member `b` -//│ ║ l.69: fun a = Test2_2.b +//│ ║ l.68: fun a = Test2_2.b //│ ╙── ^^ //│ ╔══[ERROR] namespace `Test2_2` does not contain member `e` -//│ ║ l.70: fun d = Test2_2.e +//│ ║ l.69: fun d = Test2_2.e //│ ╙── ^^ //│ class Test2_1 -//│ fun t2: ‹∀ 0. t269'#› where -//│ | t269'# := Test2_2<> +//│ fun t2: ‹∀ 1. t268''#› where +//│ | t268''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 0. a81'#› where -//│ | a81'# := b82' -//│ | b82' :> error<> | error<> <: a81'# +//│ fun a: ‹∀ 1. a80''#› where +//│ | a80''# := b81'' +//│ | b81'' :> error<> | error<> <: a80''# //│ [pretty-printed] a: error -//│ fun d: ‹∀ 0. d83'#› where -//│ | d83'# := e84' -//│ | e84' :> error<> | error<> <: d83'# +//│ fun d: ‹∀ 1. d82''#› where +//│ | d82''# := e83'' +//│ | e83'' :> error<> | error<> <: d82''# //│ [pretty-printed] d: error //│ class Test2_2 -//│ fun b: ‹∀ 0. b73'#› where -//│ | b73'# := 123 +//│ fun b: ‹∀ 1. b72''#› where +//│ | b72''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 0. c74'#› where -//│ | c74'# := a75' -//│ | a75' :> a75_76 <: c74'# +//│ fun c: ‹∀ 1. c73''#› where +//│ | c73''# := a74'' +//│ | a74'' :> a74_75 <: c73''# //│ [pretty-printed] c: nothing -//│ fun e: ‹∀ 0. e77'#› where -//│ | e77'# := d78' -//│ | d78' :> d78_79 <: e77'# +//│ fun e: ‹∀ 1. e76''#› where +//│ | e76''# := d77'' +//│ | d77'' :> d77_78 <: e76''# //│ [pretty-printed] e: nothing From 945d5e7c5fc97423087e4c1b2da888a9ac04de1b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 17:08:46 +0800 Subject: [PATCH 010/498] WIP --- .../src/main/scala/mlscript/NuTypeDefs.scala | 47 +++++++--- .../main/scala/mlscript/TyperDatatypes.scala | 29 +++++-- shared/src/test/diff/nu/BasicClasses.mls | 67 ++++++++++----- shared/src/test/diff/nu/BasicMixins.mls | 77 ++++++++--------- shared/src/test/diff/nu/MutualRec.mls | 86 +++++++++++-------- .../src/test/scala/mlscript/DiffTests.scala | 2 +- 6 files changed, 186 insertions(+), 122 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index cc1c0236e8..f833368aeb 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -33,19 +33,38 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed abstract class TypedNuDecl extends NuMember { def name: Str - def freshen(implicit ctx: Ctx): TypedNuDecl = this match { - case m @ TypedNuMxn(td, thisTV, superTV, ttu) => - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify = false)) - case _ => ??? - } + // def freshen(implicit ctx: Ctx): TypedNuDecl = this match { + // case m @ TypedNuMxn(td, thisTV, superTV, ttu) => + // implicit val freshened: MutMap[TV, ST] = MutMap.empty + // implicit val shadows: Shadows = Shadows.empty + // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify = false)) + // case _ => ??? + // } } sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { override def toString: String = this match { case _ => ??? } + def level: Level + def freshen(implicit ctx: Ctx): TypedNuDecl = { + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + freshenAbove(level, rigidify = false) + } + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + : TypedNuTermDef = { + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + this match { + case m @ TypedNuMxn(td, thisTV, superTV, ttu) => + TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) + case TypedNuFun(level, fd, ty) => + TypedNuFun(level, fd, ty.freshenAbove(level, rigidify)) + // case _ => ??? + } + } } sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { @@ -66,7 +85,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { - case class TypedNuCls(td: NuTypeDef, ttu: TypedTypingUnit, params: Ls[Var -> FieldType], + case class TypedNuCls(level: Level, td: NuTypeDef, ttu: TypedTypingUnit, params: Ls[Var -> FieldType], // members: Map[Str, LazyTypeInfo]) members: Map[Str, NuMember]) extends TypedNuTypeDef(Cls) with TypedNuTermDef { @@ -82,16 +101,17 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // def freshen(implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, } - case class TypedNuFun(fd: NuFunDef, ty: ST) extends TypedNuDecl with TypedNuTermDef { + case class TypedNuFun(level: Level, fd: NuFunDef, ty: ST) extends TypedNuDecl with TypedNuTermDef { def name: Str = fd.nme.name } - case class TypedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) { + case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) { // def freshen(implicit ctx: Ctx): TypedTypingUnit = ??? def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = - TypedTypingUnit(entities, result.map(_.freshenAbove(lim, rigidify))) + TypedTypingUnit(entities.map(_.map(_.freshenAbove(lim, rigidify))) + , result.map(_.freshenAbove(lim, rigidify))) } def typeTypingUnit(tu: TypingUnit, allowPure: Bool)(implicit ctx: Ctx, raise: Raise): TypedTypingUnit = @@ -144,7 +164,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case decl: NuDecl => val lti = named.getOrElse(decl.name, die) // completeTypeInfo() - lti.complete() + // lti.complete() // ??? // UnitType N // case ds: DesugaredStatement => @@ -171,7 +191,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val res_ty = go(tu.entities) // TypedTypingUnit(infos.unzip._2.map(_.complete()), S(res_ty)) - TypedTypingUnit(infos.unzip._2.map(_.complete()), res_ty) + // TypedTypingUnit(infos.unzip._2.map(_.complete()), res_ty) + TypedTypingUnit(infos.unzip._2, res_ty) }() // }(raise, noProv/*TODO*/)}() diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index b258ad9b83..c6c6de4d48 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -41,8 +41,15 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), N, S(decl.name))(level) + + def map(f: TypedNuTermDef => TypedNuTermDef): LazyTypeInfo = { + val res = new LazyTypeInfo(level, decl) + // if (result.nonEmpty) res.result = res + res.result = result.map(f) + res + } def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { - if (isComputing) lastWords(s"TODO cyclic defn") + if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") else { // var res: ST = errType val res = try { @@ -56,19 +63,19 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case R(PolyType(tps, ty)) => // val body_ty = typeType(ty)(ctx.nextLevel, raise, // vars = tps.map(tp => tp.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) - val body_ty = ctx.nextLevel { implicit ctx: Ctx => + val body_ty = ctx.nextLevel { implicit ctx: Ctx => // TODO use poly instead! typeType(ty)(ctx, raise, vars = tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) } // TODO check against `tv` - TypedNuFun(fd, PolymorphicType(ctx.lvl, body_ty)) + TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) case L(body) => implicit val vars: Map[Str, SimpleType] = Map.empty implicit val gl: GenLambdas = true val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) // implicit val prov: TP = noProv // TODO // subsume(body_ty, PolymorphicType(level, tv)) // TODO - TypedNuFun(fd, body_ty) + TypedNuFun(ctx.lvl, fd, body_ty) } // subsume(res_ty, tv) res_ty @@ -97,6 +104,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + ctx += "this" -> VarSymbol( + ClassTag(Var(td.name), + Set.empty//TODO + )(provTODO), + Var("this")) + val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use // val ttu.entities.map { @@ -132,8 +145,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // println(fresh) constrain(superType, mxn.superTV) constrain(finalType, mxn.thisTV) - mxn.ttu.entities.map { - case fun @ TypedNuFun(fd, ty) => + mxn.ttu.entities.map(_.complete()).map { + case fun @ TypedNuFun(_, fd, ty) => fun case _ => ??? } @@ -168,7 +181,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val paramMems = typedParams.map(f => NuParam(f._1, f._2)) val baseMems = inherit(td.parents, baseType, Nil) val mems = baseMems ++ paramMems - TypedNuCls(td, ttu, typedParams, mems.map(d => d.name -> d).toMap) + TypedNuCls(ctx.lvl, td, ttu, typedParams, mems.map(d => d.name -> d).toMap) } case Mxn => implicit val prov: TP = noProv // TODO @@ -202,7 +215,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => TupleType(cls.params.mapKeys(some))(provTODO), ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) )(provTODO) - case TypedNuFun(fd, ty) => + case TypedNuFun(_, fd, ty) => println(fd, ty) ??? } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 41606afea9..d3567d27de 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -3,39 +3,62 @@ :NoJS -// :d +// TODO +class Base0(n) { + fun me = this + fun my = this.n + fun mine = my + fun oops = this.my +} +//│ class Base0 +//│ ╔══[ERROR] class `Base0` does not contain member `my` +//│ ║ l.11: fun oops = this.my +//│ ╙── ^^^ +//│ fun me: ‹∀ 1. me29''#› where +//│ | me29''# := Base0<> +//│ [pretty-printed] me: Base0 +//│ fun my: ‹∀ 1. my30''#› where +//│ | my30''# := n31'' +//│ | n31'' :> n23' <: mine32''# & my30''# +//│ | mine32''# := my30''# +//│ [pretty-printed] my: nothing +//│ fun mine: ‹∀ 1. mine32''#› where +//│ | my30''# := n31'' +//│ | n31'' :> n23' <: mine32''# & my30''# +//│ | mine32''# := my30''# +//│ [pretty-printed] mine: nothing +//│ fun oops: ‹∀ 1. oops33''#› where +//│ | oops33''# := my34'' +//│ | my34'' :> error<> | error<> <: oops33''# +//│ [pretty-printed] oops: error + + class Base1(base: int) { fun getBase1 = base fun getBase2 = this.base fun foo(x) = this.base + x } -//│ ╔══[ERROR] identifier not found: this -//│ ║ l.9: fun getBase2 = this.base -//│ ╙── ^^^^ -//│ ╔══[ERROR] identifier not found: this -//│ ║ l.10: fun foo(x) = this.base + x -//│ ╙── ^^^^ //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase126''#› where -//│ | getBase126''# := Int +//│ fun getBase1: ‹∀ 1. getBase150''#› where +//│ | getBase150''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase227''#› where -//│ | getBase227''# := base28'' -//│ | base28'' :> error<> <: getBase227''# -//│ [pretty-printed] getBase2: error -//│ fun foo: ‹∀ 1. foo29''#› where -//│ | foo29''# := (α30'' -> α33'') -//│ | α30'' <: int -//│ | α33'' :> int +//│ fun getBase2: ‹∀ 1. getBase251''#› where +//│ | getBase251''# := base52'' +//│ | base52'' :> Int <: getBase251''# +//│ [pretty-printed] getBase2: int +//│ fun foo: ‹∀ 1. foo53''#› where +//│ | foo53''# := (α54'' -> α57'') +//│ | α54'' <: int +//│ | α57'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b42'#› where -//│ | b42'# := α43' -//│ | α43' :> Base1<> <: b42'# +//│ fun b: ‹∀ 0. b65'#› where +//│ | b65'# := α66' +//│ | α66' :> Base1<> <: b65'# //│ [pretty-printed] b: Base1 b.base @@ -45,14 +68,14 @@ b.base // :d b.getBase1 //│ ╔══[ERROR] class `Base1` does not contain member `getBase1` -//│ ║ l.46: b.getBase1 +//│ ║ l.69: b.getBase1 //│ ╙── ^^^^^^^^^ //│ Typed: error :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.53: b.getBaseTypo +//│ ║ l.76: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 4649211e04..13c61e0a2a 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -10,7 +10,6 @@ mixin BaseTest { //│ mixin BaseTest //│ this: this23' //│ super: super24' -//│ | super24' <: {base: base27_28'} //│ fun test: ‹∀ 1. test26''#› where //│ | test26''# := base27'' //│ | base27'' :> base27_28' <: test26''# @@ -22,8 +21,6 @@ mixin BaseInc { //│ mixin BaseInc //│ this: this33' //│ super: super34' -//│ | super34' <: {base: base37_38'} -//│ | base37_38' <: int //│ fun test: ‹∀ 1. test36''#› where //│ | test36''# := α40'' //│ | α40'' :> int <: test36''# @@ -32,40 +29,40 @@ mixin BaseInc { :d class Base1(base: int): BaseTest //│ 0. Typing TypingUnit(List(class Base1(base: int,): BaseTest {})) -//│ | Typing type int -//│ | | vars=Map() newDefsInfo=Map() -//│ | | 1. type int -//│ | | => Int -//│ | => Int ——— -//│ | 1. Typing TypingUnit(List()) -//│ | List() -//│ | base: int, -//│ | List(BaseTest) -//│ | Inheriting from BaseTest -//│ | | CONSTRAIN {base: Int} Int +//│ => Int ——— +//│ 1. Typing TypingUnit(List()) +//│ List() +//│ base: int, +//│ List(BaseTest) +//│ Inheriting from BaseTest +//│ | CONSTRAIN {base: Int} -//│ fun test: ‹∀ 1. test56''#› where -//│ | test56''# := (α57'' -> (α61'', α57'', misc62'',)) -//│ | α57'' <: int -//│ | α61'' :> int -//│ | misc62'' :> misc62_63' +//│ this: this56' +//│ super: super57' +//│ fun test: ‹∀ 1. test59''#› where +//│ | test59''# := (α60'' -> (α64'', α60'', misc65'',)) +//│ | α60'' <: int +//│ | α64'' :> int +//│ | misc65'' :> misc65_66' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index b82170e0d8..9d523a09bd 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -21,6 +21,7 @@ fun fooo(x) = +// TODO // :d namespace Test0_1 { fun a = Test0_2.b @@ -28,19 +29,20 @@ namespace Test0_1 { namespace Test0_2 { fun a = 123 } +//│ class Test0_1 //│ ╔══[ERROR] namespace `Test0_2` does not contain member `b` -//│ ║ l.26: fun a = Test0_2.b +//│ ║ l.27: fun a = Test0_2.b //│ ╙── ^^ -//│ class Test0_1 -//│ fun a: ‹∀ 1. a38''#› where -//│ | a38''# := b42'' -//│ | b42'' :> error<> | error<> <: a38''# +//│ fun a: ‹∀ 1. a41''#› where +//│ | a41''# := b42'' +//│ | b42'' :> error<> | error<> <: a41''# //│ [pretty-printed] a: error //│ class Test0_2 -//│ fun a: ‹∀ 1. a40''#› where -//│ | a40''# := 123 +//│ fun a: ‹∀ 1. a45''#› where +//│ | a45''# := 123 //│ [pretty-printed] a: 123 +// TODO // :d namespace Test1_1 { fun a = Test1_2.b @@ -48,21 +50,25 @@ namespace Test1_1 { namespace Test1_2 { fun a = Test1_1.a } +//│ class Test1_1 //│ ╔══[ERROR] namespace `Test1_2` does not contain member `b` -//│ ║ l.46: fun a = Test1_2.b +//│ ║ l.48: fun a = Test1_2.b //│ ╙── ^^ -//│ class Test1_1 -//│ fun a: ‹∀ 1. a50''#› where -//│ | a50''# := b56'' -//│ | b56'' :> error<> | error<> <: a50''# +//│ fun a: ‹∀ 1. a53''#› where +//│ | a53''# := b54'' +//│ | b54'' :> error<> | error<> <: a53''# //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun a: ‹∀ 1. a52''#› where -//│ | a52''# := a53'' -//│ | a53'' :> a53_54 <: a52''# -//│ [pretty-printed] a: nothing +//│ ╔══[ERROR] namespace `Test1_1` does not contain member `a` +//│ ║ l.51: fun a = Test1_1.a +//│ ╙── ^^ +//│ fun a: ‹∀ 1. a57''#› where +//│ | a57''# := a58'' +//│ | a58'' :> error<> | error<> <: a57''# +//│ [pretty-printed] a: error +// TODO namespace Test2_1 { fun t2 = Test2_2 fun a = Test2_2.b @@ -73,35 +79,41 @@ namespace Test2_2 { fun c = Test2_1.a fun e = Test2_1.d } +//│ class Test2_1 //│ ╔══[ERROR] namespace `Test2_2` does not contain member `b` -//│ ║ l.68: fun a = Test2_2.b +//│ ║ l.74: fun a = Test2_2.b //│ ╙── ^^ //│ ╔══[ERROR] namespace `Test2_2` does not contain member `e` -//│ ║ l.69: fun d = Test2_2.e +//│ ║ l.75: fun d = Test2_2.e //│ ╙── ^^ -//│ class Test2_1 -//│ fun t2: ‹∀ 1. t268''#› where -//│ | t268''# := Test2_2<> +//│ fun t2: ‹∀ 1. t271''#› where +//│ | t271''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a80''#› where -//│ | a80''# := b81'' -//│ | b81'' :> error<> | error<> <: a80''# +//│ fun a: ‹∀ 1. a72''#› where +//│ | a72''# := b73'' +//│ | b73'' :> error<> | error<> <: a72''# //│ [pretty-printed] a: error -//│ fun d: ‹∀ 1. d82''#› where -//│ | d82''# := e83'' -//│ | e83'' :> error<> | error<> <: d82''# +//│ fun d: ‹∀ 1. d74''#› where +//│ | d74''# := e75'' +//│ | e75'' :> error<> | error<> <: d74''# //│ [pretty-printed] d: error //│ class Test2_2 -//│ fun b: ‹∀ 1. b72''#› where -//│ | b72''# := 123 +//│ ╔══[ERROR] namespace `Test2_1` does not contain member `a` +//│ ║ l.79: fun c = Test2_1.a +//│ ╙── ^^ +//│ ╔══[ERROR] namespace `Test2_1` does not contain member `d` +//│ ║ l.80: fun e = Test2_1.d +//│ ╙── ^^ +//│ fun b: ‹∀ 1. b81''#› where +//│ | b81''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c73''#› where -//│ | c73''# := a74'' -//│ | a74'' :> a74_75 <: c73''# -//│ [pretty-printed] c: nothing -//│ fun e: ‹∀ 1. e76''#› where -//│ | e76''# := d77'' -//│ | d77'' :> d77_78 <: e76''# -//│ [pretty-printed] e: nothing +//│ fun c: ‹∀ 1. c82''#› where +//│ | c82''# := a83'' +//│ | a83'' :> error<> | error<> <: c82''# +//│ [pretty-printed] c: error +//│ fun e: ‹∀ 1. e84''#› where +//│ | e84''# := d85'' +//│ | d85'' :> error<> | error<> <: e84''# +//│ [pretty-printed] e: error diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 362572b30a..0d83c26575 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -495,7 +495,7 @@ class DiffTests def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind - ttu.entities.foreach { + ttu.entities.map(_.complete()(raise)).foreach { case tc: typer.TypedNuCls => output(s"${indStr}class ${tc.name}") showTTU(tc.ttu, ind + 1) From 3a6f06102869119f076bae6a8bc6e8ef747b4711 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 17:13:53 +0800 Subject: [PATCH 011/498] WIP force --- .../src/main/scala/mlscript/NuTypeDefs.scala | 8 +++ .../main/scala/mlscript/TyperDatatypes.scala | 3 + shared/src/test/diff/nu/BasicClasses.mls | 2 +- shared/src/test/diff/nu/BasicMixins.mls | 9 ++- shared/src/test/diff/nu/MutualRec.mls | 64 +++++++++---------- .../src/test/scala/mlscript/DiffTests.scala | 2 + 6 files changed, 53 insertions(+), 35 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index f833368aeb..5a39f655b9 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -65,6 +65,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // case _ => ??? } } + def force()(implicit raise: Raise): Unit = this match { + case x: TypedNuMxn => x.ttu.force() + case x: TypedNuCls => x.ttu.force() + case _: TypedNuFun => () + } } sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { @@ -112,6 +117,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => : TypedTypingUnit = TypedTypingUnit(entities.map(_.map(_.freshenAbove(lim, rigidify))) , result.map(_.freshenAbove(lim, rigidify))) + def force()(implicit raise: Raise): Unit = { + entities.foreach(_.force()) + } } def typeTypingUnit(tu: TypingUnit, allowPure: Bool)(implicit ctx: Ctx, raise: Raise): TypedTypingUnit = diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c6c6de4d48..ef8daf0899 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -219,6 +219,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => println(fd, ty) ??? } + def force()(implicit raise: Raise): Unit = { + complete().force() + } override def toString: String = s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index d3567d27de..520c71fd7f 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -10,10 +10,10 @@ class Base0(n) { fun mine = my fun oops = this.my } -//│ class Base0 //│ ╔══[ERROR] class `Base0` does not contain member `my` //│ ║ l.11: fun oops = this.my //│ ╙── ^^^ +//│ class Base0 //│ fun me: ‹∀ 1. me29''#› where //│ | me29''# := Base0<> //│ [pretty-printed] me: Base0 diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 13c61e0a2a..b72d83bc06 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -10,6 +10,7 @@ mixin BaseTest { //│ mixin BaseTest //│ this: this23' //│ super: super24' +//│ | super24' <: {base: base27_28'} //│ fun test: ‹∀ 1. test26''#› where //│ | test26''# := base27'' //│ | base27'' :> base27_28' <: test26''# @@ -21,6 +22,8 @@ mixin BaseInc { //│ mixin BaseInc //│ this: this33' //│ super: super34' +//│ | super34' <: {base: base37_38'} +//│ | base37_38' <: int //│ fun test: ‹∀ 1. test36''#› where //│ | test36''# := α40'' //│ | α40'' :> int <: test36''# @@ -72,10 +75,10 @@ class Base1(base): BaseTest :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.73: class Base1(x): BaseTest +//│ ║ l.76: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.73: class Base1(x): BaseTest +//│ ║ l.76: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -96,6 +99,8 @@ mixin Foo { //│ mixin Foo //│ this: this56' //│ super: super57' +//│ | super57' <: {misc: misc65_66'} & {base: base61_62'} +//│ | base61_62' <: int //│ fun test: ‹∀ 1. test59''#› where //│ | test59''# := (α60'' -> (α64'', α60'', misc65'',)) //│ | α60'' <: int diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 9d523a09bd..66d6c738da 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -29,17 +29,17 @@ namespace Test0_1 { namespace Test0_2 { fun a = 123 } -//│ class Test0_1 //│ ╔══[ERROR] namespace `Test0_2` does not contain member `b` //│ ║ l.27: fun a = Test0_2.b //│ ╙── ^^ -//│ fun a: ‹∀ 1. a41''#› where -//│ | a41''# := b42'' -//│ | b42'' :> error<> | error<> <: a41''# +//│ class Test0_1 +//│ fun a: ‹∀ 1. a39''#› where +//│ | a39''# := b42'' +//│ | b42'' :> error<> | error<> <: a39''# //│ [pretty-printed] a: error //│ class Test0_2 -//│ fun a: ‹∀ 1. a45''#› where -//│ | a45''# := 123 +//│ fun a: ‹∀ 1. a43''#› where +//│ | a43''# := 123 //│ [pretty-printed] a: 123 // TODO @@ -50,21 +50,21 @@ namespace Test1_1 { namespace Test1_2 { fun a = Test1_1.a } -//│ class Test1_1 //│ ╔══[ERROR] namespace `Test1_2` does not contain member `b` //│ ║ l.48: fun a = Test1_2.b //│ ╙── ^^ -//│ fun a: ‹∀ 1. a53''#› where -//│ | a53''# := b54'' -//│ | b54'' :> error<> | error<> <: a53''# -//│ [pretty-printed] a: error -//│ class Test1_2 //│ ╔══[ERROR] namespace `Test1_1` does not contain member `a` //│ ║ l.51: fun a = Test1_1.a //│ ╙── ^^ -//│ fun a: ‹∀ 1. a57''#› where -//│ | a57''# := a58'' -//│ | a58'' :> error<> | error<> <: a57''# +//│ class Test1_1 +//│ fun a: ‹∀ 1. a51''#› where +//│ | a51''# := b54'' +//│ | b54'' :> error<> | error<> <: a51''# +//│ [pretty-printed] a: error +//│ class Test1_2 +//│ fun a: ‹∀ 1. a55''#› where +//│ | a55''# := a56'' +//│ | a56'' :> error<> | error<> <: a55''# //│ [pretty-printed] a: error @@ -79,15 +79,21 @@ namespace Test2_2 { fun c = Test2_1.a fun e = Test2_1.d } -//│ class Test2_1 //│ ╔══[ERROR] namespace `Test2_2` does not contain member `b` //│ ║ l.74: fun a = Test2_2.b //│ ╙── ^^ //│ ╔══[ERROR] namespace `Test2_2` does not contain member `e` //│ ║ l.75: fun d = Test2_2.e //│ ╙── ^^ -//│ fun t2: ‹∀ 1. t271''#› where -//│ | t271''# := Test2_2<> +//│ ╔══[ERROR] namespace `Test2_1` does not contain member `a` +//│ ║ l.79: fun c = Test2_1.a +//│ ╙── ^^ +//│ ╔══[ERROR] namespace `Test2_1` does not contain member `d` +//│ ║ l.80: fun e = Test2_1.d +//│ ╙── ^^ +//│ class Test2_1 +//│ fun t2: ‹∀ 1. t267''#› where +//│ | t267''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 //│ fun a: ‹∀ 1. a72''#› where //│ | a72''# := b73'' @@ -98,22 +104,16 @@ namespace Test2_2 { //│ | e75'' :> error<> | error<> <: d74''# //│ [pretty-printed] d: error //│ class Test2_2 -//│ ╔══[ERROR] namespace `Test2_1` does not contain member `a` -//│ ║ l.79: fun c = Test2_1.a -//│ ╙── ^^ -//│ ╔══[ERROR] namespace `Test2_1` does not contain member `d` -//│ ║ l.80: fun e = Test2_1.d -//│ ╙── ^^ -//│ fun b: ‹∀ 1. b81''#› where -//│ | b81''# := 123 +//│ fun b: ‹∀ 1. b76''#› where +//│ | b76''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c82''#› where -//│ | c82''# := a83'' -//│ | a83'' :> error<> | error<> <: c82''# +//│ fun c: ‹∀ 1. c77''#› where +//│ | c77''# := a78'' +//│ | a78'' :> error<> | error<> <: c77''# //│ [pretty-printed] c: error -//│ fun e: ‹∀ 1. e84''#› where -//│ | e84''# := d85'' -//│ | d85'' :> error<> | error<> <: e84''# +//│ fun e: ‹∀ 1. e79''#› where +//│ | e79''# := d80'' +//│ | d80'' :> error<> | error<> <: e79''# //│ [pretty-printed] e: error diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 0d83c26575..9f609d3ed1 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -493,6 +493,8 @@ class DiffTests val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise) + tpd.force()(raise) + def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind ttu.entities.map(_.complete()(raise)).foreach { From 2a5af67701c4ef740e6a418727a2e0b18c3f97de Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 17:28:43 +0800 Subject: [PATCH 012/498] WIP minor --- .../scala/mlscript/ConstraintSolver.scala | 7 ++- .../main/scala/mlscript/TyperDatatypes.scala | 8 +-- shared/src/test/diff/nu/BasicClasses.mls | 7 ++- shared/src/test/diff/nu/BasicMixins.mls | 59 ++++++++++--------- 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 24410a047a..86ea9e24e2 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -558,10 +558,13 @@ class ConstraintSolver extends NormalForms { self: Typer => case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => def lookupNuTypeDef(clsNme: Str): TypedNuCls = { - ctx.tyDefs2(clsNme).complete() match { + val info = ctx.tyDefs2(clsNme) + Option.when(info.isComputing) { + ??? + }.getOrElse { info.complete() match { case td: TypedNuCls => td case _ => ??? - } + }} } def lookupNuTypeDefField(cls: TypedNuCls, rfnt: Map[Var, Field], fld: Var): FieldType = { println(fld.name, cls.members) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index ef8daf0899..1a2db6b3ff 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -50,7 +50,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") - else { + else trace(s"Completing ${decl}") { // var res: ST = errType val res = try { isComputing = true @@ -112,8 +112,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use - // val ttu.entities.map { - // case fun @ TypedNuFun(fd, ty) => + // val clsMems = ttu.entities.map(_.complete()).map { + // case fun @ TypedNuFun(_, fd, ty) => // fun // case _ => ??? // } @@ -205,7 +205,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => result = S(res) res - } + }() } def typeSignature(implicit raise: Raise): ST = if (isComputing) tv else complete() match { case cls: TypedNuCls if cls.td.kind is Nms => diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 520c71fd7f..b26db1572c 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -4,6 +4,7 @@ // TODO +// :d class Base0(n) { fun me = this fun my = this.n @@ -11,7 +12,7 @@ class Base0(n) { fun oops = this.my } //│ ╔══[ERROR] class `Base0` does not contain member `my` -//│ ║ l.11: fun oops = this.my +//│ ║ l.12: fun oops = this.my //│ ╙── ^^^ //│ class Base0 //│ fun me: ‹∀ 1. me29''#› where @@ -68,14 +69,14 @@ b.base // :d b.getBase1 //│ ╔══[ERROR] class `Base1` does not contain member `getBase1` -//│ ║ l.69: b.getBase1 +//│ ║ l.70: b.getBase1 //│ ╙── ^^^^^^^^^ //│ Typed: error :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.76: b.getBaseTypo +//│ ║ l.77: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index b72d83bc06..fb4109129b 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -32,40 +32,41 @@ mixin BaseInc { :d class Base1(base: int): BaseTest //│ 0. Typing TypingUnit(List(class Base1(base: int,): BaseTest {})) -//│ Typing type int -//│ | vars=Map() newDefsInfo=Map() -//│ | 1. type int -//│ | => Int -//│ => Int ——— -//│ 1. Typing TypingUnit(List()) -//│ List() -//│ base: int, -//│ List(BaseTest) -//│ Inheriting from BaseTest -//│ | CONSTRAIN {base: Int} Int +//│ | => Int ——— +//│ | 1. Typing TypingUnit(List()) +//│ | List() +//│ | base: int, +//│ | List(BaseTest) +//│ | Inheriting from BaseTest +//│ | | CONSTRAIN {base: Int} Date: Thu, 16 Feb 2023 17:49:50 +0800 Subject: [PATCH 013/498] WIP --- .../scala/mlscript/ConstraintSolver.scala | 8 +- .../main/scala/mlscript/TyperDatatypes.scala | 55 ++++++++++--- shared/src/test/diff/nu/BasicClasses.mls | 78 +++++++++++------- shared/src/test/diff/nu/BasicMixins.mls | 42 +++++----- shared/src/test/diff/nu/MutualRec.mls | 79 ++++++++----------- 5 files changed, 155 insertions(+), 107 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 86ea9e24e2..b2b2ce0290 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -559,9 +559,11 @@ class ConstraintSolver extends NormalForms { self: Typer => case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => def lookupNuTypeDef(clsNme: Str): TypedNuCls = { val info = ctx.tyDefs2(clsNme) - Option.when(info.isComputing) { - ??? - }.getOrElse { info.complete() match { + + // Option.when(info.isComputing) { + // ??? + // }.getOrElse + { info.complete() match { case td: TypedNuCls => td case _ => ??? }} diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 1a2db6b3ff..2d30c9fb65 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -48,6 +48,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => res.result = result.map(f) res } + private lazy val thisTV: TV = freshVar(noProv/*FIXME*/, N, S("this")) def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") else trace(s"Completing ${decl}") { @@ -104,19 +105,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) - ctx += "this" -> VarSymbol( - ClassTag(Var(td.name), - Set.empty//TODO - )(provTODO), - Var("this")) + // ctx += "this" -> VarSymbol( + // ClassTag(Var(td.name), + // Set.empty//TODO + // )(provTODO), + // Var("this")) - val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use - - // val clsMems = ttu.entities.map(_.complete()).map { - // case fun @ TypedNuFun(_, fd, ty) => - // fun - // case _ => ??? - // } + // val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) + ctx += "this" -> VarSymbol(thisTV, Var("this")) // TODO check against `tv` println(td.tparams) @@ -180,6 +176,25 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) val paramMems = typedParams.map(f => NuParam(f._1, f._2)) val baseMems = inherit(td.parents, baseType, Nil) + + // ctx += thisTV + + // TODO + // ctx += "super" -> VarSymbol(superTV, Var("super")) + + val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use + + val clsMems = ttu.entities.map(_.complete()).map { + case fun @ TypedNuFun(_, fd, ty) => + fun + case _ => ??? + } + + // val thisTy = ClassTag(Var(td.name), + // Set.empty//TODO + // )(provTODO) + // constrain(thisTy, thisTV) + val mems = baseMems ++ paramMems TypedNuCls(ctx.lvl, td, ttu, typedParams, mems.map(d => d.name -> d).toMap) } @@ -207,7 +222,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => }() } - def typeSignature(implicit raise: Raise): ST = if (isComputing) tv else complete() match { + def typeSignature(implicit raise: Raise): ST = if (isComputing) tv // FIXME wrong in general + else complete() match { case cls: TypedNuCls if cls.td.kind is Nms => ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) case cls: TypedNuCls => @@ -221,6 +237,19 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } def force()(implicit raise: Raise): Unit = { complete().force() + decl match { + case td: NuTypeDef => + td.kind match { + case Cls | Nms => + implicit val prov: TP = noProv // TODO + val thisTy = ClassTag(Var(td.name), + Set.empty//TODO + )(provTODO) + constrain(thisTy, thisTV) + case _ => + } + case _ => + } } override def toString: String = s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index b26db1572c..30b0062dab 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -15,51 +15,73 @@ class Base0(n) { //│ ║ l.12: fun oops = this.my //│ ╙── ^^^ //│ class Base0 -//│ fun me: ‹∀ 1. me29''#› where -//│ | me29''# := Base0<> +//│ fun me: ‹∀ 1. me30''#› where +//│ | this24 :> Base0<> <: {my: my36_37} & {n: n32_33} +//│ | me30''# := this24 +//│ | my36_37 :> error<> //│ [pretty-printed] me: Base0 -//│ fun my: ‹∀ 1. my30''#› where -//│ | my30''# := n31'' -//│ | n31'' :> n23' <: mine32''# & my30''# -//│ | mine32''# := my30''# +//│ fun my: ‹∀ 1. my31''#› where +//│ | my31''# := n32'' +//│ | n32'' :> n32_33 <: mine34''# & my31''# +//│ | mine34''# := my31''# //│ [pretty-printed] my: nothing -//│ fun mine: ‹∀ 1. mine32''#› where -//│ | my30''# := n31'' -//│ | n31'' :> n23' <: mine32''# & my30''# -//│ | mine32''# := my30''# +//│ fun mine: ‹∀ 1. mine34''#› where +//│ | my31''# := n32'' +//│ | n32'' :> n32_33 <: mine34''# & my31''# +//│ | mine34''# := my31''# //│ [pretty-printed] mine: nothing -//│ fun oops: ‹∀ 1. oops33''#› where -//│ | oops33''# := my34'' -//│ | my34'' :> error<> | error<> <: oops33''# +//│ fun oops: ‹∀ 1. oops35''#› where +//│ | oops35''# := my36'' +//│ | my36'' :> my36_37 <: oops35''# +//│ | my36_37 :> error<> //│ [pretty-printed] oops: error - class Base1(base: int) { fun getBase1 = base fun getBase2 = this.base fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase150''#› where -//│ | getBase150''# := Int +//│ fun getBase1: ‹∀ 1. getBase156''#› where +//│ | getBase156''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase251''#› where -//│ | getBase251''# := base52'' -//│ | base52'' :> Int <: getBase251''# +//│ fun getBase2: ‹∀ 1. getBase257''#› where +//│ | getBase257''# := base58'' +//│ | base58'' :> base58_59 <: getBase257''# +//│ | base58_59 :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo53''#› where -//│ | foo53''# := (α54'' -> α57'') -//│ | α54'' <: int -//│ | α57'' :> int +//│ fun foo: ‹∀ 1. foo60''#› where +//│ | foo60''# := (α61'' -> α65'') +//│ | α61'' <: int +//│ | α65'' :> int +//│ [pretty-printed] foo: int -> int + +class Base1(base: int) { + fun getBase1 = base + fun me = this + fun foo(x) = base + x +} +//│ class Base1 +//│ fun getBase1: ‹∀ 1. getBase179''#› where +//│ | getBase179''# := Int +//│ [pretty-printed] getBase1: int +//│ fun me: ‹∀ 1. me80''#› where +//│ | this74 :> Base1<> +//│ | me80''# := this74 +//│ [pretty-printed] me: Base1 +//│ fun foo: ‹∀ 1. foo81''#› where +//│ | foo81''# := (α82'' -> α84'') +//│ | α82'' <: int +//│ | α84'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b65'#› where -//│ | b65'# := α66' -//│ | α66' :> Base1<> <: b65'# +//│ fun b: ‹∀ 0. b92'#› where +//│ | b92'# := α93' +//│ | α93' :> Base1<> <: b92'# //│ [pretty-printed] b: Base1 b.base @@ -69,14 +91,14 @@ b.base // :d b.getBase1 //│ ╔══[ERROR] class `Base1` does not contain member `getBase1` -//│ ║ l.70: b.getBase1 +//│ ║ l.92: b.getBase1 //│ ╙── ^^^^^^^^^ //│ Typed: error :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.77: b.getBaseTypo +//│ ║ l.99: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index fb4109129b..7e18e194ef 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -38,7 +38,6 @@ class Base1(base: int): BaseTest //│ | | 1. type int //│ | | => Int //│ | => Int ——— -//│ | 1. Typing TypingUnit(List()) //│ | List() //│ | base: int, //│ | List(BaseTest) @@ -55,18 +54,23 @@ class Base1(base: int): BaseTest //│ | | | | | | | 1. C {base: Int} -//│ fun test: ‹∀ 1. test59''#› where -//│ | test59''# := (α60'' -> (α64'', α60'', misc65'',)) -//│ | α60'' <: int -//│ | α64'' :> int -//│ | misc65'' :> misc65_66' +//│ this: this59' +//│ super: super60' +//│ | super60' <: {misc: misc68_69'} & {base: base64_65'} +//│ | base64_65' <: int +//│ fun test: ‹∀ 1. test62''#› where +//│ | test62''# := (α63'' -> (α67'', α63'', misc68'',)) +//│ | α63'' <: int +//│ | α67'' :> int +//│ | misc68'' :> misc68_69' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 66d6c738da..ed734acd9c 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -14,9 +14,9 @@ Foo fun fooo(x) = class C(y, z) C(0, x) -//│ fun fooo: ‹∀ 0. fooo25'#› where -//│ | fooo25'# := (α26' -> α31') -//│ | α31' :> C<> +//│ fun fooo: ‹∀ 0. fooo26'#› where +//│ | fooo26'# := (α27' -> α33') +//│ | α33' :> C<> //│ [pretty-printed] fooo: anything -> C @@ -33,13 +33,13 @@ namespace Test0_2 { //│ ║ l.27: fun a = Test0_2.b //│ ╙── ^^ //│ class Test0_1 -//│ fun a: ‹∀ 1. a39''#› where -//│ | a39''# := b42'' -//│ | b42'' :> error<> | error<> <: a39''# +//│ fun a: ‹∀ 1. a42''#› where +//│ | a42''# := b47'' +//│ | b47'' :> error<> | error<> <: a42''# //│ [pretty-printed] a: error //│ class Test0_2 -//│ fun a: ‹∀ 1. a43''#› where -//│ | a43''# := 123 +//│ fun a: ‹∀ 1. a46''#› where +//│ | a46''# := 123 //│ [pretty-printed] a: 123 // TODO @@ -53,19 +53,16 @@ namespace Test1_2 { //│ ╔══[ERROR] namespace `Test1_2` does not contain member `b` //│ ║ l.48: fun a = Test1_2.b //│ ╙── ^^ -//│ ╔══[ERROR] namespace `Test1_1` does not contain member `a` -//│ ║ l.51: fun a = Test1_1.a -//│ ╙── ^^ //│ class Test1_1 -//│ fun a: ‹∀ 1. a51''#› where -//│ | a51''# := b54'' -//│ | b54'' :> error<> | error<> <: a51''# +//│ fun a: ‹∀ 1. a56''#› where +//│ | a56''# := b63'' +//│ | b63'' :> error<> | error<> <: a56''# //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun a: ‹∀ 1. a55''#› where -//│ | a55''# := a56'' -//│ | a56'' :> error<> | error<> <: a55''# -//│ [pretty-printed] a: error +//│ fun a: ‹∀ 1. a60''#› where +//│ | a60''# := a61'' +//│ | a61'' :> a61_62 <: a60''# +//│ [pretty-printed] a: nothing // TODO @@ -80,40 +77,34 @@ namespace Test2_2 { fun e = Test2_1.d } //│ ╔══[ERROR] namespace `Test2_2` does not contain member `b` -//│ ║ l.74: fun a = Test2_2.b +//│ ║ l.71: fun a = Test2_2.b //│ ╙── ^^ //│ ╔══[ERROR] namespace `Test2_2` does not contain member `e` -//│ ║ l.75: fun d = Test2_2.e -//│ ╙── ^^ -//│ ╔══[ERROR] namespace `Test2_1` does not contain member `a` -//│ ║ l.79: fun c = Test2_1.a -//│ ╙── ^^ -//│ ╔══[ERROR] namespace `Test2_1` does not contain member `d` -//│ ║ l.80: fun e = Test2_1.d +//│ ║ l.72: fun d = Test2_2.e //│ ╙── ^^ //│ class Test2_1 -//│ fun t2: ‹∀ 1. t267''#› where -//│ | t267''# := Test2_2<> +//│ fun t2: ‹∀ 1. t276''#› where +//│ | t276''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a72''#› where -//│ | a72''# := b73'' -//│ | b73'' :> error<> | error<> <: a72''# +//│ fun a: ‹∀ 1. a89''#› where +//│ | a89''# := b90'' +//│ | b90'' :> error<> | error<> <: a89''# //│ [pretty-printed] a: error -//│ fun d: ‹∀ 1. d74''#› where -//│ | d74''# := e75'' -//│ | e75'' :> error<> | error<> <: d74''# +//│ fun d: ‹∀ 1. d91''#› where +//│ | d91''# := e92'' +//│ | e92'' :> error<> | error<> <: d91''# //│ [pretty-printed] d: error //│ class Test2_2 -//│ fun b: ‹∀ 1. b76''#› where -//│ | b76''# := 123 +//│ fun b: ‹∀ 1. b82''#› where +//│ | b82''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c77''#› where -//│ | c77''# := a78'' -//│ | a78'' :> error<> | error<> <: c77''# -//│ [pretty-printed] c: error -//│ fun e: ‹∀ 1. e79''#› where -//│ | e79''# := d80'' -//│ | d80'' :> error<> | error<> <: e79''# -//│ [pretty-printed] e: error +//│ fun c: ‹∀ 1. c83''#› where +//│ | c83''# := a84'' +//│ | a84'' :> a84_85 <: c83''# +//│ [pretty-printed] c: nothing +//│ fun e: ‹∀ 1. e86''#› where +//│ | e86''# := d87'' +//│ | d87'' :> d87_88 <: e86''# +//│ [pretty-printed] e: nothing From b5e26d5aaaf1f69c231e9fe66eca7f0b8942609f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 17:56:09 +0800 Subject: [PATCH 014/498] WIP --- .../scala/mlscript/ConstraintSolver.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 23 +++- shared/src/test/diff/nu/BasicClasses.mls | 126 ++++++++++++------ shared/src/test/diff/nu/BasicMixins.mls | 6 +- shared/src/test/diff/nu/MutualRec.mls | 17 +-- 5 files changed, 109 insertions(+), 65 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index b2b2ce0290..b71e14da6c 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -572,7 +572,7 @@ class ConstraintSolver extends NormalForms { self: Typer => println(fld.name, cls.members) cls.members.get(fld.name) match { case S(d: TypedNuFun) => - ??? + d.ty.toUpper(provTODO) case S(p: NuParam) => p.ty case N => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 2d30c9fb65..6092986f76 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -48,7 +48,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => res.result = result.map(f) res } - private lazy val thisTV: TV = freshVar(noProv/*FIXME*/, N, S("this")) + + private lazy val thisTV: TV = + freshVar(noProv/*FIXME*/, N, S("this"))(lvl + 1) + def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") else trace(s"Completing ${decl}") { @@ -141,6 +144,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // println(fresh) constrain(superType, mxn.superTV) constrain(finalType, mxn.thisTV) + + // TODO check overriding mxn.ttu.entities.map(_.complete()).map { case fun @ TypedNuFun(_, fd, ty) => fun @@ -184,6 +189,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use + // TODO check overriding val clsMems = ttu.entities.map(_.complete()).map { case fun @ TypedNuFun(_, fd, ty) => fun @@ -195,7 +201,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // )(provTODO) // constrain(thisTy, thisTV) - val mems = baseMems ++ paramMems + val mems = baseMems ++ paramMems ++ clsMems TypedNuCls(ctx.lvl, td, ttu, typedParams, mems.map(d => d.name -> d).toMap) } case Mxn => @@ -222,7 +228,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => }() } - def typeSignature(implicit raise: Raise): ST = if (isComputing) tv // FIXME wrong in general + def typeSignature(implicit raise: Raise): ST = if (isComputing) tv // TODO FIXME wrong in general (when accessed from difft scope/level) else complete() match { case cls: TypedNuCls if cls.td.kind is Nms => ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) @@ -232,11 +238,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) )(provTODO) case TypedNuFun(_, fd, ty) => - println(fd, ty) - ??? + // println(fd, ty) + // ??? + ty } - def force()(implicit raise: Raise): Unit = { - complete().force() + def force()(implicit raise: Raise): TypedNuTermDef = { + val res = complete() + res.force() decl match { case td: NuTypeDef => td.kind match { @@ -250,6 +258,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } case _ => } + res } override def toString: String = s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 30b0062dab..89a532b3b2 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -3,38 +3,62 @@ :NoJS -// TODO -// :d + class Base0(n) { fun me = this fun my = this.n fun mine = my fun oops = this.my } -//│ ╔══[ERROR] class `Base0` does not contain member `my` -//│ ║ l.12: fun oops = this.my -//│ ╙── ^^^ //│ class Base0 //│ fun me: ‹∀ 1. me30''#› where -//│ | this24 :> Base0<> <: {my: my36_37} & {n: n32_33} -//│ | me30''# := this24 -//│ | my36_37 :> error<> +//│ | this24' :> Base0<> <: {my: my36_37'} & {n: n32_33'} +//│ | me30''# := this24' +//│ | my31''# := n32'' +//│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | mine34''# := my31''# +//│ | my36_37' :> ‹∀ 1. my31''#› //│ [pretty-printed] me: Base0 //│ fun my: ‹∀ 1. my31''#› where //│ | my31''# := n32'' -//│ | n32'' :> n32_33 <: mine34''# & my31''# +//│ | n32'' :> n32_33' <: mine34''# & my31''# //│ | mine34''# := my31''# //│ [pretty-printed] my: nothing //│ fun mine: ‹∀ 1. mine34''#› where //│ | my31''# := n32'' -//│ | n32'' :> n32_33 <: mine34''# & my31''# +//│ | n32'' :> n32_33' <: mine34''# & my31''# //│ | mine34''# := my31''# //│ [pretty-printed] mine: nothing //│ fun oops: ‹∀ 1. oops35''#› where +//│ | my31''# := n32'' +//│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | mine34''# := my31''# //│ | oops35''# := my36'' -//│ | my36'' :> my36_37 <: oops35''# -//│ | my36_37 :> error<> -//│ [pretty-printed] oops: error +//│ | my36'' :> my36_37' <: oops35''# +//│ | my36_37' :> ‹∀ 1. my31''#› +//│ [pretty-printed] oops: nothing + + +let b1 = Base0(42) +b1.n +//│ fun b1: ‹∀ 0. b154'#› where +//│ | b154'# := α55' +//│ | α55' :> Base0<> <: b154'# +//│ [pretty-printed] b1: Base0 +//│ Typed: 42 + + +let b2 = Base0("hi") +//│ fun b2: ‹∀ 0. b263'#› where +//│ | b263'# := α64' +//│ | α64' :> Base0<> <: b263'# +//│ [pretty-printed] b2: Base0 + +// FIXME 42 +b2.n +//│ Typed: "hi" | 42 + + class Base1(base: int) { fun getBase1 = base @@ -42,18 +66,18 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase156''#› where -//│ | getBase156''# := Int +//│ fun getBase1: ‹∀ 1. getBase175''#› where +//│ | getBase175''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase257''#› where -//│ | getBase257''# := base58'' -//│ | base58'' :> base58_59 <: getBase257''# -//│ | base58_59 :> Int +//│ fun getBase2: ‹∀ 1. getBase276''#› where +//│ | getBase276''# := base77'' +//│ | base77'' :> base77_78' <: getBase276''# +//│ | base77_78' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo60''#› where -//│ | foo60''# := (α61'' -> α65'') -//│ | α61'' <: int -//│ | α65'' :> int +//│ fun foo: ‹∀ 1. foo79''#› where +//│ | foo79''# := (α80'' -> α84'') +//│ | α80'' <: int +//│ | α84'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -62,44 +86,42 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase179''#› where -//│ | getBase179''# := Int +//│ fun getBase1: ‹∀ 1. getBase198''#› where +//│ | getBase198''# := Int //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me80''#› where -//│ | this74 :> Base1<> -//│ | me80''# := this74 +//│ fun me: ‹∀ 1. me99''#› where +//│ | this93' :> Base1<> +//│ | me99''# := this93' //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo81''#› where -//│ | foo81''# := (α82'' -> α84'') -//│ | α82'' <: int -//│ | α84'' :> int +//│ fun foo: ‹∀ 1. foo100''#› where +//│ | foo100''# := (α101'' -> α103'') +//│ | α101'' <: int +//│ | α103'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b92'#› where -//│ | b92'# := α93' -//│ | α93' :> Base1<> <: b92'# +//│ fun b: ‹∀ 0. b111'#› where +//│ | b111'# := α112' +//│ | α112' :> Base1<> <: b111'# //│ [pretty-printed] b: Base1 b.base //│ Typed: int -// TODO -// :d b.getBase1 -//│ ╔══[ERROR] class `Base1` does not contain member `getBase1` -//│ ║ l.92: b.getBase1 -//│ ╙── ^^^^^^^^^ -//│ Typed: error +//│ Typed: int + +b.me +//│ Typed: Base1 :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.99: b.getBaseTypo -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.121: b.getBaseTypo +//│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -107,11 +129,27 @@ b : Base1 //│ Typed: Base1 + // TODO treat `a: int` as a signature class Annots(base: 0 | 1) { a: int fun a = base } -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.135: a: int +//│ ║ ^ +//│ ╟── type `(0 | 1,)` is not an instance of type `int` +//│ ║ l.134: class Annots(base: 0 | 1) { +//│ ║ ^ +//│ ╟── but it flows into reference with expected type `int` +//│ ║ l.135: a: int +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.135: a: int +//│ ╙── ^^^ +//│ class Annots +//│ fun a: ‹∀ 1. a133''#› where +//│ | a133''# := ((0 | 1),) +//│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 7e18e194ef..6a3f9dd998 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -67,10 +67,10 @@ class Base1(base: int): BaseTest //│ | | | NEW this23' LB (0) //│ | 1. Typing TypingUnit(List()) //│ | UNSTASHING... (out) -//│ CONSTRAIN Base1<> //│ [pretty-printed] t2: Test2_2 //│ fun a: ‹∀ 1. a89''#› where +//│ | b82''# := 123 //│ | a89''# := b90'' -//│ | b90'' :> error<> | error<> <: a89''# -//│ [pretty-printed] a: error +//│ | b90'' :> ‹∀ 1. b82''#› <: a89''# +//│ [pretty-printed] a: 123 //│ fun d: ‹∀ 1. d91''#› where +//│ | e86''# := d87'' +//│ | d87'' :> d87_88 <: e86''# //│ | d91''# := e92'' -//│ | e92'' :> error<> | error<> <: d91''# -//│ [pretty-printed] d: error +//│ | e92'' :> ‹∀ 1. e86''#› <: d91''# +//│ [pretty-printed] d: nothing //│ class Test2_2 //│ fun b: ‹∀ 1. b82''#› where //│ | b82''# := 123 From ec3c29d3d631688a6dea51822648fb7bb9559290 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 18:08:10 +0800 Subject: [PATCH 015/498] WIP --- .../scala/mlscript/ConstraintSolver.scala | 5 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 22 +++- .../main/scala/mlscript/TyperDatatypes.scala | 6 +- shared/src/test/diff/nu/BasicClasses.mls | 116 +++++++++++------- shared/src/test/diff/nu/BasicMixins.mls | 18 +-- shared/src/test/diff/nu/MutualRec.mls | 69 ++++++----- 6 files changed, 144 insertions(+), 92 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index b71e14da6c..05e196789f 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -564,7 +564,10 @@ class ConstraintSolver extends NormalForms { self: Typer => // ??? // }.getOrElse { info.complete() match { - case td: TypedNuCls => td + case td: TypedNuCls => + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] case _ => ??? }} } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 5a39f655b9..b19f183dc2 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -23,11 +23,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed trait NuMember { def name: Str + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + : NuMember } case class NuParam(nme: Var, ty: FieldType) extends NuMember { def name: Str = nme.name + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + : NuParam = + NuParam(nme, ty.freshenAbove(lim, rigidify)) } @@ -50,18 +59,23 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshen(implicit ctx: Ctx): TypedNuDecl = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty + // println(level) freshenAbove(level, rigidify = false) } def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedNuTermDef = { - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty + // implicit val freshened: MutMap[TV, ST] = MutMap.empty + // implicit val shadows: Shadows = Shadows.empty this match { case m @ TypedNuMxn(td, thisTV, superTV, ttu) => TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) case TypedNuFun(level, fd, ty) => TypedNuFun(level, fd, ty.freshenAbove(level, rigidify)) + case TypedNuCls(level, td, ttu, params, members) => + TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), + params.mapValues(_.freshenAbove(level, rigidify)), + members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) // case _ => ??? } } @@ -87,6 +101,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuAls(nme: TypeName) extends TypedNuTypeDef(Als) { def name: Str = nme.name + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + : TypedNuTermDef = ??? } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 6092986f76..6b12436515 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -33,6 +33,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // TODO rm level? already in ctx class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { + private def outerCtx = ctx val tparams: Ls[TN -> TV] = Nil // TODO var isComputing: Bool = false // TODO replace by a Ctx entry var result: Opt[TypedNuTermDef] = N @@ -202,7 +203,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // constrain(thisTy, thisTV) val mems = baseMems ++ paramMems ++ clsMems - TypedNuCls(ctx.lvl, td, ttu, typedParams, mems.map(d => d.name -> d).toMap) + TypedNuCls(outerCtx.lvl, td, ttu, typedParams, mems.map(d => d.name -> d).toMap) } case Mxn => implicit val prov: TP = noProv // TODO @@ -232,7 +233,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => else complete() match { case cls: TypedNuCls if cls.td.kind is Nms => ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) - case cls: TypedNuCls => + case _cls: TypedNuCls => + val cls = _cls.freshen.asInstanceOf[TypedNuCls] FunctionType( TupleType(cls.params.mapKeys(some))(provTODO), ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 89a532b3b2..1ee1d14bf3 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -16,47 +16,75 @@ class Base0(n) { //│ | me30''# := this24' //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# //│ | my36_37' :> ‹∀ 1. my31''#› //│ [pretty-printed] me: Base0 //│ fun my: ‹∀ 1. my31''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# -//│ [pretty-printed] my: nothing +//│ [pretty-printed] my: 'n //│ fun mine: ‹∀ 1. mine34''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# -//│ [pretty-printed] mine: nothing +//│ [pretty-printed] mine: 'n //│ fun oops: ‹∀ 1. oops35''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# //│ | oops35''# := my36'' //│ | my36'' :> my36_37' <: oops35''# //│ | my36_37' :> ‹∀ 1. my31''#› -//│ [pretty-printed] oops: nothing +//│ [pretty-printed] oops: 'n +// :d +// Base0 +// Base0 let b1 = Base0(42) -b1.n -//│ fun b1: ‹∀ 0. b154'#› where -//│ | b154'# := α55' -//│ | α55' :> Base0<> <: b154'# +let n1 = b1.n +//│ fun b1: ‹∀ 0. b165'#› where +//│ | b165'# := α71' +//│ | α71' :> Base0<> <: {n: n73'} & b165'# +//│ | n172'# := n73' +//│ | n73' :> ‘n78' <: n172'# //│ [pretty-printed] b1: Base0 -//│ Typed: 42 +//│ fun n1: ‹∀ 0. n172'#› where +//│ | n172'# := n73' +//│ | n73' :> ‘n78' <: n172'# +//│ [pretty-printed] n1: 'n + +// TODO +n1 + 1 +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.63: n1 + 1 +//│ ║ ^^^^ +//│ ╟── reference of type `?n` is not an instance of type `int` +//│ ║ l.7: class Base0(n) { +//│ ║ ^ +//│ ╟── but it flows into reference with expected type `int` +//│ ║ l.63: n1 + 1 +//│ ╙── ^^ +//│ Typed: error | int let b2 = Base0("hi") -//│ fun b2: ‹∀ 0. b263'#› where -//│ | b263'# := α64' -//│ | α64' :> Base0<> <: b263'# +let n2 = b2.n +//│ fun b2: ‹∀ 0. b288'#› where +//│ | b288'# := α94' +//│ | α94' :> Base0<> <: {n: n96'} & b288'# +//│ | n295'# := n96' +//│ | n96' :> ‘n101' <: n295'# //│ [pretty-printed] b2: Base0 - -// FIXME 42 -b2.n -//│ Typed: "hi" | 42 +//│ fun n2: ‹∀ 0. n295'#› where +//│ | n295'# := n96' +//│ | n96' :> ‘n101' <: n295'# +//│ [pretty-printed] n2: 'n @@ -66,18 +94,18 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase175''#› where -//│ | getBase175''# := Int +//│ fun getBase1: ‹∀ 1. getBase1112''#› where +//│ | getBase1112''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase276''#› where -//│ | getBase276''# := base77'' -//│ | base77'' :> base77_78' <: getBase276''# -//│ | base77_78' :> Int +//│ fun getBase2: ‹∀ 1. getBase2113''#› where +//│ | getBase2113''# := base114'' +//│ | base114'' :> base114_115' <: getBase2113''# +//│ | base114_115' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo79''#› where -//│ | foo79''# := (α80'' -> α84'') -//│ | α80'' <: int -//│ | α84'' :> int +//│ fun foo: ‹∀ 1. foo116''#› where +//│ | foo116''# := (α117'' -> α121'') +//│ | α117'' <: int +//│ | α121'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -86,26 +114,26 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase198''#› where -//│ | getBase198''# := Int +//│ fun getBase1: ‹∀ 1. getBase1141''#› where +//│ | getBase1141''# := Int //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me99''#› where -//│ | this93' :> Base1<> -//│ | me99''# := this93' +//│ fun me: ‹∀ 1. me142''#› where +//│ | this136' :> Base1<> +//│ | me142''# := this136' //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo100''#› where -//│ | foo100''# := (α101'' -> α103'') -//│ | α101'' <: int -//│ | α103'' :> int +//│ fun foo: ‹∀ 1. foo143''#› where +//│ | foo143''# := (α144'' -> α146'') +//│ | α144'' <: int +//│ | α146'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b111'#› where -//│ | b111'# := α112' -//│ | α112' :> Base1<> <: b111'# +//│ fun b: ‹∀ 0. b157'#› where +//│ | b157'# := α161' +//│ | α161' :> Base1<> <: b157'# //│ [pretty-printed] b: Base1 b.base @@ -120,7 +148,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.121: b.getBaseTypo +//│ ║ l.149: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -136,20 +164,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.135: a: int +//│ ║ l.163: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.134: class Annots(base: 0 | 1) { +//│ ║ l.162: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.135: a: int +//│ ║ l.163: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.135: a: int +//│ ║ l.163: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a133''#› where -//│ | a133''# := ((0 | 1),) +//│ fun a: ‹∀ 1. a194''#› where +//│ | a194''# := ((0 | 1),) //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 6a3f9dd998..94ea94d873 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -102,14 +102,14 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo -//│ this: this59' -//│ super: super60' -//│ | super60' <: {misc: misc68_69'} & {base: base64_65'} -//│ | base64_65' <: int -//│ fun test: ‹∀ 1. test62''#› where -//│ | test62''# := (α63'' -> (α67'', α63'', misc68'',)) -//│ | α63'' <: int -//│ | α67'' :> int -//│ | misc68'' :> misc68_69' +//│ this: this60' +//│ super: super61' +//│ | super61' <: {misc: misc69_70'} & {base: base65_66'} +//│ | base65_66' <: int +//│ fun test: ‹∀ 1. test63''#› where +//│ | test63''# := (α64'' -> (α68'', α64'', misc69'',)) +//│ | α64'' <: int +//│ | α68'' :> int +//│ | misc69'' :> misc69_70' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 5aad0cba08..d2fa2a12f8 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -15,8 +15,9 @@ fun fooo(x) = class C(y, z) C(0, x) //│ fun fooo: ‹∀ 0. fooo26'#› where -//│ | fooo26'# := (α27' -> α33') -//│ | α33' :> C<> +//│ | fooo26'# := (α27' -> α35') +//│ | α27' <: z30_34' +//│ | α35' :> C<> //│ [pretty-printed] fooo: anything -> C @@ -30,16 +31,16 @@ namespace Test0_2 { fun a = 123 } //│ ╔══[ERROR] namespace `Test0_2` does not contain member `b` -//│ ║ l.27: fun a = Test0_2.b +//│ ║ l.28: fun a = Test0_2.b //│ ╙── ^^ //│ class Test0_1 -//│ fun a: ‹∀ 1. a42''#› where -//│ | a42''# := b47'' -//│ | b47'' :> error<> | error<> <: a42''# +//│ fun a: ‹∀ 1. a45''#› where +//│ | a45''# := b50'' +//│ | b50'' :> error<> | error<> <: a45''# //│ [pretty-printed] a: error //│ class Test0_2 -//│ fun a: ‹∀ 1. a46''#› where -//│ | a46''# := 123 +//│ fun a: ‹∀ 1. a49''#› where +//│ | a49''# := 123 //│ [pretty-printed] a: 123 // TODO @@ -51,17 +52,17 @@ namespace Test1_2 { fun a = Test1_1.a } //│ ╔══[ERROR] namespace `Test1_2` does not contain member `b` -//│ ║ l.48: fun a = Test1_2.b +//│ ║ l.49: fun a = Test1_2.b //│ ╙── ^^ //│ class Test1_1 -//│ fun a: ‹∀ 1. a56''#› where -//│ | a56''# := b63'' -//│ | b63'' :> error<> | error<> <: a56''# +//│ fun a: ‹∀ 1. a60''#› where +//│ | a60''# := b67'' +//│ | b67'' :> error<> | error<> <: a60''# //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun a: ‹∀ 1. a60''#› where -//│ | a60''# := a61'' -//│ | a61'' :> a61_62 <: a60''# +//│ fun a: ‹∀ 1. a64''#› where +//│ | a64''# := a65'' +//│ | a65'' :> a65_66 <: a64''# //│ [pretty-printed] a: nothing @@ -77,31 +78,31 @@ namespace Test2_2 { fun e = Test2_1.d } //│ class Test2_1 -//│ fun t2: ‹∀ 1. t276''#› where -//│ | t276''# := Test2_2<> +//│ fun t2: ‹∀ 1. t281''#› where +//│ | t281''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a89''#› where -//│ | b82''# := 123 -//│ | a89''# := b90'' -//│ | b90'' :> ‹∀ 1. b82''#› <: a89''# +//│ fun a: ‹∀ 1. a94''#› where +//│ | b87''# := 123 +//│ | a94''# := b95'' +//│ | b95'' :> ‹∀ 1. b87''#› <: a94''# //│ [pretty-printed] a: 123 -//│ fun d: ‹∀ 1. d91''#› where -//│ | e86''# := d87'' -//│ | d87'' :> d87_88 <: e86''# -//│ | d91''# := e92'' -//│ | e92'' :> ‹∀ 1. e86''#› <: d91''# +//│ fun d: ‹∀ 1. d99''#› where +//│ | e91''# := d92'' +//│ | d92'' :> d92_93 <: e91''# +//│ | d99''# := e100'' +//│ | e100'' :> ‹∀ 1. e91''#› <: d99''# //│ [pretty-printed] d: nothing //│ class Test2_2 -//│ fun b: ‹∀ 1. b82''#› where -//│ | b82''# := 123 +//│ fun b: ‹∀ 1. b87''#› where +//│ | b87''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c83''#› where -//│ | c83''# := a84'' -//│ | a84'' :> a84_85 <: c83''# +//│ fun c: ‹∀ 1. c88''#› where +//│ | c88''# := a89'' +//│ | a89'' :> a89_90 <: c88''# //│ [pretty-printed] c: nothing -//│ fun e: ‹∀ 1. e86''#› where -//│ | e86''# := d87'' -//│ | d87'' :> d87_88 <: e86''# +//│ fun e: ‹∀ 1. e91''#› where +//│ | e91''# := d92'' +//│ | d92'' :> d92_93 <: e91''# //│ [pretty-printed] e: nothing From 71784a3692b88bd0dc0562672b6795d230ba130d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 20:45:28 +0800 Subject: [PATCH 016/498] WIP --- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 4 +- shared/src/test/diff/nu/BasicMixins.mls | 39 ++++++ shared/src/test/diff/nu/MutualRec.mls | 120 ++++++++++-------- 4 files changed, 110 insertions(+), 54 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 016c2084ba..98550d0126 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -253,6 +253,7 @@ object NewLexer { "interface", "new", "namespace", + "module", "type", "where", "forall", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index fa6879f66a..03ac1dcf70 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -244,14 +244,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (SPACE, _) :: _ => consume; block case c => val t = c match { - case (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace")), l0) :: c => + case (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c => consume val kind = k match { case "class" => Cls case "trait" => Trt case "mixin" => Mxn case "type" => Als - case "namespace" => Nms + case "namespace" | "module" => Nms case _ => die } val (tn, success) = yeetSpaces match { diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 94ea94d873..cd50cd601b 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -113,3 +113,42 @@ mixin Foo { //│ | misc69'' :> misc69_70' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) + +mixin WrapBase { + fun wrap(x) = x +} +mixin Wrap { + fun wrap(x) = [super.wrap(x)] +} +//│ mixin WrapBase +//│ this: this80' +//│ super: super81' +//│ fun wrap: ‹∀ 1. wrap83''#› where +//│ | wrap83''# := (α84'' -> α84'') +//│ [pretty-printed] wrap: 'a -> 'a +//│ mixin Wrap +//│ this: this85' +//│ super: super86' +//│ | super86' <: {wrap: wrap90_91'} +//│ | wrap90_91' <: ((α89_93',) -> α92_94') +//│ fun wrap: ‹∀ 1. wrap88''#› where +//│ | wrap88''# := (α89'' -> (α92'',)) +//│ | α89'' <: α89_93' +//│ | α92'' :> α92_94' +//│ [pretty-printed] wrap: anything -> (nothing,) + +// TODO +module WrapBase1: WrapBase, Wrap +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.141: module WrapBase1: WrapBase, Wrap +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `anything` does not have field 'wrap' +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.121: fun wrap(x) = [super.wrap(x)] +//│ ║ ^^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.121: fun wrap(x) = [super.wrap(x)] +//│ ╙── ^^^^^ +//│ class WrapBase1 + + diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index d2fa2a12f8..95347cc180 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -22,87 +22,103 @@ fun fooo(x) = -// TODO -// :d -namespace Test0_1 { +module Test0_1 { fun a = Test0_2.b } -namespace Test0_2 { - fun a = 123 +module Test0_2 { + fun b = 123 } -//│ ╔══[ERROR] namespace `Test0_2` does not contain member `b` -//│ ║ l.28: fun a = Test0_2.b -//│ ╙── ^^ //│ class Test0_1 //│ fun a: ‹∀ 1. a45''#› where //│ | a45''# := b50'' -//│ | b50'' :> error<> | error<> <: a45''# -//│ [pretty-printed] a: error -//│ class Test0_2 -//│ fun a: ‹∀ 1. a49''#› where -//│ | a49''# := 123 +//│ | b49''# := 123 +//│ | b50'' :> ‹∀ 1. b49''#› <: a45''# //│ [pretty-printed] a: 123 +//│ class Test0_2 +//│ fun b: ‹∀ 1. b49''#› where +//│ | b49''# := 123 +//│ [pretty-printed] b: 123 -// TODO -// :d -namespace Test1_1 { +Test0_1.a +//│ Typed: 123 + + +module Test1_1 { fun a = Test1_2.b } -namespace Test1_2 { - fun a = Test1_1.a +module Test1_2 { + fun b = Test1_1.a } -//│ ╔══[ERROR] namespace `Test1_2` does not contain member `b` -//│ ║ l.49: fun a = Test1_2.b -//│ ╙── ^^ //│ class Test1_1 -//│ fun a: ‹∀ 1. a60''#› where -//│ | a60''# := b67'' -//│ | b67'' :> error<> | error<> <: a60''# -//│ [pretty-printed] a: error -//│ class Test1_2 -//│ fun a: ‹∀ 1. a64''#› where -//│ | a64''# := a65'' -//│ | a65'' :> a65_66 <: a64''# +//│ fun a: ‹∀ 1. a67''#› where +//│ | a67''# := b74'' +//│ | b71''# := a72'' +//│ | a72'' :> a72_73 <: b71''# +//│ | b74'' :> ‹∀ 1. b71''#› <: a67''# //│ [pretty-printed] a: nothing +//│ class Test1_2 +//│ fun b: ‹∀ 1. b71''#› where +//│ | b71''# := a72'' +//│ | a72'' :> a72_73 <: b71''# +//│ [pretty-printed] b: nothing + +Test1_1.a +//│ Typed: nothing -// TODO -namespace Test2_1 { +// TODO check TV hygiene +module Test2_1 { fun t2 = Test2_2 fun a = Test2_2.b fun d = Test2_2.e + fun n = 456 } -namespace Test2_2 { +module Test2_2 { fun b = 123 fun c = Test2_1.a - fun e = Test2_1.d + fun e = Test2_1.n } //│ class Test2_1 -//│ fun t2: ‹∀ 1. t281''#› where -//│ | t281''# := Test2_2<> +//│ fun t2: ‹∀ 1. t2100''#› where +//│ | t2100''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a94''#› where -//│ | b87''# := 123 -//│ | a94''# := b95'' -//│ | b95'' :> ‹∀ 1. b87''#› <: a94''# +//│ fun a: ‹∀ 1. a113''#› where +//│ | b106''# := 123 +//│ | a113''# := b114'' +//│ | b114'' :> ‹∀ 1. b106''#› <: a113''# //│ [pretty-printed] a: 123 -//│ fun d: ‹∀ 1. d99''#› where -//│ | e91''# := d92'' -//│ | d92'' :> d92_93 <: e91''# -//│ | d99''# := e100'' -//│ | e100'' :> ‹∀ 1. e91''#› <: d99''# +//│ fun d: ‹∀ 1. d118''#› where +//│ | e110''# := n111'' +//│ | n111'' :> n111_112 <: e110''# +//│ | d118''# := e119'' +//│ | e119'' :> ‹∀ 1. e110''#› <: d118''# //│ [pretty-printed] d: nothing +//│ fun n: ‹∀ 1. n123''#› where +//│ | n123''# := 456 +//│ [pretty-printed] n: 456 //│ class Test2_2 -//│ fun b: ‹∀ 1. b87''#› where -//│ | b87''# := 123 +//│ fun b: ‹∀ 1. b106''#› where +//│ | b106''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c88''#› where -//│ | c88''# := a89'' -//│ | a89'' :> a89_90 <: c88''# +//│ fun c: ‹∀ 1. c107''#› where +//│ | c107''# := a108'' +//│ | a108'' :> a108_109 <: c107''# //│ [pretty-printed] c: nothing -//│ fun e: ‹∀ 1. e91''#› where -//│ | e91''# := d92'' -//│ | d92'' :> d92_93 <: e91''# +//│ fun e: ‹∀ 1. e110''#› where +//│ | e110''# := n111'' +//│ | n111'' :> n111_112 <: e110''# //│ [pretty-printed] e: nothing +Test2_1.t2.b +//│ Typed: 123 + +Test2_1.a +//│ Typed: 123 + +// FIXME +Test2_1.d +//│ Typed: nothing + +Test2_1.n +//│ Typed: 456 From 700dcff85028156fad08b173d7d5bd50cf25c428 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 20:55:05 +0800 Subject: [PATCH 017/498] WIP --- .../main/scala/mlscript/TyperDatatypes.scala | 6 ++- shared/src/test/diff/nu/BasicMixins.mls | 52 ++++++++++++------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 6b12436515..aefb50b7d5 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -173,7 +173,11 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => Nil } }() - val newSuperType = superType + val newSuperType = superType & + RecordType( + // newMembs.foldLeft(TopType.toUpper(provTODO))(_ && _.ty.toUpper(provTODO)) + newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) + )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => constrain(superType, finalType) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index cd50cd601b..af215c447c 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -58,13 +58,16 @@ class Base1(base: int): BaseTest //│ | | where //│ | | 1. C this45' base27_28' <: test26''# +//│ base27_28' :> Int //│ this45' <: this23' -//│ | 1. C {base: Int} α92_94' //│ [pretty-printed] wrap: anything -> (nothing,) -// TODO + + module WrapBase1: WrapBase, Wrap -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.141: module WrapBase1: WrapBase, Wrap -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `anything` does not have field 'wrap' -//│ ╟── Note: constraint arises from field selection: -//│ ║ l.121: fun wrap(x) = [super.wrap(x)] -//│ ║ ^^^^^^^^^^ -//│ ╟── from reference: -//│ ║ l.121: fun wrap(x) = [super.wrap(x)] -//│ ╙── ^^^^^ //│ class WrapBase1 +WrapBase1 +//│ Typed: WrapBase1 + +WrapBase1.wrap +//│ Typed: 'a -> ('a,) + +WrapBase1.wrap(1) +//│ Typed: (1,) + +// FIXME +WrapBase1.wrap("ok") +//│ Typed: ("ok" | 1,) + + +module WrapBase2: WrapBase, Wrap, Wrap +//│ class WrapBase2 + +// FIXME +WrapBase2.wrap +//│ Typed: 'a -> ("ok" | 1 | 'a,) + + From f6c0b85a6064b4933b1d3202648fd7f5372d25c6 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 22:35:08 +0800 Subject: [PATCH 018/498] ?? --- .../scala/mlscript/ConstraintSolver.scala | 14 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 25 +- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- shared/src/test/diff/nu/BasicClasses.mls | 181 ++++--- shared/src/test/diff/nu/BasicMixins.mls | 470 ++++++++++++++++-- shared/src/test/diff/nu/MutualRec.mls | 71 ++- 6 files changed, 609 insertions(+), 154 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 05e196789f..4ff5d59d43 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -567,7 +567,11 @@ class ConstraintSolver extends NormalForms { self: Typer => case td: TypedNuCls => implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty - td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] + println(td) + val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] + println(res) + // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) + res case _ => ??? }} } @@ -649,6 +653,7 @@ class ConstraintSolver extends NormalForms { self: Typer => cache -= lhs -> rhs () } else { + println(s"LHS bounds ${lhs.showBounds}") val lhs2 = extrudeAndCheck(lhs, rhs.level, true, MaxLevel) println(s"EXTR LHS ~> $lhs2 to ${rhs.level}") println(s" where ${lhs2.showBounds}") @@ -1122,7 +1127,7 @@ class ConstraintSolver extends NormalForms { self: Typer => : SimpleType = { def freshenImpl(ty: SimpleType, below: Level): SimpleType = - // (trace(s"${lvl}. FRESHEN $ty || $above .. $below ${ty.level} ${ty.level <= above}") + (trace(s"${lvl}. FRESHEN $ty || $above .. $below ${ty.level} ${ty.level <= above}") { // * Cannot soundly freshen if the context's level is above the current polymorphism level, // * as that would wrongly capture the newly-freshened variables. @@ -1167,6 +1172,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case None if rigidify && tv.level <= below => // * Rigid type variables (ie, skolems) are encoded as SkolemTag-s val rv = SkolemTag(lvl, freshVar(noProv, N, tv.nameHint.orElse(S("_"))))(tv.prov) + println(s"New skolem: $tv ~> $rv") if (tv.lowerBounds.nonEmpty || tv.upperBounds.nonEmpty) { // The bounds of `tv` may be recursive (refer to `tv` itself), // so here we create a fresh variabe that will be able to tie the presumed recursive knot @@ -1181,7 +1187,9 @@ class ConstraintSolver extends NormalForms { self: Typer => // Now, since there may be recursive bounds, we do the same // but through the indirection of a type variable tv2: tv2.lowerBounds ::= tv.lowerBounds.map(freshen).foldLeft(rv: ST)(_ & _) + println(s"$tv2 :> ${tv2.lowerBounds}") tv2.upperBounds ::= tv.upperBounds.map(freshen).foldLeft(rv: ST)(_ | _) + println(s"$tv2 <: ${tv2.upperBounds}") tv2 } else { freshened += tv -> rv @@ -1239,7 +1247,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case o @ Overload(alts) => o.mapAlts(freshen)(freshen) }} - // (r => s"=> $r")) + (r => s"=> $r")) freshenImpl(ty, below) } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index b19f183dc2..054c4d23e7 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -52,9 +52,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { - override def toString: String = this match { - case _ => ??? - } + // override def toString: String = this match { + // case _ => ??? + // } def level: Level def freshen(implicit ctx: Ctx): TypedNuDecl = { implicit val freshened: MutMap[TV, ST] = MutMap.empty @@ -67,17 +67,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => : TypedNuTermDef = { // implicit val freshened: MutMap[TV, ST] = MutMap.empty // implicit val shadows: Shadows = Shadows.empty + ctx.copy(lvl = level + 1) |> { implicit ctx => this match { case m @ TypedNuMxn(td, thisTV, superTV, ttu) => - TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) + // println(">>",m.level) + // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) + TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) case TypedNuFun(level, fd, ty) => - TypedNuFun(level, fd, ty.freshenAbove(level, rigidify)) + // TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(level, rigidify)) + TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) case TypedNuCls(level, td, ttu, params, members) => - TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), - params.mapValues(_.freshenAbove(level, rigidify)), - members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) + println(">>",level,ctx.lvl) + // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), + // params.mapValues(_.freshenAbove(level, rigidify)), + // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) + TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), + params.mapValues(_.freshenAbove(lim, rigidify)), + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap) // case _ => ??? } + } } def force()(implicit raise: Raise): Unit = this match { case x: TypedNuMxn => x.ttu.force() diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index aefb50b7d5..24e6703eb5 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -131,7 +131,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // case R(p) :: ps => ??? // case L(p) :: ps => case p :: ps => - val newMembs = trace(s"Inheriting from $p") { + val newMembs = trace(s"${lvl}. Inheriting from $p") { p match { case Var(nme) => ctx.get(nme) match { diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 1ee1d14bf3..d7e58383dc 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -16,75 +16,124 @@ class Base0(n) { //│ | me30''# := this24' //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# //│ | my36_37' :> ‹∀ 1. my31''#› //│ [pretty-printed] me: Base0 //│ fun my: ‹∀ 1. my31''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# -//│ [pretty-printed] my: 'n +//│ [pretty-printed] my: nothing //│ fun mine: ‹∀ 1. mine34''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# -//│ [pretty-printed] mine: 'n +//│ [pretty-printed] mine: nothing //│ fun oops: ‹∀ 1. oops35''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> ‘n47 //│ | mine34''# := my31''# //│ | oops35''# := my36'' //│ | my36'' :> my36_37' <: oops35''# //│ | my36_37' :> ‹∀ 1. my31''#› -//│ [pretty-printed] oops: 'n +//│ [pretty-printed] oops: nothing // :d // Base0 // Base0 let b1 = Base0(42) -let n1 = b1.n -//│ fun b1: ‹∀ 0. b165'#› where -//│ | b165'# := α71' -//│ | α71' :> Base0<> <: {n: n73'} & b165'# -//│ | n172'# := n73' -//│ | n73' :> ‘n78' <: n172'# +//│ fun b1: ‹∀ 0. b162'#› where +//│ | b162'# := α113' +//│ | α113' :> Base0<> <: b162'# //│ [pretty-printed] b1: Base0 -//│ fun n1: ‹∀ 0. n172'#› where -//│ | n172'# := n73' -//│ | n73' :> ‘n78' <: n172'# -//│ [pretty-printed] n1: 'n + +:d +let n1 = b1.n +//│ 0. Typing TypingUnit(List(let n1 = (b1).n)) +//│ Completing let n1 = (b1).n +//│ | 1. Typing term (b1).n +//│ | | 1. Typing term b1 +//│ | | 1. : b162'# +//│ | | CONSTRAIN b162'# Base0<> <: b162'# +//│ | | 1. C b162'# TypedNuFun(1,fun me = this,‹∀ 1. me30''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›)),None),List((n,n23')),HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) +//│ | | | | | | (>>,0,1) +//│ | | | | | | 2. FRESHEN ‹∀ 1. me30''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. me30''#› +//│ | | | | | | 2. FRESHEN ‹∀ 1. my31''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. my31''#› +//│ | | | | | | 2. FRESHEN ‹∀ 1. mine34''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. mine34''#› +//│ | | | | | | 2. FRESHEN ‹∀ 1. oops35''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. oops35''#› +//│ | | | | | | 1. FRESHEN n23' || 1 .. 1024 1 true +//│ | | | | | | => n23' +//│ | | | | | | 1. FRESHEN n23' || 1 .. 1024 1 true +//│ | | | | | | => n23' +//│ | | | | | | 2. FRESHEN ‹∀ 1. mine34''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. mine34''#› +//│ | | | | | | 2. FRESHEN ‹∀ 1. oops35''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. oops35''#› +//│ | | | | | | 2. FRESHEN ‹∀ 1. my31''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. my31''#› +//│ | | | | | | 2. FRESHEN ‹∀ 1. me30''#› || 1 .. 1024 1 true +//│ | | | | | | => ‹∀ 1. me30''#› +//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›)),None),List((n,n23')),HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) +//│ | | | | | | (n,HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) +//│ | | | | | | 1. C n23' Base0<> <: {n: n96'} & b288'# -//│ | n295'# := n96' -//│ | n96' :> ‘n101' <: n295'# -//│ [pretty-printed] b2: Base0 -//│ fun n2: ‹∀ 0. n295'#› where -//│ | n295'# := n96' -//│ | n96' :> ‘n101' <: n295'# -//│ [pretty-printed] n2: 'n +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.113: let b2 = Base0("hi") +//│ ║ ^^^^^^^^^^^ +//│ ╟── string literal of type `"hi"` is not an instance of type `int` +//│ ║ l.113: let b2 = Base0("hi") +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.109: n1 + 1 +//│ ║ ^^ +//│ ╟── from reference: +//│ ║ l.7: class Base0(n) { +//│ ╙── ^ +//│ fun b2: ‹∀ 0. b2130'#› where +//│ | b2130'# := α183' +//│ | α183' :> Base0<> | error<> <: {n: n185'} & b2130'# +//│ | n2184'# := n185' +//│ | n185' :> error<> <: n2184'# +//│ [pretty-printed] b2: Base0 | error +//│ fun n2: ‹∀ 0. n2184'#› where +//│ | n2184'# := n185' +//│ | n185' :> error<> <: n2184'# +//│ [pretty-printed] n2: error @@ -94,18 +143,18 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1112''#› where -//│ | getBase1112''# := Int +//│ fun getBase1: ‹∀ 1. getBase1200''#› where +//│ | getBase1200''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase2113''#› where -//│ | getBase2113''# := base114'' -//│ | base114'' :> base114_115' <: getBase2113''# -//│ | base114_115' :> Int +//│ fun getBase2: ‹∀ 1. getBase2201''#› where +//│ | getBase2201''# := base202'' +//│ | base202'' :> base202_203' <: getBase2201''# +//│ | base202_203' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo116''#› where -//│ | foo116''# := (α117'' -> α121'') -//│ | α117'' <: int -//│ | α121'' :> int +//│ fun foo: ‹∀ 1. foo204''#› where +//│ | foo204''# := (α205'' -> α209'') +//│ | α205'' <: int +//│ | α209'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -114,26 +163,26 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1141''#› where -//│ | getBase1141''# := Int +//│ fun getBase1: ‹∀ 1. getBase1229''#› where +//│ | getBase1229''# := Int //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me142''#› where -//│ | this136' :> Base1<> -//│ | me142''# := this136' +//│ fun me: ‹∀ 1. me230''#› where +//│ | this224' :> Base1<> +//│ | me230''# := this224' //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo143''#› where -//│ | foo143''# := (α144'' -> α146'') -//│ | α144'' <: int -//│ | α146'' :> int +//│ fun foo: ‹∀ 1. foo231''#› where +//│ | foo231''# := (α232'' -> α234'') +//│ | α232'' <: int +//│ | α234'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b157'#› where -//│ | b157'# := α161' -//│ | α161' :> Base1<> <: b157'# +//│ fun b: ‹∀ 0. b250'#› where +//│ | b250'# := α259' +//│ | α259' :> Base1<> <: b250'# //│ [pretty-printed] b: Base1 b.base @@ -148,7 +197,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.149: b.getBaseTypo +//│ ║ l.198: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -164,20 +213,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.163: a: int +//│ ║ l.212: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.162: class Annots(base: 0 | 1) { +//│ ║ l.211: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.163: a: int +//│ ║ l.212: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.163: a: int +//│ ║ l.212: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a194''#› where -//│ | a194''# := ((0 | 1),) +//│ fun a: ‹∀ 1. a292''#› where +//│ | a292''# := ((0 | 1),) //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index af215c447c..4668628651 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -41,7 +41,31 @@ class Base1(base: int): BaseTest //│ | List() //│ | base: int, //│ | List(BaseTest) -//│ | Inheriting from BaseTest +//│ | 1. Inheriting from BaseTest +//│ | | 2. FRESHEN ‹∀ 1. test26''#› || 0 .. 1024 1 false +//│ | | | 3. FRESHEN test26''# || 1 .. 1024 2 false +//│ | | | | 3. FRESHEN base27'' || 1 .. 1024 2 false +//│ | | | | | 3. FRESHEN base27_28' || 1 .. 1024 1 true +//│ | | | | | => base27_28' +//│ | | | | | 3. FRESHEN test26''# || 1 .. 1024 2 false +//│ | | | | | | 3. FRESHEN test26''# || 1 .. 1024 2 false +//│ | | | | | | => test26_47''' +//│ | | | | | => test26_47''' +//│ | | | | => base27_48''' +//│ | | | => test26_47'''# +//│ | | | 2. FRESHEN ‹∀ 2. test26_47'''#› || 0 .. 1024 1 false +//│ | | | | 2. FRESHEN test26_47'''# || 0 .. 2 3 false +//│ | | | | | 2. FRESHEN base27_48''' || 0 .. 2 3 false +//│ | | | | | | 2. FRESHEN base27_28' || 0 .. 2 1 false +//│ | | | | | | => base27_51'' +//│ | | | | | | 2. FRESHEN test26_47'''# || 0 .. 2 3 false +//│ | | | | | | | 2. FRESHEN test26_47'''# || 0 .. 2 3 false +//│ | | | | | | | => test26_49''' +//│ | | | | | | => test26_49''' +//│ | | | | | => base27_50''' +//│ | | | | => test26_49'''# +//│ | | | => ‹∀ 2. test26_49'''#› +//│ | | => ‹∀ 2. test26_49'''#› //│ | | CONSTRAIN {base: Int} base27_28' <: test26''# -//│ base27_28' :> Int //│ this45' <: this23' -//│ | 1. C {base: Int, test: ‹∀ 1. test26''#›} base27_51'' <: test26_49'''# +//│ | 1. C {base: Int, test: ‹∀ 2. test26_49'''#›} base27_51'' <: test26_49'''# +//│ | | RECONSTRAINING TVs +//│ | | | 1. C base27_54' {base: Int, test: ‹∀ 2. test26_52'''#›} to 1 +//│ | | where +//│ test26_52'''# := base27_53''' +//│ base27_53''' :> base27_54' | base27_54' <: test26_52'''# +//│ | | 1. C {base: Int, test: ‹∀ 2. test26_52'''#›} -//│ fun test: ‹∀ 1. test63''#› where -//│ | test63''# := (α64'' -> (α68'', α64'', misc69'',)) -//│ | α64'' <: int -//│ | α68'' :> int -//│ | misc69'' :> misc69_70' +//│ this: this88' +//│ super: super89' +//│ | super89' <: {misc: misc97_98'} & {base: base93_94'} +//│ | base93_94' <: int +//│ fun test: ‹∀ 1. test91''#› where +//│ | test91''# := (α92'' -> (α96'', α92'', misc97'',)) +//│ | α92'' <: int +//│ | α96'' :> int +//│ | misc97'' :> misc97_98' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) mixin WrapBase { fun wrap(x) = x } +//│ mixin WrapBase +//│ this: this107' +//│ super: super108' +//│ fun wrap: ‹∀ 1. wrap110''#› where +//│ | wrap110''# := (α111'' -> α111'') +//│ [pretty-printed] wrap: 'a -> 'a + +:d mixin Wrap { fun wrap(x) = [super.wrap(x)] } -//│ mixin WrapBase -//│ this: this80' -//│ super: super81' -//│ fun wrap: ‹∀ 1. wrap83''#› where -//│ | wrap83''# := (α84'' -> α84'') -//│ [pretty-printed] wrap: 'a -> 'a +//│ 0. Typing TypingUnit(List(mixin Wrap() {fun wrap = (x,) => '(' (super).wrap (x,), ')'})) +//│ Completing mixin Wrap() {fun wrap = (x,) => '(' (super).wrap (x,), ')'} +//│ | 1. Typing TypingUnit(List(fun wrap = (x,) => '(' (super).wrap (x,), ')')) +//│ | UNSTASHING... (out) +//│ Completing fun wrap = (x,) => '(' (super).wrap (x,), ')' +//│ | 2. Typing term (x,) => '(' (super).wrap (x,), ')' +//│ | | 2. Typing pattern x, +//│ | | | 2. Typing pattern x +//│ | | | 2. : x121'' +//│ | | 2. : (x121'',) +//│ | | 2. Typing term '(' (super).wrap (x,), ')' +//│ | | | 2. Typing term (super).wrap (x,), +//│ | | | | 2. Typing term (super).wrap (x,) +//│ | | | | | 2. Typing term (super).wrap +//│ | | | | | | 2. Typing term super +//│ | | | | | | 2. : super118' +//│ | | | | | | CONSTRAIN super118' {wrap: wrap122_123'} to 1 +//│ | | | | | | | where +//│ | | | | | | | 2. C super118' α124'') +//│ | | | | | where +//│ wrap122'' :> wrap122_123' +//│ | | | | | 2. C wrap122'' α124'') (0) +//│ | | | | | | NEW wrap122'' UB (2) +//│ | | | | | | 2. C wrap122_123' α124'') (2) +//│ | | | | | | | wrong level: 2 +//│ | | | | | | | RECONSTRAINING TVs +//│ | | | | | | | EXTR RHS ~> (x121_125' -> α124_126') to 1 +//│ | | | | | | | where +//│ | | | | | | | 2. C wrap122_123' α124_126') (4) +//│ | | | | | | | | NEW wrap122_123' UB (1) +//│ | | | | 2. : α124'' +//│ | | | 2. : (α124'',) +//│ | | 2. : (α124'',) +//│ | 2. : (x121'' -> (α124'',)) +//│ | CONSTRAIN (x121'' -> (α124'',)) α124_126' +//│ | 2. C (x121'' -> (α124'',)) α92_94') -//│ fun wrap: ‹∀ 1. wrap88''#› where -//│ | wrap88''# := (α89'' -> (α92'',)) -//│ | α89'' <: α89_93' -//│ | α92'' :> α92_94' +//│ this: this117' +//│ super: super118' +//│ | super118' <: {wrap: wrap122_123'} +//│ | wrap122_123' <: (x121_125' -> α124_126') +//│ ⬤ Typed as: ‹∀ 1. wrap120''#› +//│ where: +//│ wrap120''# := (x121'' -> (α124'',)) +//│ x121'' <: x121_125' +//│ α124'' :> α124_126' +//│ fun wrap: ‹∀ 1. wrap120''#› where +//│ | wrap120''# := (x121'' -> (α124'',)) +//│ | x121'' <: x121_125' +//│ | α124'' :> α124_126' //│ [pretty-printed] wrap: anything -> (nothing,) +:d module WrapBase1: WrapBase, Wrap +//│ 0. Typing TypingUnit(List(namespace WrapBase1(): WrapBase, Wrap {})) +//│ Completing namespace WrapBase1(): WrapBase, Wrap {} +//│ | List() +//│ | +//│ | List(WrapBase, Wrap) +//│ | 1. Inheriting from WrapBase +//│ | | 2. FRESHEN ‹∀ 1. wrap110''#› || 0 .. 1024 0 true +//│ | | => ‹∀ 1. wrap110''#› +//│ | | CONSTRAIN {} (α124'',)) || 1 .. 1024 2 false +//│ | | | | | 3. FRESHEN (x121'',) || 1 .. 1024 2 false +//│ | | | | | | 3. FRESHEN x121'' || 1 .. 1024 2 false +//│ | | | | | | | 3. FRESHEN x121_125' || 1 .. 1024 1 true +//│ | | | | | | | => x121_125' +//│ | | | | | | => x121_138''' +//│ | | | | | => (x121_138''',) +//│ | | | | | 3. FRESHEN (α124'',) || 1 .. 1024 2 false +//│ | | | | | | 3. FRESHEN α124'' || 1 .. 1024 2 false +//│ | | | | | | | 3. FRESHEN α124_126' || 1 .. 1024 1 true +//│ | | | | | | | => α124_126' +//│ | | | | | | => α124_139''' +//│ | | | | | => (α124_139''',) +//│ | | | | => (x121_138''' -> (α124_139''',)) +//│ | | | => wrap120_137'''# +//│ | | | 2. FRESHEN ‹∀ 2. wrap120_137'''#› || 0 .. 1024 1 false +//│ | | | | 2. FRESHEN wrap120_137'''# || 0 .. 2 3 false +//│ | | | | | 2. FRESHEN (x121_138''' -> (α124_139''',)) || 0 .. 2 3 false +//│ | | | | | | 2. FRESHEN (x121_138''',) || 0 .. 2 3 false +//│ | | | | | | | 2. FRESHEN x121_138''' || 0 .. 2 3 false +//│ | | | | | | | | 2. FRESHEN x121_125' || 0 .. 2 1 false +//│ | | | | | | | | => x121_142'' +//│ | | | | | | | => x121_141''' +//│ | | | | | | => (x121_141''',) +//│ | | | | | | 2. FRESHEN (α124_139''',) || 0 .. 2 3 false +//│ | | | | | | | 2. FRESHEN α124_139''' || 0 .. 2 3 false +//│ | | | | | | | | 2. FRESHEN α124_126' || 0 .. 2 1 false +//│ | | | | | | | | => α124_144'' +//│ | | | | | | | => α124_143''' +//│ | | | | | | => (α124_143''',) +//│ | | | | | => (x121_141''' -> (α124_143''',)) +//│ | | | | => wrap120_140'''# +//│ | | | => ‹∀ 2. wrap120_140'''#› +//│ | | => ‹∀ 2. wrap120_140'''#› +//│ | | CONSTRAIN {wrap: ‹∀ 1. wrap110''#›} α111'') +//│ super118' <: {wrap: wrap122_123'} +//│ wrap122_123' <: (x121_125' -> α124_126') +//│ | | 1. C {wrap: ‹∀ 1. wrap110''#›} α124_126') (4) +//│ | | | | | | could be distribbed: Set(α111'') +//│ | | | | | | cannot be distribbed: Set(α111'') +//│ | | | | | | INST [1] ‹∀ 1. wrap110''#› +//│ | | | | | | where +//│ wrap110''# := (α111'' -> α111'') +//│ | | | | | | 1. FRESHEN wrap110''# || 1 .. 1024 2 false +//│ | | | | | | | 1. FRESHEN (α111'' -> α111'') || 1 .. 1024 2 false +//│ | | | | | | | | 1. FRESHEN (α111'',) || 1 .. 1024 2 false +//│ | | | | | | | | | 1. FRESHEN α111'' || 1 .. 1024 2 false +//│ | | | | | | | | | => α111_146' +//│ | | | | | | | | => (α111_146',) +//│ | | | | | | | | 1. FRESHEN α111'' || 1 .. 1024 2 false +//│ | | | | | | | | | 1. FRESHEN α111'' || 1 .. 1024 2 false +//│ | | | | | | | | | => α111_146' +//│ | | | | | | | | => α111_146' +//│ | | | | | | | => (α111_146' -> α111_146') +//│ | | | | | | => wrap110_145'# +//│ | | | | | | TO [1] ~> wrap110_145'# +//│ | | | | | | where +//│ wrap110_145'# := (α111_146' -> α111_146') +//│ | | | | | | 1. C wrap110_145'# α124_126') (6) +//│ | | | | | | | 1. C (α111_146' -> α111_146') α124_126') (9) +//│ | | | | | | | | 1. C (x121_125',) α111'') +//│ this134' <: this117' & this107' +//│ wrap120_140'''# := (x121_141''' -> (α124_143''',)) +//│ x121_141''' <: x121_142'' +//│ α124_143''' :> α124_144'' +//│ | 1. C {wrap: (‹∀ 1. wrap110''#› & ‹∀ 2. wrap120_140'''#›)} α111'') +//│ wrap120_140'''# := (x121_141''' -> (α124_143''',)) +//│ x121_141''' <: x121_142'' +//│ α124_143''' :> α124_144'' +//│ | | RECONSTRAINING TVs +//│ | | EXTR LHS ~> {wrap: (‹∀ 1. wrap110''#› & ‹∀ 2. wrap120_147'''#›)} to 1 +//│ | | where +//│ wrap110''# := (α111'' -> α111'') +//│ wrap120_147'''# := (x121_148''' -> (α124_150''',)) +//│ x121_148''' <: x121_149' +//│ α124_150''' :> α124_151' +//│ | | 1. C {wrap: (‹∀ 1. wrap110''#› & ‹∀ 2. wrap120_147'''#›)} ('a,) +//│ 0. Typing TypingUnit(List((WrapBase1).wrap)) +//│ | 0. Typing term (WrapBase1).wrap +//│ | | 0. Typing term WrapBase1 +//│ | | 0. : WrapBase1<> +//│ | | CONSTRAIN WrapBase1<> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_140'''#›))) +//│ | | | (>>,0,1) +//│ | | | 2. FRESHEN ‹∀ 2. wrap120_140'''#› || 1 .. 1024 2 false +//│ | | | | 2. FRESHEN wrap120_140'''# || 1 .. 2 3 false +//│ | | | | | 2. FRESHEN (x121_141''' -> (α124_143''',)) || 1 .. 2 3 false +//│ | | | | | | 2. FRESHEN (x121_141''',) || 1 .. 2 3 false +//│ | | | | | | | 2. FRESHEN x121_141''' || 1 .. 2 3 false +//│ | | | | | | | | 2. FRESHEN x121_142'' || 1 .. 2 2 false +//│ | | | | | | | | | New skolem: x121_142'' ~> ‘x155'' +//│ | | | | | | | | | 2. FRESHEN x121_149' || 1 .. 2 1 true +//│ | | | | | | | | | => x121_149' +//│ | | | | | | | | | x121_156'' :> List((‘x155'' & x121_149')) +//│ | | | | | | | | | x121_156'' <: List(‘x155'') +//│ | | | | | | | | => x121_156'' +//│ | | | | | | | => x121_154''' +//│ | | | | | | => (x121_154''',) +//│ | | | | | | 2. FRESHEN (α124_143''',) || 1 .. 2 3 false +//│ | | | | | | | 2. FRESHEN α124_143''' || 1 .. 2 3 false +//│ | | | | | | | | 2. FRESHEN α124_144'' || 1 .. 2 2 false +//│ | | | | | | | | | New skolem: α124_144'' ~> ‘_158'' +//│ | | | | | | | | | α124_159'' :> List(‘_158'') +//│ | | | | | | | | | 2. FRESHEN α124_151' || 1 .. 2 1 true +//│ | | | | | | | | | => α124_151' +//│ | | | | | | | | | α124_159'' <: List((‘_158'' | α124_151')) +//│ | | | | | | | | => α124_159'' +//│ | | | | | | | => α124_157''' +//│ | | | | | | => (α124_157''',) +//│ | | | | | => (x121_154''' -> (α124_157''',)) +//│ | | | | => wrap120_153'''# +//│ | | | => ‹∀ 2. wrap120_153'''#› +//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_153'''#›))) +//│ | | | List( +//│ wrap120_153'''# := (x121_154''' -> (α124_157''',)) +//│ x121_154''' <: x121_156'' +//│ x121_156'' :> (‘x155'' & x121_149') <: ‘x155'' +//│ α124_157''' :> α124_159'' +//│ α124_159'' :> ‘_158'' <: (‘_158'' | α124_151')) +//│ | | | (wrap,Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_153'''#›))) +//│ | | | 0. C ‹∀ 2. wrap120_153'''#› (α124_157''',)) +//│ x121_154''' <: x121_156'' +//│ x121_156'' :> (‘x155'' & x121_149') <: ‘x155'' +//│ α124_157''' :> α124_159'' +//│ α124_159'' :> ‘_158'' <: (‘_158'' | α124_151') +//│ | | | | RECONSTRAINING TVs +//│ | | | | EXTR LHS ~> ‹∀ 2. wrap120_160'''#› to 0 +//│ | | | | where +//│ wrap120_160'''# := (x121_161''' -> (α124_163''',)) +//│ x121_161''' <: x121_162 +//│ x121_162 <: ⊥ +//│ α124_163''' :> α124_164 +//│ α124_164 :> ⊤ +//│ | | | | 0. C ‹∀ 2. wrap120_160'''#› ‹∀ 2. wrap120_160'''#› +//│ wrap120_160'''# := (x121_161''' -> (α124_163''',)) +//│ x121_161''' <: x121_162 +//│ x121_162 <: ⊥ +//│ α124_163''' :> α124_164 +//│ α124_164 :> ⊤ +//│ Typed: nothing -> (anything,) + +:d +WrapBase1.wrap +//│ 0. Typing TypingUnit(List((WrapBase1).wrap)) +//│ | 0. Typing term (WrapBase1).wrap +//│ | | 0. Typing term WrapBase1 +//│ | | 0. : WrapBase1<> +//│ | | CONSTRAIN WrapBase1<> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_140'''#›))) +//│ | | | (>>,0,1) +//│ | | | 2. FRESHEN ‹∀ 2. wrap120_140'''#› || 1 .. 1024 2 false +//│ | | | | 2. FRESHEN wrap120_140'''# || 1 .. 2 3 false +//│ | | | | | 2. FRESHEN (x121_141''' -> (α124_143''',)) || 1 .. 2 3 false +//│ | | | | | | 2. FRESHEN (x121_141''',) || 1 .. 2 3 false +//│ | | | | | | | 2. FRESHEN x121_141''' || 1 .. 2 3 false +//│ | | | | | | | | 2. FRESHEN x121_142'' || 1 .. 2 2 false +//│ | | | | | | | | | New skolem: x121_142'' ~> ‘x174'' +//│ | | | | | | | | | 2. FRESHEN x121_149' || 1 .. 2 1 true +//│ | | | | | | | | | => x121_149' +//│ | | | | | | | | | x121_175'' :> List((‘x174'' & x121_149')) +//│ | | | | | | | | | x121_175'' <: List(‘x174'') +//│ | | | | | | | | => x121_175'' +//│ | | | | | | | => x121_173''' +//│ | | | | | | => (x121_173''',) +//│ | | | | | | 2. FRESHEN (α124_143''',) || 1 .. 2 3 false +//│ | | | | | | | 2. FRESHEN α124_143''' || 1 .. 2 3 false +//│ | | | | | | | | 2. FRESHEN α124_144'' || 1 .. 2 2 false +//│ | | | | | | | | | New skolem: α124_144'' ~> ‘_177'' +//│ | | | | | | | | | α124_178'' :> List(‘_177'') +//│ | | | | | | | | | 2. FRESHEN α124_151' || 1 .. 2 1 true +//│ | | | | | | | | | => α124_151' +//│ | | | | | | | | | α124_178'' <: List((‘_177'' | α124_151')) +//│ | | | | | | | | => α124_178'' +//│ | | | | | | | => α124_176''' +//│ | | | | | | => (α124_176''',) +//│ | | | | | => (x121_173''' -> (α124_176''',)) +//│ | | | | => wrap120_172'''# +//│ | | | => ‹∀ 2. wrap120_172'''#› +//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_172'''#›))) +//│ | | | List( +//│ wrap120_172'''# := (x121_173''' -> (α124_176''',)) +//│ x121_173''' <: x121_175'' +//│ x121_175'' :> (‘x174'' & x121_149') <: ‘x174'' +//│ α124_176''' :> α124_178'' +//│ α124_178'' :> ‘_177'' <: (‘_177'' | α124_151')) +//│ | | | (wrap,Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_172'''#›))) +//│ | | | 0. C ‹∀ 2. wrap120_172'''#› (α124_176''',)) +//│ x121_173''' <: x121_175'' +//│ x121_175'' :> (‘x174'' & x121_149') <: ‘x174'' +//│ α124_176''' :> α124_178'' +//│ α124_178'' :> ‘_177'' <: (‘_177'' | α124_151') +//│ | | | | RECONSTRAINING TVs +//│ | | | | EXTR LHS ~> ‹∀ 2. wrap120_179'''#› to 0 +//│ | | | | where +//│ wrap120_179'''# := (x121_180''' -> (α124_182''',)) +//│ x121_180''' <: x121_181 +//│ x121_181 <: ⊥ +//│ α124_182''' :> α124_183 +//│ α124_183 :> ⊤ +//│ | | | | 0. C ‹∀ 2. wrap120_179'''#› ‹∀ 2. wrap120_179'''#› +//│ wrap120_179'''# := (x121_180''' -> (α124_182''',)) +//│ x121_180''' <: x121_181 +//│ x121_181 <: ⊥ +//│ α124_182''' :> α124_183 +//│ α124_183 :> ⊤ +//│ Typed: nothing -> (anything,) WrapBase1.wrap(1) -//│ Typed: (1,) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.533: WrapBase1.wrap(1) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── integer literal of type `1` does not match type `nothing` +//│ ║ l.533: WrapBase1.wrap(1) +//│ ╙── ^ +//│ Typed: (anything,) | error // FIXME WrapBase1.wrap("ok") -//│ Typed: ("ok" | 1,) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.543: WrapBase1.wrap("ok") +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── string literal of type `"ok"` does not match type `nothing` +//│ ║ l.543: WrapBase1.wrap("ok") +//│ ╙── ^^^^ +//│ Typed: (anything,) | error module WrapBase2: WrapBase, Wrap, Wrap @@ -165,6 +555,6 @@ module WrapBase2: WrapBase, Wrap, Wrap // FIXME WrapBase2.wrap -//│ Typed: 'a -> ("ok" | 1 | 'a,) +//│ Typed: 'a -> ('a,) diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 95347cc180..da422b5816 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -16,7 +16,6 @@ fun fooo(x) = C(0, x) //│ fun fooo: ‹∀ 0. fooo26'#› where //│ | fooo26'# := (α27' -> α35') -//│ | α27' <: z30_34' //│ | α35' :> C<> //│ [pretty-printed] fooo: anything -> C @@ -29,14 +28,14 @@ module Test0_2 { fun b = 123 } //│ class Test0_1 -//│ fun a: ‹∀ 1. a45''#› where -//│ | a45''# := b50'' -//│ | b49''# := 123 -//│ | b50'' :> ‹∀ 1. b49''#› <: a45''# +//│ fun a: ‹∀ 1. a44''#› where +//│ | a44''# := b49'' +//│ | b48''# := 123 +//│ | b49'' :> ‹∀ 1. b48''#› <: a44''# //│ [pretty-printed] a: 123 //│ class Test0_2 -//│ fun b: ‹∀ 1. b49''#› where -//│ | b49''# := 123 +//│ fun b: ‹∀ 1. b48''#› where +//│ | b48''# := 123 //│ [pretty-printed] b: 123 Test0_1.a @@ -50,16 +49,16 @@ module Test1_2 { fun b = Test1_1.a } //│ class Test1_1 -//│ fun a: ‹∀ 1. a67''#› where -//│ | a67''# := b74'' -//│ | b71''# := a72'' -//│ | a72'' :> a72_73 <: b71''# -//│ | b74'' :> ‹∀ 1. b71''#› <: a67''# +//│ fun a: ‹∀ 1. a66''#› where +//│ | a66''# := b73'' +//│ | b70''# := a71'' +//│ | a71'' :> a71_72 <: b70''# +//│ | b73'' :> ‹∀ 1. b70''#› <: a66''# //│ [pretty-printed] a: nothing //│ class Test1_2 -//│ fun b: ‹∀ 1. b71''#› where -//│ | b71''# := a72'' -//│ | a72'' :> a72_73 <: b71''# +//│ fun b: ‹∀ 1. b70''#› where +//│ | b70''# := a71'' +//│ | a71'' :> a71_72 <: b70''# //│ [pretty-printed] b: nothing Test1_1.a @@ -79,34 +78,34 @@ module Test2_2 { fun e = Test2_1.n } //│ class Test2_1 -//│ fun t2: ‹∀ 1. t2100''#› where -//│ | t2100''# := Test2_2<> +//│ fun t2: ‹∀ 1. t299''#› where +//│ | t299''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a113''#› where -//│ | b106''# := 123 -//│ | a113''# := b114'' -//│ | b114'' :> ‹∀ 1. b106''#› <: a113''# +//│ fun a: ‹∀ 1. a112''#› where +//│ | b105''# := 123 +//│ | a112''# := b113'' +//│ | b113'' :> ‹∀ 1. b105''#› <: a112''# //│ [pretty-printed] a: 123 -//│ fun d: ‹∀ 1. d118''#› where -//│ | e110''# := n111'' -//│ | n111'' :> n111_112 <: e110''# -//│ | d118''# := e119'' -//│ | e119'' :> ‹∀ 1. e110''#› <: d118''# +//│ fun d: ‹∀ 1. d117''#› where +//│ | e109''# := n110'' +//│ | n110'' :> n110_111 <: e109''# +//│ | d117''# := e118'' +//│ | e118'' :> ‹∀ 1. e109''#› <: d117''# //│ [pretty-printed] d: nothing -//│ fun n: ‹∀ 1. n123''#› where -//│ | n123''# := 456 +//│ fun n: ‹∀ 1. n122''#› where +//│ | n122''# := 456 //│ [pretty-printed] n: 456 //│ class Test2_2 -//│ fun b: ‹∀ 1. b106''#› where -//│ | b106''# := 123 +//│ fun b: ‹∀ 1. b105''#› where +//│ | b105''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c107''#› where -//│ | c107''# := a108'' -//│ | a108'' :> a108_109 <: c107''# +//│ fun c: ‹∀ 1. c106''#› where +//│ | c106''# := a107'' +//│ | a107'' :> a107_108 <: c106''# //│ [pretty-printed] c: nothing -//│ fun e: ‹∀ 1. e110''#› where -//│ | e110''# := n111'' -//│ | n111'' :> n111_112 <: e110''# +//│ fun e: ‹∀ 1. e109''#› where +//│ | e109''# := n110'' +//│ | n110'' :> n110_111 <: e109''# //│ [pretty-printed] e: nothing Test2_1.t2.b From 2239e0552616ca35aab7f22b9d916f508ad89657 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Feb 2023 22:40:07 +0800 Subject: [PATCH 019/498] WIP --- .../scala/mlscript/ConstraintSolver.scala | 3 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 6 +- shared/src/test/diff/nu/BasicClasses.mls | 365 +++++++---- shared/src/test/diff/nu/BasicMixins.mls | 596 +++++++----------- 4 files changed, 496 insertions(+), 474 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 4ff5d59d43..eecd88c284 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -568,7 +568,8 @@ class ConstraintSolver extends NormalForms { self: Typer => implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty println(td) - val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] + // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] + val res = td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] println(res) // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) res diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 054c4d23e7..9ec1c0b842 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -60,14 +60,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty // println(level) + ctx.copy(lvl = level + 1) |> { implicit ctx => freshenAbove(level, rigidify = false) + } } def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedNuTermDef = { // implicit val freshened: MutMap[TV, ST] = MutMap.empty // implicit val shadows: Shadows = Shadows.empty - ctx.copy(lvl = level + 1) |> { implicit ctx => + // ctx.copy(lvl = level + 1) |> { implicit ctx => this match { case m @ TypedNuMxn(td, thisTV, superTV, ttu) => // println(">>",m.level) @@ -85,7 +87,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap) // case _ => ??? - } + // } } } def force()(implicit raise: Raise): Unit = this match { diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index d7e58383dc..4547fe74e1 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -14,38 +14,41 @@ class Base0(n) { //│ fun me: ‹∀ 1. me30''#› where //│ | this24' :> Base0<> <: {my: my36_37'} & {n: n32_33'} //│ | me30''# := this24' -//│ | my31''# := n32'' -//│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | mine34''# := my31''# -//│ | my36_37' :> ‹∀ 1. my31''#› +//│ | n32_33' :> ‘n68 +//│ | my36_37' :> ‹∀ 1. my31_45''#› +//│ | my31_45''# := n32_46'' +//│ | n32_46'' :> ‘n43 <: mine34_47''# & my31_45''# +//│ | mine34_47''# := my31_45''# //│ [pretty-printed] me: Base0 //│ fun my: ‹∀ 1. my31''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | n32_33' :> ‘n68 //│ | mine34''# := my31''# -//│ [pretty-printed] my: nothing +//│ [pretty-printed] my: 'n //│ fun mine: ‹∀ 1. mine34''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# +//│ | n32_33' :> ‘n68 //│ | mine34''# := my31''# -//│ [pretty-printed] mine: nothing +//│ [pretty-printed] mine: 'n //│ fun oops: ‹∀ 1. oops35''#› where -//│ | my31''# := n32'' -//│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | mine34''# := my31''# //│ | oops35''# := my36'' //│ | my36'' :> my36_37' <: oops35''# -//│ | my36_37' :> ‹∀ 1. my31''#› -//│ [pretty-printed] oops: nothing +//│ | my36_37' :> ‹∀ 1. my31_45''#› +//│ | my31_45''# := n32_46'' +//│ | n32_46'' :> ‘n43 <: mine34_47''# & my31_45''# +//│ | mine34_47''# := my31_45''# +//│ [pretty-printed] oops: 'n // :d // Base0 // Base0 let b1 = Base0(42) -//│ fun b1: ‹∀ 0. b162'#› where -//│ | b162'# := α113' -//│ | α113' :> Base0<> <: b162'# +//│ fun b1: ‹∀ 0. b184'#› where +//│ | b184'# := α99' +//│ | α99' :> Base0<> <: b184'# //│ [pretty-printed] b1: Base0 :d @@ -54,86 +57,172 @@ let n1 = b1.n //│ Completing let n1 = (b1).n //│ | 1. Typing term (b1).n //│ | | 1. Typing term b1 -//│ | | 1. : b162'# -//│ | | CONSTRAIN b162'# Base0<> <: b162'# -//│ | | 1. C b162'# Base0<> <: b184'# +//│ | | 1. C b184'# TypedNuFun(1,fun me = this,‹∀ 1. me30''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›)),None),List((n,n23')),HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) //│ | | | | | | (>>,0,1) -//│ | | | | | | 2. FRESHEN ‹∀ 1. me30''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. me30''#› -//│ | | | | | | 2. FRESHEN ‹∀ 1. my31''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. my31''#› -//│ | | | | | | 2. FRESHEN ‹∀ 1. mine34''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. mine34''#› -//│ | | | | | | 2. FRESHEN ‹∀ 1. oops35''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. oops35''#› -//│ | | | | | | 1. FRESHEN n23' || 1 .. 1024 1 true -//│ | | | | | | => n23' -//│ | | | | | | 1. FRESHEN n23' || 1 .. 1024 1 true -//│ | | | | | | => n23' -//│ | | | | | | 2. FRESHEN ‹∀ 1. mine34''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. mine34''#› -//│ | | | | | | 2. FRESHEN ‹∀ 1. oops35''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. oops35''#› -//│ | | | | | | 2. FRESHEN ‹∀ 1. my31''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. my31''#› -//│ | | | | | | 2. FRESHEN ‹∀ 1. me30''#› || 1 .. 1024 1 true -//│ | | | | | | => ‹∀ 1. me30''#› -//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›)),None),List((n,n23')),HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) -//│ | | | | | | (n,HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) -//│ | | | | | | 1. C n23' ‘this107' +//│ | | | | | | | | | | 1. FRESHEN Base0<> || 0 .. 1 0 true +//│ | | | | | | | | | | => Base0<> +//│ | | | | | | | | | | this24_108' :> List((‘this107' & Base0<>)) +//│ | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false +//│ | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | | | | 1. FRESHEN my36_37' || 0 .. 1 1 false +//│ | | | | | | | | | | | | | | | | New skolem: my36_37' ~> ‘my109' +//│ | | | | | | | | | | | | | | | | 1. FRESHEN ‹∀ 1. my31_45''#› || 0 .. 1 0 true +//│ | | | | | | | | | | | | | | | | => ‹∀ 1. my31_45''#› +//│ | | | | | | | | | | | | | | | | my36_110' :> List((‘my109' & ‹∀ 1. my31_45''#›)) +//│ | | | | | | | | | | | | | | | | my36_110' <: List(‘my109') +//│ | | | | | | | | | | | | | | | => my36_110' +//│ | | | | | | | | | | | | | | => {my: my36_110'} +//│ | | | | | | | | | | | | | => {my: my36_110'} +//│ | | | | | | | | | | | | => {my: my36_110'} +//│ | | | | | | | | | | | => {my: my36_110'} +//│ | | | | | | | | | | => {my: my36_110'} +//│ | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false +//│ | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false +//│ | | | | | | | | | | | | | | | 1. FRESHEN n32_33' || 0 .. 1 1 false +//│ | | | | | | | | | | | | | | | | New skolem: n32_33' ~> ‘n111' +//│ | | | | | | | | | | | | | | | | 1. FRESHEN ‘n68 || 0 .. 1 0 true +//│ | | | | | | | | | | | | | | | | => ‘n68 +//│ | | | | | | | | | | | | | | | | n32_112' :> List((‘n111' & ‘n68)) +//│ | | | | | | | | | | | | | | | | n32_112' <: List(‘n111') +//│ | | | | | | | | | | | | | | | => n32_112' +//│ | | | | | | | | | | | | | | => {n: n32_112'} +//│ | | | | | | | | | | | | | => {n: n32_112'} +//│ | | | | | | | | | | | | => {n: n32_112'} +//│ | | | | | | | | | | | => {n: n32_112'} +//│ | | | | | | | | | | => {n: n32_112'} +//│ | | | | | | | | | | this24_108' <: List(((‘this107' | {my: my36_110'}) | {n: n32_112'})) +//│ | | | | | | | | | => this24_108' +//│ | | | | | | | | => this24_108' +//│ | | | | | | | => me30_106''# +//│ | | | | | | => ‹∀ 1. me30_106''#› +//│ | | | | | | 1. FRESHEN ‹∀ 1. my31''#› || 0 .. 1024 1 false +//│ | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false +//│ | | | | | | | | 1. FRESHEN n32'' || 0 .. 1 2 false +//│ | | | | | | | | | 1. FRESHEN n32_33' || 0 .. 1 1 false +//│ | | | | | | | | | => n32_112' +//│ | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false +//│ | | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false +//│ | | | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false +//│ | | | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false +//│ | | | | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false +//│ | | | | | | | | | | | | | => my31_114'' +//│ | | | | | | | | | | | | => my31_114'' +//│ | | | | | | | | | | | => mine34_116''# +//│ | | | | | | | | | | => mine34_116''# +//│ | | | | | | | | | => mine34_116''# +//│ | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false +//│ | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false +//│ | | | | | | | | | | => my31_114'' +//│ | | | | | | | | | => my31_114'' +//│ | | | | | | | | => n32_115'' +//│ | | | | | | | => my31_114''# +//│ | | | | | | => ‹∀ 1. my31_114''#› +//│ | | | | | | 1. FRESHEN ‹∀ 1. mine34''#› || 0 .. 1024 1 false +//│ | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false +//│ | | | | | | | => mine34_116''# +//│ | | | | | | => ‹∀ 1. mine34_116''#› +//│ | | | | | | 1. FRESHEN ‹∀ 1. oops35''#› || 0 .. 1024 1 false +//│ | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false +//│ | | | | | | | | 1. FRESHEN my36'' || 0 .. 1 2 false +//│ | | | | | | | | | 1. FRESHEN my36_37' || 0 .. 1 1 false +//│ | | | | | | | | | => my36_110' +//│ | | | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false +//│ | | | | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false +//│ | | | | | | | | | | => oops35_119'' +//│ | | | | | | | | | => oops35_119'' +//│ | | | | | | | | => my36_120'' +//│ | | | | | | | => oops35_119''# +//│ | | | | | | => ‹∀ 1. oops35_119''#› +//│ | | | | | | 1. FRESHEN n23' || 0 .. 1024 1 false +//│ | | | | | | | New skolem: n23' ~> ‘n121' +//│ | | | | | | => ‘n121' +//│ | | | | | | 1. FRESHEN n23' || 0 .. 1024 1 false +//│ | | | | | | => ‘n121' +//│ | | | | | | 1. FRESHEN ‹∀ 1. mine34''#› || 0 .. 1024 1 false +//│ | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false +//│ | | | | | | | => mine34_116''# +//│ | | | | | | => ‹∀ 1. mine34_116''#› +//│ | | | | | | 1. FRESHEN ‹∀ 1. oops35''#› || 0 .. 1024 1 false +//│ | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false +//│ | | | | | | | => oops35_119''# +//│ | | | | | | => ‹∀ 1. oops35_119''#› +//│ | | | | | | 1. FRESHEN ‹∀ 1. my31''#› || 0 .. 1024 1 false +//│ | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false +//│ | | | | | | | => my31_114''# +//│ | | | | | | => ‹∀ 1. my31_114''#› +//│ | | | | | | 1. FRESHEN ‹∀ 1. me30''#› || 0 .. 1024 1 false +//│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false +//│ | | | | | | | => me30_106''# +//│ | | | | | | => ‹∀ 1. me30_106''#› +//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_114''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_116''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_119''#›)),None),List((n,‘n121')),HashMap(n -> NuParam(n,‘n121'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_116''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_119''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_114''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) +//│ | | | | | | (n,HashMap(n -> NuParam(n,‘n121'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_116''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_119''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_114''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) +//│ | | | | | | 1. C ‘n121' ‘n121' +//│ | 1. C n104' ‘n121' <: n1103'# +//│ fun n1: ‹∀ 0. n1103'#› where +//│ | n1103'# := n104' +//│ | n104' :> ‘n121' <: n1103'# +//│ [pretty-printed] n1: 'n // TODO n1 + 1 -//│ Typed: int +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.201: n1 + 1 +//│ ║ ^^^^ +//│ ╟── reference of type `?n` is not an instance of type `int` +//│ ║ l.7: class Base0(n) { +//│ ║ ^ +//│ ╟── but it flows into reference with expected type `int` +//│ ║ l.201: n1 + 1 +//│ ╙── ^^ +//│ Typed: error | int let b2 = Base0("hi") let n2 = b2.n -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.113: let b2 = Base0("hi") -//│ ║ ^^^^^^^^^^^ -//│ ╟── string literal of type `"hi"` is not an instance of type `int` -//│ ║ l.113: let b2 = Base0("hi") -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.109: n1 + 1 -//│ ║ ^^ -//│ ╟── from reference: -//│ ║ l.7: class Base0(n) { -//│ ╙── ^ -//│ fun b2: ‹∀ 0. b2130'#› where -//│ | b2130'# := α183' -//│ | α183' :> Base0<> | error<> <: {n: n185'} & b2130'# -//│ | n2184'# := n185' -//│ | n185' :> error<> <: n2184'# -//│ [pretty-printed] b2: Base0 | error -//│ fun n2: ‹∀ 0. n2184'#› where -//│ | n2184'# := n185' -//│ | n185' :> error<> <: n2184'# -//│ [pretty-printed] n2: error +//│ fun b2: ‹∀ 0. b2129'#› where +//│ | b2129'# := α144' +//│ | α144' :> Base0<> <: {n: n146'} & b2129'# +//│ | n2145'# := n146' +//│ | n146' :> ‘n163' <: n2145'# +//│ [pretty-printed] b2: Base0 +//│ fun n2: ‹∀ 0. n2145'#› where +//│ | n2145'# := n146' +//│ | n146' :> ‘n163' <: n2145'# +//│ [pretty-printed] n2: 'n @@ -143,18 +232,18 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1200''#› where -//│ | getBase1200''# := Int +//│ fun getBase1: ‹∀ 1. getBase1174''#› where +//│ | getBase1174''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase2201''#› where -//│ | getBase2201''# := base202'' -//│ | base202'' :> base202_203' <: getBase2201''# -//│ | base202_203' :> Int +//│ fun getBase2: ‹∀ 1. getBase2175''#› where +//│ | getBase2175''# := base176'' +//│ | base176'' :> base176_177' <: getBase2175''# +//│ | base176_177' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo204''#› where -//│ | foo204''# := (α205'' -> α209'') -//│ | α205'' <: int -//│ | α209'' :> int +//│ fun foo: ‹∀ 1. foo178''#› where +//│ | foo178''# := (α179'' -> α183'') +//│ | α179'' <: int +//│ | α183'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -163,26 +252,26 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1229''#› where -//│ | getBase1229''# := Int +//│ fun getBase1: ‹∀ 1. getBase1209''#› where +//│ | getBase1209''# := Int //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me230''#› where -//│ | this224' :> Base1<> -//│ | me230''# := this224' +//│ fun me: ‹∀ 1. me210''#› where +//│ | this204' :> Base1<> +//│ | me210''# := this204' //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo231''#› where -//│ | foo231''# := (α232'' -> α234'') -//│ | α232'' <: int -//│ | α234'' :> int +//│ fun foo: ‹∀ 1. foo211''#› where +//│ | foo211''# := (α212'' -> α214'') +//│ | α212'' <: int +//│ | α214'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b250'#› where -//│ | b250'# := α259' -//│ | α259' :> Base1<> <: b250'# +//│ fun b: ‹∀ 0. b227'#› where +//│ | b227'# := α233' +//│ | α233' :> Base1<> <: b227'# //│ [pretty-printed] b: Base1 b.base @@ -191,13 +280,67 @@ b.base b.getBase1 //│ Typed: int +:d b.me -//│ Typed: Base1 +//│ 0. Typing TypingUnit(List((b).me)) +//│ | 0. Typing term (b).me +//│ | | 0. Typing term b +//│ | | 0. : b227'# +//│ | | CONSTRAIN b227'# Base1<> <: {getBase1: getBase1244} & {base: base236} & b227'# +//│ base236 :> Int +//│ getBase1244 :> ‹∀ 1. getBase1209''#› +//│ | | 0. C b227'# + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1209''#›), me ~> TypedNuFun(1,fun me = this,‹∀ 1. me210''#›), foo ~> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1209''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me210''#›), foo -> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›))) +//│ | | | | | | (>>,0,0) +//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1209''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. getBase1209''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. me210''#› || 0 .. 1024 1 false +//│ | | | | | | | 0. FRESHEN me210''# || 0 .. 1 2 false +//│ | | | | | | | | 0. FRESHEN this204' || 0 .. 1 1 false +//│ | | | | | | | | | 0. FRESHEN this204' || 0 .. 1 1 false +//│ | | | | | | | | | | New skolem: this204' ~> ‘this257 +//│ | | | | | | | | | | 0. FRESHEN Base1<> || 0 .. 1 0 true +//│ | | | | | | | | | | => Base1<> +//│ | | | | | | | | | | this204_258 :> List((‘this257 & Base1<>)) +//│ | | | | | | | | | | this204_258 <: List(‘this257) +//│ | | | | | | | | | => this204_258 +//│ | | | | | | | | => this204_258 +//│ | | | | | | | => me210_256''# +//│ | | | | | | => ‹∀ 1. me210_256''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. foo211''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. foo211''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1209''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. getBase1209''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. me210''#› || 0 .. 1024 1 false +//│ | | | | | | | 0. FRESHEN me210''# || 0 .. 1 2 false +//│ | | | | | | | => me210_256''# +//│ | | | | | | => ‹∀ 1. me210_256''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. foo211''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. foo211''#› +//│ | | | | | | TypedNuCls(0,class Base1(base: int,) {fun getBase1 = base; fun me = this; fun foo = (x,) => + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1209''#›), me ~> TypedNuFun(0,fun me = this,‹∀ 1. me210_256''#›), foo ~> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1209''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me210_256''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›))) +//│ | | | | | | (me,Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1209''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me210_256''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›))) +//│ | | | | | | 0. C ‹∀ 1. me210_256''#› ‹∀ 1. me210_256''#› +//│ me210_256''# := this204_258 +//│ this204_258 :> (‘this257 & Base1<>) <: ‘this257 +//│ Typed: Base1 & 'this :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.198: b.getBaseTypo +//│ ║ l.341: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -213,20 +356,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.212: a: int +//│ ║ l.355: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.211: class Annots(base: 0 | 1) { +//│ ║ l.354: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.212: a: int +//│ ║ l.355: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.212: a: int +//│ ║ l.355: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a292''#› where -//│ | a292''# := ((0 | 1),) +//│ fun a: ‹∀ 1. a275''#› where +//│ | a275''# := ((0 | 1),) //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 4668628651..c6fd5ad609 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -42,30 +42,18 @@ class Base1(base: int): BaseTest //│ | base: int, //│ | List(BaseTest) //│ | 1. Inheriting from BaseTest -//│ | | 2. FRESHEN ‹∀ 1. test26''#› || 0 .. 1024 1 false -//│ | | | 3. FRESHEN test26''# || 1 .. 1024 2 false -//│ | | | | 3. FRESHEN base27'' || 1 .. 1024 2 false -//│ | | | | | 3. FRESHEN base27_28' || 1 .. 1024 1 true -//│ | | | | | => base27_28' -//│ | | | | | 3. FRESHEN test26''# || 1 .. 1024 2 false -//│ | | | | | | 3. FRESHEN test26''# || 1 .. 1024 2 false -//│ | | | | | | => test26_47''' -//│ | | | | | => test26_47''' -//│ | | | | => base27_48''' -//│ | | | => test26_47'''# -//│ | | | 2. FRESHEN ‹∀ 2. test26_47'''#› || 0 .. 1024 1 false -//│ | | | | 2. FRESHEN test26_47'''# || 0 .. 2 3 false -//│ | | | | | 2. FRESHEN base27_48''' || 0 .. 2 3 false -//│ | | | | | | 2. FRESHEN base27_28' || 0 .. 2 1 false -//│ | | | | | | => base27_51'' -//│ | | | | | | 2. FRESHEN test26_47'''# || 0 .. 2 3 false -//│ | | | | | | | 2. FRESHEN test26_47'''# || 0 .. 2 3 false -//│ | | | | | | | => test26_49''' -//│ | | | | | | => test26_49''' -//│ | | | | | => base27_50''' -//│ | | | | => test26_49'''# -//│ | | | => ‹∀ 2. test26_49'''#› -//│ | | => ‹∀ 2. test26_49'''#› +//│ | | 1. FRESHEN ‹∀ 1. test26''#› || 0 .. 1024 1 false +//│ | | | 1. FRESHEN test26''# || 0 .. 1 2 false +//│ | | | | 1. FRESHEN base27'' || 0 .. 1 2 false +//│ | | | | | 1. FRESHEN base27_28' || 0 .. 1 1 false +//│ | | | | | => base27_49' +//│ | | | | | 1. FRESHEN test26''# || 0 .. 1 2 false +//│ | | | | | | 1. FRESHEN test26''# || 0 .. 1 2 false +//│ | | | | | | => test26_47'' +//│ | | | | | => test26_47'' +//│ | | | | => base27_48'' +//│ | | | => test26_47''# +//│ | | => ‹∀ 1. test26_47''#› //│ | | CONSTRAIN {base: Int} base27_51'' <: test26_49'''# -//│ | 1. C {base: Int, test: ‹∀ 2. test26_49'''#›} base27_51'' <: test26_49'''# -//│ | | RECONSTRAINING TVs -//│ | | | 1. C base27_54' {base: Int, test: ‹∀ 2. test26_52'''#›} to 1 -//│ | | where -//│ test26_52'''# := base27_53''' -//│ base27_53''' :> base27_54' | base27_54' <: test26_52'''# -//│ | | 1. C {base: Int, test: ‹∀ 2. test26_52'''#›} base27_49' <: test26_47''# +//│ | 1. C {base: Int, test: ‹∀ 1. test26_47''#›} -//│ fun test: ‹∀ 1. test91''#› where -//│ | test91''# := (α92'' -> (α96'', α92'', misc97'',)) -//│ | α92'' <: int -//│ | α96'' :> int -//│ | misc97'' :> misc97_98' +//│ this: this72' +//│ super: super73' +//│ | super73' <: {misc: misc81_82'} & {base: base77_78'} +//│ | base77_78' <: int +//│ fun test: ‹∀ 1. test75''#› where +//│ | test75''# := (α76'' -> (α80'', α76'', misc81'',)) +//│ | α76'' <: int +//│ | α80'' :> int +//│ | misc81'' :> misc81_82' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) @@ -161,10 +132,10 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase -//│ this: this107' -//│ super: super108' -//│ fun wrap: ‹∀ 1. wrap110''#› where -//│ | wrap110''# := (α111'' -> α111'') +//│ this: this91' +//│ super: super92' +//│ fun wrap: ‹∀ 1. wrap94''#› where +//│ | wrap94''# := (α95'' -> α95'') //│ [pretty-printed] wrap: 'a -> 'a :d @@ -179,63 +150,63 @@ mixin Wrap { //│ | 2. Typing term (x,) => '(' (super).wrap (x,), ')' //│ | | 2. Typing pattern x, //│ | | | 2. Typing pattern x -//│ | | | 2. : x121'' -//│ | | 2. : (x121'',) +//│ | | | 2. : x105'' +//│ | | 2. : (x105'',) //│ | | 2. Typing term '(' (super).wrap (x,), ')' //│ | | | 2. Typing term (super).wrap (x,), //│ | | | | 2. Typing term (super).wrap (x,) //│ | | | | | 2. Typing term (super).wrap //│ | | | | | | 2. Typing term super -//│ | | | | | | 2. : super118' -//│ | | | | | | CONSTRAIN super118' {wrap: wrap122_123'} to 1 +//│ | | | | | | | EXTR RHS ~> {wrap: wrap106_107'} to 1 //│ | | | | | | | where -//│ | | | | | | | 2. C super118' α124'') +//│ | | | | | 2. : x105'' +//│ | | | | | CONSTRAIN wrap106'' α108'') //│ | | | | | where -//│ wrap122'' :> wrap122_123' -//│ | | | | | 2. C wrap122'' α124'') (0) -//│ | | | | | | NEW wrap122'' UB (2) -//│ | | | | | | 2. C wrap122_123' α124'') (2) +//│ wrap106'' :> wrap106_107' +//│ | | | | | 2. C wrap106'' α108'') (0) +//│ | | | | | | NEW wrap106'' UB (2) +//│ | | | | | | 2. C wrap106_107' α108'') (2) //│ | | | | | | | wrong level: 2 //│ | | | | | | | RECONSTRAINING TVs -//│ | | | | | | | EXTR RHS ~> (x121_125' -> α124_126') to 1 +//│ | | | | | | | EXTR RHS ~> (x105_109' -> α108_110') to 1 //│ | | | | | | | where -//│ | | | | | | | 2. C wrap122_123' α124_126') (4) -//│ | | | | | | | | NEW wrap122_123' UB (1) -//│ | | | | 2. : α124'' -//│ | | | 2. : (α124'',) -//│ | | 2. : (α124'',) -//│ | 2. : (x121'' -> (α124'',)) -//│ | CONSTRAIN (x121'' -> (α124'',)) α108_110') (4) +//│ | | | | | | | | NEW wrap106_107' UB (1) +//│ | | | | 2. : α108'' +//│ | | | 2. : (α108'',) +//│ | | 2. : (α108'',) +//│ | 2. : (x105'' -> (α108'',)) +//│ | CONSTRAIN (x105'' -> (α108'',)) α124_126' -//│ | 2. C (x121'' -> (α124'',)) α108_110' +//│ | 2. C (x105'' -> (α108'',)) α124_126') -//│ ⬤ Typed as: ‹∀ 1. wrap120''#› +//│ this: this101' +//│ super: super102' +//│ | super102' <: {wrap: wrap106_107'} +//│ | wrap106_107' <: (x105_109' -> α108_110') +//│ ⬤ Typed as: ‹∀ 1. wrap104''#› //│ where: -//│ wrap120''# := (x121'' -> (α124'',)) -//│ x121'' <: x121_125' -//│ α124'' :> α124_126' -//│ fun wrap: ‹∀ 1. wrap120''#› where -//│ | wrap120''# := (x121'' -> (α124'',)) -//│ | x121'' <: x121_125' -//│ | α124'' :> α124_126' +//│ wrap104''# := (x105'' -> (α108'',)) +//│ x105'' <: x105_109' +//│ α108'' :> α108_110' +//│ fun wrap: ‹∀ 1. wrap104''#› where +//│ | wrap104''# := (x105'' -> (α108'',)) +//│ | x105'' <: x105_109' +//│ | α108'' :> α108_110' //│ [pretty-printed] wrap: anything -> (nothing,) @@ -248,130 +219,98 @@ module WrapBase1: WrapBase, Wrap //│ | //│ | List(WrapBase, Wrap) //│ | 1. Inheriting from WrapBase -//│ | | 2. FRESHEN ‹∀ 1. wrap110''#› || 0 .. 1024 0 true -//│ | | => ‹∀ 1. wrap110''#› -//│ | | CONSTRAIN {} ‹∀ 1. wrap94''#› +//│ | | CONSTRAIN {} (α124'',)) || 1 .. 1024 2 false -//│ | | | | | 3. FRESHEN (x121'',) || 1 .. 1024 2 false -//│ | | | | | | 3. FRESHEN x121'' || 1 .. 1024 2 false -//│ | | | | | | | 3. FRESHEN x121_125' || 1 .. 1024 1 true -//│ | | | | | | | => x121_125' -//│ | | | | | | => x121_138''' -//│ | | | | | => (x121_138''',) -//│ | | | | | 3. FRESHEN (α124'',) || 1 .. 1024 2 false -//│ | | | | | | 3. FRESHEN α124'' || 1 .. 1024 2 false -//│ | | | | | | | 3. FRESHEN α124_126' || 1 .. 1024 1 true -//│ | | | | | | | => α124_126' -//│ | | | | | | => α124_139''' -//│ | | | | | => (α124_139''',) -//│ | | | | => (x121_138''' -> (α124_139''',)) -//│ | | | => wrap120_137'''# -//│ | | | 2. FRESHEN ‹∀ 2. wrap120_137'''#› || 0 .. 1024 1 false -//│ | | | | 2. FRESHEN wrap120_137'''# || 0 .. 2 3 false -//│ | | | | | 2. FRESHEN (x121_138''' -> (α124_139''',)) || 0 .. 2 3 false -//│ | | | | | | 2. FRESHEN (x121_138''',) || 0 .. 2 3 false -//│ | | | | | | | 2. FRESHEN x121_138''' || 0 .. 2 3 false -//│ | | | | | | | | 2. FRESHEN x121_125' || 0 .. 2 1 false -//│ | | | | | | | | => x121_142'' -//│ | | | | | | | => x121_141''' -//│ | | | | | | => (x121_141''',) -//│ | | | | | | 2. FRESHEN (α124_139''',) || 0 .. 2 3 false -//│ | | | | | | | 2. FRESHEN α124_139''' || 0 .. 2 3 false -//│ | | | | | | | | 2. FRESHEN α124_126' || 0 .. 2 1 false -//│ | | | | | | | | => α124_144'' -//│ | | | | | | | => α124_143''' -//│ | | | | | | => (α124_143''',) -//│ | | | | | => (x121_141''' -> (α124_143''',)) -//│ | | | | => wrap120_140'''# -//│ | | | => ‹∀ 2. wrap120_140'''#› -//│ | | => ‹∀ 2. wrap120_140'''#› -//│ | | CONSTRAIN {wrap: ‹∀ 1. wrap110''#›} (α108'',)) || 0 .. 1 2 false +//│ | | | | | 1. FRESHEN (x105'',) || 0 .. 1 2 false +//│ | | | | | | 1. FRESHEN x105'' || 0 .. 1 2 false +//│ | | | | | | | 1. FRESHEN x105_109' || 0 .. 1 1 false +//│ | | | | | | | => x105_123' +//│ | | | | | | => x105_122'' +//│ | | | | | => (x105_122'',) +//│ | | | | | 1. FRESHEN (α108'',) || 0 .. 1 2 false +//│ | | | | | | 1. FRESHEN α108'' || 0 .. 1 2 false +//│ | | | | | | | 1. FRESHEN α108_110' || 0 .. 1 1 false +//│ | | | | | | | => α108_125' +//│ | | | | | | => α108_124'' +//│ | | | | | => (α108_124'',) +//│ | | | | => (x105_122'' -> (α108_124'',)) +//│ | | | => wrap104_121''# +//│ | | => ‹∀ 1. wrap104_121''#› +//│ | | CONSTRAIN {wrap: ‹∀ 1. wrap94''#›} α111'') -//│ super118' <: {wrap: wrap122_123'} -//│ wrap122_123' <: (x121_125' -> α124_126') -//│ | | 1. C {wrap: ‹∀ 1. wrap110''#›} α124_126') (4) -//│ | | | | | | could be distribbed: Set(α111'') -//│ | | | | | | cannot be distribbed: Set(α111'') -//│ | | | | | | INST [1] ‹∀ 1. wrap110''#› +//│ wrap94''# := (α95'' -> α95'') +//│ super102' <: {wrap: wrap106_107'} +//│ wrap106_107' <: (x105_109' -> α108_110') +//│ | | 1. C {wrap: ‹∀ 1. wrap94''#›} α108_110') (4) +//│ | | | | | | could be distribbed: Set(α95'') +//│ | | | | | | cannot be distribbed: Set(α95'') +//│ | | | | | | INST [1] ‹∀ 1. wrap94''#› //│ | | | | | | where -//│ wrap110''# := (α111'' -> α111'') -//│ | | | | | | 1. FRESHEN wrap110''# || 1 .. 1024 2 false -//│ | | | | | | | 1. FRESHEN (α111'' -> α111'') || 1 .. 1024 2 false -//│ | | | | | | | | 1. FRESHEN (α111'',) || 1 .. 1024 2 false -//│ | | | | | | | | | 1. FRESHEN α111'' || 1 .. 1024 2 false -//│ | | | | | | | | | => α111_146' -//│ | | | | | | | | => (α111_146',) -//│ | | | | | | | | 1. FRESHEN α111'' || 1 .. 1024 2 false -//│ | | | | | | | | | 1. FRESHEN α111'' || 1 .. 1024 2 false -//│ | | | | | | | | | => α111_146' -//│ | | | | | | | | => α111_146' -//│ | | | | | | | => (α111_146' -> α111_146') -//│ | | | | | | => wrap110_145'# -//│ | | | | | | TO [1] ~> wrap110_145'# +//│ wrap94''# := (α95'' -> α95'') +//│ | | | | | | 1. FRESHEN wrap94''# || 1 .. 1024 2 false +//│ | | | | | | | 1. FRESHEN (α95'' -> α95'') || 1 .. 1024 2 false +//│ | | | | | | | | 1. FRESHEN (α95'',) || 1 .. 1024 2 false +//│ | | | | | | | | | 1. FRESHEN α95'' || 1 .. 1024 2 false +//│ | | | | | | | | | => α95_127' +//│ | | | | | | | | => (α95_127',) +//│ | | | | | | | | 1. FRESHEN α95'' || 1 .. 1024 2 false +//│ | | | | | | | | | 1. FRESHEN α95'' || 1 .. 1024 2 false +//│ | | | | | | | | | => α95_127' +//│ | | | | | | | | => α95_127' +//│ | | | | | | | => (α95_127' -> α95_127') +//│ | | | | | | => wrap94_126'# +//│ | | | | | | TO [1] ~> wrap94_126'# //│ | | | | | | where -//│ wrap110_145'# := (α111_146' -> α111_146') -//│ | | | | | | 1. C wrap110_145'# α124_126') (6) -//│ | | | | | | | 1. C (α111_146' -> α111_146') α124_126') (9) -//│ | | | | | | | | 1. C (x121_125',) α95_127') +//│ | | | | | | 1. C wrap94_126'# α108_110') (6) +//│ | | | | | | | 1. C (α95_127' -> α95_127') α108_110') (9) +//│ | | | | | | | | 1. C (x105_109',) α111'') -//│ this134' <: this117' & this107' -//│ wrap120_140'''# := (x121_141''' -> (α124_143''',)) -//│ x121_141''' <: x121_142'' -//│ α124_143''' :> α124_144'' -//│ | 1. C {wrap: (‹∀ 1. wrap110''#› & ‹∀ 2. wrap120_140'''#›)} α111'') -//│ wrap120_140'''# := (x121_141''' -> (α124_143''',)) -//│ x121_141''' <: x121_142'' -//│ α124_143''' :> α124_144'' -//│ | | RECONSTRAINING TVs -//│ | | EXTR LHS ~> {wrap: (‹∀ 1. wrap110''#› & ‹∀ 2. wrap120_147'''#›)} to 1 -//│ | | where -//│ wrap110''# := (α111'' -> α111'') -//│ wrap120_147'''# := (x121_148''' -> (α124_150''',)) -//│ x121_148''' <: x121_149' -//│ α124_150''' :> α124_151' -//│ | | 1. C {wrap: (‹∀ 1. wrap110''#› & ‹∀ 2. wrap120_147'''#›)} α95'') +//│ this118' <: this101' & this91' +//│ wrap104_121''# := (x105_122'' -> (α108_124'',)) +//│ x105_122'' <: x105_123' +//│ α108_124'' :> α108_125' +//│ | 1. C {wrap: (‹∀ 1. wrap94''#› & ‹∀ 1. wrap104_121''#›)} -//│ | | CONSTRAIN WrapBase1<> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_140'''#›))) -//│ | | | (>>,0,1) -//│ | | | 2. FRESHEN ‹∀ 2. wrap120_140'''#› || 1 .. 1024 2 false -//│ | | | | 2. FRESHEN wrap120_140'''# || 1 .. 2 3 false -//│ | | | | | 2. FRESHEN (x121_141''' -> (α124_143''',)) || 1 .. 2 3 false -//│ | | | | | | 2. FRESHEN (x121_141''',) || 1 .. 2 3 false -//│ | | | | | | | 2. FRESHEN x121_141''' || 1 .. 2 3 false -//│ | | | | | | | | 2. FRESHEN x121_142'' || 1 .. 2 2 false -//│ | | | | | | | | | New skolem: x121_142'' ~> ‘x155'' -//│ | | | | | | | | | 2. FRESHEN x121_149' || 1 .. 2 1 true -//│ | | | | | | | | | => x121_149' -//│ | | | | | | | | | x121_156'' :> List((‘x155'' & x121_149')) -//│ | | | | | | | | | x121_156'' <: List(‘x155'') -//│ | | | | | | | | => x121_156'' -//│ | | | | | | | => x121_154''' -//│ | | | | | | => (x121_154''',) -//│ | | | | | | 2. FRESHEN (α124_143''',) || 1 .. 2 3 false -//│ | | | | | | | 2. FRESHEN α124_143''' || 1 .. 2 3 false -//│ | | | | | | | | 2. FRESHEN α124_144'' || 1 .. 2 2 false -//│ | | | | | | | | | New skolem: α124_144'' ~> ‘_158'' -//│ | | | | | | | | | α124_159'' :> List(‘_158'') -//│ | | | | | | | | | 2. FRESHEN α124_151' || 1 .. 2 1 true -//│ | | | | | | | | | => α124_151' -//│ | | | | | | | | | α124_159'' <: List((‘_158'' | α124_151')) -//│ | | | | | | | | => α124_159'' -//│ | | | | | | | => α124_157''' -//│ | | | | | | => (α124_157''',) -//│ | | | | | => (x121_154''' -> (α124_157''',)) -//│ | | | | => wrap120_153'''# -//│ | | | => ‹∀ 2. wrap120_153'''#› -//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_153'''#›))) -//│ | | | List( -//│ wrap120_153'''# := (x121_154''' -> (α124_157''',)) -//│ x121_154''' <: x121_156'' -//│ x121_156'' :> (‘x155'' & x121_149') <: ‘x155'' -//│ α124_157''' :> α124_159'' -//│ α124_159'' :> ‘_158'' <: (‘_158'' | α124_151')) -//│ | | | (wrap,Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_153'''#›))) -//│ | | | 0. C ‹∀ 2. wrap120_153'''#› (α124_157''',)) -//│ x121_154''' <: x121_156'' -//│ x121_156'' :> (‘x155'' & x121_149') <: ‘x155'' -//│ α124_157''' :> α124_159'' -//│ α124_159'' :> ‘_158'' <: (‘_158'' | α124_151') -//│ | | | | RECONSTRAINING TVs -//│ | | | | EXTR LHS ~> ‹∀ 2. wrap120_160'''#› to 0 -//│ | | | | where -//│ wrap120_160'''# := (x121_161''' -> (α124_163''',)) -//│ x121_161''' <: x121_162 -//│ x121_162 <: ⊥ -//│ α124_163''' :> α124_164 -//│ α124_164 :> ⊤ -//│ | | | | 0. C ‹∀ 2. wrap120_160'''#› TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_121''#›))) +//│ | | | (>>,0,0) +//│ | | | 0. FRESHEN ‹∀ 1. wrap104_121''#› || 0 .. 1024 1 false +//│ | | | | 0. FRESHEN wrap104_121''# || 0 .. 1 2 false +//│ | | | | | 0. FRESHEN (x105_122'' -> (α108_124'',)) || 0 .. 1 2 false +//│ | | | | | | 0. FRESHEN (x105_122'',) || 0 .. 1 2 false +//│ | | | | | | | 0. FRESHEN x105_122'' || 0 .. 1 2 false +//│ | | | | | | | | 0. FRESHEN x105_123' || 0 .. 1 1 false +//│ | | | | | | | | | New skolem: x105_123' ~> ‘x131 +//│ | | | | | | | | => ‘x131 +//│ | | | | | | | => x105_130'' +//│ | | | | | | => (x105_130'',) +//│ | | | | | | 0. FRESHEN (α108_124'',) || 0 .. 1 2 false +//│ | | | | | | | 0. FRESHEN α108_124'' || 0 .. 1 2 false +//│ | | | | | | | | 0. FRESHEN α108_125' || 0 .. 1 1 false +//│ | | | | | | | | | New skolem: α108_125' ~> ‘_133 +//│ | | | | | | | | => ‘_133 +//│ | | | | | | | => α108_132'' +//│ | | | | | | => (α108_132'',) +//│ | | | | | => (x105_130'' -> (α108_132'',)) +//│ | | | | => wrap104_129''# +//│ | | | => ‹∀ 1. wrap104_129''#› +//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_129''#›))) +//│ | | | (wrap,Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_129''#›))) +//│ | | | 0. C ‹∀ 1. wrap104_129''#› ‹∀ 2. wrap120_160'''#› -//│ wrap120_160'''# := (x121_161''' -> (α124_163''',)) -//│ x121_161''' <: x121_162 -//│ x121_162 <: ⊥ -//│ α124_163''' :> α124_164 -//│ α124_164 :> ⊤ -//│ Typed: nothing -> (anything,) +//│ wrap128 :> ‹∀ 1. wrap104_129''#› +//│ wrap104_129''# := (x105_130'' -> (α108_132'',)) +//│ x105_130'' <: ‘x131 +//│ α108_132'' :> ‘_133 +//│ Typed: 'x -> ('_,) :d WrapBase1.wrap @@ -460,94 +367,63 @@ WrapBase1.wrap //│ | 0. Typing term (WrapBase1).wrap //│ | | 0. Typing term WrapBase1 //│ | | 0. : WrapBase1<> -//│ | | CONSTRAIN WrapBase1<> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_140'''#›))) -//│ | | | (>>,0,1) -//│ | | | 2. FRESHEN ‹∀ 2. wrap120_140'''#› || 1 .. 1024 2 false -//│ | | | | 2. FRESHEN wrap120_140'''# || 1 .. 2 3 false -//│ | | | | | 2. FRESHEN (x121_141''' -> (α124_143''',)) || 1 .. 2 3 false -//│ | | | | | | 2. FRESHEN (x121_141''',) || 1 .. 2 3 false -//│ | | | | | | | 2. FRESHEN x121_141''' || 1 .. 2 3 false -//│ | | | | | | | | 2. FRESHEN x121_142'' || 1 .. 2 2 false -//│ | | | | | | | | | New skolem: x121_142'' ~> ‘x174'' -//│ | | | | | | | | | 2. FRESHEN x121_149' || 1 .. 2 1 true -//│ | | | | | | | | | => x121_149' -//│ | | | | | | | | | x121_175'' :> List((‘x174'' & x121_149')) -//│ | | | | | | | | | x121_175'' <: List(‘x174'') -//│ | | | | | | | | => x121_175'' -//│ | | | | | | | => x121_173''' -//│ | | | | | | => (x121_173''',) -//│ | | | | | | 2. FRESHEN (α124_143''',) || 1 .. 2 3 false -//│ | | | | | | | 2. FRESHEN α124_143''' || 1 .. 2 3 false -//│ | | | | | | | | 2. FRESHEN α124_144'' || 1 .. 2 2 false -//│ | | | | | | | | | New skolem: α124_144'' ~> ‘_177'' -//│ | | | | | | | | | α124_178'' :> List(‘_177'') -//│ | | | | | | | | | 2. FRESHEN α124_151' || 1 .. 2 1 true -//│ | | | | | | | | | => α124_151' -//│ | | | | | | | | | α124_178'' <: List((‘_177'' | α124_151')) -//│ | | | | | | | | => α124_178'' -//│ | | | | | | | => α124_176''' -//│ | | | | | | => (α124_176''',) -//│ | | | | | => (x121_173''' -> (α124_176''',)) -//│ | | | | => wrap120_172'''# -//│ | | | => ‹∀ 2. wrap120_172'''#› -//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_172'''#›))) -//│ | | | List( -//│ wrap120_172'''# := (x121_173''' -> (α124_176''',)) -//│ x121_173''' <: x121_175'' -//│ x121_175'' :> (‘x174'' & x121_149') <: ‘x174'' -//│ α124_176''' :> α124_178'' -//│ α124_178'' :> ‘_177'' <: (‘_177'' | α124_151')) -//│ | | | (wrap,Map(wrap -> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 2. wrap120_172'''#›))) -//│ | | | 0. C ‹∀ 2. wrap120_172'''#› (α124_176''',)) -//│ x121_173''' <: x121_175'' -//│ x121_175'' :> (‘x174'' & x121_149') <: ‘x174'' -//│ α124_176''' :> α124_178'' -//│ α124_178'' :> ‘_177'' <: (‘_177'' | α124_151') -//│ | | | | RECONSTRAINING TVs -//│ | | | | EXTR LHS ~> ‹∀ 2. wrap120_179'''#› to 0 -//│ | | | | where -//│ wrap120_179'''# := (x121_180''' -> (α124_182''',)) -//│ x121_180''' <: x121_181 -//│ x121_181 <: ⊥ -//│ α124_182''' :> α124_183 -//│ α124_183 :> ⊤ -//│ | | | | 0. C ‹∀ 2. wrap120_179'''#› TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_121''#›))) +//│ | | | (>>,0,0) +//│ | | | 0. FRESHEN ‹∀ 1. wrap104_121''#› || 0 .. 1024 1 false +//│ | | | | 0. FRESHEN wrap104_121''# || 0 .. 1 2 false +//│ | | | | | 0. FRESHEN (x105_122'' -> (α108_124'',)) || 0 .. 1 2 false +//│ | | | | | | 0. FRESHEN (x105_122'',) || 0 .. 1 2 false +//│ | | | | | | | 0. FRESHEN x105_122'' || 0 .. 1 2 false +//│ | | | | | | | | 0. FRESHEN x105_123' || 0 .. 1 1 false +//│ | | | | | | | | | New skolem: x105_123' ~> ‘x141 +//│ | | | | | | | | => ‘x141 +//│ | | | | | | | => x105_140'' +//│ | | | | | | => (x105_140'',) +//│ | | | | | | 0. FRESHEN (α108_124'',) || 0 .. 1 2 false +//│ | | | | | | | 0. FRESHEN α108_124'' || 0 .. 1 2 false +//│ | | | | | | | | 0. FRESHEN α108_125' || 0 .. 1 1 false +//│ | | | | | | | | | New skolem: α108_125' ~> ‘_143 +//│ | | | | | | | | => ‘_143 +//│ | | | | | | | => α108_142'' +//│ | | | | | | => (α108_142'',) +//│ | | | | | => (x105_140'' -> (α108_142'',)) +//│ | | | | => wrap104_139''# +//│ | | | => ‹∀ 1. wrap104_139''#› +//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_139''#›))) +//│ | | | (wrap,Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_139''#›))) +//│ | | | 0. C ‹∀ 1. wrap104_139''#› ‹∀ 2. wrap120_179'''#› -//│ wrap120_179'''# := (x121_180''' -> (α124_182''',)) -//│ x121_180''' <: x121_181 -//│ x121_181 <: ⊥ -//│ α124_182''' :> α124_183 -//│ α124_183 :> ⊤ -//│ Typed: nothing -> (anything,) +//│ wrap138 :> ‹∀ 1. wrap104_139''#› +//│ wrap104_139''# := (x105_140'' -> (α108_142'',)) +//│ x105_140'' <: ‘x141 +//│ α108_142'' :> ‘_143 +//│ Typed: 'x -> ('_,) +// FIXME WrapBase1.wrap(1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.533: WrapBase1.wrap(1) +//│ ║ l.409: WrapBase1.wrap(1) //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `1` does not match type `nothing` -//│ ║ l.533: WrapBase1.wrap(1) +//│ ╟── integer literal of type `1` does not match type `?x` +//│ ║ l.409: WrapBase1.wrap(1) //│ ╙── ^ -//│ Typed: (anything,) | error +//│ Typed: ('_,) | error // FIXME WrapBase1.wrap("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.543: WrapBase1.wrap("ok") +//│ ║ l.419: WrapBase1.wrap("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"ok"` does not match type `nothing` -//│ ║ l.543: WrapBase1.wrap("ok") +//│ ╟── string literal of type `"ok"` does not match type `?x` +//│ ║ l.419: WrapBase1.wrap("ok") //│ ╙── ^^^^ -//│ Typed: (anything,) | error +//│ Typed: ('_,) | error module WrapBase2: WrapBase, Wrap, Wrap @@ -555,6 +431,6 @@ module WrapBase2: WrapBase, Wrap, Wrap // FIXME WrapBase2.wrap -//│ Typed: 'a -> ('a,) +//│ Typed: ('_ | '_0 | 'x) -> ('_0,) From a00ad6edc94db0b8d4943c7932feb3582c422553 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 00:54:37 +0800 Subject: [PATCH 020/498] WIP fix mixin freshen --- .../scala/mlscript/ConstraintSolver.scala | 7 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 6 +- .../main/scala/mlscript/TyperDatatypes.scala | 10 +- shared/src/test/diff/nu/BasicClasses.mls | 321 ++++++------- shared/src/test/diff/nu/BasicMixins.mls | 438 ++++-------------- 5 files changed, 263 insertions(+), 519 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index eecd88c284..23279d6b40 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -569,7 +569,9 @@ class ConstraintSolver extends NormalForms { self: Typer => implicit val shadows: Shadows = Shadows.empty println(td) // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] - val res = td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] + val res = + // td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] + td.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] println(res) // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) res @@ -758,7 +760,8 @@ class ConstraintSolver extends NormalForms { self: Typer => // * Simple case when the parameter type vars don't need to be split case (AliasOf(PolymorphicType(plvl, AliasOf(FunctionType(param, bod)))), _) if distributeForalls - && param.level <= plvl => + && param.level <= plvl + && bod.level > plvl => val newLhs = FunctionType(param, PolymorphicType(plvl, bod))(rhs.prov) println(s"DISTRIB-L ~> $newLhs") rec(newLhs, rhs, true) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 9ec1c0b842..30a1b6efbf 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -74,7 +74,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case m @ TypedNuMxn(td, thisTV, superTV, ttu) => // println(">>",m.level) // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) - TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) + // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) + TypedNuMxn(td, + thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], + superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], + ttu.freshenAbove(lim, rigidify)) case TypedNuFun(level, fd, ty) => // TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(level, rigidify)) TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 24e6703eb5..79261c1dd0 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -50,6 +50,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => res } + // TODO does this also need freshening in freshenAbove? private lazy val thisTV: TV = freshVar(noProv/*FIXME*/, N, S("this"))(lvl + 1) @@ -143,6 +144,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ??? // val fresh = mxn.freshen // println(fresh) + + println(s"Fresh $mxn") + constrain(superType, mxn.superTV) constrain(finalType, mxn.thisTV) @@ -173,11 +177,15 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => Nil } }() - val newSuperType = superType & + val newSuperType = + // superType & + WithType( + superType, RecordType( // newMembs.foldLeft(TopType.toUpper(provTODO))(_ && _.ty.toUpper(provTODO)) newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) )(provTODO) + )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => constrain(superType, finalType) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 4547fe74e1..780d32fddd 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -14,32 +14,32 @@ class Base0(n) { //│ fun me: ‹∀ 1. me30''#› where //│ | this24' :> Base0<> <: {my: my36_37'} & {n: n32_33'} //│ | me30''# := this24' -//│ | n32_33' :> ‘n68 -//│ | my36_37' :> ‹∀ 1. my31_45''#› -//│ | my31_45''# := n32_46'' -//│ | n32_46'' :> ‘n43 <: mine34_47''# & my31_45''# -//│ | mine34_47''# := my31_45''# +//│ | n32_33' :> n23_65 +//│ | my36_37' :> ‹∀ 1. my31_44''#› +//│ | my31_44''# := n32_45'' +//│ | n32_45'' :> n32_42 <: mine34_46''# & my31_44''# +//│ | mine34_46''# := my31_44''# //│ [pretty-printed] me: Base0 //│ fun my: ‹∀ 1. my31''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> ‘n68 +//│ | n32_33' :> n23_65 //│ | mine34''# := my31''# -//│ [pretty-printed] my: 'n +//│ [pretty-printed] my: nothing //│ fun mine: ‹∀ 1. mine34''#› where //│ | my31''# := n32'' //│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> ‘n68 +//│ | n32_33' :> n23_65 //│ | mine34''# := my31''# -//│ [pretty-printed] mine: 'n +//│ [pretty-printed] mine: nothing //│ fun oops: ‹∀ 1. oops35''#› where //│ | oops35''# := my36'' //│ | my36'' :> my36_37' <: oops35''# -//│ | my36_37' :> ‹∀ 1. my31_45''#› -//│ | my31_45''# := n32_46'' -//│ | n32_46'' :> ‘n43 <: mine34_47''# & my31_45''# -//│ | mine34_47''# := my31_45''# -//│ [pretty-printed] oops: 'n +//│ | my36_37' :> ‹∀ 1. my31_44''#› +//│ | my31_44''# := n32_45'' +//│ | n32_45'' :> n32_42 <: mine34_46''# & my31_44''# +//│ | mine34_46''# := my31_44''# +//│ [pretty-printed] oops: nothing // :d // Base0 @@ -73,156 +73,134 @@ let n1 = b1.n //│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false //│ | | | | | | | | 1. FRESHEN this24' || 0 .. 1 1 false //│ | | | | | | | | | 1. FRESHEN this24' || 0 .. 1 1 false -//│ | | | | | | | | | | New skolem: this24' ~> ‘this107' //│ | | | | | | | | | | 1. FRESHEN Base0<> || 0 .. 1 0 true //│ | | | | | | | | | | => Base0<> -//│ | | | | | | | | | | this24_108' :> List((‘this107' & Base0<>)) //│ | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false //│ | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false //│ | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false //│ | | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false //│ | | | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false //│ | | | | | | | | | | | | | | | 1. FRESHEN my36_37' || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | | | New skolem: my36_37' ~> ‘my109' -//│ | | | | | | | | | | | | | | | | 1. FRESHEN ‹∀ 1. my31_45''#› || 0 .. 1 0 true -//│ | | | | | | | | | | | | | | | | => ‹∀ 1. my31_45''#› -//│ | | | | | | | | | | | | | | | | my36_110' :> List((‘my109' & ‹∀ 1. my31_45''#›)) -//│ | | | | | | | | | | | | | | | | my36_110' <: List(‘my109') -//│ | | | | | | | | | | | | | | | => my36_110' -//│ | | | | | | | | | | | | | | => {my: my36_110'} -//│ | | | | | | | | | | | | | => {my: my36_110'} -//│ | | | | | | | | | | | | => {my: my36_110'} -//│ | | | | | | | | | | | => {my: my36_110'} -//│ | | | | | | | | | | => {my: my36_110'} +//│ | | | | | | | | | | | | | | | | 1. FRESHEN ‹∀ 1. my31_44''#› || 0 .. 1 0 true +//│ | | | | | | | | | | | | | | | | => ‹∀ 1. my31_44''#› +//│ | | | | | | | | | | | | | | | => my36_108' +//│ | | | | | | | | | | | | | | => {my: my36_108'} +//│ | | | | | | | | | | | | | => {my: my36_108'} +//│ | | | | | | | | | | | | => {my: my36_108'} +//│ | | | | | | | | | | | => {my: my36_108'} +//│ | | | | | | | | | | => {my: my36_108'} //│ | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false //│ | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false //│ | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false //│ | | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false //│ | | | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false //│ | | | | | | | | | | | | | | | 1. FRESHEN n32_33' || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | | | New skolem: n32_33' ~> ‘n111' -//│ | | | | | | | | | | | | | | | | 1. FRESHEN ‘n68 || 0 .. 1 0 true -//│ | | | | | | | | | | | | | | | | => ‘n68 -//│ | | | | | | | | | | | | | | | | n32_112' :> List((‘n111' & ‘n68)) -//│ | | | | | | | | | | | | | | | | n32_112' <: List(‘n111') -//│ | | | | | | | | | | | | | | | => n32_112' -//│ | | | | | | | | | | | | | | => {n: n32_112'} -//│ | | | | | | | | | | | | | => {n: n32_112'} -//│ | | | | | | | | | | | | => {n: n32_112'} -//│ | | | | | | | | | | | => {n: n32_112'} -//│ | | | | | | | | | | => {n: n32_112'} -//│ | | | | | | | | | | this24_108' <: List(((‘this107' | {my: my36_110'}) | {n: n32_112'})) -//│ | | | | | | | | | => this24_108' -//│ | | | | | | | | => this24_108' +//│ | | | | | | | | | | | | | | | | 1. FRESHEN n23_65 || 0 .. 1 0 true +//│ | | | | | | | | | | | | | | | | => n23_65 +//│ | | | | | | | | | | | | | | | => n32_109' +//│ | | | | | | | | | | | | | | => {n: n32_109'} +//│ | | | | | | | | | | | | | => {n: n32_109'} +//│ | | | | | | | | | | | | => {n: n32_109'} +//│ | | | | | | | | | | | => {n: n32_109'} +//│ | | | | | | | | | | => {n: n32_109'} +//│ | | | | | | | | | => this24_107' +//│ | | | | | | | | => this24_107' //│ | | | | | | | => me30_106''# //│ | | | | | | => ‹∀ 1. me30_106''#› //│ | | | | | | 1. FRESHEN ‹∀ 1. my31''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false //│ | | | | | | | | 1. FRESHEN n32'' || 0 .. 1 2 false //│ | | | | | | | | | 1. FRESHEN n32_33' || 0 .. 1 1 false -//│ | | | | | | | | | => n32_112' +//│ | | | | | | | | | => n32_109' //│ | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false //│ | | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false //│ | | | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false //│ | | | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false //│ | | | | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | | | | | | | => my31_114'' -//│ | | | | | | | | | | | | => my31_114'' -//│ | | | | | | | | | | | => mine34_116''# -//│ | | | | | | | | | | => mine34_116''# -//│ | | | | | | | | | => mine34_116''# +//│ | | | | | | | | | | | | | => my31_111'' +//│ | | | | | | | | | | | | => my31_111'' +//│ | | | | | | | | | | | => mine34_113''# +//│ | | | | | | | | | | => mine34_113''# +//│ | | | | | | | | | => mine34_113''# //│ | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false //│ | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | | | | => my31_114'' -//│ | | | | | | | | | => my31_114'' -//│ | | | | | | | | => n32_115'' -//│ | | | | | | | => my31_114''# -//│ | | | | | | => ‹∀ 1. my31_114''#› +//│ | | | | | | | | | | => my31_111'' +//│ | | | | | | | | | => my31_111'' +//│ | | | | | | | | => n32_112'' +//│ | | | | | | | => my31_111''# +//│ | | | | | | => ‹∀ 1. my31_111''#› //│ | | | | | | 1. FRESHEN ‹∀ 1. mine34''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false -//│ | | | | | | | => mine34_116''# -//│ | | | | | | => ‹∀ 1. mine34_116''#› +//│ | | | | | | | => mine34_113''# +//│ | | | | | | => ‹∀ 1. mine34_113''#› //│ | | | | | | 1. FRESHEN ‹∀ 1. oops35''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false //│ | | | | | | | | 1. FRESHEN my36'' || 0 .. 1 2 false //│ | | | | | | | | | 1. FRESHEN my36_37' || 0 .. 1 1 false -//│ | | | | | | | | | => my36_110' +//│ | | | | | | | | | => my36_108' //│ | | | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false //│ | | | | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false -//│ | | | | | | | | | | => oops35_119'' -//│ | | | | | | | | | => oops35_119'' -//│ | | | | | | | | => my36_120'' -//│ | | | | | | | => oops35_119''# -//│ | | | | | | => ‹∀ 1. oops35_119''#› +//│ | | | | | | | | | | => oops35_116'' +//│ | | | | | | | | | => oops35_116'' +//│ | | | | | | | | => my36_117'' +//│ | | | | | | | => oops35_116''# +//│ | | | | | | => ‹∀ 1. oops35_116''#› //│ | | | | | | 1. FRESHEN n23' || 0 .. 1024 1 false -//│ | | | | | | | New skolem: n23' ~> ‘n121' -//│ | | | | | | => ‘n121' +//│ | | | | | | => n23_118' //│ | | | | | | 1. FRESHEN n23' || 0 .. 1024 1 false -//│ | | | | | | => ‘n121' +//│ | | | | | | => n23_118' //│ | | | | | | 1. FRESHEN ‹∀ 1. mine34''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false -//│ | | | | | | | => mine34_116''# -//│ | | | | | | => ‹∀ 1. mine34_116''#› +//│ | | | | | | | => mine34_113''# +//│ | | | | | | => ‹∀ 1. mine34_113''#› //│ | | | | | | 1. FRESHEN ‹∀ 1. oops35''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false -//│ | | | | | | | => oops35_119''# -//│ | | | | | | => ‹∀ 1. oops35_119''#› +//│ | | | | | | | => oops35_116''# +//│ | | | | | | => ‹∀ 1. oops35_116''#› //│ | | | | | | 1. FRESHEN ‹∀ 1. my31''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | => my31_114''# -//│ | | | | | | => ‹∀ 1. my31_114''#› +//│ | | | | | | | => my31_111''# +//│ | | | | | | => ‹∀ 1. my31_111''#› //│ | | | | | | 1. FRESHEN ‹∀ 1. me30''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false //│ | | | | | | | => me30_106''# //│ | | | | | | => ‹∀ 1. me30_106''#› -//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_114''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_116''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_119''#›)),None),List((n,‘n121')),HashMap(n -> NuParam(n,‘n121'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_116''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_119''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_114''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) -//│ | | | | | | (n,HashMap(n -> NuParam(n,‘n121'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_116''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_119''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_114''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) -//│ | | | | | | 1. C ‘n121' TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›)),None),List((n,n23_118')),HashMap(n -> NuParam(n,n23_118'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) +//│ | | | | | | (n,HashMap(n -> NuParam(n,n23_118'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) +//│ | | | | | | 1. C n23_118' ‘n121' //│ | 1. C n104' ‘n121' <: n1103'# +//│ n104' <: n1103'# //│ fun n1: ‹∀ 0. n1103'#› where //│ | n1103'# := n104' -//│ | n104' :> ‘n121' <: n1103'# -//│ [pretty-printed] n1: 'n +//│ | n104' <: n1103'# +//│ [pretty-printed] n1: nothing // TODO n1 + 1 -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.201: n1 + 1 -//│ ║ ^^^^ -//│ ╟── reference of type `?n` is not an instance of type `int` -//│ ║ l.7: class Base0(n) { -//│ ║ ^ -//│ ╟── but it flows into reference with expected type `int` -//│ ║ l.201: n1 + 1 -//│ ╙── ^^ -//│ Typed: error | int +//│ Typed: int let b2 = Base0("hi") let n2 = b2.n -//│ fun b2: ‹∀ 0. b2129'#› where -//│ | b2129'# := α144' -//│ | α144' :> Base0<> <: {n: n146'} & b2129'# -//│ | n2145'# := n146' -//│ | n146' :> ‘n163' <: n2145'# +//│ fun b2: ‹∀ 0. b2126'#› where +//│ | b2126'# := α141' +//│ | α141' :> Base0<> <: {n: n143'} & b2126'# +//│ | n2142'# := n143' +//│ | n143' <: n2142'# //│ [pretty-printed] b2: Base0 -//│ fun n2: ‹∀ 0. n2145'#› where -//│ | n2145'# := n146' -//│ | n146' :> ‘n163' <: n2145'# -//│ [pretty-printed] n2: 'n +//│ fun n2: ‹∀ 0. n2142'#› where +//│ | n2142'# := n143' +//│ | n143' <: n2142'# +//│ [pretty-printed] n2: nothing @@ -232,18 +210,18 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1174''#› where -//│ | getBase1174''# := Int +//│ fun getBase1: ‹∀ 1. getBase1168''#› where +//│ | getBase1168''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase2175''#› where -//│ | getBase2175''# := base176'' -//│ | base176'' :> base176_177' <: getBase2175''# -//│ | base176_177' :> Int +//│ fun getBase2: ‹∀ 1. getBase2169''#› where +//│ | getBase2169''# := base170'' +//│ | base170'' :> base170_171' <: getBase2169''# +//│ | base170_171' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo178''#› where -//│ | foo178''# := (α179'' -> α183'') -//│ | α179'' <: int -//│ | α183'' :> int +//│ fun foo: ‹∀ 1. foo172''#› where +//│ | foo172''# := (α173'' -> α177'') +//│ | α173'' <: int +//│ | α177'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -252,26 +230,26 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1209''#› where -//│ | getBase1209''# := Int +//│ fun getBase1: ‹∀ 1. getBase1203''#› where +//│ | getBase1203''# := Int //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me210''#› where -//│ | this204' :> Base1<> -//│ | me210''# := this204' +//│ fun me: ‹∀ 1. me204''#› where +//│ | this198' :> Base1<> +//│ | me204''# := this198' //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo211''#› where -//│ | foo211''# := (α212'' -> α214'') -//│ | α212'' <: int -//│ | α214'' :> int +//│ fun foo: ‹∀ 1. foo205''#› where +//│ | foo205''# := (α206'' -> α208'') +//│ | α206'' <: int +//│ | α208'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b227'#› where -//│ | b227'# := α233' -//│ | α233' :> Base1<> <: b227'# +//│ fun b: ‹∀ 0. b221'#› where +//│ | b221'# := α227' +//│ | α227' :> Base1<> <: b221'# //│ [pretty-printed] b: Base1 b.base @@ -285,62 +263,59 @@ b.me //│ 0. Typing TypingUnit(List((b).me)) //│ | 0. Typing term (b).me //│ | | 0. Typing term b -//│ | | 0. : b227'# -//│ | | CONSTRAIN b227'# Base1<> <: {getBase1: getBase1244} & {base: base236} & b227'# -//│ base236 :> Int -//│ getBase1244 :> ‹∀ 1. getBase1209''#› -//│ | | 0. C b227'# + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1209''#›), me ~> TypedNuFun(1,fun me = this,‹∀ 1. me210''#›), foo ~> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1209''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me210''#›), foo -> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›))) +//│ getBase1203''# := Int +//│ b221'# := α227' +//│ α227' :> Base1<> <: {getBase1: getBase1237} & {base: base230} & b221'# +//│ base230 :> Int +//│ getBase1237 :> ‹∀ 1. getBase1203''#› +//│ | | 0. C b221'# + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo ~> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo -> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) //│ | | | | | | (>>,0,0) -//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1209''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. getBase1209''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. me210''#› || 0 .. 1024 1 false -//│ | | | | | | | 0. FRESHEN me210''# || 0 .. 1 2 false -//│ | | | | | | | | 0. FRESHEN this204' || 0 .. 1 1 false -//│ | | | | | | | | | 0. FRESHEN this204' || 0 .. 1 1 false -//│ | | | | | | | | | | New skolem: this204' ~> ‘this257 +//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1203''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. getBase1203''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. me204''#› || 0 .. 1024 1 false +//│ | | | | | | | 0. FRESHEN me204''# || 0 .. 1 2 false +//│ | | | | | | | | 0. FRESHEN this198' || 0 .. 1 1 false +//│ | | | | | | | | | 0. FRESHEN this198' || 0 .. 1 1 false //│ | | | | | | | | | | 0. FRESHEN Base1<> || 0 .. 1 0 true //│ | | | | | | | | | | => Base1<> -//│ | | | | | | | | | | this204_258 :> List((‘this257 & Base1<>)) -//│ | | | | | | | | | | this204_258 <: List(‘this257) -//│ | | | | | | | | | => this204_258 -//│ | | | | | | | | => this204_258 -//│ | | | | | | | => me210_256''# -//│ | | | | | | => ‹∀ 1. me210_256''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. foo211''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. foo211''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1209''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. getBase1209''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. me210''#› || 0 .. 1024 1 false -//│ | | | | | | | 0. FRESHEN me210''# || 0 .. 1 2 false -//│ | | | | | | | => me210_256''# -//│ | | | | | | => ‹∀ 1. me210_256''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. foo211''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. foo211''#› -//│ | | | | | | TypedNuCls(0,class Base1(base: int,) {fun getBase1 = base; fun me = this; fun foo = (x,) => + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1209''#›), me ~> TypedNuFun(0,fun me = this,‹∀ 1. me210_256''#›), foo ~> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1209''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me210_256''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›))) -//│ | | | | | | (me,Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1209''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me210_256''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo211''#›))) -//│ | | | | | | 0. C ‹∀ 1. me210_256''#› this198_249 +//│ | | | | | | | | => this198_249 +//│ | | | | | | | => me204_248''# +//│ | | | | | | => ‹∀ 1. me204_248''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. foo205''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. foo205''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1203''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. getBase1203''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. me204''#› || 0 .. 1024 1 false +//│ | | | | | | | 0. FRESHEN me204''# || 0 .. 1 2 false +//│ | | | | | | | => me204_248''# +//│ | | | | | | => ‹∀ 1. me204_248''#› +//│ | | | | | | 0. FRESHEN ‹∀ 1. foo205''#› || 0 .. 1024 0 true +//│ | | | | | | => ‹∀ 1. foo205''#› +//│ | | | | | | TypedNuCls(0,class Base1(base: int,) {fun getBase1 = base; fun me = this; fun foo = (x,) => + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo ~> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) +//│ | | | | | | (me,Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) +//│ | | | | | | 0. C ‹∀ 1. me204_248''#› ‹∀ 1. me210_256''#› -//│ me210_256''# := this204_258 -//│ this204_258 :> (‘this257 & Base1<>) <: ‘this257 -//│ Typed: Base1 & 'this +//│ me245 :> ‹∀ 1. me204_248''#› +//│ me204_248''# := this198_249 +//│ this198_249 :> Base1<> +//│ Typed: Base1 :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.341: b.getBaseTypo +//│ ║ l.316: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -356,20 +331,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.355: a: int +//│ ║ l.330: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.354: class Annots(base: 0 | 1) { +//│ ║ l.329: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.355: a: int +//│ ║ l.330: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.355: a: int +//│ ║ l.330: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a275''#› where -//│ | a275''# := ((0 | 1),) +//│ fun a: ‹∀ 1. a265''#› where +//│ | a265''# := ((0 | 1),) //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index c6fd5ad609..bcfcb82a84 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -29,75 +29,32 @@ mixin BaseInc { //│ | α40'' :> int <: test36''# //│ [pretty-printed] test: int -:d +// :d class Base1(base: int): BaseTest -//│ 0. Typing TypingUnit(List(class Base1(base: int,): BaseTest {})) -//│ Completing class Base1(base: int,): BaseTest {} -//│ | Typing type int -//│ | | vars=Map() newDefsInfo=Map() -//│ | | 1. type int -//│ | | => Int -//│ | => Int ——— -//│ | List() -//│ | base: int, -//│ | List(BaseTest) -//│ | 1. Inheriting from BaseTest -//│ | | 1. FRESHEN ‹∀ 1. test26''#› || 0 .. 1024 1 false -//│ | | | 1. FRESHEN test26''# || 0 .. 1 2 false -//│ | | | | 1. FRESHEN base27'' || 0 .. 1 2 false -//│ | | | | | 1. FRESHEN base27_28' || 0 .. 1 1 false -//│ | | | | | => base27_49' -//│ | | | | | 1. FRESHEN test26''# || 0 .. 1 2 false -//│ | | | | | | 1. FRESHEN test26''# || 0 .. 1 2 false -//│ | | | | | | => test26_47'' -//│ | | | | | => test26_47'' -//│ | | | | => base27_48'' -//│ | | | => test26_47''# -//│ | | => ‹∀ 1. test26_47''#› -//│ | | CONSTRAIN {base: Int} base27_49' <: test26_47''# -//│ | 1. C {base: Int, test: ‹∀ 1. test26_47''#›} Base1 + +// TODO +Base1(1).test +//│ Typed: nothing + + :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.95: class Base1(x): BaseTest +//│ ║ l.52: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.95: class Base1(x): BaseTest +//│ ║ l.52: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -116,321 +73,118 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo -//│ this: this72' -//│ super: super73' -//│ | super73' <: {misc: misc81_82'} & {base: base77_78'} -//│ | base77_78' <: int -//│ fun test: ‹∀ 1. test75''#› where -//│ | test75''# := (α76'' -> (α80'', α76'', misc81'',)) -//│ | α76'' <: int -//│ | α80'' :> int -//│ | misc81'' :> misc81_82' +//│ this: this110' +//│ super: super111' +//│ | super111' <: {misc: misc119_120'} & {base: base115_116'} +//│ | base115_116' <: int +//│ fun test: ‹∀ 1. test113''#› where +//│ | test113''# := (α114'' -> (α118'', α114'', misc119'',)) +//│ | α114'' <: int +//│ | α118'' :> int +//│ | misc119'' :> misc119_120' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) + mixin WrapBase { - fun wrap(x) = x + // fun wrap(x) = x + // fun wrap(x) = x : int + fun wrap(x : int) = x : int } //│ mixin WrapBase -//│ this: this91' -//│ super: super92' -//│ fun wrap: ‹∀ 1. wrap94''#› where -//│ | wrap94''# := (α95'' -> α95'') -//│ [pretty-printed] wrap: 'a -> 'a +//│ this: this129' +//│ super: super130' +//│ fun wrap: ‹∀ 1. wrap132''#› where +//│ | wrap132''# := (Int -> Int) +//│ [pretty-printed] wrap: int -> int -:d +// :d mixin Wrap { fun wrap(x) = [super.wrap(x)] } -//│ 0. Typing TypingUnit(List(mixin Wrap() {fun wrap = (x,) => '(' (super).wrap (x,), ')'})) -//│ Completing mixin Wrap() {fun wrap = (x,) => '(' (super).wrap (x,), ')'} -//│ | 1. Typing TypingUnit(List(fun wrap = (x,) => '(' (super).wrap (x,), ')')) -//│ | UNSTASHING... (out) -//│ Completing fun wrap = (x,) => '(' (super).wrap (x,), ')' -//│ | 2. Typing term (x,) => '(' (super).wrap (x,), ')' -//│ | | 2. Typing pattern x, -//│ | | | 2. Typing pattern x -//│ | | | 2. : x105'' -//│ | | 2. : (x105'',) -//│ | | 2. Typing term '(' (super).wrap (x,), ')' -//│ | | | 2. Typing term (super).wrap (x,), -//│ | | | | 2. Typing term (super).wrap (x,) -//│ | | | | | 2. Typing term (super).wrap -//│ | | | | | | 2. Typing term super -//│ | | | | | | 2. : super102' -//│ | | | | | | CONSTRAIN super102' {wrap: wrap106_107'} to 1 -//│ | | | | | | | where -//│ | | | | | | | 2. C super102' α108'') -//│ | | | | | where -//│ wrap106'' :> wrap106_107' -//│ | | | | | 2. C wrap106'' α108'') (0) -//│ | | | | | | NEW wrap106'' UB (2) -//│ | | | | | | 2. C wrap106_107' α108'') (2) -//│ | | | | | | | wrong level: 2 -//│ | | | | | | | RECONSTRAINING TVs -//│ | | | | | | | EXTR RHS ~> (x105_109' -> α108_110') to 1 -//│ | | | | | | | where -//│ | | | | | | | 2. C wrap106_107' α108_110') (4) -//│ | | | | | | | | NEW wrap106_107' UB (1) -//│ | | | | 2. : α108'' -//│ | | | 2. : (α108'',) -//│ | | 2. : (α108'',) -//│ | 2. : (x105'' -> (α108'',)) -//│ | CONSTRAIN (x105'' -> (α108'',)) α108_110' -//│ | 2. C (x105'' -> (α108'',)) α108_110') -//│ ⬤ Typed as: ‹∀ 1. wrap104''#› -//│ where: -//│ wrap104''# := (x105'' -> (α108'',)) -//│ x105'' <: x105_109' -//│ α108'' :> α108_110' -//│ fun wrap: ‹∀ 1. wrap104''#› where -//│ | wrap104''# := (x105'' -> (α108'',)) -//│ | x105'' <: x105_109' -//│ | α108'' :> α108_110' +//│ this: this135' +//│ super: super136' +//│ | super136' <: {wrap: wrap140_141'} +//│ | wrap140_141' <: ((α139_143',) -> α142_144') +//│ fun wrap: ‹∀ 1. wrap138''#› where +//│ | wrap138''# := (α139'' -> (α142'',)) +//│ | α139'' <: α139_143' +//│ | α142'' :> α142_144' //│ [pretty-printed] wrap: anything -> (nothing,) -:d +// :d module WrapBase1: WrapBase, Wrap -//│ 0. Typing TypingUnit(List(namespace WrapBase1(): WrapBase, Wrap {})) -//│ Completing namespace WrapBase1(): WrapBase, Wrap {} -//│ | List() -//│ | -//│ | List(WrapBase, Wrap) -//│ | 1. Inheriting from WrapBase -//│ | | 1. FRESHEN ‹∀ 1. wrap94''#› || 0 .. 1024 0 true -//│ | | => ‹∀ 1. wrap94''#› -//│ | | CONSTRAIN {} (α108'',)) || 0 .. 1 2 false -//│ | | | | | 1. FRESHEN (x105'',) || 0 .. 1 2 false -//│ | | | | | | 1. FRESHEN x105'' || 0 .. 1 2 false -//│ | | | | | | | 1. FRESHEN x105_109' || 0 .. 1 1 false -//│ | | | | | | | => x105_123' -//│ | | | | | | => x105_122'' -//│ | | | | | => (x105_122'',) -//│ | | | | | 1. FRESHEN (α108'',) || 0 .. 1 2 false -//│ | | | | | | 1. FRESHEN α108'' || 0 .. 1 2 false -//│ | | | | | | | 1. FRESHEN α108_110' || 0 .. 1 1 false -//│ | | | | | | | => α108_125' -//│ | | | | | | => α108_124'' -//│ | | | | | => (α108_124'',) -//│ | | | | => (x105_122'' -> (α108_124'',)) -//│ | | | => wrap104_121''# -//│ | | => ‹∀ 1. wrap104_121''#› -//│ | | CONSTRAIN {wrap: ‹∀ 1. wrap94''#›} α95'') -//│ super102' <: {wrap: wrap106_107'} -//│ wrap106_107' <: (x105_109' -> α108_110') -//│ | | 1. C {wrap: ‹∀ 1. wrap94''#›} α108_110') (4) -//│ | | | | | | could be distribbed: Set(α95'') -//│ | | | | | | cannot be distribbed: Set(α95'') -//│ | | | | | | INST [1] ‹∀ 1. wrap94''#› -//│ | | | | | | where -//│ wrap94''# := (α95'' -> α95'') -//│ | | | | | | 1. FRESHEN wrap94''# || 1 .. 1024 2 false -//│ | | | | | | | 1. FRESHEN (α95'' -> α95'') || 1 .. 1024 2 false -//│ | | | | | | | | 1. FRESHEN (α95'',) || 1 .. 1024 2 false -//│ | | | | | | | | | 1. FRESHEN α95'' || 1 .. 1024 2 false -//│ | | | | | | | | | => α95_127' -//│ | | | | | | | | => (α95_127',) -//│ | | | | | | | | 1. FRESHEN α95'' || 1 .. 1024 2 false -//│ | | | | | | | | | 1. FRESHEN α95'' || 1 .. 1024 2 false -//│ | | | | | | | | | => α95_127' -//│ | | | | | | | | => α95_127' -//│ | | | | | | | => (α95_127' -> α95_127') -//│ | | | | | | => wrap94_126'# -//│ | | | | | | TO [1] ~> wrap94_126'# -//│ | | | | | | where -//│ wrap94_126'# := (α95_127' -> α95_127') -//│ | | | | | | 1. C wrap94_126'# α108_110') (6) -//│ | | | | | | | 1. C (α95_127' -> α95_127') α108_110') (9) -//│ | | | | | | | | 1. C (x105_109',) α95'') -//│ this118' <: this101' & this91' -//│ wrap104_121''# := (x105_122'' -> (α108_124'',)) -//│ x105_122'' <: x105_123' -//│ α108_124'' :> α108_125' -//│ | 1. C {wrap: (‹∀ 1. wrap94''#› & ‹∀ 1. wrap104_121''#›)} -//│ | | CONSTRAIN WrapBase1<> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_121''#›))) -//│ | | | (>>,0,0) -//│ | | | 0. FRESHEN ‹∀ 1. wrap104_121''#› || 0 .. 1024 1 false -//│ | | | | 0. FRESHEN wrap104_121''# || 0 .. 1 2 false -//│ | | | | | 0. FRESHEN (x105_122'' -> (α108_124'',)) || 0 .. 1 2 false -//│ | | | | | | 0. FRESHEN (x105_122'',) || 0 .. 1 2 false -//│ | | | | | | | 0. FRESHEN x105_122'' || 0 .. 1 2 false -//│ | | | | | | | | 0. FRESHEN x105_123' || 0 .. 1 1 false -//│ | | | | | | | | | New skolem: x105_123' ~> ‘x131 -//│ | | | | | | | | => ‘x131 -//│ | | | | | | | => x105_130'' -//│ | | | | | | => (x105_130'',) -//│ | | | | | | 0. FRESHEN (α108_124'',) || 0 .. 1 2 false -//│ | | | | | | | 0. FRESHEN α108_124'' || 0 .. 1 2 false -//│ | | | | | | | | 0. FRESHEN α108_125' || 0 .. 1 1 false -//│ | | | | | | | | | New skolem: α108_125' ~> ‘_133 -//│ | | | | | | | | => ‘_133 -//│ | | | | | | | => α108_132'' -//│ | | | | | | => (α108_132'',) -//│ | | | | | => (x105_130'' -> (α108_132'',)) -//│ | | | | => wrap104_129''# -//│ | | | => ‹∀ 1. wrap104_129''#› -//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_129''#›))) -//│ | | | (wrap,Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_129''#›))) -//│ | | | 0. C ‹∀ 1. wrap104_129''#› ‹∀ 1. wrap104_129''#› -//│ wrap104_129''# := (x105_130'' -> (α108_132'',)) -//│ x105_130'' <: ‘x131 -//│ α108_132'' :> ‘_133 -//│ Typed: 'x -> ('_,) - -:d +// :d WrapBase1.wrap -//│ 0. Typing TypingUnit(List((WrapBase1).wrap)) -//│ | 0. Typing term (WrapBase1).wrap -//│ | | 0. Typing term WrapBase1 -//│ | | 0. : WrapBase1<> -//│ | | CONSTRAIN WrapBase1<> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_121''#›))) -//│ | | | (>>,0,0) -//│ | | | 0. FRESHEN ‹∀ 1. wrap104_121''#› || 0 .. 1024 1 false -//│ | | | | 0. FRESHEN wrap104_121''# || 0 .. 1 2 false -//│ | | | | | 0. FRESHEN (x105_122'' -> (α108_124'',)) || 0 .. 1 2 false -//│ | | | | | | 0. FRESHEN (x105_122'',) || 0 .. 1 2 false -//│ | | | | | | | 0. FRESHEN x105_122'' || 0 .. 1 2 false -//│ | | | | | | | | 0. FRESHEN x105_123' || 0 .. 1 1 false -//│ | | | | | | | | | New skolem: x105_123' ~> ‘x141 -//│ | | | | | | | | => ‘x141 -//│ | | | | | | | => x105_140'' -//│ | | | | | | => (x105_140'',) -//│ | | | | | | 0. FRESHEN (α108_124'',) || 0 .. 1 2 false -//│ | | | | | | | 0. FRESHEN α108_124'' || 0 .. 1 2 false -//│ | | | | | | | | 0. FRESHEN α108_125' || 0 .. 1 1 false -//│ | | | | | | | | | New skolem: α108_125' ~> ‘_143 -//│ | | | | | | | | => ‘_143 -//│ | | | | | | | => α108_142'' -//│ | | | | | | => (α108_142'',) -//│ | | | | | => (x105_140'' -> (α108_142'',)) -//│ | | | | => wrap104_139''# -//│ | | | => ‹∀ 1. wrap104_139''#› -//│ | | | TypedNuCls(0,namespace WrapBase1(): WrapBase, Wrap {},TypedTypingUnit(List(),None),List(),Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_139''#›))) -//│ | | | (wrap,Map(wrap -> TypedNuFun(0,fun wrap = (x,) => '(' (super).wrap (x,), ')',‹∀ 1. wrap104_139''#›))) -//│ | | | 0. C ‹∀ 1. wrap104_139''#› ‹∀ 1. wrap104_139''#› -//│ wrap104_139''# := (x105_140'' -> (α108_142'',)) -//│ x105_140'' <: ‘x141 -//│ α108_142'' :> ‘_143 -//│ Typed: 'x -> ('_,) - -// FIXME +//│ Typed: int -> (int,) + +// :d +// WrapBase1.wrap + WrapBase1.wrap(1) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.409: WrapBase1.wrap(1) -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `1` does not match type `?x` -//│ ║ l.409: WrapBase1.wrap(1) -//│ ╙── ^ -//│ Typed: ('_,) | error - -// FIXME +//│ Typed: (int,) + +:e WrapBase1.wrap("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.419: WrapBase1.wrap("ok") +//│ ║ l.137: WrapBase1.wrap("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"ok"` does not match type `?x` -//│ ║ l.419: WrapBase1.wrap("ok") -//│ ╙── ^^^^ -//│ Typed: ('_,) | error +//│ ╟── string literal of type `"ok"` is not an instance of type `int` +//│ ║ l.137: WrapBase1.wrap("ok") +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.92: fun wrap(x : int) = x : int +//│ ║ ^^^ +//│ ╟── from reference: +//│ ║ l.103: fun wrap(x) = [super.wrap(x)] +//│ ╙── ^ +//│ Typed: (int,) | error -module WrapBase2: WrapBase, Wrap, Wrap +module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ class WrapBase2 -// FIXME -WrapBase2.wrap -//│ Typed: ('_ | '_0 | 'x) -> ('_0,) +let w = WrapBase2.wrap +//│ fun w: ‹∀ 0. w241'#› where +//│ | w241'# := wrap242' +//│ | wrap242' :> ‹∀ 1. wrap138_243''#› <: w241'# +//│ | wrap138_243''# := (α139_244'' -> (α142_250'',)) +//│ | α139_244'' <: α139_245' +//│ | α139_245' <: α139_246' +//│ | α139_246' <: α139_247' +//│ | α139_247' <: α139_248' +//│ | α139_248' <: α139_249' +//│ | α139_249' <: Int +//│ | α142_250'' :> α142_251' +//│ | α142_251' :> ‹∀ 2. (α142_252''',)› +//│ | α142_252''' :> α142_253' +//│ | α142_253' :> ‹∀ 2. (α142_254''',)› +//│ | α142_254''' :> α142_255' +//│ | α142_255' :> Int +//│ [pretty-printed] w: int -> (((int,),),) + +let wd = w(1) +//│ fun wd: ‹∀ 0. wd272'#› where +//│ | α142_251' :> ‹∀ 2. (α142_252''',)› +//│ | α142_252''' :> α142_253' +//│ | α142_253' :> ‹∀ 2. (α142_254''',)› +//│ | α142_254''' :> α142_255' +//│ | α142_255' :> Int +//│ | wd272'# := α273' +//│ | α273' :> ‹∀ 2. (α142_274''',)› <: wd272'# +//│ | α142_274''' :> α142_251' +//│ [pretty-printed] wd: (((int,),),) + +wd._1._1._1 + 1 +//│ Typed: int From 41e377924b28be83f24512b7f247b79e197450e7 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 00:59:01 +0800 Subject: [PATCH 021/498] WIP Minor --- shared/src/test/diff/nu/BasicMixins.mls | 121 ++++++++++++--------- shared/src/test/diff/nu/GenericClasses.mls | 17 +++ 2 files changed, 89 insertions(+), 49 deletions(-) create mode 100644 shared/src/test/diff/nu/GenericClasses.mls diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index bcfcb82a84..44510e5eaf 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -89,28 +89,39 @@ mixin Foo { mixin WrapBase { // fun wrap(x) = x // fun wrap(x) = x : int - fun wrap(x : int) = x : int + fun wrapA(x : int) = x : int + fun wrap(x) = x } //│ mixin WrapBase //│ this: this129' //│ super: super130' -//│ fun wrap: ‹∀ 1. wrap132''#› where -//│ | wrap132''# := (Int -> Int) -//│ [pretty-printed] wrap: int -> int +//│ fun wrapA: ‹∀ 1. wrapA133''#› where +//│ | wrapA133''# := (Int -> Int) +//│ [pretty-printed] wrapA: int -> int +//│ fun wrap: ‹∀ 1. wrap134''#› where +//│ | wrap134''# := (α135'' -> α135'') +//│ [pretty-printed] wrap: 'a -> 'a // :d mixin Wrap { + fun wrapA(x) = [super.wrapA(x)] fun wrap(x) = [super.wrap(x)] } //│ mixin Wrap -//│ this: this135' -//│ super: super136' -//│ | super136' <: {wrap: wrap140_141'} -//│ | wrap140_141' <: ((α139_143',) -> α142_144') -//│ fun wrap: ‹∀ 1. wrap138''#› where -//│ | wrap138''# := (α139'' -> (α142'',)) -//│ | α139'' <: α139_143' -//│ | α142'' :> α142_144' +//│ this: this142' +//│ super: super143' +//│ | super143' <: {wrap: wrap155_156'} & {wrapA: wrapA148_149'} +//│ | wrapA148_149' <: ((α147_151',) -> α150_152') +//│ | wrap155_156' <: ((α154_158',) -> α157_159') +//│ fun wrapA: ‹∀ 1. wrapA146''#› where +//│ | wrapA146''# := (α147'' -> (α150'',)) +//│ | α147'' <: α147_151' +//│ | α150'' :> α150_152' +//│ [pretty-printed] wrapA: anything -> (nothing,) +//│ fun wrap: ‹∀ 1. wrap153''#› where +//│ | wrap153''# := (α154'' -> (α157'',)) +//│ | α154'' <: α154_158' +//│ | α157'' :> α157_159' //│ [pretty-printed] wrap: anything -> (nothing,) @@ -124,65 +135,77 @@ WrapBase1 //│ Typed: WrapBase1 // :d -WrapBase1.wrap +WrapBase1.wrapA //│ Typed: int -> (int,) +WrapBase1.wrap +//│ Typed: 'a -> ('a,) + // :d // WrapBase1.wrap + WrapBase1.wrap(1) +//│ Typed: (1,) + +WrapBase1.wrap("ok") +//│ Typed: ("ok",) + + +WrapBase1.wrapA(1) //│ Typed: (int,) :e -WrapBase1.wrap("ok") +WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.137: WrapBase1.wrap("ok") -//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.159: WrapBase1.wrapA("ok") +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.137: WrapBase1.wrap("ok") -//│ ║ ^^^^ +//│ ║ l.159: WrapBase1.wrapA("ok") +//│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.92: fun wrap(x : int) = x : int -//│ ║ ^^^ +//│ ║ l.92: fun wrapA(x : int) = x : int +//│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.103: fun wrap(x) = [super.wrap(x)] -//│ ╙── ^ +//│ ║ l.107: fun wrapA(x) = [super.wrapA(x)] +//│ ╙── ^ //│ Typed: (int,) | error + module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ class WrapBase2 let w = WrapBase2.wrap -//│ fun w: ‹∀ 0. w241'#› where -//│ | w241'# := wrap242' -//│ | wrap242' :> ‹∀ 1. wrap138_243''#› <: w241'# -//│ | wrap138_243''# := (α139_244'' -> (α142_250'',)) -//│ | α139_244'' <: α139_245' -//│ | α139_245' <: α139_246' -//│ | α139_246' <: α139_247' -//│ | α139_247' <: α139_248' -//│ | α139_248' <: α139_249' -//│ | α139_249' <: Int -//│ | α142_250'' :> α142_251' -//│ | α142_251' :> ‹∀ 2. (α142_252''',)› -//│ | α142_252''' :> α142_253' -//│ | α142_253' :> ‹∀ 2. (α142_254''',)› -//│ | α142_254''' :> α142_255' -//│ | α142_255' :> Int -//│ [pretty-printed] w: int -> (((int,),),) +//│ fun w: ‹∀ 0. w374'#› where +//│ | w374'# := wrap375' +//│ | wrap375' :> ‹∀ 1. wrap153_389''#› <: w374'# +//│ | wrap153_389''# := (α154_390'' -> (α157_398'',)) +//│ | α154_390'' <: α154_391' +//│ | α154_391' <: α154_392' +//│ | α154_392' <: α154_393' +//│ | α154_393' <: α154_394' +//│ | α154_394' <: α154_395' +//│ | α154_395' <: α135_396' +//│ | α135_396' <: α157_397' +//│ | α157_398'' :> α157_399' +//│ | α157_399' :> ‹∀ 2. (α157_400''',)› +//│ | α157_400''' :> α157_401' +//│ | α157_401' :> ‹∀ 2. (α157_402''',)› +//│ | α157_402''' :> α157_397' +//│ [pretty-printed] w: 'a -> ((('a,),),) let wd = w(1) -//│ fun wd: ‹∀ 0. wd272'#› where -//│ | α142_251' :> ‹∀ 2. (α142_252''',)› -//│ | α142_252''' :> α142_253' -//│ | α142_253' :> ‹∀ 2. (α142_254''',)› -//│ | α142_254''' :> α142_255' -//│ | α142_255' :> Int -//│ | wd272'# := α273' -//│ | α273' :> ‹∀ 2. (α142_274''',)› <: wd272'# -//│ | α142_274''' :> α142_251' -//│ [pretty-printed] wd: (((int,),),) +//│ fun wd: ‹∀ 0. wd422'#› where +//│ | α157_397' :> 1 +//│ | α157_399' :> ‹∀ 2. (α157_400''',)› +//│ | α157_400''' :> α157_401' +//│ | α157_401' :> ‹∀ 2. (α157_402''',)› +//│ | α157_402''' :> α157_397' +//│ | wd422'# := α423' +//│ | α423' :> ‹∀ 2. (α157_424''',)› <: wd422'# +//│ | α157_424''' :> α157_399' +//│ [pretty-printed] wd: (((1,),),) wd._1._1._1 + 1 //│ Typed: int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls new file mode 100644 index 0000000000..0669aa1a75 --- /dev/null +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -0,0 +1,17 @@ +:NewParser +:NewDefs +:NoJS + + +:e +class Some(value: A) +//│ ╔══[ERROR] type identifier not found: A +//│ ║ l.7: class Some(value: A) +//│ ╙── ^ +//│ class Some + + +Some(1) +//│ Typed: Some + + From d510977c2c389f10bdf5a6421e9279cd85266a0a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 01:15:20 +0800 Subject: [PATCH 022/498] WIP tparams --- .../src/main/scala/mlscript/NuTypeDefs.scala | 8 ++-- .../main/scala/mlscript/TyperDatatypes.scala | 31 +++++++++--- shared/src/test/diff/nu/BasicClasses.mls | 8 ++-- shared/src/test/diff/nu/GenericClasses.mls | 48 ++++++++++++++++--- 4 files changed, 74 insertions(+), 21 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 30a1b6efbf..5cfd6f33fe 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -82,12 +82,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case TypedNuFun(level, fd, ty) => // TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(level, rigidify)) TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) - case TypedNuCls(level, td, ttu, params, members) => + case TypedNuCls(level, td, ttu, tps, params, members) => println(">>",level,ctx.lvl) // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), // params.mapValues(_.freshenAbove(level, rigidify)), // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), + tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap) // case _ => ??? @@ -103,7 +104,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { def nme: TypeName - val tparams: Ls[TN -> TV] = Nil // TODO + // val tparams: Ls[TN -> TV] = Nil // TODO } // case class TypedNuTypeDef( // kind: TypeDefKind, @@ -123,7 +124,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { - case class TypedNuCls(level: Level, td: NuTypeDef, ttu: TypedTypingUnit, params: Ls[Var -> FieldType], + case class TypedNuCls(level: Level, td: NuTypeDef, ttu: TypedTypingUnit, + tparams: Ls[TN -> TV], params: Ls[Var -> FieldType], // members: Map[Str, LazyTypeInfo]) members: Map[Str, NuMember]) extends TypedNuTypeDef(Cls) with TypedNuTermDef { diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 79261c1dd0..0372a26cf8 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -91,12 +91,21 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => implicit val prov: TP = noProv // TODO ctx.nextLevel { implicit ctx => + val tparams = td.tparams.map(tp => + tp -> freshVar(TypeProvenance( + tp.toLoc, + "type parameter", + S(tp.name), + true), N, S(tp.name))) + val typedParams = td.params.fields.map { case (S(nme), Fld(mut, spec, value)) => assert(!mut && !spec, "TODO") // TODO value.toType match { case R(tpe) => - implicit val vars: Map[Str, SimpleType] = Map.empty // TODO type params + implicit val vars: Map[Str, SimpleType] = + // Map.empty // TODO type params + tparams.iterator.mapKeys(_.name).toMap implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? val ty = typeType(tpe) nme -> FieldType(N, ty)(provTODO) @@ -119,10 +128,11 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) ctx += "this" -> VarSymbol(thisTV, Var("this")) - // TODO check against `tv` - println(td.tparams) - println(td.params) - println(td.parents) + // // TODO check against `tv` + // println(td.tparams) + // println(td.params) + // println(td.parents) + implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) val finalType = freshVar(noProv/*TODO*/, N, S("this")) @@ -215,7 +225,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // constrain(thisTy, thisTV) val mems = baseMems ++ paramMems ++ clsMems - TypedNuCls(outerCtx.lvl, td, ttu, typedParams, mems.map(d => d.name -> d).toMap) + TypedNuCls(outerCtx.lvl, td, ttu, + tparams, typedParams, mems.map(d => d.name -> d).toMap) } case Mxn => implicit val prov: TP = noProv // TODO @@ -249,7 +260,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val cls = _cls.freshen.asInstanceOf[TypedNuCls] FunctionType( TupleType(cls.params.mapKeys(some))(provTODO), - ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) + // cls.tparams.foldLeft( + // ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) + // ) { case (acc, (tn, tv)) => acc & } + ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( + cls.tparams.map { case (tn, tv) => + Var(tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + )(provTODO) )(provTODO) case TypedNuFun(_, fd, ty) => // println(fd, ty) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 780d32fddd..a6790e2d02 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -67,7 +67,7 @@ let n1 = b1.n //│ | | | | NEW α99' UB (1) //│ | | | | 1. C Base0<> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›)),None),List((n,n23')),HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) +//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›)),None),List(),List((n,n23')),HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) //│ | | | | | | (>>,0,1) //│ | | | | | | 1. FRESHEN ‹∀ 1. me30''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false @@ -165,7 +165,7 @@ let n1 = b1.n //│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false //│ | | | | | | | => me30_106''# //│ | | | | | | => ‹∀ 1. me30_106''#› -//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›)),None),List((n,n23_118')),HashMap(n -> NuParam(n,n23_118'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) +//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›)),None),List(),List((n,n23_118')),HashMap(n -> NuParam(n,n23_118'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) //│ | | | | | | (n,HashMap(n -> NuParam(n,n23_118'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) //│ | | | | | | 1. C n23_118' + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo ~> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo -> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) +//│ | | | | | | TypedNuCls(0,class Base1(base: int,) {fun getBase1 = base; fun me = this; fun foo = (x,) => + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo ~> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List(),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo -> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) //│ | | | | | | (>>,0,0) //│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1203''#› || 0 .. 1024 0 true //│ | | | | | | => ‹∀ 1. getBase1203''#› @@ -300,7 +300,7 @@ b.me //│ | | | | | | => ‹∀ 1. me204_248''#› //│ | | | | | | 0. FRESHEN ‹∀ 1. foo205''#› || 0 .. 1024 0 true //│ | | | | | | => ‹∀ 1. foo205''#› -//│ | | | | | | TypedNuCls(0,class Base1(base: int,) {fun getBase1 = base; fun me = this; fun foo = (x,) => + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo ~> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) +//│ | | | | | | TypedNuCls(0,class Base1(base: int,) {fun getBase1 = base; fun me = this; fun foo = (x,) => + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo ~> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List(),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) //│ | | | | | | (me,Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) //│ | | | | | | 0. C ‹∀ 1. me204_248''#› (value: A) -//│ ╔══[ERROR] type identifier not found: A -//│ ║ l.7: class Some(value: A) -//│ ╙── ^ +// :d +class Some(value: A) { + fun get = value +} //│ class Some +//│ fun get: ‹∀ 1. get27''#› where +//│ | get27''# := A23' +//│ [pretty-printed] get: nothing -Some(1) -//│ Typed: Some +let s = Some(1) +//│ fun s: ‹∀ 0. s31'#› where +//│ | s31'# := α35' +//│ | A23_34' :> 1 +//│ | α35' :> (Some<> & {A: mut A23_34'..A23_34'}) <: s31'# +//│ [pretty-printed] s: Some & {A = 'A} +//│ | where +//│ | 'A :> 1 + +// TODO +s.value +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.26: s.value +//│ ║ ^^^^^^^ +//│ ╟── application of type `Some & {A = ?A}` does not have field 'value' +//│ ║ l.16: let s = Some(1) +//│ ║ ^^^^^^^ +//│ ╟── but it flows into reference with expected type `{value: ?value}` +//│ ║ l.26: s.value +//│ ╙── ^ +//│ Typed: error + +// TODO +s.get +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.39: s.get +//│ ║ ^^^^^ +//│ ╟── application of type `Some & {A = ?A}` does not have field 'get' +//│ ║ l.16: let s = Some(1) +//│ ║ ^^^^^^^ +//│ ╟── but it flows into reference with expected type `{get: ?get}` +//│ ║ l.39: s.get +//│ ╙── ^ +//│ Typed: error From 5eeefd91c2414079d62cdb5266231b18ccc79043 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 01:44:03 +0800 Subject: [PATCH 023/498] WIP refined member signatures --- .../scala/mlscript/ConstraintSolver.scala | 101 +++++++++++------- .../main/scala/mlscript/TypeSimplifier.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- shared/src/test/diff/nu/BasicClasses.mls | 16 +-- shared/src/test/diff/nu/GenericClasses.mls | 84 ++++++++++----- 5 files changed, 127 insertions(+), 78 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 23279d6b40..54f8403746 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -361,6 +361,11 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(f0, f1, true) case (LhsRefined(S(f: FunctionType), ts, r, trs), RhsBases(pts, _, _)) => annoying(Nil, LhsRefined(N, ts, r, trs), Nil, done_rs) + case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if nme.isCapitalized => + val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap), fldNme) + rec(fty.ub, fldTy.ub, false) + recLb(fldTy, fty) + // ??? case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => if (pts.contains(pt) || pts.exists(p => pt.parentsST.contains(p.id))) println(s"OK $pt <: ${pts.mkString(" | ")}") @@ -408,6 +413,65 @@ class ConstraintSolver extends NormalForms { self: Typer => } }() + def lookupNuTypeDef(clsNme: Str, rfnt: Map[Var, FieldType]) + // (implicit raise: Raise, cctx: ConCtx, ctx: Ctx, shadows: Shadows) + (implicit ctx: Ctx) + : TypedNuCls = { + val info = ctx.tyDefs2(clsNme) + + // Option.when(info.isComputing) { + // ??? + // }.getOrElse + { info.complete() match { + case td: TypedNuCls => + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + // freshened ++= td.tparams.map(tp => tp._2 -> TopType) + td.tparams.foreach { case (tn, _tv) => + val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) + println(s"Assigning $tv") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(rfnt.get(Var(td.nme.name + "#" + tn.name)) match { + case S(fty) => + TypeBounds( + fty.lb.getOrElse(BotType), + fty.ub, + )(tv.prov) + case N => + // FIXME type bounds are kind of wrong for this + TypeBounds( + tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + tv.upperBounds.foldLeft(TopType: ST)(_ & _), + )(tv.prov) + }) + freshened += _tv -> tv + } + // println(td) + // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] + val res = + // td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] + td.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] + // println(res) + // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) + res + case _ => ??? + }} + } + def lookupNuTypeDefField(cls: TypedNuCls, fld: Var): FieldType = { + // println(fld.name, cls.members) + cls.members.get(fld.name) match { + case S(d: TypedNuFun) => + d.ty.toUpper(provTODO) + case S(p: NuParam) => + p.ty + case N => + err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", + // ttp(fld)) + fld.toLoc).toUpper(noProv) + // case _ => ??? + } + } + /** Helper function to constrain Field lower bounds. */ def recLb(lhs: FieldType, rhs: FieldType) (implicit raise: Raise, cctx: ConCtx, ctx: Ctx, shadows: Shadows): Unit = { @@ -557,43 +621,8 @@ class ConstraintSolver extends NormalForms { self: Typer => case (NegType(lhs), NegType(rhs)) => rec(rhs, lhs, true) case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => - def lookupNuTypeDef(clsNme: Str): TypedNuCls = { - val info = ctx.tyDefs2(clsNme) - - // Option.when(info.isComputing) { - // ??? - // }.getOrElse - { info.complete() match { - case td: TypedNuCls => - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - println(td) - // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] - val res = - // td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] - td.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] - println(res) - // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) - res - case _ => ??? - }} - } - def lookupNuTypeDefField(cls: TypedNuCls, rfnt: Map[Var, Field], fld: Var): FieldType = { - println(fld.name, cls.members) - cls.members.get(fld.name) match { - case S(d: TypedNuFun) => - d.ty.toUpper(provTODO) - case S(p: NuParam) => - p.ty - case N => - err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", - // ttp(fld)) - fld.toLoc).toUpper(noProv) - // case _ => ??? - } - } rt.fields.foreach { case (fldNme, fldTy) => - val fty = lookupNuTypeDefField(lookupNuTypeDef(nme), Map.empty, fldNme) + val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, Map.empty), fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 74e7a18a02..2c649f4304 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -89,7 +89,7 @@ trait TypeSimplifier { self: Typer => val prefix = fnme.takeWhile(_ =/= '#') val postfix = fnme.drop(prefix.length + 1) lazy val default = fty.update(process(_ , N), process(_ , N)) - if (postfix.isEmpty) v -> default :: Nil + if (postfix.isEmpty || prefix.isCapitalized/* TODO */) v -> default :: Nil else { val td = ctx.tyDefs(prefix) td.tvarVariances.fold(v -> default :: Nil)(tvv => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 0372a26cf8..c373bb1167 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -265,7 +265,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ) { case (acc, (tn, tv)) => acc & } ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( cls.tparams.map { case (tn, tv) => - Var(tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + Var(cls.td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } )(provTODO) )(provTODO) case TypedNuFun(_, fd, ty) => diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index a6790e2d02..1d6790fca5 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -67,7 +67,6 @@ let n1 = b1.n //│ | | | | NEW α99' UB (1) //│ | | | | 1. C Base0<> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›)),None),List(),List((n,n23')),HashMap(n -> NuParam(n,n23'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30''#›))) //│ | | | | | | (>>,0,1) //│ | | | | | | 1. FRESHEN ‹∀ 1. me30''#› || 0 .. 1024 1 false //│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false @@ -165,8 +164,6 @@ let n1 = b1.n //│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false //│ | | | | | | | => me30_106''# //│ | | | | | | => ‹∀ 1. me30_106''#› -//│ | | | | | | TypedNuCls(0,class Base0(n,) {fun me = this; fun my = (this).n; fun mine = my; fun oops = (this).my},TypedTypingUnit(List(me ~> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›), my ~> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), mine ~> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops ~> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›)),None),List(),List((n,n23_118')),HashMap(n -> NuParam(n,n23_118'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) -//│ | | | | | | (n,HashMap(n -> NuParam(n,n23_118'), mine -> TypedNuFun(1,fun mine = my,‹∀ 1. mine34_113''#›), oops -> TypedNuFun(1,fun oops = (this).my,‹∀ 1. oops35_116''#›), my -> TypedNuFun(1,fun my = (this).n,‹∀ 1. my31_111''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me30_106''#›))) //│ | | | | | | 1. C n23_118' + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo ~> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List(),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(1,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(1,fun me = this,‹∀ 1. me204''#›), foo -> TypedNuFun(1,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) //│ | | | | | | (>>,0,0) //│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1203''#› || 0 .. 1024 0 true //│ | | | | | | => ‹∀ 1. getBase1203''#› @@ -300,8 +296,6 @@ b.me //│ | | | | | | => ‹∀ 1. me204_248''#› //│ | | | | | | 0. FRESHEN ‹∀ 1. foo205''#› || 0 .. 1024 0 true //│ | | | | | | => ‹∀ 1. foo205''#› -//│ | | | | | | TypedNuCls(0,class Base1(base: int,) {fun getBase1 = base; fun me = this; fun foo = (x,) => + (base,) (x,)},TypedTypingUnit(List(getBase1 ~> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me ~> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo ~> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›)),None),List(),List((base,Int)),Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) -//│ | | | | | | (me,Map(base -> NuParam(base,Int), getBase1 -> TypedNuFun(0,fun getBase1 = base,‹∀ 1. getBase1203''#›), me -> TypedNuFun(0,fun me = this,‹∀ 1. me204_248''#›), foo -> TypedNuFun(0,fun foo = (x,) => + (base,) (x,),‹∀ 1. foo205''#›))) //│ | | | | | | 0. C ‹∀ 1. me204_248''#› (value: A) { fun get = value + fun toArray = [value] } //│ class Some -//│ fun get: ‹∀ 1. get27''#› where -//│ | get27''# := A23' +//│ fun get: ‹∀ 1. get28''#› where +//│ | get28''# := A23' //│ [pretty-printed] get: nothing - +//│ fun toArray: ‹∀ 1. toArray29''#› where +//│ | toArray29''# := (A23',) +//│ [pretty-printed] toArray: (nothing,) let s = Some(1) -//│ fun s: ‹∀ 0. s31'#› where -//│ | s31'# := α35' -//│ | A23_34' :> 1 -//│ | α35' :> (Some<> & {A: mut A23_34'..A23_34'}) <: s31'# -//│ [pretty-printed] s: Some & {A = 'A} +//│ fun s: ‹∀ 0. s35'#› where +//│ | s35'# := α41' +//│ | A23_38' :> 1 +//│ | α41' :> (Some<> & {Some#A: mut A23_38'..A23_38'}) <: s35'# +//│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 -// TODO s.value -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.26: s.value -//│ ║ ^^^^^^^ -//│ ╟── application of type `Some & {A = ?A}` does not have field 'value' -//│ ║ l.16: let s = Some(1) -//│ ║ ^^^^^^^ -//│ ╟── but it flows into reference with expected type `{value: ?value}` -//│ ║ l.26: s.value -//│ ╙── ^ -//│ Typed: error +//│ Typed: 1 -// TODO s.get -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.39: s.get -//│ ║ ^^^^^ -//│ ╟── application of type `Some & {A = ?A}` does not have field 'get' -//│ ║ l.16: let s = Some(1) -//│ ║ ^^^^^^^ -//│ ╟── but it flows into reference with expected type `{get: ?get}` -//│ ║ l.39: s.get -//│ ╙── ^ +//│ Typed: 1 + +s.toArray +//│ Typed: (1,) + +module None { + fun get = error + fun toArray = [] +} +//│ class None +//│ fun get: ‹∀ 1. get81''#› where +//│ | get81''# := ⊥ +//│ [pretty-printed] get: nothing +//│ fun toArray: ‹∀ 1. toArray82''#› where +//│ | toArray82''# := () +//│ [pretty-printed] toArray: () + +None.toArray +//│ Typed: () + + +// TODO +type Option = Some | None +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + +let opt = if true then Some(123 + 1) else None +//│ fun opt: ‹∀ 0. opt92'#› where +//│ | opt92'# := (α101' | None<>) +//│ | A23_96' :> int +//│ | α101' :> (Some<> & {Some#A: mut A23_96'..A23_96'}) +//│ [pretty-printed] opt: None | Some & {Some#A = 'A} +//│ | where +//│ | 'A :> int + +opt.toArray +//│ Typed: Array[int] + +// TODO +if opt is Some then opt.value else 0 +//│ ╔══[ERROR] Cannot find the constructor `Some` in the context +//│ ║ l.71: if opt is Some then opt.value else 0 +//│ ╙── ^^^^ //│ Typed: error From 310038466aaab1b90eec6c43004b196baaa208dc Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 01:49:45 +0800 Subject: [PATCH 024/498] WIP ucs --- shared/src/main/scala/mlscript/Typer.scala | 15 ++- .../main/scala/mlscript/ucs/Desugarer.scala | 34 +++-- shared/src/test/diff/nu/GenericClasses.mls | 124 ++++++++++++++---- 3 files changed, 132 insertions(+), 41 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ba0a79810d..c911306fdb 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1028,13 +1028,20 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val patTy = pat match { case lit: Lit => ClassTag(lit, lit.baseClasses)(tp(pat.toLoc, "literal pattern")) - case Var(nme) => + case v @ Var(nme) => val tpr = tp(pat.toLoc, "type pattern") ctx.tyDefs.get(nme) match { case None => - err("type identifier not found: " + nme, pat.toLoc)(raise) - val e = ClassTag(ErrTypeId, Set.empty)(tpr) - return ((e -> e) :: Nil) -> e + ctx.tyDefs2.get(nme) match { + case N => + err("type identifier not found: " + nme, pat.toLoc)(raise) + val e = ClassTag(ErrTypeId, Set.empty)(tpr) + return ((e -> e) :: Nil) -> e + case S(td) => + ClassTag(v, + Set.empty//TODO + )(provTODO) + } case Some(td) => td.kind match { case Als => err(msg"can only match on classes and traits", pat.toLoc)(raise) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 0a8b7eac5f..ebbe5d2063 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -160,10 +160,10 @@ class Desugarer extends TypeDefs { self: Typer => // This case handles simple class tests. // x is A case classNameVar @ Var(className) => - ctx.tyDefs.get(className) match { + ctx.tyDefs.get(className).orElse(ctx.tyDefs2.get(className)) match { case N => throw new DesugaringException({ import Message.MessageContext - msg"Cannot find the constructor `$className` in the context" + msg"Cannot find constructor `$className` in scope" }, classNameVar.toLoc) case S(_) => printlnUCS(s"Build a Clause.MatchClass from $scrutinee where pattern is $classNameVar") @@ -172,18 +172,26 @@ class Desugarer extends TypeDefs { self: Typer => // This case handles classes with destruction. // x is A(r, s, t) case app @ App(classNameVar @ Var(className), Tup(args)) => - ctx.tyDefs.get(className) match { - case N => - throw new DesugaringException({ - import Message.MessageContext - msg"Cannot find class `$className` in the context" - }, classNameVar.toLoc) - case S(td) => - if (args.length === td.positionals.length) { + ctx.tyDefs.get(className).map(td => (td.kind, td.positionals)) + .orElse(ctx.tyDefs2.get(className).map(td => + (td.decl.asInstanceOf[NuTypeDef].kind, + td.complete().asInstanceOf[TypedNuCls].params.map(_._1.name)))) + match { + // ctx2.tyDefs.get(className) match { + case N => + throw new DesugaringException({ + import Message.MessageContext + msg"Cannot find class `$className` in scope" + }, classNameVar.toLoc) + // case S(td) => + // } + // case S(td) => + case S((kind, positionals)) => + if (args.length === positionals.length) { val (subPatterns, bindings) = desugarPositionals( scrutinee, args.iterator.map(_._2.value), - td.positionals + positionals ) val clause = Clause.MatchClass(scrutinee, classNameVar, bindings)(pattern.toLoc.toList ::: collectLocations(scrutinee.term)) printlnUCS(s"Build a Clause.MatchClass from $scrutinee where pattern is $pattern") @@ -193,9 +201,9 @@ class Desugarer extends TypeDefs { self: Typer => } else { throw new DesugaringException({ import Message.MessageContext - val expected = td.positionals.length + val expected = positionals.length val actual = args.length - msg"${td.kind.str} $className expects ${expected.toString} ${ + msg"${kind.str} $className expects ${expected.toString} ${ "parameter".pluralize(expected) } but found ${args.length.toString} ${ "parameter".pluralize(expected) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 8f41574b02..fd0c4d3a26 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -7,20 +7,28 @@ class Some(value: A) { fun get = value fun toArray = [value] + fun mapBad(f) = Some(f(value)) // Notice the extruded type } //│ class Some -//│ fun get: ‹∀ 1. get28''#› where -//│ | get28''# := A23' +//│ fun get: ‹∀ 1. get29''#› where +//│ | get29''# := A23' //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray29''#› where -//│ | toArray29''# := (A23',) +//│ fun toArray: ‹∀ 1. toArray30''#› where +//│ | toArray30''# := (A23',) //│ [pretty-printed] toArray: (nothing,) +//│ fun mapBad: ‹∀ 1. mapBad31''#› where +//│ | mapBad31''# := (α32'' -> α34'') +//│ | α32'' <: ((A23',) -> α33'') +//│ | α33'' <: α33_35 +//│ | α34'' :> α34_36 +//│ [pretty-printed] mapBad: (nothing -> anything) -> nothing + let s = Some(1) -//│ fun s: ‹∀ 0. s35'#› where -//│ | s35'# := α41' -//│ | A23_38' :> 1 -//│ | α41' :> (Some<> & {Some#A: mut A23_38'..A23_38'}) <: s35'# +//│ fun s: ‹∀ 0. s49'#› where +//│ | s49'# := α60' +//│ | A23_52' :> 1 +//│ | α60' :> (Some<> & {Some#A: mut A23_52'..A23_52'}) <: s49'# //│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 @@ -34,17 +42,47 @@ s.get s.toArray //│ Typed: (1,) + + +// FIXME + +s.mapBad +//│ Typed: (1 -> anything) -> nothing + +s.mapBad(succ) +//│ Typed: nothing + + +s.map +//│ ╔══[ERROR] class `Some` does not contain member `map` +//│ ║ l.55: s.map +//│ ╙── ^^^^ +//│ Typed: error + +s.map(succ) +//│ ╔══[ERROR] class `Some` does not contain member `map` +//│ ║ l.61: s.map(succ) +//│ ╙── ^^^^ +//│ Typed: error + + + module None { fun get = error fun toArray = [] + fun mapBad(f) = None } //│ class None -//│ fun get: ‹∀ 1. get81''#› where -//│ | get81''# := ⊥ +//│ fun get: ‹∀ 1. get180''#› where +//│ | get180''# := ⊥ //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray82''#› where -//│ | toArray82''# := () +//│ fun toArray: ‹∀ 1. toArray181''#› where +//│ | toArray181''# := () //│ [pretty-printed] toArray: () +//│ fun mapBad: ‹∀ 1. mapBad182''#› where +//│ | mapBad182''# := (α183'' -> None174) +//│ [pretty-printed] mapBad: anything -> nothing + None.toArray //│ Typed: () @@ -55,23 +93,61 @@ type Option = Some | None //│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing -let opt = if true then Some(123 + 1) else None -//│ fun opt: ‹∀ 0. opt92'#› where -//│ | opt92'# := (α101' | None<>) -//│ | A23_96' :> int -//│ | α101' :> (Some<> & {Some#A: mut A23_96'..A23_96'}) + +let opt = if true then Some(123) else None +//│ fun opt: ‹∀ 0. opt197'#› where +//│ | opt197'# := (α209' | None<>) +//│ | A23_201' :> 123 +//│ | α209' :> (Some<> & {Some#A: mut A23_201'..A23_201'}) //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where -//│ | 'A :> int +//│ | 'A :> 123 opt.toArray -//│ Typed: Array[int] +//│ Typed: Array[123] -// TODO -if opt is Some then opt.value else 0 -//│ ╔══[ERROR] Cannot find the constructor `Some` in the context -//│ ║ l.71: if opt is Some then opt.value else 0 -//│ ╙── ^^^^ +opt.mapBad(succ) +//│ Typed: nothing + +opt.map(succ) +//│ ╔══[ERROR] class `Some` does not contain member `map` +//│ ║ l.110: opt.map(succ) +//│ ╙── ^^^^ //│ Typed: error + +if opt is Some then opt.value else 0 +//│ Typed: 0 | 123 + +if opt is Some(v) then v else 0 +//│ Typed: 0 | 123 + + +fun map(x, f) = if x is + None then None + Some(v) then Some(f(v)) +//│ fun map: ‹∀ 0. map310'#› where +//│ | map310'# := ((α311', α312',) -> (None<> | α328')) +//│ | α311' <: ((None<> & α313') | ((Some<> & α314') & ~(None<>))) +//│ | α312' <: ((‹∀ 1. value315''›,) -> α327') +//│ | α314' <: {value: value315_316'} +//│ | value315'' :> value315_316' +//│ | α327' <: A23_319' +//│ | α328' :> (Some<> & {Some#A: mut A23_319'..A23_319'}) +//│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) + +let mo = map(opt, succ) +//│ fun mo: ‹∀ 0. mo344'#› where +//│ | A23_319' :> int +//│ | α328' :> (Some<> & {Some#A: mut A23_319'..A23_319'}) +//│ | mo344'# := α345' +//│ | α345' :> (None<> | α328') <: mo344'# +//│ [pretty-printed] mo: None | Some & {Some#A = 'A} +//│ | where +//│ | 'A :> int + +mo.toArray +//│ Typed: Array[int] + + From 3d7eae7ffe0e3b469ea39ca737c55c9066b8cc29 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 02:20:19 +0800 Subject: [PATCH 025/498] WIP type vars in context --- .../src/main/scala/mlscript/NuTypeDefs.scala | 3 +- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 16 ++-- shared/src/test/diff/nu/GenericClasses.mls | 96 +++++++++---------- .../src/test/scala/mlscript/DiffTests.scala | 5 +- 5 files changed, 65 insertions(+), 59 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 5cfd6f33fe..d75884bef2 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -157,7 +157,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - def typeTypingUnit(tu: TypingUnit, allowPure: Bool)(implicit ctx: Ctx, raise: Raise): TypedTypingUnit = + def typeTypingUnit(tu: TypingUnit, allowPure: Bool) + (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]): TypedTypingUnit = trace(s"${ctx.lvl}. Typing $tu") { // trace(s"${ctx.lvl}. Typing $tu") { ctx.nextLevel { implicit ctx: Ctx => // val named = mutable.Map.empty[Str, LazyTypeInfo[TypedNuTermDef]] diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index c911306fdb..23211ca043 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -528,8 +528,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) } /** Like `typeLetRhs` but removes unnecessary polymorphic type wrappers. */ - def typeLetRhs2(isrec: Boolean, nme: Str, rhs: Term)(implicit ctx: Ctx, raise: Raise): ST = { - val res = typeLetRhs(isrec: Boolean, nme: Str, rhs: Term)(ctx, raise, Map.empty, genLambdas = true) + def typeLetRhs2(isrec: Boolean, nme: Str, rhs: Term)(implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]): ST = { + val res = typeLetRhs(isrec: Boolean, nme: Str, rhs: Term)(ctx, raise, vars, genLambdas = true) def stripPoly(ty: ST): ST = ty match { case pt: PolymorphicType => PolymorphicType.mk(pt.polymLevel, stripPoly(pt.body)) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c373bb1167..7c83996b00 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -31,9 +31,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case class VarSymbol(ty: ST, definingVar: Var) extends TypeInfo // TODO rm level? already in ctx - class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx) extends TypeInfo { + class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx, vars: Map[Str, SimpleType]) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { private def outerCtx = ctx + private def outerVars = vars val tparams: Ls[TN -> TV] = Nil // TODO var isComputing: Bool = false // TODO replace by a Ctx entry var result: Opt[TypedNuTermDef] = N @@ -71,12 +72,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // vars = tps.map(tp => tp.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) val body_ty = ctx.nextLevel { implicit ctx: Ctx => // TODO use poly instead! typeType(ty)(ctx, raise, - vars = tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) + vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) } // TODO check against `tv` TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) case L(body) => - implicit val vars: Map[Str, SimpleType] = Map.empty + implicit val vars: Map[Str, SimpleType] = + outerVars ++ Map.empty // TODO tparams implicit val gl: GenLambdas = true val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) // implicit val prov: TP = noProv // TODO @@ -98,14 +100,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => S(tp.name), true), N, S(tp.name))) + implicit val vars: Map[Str, SimpleType] = + outerVars ++ tparams.iterator.mapKeys(_.name).toMap + val typedParams = td.params.fields.map { case (S(nme), Fld(mut, spec, value)) => assert(!mut && !spec, "TODO") // TODO value.toType match { case R(tpe) => - implicit val vars: Map[Str, SimpleType] = - // Map.empty // TODO type params - tparams.iterator.mapKeys(_.name).toMap implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? val ty = typeType(tpe) nme -> FieldType(N, ty)(provTODO) @@ -231,6 +233,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case Mxn => implicit val prov: TP = noProv // TODO ctx.nextLevel { implicit ctx => + implicit val vars: Map[Str, SimpleType] = + outerVars ++ Map.empty // TODO type params val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) val superTV = freshVar(noProv/*FIXME*/, N, S("super")) ctx += "this" -> VarSymbol(thisTV, Var("this")) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index fd0c4d3a26..81161f3092 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -3,36 +3,43 @@ :NoJS -// :d class Some(value: A) { fun get = value fun toArray = [value] fun mapBad(f) = Some(f(value)) // Notice the extruded type + fun map(f : A => 'b) = Some(f(value)) // FIXME still problematic } //│ class Some -//│ fun get: ‹∀ 1. get29''#› where -//│ | get29''# := A23' +//│ fun get: ‹∀ 1. get30''#› where +//│ | get30''# := A23' //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray30''#› where -//│ | toArray30''# := (A23',) +//│ fun toArray: ‹∀ 1. toArray31''#› where +//│ | toArray31''# := (A23',) //│ [pretty-printed] toArray: (nothing,) -//│ fun mapBad: ‹∀ 1. mapBad31''#› where -//│ | mapBad31''# := (α32'' -> α34'') -//│ | α32'' <: ((A23',) -> α33'') -//│ | α33'' <: α33_35 -//│ | α34'' :> α34_36 +//│ fun mapBad: ‹∀ 1. mapBad32''#› where +//│ | mapBad32''# := (α33'' -> α35'') +//│ | α33'' <: ((A23',) -> α34'') +//│ | α34'' <: α34_36 +//│ | α35'' :> α35_37 //│ [pretty-printed] mapBad: (nothing -> anything) -> nothing +//│ fun map: ‹∀ 1. map38''#› where +//│ | map38''# := ((A23' -> 'b39'') -> α41'') +//│ | 'b39'' <: α40'' +//│ | α40'' <: α40_42 +//│ | α41'' :> α41_43 +//│ [pretty-printed] map: (nothing -> anything) -> nothing let s = Some(1) -//│ fun s: ‹∀ 0. s49'#› where -//│ | s49'# := α60' -//│ | A23_52' :> 1 -//│ | α60' :> (Some<> & {Some#A: mut A23_52'..A23_52'}) <: s49'# +//│ fun s: ‹∀ 0. s63'#› where +//│ | s63'# := α79' +//│ | A23_66' :> 1 +//│ | α79' :> (Some<> & {Some#A: mut A23_66'..A23_66'}) <: s63'# //│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 + s.value //│ Typed: 1 @@ -43,7 +50,6 @@ s.toArray //│ Typed: (1,) - // FIXME s.mapBad @@ -54,16 +60,10 @@ s.mapBad(succ) s.map -//│ ╔══[ERROR] class `Some` does not contain member `map` -//│ ║ l.55: s.map -//│ ╙── ^^^^ -//│ Typed: error +//│ Typed: (1 -> anything) -> nothing s.map(succ) -//│ ╔══[ERROR] class `Some` does not contain member `map` -//│ ║ l.61: s.map(succ) -//│ ╙── ^^^^ -//│ Typed: error +//│ Typed: nothing @@ -73,14 +73,14 @@ module None { fun mapBad(f) = None } //│ class None -//│ fun get: ‹∀ 1. get180''#› where -//│ | get180''# := ⊥ +//│ fun get: ‹∀ 1. get248''#› where +//│ | get248''# := ⊥ //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray181''#› where -//│ | toArray181''# := () +//│ fun toArray: ‹∀ 1. toArray249''#› where +//│ | toArray249''# := () //│ [pretty-printed] toArray: () -//│ fun mapBad: ‹∀ 1. mapBad182''#› where -//│ | mapBad182''# := (α183'' -> None174) +//│ fun mapBad: ‹∀ 1. mapBad250''#› where +//│ | mapBad250''# := (α251'' -> None242) //│ [pretty-printed] mapBad: anything -> nothing @@ -95,10 +95,10 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ fun opt: ‹∀ 0. opt197'#› where -//│ | opt197'# := (α209' | None<>) -//│ | A23_201' :> 123 -//│ | α209' :> (Some<> & {Some#A: mut A23_201'..A23_201'}) +//│ fun opt: ‹∀ 0. opt265'#› where +//│ | opt265'# := (α282' | None<>) +//│ | A23_269' :> 123 +//│ | α282' :> (Some<> & {Some#A: mut A23_269'..A23_269'}) //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> 123 @@ -110,8 +110,8 @@ opt.mapBad(succ) //│ Typed: nothing opt.map(succ) -//│ ╔══[ERROR] class `Some` does not contain member `map` -//│ ║ l.110: opt.map(succ) +//│ ╔══[ERROR] namespace `None` does not contain member `map` +//│ ║ l.112: opt.map(succ) //│ ╙── ^^^^ //│ Typed: error @@ -127,22 +127,22 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ‹∀ 0. map310'#› where -//│ | map310'# := ((α311', α312',) -> (None<> | α328')) -//│ | α311' <: ((None<> & α313') | ((Some<> & α314') & ~(None<>))) -//│ | α312' <: ((‹∀ 1. value315''›,) -> α327') -//│ | α314' <: {value: value315_316'} -//│ | value315'' :> value315_316' -//│ | α327' <: A23_319' -//│ | α328' :> (Some<> & {Some#A: mut A23_319'..A23_319'}) +//│ fun map: ‹∀ 0. map413'#› where +//│ | map413'# := ((α414', α415',) -> (None<> | α436')) +//│ | α414' <: ((None<> & α416') | ((Some<> & α417') & ~(None<>))) +//│ | α415' <: ((‹∀ 1. value418''›,) -> α435') +//│ | α417' <: {value: value418_419'} +//│ | value418'' :> value418_419' +//│ | α435' <: A23_422' +//│ | α436' :> (Some<> & {Some#A: mut A23_422'..A23_422'}) //│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) let mo = map(opt, succ) -//│ fun mo: ‹∀ 0. mo344'#› where -//│ | A23_319' :> int -//│ | α328' :> (Some<> & {Some#A: mut A23_319'..A23_319'}) -//│ | mo344'# := α345' -//│ | α345' :> (None<> | α328') <: mo344'# +//│ fun mo: ‹∀ 0. mo452'#› where +//│ | A23_422' :> int +//│ | α436' :> (Some<> & {Some#A: mut A23_422'..A23_422'}) +//│ | mo452'# := α453' +//│ | α453' :> (None<> | α436') <: mo452'# //│ [pretty-printed] mo: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> int diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 9f609d3ed1..7cd9310ed7 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -491,7 +491,8 @@ class DiffTests val (typeDefs, stmts) = if (newDefs) { - val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise) + val vars: Map[Str, typer.SimpleType] = Map.empty + val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise, vars) tpd.force()(raise) @@ -683,7 +684,7 @@ class DiffTests // statement is defined and has a body/definition case d @ Def(isrec, nme, L(rhs), isByname) => typer.dbg = mode.dbg - val ty_sch = typer.typeLetRhs2(isrec, nme.name, rhs)(ctx, raiseToBuffer) + val ty_sch = typer.typeLetRhs2(isrec, nme.name, rhs)(ctx, raiseToBuffer, vars = Map.empty) val exp = getType(ty_sch) // statement does not have a declared type for the body // the inferred type must be used and stored for lookup From 8d722b585ee49e497a0e750feb0117678b8587e3 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 02:27:55 +0800 Subject: [PATCH 026/498] WIP forget about self-constructing classes for now --- .../main/scala/mlscript/TyperDatatypes.scala | 10 +- shared/src/test/diff/nu/BasicClasses.mls | 207 +++--------------- shared/src/test/diff/nu/GenericClasses.mls | 105 ++++----- shared/src/test/diff/nu/MutualRec.mls | 98 ++++++--- 4 files changed, 145 insertions(+), 275 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 7c83996b00..83673f0b2b 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -39,6 +39,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => var isComputing: Bool = false // TODO replace by a Ctx entry var result: Opt[TypedNuTermDef] = N // var result: Opt[A] = N + val tv: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), N, @@ -256,7 +257,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => }() } - def typeSignature(implicit raise: Raise): ST = if (isComputing) tv // TODO FIXME wrong in general (when accessed from difft scope/level) + def typeSignature(implicit raise: Raise): ST = + if (isComputing) + decl match { + case _: NuFunDef => + tv // TODO FIXME wrong in general (when accessed from difft scope/level) + case _ => + err(msg"Cyclic definition", decl.toLoc) + } else complete() match { case cls: TypedNuCls if cls.td.kind is Nms => ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 1d6790fca5..667c425f20 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -51,131 +51,8 @@ let b1 = Base0(42) //│ | α99' :> Base0<> <: b184'# //│ [pretty-printed] b1: Base0 -:d +// :d let n1 = b1.n -//│ 0. Typing TypingUnit(List(let n1 = (b1).n)) -//│ Completing let n1 = (b1).n -//│ | 1. Typing term (b1).n -//│ | | 1. Typing term b1 -//│ | | 1. : b184'# -//│ | | CONSTRAIN b184'# Base0<> <: b184'# -//│ | | 1. C b184'# >,0,1) -//│ | | | | | | 1. FRESHEN ‹∀ 1. me30''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false -//│ | | | | | | | | 1. FRESHEN this24' || 0 .. 1 1 false -//│ | | | | | | | | | 1. FRESHEN this24' || 0 .. 1 1 false -//│ | | | | | | | | | | 1. FRESHEN Base0<> || 0 .. 1 0 true -//│ | | | | | | | | | | => Base0<> -//│ | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false -//│ | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | 1. FRESHEN {my: my36_37'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | | 1. FRESHEN my36_37' || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | | | 1. FRESHEN ‹∀ 1. my31_44''#› || 0 .. 1 0 true -//│ | | | | | | | | | | | | | | | | => ‹∀ 1. my31_44''#› -//│ | | | | | | | | | | | | | | | => my36_108' -//│ | | | | | | | | | | | | | | => {my: my36_108'} -//│ | | | | | | | | | | | | | => {my: my36_108'} -//│ | | | | | | | | | | | | => {my: my36_108'} -//│ | | | | | | | | | | | => {my: my36_108'} -//│ | | | | | | | | | | => {my: my36_108'} -//│ | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false -//│ | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | 1. FRESHEN {n: n32_33'} || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | | 1. FRESHEN n32_33' || 0 .. 1 1 false -//│ | | | | | | | | | | | | | | | | 1. FRESHEN n23_65 || 0 .. 1 0 true -//│ | | | | | | | | | | | | | | | | => n23_65 -//│ | | | | | | | | | | | | | | | => n32_109' -//│ | | | | | | | | | | | | | | => {n: n32_109'} -//│ | | | | | | | | | | | | | => {n: n32_109'} -//│ | | | | | | | | | | | | => {n: n32_109'} -//│ | | | | | | | | | | | => {n: n32_109'} -//│ | | | | | | | | | | => {n: n32_109'} -//│ | | | | | | | | | => this24_107' -//│ | | | | | | | | => this24_107' -//│ | | | | | | | => me30_106''# -//│ | | | | | | => ‹∀ 1. me30_106''#› -//│ | | | | | | 1. FRESHEN ‹∀ 1. my31''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | | 1. FRESHEN n32'' || 0 .. 1 2 false -//│ | | | | | | | | | 1. FRESHEN n32_33' || 0 .. 1 1 false -//│ | | | | | | | | | => n32_109' -//│ | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false -//│ | | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false -//│ | | | | | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false -//│ | | | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | | | | | | | => my31_111'' -//│ | | | | | | | | | | | | => my31_111'' -//│ | | | | | | | | | | | => mine34_113''# -//│ | | | | | | | | | | => mine34_113''# -//│ | | | | | | | | | => mine34_113''# -//│ | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | | | | => my31_111'' -//│ | | | | | | | | | => my31_111'' -//│ | | | | | | | | => n32_112'' -//│ | | | | | | | => my31_111''# -//│ | | | | | | => ‹∀ 1. my31_111''#› -//│ | | | | | | 1. FRESHEN ‹∀ 1. mine34''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false -//│ | | | | | | | => mine34_113''# -//│ | | | | | | => ‹∀ 1. mine34_113''#› -//│ | | | | | | 1. FRESHEN ‹∀ 1. oops35''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false -//│ | | | | | | | | 1. FRESHEN my36'' || 0 .. 1 2 false -//│ | | | | | | | | | 1. FRESHEN my36_37' || 0 .. 1 1 false -//│ | | | | | | | | | => my36_108' -//│ | | | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false -//│ | | | | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false -//│ | | | | | | | | | | => oops35_116'' -//│ | | | | | | | | | => oops35_116'' -//│ | | | | | | | | => my36_117'' -//│ | | | | | | | => oops35_116''# -//│ | | | | | | => ‹∀ 1. oops35_116''#› -//│ | | | | | | 1. FRESHEN n23' || 0 .. 1024 1 false -//│ | | | | | | => n23_118' -//│ | | | | | | 1. FRESHEN n23' || 0 .. 1024 1 false -//│ | | | | | | => n23_118' -//│ | | | | | | 1. FRESHEN ‹∀ 1. mine34''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN mine34''# || 0 .. 1 2 false -//│ | | | | | | | => mine34_113''# -//│ | | | | | | => ‹∀ 1. mine34_113''#› -//│ | | | | | | 1. FRESHEN ‹∀ 1. oops35''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN oops35''# || 0 .. 1 2 false -//│ | | | | | | | => oops35_116''# -//│ | | | | | | => ‹∀ 1. oops35_116''#› -//│ | | | | | | 1. FRESHEN ‹∀ 1. my31''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN my31''# || 0 .. 1 2 false -//│ | | | | | | | => my31_111''# -//│ | | | | | | => ‹∀ 1. my31_111''#› -//│ | | | | | | 1. FRESHEN ‹∀ 1. me30''#› || 0 .. 1024 1 false -//│ | | | | | | | 1. FRESHEN me30''# || 0 .. 1 2 false -//│ | | | | | | | => me30_106''# -//│ | | | | | | => ‹∀ 1. me30_106''#› -//│ | | | | | | 1. C n23_118' Base1<> <: {getBase1: getBase1237} & {base: base230} & b221'# -//│ base230 :> Int -//│ getBase1237 :> ‹∀ 1. getBase1203''#› -//│ | | 0. C b221'# >,0,0) -//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1203''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. getBase1203''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. me204''#› || 0 .. 1024 1 false -//│ | | | | | | | 0. FRESHEN me204''# || 0 .. 1 2 false -//│ | | | | | | | | 0. FRESHEN this198' || 0 .. 1 1 false -//│ | | | | | | | | | 0. FRESHEN this198' || 0 .. 1 1 false -//│ | | | | | | | | | | 0. FRESHEN Base1<> || 0 .. 1 0 true -//│ | | | | | | | | | | => Base1<> -//│ | | | | | | | | | => this198_249 -//│ | | | | | | | | => this198_249 -//│ | | | | | | | => me204_248''# -//│ | | | | | | => ‹∀ 1. me204_248''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. foo205''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. foo205''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. getBase1203''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. getBase1203''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. me204''#› || 0 .. 1024 1 false -//│ | | | | | | | 0. FRESHEN me204''# || 0 .. 1 2 false -//│ | | | | | | | => me204_248''# -//│ | | | | | | => ‹∀ 1. me204_248''#› -//│ | | | | | | 0. FRESHEN ‹∀ 1. foo205''#› || 0 .. 1024 0 true -//│ | | | | | | => ‹∀ 1. foo205''#› -//│ | | | | | | 0. C ‹∀ 1. me204_248''#› ‹∀ 1. me204_248''#› -//│ me204_248''# := this198_249 -//│ this198_249 :> Base1<> //│ Typed: Base1 :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.310: b.getBaseTypo +//│ ║ l.140: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -318,6 +148,25 @@ b : Base1 //│ Typed: Base1 +:e // TODO +class Rec(n) { + fun go = Rec(n + 1) +} +//│ ╔══[ERROR] Cyclic definition +//│ ║ l.152: class Rec(n) { +//│ ║ ^^^^^^^^ +//│ ║ l.153: fun go = Rec(n + 1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.154: } +//│ ╙── ^ +//│ class Rec +//│ fun go: ‹∀ 1. go266''#› where +//│ | go266''# := α269'' +//│ | α269'' :> error<> <: go266''# +//│ [pretty-printed] go: error + + + // TODO treat `a: int` as a signature class Annots(base: 0 | 1) { @@ -325,20 +174,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.324: a: int +//│ ║ l.173: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.323: class Annots(base: 0 | 1) { +//│ ║ l.172: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.324: a: int +//│ ║ l.173: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.324: a: int +//│ ║ l.173: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a265''#› where -//│ | a265''# := ((0 | 1),) +//│ fun a: ‹∀ 1. a276''#› where +//│ | a276''# := ((0 | 1),) //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 81161f3092..eeacfbbf19 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -6,35 +6,23 @@ class Some(value: A) { fun get = value fun toArray = [value] - fun mapBad(f) = Some(f(value)) // Notice the extruded type - fun map(f : A => 'b) = Some(f(value)) // FIXME still problematic + // fun mapBad(f) = Some(f(value)) // TODO + // fun map(f : A => 'b) = Some(f(value)) // TODO } //│ class Some -//│ fun get: ‹∀ 1. get30''#› where -//│ | get30''# := A23' +//│ fun get: ‹∀ 1. get28''#› where +//│ | get28''# := A23' //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray31''#› where -//│ | toArray31''# := (A23',) +//│ fun toArray: ‹∀ 1. toArray29''#› where +//│ | toArray29''# := (A23',) //│ [pretty-printed] toArray: (nothing,) -//│ fun mapBad: ‹∀ 1. mapBad32''#› where -//│ | mapBad32''# := (α33'' -> α35'') -//│ | α33'' <: ((A23',) -> α34'') -//│ | α34'' <: α34_36 -//│ | α35'' :> α35_37 -//│ [pretty-printed] mapBad: (nothing -> anything) -> nothing -//│ fun map: ‹∀ 1. map38''#› where -//│ | map38''# := ((A23' -> 'b39'') -> α41'') -//│ | 'b39'' <: α40'' -//│ | α40'' <: α40_42 -//│ | α41'' :> α41_43 -//│ [pretty-printed] map: (nothing -> anything) -> nothing let s = Some(1) -//│ fun s: ‹∀ 0. s63'#› where -//│ | s63'# := α79' -//│ | A23_66' :> 1 -//│ | α79' :> (Some<> & {Some#A: mut A23_66'..A23_66'}) <: s63'# +//│ fun s: ‹∀ 0. s35'#› where +//│ | s35'# := α41' +//│ | A23_38' :> 1 +//│ | α41' :> (Some<> & {Some#A: mut A23_38'..A23_38'}) <: s35'# //│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 @@ -50,38 +38,31 @@ s.toArray //│ Typed: (1,) -// FIXME +// TODO -s.mapBad -//│ Typed: (1 -> anything) -> nothing +// s.mapBad -s.mapBad(succ) -//│ Typed: nothing +// s.mapBad(succ) -s.map -//│ Typed: (1 -> anything) -> nothing +// s.map -s.map(succ) -//│ Typed: nothing +// s.map(succ) module None { fun get = error fun toArray = [] - fun mapBad(f) = None + // fun mapBad(f) = None // TODO } //│ class None -//│ fun get: ‹∀ 1. get248''#› where -//│ | get248''# := ⊥ +//│ fun get: ‹∀ 1. get81''#› where +//│ | get81''# := ⊥ //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray249''#› where -//│ | toArray249''# := () +//│ fun toArray: ‹∀ 1. toArray82''#› where +//│ | toArray82''# := () //│ [pretty-printed] toArray: () -//│ fun mapBad: ‹∀ 1. mapBad250''#› where -//│ | mapBad250''# := (α251'' -> None242) -//│ [pretty-printed] mapBad: anything -> nothing None.toArray @@ -95,10 +76,10 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ fun opt: ‹∀ 0. opt265'#› where -//│ | opt265'# := (α282' | None<>) -//│ | A23_269' :> 123 -//│ | α282' :> (Some<> & {Some#A: mut A23_269'..A23_269'}) +//│ fun opt: ‹∀ 0. opt92'#› where +//│ | opt92'# := (α99' | None<>) +//│ | A23_96' :> 123 +//│ | α99' :> (Some<> & {Some#A: mut A23_96'..A23_96'}) //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> 123 @@ -106,14 +87,12 @@ let opt = if true then Some(123) else None opt.toArray //│ Typed: Array[123] -opt.mapBad(succ) -//│ Typed: nothing -opt.map(succ) -//│ ╔══[ERROR] namespace `None` does not contain member `map` -//│ ║ l.112: opt.map(succ) -//│ ╙── ^^^^ -//│ Typed: error +// TODO + +// opt.mapBad(succ) + +// opt.map(succ) @@ -127,22 +106,22 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ‹∀ 0. map413'#› where -//│ | map413'# := ((α414', α415',) -> (None<> | α436')) -//│ | α414' <: ((None<> & α416') | ((Some<> & α417') & ~(None<>))) -//│ | α415' <: ((‹∀ 1. value418''›,) -> α435') -//│ | α417' <: {value: value418_419'} -//│ | value418'' :> value418_419' -//│ | α435' <: A23_422' -//│ | α436' :> (Some<> & {Some#A: mut A23_422'..A23_422'}) +//│ fun map: ‹∀ 0. map145'#› where +//│ | map145'# := ((α146', α147',) -> (None<> | α158')) +//│ | α146' <: ((None<> & α148') | ((Some<> & α149') & ~(None<>))) +//│ | α147' <: ((‹∀ 1. value150''›,) -> α157') +//│ | α149' <: {value: value150_151'} +//│ | value150'' :> value150_151' +//│ | α157' <: A23_154' +//│ | α158' :> (Some<> & {Some#A: mut A23_154'..A23_154'}) //│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) let mo = map(opt, succ) -//│ fun mo: ‹∀ 0. mo452'#› where -//│ | A23_422' :> int -//│ | α436' :> (Some<> & {Some#A: mut A23_422'..A23_422'}) -//│ | mo452'# := α453' -//│ | α453' :> (None<> | α436') <: mo452'# +//│ fun mo: ‹∀ 0. mo174'#› where +//│ | A23_154' :> int +//│ | α158' :> (Some<> & {Some#A: mut A23_154'..A23_154'}) +//│ | mo174'# := α175' +//│ | α175' :> (None<> | α158') <: mo174'# //│ [pretty-printed] mo: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> int diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index da422b5816..b69bfde1a1 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -42,27 +42,35 @@ Test0_1.a //│ Typed: 123 +:e // TODO module Test1_1 { fun a = Test1_2.b } module Test1_2 { fun b = Test1_1.a } +//│ ╔══[ERROR] Cyclic definition +//│ ║ l.46: module Test1_1 { +//│ ║ ^^^^^^^^^ +//│ ║ l.47: fun a = Test1_2.b +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.48: } +//│ ╙── ^ //│ class Test1_1 //│ fun a: ‹∀ 1. a66''#› where -//│ | a66''# := b73'' +//│ | a66''# := b72'' //│ | b70''# := a71'' -//│ | a71'' :> a71_72 <: b70''# -//│ | b73'' :> ‹∀ 1. b70''#› <: a66''# -//│ [pretty-printed] a: nothing +//│ | a71'' :> error<> <: b70''# +//│ | b72'' :> ‹∀ 1. b70''#› <: a66''# +//│ [pretty-printed] a: error //│ class Test1_2 //│ fun b: ‹∀ 1. b70''#› where //│ | b70''# := a71'' -//│ | a71'' :> a71_72 <: b70''# -//│ [pretty-printed] b: nothing +//│ | a71'' :> error<> <: b70''# +//│ [pretty-printed] b: error Test1_1.a -//│ Typed: nothing +//│ Typed: error // TODO check TV hygiene @@ -77,36 +85,62 @@ module Test2_2 { fun c = Test2_1.a fun e = Test2_1.n } +//│ ╔══[ERROR] Cyclic definition +//│ ║ l.77: module Test2_1 { +//│ ║ ^^^^^^^^^ +//│ ║ l.78: fun t2 = Test2_2 +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.79: fun a = Test2_2.b +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.80: fun d = Test2_2.e +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.81: fun n = 456 +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.82: } +//│ ╙── ^ +//│ ╔══[ERROR] Cyclic definition +//│ ║ l.77: module Test2_1 { +//│ ║ ^^^^^^^^^ +//│ ║ l.78: fun t2 = Test2_2 +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.79: fun a = Test2_2.b +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.80: fun d = Test2_2.e +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.81: fun n = 456 +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.82: } +//│ ╙── ^ //│ class Test2_1 -//│ fun t2: ‹∀ 1. t299''#› where -//│ | t299''# := Test2_2<> +//│ fun t2: ‹∀ 1. t295''#› where +//│ | t295''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a112''#› where -//│ | b105''# := 123 -//│ | a112''# := b113'' -//│ | b113'' :> ‹∀ 1. b105''#› <: a112''# +//│ fun a: ‹∀ 1. a106''#› where +//│ | b101''# := 123 +//│ | a106''# := b107'' +//│ | b107'' :> ‹∀ 1. b101''#› <: a106''# //│ [pretty-printed] a: 123 -//│ fun d: ‹∀ 1. d117''#› where -//│ | e109''# := n110'' -//│ | n110'' :> n110_111 <: e109''# -//│ | d117''# := e118'' -//│ | e118'' :> ‹∀ 1. e109''#› <: d117''# -//│ [pretty-printed] d: nothing -//│ fun n: ‹∀ 1. n122''#› where -//│ | n122''# := 456 +//│ fun d: ‹∀ 1. d111''#› where +//│ | e104''# := n105'' +//│ | n105'' :> error<> <: e104''# +//│ | d111''# := e112'' +//│ | e112'' :> ‹∀ 1. e104''#› <: d111''# +//│ [pretty-printed] d: error +//│ fun n: ‹∀ 1. n116''#› where +//│ | n116''# := 456 //│ [pretty-printed] n: 456 //│ class Test2_2 -//│ fun b: ‹∀ 1. b105''#› where -//│ | b105''# := 123 +//│ fun b: ‹∀ 1. b101''#› where +//│ | b101''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c106''#› where -//│ | c106''# := a107'' -//│ | a107'' :> a107_108 <: c106''# -//│ [pretty-printed] c: nothing -//│ fun e: ‹∀ 1. e109''#› where -//│ | e109''# := n110'' -//│ | n110'' :> n110_111 <: e109''# -//│ [pretty-printed] e: nothing +//│ fun c: ‹∀ 1. c102''#› where +//│ | c102''# := a103'' +//│ | a103'' :> error<> <: c102''# +//│ [pretty-printed] c: error +//│ fun e: ‹∀ 1. e104''#› where +//│ | e104''# := n105'' +//│ | n105'' :> error<> <: e104''# +//│ [pretty-printed] e: error Test2_1.t2.b //│ Typed: 123 @@ -116,7 +150,7 @@ Test2_1.a // FIXME Test2_1.d -//│ Typed: nothing +//│ Typed: error Test2_1.n //│ Typed: 456 From cf3c0e6aa88f03a2db469e9a6f107ede5a2a6b95 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 02:43:37 +0800 Subject: [PATCH 027/498] WIP add ECOOP example --- shared/src/test/diff/nu/ECOOP23.mls | 161 ++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 shared/src/test/diff/nu/ECOOP23.mls diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls new file mode 100644 index 0000000000..43b3be88c8 --- /dev/null +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -0,0 +1,161 @@ +:NewParser +:NewDefs +:NoJS + + +class Add(lhs: E, rhs: E) +class Lit(n: int) +//│ class Add +//│ class Lit + +let add11 = Add(Lit(1), Lit(2)) +//│ fun add11: ‹∀ 0. add1130'#› where +//│ | add1130'# := α34' +//│ | E24_31' :> Lit<> +//│ | α34' :> (Add<> & {Add#E: mut E24_31'..E24_31'}) <: add1130'# +//│ [pretty-printed] add11: Add & {Add#E = 'E} +//│ | where +//│ | 'E :> Lit + + +mixin EvalBase { + fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then this.eval(l) + this.eval(r) +} +//│ mixin EvalBase +//│ this: this41' +//│ | this41' <: {eval: eval62_63'} & {eval: eval55_56'} +//│ | eval55_56' <: ((‹∀ 2. lhs51_58'''›,) -> α57_60') +//│ | lhs51_58''' :> lhs51_59' +//│ | α57_60' <: int +//│ | eval62_63' <: ((‹∀ 2. rhs53_65'''›,) -> α64_67') +//│ | rhs53_65''' :> rhs53_66' +//│ | α64_67' <: int +//│ super: super42' +//│ fun eval: ‹∀ 1. eval44''#› where +//│ | eval44''# := (α45'' -> (Int | α68'')) +//│ | α45'' <: ((Lit<> & α46'') | ((Add<> & α50'') & ~(Lit<>))) +//│ | α46'' <: {n: n47_48''} +//│ | n47_48'' <: int +//│ | α50'' <: {rhs: rhs53_54''} & {lhs: lhs51_52''} +//│ | lhs51_52'' <: lhs51_59' +//│ | rhs53_54'' <: rhs53_66' +//│ | α68'' :> int +//│ [pretty-printed] eval: (Add & {lhs: anything, rhs: anything} | Lit & {n: int}) -> int + + +module TestLang: EvalBase +//│ class TestLang + +TestLang.eval +//│ Typed: 'rhs -> int +//│ where +//│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} + +TestLang.eval(add11) +//│ Typed: int + + +class Neg(expr: A) +//│ class Neg + +let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ fun add2negadd11: ‹∀ 0. add2negadd11208'#› where +//│ | E24_31' :> E24_188 | Lit<> <: E24_189 +//│ | rhs53_171 :> Lit<> <: ((Lit<> & α46_172) | ((Add<> & α50_174) & ~(Lit<>))) +//│ | α46_172 :> Lit<> <: {n: n47_173} +//│ | n47_173 :> Int <: int +//│ | α50_174 <: {rhs: rhs53_175} & {lhs: lhs51_176} +//│ | rhs53_175 <: rhs53_171 +//│ | lhs51_176 <: lhs51_177 +//│ | lhs51_177 :> Lit<> <: ((Lit<> & α46_178) | ((Add<> & α50_180) & ~(Lit<>))) +//│ | α46_178 :> Lit<> <: {n: n47_179} +//│ | n47_179 :> Int <: int +//│ | α50_180 <: {rhs: rhs53_181} & {lhs: lhs51_182} +//│ | rhs53_181 <: rhs53_171 +//│ | lhs51_182 <: lhs51_177 +//│ | add1130_186' :> (Add<> & {Add#E: mut E24_188..E24_189}) | α34_187 <: add1130_191 & α34_190 +//│ | α34_187 :> (Add<> & {Add#E: mut E24_188..E24_189}) | (Add<> & {Add#E: mut E24_188..E24_189}) <: α45_193 & α34_190 +//│ | E24_188 <: lhs51_198 & rhs53_197 +//│ | E24_189 :> E24_188 | Lit<> <: lhs51_198 & rhs53_197 +//│ | α34_190 :> (Add<> & {Add#E: mut E24_188..E24_189}) <: α34_187 & add1130_186' +//│ | add1130_191 :> (Add<> & {Add#E: mut E24_188..E24_189}) | α34_187 <: α45_193 +//│ | α45_193 :> (Add<> & {Add#E: mut E24_188..E24_189}) <: ((Lit<> & α46_194) | ((Add<> & α50_196) & ~(Lit<>))) +//│ | α46_194 <: {n: n47_195} +//│ | n47_195 <: int +//│ | α50_196 :> (Add<> & {Add#E: mut E24_188..E24_189}) <: {rhs: rhs53_197} & {lhs: lhs51_198} +//│ | rhs53_197 :> Lit<> <: rhs53_171 +//│ | lhs51_198 :> Lit<> <: lhs51_177 +//│ | add2negadd11208'# := α213' +//│ | E24_209' :> (Neg<> & {Neg#A: mut A204_211'..A204_211'}) | Lit<> +//│ | A204_211' :> (Add<> & {Add#E: mut E24_31'..E24_31'}) | α34_190 +//│ | α213' :> (Add<> & {Add#E: mut E24_209'..E24_209'}) <: add2negadd11208'# +//│ [pretty-printed] add2negadd11: Add & {Add#E = 'E} +//│ | where +//│ | 'E :> Lit | Neg & {Neg#A = 'A} +//│ | 'A :> Add & {Add#E :> 'lhs & 'E0 <: Lit | 'E0} +//│ | 'lhs <: Add & {lhs: 'lhs, rhs: 'lhs} | Lit & {n: int} + + +mixin EvalNeg { + fun eval(e) = + if e is Neg(d) then 0 - this.eval(d) + else super.eval(e) +} +//│ mixin EvalNeg +//│ this: this249' +//│ | this249' <: {eval: eval258_259'} +//│ | eval258_259' <: ((‹∀ 2. expr255_261'''›,) -> α260_263') +//│ | expr255_261''' :> expr255_262' +//│ | α260_263' <: int +//│ super: super250' +//│ | super250' <: {eval: eval266_267'} +//│ | eval266_267' <: ((α265_269',) -> α268_270') +//│ fun eval: ‹∀ 1. eval252''#› where +//│ | eval252''# := (α253'' -> (α264'' | α268'')) +//│ | α253'' <: ((Neg<> & α254'') | (α265'' & ~(Neg<>))) +//│ | α254'' <: {expr: expr255_256''} +//│ | expr255_256'' <: expr255_262' +//│ | α264'' :> int +//│ | α265'' <: α265_269' +//│ | α268'' :> α268_270' +//│ [pretty-printed] eval: (Neg & {expr: anything} | ~Neg) -> int + + +module TestLang: EvalBase, EvalNeg +//│ class TestLang + +TestLang.eval +//│ Typed: 'expr -> int +//│ where +//│ 'expr <: Neg & {expr: 'expr} | (Add & {lhs: 'expr, rhs: 'expr} | Lit & {n: int}) & ~Neg + + +TestLang.eval(add11) +//│ Typed: int + +TestLang.eval(Neg(add11)) +//│ Typed: int + +TestLang.eval(Add(Lit(2), Neg(Lit(1)))) +//│ Typed: int + +TestLang.eval(Neg(Neg(add11))) +//│ Typed: int + + +// FIXME too much polymorphism inferred? +:ex +TestLang.eval(add2negadd11) +//│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required +//│ ║ l.151: TestLang.eval(add2negadd11) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── ————————— Additional debugging info: ————————— +//│ ╟── this constraint: E24_682# <: rhs53_649 TypeVariable TypeVariable +//│ ╙── ... looks like: E24' <: rhs53_649 +//│ Typed: error | int + +// TestLang.eval(Add(Lit(2), Neg(add11))) + From 92a51ce1aded0db37a068bd40452790b615e35ea Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 02:49:10 +0800 Subject: [PATCH 028/498] WIP fix cycle --- .../main/scala/mlscript/ConstraintSolver.scala | 3 ++- shared/src/test/diff/nu/ECOOP23.mls | 16 +++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 54f8403746..201e279405 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -428,7 +428,8 @@ class ConstraintSolver extends NormalForms { self: Typer => implicit val shadows: Shadows = Shadows.empty // freshened ++= td.tparams.map(tp => tp._2 -> TopType) td.tparams.foreach { case (tn, _tv) => - val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) + // val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) + val tv = freshVar(_tv.prov, N, _tv.nameHint) // TODO safe not to set original?! println(s"Assigning $tv") assert(tv.assignedTo.isEmpty) tv.assignedTo = S(rfnt.get(Var(td.nme.name + "#" + tn.name)) match { diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 43b3be88c8..30a8d66746 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -146,16 +146,10 @@ TestLang.eval(Neg(Neg(add11))) //│ Typed: int -// FIXME too much polymorphism inferred? -:ex TestLang.eval(add2negadd11) -//│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.151: TestLang.eval(add2negadd11) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── ————————— Additional debugging info: ————————— -//│ ╟── this constraint: E24_682# <: rhs53_649 TypeVariable TypeVariable -//│ ╙── ... looks like: E24' <: rhs53_649 -//│ Typed: error | int - -// TestLang.eval(Add(Lit(2), Neg(add11))) +//│ Typed: int + +TestLang.eval(Add(Lit(2), Neg(add11))) +//│ Typed: int + From 59911f8a35f274ca949700064d322b60d454a565 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 09:02:42 +0800 Subject: [PATCH 029/498] WIP New tests --- shared/src/test/diff/nu/BasicMixins.mls | 156 +++++++++++--------- shared/src/test/diff/nu/ParamOverriding.mls | 32 ++++ 2 files changed, 122 insertions(+), 66 deletions(-) create mode 100644 shared/src/test/diff/nu/ParamOverriding.mls diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 44510e5eaf..f0b5b8d0c2 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -18,24 +18,43 @@ mixin BaseTest { mixin BaseInc { fun test = super.base + 1 + fun test2 = this.base } //│ mixin BaseInc //│ this: this33' +//│ | this33' <: {base: base43_44'} //│ super: super34' -//│ | super34' <: {base: base37_38'} -//│ | base37_38' <: int -//│ fun test: ‹∀ 1. test36''#› where -//│ | test36''# := α40'' -//│ | α40'' :> int <: test36''# +//│ | super34' <: {base: base38_39'} +//│ | base38_39' <: int +//│ fun test: ‹∀ 1. test37''#› where +//│ | test37''# := α41'' +//│ | α41'' :> int <: test37''# //│ [pretty-printed] test: int +//│ fun test2: ‹∀ 1. test242''#› where +//│ | test242''# := base43'' +//│ | base43'' :> base43_44' <: test242''# +//│ [pretty-printed] test2: nothing // :d -class Base1(base: int): BaseTest +class Base1(base: int): BaseTest, BaseInc { + fun test3 = [base, this.base] +} //│ class Base1 +//│ fun test3: ‹∀ 1. test368''#› where +//│ | test368''# := (Int, base69'',) +//│ | base69'' :> base69_70' +//│ | base69_70' :> Int +//│ [pretty-printed] test3: (int, int,) Base1(1).test //│ Typed: int +Base1(1).test2 +//│ Typed: int + +Base1(1).test3 +//│ Typed: (int, int,) + class Base1(base): BaseTest //│ class Base1 @@ -51,10 +70,10 @@ Base1(1).test :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.52: class Base1(x): BaseTest +//│ ║ l.71: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.52: class Base1(x): BaseTest +//│ ║ l.71: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -73,17 +92,22 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo -//│ this: this110' -//│ super: super111' -//│ | super111' <: {misc: misc119_120'} & {base: base115_116'} -//│ | base115_116' <: int -//│ fun test: ‹∀ 1. test113''#› where -//│ | test113''# := (α114'' -> (α118'', α114'', misc119'',)) -//│ | α114'' <: int -//│ | α118'' :> int -//│ | misc119'' :> misc119_120' +//│ this: this186' +//│ super: super187' +//│ | super187' <: {misc: misc195_196'} & {base: base191_192'} +//│ | base191_192' <: int +//│ fun test: ‹∀ 1. test189''#› where +//│ | test189''# := (α190'' -> (α194'', α190'', misc195'',)) +//│ | α190'' <: int +//│ | α194'' :> int +//│ | misc195'' :> misc195_196' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) +module Base1(base: int, misc: string): Foo +//│ class Base1 + +Base1.test +//│ Typed: (int & 'a) -> (int, 'a, string,) mixin WrapBase { @@ -93,13 +117,13 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase -//│ this: this129' -//│ super: super130' -//│ fun wrapA: ‹∀ 1. wrapA133''#› where -//│ | wrapA133''# := (Int -> Int) +//│ this: this231' +//│ super: super232' +//│ fun wrapA: ‹∀ 1. wrapA235''#› where +//│ | wrapA235''# := (Int -> Int) //│ [pretty-printed] wrapA: int -> int -//│ fun wrap: ‹∀ 1. wrap134''#› where -//│ | wrap134''# := (α135'' -> α135'') +//│ fun wrap: ‹∀ 1. wrap236''#› where +//│ | wrap236''# := (α237'' -> α237'') //│ [pretty-printed] wrap: 'a -> 'a // :d @@ -108,20 +132,20 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ mixin Wrap -//│ this: this142' -//│ super: super143' -//│ | super143' <: {wrap: wrap155_156'} & {wrapA: wrapA148_149'} -//│ | wrapA148_149' <: ((α147_151',) -> α150_152') -//│ | wrap155_156' <: ((α154_158',) -> α157_159') -//│ fun wrapA: ‹∀ 1. wrapA146''#› where -//│ | wrapA146''# := (α147'' -> (α150'',)) -//│ | α147'' <: α147_151' -//│ | α150'' :> α150_152' +//│ this: this244' +//│ super: super245' +//│ | super245' <: {wrap: wrap257_258'} & {wrapA: wrapA250_251'} +//│ | wrapA250_251' <: ((α249_253',) -> α252_254') +//│ | wrap257_258' <: ((α256_260',) -> α259_261') +//│ fun wrapA: ‹∀ 1. wrapA248''#› where +//│ | wrapA248''# := (α249'' -> (α252'',)) +//│ | α249'' <: α249_253' +//│ | α252'' :> α252_254' //│ [pretty-printed] wrapA: anything -> (nothing,) -//│ fun wrap: ‹∀ 1. wrap153''#› where -//│ | wrap153''# := (α154'' -> (α157'',)) -//│ | α154'' <: α154_158' -//│ | α157'' :> α157_159' +//│ fun wrap: ‹∀ 1. wrap255''#› where +//│ | wrap255''# := (α256'' -> (α259'',)) +//│ | α256'' <: α256_260' +//│ | α259'' :> α259_261' //│ [pretty-printed] wrap: anything -> (nothing,) @@ -158,16 +182,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.159: WrapBase1.wrapA("ok") +//│ ║ l.183: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.159: WrapBase1.wrapA("ok") +//│ ║ l.183: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.92: fun wrapA(x : int) = x : int -//│ ║ ^^^ +//│ ║ l.116: fun wrapA(x : int) = x : int +//│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.107: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.131: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ Typed: (int,) | error @@ -177,34 +201,34 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ class WrapBase2 let w = WrapBase2.wrap -//│ fun w: ‹∀ 0. w374'#› where -//│ | w374'# := wrap375' -//│ | wrap375' :> ‹∀ 1. wrap153_389''#› <: w374'# -//│ | wrap153_389''# := (α154_390'' -> (α157_398'',)) -//│ | α154_390'' <: α154_391' -//│ | α154_391' <: α154_392' -//│ | α154_392' <: α154_393' -//│ | α154_393' <: α154_394' -//│ | α154_394' <: α154_395' -//│ | α154_395' <: α135_396' -//│ | α135_396' <: α157_397' -//│ | α157_398'' :> α157_399' -//│ | α157_399' :> ‹∀ 2. (α157_400''',)› -//│ | α157_400''' :> α157_401' -//│ | α157_401' :> ‹∀ 2. (α157_402''',)› -//│ | α157_402''' :> α157_397' +//│ fun w: ‹∀ 0. w476'#› where +//│ | w476'# := wrap477' +//│ | wrap477' :> ‹∀ 1. wrap255_491''#› <: w476'# +//│ | wrap255_491''# := (α256_492'' -> (α259_500'',)) +//│ | α256_492'' <: α256_493' +//│ | α256_493' <: α256_494' +//│ | α256_494' <: α256_495' +//│ | α256_495' <: α256_496' +//│ | α256_496' <: α256_497' +//│ | α256_497' <: α237_498' +//│ | α237_498' <: α259_499' +//│ | α259_500'' :> α259_501' +//│ | α259_501' :> ‹∀ 2. (α259_502''',)› +//│ | α259_502''' :> α259_503' +//│ | α259_503' :> ‹∀ 2. (α259_504''',)› +//│ | α259_504''' :> α259_499' //│ [pretty-printed] w: 'a -> ((('a,),),) let wd = w(1) -//│ fun wd: ‹∀ 0. wd422'#› where -//│ | α157_397' :> 1 -//│ | α157_399' :> ‹∀ 2. (α157_400''',)› -//│ | α157_400''' :> α157_401' -//│ | α157_401' :> ‹∀ 2. (α157_402''',)› -//│ | α157_402''' :> α157_397' -//│ | wd422'# := α423' -//│ | α423' :> ‹∀ 2. (α157_424''',)› <: wd422'# -//│ | α157_424''' :> α157_399' +//│ fun wd: ‹∀ 0. wd524'#› where +//│ | α259_499' :> 1 +//│ | α259_501' :> ‹∀ 2. (α259_502''',)› +//│ | α259_502''' :> α259_503' +//│ | α259_503' :> ‹∀ 2. (α259_504''',)› +//│ | α259_504''' :> α259_499' +//│ | wd524'# := α525' +//│ | α525' :> ‹∀ 2. (α259_526''',)› <: wd524'# +//│ | α259_526''' :> α259_501' //│ [pretty-printed] wd: (((1,),),) wd._1._1._1 + 1 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls new file mode 100644 index 0000000000..92a1b00e88 --- /dev/null +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -0,0 +1,32 @@ +:NewParser +:NewDefs +:NoJS + + +mixin Over { + fun p = "hi" +} +//│ mixin Over +//│ this: this23' +//│ super: super24' +//│ fun p: ‹∀ 1. p26''#› where +//│ | p26''# := "hi" +//│ [pretty-printed] p: "hi" + + +class Base1(p: int): Over { + fun test = [p, this.p] +} +//│ class Base1 +//│ fun test: ‹∀ 1. test35''#› where +//│ | test35''# := (Int, p36'',) +//│ | p36'' :> p36_37' +//│ | p36_37' :> Int +//│ [pretty-printed] test: (int, int,) + + +// FIXME +Base1(123).test +//│ Typed: (int, int,) + + From 16f3ee6e956c9ff95182142de1a23f341cb452c8 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 10:11:17 +0800 Subject: [PATCH 030/498] WIP Start fixing param overriding --- .../main/scala/mlscript/TyperDatatypes.scala | 8 ++++--- shared/src/test/diff/nu/ParamOverriding.mls | 23 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 83673f0b2b..7be9b29640 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -140,7 +140,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => TypeProvenance(decl.toLoc, decl.describe) val finalType = freshVar(noProv/*TODO*/, N, S("this")) // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { - def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { + def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]): Ls[NuMember] = parents match { // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { // case R(p) :: ps => ??? // case L(p) :: ps => @@ -206,7 +206,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) val paramMems = typedParams.map(f => NuParam(f._1, f._2)) - val baseMems = inherit(td.parents, baseType, Nil) + // val baseMems = inherit(td.parents, baseType, Nil) + val baseMems = inherit(td.parents, baseType, paramMems) // ctx += thisTV @@ -227,7 +228,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // )(provTODO) // constrain(thisTy, thisTV) - val mems = baseMems ++ paramMems ++ clsMems + // val mems = baseMems ++ paramMems ++ clsMems + val mems = baseMems ++ clsMems TypedNuCls(outerCtx.lvl, td, ttu, tparams, typedParams, mems.map(d => d.name -> d).toMap) } diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 92a1b00e88..02c5aea55e 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -16,17 +16,26 @@ mixin Over { class Base1(p: int): Over { fun test = [p, this.p] + fun test2 = super.p } //│ class Base1 -//│ fun test: ‹∀ 1. test35''#› where -//│ | test35''# := (Int, p36'',) -//│ | p36'' :> p36_37' -//│ | p36_37' :> Int -//│ [pretty-printed] test: (int, int,) +//│ fun test: ‹∀ 1. test36''#› where +//│ | p26''# := "hi" +//│ | test36''# := (Int, p37'',) +//│ | p37'' :> p37_38' +//│ | p37_38' :> ‹∀ 1. p26''#› +//│ [pretty-printed] test: (int, "hi",) +//│ fun test2: ‹∀ 1. test239''#› where +//│ | test239''# := p40'' +//│ | p40'' :> p40_41' <: test239''# +//│ [pretty-printed] test2: nothing -// FIXME Base1(123).test -//│ Typed: (int, int,) +//│ Typed: (int, "hi",) + +// FIXME +Base1(123).test2 +//│ Typed: nothing From 2478c67a9654683b8fcb2441fe7d6c02538844df Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 17 Feb 2023 10:19:00 +0800 Subject: [PATCH 031/498] WIP Fix missing context nesting --- .../scala/mlscript/ConstraintSolver.scala | 4 ++-- .../main/scala/mlscript/TyperDatatypes.scala | 4 ++-- shared/src/test/diff/nu/ParamOverriding.mls | 19 +++++++------------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 201e279405..6fe7d2c7a6 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1161,7 +1161,7 @@ class ConstraintSolver extends NormalForms { self: Typer => : SimpleType = { def freshenImpl(ty: SimpleType, below: Level): SimpleType = - (trace(s"${lvl}. FRESHEN $ty || $above .. $below ${ty.level} ${ty.level <= above}") + // (trace(s"${lvl}. FRESHEN $ty || $above .. $below ${ty.level} ${ty.level <= above}") { // * Cannot soundly freshen if the context's level is above the current polymorphism level, // * as that would wrongly capture the newly-freshened variables. @@ -1281,7 +1281,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case o @ Overload(alts) => o.mapAlts(freshen)(freshen) }} - (r => s"=> $r")) + // (r => s"=> $r")) freshenImpl(ty, below) } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 7be9b29640..6821dc385b 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -92,7 +92,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => td.kind match { case Cls | Nms => implicit val prov: TP = noProv // TODO - ctx.nextLevel { implicit ctx => + ctx.nest.nextLevel { implicit ctx => val tparams = td.tparams.map(tp => tp -> freshVar(TypeProvenance( @@ -235,7 +235,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } case Mxn => implicit val prov: TP = noProv // TODO - ctx.nextLevel { implicit ctx => + ctx.nest.nextLevel { implicit ctx => implicit val vars: Map[Str, SimpleType] = outerVars ++ Map.empty // TODO type params val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 02c5aea55e..92e2d81316 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -16,26 +16,21 @@ mixin Over { class Base1(p: int): Over { fun test = [p, this.p] - fun test2 = super.p + // fun test2 = super.p // TODO } //│ class Base1 -//│ fun test: ‹∀ 1. test36''#› where +//│ fun test: ‹∀ 1. test35''#› where //│ | p26''# := "hi" -//│ | test36''# := (Int, p37'',) -//│ | p37'' :> p37_38' -//│ | p37_38' :> ‹∀ 1. p26''#› +//│ | test35''# := (Int, p36'',) +//│ | p36'' :> p36_37' +//│ | p36_37' :> ‹∀ 1. p26''#› //│ [pretty-printed] test: (int, "hi",) -//│ fun test2: ‹∀ 1. test239''#› where -//│ | test239''# := p40'' -//│ | p40'' :> p40_41' <: test239''# -//│ [pretty-printed] test2: nothing Base1(123).test //│ Typed: (int, "hi",) -// FIXME -Base1(123).test2 -//│ Typed: nothing +// TODO +// Base1(123).test2 From d93e0d607b3d46ab68a19d5f8f1a1a79e7ac1a11 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 21 Feb 2023 17:59:40 +0800 Subject: [PATCH 032/498] Add examples from meeting --- shared/src/test/diff/ucs/InterleavedLet.mls | 36 +++++++- shared/src/test/diff/ucs/NestedBranches.mls | 82 ++++++++++++++++--- .../src/test/diff/ucs/PlainConditionals.mls | 34 ++++++++ shared/src/test/diff/ucs/TrivialIf.mls | 27 ++++++ 4 files changed, 164 insertions(+), 15 deletions(-) diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index d9f3144dde..fc4b42fc30 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -265,12 +265,40 @@ mapPartition(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) //│ Runtime error: //│ RangeError: Maximum call stack size exceeded +// TODO this should be the desugaring of the above: +fun mapPartition(f, xs) = + if xs is + Nil then Pair(Nil(), Nil()) + Cons(x, xs) and mapPartition(f, xs) is tmp0 and res.fst is l and res.snd is r and f(x) is + Left(v) then Pair(Cons(v, l), r) + Right(v) then Pair(l, Cons(v, r)) +//│ ╔══[ERROR] Cannot find the constructor `tmp0` in the context +//│ ║ l.272: Cons(x, xs) and mapPartition(f, xs) is tmp0 and res.fst is l and res.snd is r and f(x) is +//│ ╙── ^^^^ +//│ mapPartition: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression has not been desugared + +// FIXME `b` should be bound here! fun mn(a) = if a is Some(x) and x is - Left(a) then "left-defined" - let y = x + 1 + Left(b) then "left-defined" + let y = b + 1 Right(b) then "right-defined" None then "undefined" -//│ mn: (None | Some & {value: nothing}) -> ("left-defined" | "right-defined" | "undefined") -//│ = [Function: mn] +//│ ╔══[ERROR] identifier not found: b +//│ ║ l.287: let y = b + 1 +//│ ╙── ^ +//│ mn: (None | Some & {value: Left | Right}) -> ("left-defined" | "right-defined" | "undefined") +//│ Code generation encountered an error: +//│ unresolved symbol b + +:ng +mn(Some(Left(0))) +mn(Some(Right(0))) +mn(None()) +//│ res: "left-defined" | "right-defined" | "undefined" +//│ res: "left-defined" | "right-defined" | "undefined" +//│ res: "left-defined" | "right-defined" | "undefined" + diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index e428fda032..8049015847 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -9,6 +9,7 @@ class Left(leftValue): Either class Right(rightValue): Either class List class Nil: List +let Nil = Nil() class Cons(head, tail): List class Pair(fst, snd) //│ Defined class Option @@ -37,6 +38,8 @@ class Pair(fst, snd) //│ = [Function: List1] //│ Nil: () -> Nil //│ = [Function: Nil1] +//│ Nil: Nil +//│ = Nil {} //│ Cons: ('head, 'tail,) -> (Cons with {head: 'head, tail: 'tail}) //│ = [Function: Cons1] //│ Pair: ('fst, 'snd,) -> (Pair with {fst: 'fst, snd: 'snd}) @@ -53,6 +56,16 @@ fun optionApply(x, y, f) = //│ optionApply: (None | (Some with {value: 'value}), None | (Some with {value: 'value0}), ('value, 'value0,) -> 'value1,) -> (None | (Some with {value: 'value1})) //│ = [Function: optionApply] +let zeroToThree = Cons(0, Cons(1, Cons(2, Cons(3, Nil)))) +//│ zeroToThree: Cons & {head: 0, tail: Cons & {head: 1, tail: Cons & {head: 2, tail: Cons & {head: 3, tail: Nil}}}} +//│ = Cons { +//│ head: 0, +//│ tail: Cons { head: 1, tail: Cons { head: 2, tail: [Cons] } } +//│ } + +fun f(x) = if x % 2 == 0 then Left(x) else Right(x) +//│ f: (int & 'rightValue) -> ((Left with {leftValue: 'rightValue}) | (Right with {rightValue: 'rightValue})) +//│ = [Function: f] fun mapPartition(f, xs) = if xs is @@ -62,11 +75,32 @@ fun mapPartition(f, xs) = if xs is Right(v) then Pair(l, Cons(v, r)) //│ mapPartition: ('head -> ((Left with {leftValue: 'head0}) | (Right with {rightValue: 'head1})), 'a,) -> (Pair with {fst: 'fst, snd: 'tail}) //│ where -//│ 'tail :> (Cons with {head: 'head1, tail: 'tail}) | () -> Nil -//│ 'fst :> () -> Nil | (Cons with {head: 'head0, tail: 'fst}) +//│ 'tail :> (Cons with {head: 'head1, tail: 'tail}) | Nil +//│ 'fst :> Nil | (Cons with {head: 'head0, tail: 'fst}) //│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil //│ = [Function: mapPartition] +mapPartition(x => Left(x + 1), zeroToThree) +//│ res: Pair with {fst: 'fst, snd: 'tail} +//│ where +//│ 'tail :> (Cons with {head: nothing, tail: 'tail}) | Nil +//│ 'fst :> Nil | (Cons with {head: int, tail: 'fst}) +//│ = Pair { +//│ fst: Cons { head: 1, tail: Cons { head: 2, tail: [Cons] } }, +//│ snd: Nil {} +//│ } + +mapPartition(f, zeroToThree) +//│ res: Pair with {fst: 'fst, snd: 'tail} +//│ where +//│ 'tail :> (Cons with {head: 0 | 1 | 2 | 3, tail: 'tail}) | Nil +//│ 'fst :> Nil | (Cons with {head: 0 | 1 | 2 | 3, tail: 'fst}) +//│ = Pair { +//│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, +//│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } +//│ } + + fun mapPartition(f, xs) = if xs is Nil then Pair(Nil, Nil) Cons(x, xs) and @@ -75,11 +109,22 @@ fun mapPartition(f, xs) = if xs is Right(v) then Pair(l, Cons(v, r)) //│ mapPartition: ('head -> ((Left with {leftValue: 'head0}) | (Right with {rightValue: 'head1})), 'a,) -> (Pair with {fst: 'fst, snd: 'tail}) //│ where -//│ 'tail :> (Cons with {head: 'head1, tail: 'tail}) | () -> Nil -//│ 'fst :> () -> Nil | (Cons with {head: 'head0, tail: 'fst}) +//│ 'tail :> (Cons with {head: 'head1, tail: 'tail}) | Nil +//│ 'fst :> Nil | (Cons with {head: 'head0, tail: 'fst}) //│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil //│ = [Function: mapPartition1] +mapPartition(f, zeroToThree) +//│ res: Pair with {fst: 'fst, snd: 'tail} +//│ where +//│ 'tail :> (Cons with {head: 0 | 1 | 2 | 3, tail: 'tail}) | Nil +//│ 'fst :> Nil | (Cons with {head: 0 | 1 | 2 | 3, tail: 'fst}) +//│ = Pair { +//│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, +//│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } +//│ } + + fun mapPartition(f, xs) = if xs is Nil then Pair(Nil, Nil) @@ -93,11 +138,21 @@ fun mapPartition(f, xs) = if xs is Pair(l, Cons(v, r)) //│ mapPartition: ('head -> ((Left with {leftValue: 'head0}) | (Right with {rightValue: 'head1})), 'a,) -> (Pair with {fst: 'fst, snd: 'tail}) //│ where -//│ 'tail :> (Cons with {head: 'head1, tail: 'tail}) | () -> Nil -//│ 'fst :> () -> Nil | (Cons with {head: 'head0, tail: 'fst}) +//│ 'tail :> (Cons with {head: 'head1, tail: 'tail}) | Nil +//│ 'fst :> Nil | (Cons with {head: 'head0, tail: 'fst}) //│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil //│ = [Function: mapPartition2] +mapPartition(f, zeroToThree) +//│ res: Pair with {fst: 'fst, snd: 'tail} +//│ where +//│ 'tail :> (Cons with {head: 0 | 1 | 2 | 3, tail: 'tail}) | Nil +//│ 'fst :> Nil | (Cons with {head: 0 | 1 | 2 | 3, tail: 'fst}) +//│ = Pair { +//│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, +//│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } +//│ } + // TODO make this one work (needs tuple support) fun mapPartition(f, xs) = if xs is @@ -106,12 +161,17 @@ fun mapPartition(f, xs) = if xs is Left(v) then (Cons(v, l), r) Right(v) then (l, Cons(v, r)) //│ ╔══[ERROR] The case when this is false is not handled: is (mapPartition (f, xs,),) (l, r,) -//│ ║ l.105: Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is +//│ ║ l.160: Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ mapPartition: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression has not been desugared +// TODO +mapPartition(f, zeroToThree) +//│ res: error +//│ Runtime error: +//│ ReferenceError: mapPartition3 is not defined // * Vertical alignment is not allowed! (good) @@ -125,16 +185,16 @@ fun mapPartition(f, xs) = if xs is and f(x) is Left(v) then (Cons(v, l), r) Right(v) then (l, Cons(v, r)) //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here -//│ ║ l.126: Right(v) then (l, Cons(v, r)) +//│ ║ l.186: Right(v) then (l, Cons(v, r)) //│ ╙── ^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.125: and f(x) is Left(v) then (Cons(v, l), r) +//│ ║ l.185: and f(x) is Left(v) then (Cons(v, l), r) //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.126: Right(v) then (l, Cons(v, r)) +//│ ║ l.186: Right(v) then (l, Cons(v, r)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── -//│ mapPartition: (anything, 'a,) -> ((() -> Nil, () -> Nil,) | error) +//│ mapPartition: (anything, 'a,) -> ((Nil, Nil,) | error) //│ where //│ 'a <: Cons & {tail: 'a} | Nil //│ Code generation encountered an error: diff --git a/shared/src/test/diff/ucs/PlainConditionals.mls b/shared/src/test/diff/ucs/PlainConditionals.mls index d45751920e..262a45bc2e 100644 --- a/shared/src/test/diff/ucs/PlainConditionals.mls +++ b/shared/src/test/diff/ucs/PlainConditionals.mls @@ -8,10 +8,18 @@ class Pair(fst, snd) +Pair(0, 1) is Pair +//│ res: bool +//│ = true + Pair(0, 1) is Pair(a, b) //│ res: bool //│ = true +Pair(0, 1) is Pair(0, _) +//│ res: bool +//│ = true + if Pair(0, 1) is Pair(a, b) then true else false //│ res: bool //│ = true @@ -40,4 +48,30 @@ fun foo(x) = if x is Pair(a, b) then a > b else false //│ = [Function: foo2] +// TODO proper error +fun foo(x) = x is + Pair + Int +//│ /!!!\ Uncaught error: java.lang.Exception: illegal pattern: Blk(...) + +// TODO proper error +fun foo(x) = x is + Pair(a, b) and a > b + Int +//│ /!!!\ Uncaught error: java.lang.Exception: illegal pattern: Blk(...) + +// TODO support `|` +fun foo(x) = x is Pair(a, b) | Int +fun foo(x) = x is (Pair(a, b) and a > b) | Int +//│ ╔══[ERROR] Cannot find operator `|` in the context +//│ ║ l.64: fun foo(x) = x is Pair(a, b) | Int +//│ ╙── ^ +//│ foo: anything -> error +//│ ╔══[ERROR] Cannot find operator `|` in the context +//│ ║ l.65: fun foo(x) = x is (Pair(a, b) and a > b) | Int +//│ ╙── ^ +//│ foo: anything -> error +//│ Code generation encountered an error: +//│ if expression has not been desugared + diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index b2a30947bc..7d01d545ef 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -56,3 +56,30 @@ fun f(x, y) = //│ ║ l.54: else if x == y + 7 then 0 //│ ╙── ^^^^^^^^^^ //│ f: (number, int,) -> (0 | error) + + + +// FIXME +if 42 is n then n + 1 +//│ ╔══[ERROR] Cannot find the constructor `n` in the context +//│ ║ l.63: if 42 is n then n + 1 +//│ ╙── ^ +//│ res: error + +// FIXME +:e +if 42 is n then n + 1 else 0 +//│ ╔══[ERROR] Cannot find the constructor `n` in the context +//│ ║ l.71: if 42 is n then n + 1 else 0 +//│ ╙── ^ +//│ res: error + + +if Some(42) is Some(n) then n + 1 +//│ res: int + +// TODO warn useless `else` +if Some(42) is Some(n) then n + 1 else 0 +//│ res: int + + From f701a71915bf47ef398186c0cab0764f6f3ed06a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 11:42:41 +0800 Subject: [PATCH 033/498] WIP Make class type params rigid --- .../main/scala/mlscript/TypeSimplifier.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 5 +- shared/src/test/diff/nu/GenericClasses.mls | 180 +++++++++++++++--- 3 files changed, 156 insertions(+), 31 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 2c649f4304..df2e27a35c 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -639,7 +639,7 @@ trait TypeSimplifier { self: Typer => // * Remove variables that are 'dominated' by another type or variable // * A variable v dominated by T if T is in both of v's positive and negative cooccurrences - allVars.foreach { case v => if (!varSubst.contains(v)) { + allVars.foreach { case v => if (v.assignedTo.isEmpty && !varSubst.contains(v)) { println(s"2[v] $v ${coOccurrences.get(true -> v)} ${coOccurrences.get(false -> v)}") coOccurrences.get(true -> v).iterator.flatMap(_.iterator).foreach { diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 53156fc36b..16cd7c5c35 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -102,7 +102,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => true), N, S(tp.name))) implicit val vars: Map[Str, SimpleType] = - outerVars ++ tparams.iterator.mapKeys(_.name).toMap + // outerVars ++ tparams.iterator.mapKeys(_.name).toMap + outerVars ++ tparams.iterator.map { + case (tp, tv) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) + } val typedParams = td.params.fields.map { case (S(nme), Fld(mut, spec, value)) => diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index eeacfbbf19..21aa1b55c0 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -11,18 +11,18 @@ class Some(value: A) { } //│ class Some //│ fun get: ‹∀ 1. get28''#› where -//│ | get28''# := A23' -//│ [pretty-printed] get: nothing +//│ | get28''# := ‘A23' +//│ [pretty-printed] get: A //│ fun toArray: ‹∀ 1. toArray29''#› where -//│ | toArray29''# := (A23',) -//│ [pretty-printed] toArray: (nothing,) +//│ | toArray29''# := (‘A23',) +//│ [pretty-printed] toArray: (A,) let s = Some(1) -//│ fun s: ‹∀ 0. s35'#› where -//│ | s35'# := α41' -//│ | A23_38' :> 1 -//│ | α41' :> (Some<> & {Some#A: mut A23_38'..A23_38'}) <: s35'# +//│ fun s: ‹∀ 0. s33'#› where +//│ | s33'# := α39' +//│ | A23_36' :> 1 +//│ | α39' :> (Some<> & {Some#A: mut A23_36'..A23_36'}) <: s33'# //│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 @@ -57,11 +57,11 @@ module None { // fun mapBad(f) = None // TODO } //│ class None -//│ fun get: ‹∀ 1. get81''#› where -//│ | get81''# := ⊥ +//│ fun get: ‹∀ 1. get79''#› where +//│ | get79''# := ⊥ //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray82''#› where -//│ | toArray82''# := () +//│ fun toArray: ‹∀ 1. toArray80''#› where +//│ | toArray80''# := () //│ [pretty-printed] toArray: () @@ -76,10 +76,10 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ fun opt: ‹∀ 0. opt92'#› where -//│ | opt92'# := (α99' | None<>) -//│ | A23_96' :> 123 -//│ | α99' :> (Some<> & {Some#A: mut A23_96'..A23_96'}) +//│ fun opt: ‹∀ 0. opt90'#› where +//│ | opt90'# := (α97' | None<>) +//│ | A23_94' :> 123 +//│ | α97' :> (Some<> & {Some#A: mut A23_94'..A23_94'}) //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> 123 @@ -106,22 +106,22 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ‹∀ 0. map145'#› where -//│ | map145'# := ((α146', α147',) -> (None<> | α158')) -//│ | α146' <: ((None<> & α148') | ((Some<> & α149') & ~(None<>))) -//│ | α147' <: ((‹∀ 1. value150''›,) -> α157') -//│ | α149' <: {value: value150_151'} -//│ | value150'' :> value150_151' -//│ | α157' <: A23_154' -//│ | α158' :> (Some<> & {Some#A: mut A23_154'..A23_154'}) +//│ fun map: ‹∀ 0. map143'#› where +//│ | map143'# := ((α144', α145',) -> (None<> | α156')) +//│ | α144' <: ((None<> & α146') | ((Some<> & α147') & ~(None<>))) +//│ | α145' <: ((‹∀ 1. value148''›,) -> α155') +//│ | α147' <: {value: value148_149'} +//│ | value148'' :> value148_149' +//│ | α155' <: A23_152' +//│ | α156' :> (Some<> & {Some#A: mut A23_152'..A23_152'}) //│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) let mo = map(opt, succ) -//│ fun mo: ‹∀ 0. mo174'#› where -//│ | A23_154' :> int -//│ | α158' :> (Some<> & {Some#A: mut A23_154'..A23_154'}) -//│ | mo174'# := α175' -//│ | α175' :> (None<> | α158') <: mo174'# +//│ fun mo: ‹∀ 0. mo172'#› where +//│ | A23_152' :> int +//│ | α156' :> (Some<> & {Some#A: mut A23_152'..A23_152'}) +//│ | mo172'# := α173' +//│ | α173' :> (None<> | α156') <: mo172'# //│ [pretty-printed] mo: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> int @@ -130,3 +130,125 @@ mo.toArray //│ Typed: Array[int] + +class Test(n) { + fun foo = n + 1 +} +//│ class Test +//│ fun foo: ‹∀ 1. foo204''#› where +//│ | foo204''# := α206'' +//│ | α206'' :> int <: foo204''# +//│ [pretty-printed] foo: int + +Test(1) +//│ Typed: Test + +:e +Test(true) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.147: Test(true) +//│ ║ ^^^^^^^^^^ +//│ ╟── reference of type `true` is not an instance of type `int` +//│ ║ l.147: Test(true) +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.135: fun foo = n + 1 +//│ ║ ^ +//│ ╟── from reference: +//│ ║ l.134: class Test(n) { +//│ ╙── ^ +//│ Typed: Test | error + + +:e +class Test(n: A) { + fun foo = n + 1 +} +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.165: fun foo = n + 1 +//│ ║ ^^^ +//│ ╟── reference of type `A` is not an instance of type `int` +//│ ║ l.165: fun foo = n + 1 +//│ ║ ^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.164: class Test(n: A) { +//│ ╙── ^ +//│ class Test +//│ fun foo: ‹∀ 1. foo222''#› where +//│ | foo222''# := α224'' +//│ | α224'' :> error<> | int <: foo222''# +//│ [pretty-printed] foo: error | int + +Test(1) +//│ Typed: Test & {Test#A :> 'A <: 1 | 'A} + +Test(true) +//│ Typed: Test & {Test#A :> 'A <: 'A | true} + + +class Test(n: A) { + fun foo: A = n +} +//│ class Test +//│ fun foo: ‹∀ 1. foo252''#› where +//│ | foo252''# := ‘A248' +//│ [pretty-printed] foo: A + +Test(1).foo +//│ Typed: 1 + +Test("ok").foo +//│ Typed: "ok" + + +:e +class Test { + // fun foo(x: A) = x // FIXME + fun foo1(x : A) = x + fun foo2(x : A) = x + 1 +} +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.208: fun foo2(x : A) = x + 1 +//│ ║ ^^^ +//│ ╟── reference of type `A` is not an instance of type `int` +//│ ║ l.208: fun foo2(x : A) = x + 1 +//│ ║ ^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.205: class Test { +//│ ╙── ^ +//│ class Test +//│ fun foo1: ‹∀ 1. foo1290''#› where +//│ | foo1290''# := (‘A285' -> ‘A285') +//│ [pretty-printed] foo1: A -> A +//│ fun foo2: ‹∀ 1. foo2291''#› where +//│ | foo2291''# := (‘A285' -> α293'') +//│ | α293'' :> error<> | int +//│ [pretty-printed] foo2: A -> (error | int) + +Test().foo1 +//│ Typed: 'A -> 'A + +Test().foo1(1) +//│ Typed: 1 + +x => Test().foo1(x) +//│ Typed: 'a -> 'a + +let t = Test() +//│ fun t: ‹∀ 0. t364'#› where +//│ | t364'# := α371' +//│ | α371' :> (Test<> & {Test#A: mut A285_367'..A285_367'}) <: t364'# +//│ [pretty-printed] t: Test & {Test#A = 'A} + +[t.foo1(0), t.foo1(true)] +//│ Typed: (0 | true, 0 | true,) + +// FIXME +fun foo(x : Test) = x.foo1 +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Test + + +Test().foo2 +//│ Typed: anything -> (error | int) + + From 9dbddf4d500aafc814caf347a148256cbdfc6d47 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 12:51:18 +0800 Subject: [PATCH 034/498] WIP --- .../scala/mlscript/ConstraintSolver.scala | 47 +++- .../main/scala/mlscript/TyperDatatypes.scala | 8 +- shared/src/test/diff/nu/GenericClasses.mls | 247 +++++++++++++++--- 3 files changed, 255 insertions(+), 47 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index d4b84509b4..0febdcb6a5 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -427,12 +427,41 @@ class ConstraintSolver extends NormalForms { self: Typer => implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty // freshened ++= td.tparams.map(tp => tp._2 -> TopType) + + // /* td.tparams.foreach { case (tn, _tv) => // val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) - val tv = freshVar(_tv.prov, N, _tv.nameHint) // TODO safe not to set original?! - println(s"Assigning $tv") + val targ = rfnt.get(Var(td.nme.name + "#" + tn.name)) match { + case S(fty) => + TypeBounds( + fty.lb.getOrElse(BotType), + fty.ub, + )(_tv.prov) + case N => + // FIXME type bounds are kind of wrong for this + TypeBounds( + _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + _tv.upperBounds.foldLeft(TopType: ST)(_ & _), + )(_tv.prov) + } + // println(s"Assigning ${_tv} ~> $tv := $targ where ${ + // targ.ub.showBounds}${targ.showBounds}") + // // targ.ub.showBounds}${targ.lb.fold("")(_.showBounds)}") + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) // TODO safe not to set original?! + println(s"Set ${_tv} ~> $tv") assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(rfnt.get(Var(td.nme.name + "#" + tn.name)) match { + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + freshened += _tv -> tv + } + // */ + /* + td.tparams.foreach { case (tn, tv) => + assert(tv.assignedTo.isEmpty) + val targ = rfnt.get(Var(td.nme.name + "#" + tn.name)) match { case S(fty) => TypeBounds( fty.lb.getOrElse(BotType), @@ -444,9 +473,12 @@ class ConstraintSolver extends NormalForms { self: Typer => tv.lowerBounds.foldLeft(BotType: ST)(_ | _), tv.upperBounds.foldLeft(TopType: ST)(_ & _), )(tv.prov) - }) - freshened += _tv -> tv + } + println(s"Type param $tv := ${targ}") + freshened += tv -> targ } + */ + // println(td) // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] val res = @@ -460,7 +492,8 @@ class ConstraintSolver extends NormalForms { self: Typer => } def lookupNuTypeDefField(cls: TypedNuCls, fld: Var): FieldType = { // println(fld.name, cls.members) - cls.members.get(fld.name) match { + println(s"Looking up $fld in ${cls.td.nme}") + val res = cls.members.get(fld.name) match { case S(d: TypedNuFun) => d.ty.toUpper(provTODO) case S(p: NuParam) => @@ -471,6 +504,8 @@ class ConstraintSolver extends NormalForms { self: Typer => fld.toLoc).toUpper(noProv) // case _ => ??? } + println(s"Looked up $res where ${res.ub.showBounds}") + res } /** Helper function to constrain Field lower bounds. */ diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 16cd7c5c35..6c10de91c2 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -868,7 +868,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => require(level <= MaxLevel) - var assignedTo: Opt[ST] = N + // var assignedTo: Opt[ST] = N + private var _assignedTo: Opt[ST] = N + def assignedTo: Opt[ST] = _assignedTo + def assignedTo_=(value: Opt[ST]): Unit = { + require(value.forall(_.level <= level)) + _assignedTo = value + } // * Bounds shoudl always be disregarded when `equatedTo` is defined, as they are then irrelevant: def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty); _lowerBounds } diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 21aa1b55c0..6488846b04 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -57,11 +57,11 @@ module None { // fun mapBad(f) = None // TODO } //│ class None -//│ fun get: ‹∀ 1. get79''#› where -//│ | get79''# := ⊥ +//│ fun get: ‹∀ 1. get92''#› where +//│ | get92''# := ⊥ //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray80''#› where -//│ | toArray80''# := () +//│ fun toArray: ‹∀ 1. toArray93''#› where +//│ | toArray93''# := () //│ [pretty-printed] toArray: () @@ -76,10 +76,10 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ fun opt: ‹∀ 0. opt90'#› where -//│ | opt90'# := (α97' | None<>) -//│ | A23_94' :> 123 -//│ | α97' :> (Some<> & {Some#A: mut A23_94'..A23_94'}) +//│ fun opt: ‹∀ 0. opt103'#› where +//│ | opt103'# := (α110' | None<>) +//│ | A23_107' :> 123 +//│ | α110' :> (Some<> & {Some#A: mut A23_107'..A23_107'}) //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> 123 @@ -106,22 +106,22 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ‹∀ 0. map143'#› where -//│ | map143'# := ((α144', α145',) -> (None<> | α156')) -//│ | α144' <: ((None<> & α146') | ((Some<> & α147') & ~(None<>))) -//│ | α145' <: ((‹∀ 1. value148''›,) -> α155') -//│ | α147' <: {value: value148_149'} -//│ | value148'' :> value148_149' -//│ | α155' <: A23_152' -//│ | α156' :> (Some<> & {Some#A: mut A23_152'..A23_152'}) +//│ fun map: ‹∀ 0. map163'#› where +//│ | map163'# := ((α164', α165',) -> (None<> | α176')) +//│ | α164' <: ((None<> & α166') | ((Some<> & α167') & ~(None<>))) +//│ | α165' <: ((‹∀ 1. value168''›,) -> α175') +//│ | α167' <: {value: value168_169'} +//│ | value168'' :> value168_169' +//│ | α175' <: A23_172' +//│ | α176' :> (Some<> & {Some#A: mut A23_172'..A23_172'}) //│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) let mo = map(opt, succ) -//│ fun mo: ‹∀ 0. mo172'#› where -//│ | A23_152' :> int -//│ | α156' :> (Some<> & {Some#A: mut A23_152'..A23_152'}) -//│ | mo172'# := α173' -//│ | α173' :> (None<> | α156') <: mo172'# +//│ fun mo: ‹∀ 0. mo192'#› where +//│ | A23_172' :> int +//│ | α176' :> (Some<> & {Some#A: mut A23_172'..A23_172'}) +//│ | mo192'# := α193' +//│ | α193' :> (None<> | α176') <: mo192'# //│ [pretty-printed] mo: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> int @@ -135,9 +135,9 @@ class Test(n) { fun foo = n + 1 } //│ class Test -//│ fun foo: ‹∀ 1. foo204''#› where -//│ | foo204''# := α206'' -//│ | α206'' :> int <: foo204''# +//│ fun foo: ‹∀ 1. foo231''#› where +//│ | foo231''# := α233'' +//│ | α233'' :> int <: foo231''# //│ [pretty-printed] foo: int Test(1) @@ -174,9 +174,9 @@ class Test(n: A) { //│ ║ l.164: class Test(n: A) { //│ ╙── ^ //│ class Test -//│ fun foo: ‹∀ 1. foo222''#› where -//│ | foo222''# := α224'' -//│ | α224'' :> error<> | int <: foo222''# +//│ fun foo: ‹∀ 1. foo249''#› where +//│ | foo249''# := α251'' +//│ | α251'' :> error<> | int <: foo249''# //│ [pretty-printed] foo: error | int Test(1) @@ -190,10 +190,13 @@ class Test(n: A) { fun foo: A = n } //│ class Test -//│ fun foo: ‹∀ 1. foo252''#› where -//│ | foo252''# := ‘A248' +//│ fun foo: ‹∀ 1. foo279''#› where +//│ | foo279''# := ‘A275' //│ [pretty-printed] foo: A +Test(1) +//│ Typed: Test & {Test#A :> 'A <: 1 | 'A} + Test(1).foo //│ Typed: 1 @@ -208,21 +211,21 @@ class Test { fun foo2(x : A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.208: fun foo2(x : A) = x + 1 +//│ ║ l.211: fun foo2(x : A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.208: fun foo2(x : A) = x + 1 +//│ ║ l.211: fun foo2(x : A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.205: class Test { +//│ ║ l.208: class Test { //│ ╙── ^ //│ class Test -//│ fun foo1: ‹∀ 1. foo1290''#› where -//│ | foo1290''# := (‘A285' -> ‘A285') +//│ fun foo1: ‹∀ 1. foo1328''#› where +//│ | foo1328''# := (‘A323' -> ‘A323') //│ [pretty-printed] foo1: A -> A -//│ fun foo2: ‹∀ 1. foo2291''#› where -//│ | foo2291''# := (‘A285' -> α293'') -//│ | α293'' :> error<> | int +//│ fun foo2: ‹∀ 1. foo2329''#› where +//│ | foo2329''# := (‘A323' -> α331'') +//│ | α331'' :> error<> | int //│ [pretty-printed] foo2: A -> (error | int) Test().foo1 @@ -234,15 +237,179 @@ Test().foo1(1) x => Test().foo1(x) //│ Typed: 'a -> 'a +:d let t = Test() -//│ fun t: ‹∀ 0. t364'#› where -//│ | t364'# := α371' -//│ | α371' :> (Test<> & {Test#A: mut A285_367'..A285_367'}) <: t364'# +//│ 0. Typing TypingUnit(List(let t = Test ())) +//│ Completing let t = Test () +//│ | 1. Typing term Test () +//│ | | 1. Typing term Test +//│ | | | (>>,0,1) +//│ | | 1. : (() -> (Test<> & {Test#A: mut A323_405'..A323_405'})) +//│ | | CONSTRAIN (() -> (Test<> & {Test#A: mut A323_405'..A323_405'})) α409') +//│ | | where +//│ | | 1. C (() -> (Test<> & {Test#A: mut A323_405'..A323_405'})) α409') (0) +//│ | | | 1. C () & {Test#A: mut A323_405'..A323_405'}) (Test<> & {Test#A: mut A323_405'..A323_405'}) +//│ | 1. C α409' & {Test#A: mut A323_405'..A323_405'}) (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# +//│ fun t: ‹∀ 0. t402'#› where +//│ | t402'# := α409' +//│ | α409' :> (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# //│ [pretty-printed] t: Test & {Test#A = 'A} +:d +t +//│ 0. Typing TypingUnit(List(t)) +//│ | 0. Typing term t +//│ | 0. : t402'# +//│ ⬤ Typed as: ‹∀ 0. t402'#› +//│ where: +//│ t402'# := α409' +//│ α409' :> (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# +//│ Typed: Test & {Test#A = 'A} + +:d +t.foo1 +//│ 0. Typing TypingUnit(List((t).foo1)) +//│ | 0. Typing term (t).foo1 +//│ | | 0. Typing term t +//│ | | 0. : t402'# +//│ | | CONSTRAIN t402'# (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# +//│ | | 0. C t402'# & {Test#A: mut A323_405'..A323_405'}) {Test#A: mut A323_405'..A323_405'}) {Test#A: mut A323_405'..A323_405'} <: DNF(0, {foo1: foo1420}) +//│ | | | | | | Possible: List({foo1: foo1420}) +//│ | | | | | | 0. A Test<>{Test#A: mut A323_405'..A323_405'} % List() {Test#A: mut A323_405'..A323_405'} % List() {Test#A: mut A323_405'..A323_405'} % List() A421' +//│ | | | | | | | | | (>>,0,0) +//│ | | | | | | | | | Looking up foo1 in TypeName(Test) +//│ | | | | | | | | | Looked up ‹∀ 1. foo1328_423''#› where +//│ A421'# := A323_405'..A323_405' +//│ foo1328_423''# := (A421'# -> A421'#) +//│ | | | | | | | | | 0. C ‹∀ 1. foo1328_423''#› ‹∀ 1. foo1328_427''#› to 0 +//│ | | | | | | | | | | where +//│ foo1328_427''# := (A421_428' -> A421_428') +//│ A421_428' :> A323_429 <: A323_430 +//│ A323_429 <: A323_430 +//│ A323_430 <: A323_429 +//│ | | | | | | | | | | 0. C ‹∀ 1. foo1328_427''#› A421_433) A421_432) (5) +//│ | | | | | | | | | | | | | 0. C (A421_433,) ‹∀ 1. foo1328_431''› to 0 +//│ | | | | | | | | | | | where +//│ A323_429 <: A421_432 & A323_430 +//│ A323_430 <: A323_429 +//│ foo1328_431'' :> (A421_432 -> A421_433) <: (A421_433 -> A421_432) +//│ A421_432 <: A323_430 +//│ A421_433 :> A421_432 | A323_429 <: A421_432 +//│ | | | | | | | | | | | 0. C ‹∀ 1. foo1328_431''› ‹∀ 1. foo1328_431''› +//│ A323_429 <: A421_432 & A323_430 +//│ A323_430 <: A323_429 +//│ foo1328_431'' :> (A421_432 -> A421_433) <: (A421_433 -> A421_432) +//│ A421_432 <: A323_430 +//│ A421_433 :> A421_432 | A323_429 <: A421_432 +//│ Typed: 'A -> 'A + [t.foo1(0), t.foo1(true)] //│ Typed: (0 | true, 0 | true,) +t.foo1(0) +//│ Typed: 0 | true + +:d +t +//│ 0. Typing TypingUnit(List(t)) +//│ | 0. Typing term t +//│ | 0. : t402'# +//│ ⬤ Typed as: ‹∀ 0. t402'#› +//│ where: +//│ t402'# := α409' +//│ A323_405' :> A323_486 | A323_468 | A323_452 | A323_430 <: A323_485 & A323_467 & A323_451 & A323_429 +//│ α409' :> (Test<> & {Test#A: mut A323_405'..A323_405'}) <: {foo1: foo1476} & {foo1: foo1458} & {foo1: foo1442} & {foo1: foo1420} & t402'# +//│ foo1420 :> ‹∀ 1. foo1328_431''› +//│ A323_429 :> 0 | true | true | 0 | 0 <: A421_432 & A323_430 +//│ A323_430 :> 0 | true | true | 0 | 0 <: α490 & A477_488 & A323_486 & α472 & A459_470 & A323_468 & α456 & A443_454 & A323_452 & A323_429 +//│ foo1328_431'' :> (A421_432 -> A421_433) <: (A421_433 -> A421_432) +//│ A421_432 :> 0 | true | true | 0 | 0 <: A323_430 +//│ A421_433 :> A421_432 | A323_429 <: A421_432 +//│ foo1442 :> ‹∀ 1. foo1328_453''› <: ((0,) -> α456) +//│ A323_451 :> 0 | true | true | 0 | 0 | A323_430 <: α456 & A443_454 & A323_452 +//│ A323_452 :> 0 | true | true | 0 | 0 <: α490 & A477_488 & A323_486 & α472 & A459_470 & A323_468 & A323_451 & A323_429 +//│ foo1328_453'' :> (A443_454 -> A443_455) <: (A443_455 -> A443_454) +//│ A443_454 :> 0 | true | true | 0 | 0 <: α456 & A323_452 +//│ A443_455 :> A443_454 | A323_451 <: α456 & A443_454 +//│ α456 :> 0 | true | true | 0 | 0 +//│ foo1458 :> ‹∀ 1. foo1328_469''› <: ((true,) -> α472) +//│ A323_467 :> 0 | true | true | 0 | A323_452 | A323_430 <: α472 & A459_470 & A323_468 +//│ A323_468 :> 0 | true | true | 0 <: α490 & A477_488 & A323_486 & A323_467 & A323_451 & A323_429 +//│ foo1328_469'' :> (A459_470 -> A459_471) <: (A459_471 -> A459_470) +//│ A459_470 :> 0 | true | true | 0 <: α472 & A323_468 +//│ A459_471 :> A459_470 | A323_467 <: α472 & A459_470 +//│ α472 :> 0 | true | 0 | true +//│ foo1476 :> ‹∀ 1. foo1328_487''› <: ((0,) -> α490) +//│ A323_485 :> 0 | true | A323_468 | A323_452 | A323_430 <: α490 & A477_488 & A323_486 +//│ A323_486 :> 0 | true <: A323_485 & A323_467 & A323_451 & A323_429 +//│ foo1328_487'' :> (A477_488 -> A477_489) <: (A477_489 -> A477_488) +//│ A477_488 :> true | 0 <: α490 & A323_486 +//│ A477_489 :> A477_488 | A323_485 <: α490 & A477_488 +//│ α490 :> 0 | true +//│ Typed: Test & {Test#A = 'A & 'A0} +//│ where +//│ 'A :> 0 | true +//│ <: 'A0 +//│ 'A0 <: 'A + // FIXME fun foo(x : Test) = x.foo1 //│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Test From a85f98cba6f7dce1f2d29a3b159874115907db2c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 15:25:27 +0800 Subject: [PATCH 035/498] WIP make ctors polymorphic --- .../scala/mlscript/ConstraintSolver.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 20 +- shared/src/test/diff/nu/BasicClasses.mls | 76 +++--- shared/src/test/diff/nu/BasicMixins.mls | 106 +++---- shared/src/test/diff/nu/ECOOP23.mls | 132 ++++----- shared/src/test/diff/nu/GenericClasses.mls | 258 ++++-------------- shared/src/test/diff/nu/MutualRec.mls | 101 +++---- 7 files changed, 276 insertions(+), 421 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 0febdcb6a5..c9d322e519 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -492,7 +492,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } def lookupNuTypeDefField(cls: TypedNuCls, fld: Var): FieldType = { // println(fld.name, cls.members) - println(s"Looking up $fld in ${cls.td.nme}") + // println(s"Looking up $fld in ${cls.td.nme}") val res = cls.members.get(fld.name) match { case S(d: TypedNuFun) => d.ty.toUpper(provTODO) @@ -504,7 +504,7 @@ class ConstraintSolver extends NormalForms { self: Typer => fld.toLoc).toUpper(noProv) // case _ => ??? } - println(s"Looked up $res where ${res.ub.showBounds}") + println(s"Lookup ${cls.td.nme.name}.${fld.name} : $res where ${res.ub.showBounds}") res } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 6c10de91c2..9918790513 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -275,16 +275,18 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) case _cls: TypedNuCls => val cls = _cls.freshen.asInstanceOf[TypedNuCls] - FunctionType( - TupleType(cls.params.mapKeys(some))(provTODO), - // cls.tparams.foldLeft( - // ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) - // ) { case (acc, (tn, tv)) => acc & } - ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( - cls.tparams.map { case (tn, tv) => - Var(cls.td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + PolymorphicType.mk(cls.level, + FunctionType( + TupleType(cls.params.mapKeys(some))(provTODO), + // cls.tparams.foldLeft( + // ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) + // ) { case (acc, (tn, tv)) => acc & } + ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( + cls.tparams.map { case (tn, tv) => + Var(cls.td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + )(provTODO) )(provTODO) - )(provTODO) + ) case TypedNuFun(_, fd, ty) => // println(fd, ty) // ??? diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 667c425f20..b49aac664a 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -53,9 +53,9 @@ let b1 = Base0(42) // :d let n1 = b1.n -//│ fun n1: ‹∀ 0. n1103'#› where -//│ | n1103'# := n104' -//│ | n104' <: n1103'# +//│ fun n1: ‹∀ 0. n1104'#› where +//│ | n1104'# := n105' +//│ | n105' <: n1104'# //│ [pretty-printed] n1: nothing // TODO @@ -65,15 +65,15 @@ n1 + 1 let b2 = Base0("hi") let n2 = b2.n -//│ fun b2: ‹∀ 0. b2126'#› where -//│ | b2126'# := α141' -//│ | α141' :> Base0<> <: {n: n143'} & b2126'# -//│ | n2142'# := n143' -//│ | n143' <: n2142'# +//│ fun b2: ‹∀ 0. b2127'#› where +//│ | b2127'# := α142' +//│ | α142' :> Base0<> <: {n: n145'} & b2127'# +//│ | n2144'# := n145' +//│ | n145' <: n2144'# //│ [pretty-printed] b2: Base0 -//│ fun n2: ‹∀ 0. n2142'#› where -//│ | n2142'# := n143' -//│ | n143' <: n2142'# +//│ fun n2: ‹∀ 0. n2144'#› where +//│ | n2144'# := n145' +//│ | n145' <: n2144'# //│ [pretty-printed] n2: nothing @@ -84,18 +84,18 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1168''#› where -//│ | getBase1168''# := Int +//│ fun getBase1: ‹∀ 1. getBase1170''#› where +//│ | getBase1170''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase2169''#› where -//│ | getBase2169''# := base170'' -//│ | base170'' :> base170_171' <: getBase2169''# -//│ | base170_171' :> Int +//│ fun getBase2: ‹∀ 1. getBase2171''#› where +//│ | getBase2171''# := base172'' +//│ | base172'' :> base172_173' <: getBase2171''# +//│ | base172_173' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo172''#› where -//│ | foo172''# := (α173'' -> α177'') -//│ | α173'' <: int -//│ | α177'' :> int +//│ fun foo: ‹∀ 1. foo174''#› where +//│ | foo174''# := (α175'' -> α179'') +//│ | α175'' <: int +//│ | α179'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -104,26 +104,26 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1203''#› where -//│ | getBase1203''# := Int +//│ fun getBase1: ‹∀ 1. getBase1205''#› where +//│ | getBase1205''# := Int //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me204''#› where -//│ | this198' :> Base1<> -//│ | me204''# := this198' +//│ fun me: ‹∀ 1. me206''#› where +//│ | this200' :> Base1<> +//│ | me206''# := this200' //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo205''#› where -//│ | foo205''# := (α206'' -> α208'') -//│ | α206'' <: int -//│ | α208'' :> int +//│ fun foo: ‹∀ 1. foo207''#› where +//│ | foo207''# := (α208'' -> α210'') +//│ | α208'' <: int +//│ | α210'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b221'#› where -//│ | b221'# := α227' -//│ | α227' :> Base1<> <: b221'# +//│ fun b: ‹∀ 0. b223'#› where +//│ | b223'# := α229' +//│ | α229' :> Base1<> <: b223'# //│ [pretty-printed] b: Base1 b.base @@ -160,9 +160,9 @@ class Rec(n) { //│ ║ l.154: } //│ ╙── ^ //│ class Rec -//│ fun go: ‹∀ 1. go266''#› where -//│ | go266''# := α269'' -//│ | α269'' :> error<> <: go266''# +//│ fun go: ‹∀ 1. go268''#› where +//│ | go268''# := α271'' +//│ | α271'' :> error<> <: go268''# //│ [pretty-printed] go: error @@ -186,8 +186,8 @@ class Annots(base: 0 | 1) { //│ ║ l.173: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a276''#› where -//│ | a276''# := ((0 | 1),) +//│ fun a: ‹∀ 1. a278''#› where +//│ | a278''# := ((0 | 1),) //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index f0b5b8d0c2..58bffaab2a 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -92,15 +92,15 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo -//│ this: this186' -//│ super: super187' -//│ | super187' <: {misc: misc195_196'} & {base: base191_192'} -//│ | base191_192' <: int -//│ fun test: ‹∀ 1. test189''#› where -//│ | test189''# := (α190'' -> (α194'', α190'', misc195'',)) -//│ | α190'' <: int -//│ | α194'' :> int -//│ | misc195'' :> misc195_196' +//│ this: this191' +//│ super: super192' +//│ | super192' <: {misc: misc200_201'} & {base: base196_197'} +//│ | base196_197' <: int +//│ fun test: ‹∀ 1. test194''#› where +//│ | test194''# := (α195'' -> (α199'', α195'', misc200'',)) +//│ | α195'' <: int +//│ | α199'' :> int +//│ | misc200'' :> misc200_201' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) module Base1(base: int, misc: string): Foo @@ -117,13 +117,13 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase -//│ this: this231' -//│ super: super232' -//│ fun wrapA: ‹∀ 1. wrapA235''#› where -//│ | wrapA235''# := (Int -> Int) +//│ this: this236' +//│ super: super237' +//│ fun wrapA: ‹∀ 1. wrapA240''#› where +//│ | wrapA240''# := (Int -> Int) //│ [pretty-printed] wrapA: int -> int -//│ fun wrap: ‹∀ 1. wrap236''#› where -//│ | wrap236''# := (α237'' -> α237'') +//│ fun wrap: ‹∀ 1. wrap241''#› where +//│ | wrap241''# := (α242'' -> α242'') //│ [pretty-printed] wrap: 'a -> 'a // :d @@ -132,20 +132,20 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ mixin Wrap -//│ this: this244' -//│ super: super245' -//│ | super245' <: {wrap: wrap257_258'} & {wrapA: wrapA250_251'} -//│ | wrapA250_251' <: ((α249_253',) -> α252_254') -//│ | wrap257_258' <: ((α256_260',) -> α259_261') -//│ fun wrapA: ‹∀ 1. wrapA248''#› where -//│ | wrapA248''# := (α249'' -> (α252'',)) -//│ | α249'' <: α249_253' -//│ | α252'' :> α252_254' +//│ this: this249' +//│ super: super250' +//│ | super250' <: {wrap: wrap262_263'} & {wrapA: wrapA255_256'} +//│ | wrapA255_256' <: ((α254_258',) -> α257_259') +//│ | wrap262_263' <: ((α261_265',) -> α264_266') +//│ fun wrapA: ‹∀ 1. wrapA253''#› where +//│ | wrapA253''# := (α254'' -> (α257'',)) +//│ | α254'' <: α254_258' +//│ | α257'' :> α257_259' //│ [pretty-printed] wrapA: anything -> (nothing,) -//│ fun wrap: ‹∀ 1. wrap255''#› where -//│ | wrap255''# := (α256'' -> (α259'',)) -//│ | α256'' <: α256_260' -//│ | α259'' :> α259_261' +//│ fun wrap: ‹∀ 1. wrap260''#› where +//│ | wrap260''# := (α261'' -> (α264'',)) +//│ | α261'' <: α261_265' +//│ | α264'' :> α264_266' //│ [pretty-printed] wrap: anything -> (nothing,) @@ -201,34 +201,34 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ class WrapBase2 let w = WrapBase2.wrap -//│ fun w: ‹∀ 0. w476'#› where -//│ | w476'# := wrap477' -//│ | wrap477' :> ‹∀ 1. wrap255_491''#› <: w476'# -//│ | wrap255_491''# := (α256_492'' -> (α259_500'',)) -//│ | α256_492'' <: α256_493' -//│ | α256_493' <: α256_494' -//│ | α256_494' <: α256_495' -//│ | α256_495' <: α256_496' -//│ | α256_496' <: α256_497' -//│ | α256_497' <: α237_498' -//│ | α237_498' <: α259_499' -//│ | α259_500'' :> α259_501' -//│ | α259_501' :> ‹∀ 2. (α259_502''',)› -//│ | α259_502''' :> α259_503' -//│ | α259_503' :> ‹∀ 2. (α259_504''',)› -//│ | α259_504''' :> α259_499' +//│ fun w: ‹∀ 0. w481'#› where +//│ | w481'# := wrap482' +//│ | wrap482' :> ‹∀ 1. wrap260_496''#› <: w481'# +//│ | wrap260_496''# := (α261_497'' -> (α264_505'',)) +//│ | α261_497'' <: α261_498' +//│ | α261_498' <: α261_499' +//│ | α261_499' <: α261_500' +//│ | α261_500' <: α261_501' +//│ | α261_501' <: α261_502' +//│ | α261_502' <: α242_503' +//│ | α242_503' <: α264_504' +//│ | α264_505'' :> α264_506' +//│ | α264_506' :> ‹∀ 2. (α264_507''',)› +//│ | α264_507''' :> α264_508' +//│ | α264_508' :> ‹∀ 2. (α264_509''',)› +//│ | α264_509''' :> α264_504' //│ [pretty-printed] w: 'a -> ((('a,),),) let wd = w(1) -//│ fun wd: ‹∀ 0. wd524'#› where -//│ | α259_499' :> 1 -//│ | α259_501' :> ‹∀ 2. (α259_502''',)› -//│ | α259_502''' :> α259_503' -//│ | α259_503' :> ‹∀ 2. (α259_504''',)› -//│ | α259_504''' :> α259_499' -//│ | wd524'# := α525' -//│ | α525' :> ‹∀ 2. (α259_526''',)› <: wd524'# -//│ | α259_526''' :> α259_501' +//│ fun wd: ‹∀ 0. wd529'#› where +//│ | α264_504' :> 1 +//│ | α264_506' :> ‹∀ 2. (α264_507''',)› +//│ | α264_507''' :> α264_508' +//│ | α264_508' :> ‹∀ 2. (α264_509''',)› +//│ | α264_509''' :> α264_504' +//│ | wd529'# := α530' +//│ | α530' :> ‹∀ 2. (α264_531''',)› <: wd529'# +//│ | α264_531''' :> α264_506' //│ [pretty-printed] wd: (((1,),),) wd._1._1._1 + 1 diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 30a8d66746..a4c26ecfb1 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -11,8 +11,8 @@ class Lit(n: int) let add11 = Add(Lit(1), Lit(2)) //│ fun add11: ‹∀ 0. add1130'#› where //│ | add1130'# := α34' -//│ | E24_31' :> Lit<> -//│ | α34' :> (Add<> & {Add#E: mut E24_31'..E24_31'}) <: add1130'# +//│ | α34' :> (Add<> & {Add#E: mut E24_35'..E24_35'}) <: add1130'# +//│ | E24_35' :> Lit<> //│ [pretty-printed] add11: Add & {Add#E = 'E} //│ | where //│ | 'E :> Lit @@ -25,24 +25,24 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase -//│ this: this41' -//│ | this41' <: {eval: eval62_63'} & {eval: eval55_56'} -//│ | eval55_56' <: ((‹∀ 2. lhs51_58'''›,) -> α57_60') -//│ | lhs51_58''' :> lhs51_59' -//│ | α57_60' <: int -//│ | eval62_63' <: ((‹∀ 2. rhs53_65'''›,) -> α64_67') -//│ | rhs53_65''' :> rhs53_66' -//│ | α64_67' <: int -//│ super: super42' -//│ fun eval: ‹∀ 1. eval44''#› where -//│ | eval44''# := (α45'' -> (Int | α68'')) -//│ | α45'' <: ((Lit<> & α46'') | ((Add<> & α50'') & ~(Lit<>))) -//│ | α46'' <: {n: n47_48''} -//│ | n47_48'' <: int -//│ | α50'' <: {rhs: rhs53_54''} & {lhs: lhs51_52''} -//│ | lhs51_52'' <: lhs51_59' -//│ | rhs53_54'' <: rhs53_66' -//│ | α68'' :> int +//│ this: this42' +//│ | this42' <: {eval: eval63_64'} & {eval: eval56_57'} +//│ | eval56_57' <: ((‹∀ 2. lhs52_59'''›,) -> α58_61') +//│ | lhs52_59''' :> lhs52_60' +//│ | α58_61' <: int +//│ | eval63_64' <: ((‹∀ 2. rhs54_66'''›,) -> α65_68') +//│ | rhs54_66''' :> rhs54_67' +//│ | α65_68' <: int +//│ super: super43' +//│ fun eval: ‹∀ 1. eval45''#› where +//│ | eval45''# := (α46'' -> (Int | α69'')) +//│ | α46'' <: ((Lit<> & α47'') | ((Add<> & α51'') & ~(Lit<>))) +//│ | α47'' <: {n: n48_49''} +//│ | n48_49'' <: int +//│ | α51'' <: {rhs: rhs54_55''} & {lhs: lhs52_53''} +//│ | lhs52_53'' <: lhs52_60' +//│ | rhs54_55'' <: rhs54_67' +//│ | α69'' :> int //│ [pretty-printed] eval: (Add & {lhs: anything, rhs: anything} | Lit & {n: int}) -> int @@ -62,36 +62,36 @@ class Neg(expr: A) //│ class Neg let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ fun add2negadd11: ‹∀ 0. add2negadd11208'#› where -//│ | E24_31' :> E24_188 | Lit<> <: E24_189 -//│ | rhs53_171 :> Lit<> <: ((Lit<> & α46_172) | ((Add<> & α50_174) & ~(Lit<>))) -//│ | α46_172 :> Lit<> <: {n: n47_173} -//│ | n47_173 :> Int <: int -//│ | α50_174 <: {rhs: rhs53_175} & {lhs: lhs51_176} -//│ | rhs53_175 <: rhs53_171 -//│ | lhs51_176 <: lhs51_177 -//│ | lhs51_177 :> Lit<> <: ((Lit<> & α46_178) | ((Add<> & α50_180) & ~(Lit<>))) -//│ | α46_178 :> Lit<> <: {n: n47_179} -//│ | n47_179 :> Int <: int -//│ | α50_180 <: {rhs: rhs53_181} & {lhs: lhs51_182} -//│ | rhs53_181 <: rhs53_171 -//│ | lhs51_182 <: lhs51_177 -//│ | add1130_186' :> (Add<> & {Add#E: mut E24_188..E24_189}) | α34_187 <: add1130_191 & α34_190 -//│ | α34_187 :> (Add<> & {Add#E: mut E24_188..E24_189}) | (Add<> & {Add#E: mut E24_188..E24_189}) <: α45_193 & α34_190 -//│ | E24_188 <: lhs51_198 & rhs53_197 -//│ | E24_189 :> E24_188 | Lit<> <: lhs51_198 & rhs53_197 -//│ | α34_190 :> (Add<> & {Add#E: mut E24_188..E24_189}) <: α34_187 & add1130_186' -//│ | add1130_191 :> (Add<> & {Add#E: mut E24_188..E24_189}) | α34_187 <: α45_193 -//│ | α45_193 :> (Add<> & {Add#E: mut E24_188..E24_189}) <: ((Lit<> & α46_194) | ((Add<> & α50_196) & ~(Lit<>))) -//│ | α46_194 <: {n: n47_195} -//│ | n47_195 <: int -//│ | α50_196 :> (Add<> & {Add#E: mut E24_188..E24_189}) <: {rhs: rhs53_197} & {lhs: lhs51_198} -//│ | rhs53_197 :> Lit<> <: rhs53_171 -//│ | lhs51_198 :> Lit<> <: lhs51_177 -//│ | add2negadd11208'# := α213' -//│ | E24_209' :> (Neg<> & {Neg#A: mut A204_211'..A204_211'}) | Lit<> -//│ | A204_211' :> (Add<> & {Add#E: mut E24_31'..E24_31'}) | α34_190 -//│ | α213' :> (Add<> & {Add#E: mut E24_209'..E24_209'}) <: add2negadd11208'# +//│ fun add2negadd11: ‹∀ 0. add2negadd11209'#› where +//│ | E24_35' :> E24_189 | Lit<> <: E24_190 +//│ | rhs54_172 :> Lit<> <: ((Lit<> & α47_173) | ((Add<> & α51_175) & ~(Lit<>))) +//│ | α47_173 :> Lit<> <: {n: n48_174} +//│ | n48_174 :> Int <: int +//│ | α51_175 <: {rhs: rhs54_176} & {lhs: lhs52_177} +//│ | rhs54_176 <: rhs54_172 +//│ | lhs52_177 <: lhs52_178 +//│ | lhs52_178 :> Lit<> <: ((Lit<> & α47_179) | ((Add<> & α51_181) & ~(Lit<>))) +//│ | α47_179 :> Lit<> <: {n: n48_180} +//│ | n48_180 :> Int <: int +//│ | α51_181 <: {rhs: rhs54_182} & {lhs: lhs52_183} +//│ | rhs54_182 <: rhs54_172 +//│ | lhs52_183 <: lhs52_178 +//│ | add1130_187' :> (Add<> & {Add#E: mut E24_189..E24_190}) | α34_188 <: add1130_192 & α34_191 +//│ | α34_188 :> (Add<> & {Add#E: mut E24_189..E24_190}) | (Add<> & {Add#E: mut E24_189..E24_190}) <: α46_194 & α34_191 +//│ | E24_189 <: lhs52_199 & rhs54_198 +//│ | E24_190 :> E24_189 | Lit<> <: lhs52_199 & rhs54_198 +//│ | α34_191 :> (Add<> & {Add#E: mut E24_189..E24_190}) <: α34_188 & add1130_187' +//│ | add1130_192 :> (Add<> & {Add#E: mut E24_189..E24_190}) | α34_188 <: α46_194 +//│ | α46_194 :> (Add<> & {Add#E: mut E24_189..E24_190}) <: ((Lit<> & α47_195) | ((Add<> & α51_197) & ~(Lit<>))) +//│ | α47_195 <: {n: n48_196} +//│ | n48_196 <: int +//│ | α51_197 :> (Add<> & {Add#E: mut E24_189..E24_190}) <: {rhs: rhs54_198} & {lhs: lhs52_199} +//│ | rhs54_198 :> Lit<> <: rhs54_172 +//│ | lhs52_199 :> Lit<> <: lhs52_178 +//│ | add2negadd11209'# := α215' +//│ | A205_214' :> (Add<> & {Add#E: mut E24_35'..E24_35'}) | α34_191 +//│ | α215' :> (Add<> & {Add#E: mut E24_216'..E24_216'}) <: add2negadd11209'# +//│ | E24_216' :> (Neg<> & {Neg#A: mut A205_214'..A205_214'}) | Lit<> //│ [pretty-printed] add2negadd11: Add & {Add#E = 'E} //│ | where //│ | 'E :> Lit | Neg & {Neg#A = 'A} @@ -105,22 +105,22 @@ mixin EvalNeg { else super.eval(e) } //│ mixin EvalNeg -//│ this: this249' -//│ | this249' <: {eval: eval258_259'} -//│ | eval258_259' <: ((‹∀ 2. expr255_261'''›,) -> α260_263') -//│ | expr255_261''' :> expr255_262' -//│ | α260_263' <: int -//│ super: super250' -//│ | super250' <: {eval: eval266_267'} -//│ | eval266_267' <: ((α265_269',) -> α268_270') -//│ fun eval: ‹∀ 1. eval252''#› where -//│ | eval252''# := (α253'' -> (α264'' | α268'')) -//│ | α253'' <: ((Neg<> & α254'') | (α265'' & ~(Neg<>))) -//│ | α254'' <: {expr: expr255_256''} -//│ | expr255_256'' <: expr255_262' -//│ | α264'' :> int -//│ | α265'' <: α265_269' -//│ | α268'' :> α268_270' +//│ this: this252' +//│ | this252' <: {eval: eval261_262'} +//│ | eval261_262' <: ((‹∀ 2. expr258_264'''›,) -> α263_266') +//│ | expr258_264''' :> expr258_265' +//│ | α263_266' <: int +//│ super: super253' +//│ | super253' <: {eval: eval269_270'} +//│ | eval269_270' <: ((α268_272',) -> α271_273') +//│ fun eval: ‹∀ 1. eval255''#› where +//│ | eval255''# := (α256'' -> (α267'' | α271'')) +//│ | α256'' <: ((Neg<> & α257'') | (α268'' & ~(Neg<>))) +//│ | α257'' <: {expr: expr258_259''} +//│ | expr258_259'' <: expr258_265' +//│ | α267'' :> int +//│ | α268'' <: α268_272' +//│ | α271'' :> α271_273' //│ [pretty-printed] eval: (Neg & {expr: anything} | ~Neg) -> int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 6488846b04..ea97f8ea77 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -21,8 +21,8 @@ class Some(value: A) { let s = Some(1) //│ fun s: ‹∀ 0. s33'#› where //│ | s33'# := α39' -//│ | A23_36' :> 1 -//│ | α39' :> (Some<> & {Some#A: mut A23_36'..A23_36'}) <: s33'# +//│ | α39' :> (Some<> & {Some#A: mut A23_40'..A23_40'}) <: s33'# +//│ | A23_40' :> 1 //│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 @@ -57,11 +57,11 @@ module None { // fun mapBad(f) = None // TODO } //│ class None -//│ fun get: ‹∀ 1. get92''#› where -//│ | get92''# := ⊥ +//│ fun get: ‹∀ 1. get93''#› where +//│ | get93''# := ⊥ //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray93''#› where -//│ | toArray93''# := () +//│ fun toArray: ‹∀ 1. toArray94''#› where +//│ | toArray94''# := () //│ [pretty-printed] toArray: () @@ -76,10 +76,10 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ fun opt: ‹∀ 0. opt103'#› where -//│ | opt103'# := (α110' | None<>) -//│ | A23_107' :> 123 -//│ | α110' :> (Some<> & {Some#A: mut A23_107'..A23_107'}) +//│ fun opt: ‹∀ 0. opt104'#› where +//│ | opt104'# := (α111' | None<>) +//│ | α111' :> (Some<> & {Some#A: mut A23_112'..A23_112'}) +//│ | A23_112' :> 123 //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> 123 @@ -106,22 +106,22 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ‹∀ 0. map163'#› where -//│ | map163'# := ((α164', α165',) -> (None<> | α176')) -//│ | α164' <: ((None<> & α166') | ((Some<> & α167') & ~(None<>))) -//│ | α165' <: ((‹∀ 1. value168''›,) -> α175') -//│ | α167' <: {value: value168_169'} -//│ | value168'' :> value168_169' -//│ | α175' <: A23_172' -//│ | α176' :> (Some<> & {Some#A: mut A23_172'..A23_172'}) +//│ fun map: ‹∀ 0. map165'#› where +//│ | map165'# := ((α166', α167',) -> (None<> | α178')) +//│ | α166' <: ((None<> & α168') | ((Some<> & α169') & ~(None<>))) +//│ | α167' <: ((‹∀ 1. value170''›,) -> α177') +//│ | α169' <: {value: value170_171'} +//│ | value170'' :> value170_171' +//│ | α177' <: A23_179' +//│ | α178' :> (Some<> & {Some#A: mut A23_179'..A23_179'}) //│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) let mo = map(opt, succ) -//│ fun mo: ‹∀ 0. mo192'#› where -//│ | A23_172' :> int -//│ | α176' :> (Some<> & {Some#A: mut A23_172'..A23_172'}) -//│ | mo192'# := α193' -//│ | α193' :> (None<> | α176') <: mo192'# +//│ fun mo: ‹∀ 0. mo195'#› where +//│ | α178' :> (Some<> & {Some#A: mut A23_179'..A23_179'}) +//│ | A23_179' :> int +//│ | mo195'# := α196' +//│ | α196' :> (None<> | α178') <: mo195'# //│ [pretty-printed] mo: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> int @@ -135,9 +135,9 @@ class Test(n) { fun foo = n + 1 } //│ class Test -//│ fun foo: ‹∀ 1. foo231''#› where -//│ | foo231''# := α233'' -//│ | α233'' :> int <: foo231''# +//│ fun foo: ‹∀ 1. foo234''#› where +//│ | foo234''# := α236'' +//│ | α236'' :> int <: foo234''# //│ [pretty-printed] foo: int Test(1) @@ -174,28 +174,34 @@ class Test(n: A) { //│ ║ l.164: class Test(n: A) { //│ ╙── ^ //│ class Test -//│ fun foo: ‹∀ 1. foo249''#› where -//│ | foo249''# := α251'' -//│ | α251'' :> error<> | int <: foo249''# +//│ fun foo: ‹∀ 1. foo254''#› where +//│ | foo254''# := α256'' +//│ | α256'' :> error<> | int <: foo254''# //│ [pretty-printed] foo: error | int Test(1) -//│ Typed: Test & {Test#A :> 'A <: 1 | 'A} +//│ Typed: Test & {Test#A = 'A} +//│ where +//│ 'A :> 1 Test(true) -//│ Typed: Test & {Test#A :> 'A <: 'A | true} +//│ Typed: Test & {Test#A = 'A} +//│ where +//│ 'A :> true class Test(n: A) { fun foo: A = n } //│ class Test -//│ fun foo: ‹∀ 1. foo279''#› where -//│ | foo279''# := ‘A275' +//│ fun foo: ‹∀ 1. foo280''#› where +//│ | foo280''# := ‘A276' //│ [pretty-printed] foo: A Test(1) -//│ Typed: Test & {Test#A :> 'A <: 1 | 'A} +//│ Typed: Test & {Test#A = 'A} +//│ where +//│ 'A :> 1 Test(1).foo //│ Typed: 1 @@ -211,21 +217,21 @@ class Test { fun foo2(x : A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.211: fun foo2(x : A) = x + 1 +//│ ║ l.217: fun foo2(x : A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.211: fun foo2(x : A) = x + 1 +//│ ║ l.217: fun foo2(x : A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.208: class Test { +//│ ║ l.214: class Test { //│ ╙── ^ //│ class Test -//│ fun foo1: ‹∀ 1. foo1328''#› where -//│ | foo1328''# := (‘A323' -> ‘A323') +//│ fun foo1: ‹∀ 1. foo1323''#› where +//│ | foo1323''# := (‘A318' -> ‘A318') //│ [pretty-printed] foo1: A -> A -//│ fun foo2: ‹∀ 1. foo2329''#› where -//│ | foo2329''# := (‘A323' -> α331'') -//│ | α331'' :> error<> | int +//│ fun foo2: ‹∀ 1. foo2324''#› where +//│ | foo2324''# := (‘A318' -> α326'') +//│ | α326'' :> error<> | int //│ [pretty-printed] foo2: A -> (error | int) Test().foo1 @@ -237,178 +243,24 @@ Test().foo1(1) x => Test().foo1(x) //│ Typed: 'a -> 'a -:d let t = Test() -//│ 0. Typing TypingUnit(List(let t = Test ())) -//│ Completing let t = Test () -//│ | 1. Typing term Test () -//│ | | 1. Typing term Test -//│ | | | (>>,0,1) -//│ | | 1. : (() -> (Test<> & {Test#A: mut A323_405'..A323_405'})) -//│ | | CONSTRAIN (() -> (Test<> & {Test#A: mut A323_405'..A323_405'})) α409') -//│ | | where -//│ | | 1. C (() -> (Test<> & {Test#A: mut A323_405'..A323_405'})) α409') (0) -//│ | | | 1. C () & {Test#A: mut A323_405'..A323_405'}) (Test<> & {Test#A: mut A323_405'..A323_405'}) -//│ | 1. C α409' & {Test#A: mut A323_405'..A323_405'}) (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# -//│ fun t: ‹∀ 0. t402'#› where -//│ | t402'# := α409' -//│ | α409' :> (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# +//│ fun t: ‹∀ 0. t393'#› where +//│ | t393'# := α400' +//│ | α400' :> ‹∀ 0. (Test<> & {Test#A: mut A318_396'..A318_396'})› <: t393'# //│ [pretty-printed] t: Test & {Test#A = 'A} -:d -t -//│ 0. Typing TypingUnit(List(t)) -//│ | 0. Typing term t -//│ | 0. : t402'# -//│ ⬤ Typed as: ‹∀ 0. t402'#› -//│ where: -//│ t402'# := α409' -//│ α409' :> (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# -//│ Typed: Test & {Test#A = 'A} - -:d t.foo1 -//│ 0. Typing TypingUnit(List((t).foo1)) -//│ | 0. Typing term (t).foo1 -//│ | | 0. Typing term t -//│ | | 0. : t402'# -//│ | | CONSTRAIN t402'# (Test<> & {Test#A: mut A323_405'..A323_405'}) <: t402'# -//│ | | 0. C t402'# & {Test#A: mut A323_405'..A323_405'}) {Test#A: mut A323_405'..A323_405'}) {Test#A: mut A323_405'..A323_405'} <: DNF(0, {foo1: foo1420}) -//│ | | | | | | Possible: List({foo1: foo1420}) -//│ | | | | | | 0. A Test<>{Test#A: mut A323_405'..A323_405'} % List() {Test#A: mut A323_405'..A323_405'} % List() {Test#A: mut A323_405'..A323_405'} % List() A421' -//│ | | | | | | | | | (>>,0,0) -//│ | | | | | | | | | Looking up foo1 in TypeName(Test) -//│ | | | | | | | | | Looked up ‹∀ 1. foo1328_423''#› where -//│ A421'# := A323_405'..A323_405' -//│ foo1328_423''# := (A421'# -> A421'#) -//│ | | | | | | | | | 0. C ‹∀ 1. foo1328_423''#› ‹∀ 1. foo1328_427''#› to 0 -//│ | | | | | | | | | | where -//│ foo1328_427''# := (A421_428' -> A421_428') -//│ A421_428' :> A323_429 <: A323_430 -//│ A323_429 <: A323_430 -//│ A323_430 <: A323_429 -//│ | | | | | | | | | | 0. C ‹∀ 1. foo1328_427''#› A421_433) A421_432) (5) -//│ | | | | | | | | | | | | | 0. C (A421_433,) ‹∀ 1. foo1328_431''› to 0 -//│ | | | | | | | | | | | where -//│ A323_429 <: A421_432 & A323_430 -//│ A323_430 <: A323_429 -//│ foo1328_431'' :> (A421_432 -> A421_433) <: (A421_433 -> A421_432) -//│ A421_432 <: A323_430 -//│ A421_433 :> A421_432 | A323_429 <: A421_432 -//│ | | | | | | | | | | | 0. C ‹∀ 1. foo1328_431''› ‹∀ 1. foo1328_431''› -//│ A323_429 <: A421_432 & A323_430 -//│ A323_430 <: A323_429 -//│ foo1328_431'' :> (A421_432 -> A421_433) <: (A421_433 -> A421_432) -//│ A421_432 <: A323_430 -//│ A421_433 :> A421_432 | A323_429 <: A421_432 //│ Typed: 'A -> 'A [t.foo1(0), t.foo1(true)] -//│ Typed: (0 | true, 0 | true,) +//│ Typed: (0, true,) t.foo1(0) -//│ Typed: 0 | true +//│ Typed: 0 -:d t -//│ 0. Typing TypingUnit(List(t)) -//│ | 0. Typing term t -//│ | 0. : t402'# -//│ ⬤ Typed as: ‹∀ 0. t402'#› -//│ where: -//│ t402'# := α409' -//│ A323_405' :> A323_486 | A323_468 | A323_452 | A323_430 <: A323_485 & A323_467 & A323_451 & A323_429 -//│ α409' :> (Test<> & {Test#A: mut A323_405'..A323_405'}) <: {foo1: foo1476} & {foo1: foo1458} & {foo1: foo1442} & {foo1: foo1420} & t402'# -//│ foo1420 :> ‹∀ 1. foo1328_431''› -//│ A323_429 :> 0 | true | true | 0 | 0 <: A421_432 & A323_430 -//│ A323_430 :> 0 | true | true | 0 | 0 <: α490 & A477_488 & A323_486 & α472 & A459_470 & A323_468 & α456 & A443_454 & A323_452 & A323_429 -//│ foo1328_431'' :> (A421_432 -> A421_433) <: (A421_433 -> A421_432) -//│ A421_432 :> 0 | true | true | 0 | 0 <: A323_430 -//│ A421_433 :> A421_432 | A323_429 <: A421_432 -//│ foo1442 :> ‹∀ 1. foo1328_453''› <: ((0,) -> α456) -//│ A323_451 :> 0 | true | true | 0 | 0 | A323_430 <: α456 & A443_454 & A323_452 -//│ A323_452 :> 0 | true | true | 0 | 0 <: α490 & A477_488 & A323_486 & α472 & A459_470 & A323_468 & A323_451 & A323_429 -//│ foo1328_453'' :> (A443_454 -> A443_455) <: (A443_455 -> A443_454) -//│ A443_454 :> 0 | true | true | 0 | 0 <: α456 & A323_452 -//│ A443_455 :> A443_454 | A323_451 <: α456 & A443_454 -//│ α456 :> 0 | true | true | 0 | 0 -//│ foo1458 :> ‹∀ 1. foo1328_469''› <: ((true,) -> α472) -//│ A323_467 :> 0 | true | true | 0 | A323_452 | A323_430 <: α472 & A459_470 & A323_468 -//│ A323_468 :> 0 | true | true | 0 <: α490 & A477_488 & A323_486 & A323_467 & A323_451 & A323_429 -//│ foo1328_469'' :> (A459_470 -> A459_471) <: (A459_471 -> A459_470) -//│ A459_470 :> 0 | true | true | 0 <: α472 & A323_468 -//│ A459_471 :> A459_470 | A323_467 <: α472 & A459_470 -//│ α472 :> 0 | true | 0 | true -//│ foo1476 :> ‹∀ 1. foo1328_487''› <: ((0,) -> α490) -//│ A323_485 :> 0 | true | A323_468 | A323_452 | A323_430 <: α490 & A477_488 & A323_486 -//│ A323_486 :> 0 | true <: A323_485 & A323_467 & A323_451 & A323_429 -//│ foo1328_487'' :> (A477_488 -> A477_489) <: (A477_489 -> A477_488) -//│ A477_488 :> true | 0 <: α490 & A323_486 -//│ A477_489 :> A477_488 | A323_485 <: α490 & A477_488 -//│ α490 :> 0 | true -//│ Typed: Test & {Test#A = 'A & 'A0} -//│ where -//│ 'A :> 0 | true -//│ <: 'A0 -//│ 'A0 <: 'A +//│ Typed: Test & {Test#A = 'A} + // FIXME fun foo(x : Test) = x.foo1 diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index b69bfde1a1..71facaa529 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -16,6 +16,7 @@ fun fooo(x) = C(0, x) //│ fun fooo: ‹∀ 0. fooo26'#› where //│ | fooo26'# := (α27' -> α35') +//│ | α27' <: z30_37' //│ | α35' :> C<> //│ [pretty-printed] fooo: anything -> C @@ -28,14 +29,14 @@ module Test0_2 { fun b = 123 } //│ class Test0_1 -//│ fun a: ‹∀ 1. a44''#› where -//│ | a44''# := b49'' -//│ | b48''# := 123 -//│ | b49'' :> ‹∀ 1. b48''#› <: a44''# +//│ fun a: ‹∀ 1. a47''#› where +//│ | a47''# := b52'' +//│ | b51''# := 123 +//│ | b52'' :> ‹∀ 1. b51''#› <: a47''# //│ [pretty-printed] a: 123 //│ class Test0_2 -//│ fun b: ‹∀ 1. b48''#› where -//│ | b48''# := 123 +//│ fun b: ‹∀ 1. b51''#› where +//│ | b51''# := 123 //│ [pretty-printed] b: 123 Test0_1.a @@ -50,23 +51,23 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.46: module Test1_1 { +//│ ║ l.47: module Test1_1 { //│ ║ ^^^^^^^^^ -//│ ║ l.47: fun a = Test1_2.b +//│ ║ l.48: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.48: } +//│ ║ l.49: } //│ ╙── ^ //│ class Test1_1 -//│ fun a: ‹∀ 1. a66''#› where -//│ | a66''# := b72'' -//│ | b70''# := a71'' -//│ | a71'' :> error<> <: b70''# -//│ | b72'' :> ‹∀ 1. b70''#› <: a66''# +//│ fun a: ‹∀ 1. a69''#› where +//│ | a69''# := b75'' +//│ | b73''# := a74'' +//│ | a74'' :> error<> <: b73''# +//│ | b75'' :> ‹∀ 1. b73''#› <: a69''# //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun b: ‹∀ 1. b70''#› where -//│ | b70''# := a71'' -//│ | a71'' :> error<> <: b70''# +//│ fun b: ‹∀ 1. b73''#› where +//│ | b73''# := a74'' +//│ | a74'' :> error<> <: b73''# //│ [pretty-printed] b: error Test1_1.a @@ -86,60 +87,60 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.77: module Test2_1 { +//│ ║ l.78: module Test2_1 { //│ ║ ^^^^^^^^^ -//│ ║ l.78: fun t2 = Test2_2 +//│ ║ l.79: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.79: fun a = Test2_2.b +//│ ║ l.80: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.80: fun d = Test2_2.e +//│ ║ l.81: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.81: fun n = 456 +//│ ║ l.82: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.82: } +//│ ║ l.83: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.77: module Test2_1 { +//│ ║ l.78: module Test2_1 { //│ ║ ^^^^^^^^^ -//│ ║ l.78: fun t2 = Test2_2 +//│ ║ l.79: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.79: fun a = Test2_2.b +//│ ║ l.80: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.80: fun d = Test2_2.e +//│ ║ l.81: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.81: fun n = 456 +//│ ║ l.82: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.82: } +//│ ║ l.83: } //│ ╙── ^ //│ class Test2_1 -//│ fun t2: ‹∀ 1. t295''#› where -//│ | t295''# := Test2_2<> +//│ fun t2: ‹∀ 1. t298''#› where +//│ | t298''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a106''#› where -//│ | b101''# := 123 -//│ | a106''# := b107'' -//│ | b107'' :> ‹∀ 1. b101''#› <: a106''# +//│ fun a: ‹∀ 1. a109''#› where +//│ | b104''# := 123 +//│ | a109''# := b110'' +//│ | b110'' :> ‹∀ 1. b104''#› <: a109''# //│ [pretty-printed] a: 123 -//│ fun d: ‹∀ 1. d111''#› where -//│ | e104''# := n105'' -//│ | n105'' :> error<> <: e104''# -//│ | d111''# := e112'' -//│ | e112'' :> ‹∀ 1. e104''#› <: d111''# +//│ fun d: ‹∀ 1. d114''#› where +//│ | e107''# := n108'' +//│ | n108'' :> error<> <: e107''# +//│ | d114''# := e115'' +//│ | e115'' :> ‹∀ 1. e107''#› <: d114''# //│ [pretty-printed] d: error -//│ fun n: ‹∀ 1. n116''#› where -//│ | n116''# := 456 +//│ fun n: ‹∀ 1. n119''#› where +//│ | n119''# := 456 //│ [pretty-printed] n: 456 //│ class Test2_2 -//│ fun b: ‹∀ 1. b101''#› where -//│ | b101''# := 123 +//│ fun b: ‹∀ 1. b104''#› where +//│ | b104''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c102''#› where -//│ | c102''# := a103'' -//│ | a103'' :> error<> <: c102''# +//│ fun c: ‹∀ 1. c105''#› where +//│ | c105''# := a106'' +//│ | a106'' :> error<> <: c105''# //│ [pretty-printed] c: error -//│ fun e: ‹∀ 1. e104''#› where -//│ | e104''# := n105'' -//│ | n105'' :> error<> <: e104''# +//│ fun e: ‹∀ 1. e107''#› where +//│ | e107''# := n108'' +//│ | n108'' :> error<> <: e107''# //│ [pretty-printed] e: error Test2_1.t2.b From f38ddf9fedbc1a05753828a3060025b874da8ab6 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 15:38:09 +0800 Subject: [PATCH 036/498] WIP make let non-polymorphic --- .../main/scala/mlscript/TyperDatatypes.scala | 22 ++- shared/src/test/diff/nu/BasicClasses.mls | 89 ++++++------ shared/src/test/diff/nu/BasicMixins.mls | 48 ++++--- shared/src/test/diff/nu/ECOOP23.mls | 128 ++++++++---------- shared/src/test/diff/nu/GenericClasses.mls | 103 +++++++------- .../src/test/scala/mlscript/DiffTests.scala | 6 +- 6 files changed, 191 insertions(+), 205 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 9918790513..0755d38768 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -78,13 +78,21 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // TODO check against `tv` TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) case L(body) => - implicit val vars: Map[Str, SimpleType] = - outerVars ++ Map.empty // TODO tparams - implicit val gl: GenLambdas = true - val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) - // implicit val prov: TP = noProv // TODO - // subsume(body_ty, PolymorphicType(level, tv)) // TODO - TypedNuFun(ctx.lvl, fd, body_ty) + // println(fd.isLetRec) + // implicit val vars: Map[Str, SimpleType] = + // outerVars ++ Map.empty // TODO tparams + fd.isLetRec match { + case S(true) => ??? + case S(false) => + implicit val gl: GenLambdas = true + TypedNuFun(ctx.lvl, fd, typeTerm(body)) + case N => + implicit val gl: GenLambdas = true + val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) + // implicit val prov: TP = noProv // TODO + // subsume(body_ty, PolymorphicType(level, tv)) // TODO + TypedNuFun(ctx.lvl, fd, body_ty) + } } // subsume(res_ty, tv) res_ty diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index b49aac664a..12865a4e96 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -46,16 +46,13 @@ class Base0(n) { // Base0 let b1 = Base0(42) -//│ fun b1: ‹∀ 0. b184'#› where -//│ | b184'# := α99' -//│ | α99' :> Base0<> <: b184'# +//│ let b1: α98 where +//│ | α98 :> Base0<> //│ [pretty-printed] b1: Base0 // :d let n1 = b1.n -//│ fun n1: ‹∀ 0. n1104'#› where -//│ | n1104'# := n105' -//│ | n105' <: n1104'# +//│ let n1: n102 where //│ [pretty-printed] n1: nothing // TODO @@ -65,15 +62,10 @@ n1 + 1 let b2 = Base0("hi") let n2 = b2.n -//│ fun b2: ‹∀ 0. b2127'#› where -//│ | b2127'# := α142' -//│ | α142' :> Base0<> <: {n: n145'} & b2127'# -//│ | n2144'# := n145' -//│ | n145' <: n2144'# +//│ let b2: α137 where +//│ | α137 :> Base0<> <: {n: n139} //│ [pretty-printed] b2: Base0 -//│ fun n2: ‹∀ 0. n2144'#› where -//│ | n2144'# := n145' -//│ | n145' <: n2144'# +//│ let n2: n139 where //│ [pretty-printed] n2: nothing @@ -84,18 +76,18 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1170''#› where -//│ | getBase1170''# := Int +//│ fun getBase1: ‹∀ 1. getBase1162''#› where +//│ | getBase1162''# := Int //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase2171''#› where -//│ | getBase2171''# := base172'' -//│ | base172'' :> base172_173' <: getBase2171''# -//│ | base172_173' :> Int +//│ fun getBase2: ‹∀ 1. getBase2163''#› where +//│ | getBase2163''# := base164'' +//│ | base164'' :> base164_165' <: getBase2163''# +//│ | base164_165' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo174''#› where -//│ | foo174''# := (α175'' -> α179'') -//│ | α175'' <: int -//│ | α179'' :> int +//│ fun foo: ‹∀ 1. foo166''#› where +//│ | foo166''# := (α167'' -> α171'') +//│ | α167'' <: int +//│ | α171'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -104,26 +96,25 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1205''#› where -//│ | getBase1205''# := Int +//│ fun getBase1: ‹∀ 1. getBase1197''#› where +//│ | getBase1197''# := Int //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me206''#› where -//│ | this200' :> Base1<> -//│ | me206''# := this200' +//│ fun me: ‹∀ 1. me198''#› where +//│ | this192' :> Base1<> +//│ | me198''# := this192' //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo207''#› where -//│ | foo207''# := (α208'' -> α210'') -//│ | α208'' <: int -//│ | α210'' :> int +//│ fun foo: ‹∀ 1. foo199''#› where +//│ | foo199''# := (α200'' -> α202'') +//│ | α200'' <: int +//│ | α202'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ fun b: ‹∀ 0. b223'#› where -//│ | b223'# := α229' -//│ | α229' :> Base1<> <: b223'# +//│ let b: α220 where +//│ | α220 :> Base1<> //│ [pretty-printed] b: Base1 b.base @@ -139,7 +130,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.140: b.getBaseTypo +//│ ║ l.131: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -153,16 +144,16 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.152: class Rec(n) { +//│ ║ l.143: class Rec(n) { //│ ║ ^^^^^^^^ -//│ ║ l.153: fun go = Rec(n + 1) +//│ ║ l.144: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.154: } +//│ ║ l.145: } //│ ╙── ^ //│ class Rec -//│ fun go: ‹∀ 1. go268''#› where -//│ | go268''# := α271'' -//│ | α271'' :> error<> <: go268''# +//│ fun go: ‹∀ 1. go258''#› where +//│ | go258''# := α261'' +//│ | α261'' :> error<> <: go258''# //│ [pretty-printed] go: error @@ -174,20 +165,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.173: a: int +//│ ║ l.164: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.172: class Annots(base: 0 | 1) { +//│ ║ l.163: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.173: a: int +//│ ║ l.164: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.173: a: int +//│ ║ l.164: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a278''#› where -//│ | a278''# := ((0 | 1),) +//│ fun a: ‹∀ 1. a268''#› where +//│ | a268''# := ((0 | 1),) //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 58bffaab2a..70665951e4 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -201,34 +201,32 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ class WrapBase2 let w = WrapBase2.wrap -//│ fun w: ‹∀ 0. w481'#› where -//│ | w481'# := wrap482' -//│ | wrap482' :> ‹∀ 1. wrap260_496''#› <: w481'# -//│ | wrap260_496''# := (α261_497'' -> (α264_505'',)) -//│ | α261_497'' <: α261_498' -//│ | α261_498' <: α261_499' -//│ | α261_499' <: α261_500' -//│ | α261_500' <: α261_501' -//│ | α261_501' <: α261_502' -//│ | α261_502' <: α242_503' -//│ | α242_503' <: α264_504' -//│ | α264_505'' :> α264_506' -//│ | α264_506' :> ‹∀ 2. (α264_507''',)› -//│ | α264_507''' :> α264_508' -//│ | α264_508' :> ‹∀ 2. (α264_509''',)› -//│ | α264_509''' :> α264_504' +//│ let w: wrap481 where +//│ | wrap481 :> ‹∀ 1. wrap260_495''#› +//│ | wrap260_495''# := (α261_496'' -> (α264_504'',)) +//│ | α261_496'' <: α261_497 +//│ | α261_497 <: α261_498 +//│ | α261_498 <: α261_499 +//│ | α261_499 <: α261_500 +//│ | α261_500 <: α261_501 +//│ | α261_501 <: α242_502 +//│ | α242_502 <: α264_503 +//│ | α264_504'' :> α264_505 +//│ | α264_505 :> ‹∀ 2. (α264_506''',)› +//│ | α264_506''' :> α264_507 +//│ | α264_507 :> ‹∀ 2. (α264_508''',)› +//│ | α264_508''' :> α264_503 //│ [pretty-printed] w: 'a -> ((('a,),),) let wd = w(1) -//│ fun wd: ‹∀ 0. wd529'#› where -//│ | α264_504' :> 1 -//│ | α264_506' :> ‹∀ 2. (α264_507''',)› -//│ | α264_507''' :> α264_508' -//│ | α264_508' :> ‹∀ 2. (α264_509''',)› -//│ | α264_509''' :> α264_504' -//│ | wd529'# := α530' -//│ | α530' :> ‹∀ 2. (α264_531''',)› <: wd529'# -//│ | α264_531''' :> α264_506' +//│ let wd: α527 where +//│ | α264_503 :> 1 +//│ | α264_505 :> ‹∀ 2. (α264_506''',)› +//│ | α264_506''' :> α264_507 +//│ | α264_507 :> ‹∀ 2. (α264_508''',)› +//│ | α264_508''' :> α264_503 +//│ | α527 :> ‹∀ 2. (α264_528''',)› +//│ | α264_528''' :> α264_505 //│ [pretty-printed] wd: (((1,),),) wd._1._1._1 + 1 diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index a4c26ecfb1..789371045f 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -9,10 +9,9 @@ class Lit(n: int) //│ class Lit let add11 = Add(Lit(1), Lit(2)) -//│ fun add11: ‹∀ 0. add1130'#› where -//│ | add1130'# := α34' -//│ | α34' :> (Add<> & {Add#E: mut E24_35'..E24_35'}) <: add1130'# -//│ | E24_35' :> Lit<> +//│ let add11: α33 where +//│ | α33 :> (Add<> & {Add#E: mut E24_34..E24_34}) +//│ | E24_34 :> Lit<> //│ [pretty-printed] add11: Add & {Add#E = 'E} //│ | where //│ | 'E :> Lit @@ -25,24 +24,24 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase -//│ this: this42' -//│ | this42' <: {eval: eval63_64'} & {eval: eval56_57'} -//│ | eval56_57' <: ((‹∀ 2. lhs52_59'''›,) -> α58_61') -//│ | lhs52_59''' :> lhs52_60' -//│ | α58_61' <: int -//│ | eval63_64' <: ((‹∀ 2. rhs54_66'''›,) -> α65_68') -//│ | rhs54_66''' :> rhs54_67' -//│ | α65_68' <: int -//│ super: super43' -//│ fun eval: ‹∀ 1. eval45''#› where -//│ | eval45''# := (α46'' -> (Int | α69'')) -//│ | α46'' <: ((Lit<> & α47'') | ((Add<> & α51'') & ~(Lit<>))) -//│ | α47'' <: {n: n48_49''} -//│ | n48_49'' <: int -//│ | α51'' <: {rhs: rhs54_55''} & {lhs: lhs52_53''} -//│ | lhs52_53'' <: lhs52_60' -//│ | rhs54_55'' <: rhs54_67' -//│ | α69'' :> int +//│ this: this40' +//│ | this40' <: {eval: eval61_62'} & {eval: eval54_55'} +//│ | eval54_55' <: ((‹∀ 2. lhs50_57'''›,) -> α56_59') +//│ | lhs50_57''' :> lhs50_58' +//│ | α56_59' <: int +//│ | eval61_62' <: ((‹∀ 2. rhs52_64'''›,) -> α63_66') +//│ | rhs52_64''' :> rhs52_65' +//│ | α63_66' <: int +//│ super: super41' +//│ fun eval: ‹∀ 1. eval43''#› where +//│ | eval43''# := (α44'' -> (Int | α67'')) +//│ | α44'' <: ((Lit<> & α45'') | ((Add<> & α49'') & ~(Lit<>))) +//│ | α45'' <: {n: n46_47''} +//│ | n46_47'' <: int +//│ | α49'' <: {rhs: rhs52_53''} & {lhs: lhs50_51''} +//│ | lhs50_51'' <: lhs50_58' +//│ | rhs52_53'' <: rhs52_65' +//│ | α67'' :> int //│ [pretty-printed] eval: (Add & {lhs: anything, rhs: anything} | Lit & {n: int}) -> int @@ -62,40 +61,31 @@ class Neg(expr: A) //│ class Neg let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ fun add2negadd11: ‹∀ 0. add2negadd11209'#› where -//│ | E24_35' :> E24_189 | Lit<> <: E24_190 -//│ | rhs54_172 :> Lit<> <: ((Lit<> & α47_173) | ((Add<> & α51_175) & ~(Lit<>))) -//│ | α47_173 :> Lit<> <: {n: n48_174} -//│ | n48_174 :> Int <: int -//│ | α51_175 <: {rhs: rhs54_176} & {lhs: lhs52_177} -//│ | rhs54_176 <: rhs54_172 -//│ | lhs52_177 <: lhs52_178 -//│ | lhs52_178 :> Lit<> <: ((Lit<> & α47_179) | ((Add<> & α51_181) & ~(Lit<>))) -//│ | α47_179 :> Lit<> <: {n: n48_180} -//│ | n48_180 :> Int <: int -//│ | α51_181 <: {rhs: rhs54_182} & {lhs: lhs52_183} -//│ | rhs54_182 <: rhs54_172 -//│ | lhs52_183 <: lhs52_178 -//│ | add1130_187' :> (Add<> & {Add#E: mut E24_189..E24_190}) | α34_188 <: add1130_192 & α34_191 -//│ | α34_188 :> (Add<> & {Add#E: mut E24_189..E24_190}) | (Add<> & {Add#E: mut E24_189..E24_190}) <: α46_194 & α34_191 -//│ | E24_189 <: lhs52_199 & rhs54_198 -//│ | E24_190 :> E24_189 | Lit<> <: lhs52_199 & rhs54_198 -//│ | α34_191 :> (Add<> & {Add#E: mut E24_189..E24_190}) <: α34_188 & add1130_187' -//│ | add1130_192 :> (Add<> & {Add#E: mut E24_189..E24_190}) | α34_188 <: α46_194 -//│ | α46_194 :> (Add<> & {Add#E: mut E24_189..E24_190}) <: ((Lit<> & α47_195) | ((Add<> & α51_197) & ~(Lit<>))) -//│ | α47_195 <: {n: n48_196} -//│ | n48_196 <: int -//│ | α51_197 :> (Add<> & {Add#E: mut E24_189..E24_190}) <: {rhs: rhs54_198} & {lhs: lhs52_199} -//│ | rhs54_198 :> Lit<> <: rhs54_172 -//│ | lhs52_199 :> Lit<> <: lhs52_178 -//│ | add2negadd11209'# := α215' -//│ | A205_214' :> (Add<> & {Add#E: mut E24_35'..E24_35'}) | α34_191 -//│ | α215' :> (Add<> & {Add#E: mut E24_216'..E24_216'}) <: add2negadd11209'# -//│ | E24_216' :> (Neg<> & {Neg#A: mut A205_214'..A205_214'}) | Lit<> +//│ let add2negadd11: α206 where +//│ | E24_34 :> Lit<> <: lhs50_191 & rhs52_190 +//│ | rhs52_170 :> Lit<> <: ((Lit<> & α45_171) | ((Add<> & α49_173) & ~(Lit<>))) +//│ | α45_171 :> Lit<> <: {n: n46_172} +//│ | n46_172 :> Int <: int +//│ | α49_173 <: {rhs: rhs52_174} & {lhs: lhs50_175} +//│ | rhs52_174 <: rhs52_170 +//│ | lhs50_175 <: lhs50_176 +//│ | lhs50_176 :> Lit<> <: ((Lit<> & α45_177) | ((Add<> & α49_179) & ~(Lit<>))) +//│ | α45_177 :> Lit<> <: {n: n46_178} +//│ | n46_178 :> Int <: int +//│ | α49_179 <: {rhs: rhs52_180} & {lhs: lhs50_181} +//│ | rhs52_180 <: rhs52_170 +//│ | lhs50_181 <: lhs50_176 +//│ | rhs52_190 :> Lit<> <: rhs52_170 +//│ | lhs50_191 :> Lit<> <: lhs50_176 +//│ | A197_205 :> (Add<> & {Add#E: mut E24_34..E24_34}) +//│ | α206 :> (Add<> & {Add#E: mut E24_207..E24_207}) +//│ | E24_207 :> (Neg<> & {Neg#A: mut A197_205..A197_205}) | Lit<> //│ [pretty-printed] add2negadd11: Add & {Add#E = 'E} //│ | where //│ | 'E :> Lit | Neg & {Neg#A = 'A} -//│ | 'A :> Add & {Add#E :> 'lhs & 'E0 <: Lit | 'E0} +//│ | 'A :> Add & {Add#E = 'E0} +//│ | 'E0 :> Lit +//│ | <: 'lhs //│ | 'lhs <: Add & {lhs: 'lhs, rhs: 'lhs} | Lit & {n: int} @@ -105,22 +95,22 @@ mixin EvalNeg { else super.eval(e) } //│ mixin EvalNeg -//│ this: this252' -//│ | this252' <: {eval: eval261_262'} -//│ | eval261_262' <: ((‹∀ 2. expr258_264'''›,) -> α263_266') -//│ | expr258_264''' :> expr258_265' -//│ | α263_266' <: int -//│ super: super253' -//│ | super253' <: {eval: eval269_270'} -//│ | eval269_270' <: ((α268_272',) -> α271_273') -//│ fun eval: ‹∀ 1. eval255''#› where -//│ | eval255''# := (α256'' -> (α267'' | α271'')) -//│ | α256'' <: ((Neg<> & α257'') | (α268'' & ~(Neg<>))) -//│ | α257'' <: {expr: expr258_259''} -//│ | expr258_259'' <: expr258_265' -//│ | α267'' :> int -//│ | α268'' <: α268_272' -//│ | α271'' :> α271_273' +//│ this: this237' +//│ | this237' <: {eval: eval246_247'} +//│ | eval246_247' <: ((‹∀ 2. expr243_249'''›,) -> α248_251') +//│ | expr243_249''' :> expr243_250' +//│ | α248_251' <: int +//│ super: super238' +//│ | super238' <: {eval: eval254_255'} +//│ | eval254_255' <: ((α253_257',) -> α256_258') +//│ fun eval: ‹∀ 1. eval240''#› where +//│ | eval240''# := (α241'' -> (α252'' | α256'')) +//│ | α241'' <: ((Neg<> & α242'') | (α253'' & ~(Neg<>))) +//│ | α242'' <: {expr: expr243_244''} +//│ | expr243_244'' <: expr243_250' +//│ | α252'' :> int +//│ | α253'' <: α253_257' +//│ | α256'' :> α256_258' //│ [pretty-printed] eval: (Neg & {expr: anything} | ~Neg) -> int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index ea97f8ea77..d2034c27c4 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -19,10 +19,9 @@ class Some(value: A) { let s = Some(1) -//│ fun s: ‹∀ 0. s33'#› where -//│ | s33'# := α39' -//│ | α39' :> (Some<> & {Some#A: mut A23_40'..A23_40'}) <: s33'# -//│ | A23_40' :> 1 +//│ let s: α38 where +//│ | α38 :> (Some<> & {Some#A: mut A23_39..A23_39}) +//│ | A23_39 :> 1 //│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 @@ -57,11 +56,11 @@ module None { // fun mapBad(f) = None // TODO } //│ class None -//│ fun get: ‹∀ 1. get93''#› where -//│ | get93''# := ⊥ +//│ fun get: ‹∀ 1. get78''#› where +//│ | get78''# := ⊥ //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray94''#› where -//│ | toArray94''# := () +//│ fun toArray: ‹∀ 1. toArray79''#› where +//│ | toArray79''# := () //│ [pretty-printed] toArray: () @@ -76,10 +75,9 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ fun opt: ‹∀ 0. opt104'#› where -//│ | opt104'# := (α111' | None<>) -//│ | α111' :> (Some<> & {Some#A: mut A23_112'..A23_112'}) -//│ | A23_112' :> 123 +//│ let opt: (α95 | None<>) where +//│ | α95 :> (Some<> & {Some#A: mut A23_96..A23_96}) +//│ | A23_96 :> 123 //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> 123 @@ -106,25 +104,22 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ‹∀ 0. map165'#› where -//│ | map165'# := ((α166', α167',) -> (None<> | α178')) -//│ | α166' <: ((None<> & α168') | ((Some<> & α169') & ~(None<>))) -//│ | α167' <: ((‹∀ 1. value170''›,) -> α177') -//│ | α169' <: {value: value170_171'} -//│ | value170'' :> value170_171' -//│ | α177' <: A23_179' -//│ | α178' :> (Some<> & {Some#A: mut A23_179'..A23_179'}) +//│ fun map: ‹∀ 0. map137'#› where +//│ | map137'# := ((α138', α139',) -> (None<> | α150')) +//│ | α138' <: ((None<> & α140') | ((Some<> & α141') & ~(None<>))) +//│ | α139' <: ((‹∀ 1. value142''›,) -> α149') +//│ | α141' <: {value: value142_143'} +//│ | value142'' :> value142_143' +//│ | α149' <: A23_151' +//│ | α150' :> (Some<> & {Some#A: mut A23_151'..A23_151'}) //│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) let mo = map(opt, succ) -//│ fun mo: ‹∀ 0. mo195'#› where -//│ | α178' :> (Some<> & {Some#A: mut A23_179'..A23_179'}) -//│ | A23_179' :> int -//│ | mo195'# := α196' -//│ | α196' :> (None<> | α178') <: mo195'# -//│ [pretty-printed] mo: None | Some & {Some#A = 'A} -//│ | where -//│ | 'A :> int +//│ let mo: α167 where +//│ | α167 :> (None<> | α150_177) +//│ | α150_177 :> (Some<> & {Some#A: mut A23_178..A23_179}) +//│ | A23_179 :> A23_178 | int +//│ [pretty-printed] mo: None | Some & {Some#A :> 'A <: 'A | int} mo.toArray //│ Typed: Array[int] @@ -135,9 +130,9 @@ class Test(n) { fun foo = n + 1 } //│ class Test -//│ fun foo: ‹∀ 1. foo234''#› where -//│ | foo234''# := α236'' -//│ | α236'' :> int <: foo234''# +//│ fun foo: ‹∀ 1. foo205''#› where +//│ | foo205''# := α207'' +//│ | α207'' :> int <: foo205''# //│ [pretty-printed] foo: int Test(1) @@ -146,16 +141,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.147: Test(true) +//│ ║ l.142: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.147: Test(true) +//│ ║ l.142: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.135: fun foo = n + 1 +//│ ║ l.130: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.134: class Test(n) { +//│ ║ l.129: class Test(n) { //│ ╙── ^ //│ Typed: Test | error @@ -165,18 +160,18 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.165: fun foo = n + 1 +//│ ║ l.160: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.165: fun foo = n + 1 +//│ ║ l.160: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.164: class Test(n: A) { +//│ ║ l.159: class Test(n: A) { //│ ╙── ^ //│ class Test -//│ fun foo: ‹∀ 1. foo254''#› where -//│ | foo254''# := α256'' -//│ | α256'' :> error<> | int <: foo254''# +//│ fun foo: ‹∀ 1. foo225''#› where +//│ | foo225''# := α227'' +//│ | α227'' :> error<> | int <: foo225''# //│ [pretty-printed] foo: error | int Test(1) @@ -194,8 +189,8 @@ class Test(n: A) { fun foo: A = n } //│ class Test -//│ fun foo: ‹∀ 1. foo280''#› where -//│ | foo280''# := ‘A276' +//│ fun foo: ‹∀ 1. foo251''#› where +//│ | foo251''# := ‘A247' //│ [pretty-printed] foo: A Test(1) @@ -217,21 +212,21 @@ class Test { fun foo2(x : A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.217: fun foo2(x : A) = x + 1 +//│ ║ l.212: fun foo2(x : A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.217: fun foo2(x : A) = x + 1 +//│ ║ l.212: fun foo2(x : A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.214: class Test { +//│ ║ l.209: class Test { //│ ╙── ^ //│ class Test -//│ fun foo1: ‹∀ 1. foo1323''#› where -//│ | foo1323''# := (‘A318' -> ‘A318') +//│ fun foo1: ‹∀ 1. foo1294''#› where +//│ | foo1294''# := (‘A289' -> ‘A289') //│ [pretty-printed] foo1: A -> A -//│ fun foo2: ‹∀ 1. foo2324''#› where -//│ | foo2324''# := (‘A318' -> α326'') -//│ | α326'' :> error<> | int +//│ fun foo2: ‹∀ 1. foo2295''#› where +//│ | foo2295''# := (‘A289' -> α297'') +//│ | α297'' :> error<> | int //│ [pretty-printed] foo2: A -> (error | int) Test().foo1 @@ -243,10 +238,10 @@ Test().foo1(1) x => Test().foo1(x) //│ Typed: 'a -> 'a +// :d let t = Test() -//│ fun t: ‹∀ 0. t393'#› where -//│ | t393'# := α400' -//│ | α400' :> ‹∀ 0. (Test<> & {Test#A: mut A318_396'..A318_396'})› <: t393'# +//│ let t: α370 where +//│ | α370 :> ‹∀ 0. (Test<> & {Test#A: mut A289_366'..A289_366'})› //│ [pretty-printed] t: Test & {Test#A = 'A} t.foo1 diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 7cd9310ed7..2421f9ba21 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -512,7 +512,11 @@ class DiffTests showTTU(tm.ttu, ind + 1) case tf: typer.TypedNuFun => val exp = getType(tf.ty) - output(s"${indStr}fun ${tf.name}: ${tf.ty} where ${tf.ty.showBounds + output(s"${indStr}${tf.fd.isLetRec match { + case S(false) => "let" + case S(true) => "let rec" + case N => "fun" + }} ${tf.name}: ${tf.ty} where ${tf.ty.showBounds .indentNewLines(indStr+"|")}") output(s"${indStr}[pretty-printed] ${tf.name}: ${exp.show.indentNewLines(indStr+"|")}") } From b85cd431ff4638169c9d6b099fcf95af8664dc23 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 15:58:20 +0800 Subject: [PATCH 037/498] WIP expand new type refs correctly --- .../src/main/scala/mlscript/NuTypeDefs.scala | 12 ++++- .../main/scala/mlscript/TyperDatatypes.scala | 38 +++++++++++----- shared/src/test/diff/nu/GenericClasses.mls | 44 ++++++++++++++----- 3 files changed, 70 insertions(+), 24 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index d75884bef2..a245b1e1bb 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -30,14 +30,22 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - case class NuParam(nme: Var, ty: FieldType) extends NuMember { + case class NuParam(nme: Var, ty: FieldType, isType: Bool) extends NuMember { def name: Str = nme.name def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuParam = - NuParam(nme, ty.freshenAbove(lim, rigidify)) + NuParam(nme, ty.freshenAbove(lim, rigidify), isType) } + // case class NuTypeParam(nme: TN, ty: FieldType) extends NuMember { + // def name: Str = nme.name + + // def freshenAbove(lim: Int, rigidify: Bool) + // (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + // : NuParam = + // NuParam(nme, ty.freshenAbove(lim, rigidify)) + // } sealed abstract class TypedNuDecl extends NuMember { diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 0755d38768..74731cc121 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -216,9 +216,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => members } val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) - val paramMems = typedParams.map(f => NuParam(f._1, f._2)) + val tparamMems = tparams.map { case (tn, tv) => + val fldNme = td.nme.name + "#" + tn.name + NuParam(Var(fldNme).withLocOf(tn), FieldType(S(tv), tv)(tv.prov), isType = true) + } + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) // val baseMems = inherit(td.parents, baseType, Nil) - val baseMems = inherit(td.parents, baseType, paramMems) + val baseMems = inherit(td.parents, baseType, tparamMems ++ paramMems) // ctx += thisTV @@ -675,14 +679,28 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => TypeRef(defn, targs.map(_.freshenAbove(lim, rigidify)))(prov) def expand(implicit ctx: Ctx): SimpleType = expandWith(paramTags = true) def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = //if (defn.name.isCapitalized) { - ctx.tyDefs2.get(defn.name).map(_.decl match { - case td: NuTypeDef if td.kind is Cls => - ClassTag(Var(td.nme.name).withLocOf(td.nme), - Set.empty//TODO - )(provTODO) - case _ => ??? - } - ).getOrElse { + // ctx.tyDefs2.get(defn.name).map(_.decl match { + // case td: NuTypeDef if td.kind is Cls => + // ClassTag(Var(td.nme.name).withLocOf(td.nme), + // Set.empty//TODO + // )(provTODO) + // case _ => ??? + // } + ctx.tyDefs2.get(defn.name).map { info => + implicit val raise: Raise = throw _ // FIXME + info.complete() match { + case td: TypedNuCls => + assert(td.tparams.size === targs.size) + ClassTag(Var(td.nme.name).withLocOf(td.nme), + Set.empty//TODO + )(provTODO) & RecordType(td.tparams.lazyZip(targs).map { + case ((tn, tv), ta) => + val fldNme = td.td.nme.name + "#" + tn.name + Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) + })(provTODO) + case _ => ??? + } + }.getOrElse { val td = ctx.tyDefs(defn.name) require(targs.size === td.tparamsargs.size) lazy val tparamTags = diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index d2034c27c4..3efcc0ff3c 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -187,11 +187,15 @@ Test(true) class Test(n: A) { fun foo: A = n + fun foo1(x : A) = x } //│ class Test -//│ fun foo: ‹∀ 1. foo251''#› where -//│ | foo251''# := ‘A247' +//│ fun foo: ‹∀ 1. foo252''#› where +//│ | foo252''# := ‘A247' //│ [pretty-printed] foo: A +//│ fun foo1: ‹∀ 1. foo1253''#› where +//│ | foo1253''# := (‘A247' -> ‘A247') +//│ [pretty-printed] foo1: A -> A Test(1) //│ Typed: Test & {Test#A = 'A} @@ -204,6 +208,22 @@ Test(1).foo Test("ok").foo //│ Typed: "ok" +let t = Test(1) +//│ let t: α307 where +//│ | α307 :> (Test<> & {Test#A: mut A247_308..A247_308}) +//│ | A247_308 :> 1 +//│ [pretty-printed] t: Test & {Test#A = 'A} +//│ | where +//│ | 'A :> 1 + +t.foo1(true) +//│ Typed: 1 | true + +t : Test<'a> +//│ Typed: Test['a] +//│ where +//│ 'a :> 1 | true + :e class Test { @@ -212,21 +232,21 @@ class Test { fun foo2(x : A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.212: fun foo2(x : A) = x + 1 +//│ ║ l.232: fun foo2(x : A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.212: fun foo2(x : A) = x + 1 +//│ ║ l.232: fun foo2(x : A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.209: class Test { +//│ ║ l.229: class Test { //│ ╙── ^ //│ class Test -//│ fun foo1: ‹∀ 1. foo1294''#› where -//│ | foo1294''# := (‘A289' -> ‘A289') +//│ fun foo1: ‹∀ 1. foo1339''#› where +//│ | foo1339''# := (‘A334' -> ‘A334') //│ [pretty-printed] foo1: A -> A -//│ fun foo2: ‹∀ 1. foo2295''#› where -//│ | foo2295''# := (‘A289' -> α297'') -//│ | α297'' :> error<> | int +//│ fun foo2: ‹∀ 1. foo2340''#› where +//│ | foo2340''# := (‘A334' -> α342'') +//│ | α342'' :> error<> | int //│ [pretty-printed] foo2: A -> (error | int) Test().foo1 @@ -240,8 +260,8 @@ x => Test().foo1(x) // :d let t = Test() -//│ let t: α370 where -//│ | α370 :> ‹∀ 0. (Test<> & {Test#A: mut A289_366'..A289_366'})› +//│ let t: α415 where +//│ | α415 :> ‹∀ 0. (Test<> & {Test#A: mut A334_411'..A334_411'})› //│ [pretty-printed] t: Test & {Test#A = 'A} t.foo1 From fa02037b63e19a58377f7e9a8464c5641e9ee80f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 16:16:40 +0800 Subject: [PATCH 038/498] WIP fix type def locs + some test cases --- .../src/main/scala/mlscript/NewParser.scala | 3 +- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/test/diff/nu/BasicClasses.mls | 2 +- shared/src/test/diff/nu/BasicMixins.mls | 2 +- shared/src/test/diff/nu/MutualRec.mls | 289 ++++++++++++++---- 5 files changed, 229 insertions(+), 69 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index e530838c2e..411a7bbbf8 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -292,7 +292,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } val ps = parents(if (kind === Als) KEYWORD("=") else KEYWORD(":")) val body = curlyTypingUnit - R(NuTypeDef(kind, tn, tparams, params, ps, body)) + val res = NuTypeDef(kind, tn, tparams, params, ps, body) + R(res.withLoc(S(l0 ++ res.getLoc))) // TODO make `fun` by-name and `let` by-value case (KEYWORD(kwStr @ ("fun" | "let")), l0) :: c => // TODO support rec? diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index e440c90324..5a9f05e432 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -567,7 +567,7 @@ trait Located { def withLocOf(that: Located): this.type = withLoc(that.toLoc) def hasLoc: Bool = origin.isDefined lazy val toLoc: Opt[Loc] = getLoc - private def getLoc: Opt[Loc] = { + private[mlscript] def getLoc: Opt[Loc] = { def subLocs = children.iterator.flatMap(_.toLoc.iterator) if (spanStart < 0) spanStart = subLocs.map(_.spanStart).minOption.getOrElse(return N) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 12865a4e96..86ee0fea97 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -145,7 +145,7 @@ class Rec(n) { } //│ ╔══[ERROR] Cyclic definition //│ ║ l.143: class Rec(n) { -//│ ║ ^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^ //│ ║ l.144: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.145: } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 70665951e4..62b4eb751d 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -71,7 +71,7 @@ Base1(1).test class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.71: class Base1(x): BaseTest -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' //│ ║ l.71: class Base1(x): BaseTest //│ ║ ^^^ diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 71facaa529..41ecb73791 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -3,6 +3,7 @@ :NoJS + class Foo() 123 //│ class Foo @@ -22,6 +23,119 @@ fun fooo(x) = +fun foo = bar +fun bar = foo +//│ fun foo: ‹∀ 0. foo44'#› where +//│ | foo44'# := ‹∀ 0. bar45'#› +//│ | bar45'# := foo44'# +//│ [pretty-printed] foo: nothing +//│ fun bar: ‹∀ 0. bar45'#› where +//│ | foo44'# := ‹∀ 0. bar45'#› +//│ | bar45'# := foo44'# +//│ [pretty-printed] bar: nothing + +foo(bar) +//│ Typed: nothing + + +fun foo = {x: foo} +//│ fun foo: ‹∀ 0. foo57'#› where +//│ | foo57'# := {x: foo57'#} +//│ [pretty-printed] foo: 'foo +//│ | where +//│ | 'foo :> {x: 'foo} + + +fun foo = {x: bar} +fun bar = {y: foo} +//│ fun foo: ‹∀ 0. foo63'#› where +//│ | foo63'# := {x: ‹∀ 0. bar64'#›} +//│ | bar64'# := {y: foo63'#} +//│ [pretty-printed] foo: 'foo +//│ | where +//│ | 'foo :> {x: forall 'foo. {y: 'foo}} +//│ fun bar: ‹∀ 0. bar64'#› where +//│ | foo63'# := {x: ‹∀ 0. bar64'#›} +//│ | bar64'# := {y: foo63'#} +//│ [pretty-printed] bar: 'bar +//│ | where +//│ | 'bar :> {y: {x: forall 'bar. 'bar}} + +// FIXME pretty-printing? +foo +//│ Typed: 'foo +//│ where +//│ 'foo :> {x: forall 'foo. {y: 'foo}} + +:ns +foo +//│ Typed: forall 'foo. 'foo +//│ where +//│ 'foo := {x: forall 'bar 'foo. 'bar} +//│ 'bar := {y: 'foo} + +foo.x +//│ Typed: 'x +//│ where +//│ 'x :> {y: {x: 'x}} + +foo.x.y +//│ Typed: 'foo +//│ where +//│ 'foo :> {x: forall 'foo. {y: 'foo}} + + +// FIXME: + +fun foo(a) = {h: a, t: bar(a)} +fun bar(b) = foo(b) +//│ fun foo: ‹∀ 0. foo94'#› where +//│ | foo94'# := (α95' -> {h: α95', t: α99'}) +//│ | α95' <: α97_101' +//│ | α99' :> ‹∀ 1. α98_100''› +//│ [pretty-printed] foo: 'a -> {h: 'a, t: nothing} +//│ fun bar: ‹∀ 0. bar96'#› where +//│ | α95' <: α97_101' +//│ | bar96'# := (α97' -> α98') +//│ | α97' <: α95' +//│ | α98' :> {h: α95', t: α99'} +//│ | α99' :> ‹∀ 1. α98_100''› +//│ [pretty-printed] bar: 'a -> {h: 'a, t: nothing} + +:ns +foo +//│ Typed: forall 'a 'b 'foo 'c. 'foo +//│ where +//│ 'foo := 'c -> {h: 'c, t: 'a} +//│ 'a :> forall 'd. 'd +//│ 'c <: 'b + + +fun foo(a) = {h1: a, t1: bar(a)} +fun bar(b) = {h2: b, t2: foo(b)} +//│ fun foo: ‹∀ 0. foo120'#› where +//│ | foo120'# := (α121' -> {h1: α121', t1: α125'}) +//│ | α121' <: α123_127' +//│ | α125' :> ‹∀ 1. {h2: α123_127', t2: α124_128''}› +//│ [pretty-printed] foo: 'a -> {h1: 'a, t1: {h2: 'a, t2: nothing}} +//│ fun bar: ‹∀ 0. bar122'#› where +//│ | α121' <: α123_127' +//│ | bar122'# := (α123' -> {h2: α123', t2: α124'}) +//│ | α123' <: α121' +//│ | α124' :> {h1: α121', t1: α125'} +//│ | α125' :> ‹∀ 1. {h2: α123_127', t2: α124_128''}› +//│ [pretty-printed] bar: 'a -> {h2: 'a, t2: {h1: 'a, t1: {h2: 'a, t2: nothing}}} + +:ns +foo +//│ Typed: forall 'foo 'a 'b 'c. 'foo +//│ where +//│ 'foo := 'a -> {h1: 'a, t1: 'b} +//│ 'b :> forall 'd. {h2: 'c, t2: 'd} +//│ 'a <: 'c + + + module Test0_1 { fun a = Test0_2.b } @@ -29,19 +143,36 @@ module Test0_2 { fun b = 123 } //│ class Test0_1 -//│ fun a: ‹∀ 1. a47''#› where -//│ | a47''# := b52'' -//│ | b51''# := 123 -//│ | b52'' :> ‹∀ 1. b51''#› <: a47''# +//│ fun a: ‹∀ 1. a150''#› where +//│ | a150''# := b155'' +//│ | b154''# := 123 +//│ | b155'' :> ‹∀ 1. b154''#› <: a150''# //│ [pretty-printed] a: 123 //│ class Test0_2 -//│ fun b: ‹∀ 1. b51''#› where -//│ | b51''# := 123 +//│ fun b: ‹∀ 1. b154''#› where +//│ | b154''# := 123 //│ [pretty-printed] b: 123 Test0_1.a //│ Typed: 123 +class Test0_1 { + fun a = Test0_2().b +} +class Test0_2() { + fun b = 123 +} +//│ class Test0_1 +//│ fun a: ‹∀ 1. a172''#› where +//│ | a172''# := b179'' +//│ | b176''# := 123 +//│ | b179'' :> ‹∀ 1. b176''#› <: a172''# +//│ [pretty-printed] a: 123 +//│ class Test0_2 +//│ fun b: ‹∀ 1. b176''#› where +//│ | b176''# := 123 +//│ [pretty-printed] b: 123 + :e // TODO module Test1_1 { @@ -51,29 +182,57 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.47: module Test1_1 { -//│ ║ ^^^^^^^^^ -//│ ║ l.48: fun a = Test1_2.b -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.49: } -//│ ╙── ^ +//│ ║ l.178: module Test1_1 { +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.179: fun a = Test1_2.b +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.180: } +//│ ╙── ^ //│ class Test1_1 -//│ fun a: ‹∀ 1. a69''#› where -//│ | a69''# := b75'' -//│ | b73''# := a74'' -//│ | a74'' :> error<> <: b73''# -//│ | b75'' :> ‹∀ 1. b73''#› <: a69''# +//│ fun a: ‹∀ 1. a190''#› where +//│ | a190''# := b196'' +//│ | b194''# := a195'' +//│ | a195'' :> error<> <: b194''# +//│ | b196'' :> ‹∀ 1. b194''#› <: a190''# //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun b: ‹∀ 1. b73''#› where -//│ | b73''# := a74'' -//│ | a74'' :> error<> <: b73''# +//│ fun b: ‹∀ 1. b194''#› where +//│ | b194''# := a195'' +//│ | a195'' :> error<> <: b194''# //│ [pretty-printed] b: error Test1_1.a //│ Typed: error +:e // TODO +class Test1_1 { + fun a = Test1_2().b +} +class Test1_2 { + fun b = Test1_1().a +} +//│ ╔══[ERROR] Cyclic definition +//│ ║ l.209: class Test1_1 { +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.210: fun a = Test1_2().b +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.211: } +//│ ╙── ^ +//│ class Test1_1 +//│ fun a: ‹∀ 1. a216''#› where +//│ | a216''# := b225'' +//│ | b220''# := a222'' +//│ | a222'' :> error<> <: b220''# +//│ | b225'' :> ‹∀ 1. b220''#› <: a216''# +//│ [pretty-printed] a: error +//│ class Test1_2 +//│ fun b: ‹∀ 1. b220''#› where +//│ | b220''# := a222'' +//│ | a222'' :> error<> <: b220''# +//│ [pretty-printed] b: error + + // TODO check TV hygiene module Test2_1 { fun t2 = Test2_2 @@ -87,60 +246,60 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.78: module Test2_1 { -//│ ║ ^^^^^^^^^ -//│ ║ l.79: fun t2 = Test2_2 -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.80: fun a = Test2_2.b -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.81: fun d = Test2_2.e -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.82: fun n = 456 -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.83: } -//│ ╙── ^ +//│ ║ l.237: module Test2_1 { +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.238: fun t2 = Test2_2 +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.239: fun a = Test2_2.b +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.240: fun d = Test2_2.e +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.241: fun n = 456 +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.242: } +//│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.78: module Test2_1 { -//│ ║ ^^^^^^^^^ -//│ ║ l.79: fun t2 = Test2_2 -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.80: fun a = Test2_2.b -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.81: fun d = Test2_2.e -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.82: fun n = 456 -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.83: } -//│ ╙── ^ +//│ ║ l.237: module Test2_1 { +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.238: fun t2 = Test2_2 +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.239: fun a = Test2_2.b +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.240: fun d = Test2_2.e +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.241: fun n = 456 +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.242: } +//│ ╙── ^ //│ class Test2_1 -//│ fun t2: ‹∀ 1. t298''#› where -//│ | t298''# := Test2_2<> +//│ fun t2: ‹∀ 1. t2241''#› where +//│ | t2241''# := Test2_2<> //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a109''#› where -//│ | b104''# := 123 -//│ | a109''# := b110'' -//│ | b110'' :> ‹∀ 1. b104''#› <: a109''# +//│ fun a: ‹∀ 1. a252''#› where +//│ | b247''# := 123 +//│ | a252''# := b253'' +//│ | b253'' :> ‹∀ 1. b247''#› <: a252''# //│ [pretty-printed] a: 123 -//│ fun d: ‹∀ 1. d114''#› where -//│ | e107''# := n108'' -//│ | n108'' :> error<> <: e107''# -//│ | d114''# := e115'' -//│ | e115'' :> ‹∀ 1. e107''#› <: d114''# +//│ fun d: ‹∀ 1. d257''#› where +//│ | e250''# := n251'' +//│ | n251'' :> error<> <: e250''# +//│ | d257''# := e258'' +//│ | e258'' :> ‹∀ 1. e250''#› <: d257''# //│ [pretty-printed] d: error -//│ fun n: ‹∀ 1. n119''#› where -//│ | n119''# := 456 +//│ fun n: ‹∀ 1. n262''#› where +//│ | n262''# := 456 //│ [pretty-printed] n: 456 //│ class Test2_2 -//│ fun b: ‹∀ 1. b104''#› where -//│ | b104''# := 123 +//│ fun b: ‹∀ 1. b247''#› where +//│ | b247''# := 123 //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c105''#› where -//│ | c105''# := a106'' -//│ | a106'' :> error<> <: c105''# +//│ fun c: ‹∀ 1. c248''#› where +//│ | c248''# := a249'' +//│ | a249'' :> error<> <: c248''# //│ [pretty-printed] c: error -//│ fun e: ‹∀ 1. e107''#› where -//│ | e107''# := n108'' -//│ | n108'' :> error<> <: e107''# +//│ fun e: ‹∀ 1. e250''#› where +//│ | e250''# := n251'' +//│ | n251'' :> error<> <: e250''# //│ [pretty-printed] e: error Test2_1.t2.b From d7b85f46bd7aace8e43a64b5b48acb7abee50dfe Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 16:44:20 +0800 Subject: [PATCH 039/498] WIP type unit functions together and monomorphically --- .../src/main/scala/mlscript/NuTypeDefs.scala | 1 + .../main/scala/mlscript/TyperDatatypes.scala | 17 +- shared/src/test/diff/nu/BasicClasses.mls | 123 +++++---- shared/src/test/diff/nu/BasicMixins.mls | 145 +++++------ shared/src/test/diff/nu/ECOOP23.mls | 97 ++++--- shared/src/test/diff/nu/GenericClasses.mls | 112 ++++---- shared/src/test/diff/nu/MutualRec.mls | 239 ++++++++---------- shared/src/test/diff/nu/ParamOverriding.mls | 11 +- 8 files changed, 356 insertions(+), 389 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index a245b1e1bb..683e96e854 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -149,6 +149,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // def freshen(implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, } + /** Note: the type `ty` is stoed *without* its polymorphic wrapper! */ case class TypedNuFun(level: Level, fd: NuFunDef, ty: ST) extends TypedNuDecl with TypedNuTermDef { def name: Str = fd.nme.name } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 74731cc121..c01355a3f8 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -43,7 +43,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val tv: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), N, - S(decl.name))(level) + S(decl.name))(level + 1) def map(f: TypedNuTermDef => TypedNuTermDef): LazyTypeInfo = { val res = new LazyTypeInfo(level, decl) @@ -87,14 +87,28 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => implicit val gl: GenLambdas = true TypedNuFun(ctx.lvl, fd, typeTerm(body)) case N => + /* implicit val gl: GenLambdas = true val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) // implicit val prov: TP = noProv // TODO // subsume(body_ty, PolymorphicType(level, tv)) // TODO TypedNuFun(ctx.lvl, fd, body_ty) + */ + + // * We don't type functions polymorphically from the point of view of a typing unit + // * to avoid cyclic-looking constraints due to the polymorphic recursion limitation, + // * as these functions are allowed to be mutually-recursive. + // * In the future, we should type each mutual-recursion-component independently + // * and polymorphically wrt to non-recursive users of them. + implicit val gl: GenLambdas = false + val body_ty = ctx.nextLevel { implicit ctx: Ctx => + typeTerm(body) + } + TypedNuFun(ctx.lvl, fd, body_ty) } } // subsume(res_ty, tv) + constrain(res_ty.ty, tv) res_ty case td: NuTypeDef => td.kind match { @@ -278,6 +292,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => if (isComputing) decl match { case _: NuFunDef => + println(s"Already computing! Using TV: $tv") tv // TODO FIXME wrong in general (when accessed from difft scope/level) case _ => err(msg"Cyclic definition", decl.toLoc) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 86ee0fea97..3f72ce09ce 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -11,34 +11,33 @@ class Base0(n) { fun oops = this.my } //│ class Base0 -//│ fun me: ‹∀ 1. me30''#› where -//│ | this24' :> Base0<> <: {my: my36_37'} & {n: n32_33'} -//│ | me30''# := this24' -//│ | n32_33' :> n23_65 -//│ | my36_37' :> ‹∀ 1. my31_44''#› -//│ | my31_44''# := n32_45'' -//│ | n32_45'' :> n32_42 <: mine34_46''# & my31_44''# -//│ | mine34_46''# := my31_44''# +//│ fun me: this24' where +//│ | this24' :> Base0<> <: {my: my32_33'} & {n: n30_31'} +//│ | n30_31' :> n23_59 +//│ | my32_33' :> n30_39 +//│ | n30_39 :> n30_37 <: mine28_40 & my27_41 +//│ | mine28_40 :> n30_37 +//│ | my27_41 :> n30_37 //│ [pretty-printed] me: Base0 -//│ fun my: ‹∀ 1. my31''#› where -//│ | my31''# := n32'' -//│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> n23_65 -//│ | mine34''# := my31''# +//│ fun my: n30'' where +//│ | my27'' :> n30_31' +//│ | mine28'' :> n30_31' +//│ | n30'' :> n30_31' <: mine28'' & my27'' +//│ | n30_31' :> n23_59 //│ [pretty-printed] my: nothing -//│ fun mine: ‹∀ 1. mine34''#› where -//│ | my31''# := n32'' -//│ | n32'' :> n32_33' <: mine34''# & my31''# -//│ | n32_33' :> n23_65 -//│ | mine34''# := my31''# +//│ fun mine: n30'' where +//│ | my27'' :> n30_31' +//│ | mine28'' :> n30_31' +//│ | n30'' :> n30_31' <: mine28'' & my27'' +//│ | n30_31' :> n23_59 //│ [pretty-printed] mine: nothing -//│ fun oops: ‹∀ 1. oops35''#› where -//│ | oops35''# := my36'' -//│ | my36'' :> my36_37' <: oops35''# -//│ | my36_37' :> ‹∀ 1. my31_44''#› -//│ | my31_44''# := n32_45'' -//│ | n32_45'' :> n32_42 <: mine34_46''# & my31_44''# -//│ | mine34_46''# := my31_44''# +//│ fun oops: my32'' where +//│ | oops29'' :> my32_33' +//│ | my32'' :> my32_33' <: oops29'' +//│ | my32_33' :> n30_39 +//│ | n30_39 :> n30_37 <: mine28_40 & my27_41 +//│ | mine28_40 :> n30_37 +//│ | my27_41 :> n30_37 //│ [pretty-printed] oops: nothing // :d @@ -46,13 +45,13 @@ class Base0(n) { // Base0 let b1 = Base0(42) -//│ let b1: α98 where -//│ | α98 :> Base0<> +//│ let b1: α85 where +//│ | α85 :> Base0<> //│ [pretty-printed] b1: Base0 // :d let n1 = b1.n -//│ let n1: n102 where +//│ let n1: n89 where //│ [pretty-printed] n1: nothing // TODO @@ -62,10 +61,10 @@ n1 + 1 let b2 = Base0("hi") let n2 = b2.n -//│ let b2: α137 where -//│ | α137 :> Base0<> <: {n: n139} +//│ let b2: α122 where +//│ | α122 :> Base0<> <: {n: n124} //│ [pretty-printed] b2: Base0 -//│ let n2: n139 where +//│ let n2: n124 where //│ [pretty-printed] n2: nothing @@ -76,18 +75,16 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1162''#› where -//│ | getBase1162''# := Int +//│ fun getBase1: Int where //│ [pretty-printed] getBase1: int -//│ fun getBase2: ‹∀ 1. getBase2163''#› where -//│ | getBase2163''# := base164'' -//│ | base164'' :> base164_165' <: getBase2163''# -//│ | base164_165' :> Int +//│ fun getBase2: base146'' where +//│ | getBase2144'' :> base146_147' +//│ | base146'' :> base146_147' <: getBase2144'' +//│ | base146_147' :> Int //│ [pretty-printed] getBase2: int -//│ fun foo: ‹∀ 1. foo166''#› where -//│ | foo166''# := (α167'' -> α171'') -//│ | α167'' <: int -//│ | α171'' :> int +//│ fun foo: (α148'' -> α152'') where +//│ | α148'' <: int +//│ | α152'' :> int //│ [pretty-printed] foo: int -> int class Base1(base: int) { @@ -96,25 +93,22 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1 -//│ fun getBase1: ‹∀ 1. getBase1197''#› where -//│ | getBase1197''# := Int +//│ fun getBase1: Int where //│ [pretty-printed] getBase1: int -//│ fun me: ‹∀ 1. me198''#› where -//│ | this192' :> Base1<> -//│ | me198''# := this192' +//│ fun me: this174' where +//│ | this174' :> Base1<> //│ [pretty-printed] me: Base1 -//│ fun foo: ‹∀ 1. foo199''#› where -//│ | foo199''# := (α200'' -> α202'') -//│ | α200'' <: int -//│ | α202'' :> int +//│ fun foo: (α179'' -> α181'') where +//│ | α179'' <: int +//│ | α181'' :> int //│ [pretty-printed] foo: int -> int Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ let b: α220 where -//│ | α220 :> Base1<> +//│ let b: α198 where +//│ | α198 :> Base1<> //│ [pretty-printed] b: Base1 b.base @@ -130,7 +124,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.131: b.getBaseTypo +//│ ║ l.125: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ Typed: error @@ -144,16 +138,16 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.143: class Rec(n) { +//│ ║ l.137: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.144: fun go = Rec(n + 1) +//│ ║ l.138: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.145: } +//│ ║ l.139: } //│ ╙── ^ //│ class Rec -//│ fun go: ‹∀ 1. go258''#› where -//│ | go258''# := α261'' -//│ | α261'' :> error<> <: go258''# +//│ fun go: α239'' where +//│ | go236'' :> error<> +//│ | α239'' :> error<> <: go236'' //│ [pretty-printed] go: error @@ -165,20 +159,19 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.164: a: int +//│ ║ l.158: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.163: class Annots(base: 0 | 1) { +//│ ║ l.157: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.164: a: int +//│ ║ l.158: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.164: a: int +//│ ║ l.158: a: int //│ ╙── ^^^ //│ class Annots -//│ fun a: ‹∀ 1. a268''#› where -//│ | a268''# := ((0 | 1),) +//│ fun a: ((0 | 1),) where //│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 62b4eb751d..6fb6901ce7 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -10,10 +10,10 @@ mixin BaseTest { //│ mixin BaseTest //│ this: this23' //│ super: super24' -//│ | super24' <: {base: base27_28'} -//│ fun test: ‹∀ 1. test26''#› where -//│ | test26''# := base27'' -//│ | base27'' :> base27_28' <: test26''# +//│ | super24' <: {base: base26_27'} +//│ fun test: base26'' where +//│ | test25'' :> base26_27' +//│ | base26'' :> base26_27' <: test25'' //│ [pretty-printed] test: nothing mixin BaseInc { @@ -21,18 +21,18 @@ mixin BaseInc { fun test2 = this.base } //│ mixin BaseInc -//│ this: this33' -//│ | this33' <: {base: base43_44'} -//│ super: super34' -//│ | super34' <: {base: base38_39'} -//│ | base38_39' <: int -//│ fun test: ‹∀ 1. test37''#› where -//│ | test37''# := α41'' -//│ | α41'' :> int <: test37''# +//│ this: this31' +//│ | this31' <: {base: base39_40'} +//│ super: super32' +//│ | super32' <: {base: base35_36'} +//│ | base35_36' <: int +//│ fun test: α38'' where +//│ | test33'' :> int +//│ | α38'' :> int <: test33'' //│ [pretty-printed] test: int -//│ fun test2: ‹∀ 1. test242''#› where -//│ | test242''# := base43'' -//│ | base43'' :> base43_44' <: test242''# +//│ fun test2: base39'' where +//│ | test234'' :> base39_40' +//│ | base39'' :> base39_40' <: test234'' //│ [pretty-printed] test2: nothing // :d @@ -40,10 +40,9 @@ class Base1(base: int): BaseTest, BaseInc { fun test3 = [base, this.base] } //│ class Base1 -//│ fun test3: ‹∀ 1. test368''#› where -//│ | test368''# := (Int, base69'',) -//│ | base69'' :> base69_70' -//│ | base69_70' :> Int +//│ fun test3: (Int, base64'',) where +//│ | base64'' :> base64_65' +//│ | base64_65' :> Int //│ [pretty-printed] test3: (int, int,) Base1(1).test @@ -70,10 +69,10 @@ Base1(1).test :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.71: class Base1(x): BaseTest +//│ ║ l.70: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.71: class Base1(x): BaseTest +//│ ║ l.70: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -92,15 +91,14 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo -//│ this: this191' -//│ super: super192' -//│ | super192' <: {misc: misc200_201'} & {base: base196_197'} -//│ | base196_197' <: int -//│ fun test: ‹∀ 1. test194''#› where -//│ | test194''# := (α195'' -> (α199'', α195'', misc200'',)) -//│ | α195'' <: int -//│ | α199'' :> int -//│ | misc200'' :> misc200_201' +//│ this: this183' +//│ super: super184' +//│ | super184' <: {misc: misc191_192'} & {base: base187_188'} +//│ | base187_188' <: int +//│ fun test: (α186'' -> (α190'', α186'', misc191'',)) where +//│ | α186'' <: int +//│ | α190'' :> int +//│ | misc191'' :> misc191_192' //│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) module Base1(base: int, misc: string): Foo @@ -117,13 +115,11 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase -//│ this: this236' -//│ super: super237' -//│ fun wrapA: ‹∀ 1. wrapA240''#› where -//│ | wrapA240''# := (Int -> Int) +//│ this: this223' +//│ super: super224' +//│ fun wrapA: (Int -> Int) where //│ [pretty-printed] wrapA: int -> int -//│ fun wrap: ‹∀ 1. wrap241''#› where -//│ | wrap241''# := (α242'' -> α242'') +//│ fun wrap: (α227'' -> α227'') where //│ [pretty-printed] wrap: 'a -> 'a // :d @@ -132,20 +128,18 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ mixin Wrap -//│ this: this249' -//│ super: super250' -//│ | super250' <: {wrap: wrap262_263'} & {wrapA: wrapA255_256'} -//│ | wrapA255_256' <: ((α254_258',) -> α257_259') -//│ | wrap262_263' <: ((α261_265',) -> α264_266') -//│ fun wrapA: ‹∀ 1. wrapA253''#› where -//│ | wrapA253''# := (α254'' -> (α257'',)) -//│ | α254'' <: α254_258' -//│ | α257'' :> α257_259' +//│ this: this232' +//│ super: super233' +//│ | super233' <: {wrap: wrap243_244'} & {wrapA: wrapA237_238'} +//│ | wrapA237_238' <: ((α236_240',) -> α239_241') +//│ | wrap243_244' <: ((α242_246',) -> α245_247') +//│ fun wrapA: (α236'' -> (α239'',)) where +//│ | α236'' <: α236_240' +//│ | α239'' :> α239_241' //│ [pretty-printed] wrapA: anything -> (nothing,) -//│ fun wrap: ‹∀ 1. wrap260''#› where -//│ | wrap260''# := (α261'' -> (α264'',)) -//│ | α261'' <: α261_265' -//│ | α264'' :> α264_266' +//│ fun wrap: (α242'' -> (α245'',)) where +//│ | α242'' <: α242_246' +//│ | α245'' :> α245_247' //│ [pretty-printed] wrap: anything -> (nothing,) @@ -182,16 +176,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.183: WrapBase1.wrapA("ok") +//│ ║ l.177: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.183: WrapBase1.wrapA("ok") +//│ ║ l.177: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.116: fun wrapA(x : int) = x : int +//│ ║ l.114: fun wrapA(x : int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.131: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.127: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ Typed: (int,) | error @@ -201,32 +195,31 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ class WrapBase2 let w = WrapBase2.wrap -//│ let w: wrap481 where -//│ | wrap481 :> ‹∀ 1. wrap260_495''#› -//│ | wrap260_495''# := (α261_496'' -> (α264_504'',)) -//│ | α261_496'' <: α261_497 -//│ | α261_497 <: α261_498 -//│ | α261_498 <: α261_499 -//│ | α261_499 <: α261_500 -//│ | α261_500 <: α261_501 -//│ | α261_501 <: α242_502 -//│ | α242_502 <: α264_503 -//│ | α264_504'' :> α264_505 -//│ | α264_505 :> ‹∀ 2. (α264_506''',)› -//│ | α264_506''' :> α264_507 -//│ | α264_507 :> ‹∀ 2. (α264_508''',)› -//│ | α264_508''' :> α264_503 +//│ let w: wrap418 where +//│ | wrap418 :> (α242_431 -> (α245_439,)) +//│ | α242_431 <: α242_432 +//│ | α242_432 <: α242_433 +//│ | α242_433 <: α242_434 +//│ | α242_434 <: α242_435 +//│ | α242_435 <: α242_436 +//│ | α242_436 <: α227_437 +//│ | α227_437 <: α245_438 +//│ | α245_439 :> α245_440 +//│ | α245_440 :> (α245_441,) +//│ | α245_441 :> α245_442 +//│ | α245_442 :> (α245_443,) +//│ | α245_443 :> α245_438 //│ [pretty-printed] w: 'a -> ((('a,),),) let wd = w(1) -//│ let wd: α527 where -//│ | α264_503 :> 1 -//│ | α264_505 :> ‹∀ 2. (α264_506''',)› -//│ | α264_506''' :> α264_507 -//│ | α264_507 :> ‹∀ 2. (α264_508''',)› -//│ | α264_508''' :> α264_503 -//│ | α527 :> ‹∀ 2. (α264_528''',)› -//│ | α264_528''' :> α264_505 +//│ let wd: α461 where +//│ | α245_438 :> 1 +//│ | α245_439 :> α245_440 +//│ | α245_440 :> (α245_441,) +//│ | α245_441 :> α245_442 +//│ | α245_442 :> (α245_443,) +//│ | α245_443 :> α245_438 +//│ | α461 :> (α245_439,) //│ [pretty-printed] wd: (((1,),),) wd._1._1._1 + 1 diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 789371045f..f1043f5f65 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -25,23 +25,22 @@ mixin EvalBase { } //│ mixin EvalBase //│ this: this40' -//│ | this40' <: {eval: eval61_62'} & {eval: eval54_55'} -//│ | eval54_55' <: ((‹∀ 2. lhs50_57'''›,) -> α56_59') -//│ | lhs50_57''' :> lhs50_58' -//│ | α56_59' <: int -//│ | eval61_62' <: ((‹∀ 2. rhs52_64'''›,) -> α63_66') -//│ | rhs52_64''' :> rhs52_65' -//│ | α63_66' <: int +//│ | this40' <: {eval: eval60_61'} & {eval: eval53_54'} +//│ | eval53_54' <: ((‹∀ 2. lhs49_56'''›,) -> α55_58') +//│ | lhs49_56''' :> lhs49_57' +//│ | α55_58' <: int +//│ | eval60_61' <: ((‹∀ 2. rhs51_63'''›,) -> α62_65') +//│ | rhs51_63''' :> rhs51_64' +//│ | α62_65' <: int //│ super: super41' -//│ fun eval: ‹∀ 1. eval43''#› where -//│ | eval43''# := (α44'' -> (Int | α67'')) -//│ | α44'' <: ((Lit<> & α45'') | ((Add<> & α49'') & ~(Lit<>))) -//│ | α45'' <: {n: n46_47''} -//│ | n46_47'' <: int -//│ | α49'' <: {rhs: rhs52_53''} & {lhs: lhs50_51''} -//│ | lhs50_51'' <: lhs50_58' -//│ | rhs52_53'' <: rhs52_65' -//│ | α67'' :> int +//│ fun eval: (α43'' -> (Int | α66'')) where +//│ | α43'' <: ((Lit<> & α44'') | ((Add<> & α48'') & ~(Lit<>))) +//│ | α44'' <: {n: n45_46''} +//│ | n45_46'' <: int +//│ | α48'' <: {rhs: rhs51_52''} & {lhs: lhs49_50''} +//│ | lhs49_50'' <: lhs49_57' +//│ | rhs51_52'' <: rhs51_64' +//│ | α66'' :> int //│ [pretty-printed] eval: (Add & {lhs: anything, rhs: anything} | Lit & {n: int}) -> int @@ -61,25 +60,18 @@ class Neg(expr: A) //│ class Neg let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: α206 where -//│ | E24_34 :> Lit<> <: lhs50_191 & rhs52_190 -//│ | rhs52_170 :> Lit<> <: ((Lit<> & α45_171) | ((Add<> & α49_173) & ~(Lit<>))) -//│ | α45_171 :> Lit<> <: {n: n46_172} -//│ | n46_172 :> Int <: int -//│ | α49_173 <: {rhs: rhs52_174} & {lhs: lhs50_175} -//│ | rhs52_174 <: rhs52_170 -//│ | lhs50_175 <: lhs50_176 -//│ | lhs50_176 :> Lit<> <: ((Lit<> & α45_177) | ((Add<> & α49_179) & ~(Lit<>))) -//│ | α45_177 :> Lit<> <: {n: n46_178} -//│ | n46_178 :> Int <: int -//│ | α49_179 <: {rhs: rhs52_180} & {lhs: lhs50_181} -//│ | rhs52_180 <: rhs52_170 -//│ | lhs50_181 <: lhs50_176 -//│ | rhs52_190 :> Lit<> <: rhs52_170 -//│ | lhs50_191 :> Lit<> <: lhs50_176 -//│ | A197_205 :> (Add<> & {Add#E: mut E24_34..E24_34}) -//│ | α206 :> (Add<> & {Add#E: mut E24_207..E24_207}) -//│ | E24_207 :> (Neg<> & {Neg#A: mut A197_205..A197_205}) | Lit<> +//│ let add2negadd11: α150 where +//│ | E24_34 :> Lit<> <: lhs49_132 & rhs51_130 +//│ | lhs49_126 :> Lit<> <: ((Lit<> & α44_127) | ((Add<> & α48_129) & ~(Lit<>))) +//│ | α44_127 :> Lit<> <: {n: n45_128} +//│ | n45_128 :> Int <: int +//│ | α48_129 :> (Add<> & {Add#E: mut E24_34..E24_34}) <: {rhs: rhs51_130} & {lhs: lhs49_132} +//│ | rhs51_130 :> Lit<> <: rhs51_131 +//│ | rhs51_131 :> Lit<> <: ((Lit<> & α44_127) | ((Add<> & α48_129) & ~(Lit<>))) +//│ | lhs49_132 :> Lit<> <: lhs49_126 +//│ | A141_149 :> (Add<> & {Add#E: mut E24_34..E24_34}) +//│ | α150 :> (Add<> & {Add#E: mut E24_151..E24_151}) +//│ | E24_151 :> (Neg<> & {Neg#A: mut A141_149..A141_149}) | Lit<> //│ [pretty-printed] add2negadd11: Add & {Add#E = 'E} //│ | where //│ | 'E :> Lit | Neg & {Neg#A = 'A} @@ -95,22 +87,21 @@ mixin EvalNeg { else super.eval(e) } //│ mixin EvalNeg -//│ this: this237' -//│ | this237' <: {eval: eval246_247'} -//│ | eval246_247' <: ((‹∀ 2. expr243_249'''›,) -> α248_251') -//│ | expr243_249''' :> expr243_250' -//│ | α248_251' <: int -//│ super: super238' -//│ | super238' <: {eval: eval254_255'} -//│ | eval254_255' <: ((α253_257',) -> α256_258') -//│ fun eval: ‹∀ 1. eval240''#› where -//│ | eval240''# := (α241'' -> (α252'' | α256'')) -//│ | α241'' <: ((Neg<> & α242'') | (α253'' & ~(Neg<>))) -//│ | α242'' <: {expr: expr243_244''} -//│ | expr243_244'' <: expr243_250' -//│ | α252'' :> int -//│ | α253'' <: α253_257' -//│ | α256'' :> α256_258' +//│ this: this175' +//│ | this175' <: {eval: eval183_184'} +//│ | eval183_184' <: ((‹∀ 2. expr180_186'''›,) -> α185_188') +//│ | expr180_186''' :> expr180_187' +//│ | α185_188' <: int +//│ super: super176' +//│ | super176' <: {eval: eval191_192'} +//│ | eval191_192' <: ((α190_194',) -> α193_195') +//│ fun eval: (α178'' -> (α189'' | α193'')) where +//│ | α178'' <: ((Neg<> & α179'') | (α190'' & ~(Neg<>))) +//│ | α179'' <: {expr: expr180_181''} +//│ | expr180_181'' <: expr180_187' +//│ | α189'' :> int +//│ | α190'' <: α190_194' +//│ | α193'' :> α193_195' //│ [pretty-printed] eval: (Neg & {expr: anything} | ~Neg) -> int @@ -118,9 +109,9 @@ module TestLang: EvalBase, EvalNeg //│ class TestLang TestLang.eval -//│ Typed: 'expr -> int +//│ Typed: 'rhs -> int //│ where -//│ 'expr <: Neg & {expr: 'expr} | (Add & {lhs: 'expr, rhs: 'expr} | Lit & {n: int}) & ~Neg +//│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} | Neg & {expr: 'rhs} TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 3efcc0ff3c..f3f189c6a7 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -10,18 +10,16 @@ class Some(value: A) { // fun map(f : A => 'b) = Some(f(value)) // TODO } //│ class Some -//│ fun get: ‹∀ 1. get28''#› where -//│ | get28''# := ‘A23' +//│ fun get: ‘A23' where //│ [pretty-printed] get: A -//│ fun toArray: ‹∀ 1. toArray29''#› where -//│ | toArray29''# := (‘A23',) +//│ fun toArray: (‘A23',) where //│ [pretty-printed] toArray: (A,) let s = Some(1) -//│ let s: α38 where -//│ | α38 :> (Some<> & {Some#A: mut A23_39..A23_39}) -//│ | A23_39 :> 1 +//│ let s: α32 where +//│ | α32 :> (Some<> & {Some#A: mut A23_33..A23_33}) +//│ | A23_33 :> 1 //│ [pretty-printed] s: Some & {Some#A = 'A} //│ | where //│ | 'A :> 1 @@ -56,11 +54,9 @@ module None { // fun mapBad(f) = None // TODO } //│ class None -//│ fun get: ‹∀ 1. get78''#› where -//│ | get78''# := ⊥ +//│ fun get: ⊥ where //│ [pretty-printed] get: nothing -//│ fun toArray: ‹∀ 1. toArray79''#› where -//│ | toArray79''# := () +//│ fun toArray: () where //│ [pretty-printed] toArray: () @@ -75,9 +71,9 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ let opt: (α95 | None<>) where -//│ | α95 :> (Some<> & {Some#A: mut A23_96..A23_96}) -//│ | A23_96 :> 123 +//│ let opt: (α72 | None<>) where +//│ | α72 :> (Some<> & {Some#A: mut A23_73..A23_73}) +//│ | A23_73 :> 123 //│ [pretty-printed] opt: None | Some & {Some#A = 'A} //│ | where //│ | 'A :> 123 @@ -104,21 +100,20 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ‹∀ 0. map137'#› where -//│ | map137'# := ((α138', α139',) -> (None<> | α150')) -//│ | α138' <: ((None<> & α140') | ((Some<> & α141') & ~(None<>))) -//│ | α139' <: ((‹∀ 1. value142''›,) -> α149') -//│ | α141' <: {value: value142_143'} -//│ | value142'' :> value142_143' -//│ | α149' <: A23_151' -//│ | α150' :> (Some<> & {Some#A: mut A23_151'..A23_151'}) +//│ fun map: ((α106', α107',) -> (None<> | α116')) where +//│ | α106' <: ((None<> & α108') | ((Some<> & α109') & ~(None<>))) +//│ | α107' <: ((‹∀ 1. value110''›,) -> α115') +//│ | α109' <: {value: value110_111'} +//│ | value110'' :> value110_111' +//│ | α115' <: A23_117' +//│ | α116' :> (Some<> & {Some#A: mut A23_117'..A23_117'}) //│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) let mo = map(opt, succ) -//│ let mo: α167 where -//│ | α167 :> (None<> | α150_177) -//│ | α150_177 :> (Some<> & {Some#A: mut A23_178..A23_179}) -//│ | A23_179 :> A23_178 | int +//│ let mo: α132 where +//│ | α132 :> (None<> | α116_140) +//│ | α116_140 :> (Some<> & {Some#A: mut A23_141..A23_142}) +//│ | A23_142 :> A23_141 | int //│ [pretty-printed] mo: None | Some & {Some#A :> 'A <: 'A | int} mo.toArray @@ -130,9 +125,9 @@ class Test(n) { fun foo = n + 1 } //│ class Test -//│ fun foo: ‹∀ 1. foo205''#› where -//│ | foo205''# := α207'' -//│ | α207'' :> int <: foo205''# +//│ fun foo: α165'' where +//│ | foo163'' :> int +//│ | α165'' :> int <: foo163'' //│ [pretty-printed] foo: int Test(1) @@ -141,16 +136,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.142: Test(true) +//│ ║ l.137: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.142: Test(true) +//│ ║ l.137: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.130: fun foo = n + 1 +//│ ║ l.125: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.129: class Test(n) { +//│ ║ l.124: class Test(n) { //│ ╙── ^ //│ Typed: Test | error @@ -160,18 +155,18 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.160: fun foo = n + 1 +//│ ║ l.155: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.160: fun foo = n + 1 +//│ ║ l.155: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.159: class Test(n: A) { +//│ ║ l.154: class Test(n: A) { //│ ╙── ^ //│ class Test -//│ fun foo: ‹∀ 1. foo225''#› where -//│ | foo225''# := α227'' -//│ | α227'' :> error<> | int <: foo225''# +//│ fun foo: α187'' where +//│ | foo185'' :> int | error<> +//│ | α187'' :> error<> | int <: foo185'' //│ [pretty-printed] foo: error | int Test(1) @@ -188,14 +183,15 @@ Test(true) class Test(n: A) { fun foo: A = n fun foo1(x : A) = x + fun id(x) = x } //│ class Test -//│ fun foo: ‹∀ 1. foo252''#› where -//│ | foo252''# := ‘A247' +//│ fun foo: ‘A210' where //│ [pretty-printed] foo: A -//│ fun foo1: ‹∀ 1. foo1253''#› where -//│ | foo1253''# := (‘A247' -> ‘A247') +//│ fun foo1: (‘A210' -> ‘A210') where //│ [pretty-printed] foo1: A -> A +//│ fun id: (α216'' -> α216'') where +//│ [pretty-printed] id: 'a -> 'a Test(1) //│ Typed: Test & {Test#A = 'A} @@ -209,9 +205,9 @@ Test("ok").foo //│ Typed: "ok" let t = Test(1) -//│ let t: α307 where -//│ | α307 :> (Test<> & {Test#A: mut A247_308..A247_308}) -//│ | A247_308 :> 1 +//│ let t: α265 where +//│ | α265 :> (Test<> & {Test#A: mut A210_266..A210_266}) +//│ | A210_266 :> 1 //│ [pretty-printed] t: Test & {Test#A = 'A} //│ | where //│ | 'A :> 1 @@ -224,6 +220,12 @@ t : Test<'a> //│ where //│ 'a :> 1 | true +t.id +//│ Typed: 'a -> 'a + +[t.id(1), t.id(true)] +//│ Typed: (1, true,) + :e class Test { @@ -232,21 +234,19 @@ class Test { fun foo2(x : A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.232: fun foo2(x : A) = x + 1 +//│ ║ l.234: fun foo2(x : A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.232: fun foo2(x : A) = x + 1 +//│ ║ l.234: fun foo2(x : A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.229: class Test { +//│ ║ l.231: class Test { //│ ╙── ^ //│ class Test -//│ fun foo1: ‹∀ 1. foo1339''#› where -//│ | foo1339''# := (‘A334' -> ‘A334') +//│ fun foo1: (‘A317' -> ‘A317') where //│ [pretty-printed] foo1: A -> A -//│ fun foo2: ‹∀ 1. foo2340''#› where -//│ | foo2340''# := (‘A334' -> α342'') -//│ | α342'' :> error<> | int +//│ fun foo2: (‘A317' -> α323'') where +//│ | α323'' :> error<> | int //│ [pretty-printed] foo2: A -> (error | int) Test().foo1 @@ -260,8 +260,8 @@ x => Test().foo1(x) // :d let t = Test() -//│ let t: α415 where -//│ | α415 :> ‹∀ 0. (Test<> & {Test#A: mut A334_411'..A334_411'})› +//│ let t: α377 where +//│ | α377 :> ‹∀ 0. (Test<> & {Test#A: mut A317_374'..A317_374'})› //│ [pretty-printed] t: Test & {Test#A = 'A} t.foo1 diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 41ecb73791..a46f449e89 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -15,23 +15,20 @@ Foo fun fooo(x) = class C(y, z) C(0, x) -//│ fun fooo: ‹∀ 0. fooo26'#› where -//│ | fooo26'# := (α27' -> α35') -//│ | α27' <: z30_37' -//│ | α35' :> C<> +//│ fun fooo: (α26' -> α34') where +//│ | α26' <: z29_36' +//│ | α34' :> C<> //│ [pretty-printed] fooo: anything -> C fun foo = bar fun bar = foo -//│ fun foo: ‹∀ 0. foo44'#› where -//│ | foo44'# := ‹∀ 0. bar45'#› -//│ | bar45'# := foo44'# +//│ fun foo: foo40' where +//│ | foo40' <: bar41' //│ [pretty-printed] foo: nothing -//│ fun bar: ‹∀ 0. bar45'#› where -//│ | foo44'# := ‹∀ 0. bar45'#› -//│ | bar45'# := foo44'# +//│ fun bar: foo40' where +//│ | foo40' <: bar41' //│ [pretty-printed] bar: nothing foo(bar) @@ -39,8 +36,8 @@ foo(bar) fun foo = {x: foo} -//│ fun foo: ‹∀ 0. foo57'#› where -//│ | foo57'# := {x: foo57'#} +//│ fun foo: {x: foo46'} where +//│ | foo46' :> {x: foo46'} //│ [pretty-printed] foo: 'foo //│ | where //│ | 'foo :> {x: 'foo} @@ -48,31 +45,28 @@ fun foo = {x: foo} fun foo = {x: bar} fun bar = {y: foo} -//│ fun foo: ‹∀ 0. foo63'#› where -//│ | foo63'# := {x: ‹∀ 0. bar64'#›} -//│ | bar64'# := {y: foo63'#} +//│ fun foo: {x: {y: foo50'}} where +//│ | foo50' :> {x: {y: foo50'}} //│ [pretty-printed] foo: 'foo //│ | where -//│ | 'foo :> {x: forall 'foo. {y: 'foo}} -//│ fun bar: ‹∀ 0. bar64'#› where -//│ | foo63'# := {x: ‹∀ 0. bar64'#›} -//│ | bar64'# := {y: foo63'#} -//│ [pretty-printed] bar: 'bar +//│ | 'foo :> {x: {y: 'foo}} +//│ fun bar: {y: foo50'} where +//│ | foo50' :> {x: {y: foo50'}} +//│ [pretty-printed] bar: {y: 'foo} //│ | where -//│ | 'bar :> {y: {x: forall 'bar. 'bar}} +//│ | 'foo :> {x: {y: 'foo}} // FIXME pretty-printing? foo //│ Typed: 'foo //│ where -//│ 'foo :> {x: forall 'foo. {y: 'foo}} +//│ 'foo :> {x: {y: 'foo}} :ns foo -//│ Typed: forall 'foo. 'foo +//│ Typed: forall 'foo. {x: {y: 'foo}} //│ where -//│ 'foo := {x: forall 'bar 'foo. 'bar} -//│ 'bar := {y: 'foo} +//│ 'foo :> {x: {y: 'foo}} foo.x //│ Typed: 'x @@ -82,57 +76,54 @@ foo.x foo.x.y //│ Typed: 'foo //│ where -//│ 'foo :> {x: forall 'foo. {y: 'foo}} +//│ 'foo :> {x: {y: 'foo}} -// FIXME: - fun foo(a) = {h: a, t: bar(a)} fun bar(b) = foo(b) -//│ fun foo: ‹∀ 0. foo94'#› where -//│ | foo94'# := (α95' -> {h: α95', t: α99'}) -//│ | α95' <: α97_101' -//│ | α99' :> ‹∀ 1. α98_100''› -//│ [pretty-printed] foo: 'a -> {h: 'a, t: nothing} -//│ fun bar: ‹∀ 0. bar96'#› where -//│ | α95' <: α97_101' -//│ | bar96'# := (α97' -> α98') -//│ | α97' <: α95' -//│ | α98' :> {h: α95', t: α99'} -//│ | α99' :> ‹∀ 1. α98_100''› -//│ [pretty-printed] bar: 'a -> {h: 'a, t: nothing} +//│ fun foo: (α76' -> {h: α76', t: α79'}) where +//│ | α76' <: α77' +//│ | α77' <: α76' +//│ | α79' :> {h: α76', t: α79'} +//│ [pretty-printed] foo: 'a -> 'b +//│ | where +//│ | 'b :> {h: 'a, t: 'b} +//│ fun bar: (α77' -> α78') where +//│ | α76' <: α77' +//│ | α77' <: α76' +//│ | α78' :> {h: α76', t: α79'} <: α79' +//│ | α79' :> {h: α76', t: α79'} +//│ [pretty-printed] bar: 'a -> 'b +//│ | where +//│ | 'b :> {h: 'a, t: 'b} :ns foo -//│ Typed: forall 'a 'b 'foo 'c. 'foo +//│ Typed: forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} //│ where -//│ 'foo := 'c -> {h: 'c, t: 'a} -//│ 'a :> forall 'd. 'd -//│ 'c <: 'b +//│ 'c :> {h: 'a, t: 'c} +//│ 'a <: 'b +//│ 'b <: 'a fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} -//│ fun foo: ‹∀ 0. foo120'#› where -//│ | foo120'# := (α121' -> {h1: α121', t1: α125'}) -//│ | α121' <: α123_127' -//│ | α125' :> ‹∀ 1. {h2: α123_127', t2: α124_128''}› -//│ [pretty-printed] foo: 'a -> {h1: 'a, t1: {h2: 'a, t2: nothing}} -//│ fun bar: ‹∀ 0. bar122'#› where -//│ | α121' <: α123_127' -//│ | bar122'# := (α123' -> {h2: α123', t2: α124'}) -//│ | α123' <: α121' -//│ | α124' :> {h1: α121', t1: α125'} -//│ | α125' :> ‹∀ 1. {h2: α123_127', t2: α124_128''}› -//│ [pretty-printed] bar: 'a -> {h2: 'a, t2: {h1: 'a, t1: {h2: 'a, t2: nothing}}} - -:ns -foo -//│ Typed: forall 'foo 'a 'b 'c. 'foo -//│ where -//│ 'foo := 'a -> {h1: 'a, t1: 'b} -//│ 'b :> forall 'd. {h2: 'c, t2: 'd} -//│ 'a <: 'c +//│ fun foo: (α97' -> {h1: α97', t1: α100'}) where +//│ | α97' <: α98' +//│ | α98' <: α97' +//│ | α99' :> {h1: α97', t1: α100'} +//│ | α100' :> {h2: α98', t2: α99'} +//│ [pretty-printed] foo: 'a -> 'b +//│ | where +//│ | 'b :> {h1: 'a, t1: {h2: 'a, t2: 'b}} +//│ fun bar: (α98' -> {h2: α98', t2: α99'}) where +//│ | α97' <: α98' +//│ | α98' <: α97' +//│ | α99' :> {h1: α97', t1: α100'} +//│ | α100' :> {h2: α98', t2: α99'} +//│ [pretty-printed] bar: 'a -> 'b +//│ | where +//│ | 'b :> {h2: 'a, t2: {h1: 'a, t1: 'b}} @@ -143,14 +134,12 @@ module Test0_2 { fun b = 123 } //│ class Test0_1 -//│ fun a: ‹∀ 1. a150''#› where -//│ | a150''# := b155'' -//│ | b154''# := 123 -//│ | b155'' :> ‹∀ 1. b154''#› <: a150''# +//│ fun a: b125'' where +//│ | a121'' :> 123 +//│ | b125'' :> 123 <: a121'' //│ [pretty-printed] a: 123 //│ class Test0_2 -//│ fun b: ‹∀ 1. b154''#› where -//│ | b154''# := 123 +//│ fun b: 123 where //│ [pretty-printed] b: 123 Test0_1.a @@ -163,14 +152,12 @@ class Test0_2() { fun b = 123 } //│ class Test0_1 -//│ fun a: ‹∀ 1. a172''#› where -//│ | a172''# := b179'' -//│ | b176''# := 123 -//│ | b179'' :> ‹∀ 1. b176''#› <: a172''# +//│ fun a: b143'' where +//│ | a137'' :> 123 +//│ | b143'' :> 123 <: a137'' //│ [pretty-printed] a: 123 //│ class Test0_2 -//│ fun b: ‹∀ 1. b176''#› where -//│ | b176''# := 123 +//│ fun b: 123 where //│ [pretty-printed] b: 123 @@ -182,23 +169,21 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.178: module Test1_1 { +//│ ║ l.165: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.179: fun a = Test1_2.b +//│ ║ l.166: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.180: } +//│ ║ l.167: } //│ ╙── ^ //│ class Test1_1 -//│ fun a: ‹∀ 1. a190''#› where -//│ | a190''# := b196'' -//│ | b194''# := a195'' -//│ | a195'' :> error<> <: b194''# -//│ | b196'' :> ‹∀ 1. b194''#› <: a190''# +//│ fun a: b155'' where +//│ | a150'' :> error<> +//│ | b155'' :> error<> <: a150'' //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun b: ‹∀ 1. b194''#› where -//│ | b194''# := a195'' -//│ | a195'' :> error<> <: b194''# +//│ fun b: a154'' where +//│ | b153'' :> error<> +//│ | a154'' :> error<> <: b153'' //│ [pretty-printed] b: error Test1_1.a @@ -213,23 +198,21 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.209: class Test1_1 { +//│ ║ l.194: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.210: fun a = Test1_2().b +//│ ║ l.195: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.211: } +//│ ║ l.196: } //│ ╙── ^ //│ class Test1_1 -//│ fun a: ‹∀ 1. a216''#› where -//│ | a216''# := b225'' -//│ | b220''# := a222'' -//│ | a222'' :> error<> <: b220''# -//│ | b225'' :> ‹∀ 1. b220''#› <: a216''# +//│ fun a: b180'' where +//│ | a170'' :> error<> +//│ | b180'' :> error<> <: a170'' //│ [pretty-printed] a: error //│ class Test1_2 -//│ fun b: ‹∀ 1. b220''#› where -//│ | b220''# := a222'' -//│ | a222'' :> error<> <: b220''# +//│ fun b: a175'' where +//│ | b173'' :> error<> +//│ | a175'' :> error<> <: b173'' //│ [pretty-printed] b: error @@ -246,60 +229,54 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.237: module Test2_1 { +//│ ║ l.220: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.238: fun t2 = Test2_2 +//│ ║ l.221: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.239: fun a = Test2_2.b +//│ ║ l.222: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.240: fun d = Test2_2.e +//│ ║ l.223: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.241: fun n = 456 +//│ ║ l.224: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.242: } +//│ ║ l.225: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.237: module Test2_1 { +//│ ║ l.220: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.238: fun t2 = Test2_2 +//│ ║ l.221: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.239: fun a = Test2_2.b +//│ ║ l.222: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.240: fun d = Test2_2.e +//│ ║ l.223: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.241: fun n = 456 +//│ ║ l.224: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.242: } +//│ ║ l.225: } //│ ╙── ^ //│ class Test2_1 -//│ fun t2: ‹∀ 1. t2241''#› where -//│ | t2241''# := Test2_2<> +//│ fun t2: Test2_2<> where //│ [pretty-printed] t2: Test2_2 -//│ fun a: ‹∀ 1. a252''#› where -//│ | b247''# := 123 -//│ | a252''# := b253'' -//│ | b253'' :> ‹∀ 1. b247''#› <: a252''# +//│ fun a: b201'' where +//│ | a191'' :> 123 +//│ | b201'' :> 123 <: a191'' //│ [pretty-printed] a: 123 -//│ fun d: ‹∀ 1. d257''#› where -//│ | e250''# := n251'' -//│ | n251'' :> error<> <: e250''# -//│ | d257''# := e258'' -//│ | e258'' :> ‹∀ 1. e250''#› <: d257''# +//│ fun d: e209'' where +//│ | d192'' :> error<> +//│ | e209'' :> error<> <: d192'' //│ [pretty-printed] d: error -//│ fun n: ‹∀ 1. n262''#› where -//│ | n262''# := 456 +//│ fun n: 456 where //│ [pretty-printed] n: 456 //│ class Test2_2 -//│ fun b: ‹∀ 1. b247''#› where -//│ | b247''# := 123 +//│ fun b: 123 where //│ [pretty-printed] b: 123 -//│ fun c: ‹∀ 1. c248''#› where -//│ | c248''# := a249'' -//│ | a249'' :> error<> <: c248''# +//│ fun c: a199'' where +//│ | c197'' :> error<> +//│ | a199'' :> error<> <: c197'' //│ [pretty-printed] c: error -//│ fun e: ‹∀ 1. e250''#› where -//│ | e250''# := n251'' -//│ | n251'' :> error<> <: e250''# +//│ fun e: n200'' where +//│ | e198'' :> error<> +//│ | n200'' :> error<> <: e198'' //│ [pretty-printed] e: error Test2_1.t2.b diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 92e2d81316..b782dfaded 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -9,8 +9,7 @@ mixin Over { //│ mixin Over //│ this: this23' //│ super: super24' -//│ fun p: ‹∀ 1. p26''#› where -//│ | p26''# := "hi" +//│ fun p: "hi" where //│ [pretty-printed] p: "hi" @@ -19,11 +18,9 @@ class Base1(p: int): Over { // fun test2 = super.p // TODO } //│ class Base1 -//│ fun test: ‹∀ 1. test35''#› where -//│ | p26''# := "hi" -//│ | test35''# := (Int, p36'',) -//│ | p36'' :> p36_37' -//│ | p36_37' :> ‹∀ 1. p26''#› +//│ fun test: (Int, p33'',) where +//│ | p33'' :> p33_34' +//│ | p33_34' :> "hi" //│ [pretty-printed] test: (int, "hi",) From 875a29f1dc19cbadfce89f942d0413d8193f2796 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 17:07:44 +0800 Subject: [PATCH 040/498] WIP Correctly parse annotated parameters --- .../src/main/scala/mlscript/JSBackend.scala | 6 +++- shared/src/main/scala/mlscript/Typer.scala | 14 ++++++-- shared/src/main/scala/mlscript/helpers.scala | 6 +++- shared/src/main/scala/mlscript/package.scala | 2 ++ shared/src/test/diff/nu/Ascription.mls | 14 ++------ shared/src/test/diff/nu/BasicMixins.mls | 10 +++--- shared/src/test/diff/nu/GenericClasses.mls | 35 +++++++++---------- shared/src/test/diff/nu/NamedArgs.mls | 17 +++------ .../src/test/scala/mlscript/DiffTests.scala | 6 ++-- 9 files changed, 55 insertions(+), 55 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 9a9c2bf26a..bf57079fe0 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -72,7 +72,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } private def translateParams(t: Term)(implicit scope: Scope): Ls[JSPattern] = t match { - case Tup(params) => params map { case _ -> Fld(_, _, p) => translatePattern(p) } + case Tup(params) => params map { + case N -> Fld(_, _, p) => translatePattern(p) + case S(nme) -> Fld(_, _, p) => translatePattern(nme) + } case _ => throw CodeGenError(s"term $t is not a valid parameter list") } @@ -617,6 +620,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage()) case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) } + // generate(pgrm)(topLevelScope, allowEscape) /** * Generate JavaScript code which targets MLscript test from the given block. diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 224245be6b..4018eabc66 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -36,7 +36,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) var recordProvenances: Boolean = true - type Raise = Diagnostic => Unit type Binding = Str -> SimpleType type Bindings = Map[Str, SimpleType] @@ -762,8 +761,17 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case tup: Tup if funkyTuples => typeTerms(tup :: Nil, false, Nil) case Tup(fs) => - TupleType(fs.map { case (n, Fld(mut, _, t)) => + TupleType(fs.mapConserve { case e @ (n, Fld(mut, spec, t)) => + n match { + case S(v) if ctx.inPattern => + (n, Fld(mut, spec, + Asc(v, t.toTypeRaise).withLoc(v.toLoc.fold(t.toLoc)(_ ++ t.toLoc |> some)))) + case _ => e + } + }.map { case (n, Fld(mut, _, t)) => val tym = typePolymorphicTerm(t) + // val tym = if (n.isDefined) typeType(t.toTypeRaise) + // else typePolymorphicTerm(t) val fprov = tp(t.toLoc, (if (mut) "mutable " else "") + "tuple field") if (mut) { val res = freshVar(fprov, N, n.map(_.name)) @@ -771,7 +779,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) (n, FieldType(Some(rs), rs)(fprov)) } else (n, tym.toUpper(fprov)) })(fs match { - case Nil | ((N, _) :: Nil) => noProv + case Nil | ((N, _) :: Nil) => noProv // TODO rm? case _ => tp(term.toLoc, "tuple literal") }) case Subs(a, i) => diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 5a9f05e432..e837dfdb52 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -443,6 +443,10 @@ trait TermImpl extends StatementImpl { self: Term => case Inst(bod) => s"${bod.print(true)}!" }} + def toTypeRaise(implicit raise: Raise): Type = toType match { + case L(d) => raise(d); Bot + case R(ty) => ty + } def toType: Diagnostic \/ Type = try R(toType_!.withLocOf(this)) catch { case e: NotAType => @@ -645,7 +649,7 @@ trait StatementImpl extends Located { self: Statement => val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) val termName = Var(nme.name).withLocOf(nme) val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(false, false, Rcd(fs.map { - case (S(nme), fld) => nme -> fld + case (S(nme), fld) => nme -> Fld(false, false, nme) case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld case _ => die })) :: Nil)))), true) diff --git a/shared/src/main/scala/mlscript/package.scala b/shared/src/main/scala/mlscript/package.scala index bd4c4023e5..95cff80304 100644 --- a/shared/src/main/scala/mlscript/package.scala +++ b/shared/src/main/scala/mlscript/package.scala @@ -3,6 +3,8 @@ import mlscript.utils.shorthands._ package object mlscript { + type Raise = Diagnostic => Unit + val ExtrusionPrefix: Str = "??" } diff --git a/shared/src/test/diff/nu/Ascription.mls b/shared/src/test/diff/nu/Ascription.mls index 558490d024..49b308b0b6 100644 --- a/shared/src/test/diff/nu/Ascription.mls +++ b/shared/src/test/diff/nu/Ascription.mls @@ -17,19 +17,9 @@ //│ res: anything //│ = 1 -// FIXME -:w -:e fun foo(x: int) = x + 1 -//│ ╔══[WARNING] Variable name 'int' already names a symbol in scope. If you want to refer to that symbol, you can use `scope.int`; if not, give your future readers a break and use another name :^) -//│ ║ l.23: fun foo(x: int) = x + 1 -//│ ╙── ^^^ -//│ ╔══[ERROR] identifier not found: x -//│ ║ l.23: fun foo(x: int) = x + 1 -//│ ╙── ^ -//│ foo: (x: anything,) -> int -//│ Code generation encountered an error: -//│ unresolved symbol x +//│ foo: (x: int,) -> int +//│ = [Function: foo] fun foo(x : int) = x + 1 //│ foo: int -> int diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 6fb6901ce7..87547a533c 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -111,14 +111,14 @@ Base1.test mixin WrapBase { // fun wrap(x) = x // fun wrap(x) = x : int - fun wrapA(x : int) = x : int + fun wrapA(x: int) = x : int fun wrap(x) = x } //│ mixin WrapBase //│ this: this223' //│ super: super224' -//│ fun wrapA: (Int -> Int) where -//│ [pretty-printed] wrapA: int -> int +//│ fun wrapA: ((x: Int,) -> Int) where +//│ [pretty-printed] wrapA: (x: int,) -> int //│ fun wrap: (α227'' -> α227'') where //│ [pretty-printed] wrap: 'a -> 'a @@ -182,8 +182,8 @@ WrapBase1.wrapA("ok") //│ ║ l.177: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.114: fun wrapA(x : int) = x : int -//│ ║ ^^^ +//│ ║ l.114: fun wrapA(x: int) = x : int +//│ ║ ^^^ //│ ╟── from reference: //│ ║ l.127: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index f3f189c6a7..7fc13c3212 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -182,14 +182,14 @@ Test(true) class Test(n: A) { fun foo: A = n - fun foo1(x : A) = x + fun foo1(x: A) = x fun id(x) = x } //│ class Test //│ fun foo: ‘A210' where //│ [pretty-printed] foo: A -//│ fun foo1: (‘A210' -> ‘A210') where -//│ [pretty-printed] foo1: A -> A +//│ fun foo1: ((x: ‘A210',) -> ‘A210') where +//│ [pretty-printed] foo1: (x: A,) -> A //│ fun id: (α216'' -> α216'') where //│ [pretty-printed] id: 'a -> 'a @@ -229,28 +229,27 @@ t.id :e class Test { - // fun foo(x: A) = x // FIXME - fun foo1(x : A) = x - fun foo2(x : A) = x + 1 + fun foo1(x: A) = x + fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.234: fun foo2(x : A) = x + 1 -//│ ║ ^^^ +//│ ║ l.233: fun foo2(x: A) = x + 1 +//│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.234: fun foo2(x : A) = x + 1 -//│ ║ ^ +//│ ║ l.233: fun foo2(x: A) = x + 1 +//│ ║ ^ //│ ╟── Note: type parameter A is defined at: //│ ║ l.231: class Test { //│ ╙── ^ //│ class Test -//│ fun foo1: (‘A317' -> ‘A317') where -//│ [pretty-printed] foo1: A -> A -//│ fun foo2: (‘A317' -> α323'') where +//│ fun foo1: ((x: ‘A317',) -> ‘A317') where +//│ [pretty-printed] foo1: (x: A,) -> A +//│ fun foo2: ((x: ‘A317',) -> α323'') where //│ | α323'' :> error<> | int -//│ [pretty-printed] foo2: A -> (error | int) +//│ [pretty-printed] foo2: (x: A,) -> (error | int) Test().foo1 -//│ Typed: 'A -> 'A +//│ Typed: (x: 'A,) -> 'A Test().foo1(1) //│ Typed: 1 @@ -265,7 +264,7 @@ let t = Test() //│ [pretty-printed] t: Test & {Test#A = 'A} t.foo1 -//│ Typed: 'A -> 'A +//│ Typed: (x: 'A,) -> 'A [t.foo1(0), t.foo1(true)] //│ Typed: (0, true,) @@ -278,11 +277,11 @@ t // FIXME -fun foo(x : Test) = x.foo1 +fun foo(x: Test) = x.foo1 //│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Test Test().foo2 -//│ Typed: anything -> (error | int) +//│ Typed: (x: anything,) -> (error | int) diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index 54976317b3..953ac86b93 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -1,29 +1,22 @@ :NewParser -:w class Foo(x: int) //│ Defined class Foo -//│ ╔══[WARNING] Variable name 'int' already names a symbol in scope. If you want to refer to that symbol, you can use `scope.int`; if not, give your future readers a break and use another name :^) -//│ ║ l.5: class Foo(x: int) -//│ ╙── ^^^ -//│ Foo: (x: int & 'x,) -> (Foo with {x: 'x}) +//│ Foo: (x: int,) -> Foo //│ = [Function: Foo1] Foo(1) -//│ res: Foo & {x: 1} +//│ res: Foo //│ = Foo { x: 1 } Foo(x: 1) -//│ res: Foo & {x: 1} +//│ res: Foo //│ = Foo { x: 1 } -:e +// :e // TODO check parameter name matches Foo(y: 1) -//│ ╔══[ERROR] Wrong tuple field name: found 'y' instead of 'x' -//│ ║ l.22: Foo(y: 1) -//│ ╙── ^^^^^^ -//│ res: error | Foo & {x: 1} +//│ res: Foo //│ = Foo { x: 1 } diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 2421f9ba21..600500879d 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -390,7 +390,7 @@ class DiffTests } } - val raise: typer.Raise = d => report(d :: Nil) + val raise: Raise = d => report(d :: Nil) // try to parse block of text into mlscript ast val ans = try { @@ -658,7 +658,7 @@ class DiffTests // `typerResults` buffer after the statement has been processed. val diagnosticLines = mutable.Buffer.empty[Str] // We put diagnosis to the buffer in the following `Typer` routines. - val raiseToBuffer: typer.Raise = d => { + val raiseToBuffer: Raise = d => { report(d :: Nil, diagnosticLines += _) } // Typing results are before diagnostic messages in the subsumption case. @@ -671,7 +671,7 @@ class DiffTests typer.dbg = mode.dbg implicit val prov: typer.TP = typer.NoProv // TODO - implicit val r: typer.Raise = raise + implicit val r: Raise = raise val ty_sch = ctx.poly { ctx => typer.typeType(rhs)(ctx, raise, vars = tps.collect { From eff014450b320b4dbc7335a8203ebd5c10aba96e Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 17:10:49 +0800 Subject: [PATCH 041/498] WIP fix <:< with newdefs --- shared/src/main/scala/mlscript/TyperHelpers.scala | 6 ++++-- shared/src/test/diff/nu/GenericClasses.mls | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index ae46227663..45eac02c69 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -513,8 +513,8 @@ abstract class TyperHelpers { Typer: Typer => if (primitiveTypes contains tr.defn.name) => tr.expand <:< that case (_, tr: TypeRef) if (primitiveTypes contains tr.defn.name) => this <:< tr.expand - case (tr1: TypeRef, _) => - val td1 = ctx.tyDefs(tr1.defn.name) + case (tr1: TypeRef, _) => ctx.tyDefs.get(tr1.defn.name) match { + case S(td1) => that match { case tr2: TypeRef if tr2.defn === tr1.defn => val tvv = td1.getVariancesOrDefault @@ -525,6 +525,8 @@ abstract class TyperHelpers { Typer: Typer => case _ => (td1.kind is Cls) && clsNameToNomTag(td1)(noProv, ctx) <:< that } + case N => false // TODO look into ctx.tyDefs2 + } case (_, _: TypeRef) => false // TODO try to expand them (this requires populating the cache because of recursive types) case (_: PolymorphicType, _) | (_, _: PolymorphicType) => false diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 7fc13c3212..4de945a83d 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -276,9 +276,17 @@ t //│ Typed: Test & {Test#A = 'A} -// FIXME fun foo(x: Test) = x.foo1 -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: Test +//│ fun foo: ((x: Test[Int],) -> foo1422') where +//│ | foo1422' :> ((x: A423#,) -> A423#) +//│ | A423# := int..int +//│ [pretty-printed] foo: (x: Test[int],) -> (x: int,) -> int + +foo(t) +//│ Typed: (x: int,) -> int + +foo(t)(1) +//│ Typed: int Test().foo2 From c504de9298ba09279e1b1558a79f8b36fff57a23 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 17:44:06 +0800 Subject: [PATCH 042/498] WIP Fix other tests --- shared/src/main/scala/mlscript/TypeSimplifier.scala | 8 +++++--- shared/src/test/diff/ucs/SplitBeforeOp.mls | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index df2e27a35c..4dd180d637 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -89,9 +89,9 @@ trait TypeSimplifier { self: Typer => val prefix = fnme.takeWhile(_ =/= '#') val postfix = fnme.drop(prefix.length + 1) lazy val default = fty.update(process(_ , N), process(_ , N)) - if (postfix.isEmpty || prefix.isCapitalized/* TODO */) v -> default :: Nil - else { - val td = ctx.tyDefs(prefix) + if (postfix.isEmpty) v -> default :: Nil + else ctx.tyDefs.get(prefix) match { + case S(td) => td.tvarVariances.fold(v -> default :: Nil)(tvv => tvv(td.tparamsargs.find(_._1.name === postfix).getOrElse(die)._2) match { case VarianceInfo(true, true) => Nil @@ -100,6 +100,8 @@ trait TypeSimplifier { self: Typer => else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil else v -> default :: Nil }) + case N => // TODO look into ctx.tyDefs2 + v -> default :: Nil } })(ty.prov) diff --git a/shared/src/test/diff/ucs/SplitBeforeOp.mls b/shared/src/test/diff/ucs/SplitBeforeOp.mls index 07b7e340a2..c8a7ae203e 100644 --- a/shared/src/test/diff/ucs/SplitBeforeOp.mls +++ b/shared/src/test/diff/ucs/SplitBeforeOp.mls @@ -18,7 +18,7 @@ if x if x is A and y then 0 -//│ ╔══[ERROR] Cannot find the constructor `A` in the context +//│ ╔══[ERROR] Cannot find constructor `A` in scope //│ ║ l.19: is A and //│ ╙── ^ //│ res: error @@ -32,7 +32,7 @@ if x is A() then "A" B() then "B" -//│ ╔══[ERROR] Cannot find class `A` in the context +//│ ╔══[ERROR] Cannot find class `A` in scope //│ ║ l.33: A() then "A" //│ ╙── ^ //│ res: error From 0ca680bd986f7aa58cc81bc7f68c4d62688bb265 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Feb 2023 18:35:29 +0800 Subject: [PATCH 043/498] WIPIP --- .../src/main/scala/mlscript/NuTypeDefs.scala | 37 ++- shared/src/main/scala/mlscript/Typer.scala | 3 + .../main/scala/mlscript/TyperDatatypes.scala | 21 +- shared/src/main/scala/mlscript/syntax.scala | 4 +- shared/src/test/diff/nu/BasicClasses.mls | 161 +++++------ shared/src/test/diff/nu/BasicMixins.mls | 193 ++++++++----- shared/src/test/diff/nu/ECOOP23.mls | 131 +++++---- shared/src/test/diff/nu/GenericClasses.mls | 137 +++++---- shared/src/test/diff/nu/MutualRec.mls | 263 +++++++++++------- shared/src/test/diff/nu/ParamOverriding.mls | 5 +- .../src/test/scala/mlscript/DiffTests.scala | 26 +- 11 files changed, 593 insertions(+), 388 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 683e96e854..6f5a022c97 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -48,7 +48,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } - sealed abstract class TypedNuDecl extends NuMember { + // sealed abstract class TypedNuDecl extends NuMember { + sealed trait TypedNuDecl extends NuMember { def name: Str // def freshen(implicit ctx: Ctx): TypedNuDecl = this match { // case m @ TypedNuMxn(td, thisTV, superTV, ttu) => @@ -69,9 +70,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => implicit val shadows: Shadows = Shadows.empty // println(level) ctx.copy(lvl = level + 1) |> { implicit ctx => - freshenAbove(level, rigidify = false) + freshenAbove(level, rigidify = false).asInstanceOf[TypedNuDecl] } } + /* def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedNuTermDef = { @@ -103,6 +105,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } } } + */ def force()(implicit raise: Raise): Unit = this match { case x: TypedNuMxn => x.ttu.force() case x: TypedNuCls => x.ttu.force() @@ -110,9 +113,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { + sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuTypeDefBase with TypedNuDecl { def nme: TypeName // val tparams: Ls[TN -> TV] = Nil // TODO + override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = ??? + // val prov: TP + val td: NuTypeDef + val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) + val level: Level + def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = ??? } // case class TypedNuTypeDef( // kind: TypeDefKind, @@ -123,12 +132,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // toLoc: Opt[Loc], // ) - case class TypedNuAls(nme: TypeName) extends TypedNuTypeDef(Als) { + // case class TypedNuAls(level: Level, nme: TypeName)(val prov: TP) extends TypedNuTypeDef(Als) { + case class TypedNuAls(level: Level, td: NuTypeDef) extends TypedNuTypeDef(Als) { def name: Str = nme.name - - def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - : TypedNuTermDef = ??? + def nme: mlscript.TypeName = ??? + // def freshenAbove(lim: Int, rigidify: Bool) + // (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + // : TypedNuTypeDef = ??? } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { @@ -143,7 +153,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { - def level: Level = thisTV.level - 1 // TODO cleaner + val level: Level = thisTV.level - 1 // TODO cleaner def nme: TypeName = td.nme def name: Str = nme.name // def freshen(implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, @@ -152,6 +162,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => /** Note: the type `ty` is stoed *without* its polymorphic wrapper! */ case class TypedNuFun(level: Level, fd: NuFunDef, ty: ST) extends TypedNuDecl with TypedNuTermDef { def name: Str = fd.nme.name + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + : TypedNuFun = this match { + case TypedNuFun(level, fd, ty) => + // TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(level, rigidify)) + TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) + } } case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) { @@ -159,7 +176,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = - TypedTypingUnit(entities.map(_.map(_.freshenAbove(lim, rigidify))) + TypedTypingUnit(entities.map(_.map(_.freshenAbove(lim, rigidify).asInstanceOf[TypedNuTermDef])) , result.map(_.freshenAbove(lim, rigidify))) def force()(implicit raise: Raise): Unit = { entities.foreach(_.force()) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 4018eabc66..ed289b4dc2 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1262,6 +1262,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val bounds = (ubs.mapValues(_.reduce(_ &- _)) ++ lbs.mapValues(_.reduce(_ | _)).map(_.swap)) val procesased = bounds.map { case (lo, hi) => Bounds(go(lo), go(hi)) } Constrained(go(bod), Nil, procesased) + + // case DeclType(lvl, info) => + } // }(r => s"~> $r") diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c01355a3f8..7c1160bff2 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -30,6 +30,15 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case class VarSymbol(ty: ST, definingVar: Var) extends TypeInfo + // case class DeclType(level: Level, info: LazyTypeInfo) extends SimpleType { + // // def level: Level = info.complete().level + // def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = ??? + // val prov: TP = TypeProvenance(info.decl.toLoc, info.decl.describe, isType = true) + // } + // case class DeclType() extends SimpleType { + + protected abstract class TypedNuTypeDefBase extends SimpleType + // TODO rm level? already in ctx class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx, vars: Map[Str, SimpleType]) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { @@ -246,11 +255,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use // TODO check overriding - val clsMems = ttu.entities.map(_.complete()).map { - case fun @ TypedNuFun(_, fd, ty) => - fun - case _ => ??? - } + val clsMems = ttu.entities.map(_.complete()) + // .map { + // case fun @ TypedNuFun(_, fd, ty) => + // fun + // // case _ => ??? + // case m => m + // } // val thisTy = ClassTag(Var(td.name), // Set.empty//TODO diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index c98a7eada8..9b0c4aeffc 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -136,6 +136,7 @@ final case class Bounds(lb: Type, ub: Type) extends Type final case class WithExtension(base: Type, rcd: Record) extends Type final case class Splice(fields: Ls[Either[Type, Field]]) extends Type final case class Constrained(base: Type, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds]) extends Type +final case class FirstClassDefn(defn: NuTypeDef) extends Type final case class Field(in: Opt[Type], out: Type) extends FieldImpl @@ -185,4 +186,5 @@ final case class NuFunDef( } -sealed abstract class PgrmOrTypingUnit +sealed abstract class PgrmOrTypingUnit // TODO rm + diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 3f72ce09ce..03eada7ce4 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -4,68 +4,57 @@ +class C { + fun id(x) = x + fun const(x) = id +} + + class Base0(n) { fun me = this fun my = this.n fun mine = my fun oops = this.my } -//│ class Base0 -//│ fun me: this24' where -//│ | this24' :> Base0<> <: {my: my32_33'} & {n: n30_31'} -//│ | n30_31' :> n23_59 -//│ | my32_33' :> n30_39 -//│ | n30_39 :> n30_37 <: mine28_40 & my27_41 -//│ | mine28_40 :> n30_37 -//│ | my27_41 :> n30_37 -//│ [pretty-printed] me: Base0 -//│ fun my: n30'' where -//│ | my27'' :> n30_31' -//│ | mine28'' :> n30_31' -//│ | n30'' :> n30_31' <: mine28'' & my27'' -//│ | n30_31' :> n23_59 -//│ [pretty-printed] my: nothing -//│ fun mine: n30'' where -//│ | my27'' :> n30_31' -//│ | mine28'' :> n30_31' -//│ | n30'' :> n30_31' <: mine28'' & my27'' -//│ | n30_31' :> n23_59 -//│ [pretty-printed] mine: nothing -//│ fun oops: my32'' where -//│ | oops29'' :> my32_33' -//│ | my32'' :> my32_33' <: oops29'' -//│ | my32_33' :> n30_39 -//│ | n30_39 :> n30_37 <: mine28_40 & my27_41 -//│ | mine28_40 :> n30_37 -//│ | my27_41 :> n30_37 -//│ [pretty-printed] oops: nothing +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ at: scala.Predef$.$qmark$qmark$qmark(Predef.scala:344) +//│ at: mlscript.NuTypeDefs$TypedNuTypeDef.freshenAbove(NuTypeDefs.scala:119) +//│ at: mlscript.ConstraintSolver.lookupNuTypeDef$1(ConstraintSolver.scala:486) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94(ConstraintSolver.scala:667) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94$adapted(ConstraintSolver.scala:666) +//│ at: scala.collection.immutable.List.foreach(List.scala:333) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93(ConstraintSolver.scala:666) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93$adapted(ConstraintSolver.scala:654) +//│ at: mlscript.utils.package$GenHelper$.$bar$greater$extension(package.scala:111) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$89(ConstraintSolver.scala:654) // :d // Base0 // Base0 let b1 = Base0(42) -//│ let b1: α85 where -//│ | α85 :> Base0<> -//│ [pretty-printed] b1: Base0 +//│ ╔══[ERROR] identifier not found: Base0 +//│ ║ l.35: let b1 = Base0(42) +//│ ╙── ^^^^^ // :d let n1 = b1.n -//│ let n1: n89 where -//│ [pretty-printed] n1: nothing +//│ ╔══[ERROR] identifier not found: b1 +//│ ║ l.41: let n1 = b1.n +//│ ╙── ^^ // TODO n1 + 1 -//│ Typed: int +//│ ╔══[ERROR] identifier not found: n1 +//│ ║ l.47: n1 + 1 +//│ ╙── ^^ let b2 = Base0("hi") let n2 = b2.n -//│ let b2: α122 where -//│ | α122 :> Base0<> <: {n: n124} -//│ [pretty-printed] b2: Base0 -//│ let n2: n124 where -//│ [pretty-printed] n2: nothing +//│ ╔══[ERROR] identifier not found: Base0 +//│ ║ l.53: let b2 = Base0("hi") +//│ ╙── ^^^^^ @@ -74,63 +63,64 @@ class Base1(base: int) { fun getBase2 = this.base fun foo(x) = this.base + x } -//│ class Base1 -//│ fun getBase1: Int where -//│ [pretty-printed] getBase1: int -//│ fun getBase2: base146'' where -//│ | getBase2144'' :> base146_147' -//│ | base146'' :> base146_147' <: getBase2144'' -//│ | base146_147' :> Int -//│ [pretty-printed] getBase2: int -//│ fun foo: (α148'' -> α152'') where -//│ | α148'' <: int -//│ | α152'' :> int -//│ [pretty-printed] foo: int -> int +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ at: scala.Predef$.$qmark$qmark$qmark(Predef.scala:344) +//│ at: mlscript.NuTypeDefs$TypedNuTypeDef.freshenAbove(NuTypeDefs.scala:119) +//│ at: mlscript.ConstraintSolver.lookupNuTypeDef$1(ConstraintSolver.scala:486) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94(ConstraintSolver.scala:667) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94$adapted(ConstraintSolver.scala:666) +//│ at: scala.collection.immutable.List.foreach(List.scala:333) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93(ConstraintSolver.scala:666) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93$adapted(ConstraintSolver.scala:654) +//│ at: mlscript.utils.package$GenHelper$.$bar$greater$extension(package.scala:111) +//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$89(ConstraintSolver.scala:654) class Base1(base: int) { fun getBase1 = base fun me = this fun foo(x) = base + x } -//│ class Base1 -//│ fun getBase1: Int where -//│ [pretty-printed] getBase1: int -//│ fun me: this174' where -//│ | this174' :> Base1<> -//│ [pretty-printed] me: Base1 -//│ fun foo: (α179'' -> α181'') where -//│ | α179'' <: int -//│ | α181'' :> int -//│ [pretty-printed] foo: int -> int Base1 -//│ Typed: (base: int,) -> Base1 +//│ ╔══[ERROR] identifier not found: Base1 +//│ ║ l.84: Base1 +//│ ╙── ^^^^^ let b = Base1(1) -//│ let b: α198 where -//│ | α198 :> Base1<> -//│ [pretty-printed] b: Base1 +//│ ╔══[ERROR] identifier not found: Base1 +//│ ║ l.89: let b = Base1(1) +//│ ╙── ^^^^^ b.base -//│ Typed: int +//│ ╔══[ERROR] identifier not found: b +//│ ║ l.94: b.base +//│ ╙── ^ b.getBase1 -//│ Typed: int +//│ ╔══[ERROR] identifier not found: b +//│ ║ l.99: b.getBase1 +//│ ╙── ^ // :d b.me -//│ Typed: Base1 +//│ ╔══[ERROR] identifier not found: b +//│ ║ l.105: b.me +//│ ╙── ^ :e b.getBaseTypo -//│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.125: b.getBaseTypo -//│ ╙── ^^^^^^^^^^^^ -//│ Typed: error +//│ ╔══[ERROR] identifier not found: b +//│ ║ l.111: b.getBaseTypo +//│ ╙── ^ b : Base1 -//│ Typed: Base1 +//│ ╔══[ERROR] identifier not found: b +//│ ║ l.117: b : Base1 +//│ ╙── ^ +//│ ╔══[ERROR] type identifier not found: Base1 +//│ ║ l.117: b : Base1 +//│ ╙── ^^^^^ :e // TODO @@ -138,17 +128,12 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.137: class Rec(n) { +//│ ║ l.127: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.138: fun go = Rec(n + 1) +//│ ║ l.128: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.139: } +//│ ║ l.129: } //│ ╙── ^ -//│ class Rec -//│ fun go: α239'' where -//│ | go236'' :> error<> -//│ | α239'' :> error<> <: go236'' -//│ [pretty-printed] go: error @@ -159,19 +144,17 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.158: a: int +//│ ║ l.143: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.157: class Annots(base: 0 | 1) { +//│ ║ l.142: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.158: a: int +//│ ║ l.143: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.158: a: int +//│ ║ l.143: a: int //│ ╙── ^^^ -//│ class Annots -//│ fun a: ((0 | 1),) where -//│ [pretty-printed] a: (0 | 1,) + diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 87547a533c..1bc89d9187 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -14,36 +14,51 @@ mixin BaseTest { //│ fun test: base26'' where //│ | test25'' :> base26_27' //│ | base26'' :> base26_27' <: test25'' -//│ [pretty-printed] test: nothing +//│ [pretty-printed] test: 'base +//│ | where +//│ | 'base :> 'base0 +//│ | <: 'test +//│ | 'test :> 'base0 mixin BaseInc { fun test = super.base + 1 fun test2 = this.base } //│ mixin BaseInc -//│ this: this31' -//│ | this31' <: {base: base39_40'} -//│ super: super32' -//│ | super32' <: {base: base35_36'} -//│ | base35_36' <: int -//│ fun test: α38'' where -//│ | test33'' :> int -//│ | α38'' :> int <: test33'' -//│ [pretty-printed] test: int -//│ fun test2: base39'' where -//│ | test234'' :> base39_40' -//│ | base39'' :> base39_40' <: test234'' -//│ [pretty-printed] test2: nothing +//│ this: this29' +//│ | this29' <: {base: base37_38'} +//│ super: super30' +//│ | super30' <: {base: base33_34'} +//│ | base33_34' <: int +//│ fun test: α36'' where +//│ | test31'' :> int +//│ | α36'' :> int <: test31'' +//│ [pretty-printed] test: 'a +//│ | where +//│ | 'a :> int +//│ | <: 'test +//│ | 'test :> int +//│ fun test2: base37'' where +//│ | test232'' :> base37_38' +//│ | base37'' :> base37_38' <: test232'' +//│ [pretty-printed] test2: 'base +//│ | where +//│ | 'base :> 'base0 +//│ | <: 'test2 +//│ | 'test2 :> 'base0 // :d class Base1(base: int): BaseTest, BaseInc { fun test3 = [base, this.base] } //│ class Base1 -//│ fun test3: (Int, base64'',) where -//│ | base64'' :> base64_65' -//│ | base64_65' :> Int -//│ [pretty-printed] test3: (int, int,) +//│ fun test3: (Int, base59'',) where +//│ | base59'' :> base59_60' +//│ | base59_60' :> Int +//│ [pretty-printed] test3: (int, 'base,) +//│ | where +//│ | 'base :> 'base0 +//│ | 'base0 :> int Base1(1).test //│ Typed: int @@ -69,10 +84,10 @@ Base1(1).test :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.70: class Base1(x): BaseTest +//│ ║ l.85: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.70: class Base1(x): BaseTest +//│ ║ l.85: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -91,15 +106,19 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo -//│ this: this183' -//│ super: super184' -//│ | super184' <: {misc: misc191_192'} & {base: base187_188'} -//│ | base187_188' <: int -//│ fun test: (α186'' -> (α190'', α186'', misc191'',)) where -//│ | α186'' <: int -//│ | α190'' :> int -//│ | misc191'' :> misc191_192' -//│ [pretty-printed] test: (int & 'a) -> (int, 'a, nothing,) +//│ this: this176' +//│ super: super177' +//│ | super177' <: {misc: misc184_185'} & {base: base180_181'} +//│ | base180_181' <: int +//│ fun test: (α179'' -> (α183'', α179'', misc184'',)) where +//│ | α179'' <: int +//│ | α183'' :> int +//│ | misc184'' :> misc184_185' +//│ [pretty-printed] test: 'a -> ('b, 'a, 'misc,) +//│ | where +//│ | 'misc :> 'misc0 +//│ | 'b :> int +//│ | 'a <: int module Base1(base: int, misc: string): Foo //│ class Base1 @@ -115,11 +134,11 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase -//│ this: this223' -//│ super: super224' +//│ this: this210' +//│ super: super211' //│ fun wrapA: ((x: Int,) -> Int) where //│ [pretty-printed] wrapA: (x: int,) -> int -//│ fun wrap: (α227'' -> α227'') where +//│ fun wrap: (α214'' -> α214'') where //│ [pretty-printed] wrap: 'a -> 'a // :d @@ -128,19 +147,25 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ mixin Wrap -//│ this: this232' -//│ super: super233' -//│ | super233' <: {wrap: wrap243_244'} & {wrapA: wrapA237_238'} -//│ | wrapA237_238' <: ((α236_240',) -> α239_241') -//│ | wrap243_244' <: ((α242_246',) -> α245_247') -//│ fun wrapA: (α236'' -> (α239'',)) where -//│ | α236'' <: α236_240' -//│ | α239'' :> α239_241' -//│ [pretty-printed] wrapA: anything -> (nothing,) -//│ fun wrap: (α242'' -> (α245'',)) where -//│ | α242'' <: α242_246' -//│ | α245'' :> α245_247' -//│ [pretty-printed] wrap: anything -> (nothing,) +//│ this: this216' +//│ super: super217' +//│ | super217' <: {wrap: wrap227_228'} & {wrapA: wrapA221_222'} +//│ | wrapA221_222' <: ((α220_224',) -> α223_225') +//│ | wrap227_228' <: ((α226_230',) -> α229_231') +//│ fun wrapA: (α220'' -> (α223'',)) where +//│ | α220'' <: α220_224' +//│ | α223'' :> α223_225' +//│ [pretty-printed] wrapA: 'a -> ('b,) +//│ | where +//│ | 'b :> 'c +//│ | 'a <: 'd +//│ fun wrap: (α226'' -> (α229'',)) where +//│ | α226'' <: α226_230' +//│ | α229'' :> α229_231' +//│ [pretty-printed] wrap: 'a -> ('b,) +//│ | where +//│ | 'b :> 'c +//│ | 'a <: 'd @@ -176,16 +201,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.177: WrapBase1.wrapA("ok") +//│ ║ l.202: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.177: WrapBase1.wrapA("ok") +//│ ║ l.202: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.114: fun wrapA(x: int) = x : int +//│ ║ l.133: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.127: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.146: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ Typed: (int,) | error @@ -195,32 +220,54 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ class WrapBase2 let w = WrapBase2.wrap -//│ let w: wrap418 where -//│ | wrap418 :> (α242_431 -> (α245_439,)) -//│ | α242_431 <: α242_432 -//│ | α242_432 <: α242_433 -//│ | α242_433 <: α242_434 -//│ | α242_434 <: α242_435 -//│ | α242_435 <: α242_436 -//│ | α242_436 <: α227_437 -//│ | α227_437 <: α245_438 -//│ | α245_439 :> α245_440 -//│ | α245_440 :> (α245_441,) -//│ | α245_441 :> α245_442 -//│ | α245_442 :> (α245_443,) -//│ | α245_443 :> α245_438 -//│ [pretty-printed] w: 'a -> ((('a,),),) +//│ let w: wrap394 where +//│ | wrap394 :> (α226_407 -> (α229_415,)) +//│ | α226_407 <: α226_408 +//│ | α226_408 <: α226_409 +//│ | α226_409 <: α226_410 +//│ | α226_410 <: α226_411 +//│ | α226_411 <: α226_412 +//│ | α226_412 <: α214_413 +//│ | α214_413 <: α229_414 +//│ | α229_415 :> α229_416 +//│ | α229_416 :> (α229_417,) +//│ | α229_417 :> α229_418 +//│ | α229_418 :> (α229_419,) +//│ | α229_419 :> α229_414 +//│ [pretty-printed] w: 'wrap +//│ | where +//│ | 'wrap :> 'a -> ('b,) +//│ | 'b :> 'c +//│ | 'c :> ('d,) +//│ | 'd :> 'e +//│ | 'e :> ('f,) +//│ | 'f :> 'g +//│ | 'a <: 'h +//│ | 'h <: 'i +//│ | 'i <: 'j +//│ | 'j <: 'k +//│ | 'k <: 'l +//│ | 'l <: 'm +//│ | 'm <: 'g let wd = w(1) -//│ let wd: α461 where -//│ | α245_438 :> 1 -//│ | α245_439 :> α245_440 -//│ | α245_440 :> (α245_441,) -//│ | α245_441 :> α245_442 -//│ | α245_442 :> (α245_443,) -//│ | α245_443 :> α245_438 -//│ | α461 :> (α245_439,) -//│ [pretty-printed] wd: (((1,),),) +//│ let wd: α421 where +//│ | α229_414 :> 1 +//│ | α229_415 :> α229_416 +//│ | α229_416 :> (α229_417,) +//│ | α229_417 :> α229_418 +//│ | α229_418 :> (α229_419,) +//│ | α229_419 :> α229_414 +//│ | α421 :> (α229_415,) +//│ [pretty-printed] wd: 'a +//│ | where +//│ | 'a :> ('b,) +//│ | 'b :> 'c +//│ | 'c :> ('d,) +//│ | 'd :> 'e +//│ | 'e :> ('f,) +//│ | 'f :> 'g +//│ | 'g :> 1 wd._1._1._1 + 1 //│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index f1043f5f65..b9ed3fcbf0 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -12,8 +12,9 @@ let add11 = Add(Lit(1), Lit(2)) //│ let add11: α33 where //│ | α33 :> (Add<> & {Add#E: mut E24_34..E24_34}) //│ | E24_34 :> Lit<> -//│ [pretty-printed] add11: Add & {Add#E = 'E} +//│ [pretty-printed] add11: 'a //│ | where +//│ | 'a :> Add & {Add#E = 'E} //│ | 'E :> Lit @@ -24,24 +25,32 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase -//│ this: this40' -//│ | this40' <: {eval: eval60_61'} & {eval: eval53_54'} -//│ | eval53_54' <: ((‹∀ 2. lhs49_56'''›,) -> α55_58') -//│ | lhs49_56''' :> lhs49_57' -//│ | α55_58' <: int -//│ | eval60_61' <: ((‹∀ 2. rhs51_63'''›,) -> α62_65') -//│ | rhs51_63''' :> rhs51_64' -//│ | α62_65' <: int -//│ super: super41' -//│ fun eval: (α43'' -> (Int | α66'')) where -//│ | α43'' <: ((Lit<> & α44'') | ((Add<> & α48'') & ~(Lit<>))) -//│ | α44'' <: {n: n45_46''} -//│ | n45_46'' <: int -//│ | α48'' <: {rhs: rhs51_52''} & {lhs: lhs49_50''} -//│ | lhs49_50'' <: lhs49_57' -//│ | rhs51_52'' <: rhs51_64' -//│ | α66'' :> int -//│ [pretty-printed] eval: (Add & {lhs: anything, rhs: anything} | Lit & {n: int}) -> int +//│ this: this36' +//│ | this36' <: {eval: eval56_57'} & {eval: eval49_50'} +//│ | eval49_50' <: ((‹∀ 2. lhs45_52'''›,) -> α51_54') +//│ | lhs45_52''' :> lhs45_53' +//│ | α51_54' <: int +//│ | eval56_57' <: ((‹∀ 2. rhs47_59'''›,) -> α58_61') +//│ | rhs47_59''' :> rhs47_60' +//│ | α58_61' <: int +//│ super: super37' +//│ fun eval: (α39'' -> (Int | α62'')) where +//│ | α39'' <: ((Lit<> & α40'') | ((Add<> & α44'') & ~(Lit<>))) +//│ | α40'' <: {n: n41_42''} +//│ | n41_42'' <: int +//│ | α44'' <: {rhs: rhs47_48''} & {lhs: lhs45_46''} +//│ | lhs45_46'' <: lhs45_53' +//│ | rhs47_48'' <: rhs47_60' +//│ | α62'' :> int +//│ [pretty-printed] eval: 'a -> (int | 'b) +//│ | where +//│ | 'b :> int +//│ | 'a <: Lit & 'c | Add & 'd & ~Lit +//│ | 'd <: {rhs: 'rhs} & {lhs: 'lhs} +//│ | 'lhs <: 'lhs0 +//│ | 'rhs <: 'rhs0 +//│ | 'c <: {n: 'n} +//│ | 'n <: int module TestLang: EvalBase @@ -60,25 +69,38 @@ class Neg(expr: A) //│ class Neg let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: α150 where -//│ | E24_34 :> Lit<> <: lhs49_132 & rhs51_130 -//│ | lhs49_126 :> Lit<> <: ((Lit<> & α44_127) | ((Add<> & α48_129) & ~(Lit<>))) -//│ | α44_127 :> Lit<> <: {n: n45_128} -//│ | n45_128 :> Int <: int -//│ | α48_129 :> (Add<> & {Add#E: mut E24_34..E24_34}) <: {rhs: rhs51_130} & {lhs: lhs49_132} -//│ | rhs51_130 :> Lit<> <: rhs51_131 -//│ | rhs51_131 :> Lit<> <: ((Lit<> & α44_127) | ((Add<> & α48_129) & ~(Lit<>))) -//│ | lhs49_132 :> Lit<> <: lhs49_126 -//│ | A141_149 :> (Add<> & {Add#E: mut E24_34..E24_34}) -//│ | α150 :> (Add<> & {Add#E: mut E24_151..E24_151}) -//│ | E24_151 :> (Neg<> & {Neg#A: mut A141_149..A141_149}) | Lit<> -//│ [pretty-printed] add2negadd11: Add & {Add#E = 'E} +//│ let add2negadd11: α137 where +//│ | E24_34 :> Lit<> <: lhs45_119 & rhs47_117 +//│ | lhs45_113 :> Lit<> <: ((Lit<> & α40_114) | ((Add<> & α44_116) & ~(Lit<>))) +//│ | α40_114 :> Lit<> <: {n: n41_115} +//│ | n41_115 :> Int <: int +//│ | α44_116 :> (Add<> & {Add#E: mut E24_34..E24_34}) <: {rhs: rhs47_117} & {lhs: lhs45_119} +//│ | rhs47_117 :> Lit<> <: rhs47_118 +//│ | rhs47_118 :> Lit<> <: ((Lit<> & α40_114) | ((Add<> & α44_116) & ~(Lit<>))) +//│ | lhs45_119 :> Lit<> <: lhs45_113 +//│ | A128_136 :> (Add<> & {Add#E: mut E24_34..E24_34}) +//│ | α137 :> (Add<> & {Add#E: mut E24_138..E24_138}) +//│ | E24_138 :> (Neg<> & {Neg#A: mut A128_136..A128_136}) | Lit<> +//│ [pretty-printed] add2negadd11: 'a //│ | where -//│ | 'E :> Lit | Neg & {Neg#A = 'A} +//│ | 'a :> Add & {Add#E = 'E} +//│ | 'E :> Neg & {Neg#A = 'A} | Lit //│ | 'A :> Add & {Add#E = 'E0} //│ | 'E0 :> Lit -//│ | <: 'lhs -//│ | 'lhs <: Add & {lhs: 'lhs, rhs: 'lhs} | Lit & {n: int} +//│ | <: 'lhs & 'rhs +//│ | 'lhs :> Lit +//│ | <: 'lhs0 +//│ | 'lhs0 :> Lit +//│ | <: Lit & 'b | Add & 'c & ~Lit +//│ | 'c :> Add & {Add#E = 'E0} +//│ | <: {rhs: 'rhs} & {lhs: 'lhs} +//│ | 'rhs :> Lit +//│ | <: 'rhs0 +//│ | 'rhs0 :> Lit +//│ | <: Lit & 'b | Add & 'c & ~Lit +//│ | 'b :> Lit +//│ | <: {n: 'n} +//│ | 'n := int mixin EvalNeg { @@ -87,22 +109,29 @@ mixin EvalNeg { else super.eval(e) } //│ mixin EvalNeg -//│ this: this175' -//│ | this175' <: {eval: eval183_184'} -//│ | eval183_184' <: ((‹∀ 2. expr180_186'''›,) -> α185_188') -//│ | expr180_186''' :> expr180_187' -//│ | α185_188' <: int -//│ super: super176' -//│ | super176' <: {eval: eval191_192'} -//│ | eval191_192' <: ((α190_194',) -> α193_195') -//│ fun eval: (α178'' -> (α189'' | α193'')) where -//│ | α178'' <: ((Neg<> & α179'') | (α190'' & ~(Neg<>))) -//│ | α179'' <: {expr: expr180_181''} -//│ | expr180_181'' <: expr180_187' -//│ | α189'' :> int -//│ | α190'' <: α190_194' -//│ | α193'' :> α193_195' -//│ [pretty-printed] eval: (Neg & {expr: anything} | ~Neg) -> int +//│ this: this140' +//│ | this140' <: {eval: eval148_149'} +//│ | eval148_149' <: ((‹∀ 2. expr145_151'''›,) -> α150_153') +//│ | expr145_151''' :> expr145_152' +//│ | α150_153' <: int +//│ super: super141' +//│ | super141' <: {eval: eval156_157'} +//│ | eval156_157' <: ((α155_159',) -> α158_160') +//│ fun eval: (α143'' -> (α154'' | α158'')) where +//│ | α143'' <: ((Neg<> & α144'') | (α155'' & ~(Neg<>))) +//│ | α144'' <: {expr: expr145_146''} +//│ | expr145_146'' <: expr145_152' +//│ | α154'' :> int +//│ | α155'' <: α155_159' +//│ | α158'' :> α158_160' +//│ [pretty-printed] eval: 'a -> ('b | 'c) +//│ | where +//│ | 'c :> 'd +//│ | 'b :> int +//│ | 'a <: Neg & 'e | 'f & ~Neg +//│ | 'f <: 'g +//│ | 'e <: {expr: 'expr} +//│ | 'expr <: 'expr0 module TestLang: EvalBase, EvalNeg diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 4de945a83d..315d67b55b 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -20,8 +20,9 @@ let s = Some(1) //│ let s: α32 where //│ | α32 :> (Some<> & {Some#A: mut A23_33..A23_33}) //│ | A23_33 :> 1 -//│ [pretty-printed] s: Some & {Some#A = 'A} +//│ [pretty-printed] s: 'a //│ | where +//│ | 'a :> Some & {Some#A = 'A} //│ | 'A :> 1 @@ -71,11 +72,12 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ let opt: (α72 | None<>) where -//│ | α72 :> (Some<> & {Some#A: mut A23_73..A23_73}) -//│ | A23_73 :> 123 -//│ [pretty-printed] opt: None | Some & {Some#A = 'A} +//│ let opt: (α68 | None<>) where +//│ | α68 :> (Some<> & {Some#A: mut A23_69..A23_69}) +//│ | A23_69 :> 123 +//│ [pretty-printed] opt: 'a | None //│ | where +//│ | 'a :> Some & {Some#A = 'A} //│ | 'A :> 123 opt.toArray @@ -100,21 +102,32 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ((α106', α107',) -> (None<> | α116')) where -//│ | α106' <: ((None<> & α108') | ((Some<> & α109') & ~(None<>))) -//│ | α107' <: ((‹∀ 1. value110''›,) -> α115') -//│ | α109' <: {value: value110_111'} -//│ | value110'' :> value110_111' -//│ | α115' <: A23_117' -//│ | α116' :> (Some<> & {Some#A: mut A23_117'..A23_117'}) -//│ [pretty-printed] map: (None | Some & {value: 'value}, 'value -> 'A,) -> (None | Some & {Some#A = 'A}) +//│ fun map: ((α98', α99',) -> (None<> | α108')) where +//│ | α98' <: ((None<> & α100') | ((Some<> & α101') & ~(None<>))) +//│ | α99' <: ((‹∀ 1. value102''›,) -> α107') +//│ | α101' <: {value: value102_103'} +//│ | value102'' :> value102_103' +//│ | α107' <: A23_109' +//│ | α108' :> (Some<> & {Some#A: mut A23_109'..A23_109'}) +//│ [pretty-printed] map: ('a, 'b,) -> (None | 'c) +//│ | where +//│ | 'c :> Some & {Some#A = 'A} +//│ | 'b <: (forall 'value. 'value) -> 'd +//│ | 'd <: 'A +//│ | 'value :> 'value0 +//│ | 'a <: None & 'e | Some & 'f & ~None +//│ | 'f <: {value: 'value0} let mo = map(opt, succ) -//│ let mo: α132 where -//│ | α132 :> (None<> | α116_140) -//│ | α116_140 :> (Some<> & {Some#A: mut A23_141..A23_142}) -//│ | A23_142 :> A23_141 | int -//│ [pretty-printed] mo: None | Some & {Some#A :> 'A <: 'A | int} +//│ let mo: α111 where +//│ | α111 :> (None<> | α108_119) +//│ | α108_119 :> (Some<> & {Some#A: mut A23_120..A23_121}) +//│ | A23_121 :> A23_120 | int +//│ [pretty-printed] mo: 'a +//│ | where +//│ | 'a :> None | 'b +//│ | 'b :> Some & {Some#A :> 'A <: 'A0} +//│ | 'A0 :> 'A | int mo.toArray //│ Typed: Array[int] @@ -125,10 +138,14 @@ class Test(n) { fun foo = n + 1 } //│ class Test -//│ fun foo: α165'' where -//│ | foo163'' :> int -//│ | α165'' :> int <: foo163'' -//│ [pretty-printed] foo: int +//│ fun foo: α138'' where +//│ | foo136'' :> int +//│ | α138'' :> int <: foo136'' +//│ [pretty-printed] foo: 'a +//│ | where +//│ | 'a :> int +//│ | <: 'foo +//│ | 'foo :> int Test(1) //│ Typed: Test @@ -136,16 +153,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.137: Test(true) +//│ ║ l.154: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.137: Test(true) +//│ ║ l.154: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.125: fun foo = n + 1 +//│ ║ l.138: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.124: class Test(n) { +//│ ║ l.137: class Test(n) { //│ ╙── ^ //│ Typed: Test | error @@ -155,19 +172,23 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.155: fun foo = n + 1 +//│ ║ l.172: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.155: fun foo = n + 1 +//│ ║ l.172: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.154: class Test(n: A) { +//│ ║ l.171: class Test(n: A) { //│ ╙── ^ //│ class Test -//│ fun foo: α187'' where -//│ | foo185'' :> int | error<> -//│ | α187'' :> error<> | int <: foo185'' -//│ [pretty-printed] foo: error | int +//│ fun foo: α159'' where +//│ | foo157'' :> int | error<> +//│ | α159'' :> error<> | int <: foo157'' +//│ [pretty-printed] foo: 'a +//│ | where +//│ | 'a :> error | int +//│ | <: 'foo +//│ | 'foo :> int | error Test(1) //│ Typed: Test & {Test#A = 'A} @@ -186,11 +207,11 @@ class Test(n: A) { fun id(x) = x } //│ class Test -//│ fun foo: ‘A210' where +//│ fun foo: ‘A181' where //│ [pretty-printed] foo: A -//│ fun foo1: ((x: ‘A210',) -> ‘A210') where +//│ fun foo1: ((x: ‘A181',) -> ‘A181') where //│ [pretty-printed] foo1: (x: A,) -> A -//│ fun id: (α216'' -> α216'') where +//│ fun id: (α187'' -> α187'') where //│ [pretty-printed] id: 'a -> 'a Test(1) @@ -205,11 +226,12 @@ Test("ok").foo //│ Typed: "ok" let t = Test(1) -//│ let t: α265 where -//│ | α265 :> (Test<> & {Test#A: mut A210_266..A210_266}) -//│ | A210_266 :> 1 -//│ [pretty-printed] t: Test & {Test#A = 'A} +//│ let t: α233 where +//│ | α233 :> (Test<> & {Test#A: mut A181_234..A181_234}) +//│ | A181_234 :> 1 +//│ [pretty-printed] t: 'a //│ | where +//│ | 'a :> Test & {Test#A = 'A} //│ | 'A :> 1 t.foo1(true) @@ -233,20 +255,22 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.233: fun foo2(x: A) = x + 1 +//│ ║ l.255: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.233: fun foo2(x: A) = x + 1 +//│ ║ l.255: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.231: class Test { +//│ ║ l.253: class Test { //│ ╙── ^ //│ class Test -//│ fun foo1: ((x: ‘A317',) -> ‘A317') where +//│ fun foo1: ((x: ‘A281',) -> ‘A281') where //│ [pretty-printed] foo1: (x: A,) -> A -//│ fun foo2: ((x: ‘A317',) -> α323'') where -//│ | α323'' :> error<> | int -//│ [pretty-printed] foo2: (x: A,) -> (error | int) +//│ fun foo2: ((x: ‘A281',) -> α287'') where +//│ | α287'' :> error<> | int +//│ [pretty-printed] foo2: (x: A,) -> 'a +//│ | where +//│ | 'a :> error | int Test().foo1 //│ Typed: (x: 'A,) -> 'A @@ -259,9 +283,11 @@ x => Test().foo1(x) // :d let t = Test() -//│ let t: α377 where -//│ | α377 :> ‹∀ 0. (Test<> & {Test#A: mut A317_374'..A317_374'})› -//│ [pretty-printed] t: Test & {Test#A = 'A} +//│ let t: α340 where +//│ | α340 :> ‹∀ 0. (Test<> & {Test#A: mut A281_337'..A281_337'})› +//│ [pretty-printed] t: 'a +//│ | where +//│ | 'a :> forall 'A. Test & {Test#A = 'A} t.foo1 //│ Typed: (x: 'A,) -> 'A @@ -277,10 +303,13 @@ t fun foo(x: Test) = x.foo1 -//│ fun foo: ((x: Test[Int],) -> foo1422') where -//│ | foo1422' :> ((x: A423#,) -> A423#) -//│ | A423# := int..int -//│ [pretty-printed] foo: (x: Test[int],) -> (x: int,) -> int +//│ fun foo: ((x: Test[Int],) -> foo1381') where +//│ | foo1381' :> ((x: A382#,) -> A382#) +//│ | A382# := int..int +//│ [pretty-printed] foo: (x: Test[int],) -> 'foo1 +//│ | where +//│ | 'foo1 :> (x: 'A,) -> 'A +//│ | 'A := int foo(t) //│ Typed: (x: int,) -> int diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index a46f449e89..ca1de79d51 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -18,40 +18,47 @@ fun fooo(x) = //│ fun fooo: (α26' -> α34') where //│ | α26' <: z29_36' //│ | α34' :> C<> -//│ [pretty-printed] fooo: anything -> C +//│ [pretty-printed] fooo: 'a -> 'b +//│ | where +//│ | 'b :> C +//│ | 'a <: 'z fun foo = bar fun bar = foo -//│ fun foo: foo40' where -//│ | foo40' <: bar41' -//│ [pretty-printed] foo: nothing -//│ fun bar: foo40' where -//│ | foo40' <: bar41' -//│ [pretty-printed] bar: nothing +//│ fun foo: foo37' where +//│ | foo37' <: bar38' +//│ [pretty-printed] foo: 'foo +//│ | where +//│ | 'foo <: 'bar +//│ fun bar: foo37' where +//│ | foo37' <: bar38' +//│ [pretty-printed] bar: 'foo +//│ | where +//│ | 'foo <: 'bar foo(bar) //│ Typed: nothing fun foo = {x: foo} -//│ fun foo: {x: foo46'} where -//│ | foo46' :> {x: foo46'} -//│ [pretty-printed] foo: 'foo +//│ fun foo: {x: foo41'} where +//│ | foo41' :> {x: foo41'} +//│ [pretty-printed] foo: {x: 'foo} //│ | where //│ | 'foo :> {x: 'foo} fun foo = {x: bar} fun bar = {y: foo} -//│ fun foo: {x: {y: foo50'}} where -//│ | foo50' :> {x: {y: foo50'}} -//│ [pretty-printed] foo: 'foo +//│ fun foo: {x: {y: foo42'}} where +//│ | foo42' :> {x: {y: foo42'}} +//│ [pretty-printed] foo: {x: {y: 'foo}} //│ | where //│ | 'foo :> {x: {y: 'foo}} -//│ fun bar: {y: foo50'} where -//│ | foo50' :> {x: {y: foo50'}} +//│ fun bar: {y: foo42'} where +//│ | foo42' :> {x: {y: foo42'}} //│ [pretty-printed] bar: {y: 'foo} //│ | where //│ | 'foo :> {x: {y: 'foo}} @@ -81,49 +88,61 @@ foo.x.y fun foo(a) = {h: a, t: bar(a)} fun bar(b) = foo(b) -//│ fun foo: (α76' -> {h: α76', t: α79'}) where -//│ | α76' <: α77' -//│ | α77' <: α76' -//│ | α79' :> {h: α76', t: α79'} -//│ [pretty-printed] foo: 'a -> 'b +//│ fun foo: (α62' -> {h: α62', t: α65'}) where +//│ | α62' <: α63' +//│ | α63' <: α62' +//│ | α65' :> {h: α62', t: α65'} +//│ [pretty-printed] foo: 'a -> {h: 'a, t: 'b} //│ | where //│ | 'b :> {h: 'a, t: 'b} -//│ fun bar: (α77' -> α78') where -//│ | α76' <: α77' -//│ | α77' <: α76' -//│ | α78' :> {h: α76', t: α79'} <: α79' -//│ | α79' :> {h: α76', t: α79'} +//│ | 'a <: 'c +//│ | 'c <: 'a +//│ fun bar: (α63' -> α64') where +//│ | α62' <: α63' +//│ | α63' <: α62' +//│ | α64' :> {h: α62', t: α65'} <: α65' +//│ | α65' :> {h: α62', t: α65'} //│ [pretty-printed] bar: 'a -> 'b //│ | where -//│ | 'b :> {h: 'a, t: 'b} +//│ | 'b :> {h: 'c, t: 'd} +//│ | <: 'd +//│ | 'd :> {h: 'c, t: 'd} +//│ | 'a <: 'c +//│ | 'c <: 'a :ns foo -//│ Typed: forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} +//│ Typed: forall 'a 'b 'c. 'b -> {h: 'b, t: 'a} //│ where -//│ 'c :> {h: 'a, t: 'c} -//│ 'a <: 'b -//│ 'b <: 'a +//│ 'a :> {h: 'b, t: 'a} +//│ 'b <: 'c +//│ 'c <: 'b fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} -//│ fun foo: (α97' -> {h1: α97', t1: α100'}) where -//│ | α97' <: α98' -//│ | α98' <: α97' -//│ | α99' :> {h1: α97', t1: α100'} -//│ | α100' :> {h2: α98', t2: α99'} -//│ [pretty-printed] foo: 'a -> 'b +//│ fun foo: (α68' -> {h1: α68', t1: α71'}) where +//│ | α68' <: α69' +//│ | α69' <: α68' +//│ | α70' :> {h1: α68', t1: α71'} +//│ | α71' :> {h2: α69', t2: α70'} +//│ [pretty-printed] foo: 'a -> {h1: 'a, t1: 'b} //│ | where -//│ | 'b :> {h1: 'a, t1: {h2: 'a, t2: 'b}} -//│ fun bar: (α98' -> {h2: α98', t2: α99'}) where -//│ | α97' <: α98' -//│ | α98' <: α97' -//│ | α99' :> {h1: α97', t1: α100'} -//│ | α100' :> {h2: α98', t2: α99'} -//│ [pretty-printed] bar: 'a -> 'b +//│ | 'b :> {h2: 'c, t2: 'd} +//│ | 'd :> {h1: 'a, t1: 'b} +//│ | 'a <: 'c +//│ | 'c <: 'a +//│ fun bar: (α69' -> {h2: α69', t2: α70'}) where +//│ | α68' <: α69' +//│ | α69' <: α68' +//│ | α70' :> {h1: α68', t1: α71'} +//│ | α71' :> {h2: α69', t2: α70'} +//│ [pretty-printed] bar: 'a -> {h2: 'a, t2: 'b} //│ | where -//│ | 'b :> {h2: 'a, t2: {h1: 'a, t1: 'b}} +//│ | 'b :> {h1: 'c, t1: 'd} +//│ | 'd :> {h2: 'a, t2: 'b} +//│ | 'a <: 'c +//│ | 'c <: 'a @@ -134,10 +153,14 @@ module Test0_2 { fun b = 123 } //│ class Test0_1 -//│ fun a: b125'' where -//│ | a121'' :> 123 -//│ | b125'' :> 123 <: a121'' -//│ [pretty-printed] a: 123 +//│ fun a: b80'' where +//│ | a76'' :> 123 +//│ | b80'' :> 123 <: a76'' +//│ [pretty-printed] a: 'b +//│ | where +//│ | 'b :> 123 +//│ | <: 'a +//│ | 'a :> 123 //│ class Test0_2 //│ fun b: 123 where //│ [pretty-printed] b: 123 @@ -152,10 +175,14 @@ class Test0_2() { fun b = 123 } //│ class Test0_1 -//│ fun a: b143'' where -//│ | a137'' :> 123 -//│ | b143'' :> 123 <: a137'' -//│ [pretty-printed] a: 123 +//│ fun a: b97'' where +//│ | a91'' :> 123 +//│ | b97'' :> 123 <: a91'' +//│ [pretty-printed] a: 'b +//│ | where +//│ | 'b :> 123 +//│ | <: 'a +//│ | 'a :> 123 //│ class Test0_2 //│ fun b: 123 where //│ [pretty-printed] b: 123 @@ -169,22 +196,30 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.165: module Test1_1 { +//│ ║ l.192: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.166: fun a = Test1_2.b +//│ ║ l.193: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.167: } +//│ ║ l.194: } //│ ╙── ^ //│ class Test1_1 -//│ fun a: b155'' where -//│ | a150'' :> error<> -//│ | b155'' :> error<> <: a150'' -//│ [pretty-printed] a: error +//│ fun a: b108'' where +//│ | a103'' :> error<> +//│ | b108'' :> error<> <: a103'' +//│ [pretty-printed] a: 'b +//│ | where +//│ | 'b :> error +//│ | <: 'a +//│ | 'a :> error //│ class Test1_2 -//│ fun b: a154'' where -//│ | b153'' :> error<> -//│ | a154'' :> error<> <: b153'' -//│ [pretty-printed] b: error +//│ fun b: a107'' where +//│ | b106'' :> error<> +//│ | a107'' :> error<> <: b106'' +//│ [pretty-printed] b: 'a +//│ | where +//│ | 'a :> error +//│ | <: 'b +//│ | 'b :> error Test1_1.a //│ Typed: error @@ -198,22 +233,30 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.194: class Test1_1 { +//│ ║ l.229: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.195: fun a = Test1_2().b +//│ ║ l.230: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.196: } +//│ ║ l.231: } //│ ╙── ^ //│ class Test1_1 -//│ fun a: b180'' where -//│ | a170'' :> error<> -//│ | b180'' :> error<> <: a170'' -//│ [pretty-printed] a: error +//│ fun a: b131'' where +//│ | a121'' :> error<> +//│ | b131'' :> error<> <: a121'' +//│ [pretty-printed] a: 'b +//│ | where +//│ | 'b :> error +//│ | <: 'a +//│ | 'a :> error //│ class Test1_2 -//│ fun b: a175'' where -//│ | b173'' :> error<> -//│ | a175'' :> error<> <: b173'' -//│ [pretty-printed] b: error +//│ fun b: a126'' where +//│ | b124'' :> error<> +//│ | a126'' :> error<> <: b124'' +//│ [pretty-printed] b: 'a +//│ | where +//│ | 'a :> error +//│ | <: 'b +//│ | 'b :> error // TODO check TV hygiene @@ -229,55 +272,71 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.220: module Test2_1 { +//│ ║ l.263: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.221: fun t2 = Test2_2 +//│ ║ l.264: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.222: fun a = Test2_2.b +//│ ║ l.265: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.223: fun d = Test2_2.e +//│ ║ l.266: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.224: fun n = 456 +//│ ║ l.267: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.225: } +//│ ║ l.268: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.220: module Test2_1 { +//│ ║ l.263: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.221: fun t2 = Test2_2 +//│ ║ l.264: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.222: fun a = Test2_2.b +//│ ║ l.265: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.223: fun d = Test2_2.e +//│ ║ l.266: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.224: fun n = 456 +//│ ║ l.267: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.225: } +//│ ║ l.268: } //│ ╙── ^ //│ class Test2_1 //│ fun t2: Test2_2<> where //│ [pretty-printed] t2: Test2_2 -//│ fun a: b201'' where -//│ | a191'' :> 123 -//│ | b201'' :> 123 <: a191'' -//│ [pretty-printed] a: 123 -//│ fun d: e209'' where -//│ | d192'' :> error<> -//│ | e209'' :> error<> <: d192'' -//│ [pretty-printed] d: error +//│ fun a: b150'' where +//│ | a140'' :> 123 +//│ | b150'' :> 123 <: a140'' +//│ [pretty-printed] a: 'b +//│ | where +//│ | 'b :> 123 +//│ | <: 'a +//│ | 'a :> 123 +//│ fun d: e158'' where +//│ | d141'' :> error<> +//│ | e158'' :> error<> <: d141'' +//│ [pretty-printed] d: 'e +//│ | where +//│ | 'e :> error +//│ | <: 'd +//│ | 'd :> error //│ fun n: 456 where //│ [pretty-printed] n: 456 //│ class Test2_2 //│ fun b: 123 where //│ [pretty-printed] b: 123 -//│ fun c: a199'' where -//│ | c197'' :> error<> -//│ | a199'' :> error<> <: c197'' -//│ [pretty-printed] c: error -//│ fun e: n200'' where -//│ | e198'' :> error<> -//│ | n200'' :> error<> <: e198'' -//│ [pretty-printed] e: error +//│ fun c: a148'' where +//│ | c146'' :> error<> +//│ | a148'' :> error<> <: c146'' +//│ [pretty-printed] c: 'a +//│ | where +//│ | 'a :> error +//│ | <: 'c +//│ | 'c :> error +//│ fun e: n149'' where +//│ | e147'' :> error<> +//│ | n149'' :> error<> <: e147'' +//│ [pretty-printed] e: 'n +//│ | where +//│ | 'n :> error +//│ | <: 'e +//│ | 'e :> error Test2_1.t2.b //│ Typed: 123 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index b782dfaded..a26ae0fe4f 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -21,7 +21,10 @@ class Base1(p: int): Over { //│ fun test: (Int, p33'',) where //│ | p33'' :> p33_34' //│ | p33_34' :> "hi" -//│ [pretty-printed] test: (int, "hi",) +//│ [pretty-printed] test: (int, 'p,) +//│ | where +//│ | 'p :> 'p0 +//│ | 'p0 :> "hi" Base1(123).test diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 600500879d..00593c523b 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -491,11 +491,14 @@ class DiffTests val (typeDefs, stmts) = if (newDefs) { + /* val vars: Map[Str, typer.SimpleType] = Map.empty val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise, vars) tpd.force()(raise) + // val sctx = ShowCtx.mk(tpd) + def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind ttu.entities.map(_.complete()(raise)).foreach { @@ -511,14 +514,18 @@ class DiffTests // tm.ttu.entities.foreach { } showTTU(tm.ttu, ind + 1) case tf: typer.TypedNuFun => - val exp = getType(tf.ty) + // val exp = getType(tf.ty) output(s"${indStr}${tf.fd.isLetRec match { case S(false) => "let" case S(true) => "let rec" case N => "fun" }} ${tf.name}: ${tf.ty} where ${tf.ty.showBounds .indentNewLines(indStr+"|")}") - output(s"${indStr}[pretty-printed] ${tf.name}: ${exp.show.indentNewLines(indStr+"|")}") + output(s"${indStr}[pretty-printed] ${tf.name}: ${ + // exp.show + typer.expandType(tf.ty)(ctx).show + // typer.expandType(tf.ty)(ctx).showIn(sctx) + .indentNewLines(indStr+"|")}") } } showTTU(tpd, 0) @@ -529,6 +536,21 @@ class DiffTests val exp = getType(typer.PolymorphicType(0, res_ty)) output(s"Typed: ${exp.show}") } + */ + + import typer._ + + val mod = NuTypeDef(Nms, TypeName("ws"), Nil, Tup(Nil), Nil, TypingUnit(p.tops)) + val info = new LazyTypeInfo(ctx.lvl, mod)(ctx, Map.empty) + // val modTpe = DeclType(ctx.lvl, info) + info.force()(raise) + + // val tpd = info + + + // val exp = typer.expandType(modTpe)(ctx) + // FirstClassDefn() + (Nil, Nil) From 9a4e06ae28741aef1303c61cc7280238fddef91b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 00:16:34 +0800 Subject: [PATCH 044/498] WIP --- js/src/main/scala/Main.scala | 2 +- shared/src/main/scala/mlscript/Message.scala | 6 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 25 +- shared/src/main/scala/mlscript/Typer.scala | 21 +- .../main/scala/mlscript/TyperDatatypes.scala | 13 +- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/main/scala/mlscript/helpers.scala | 59 +++-- shared/src/main/scala/mlscript/syntax.scala | 11 +- shared/src/test/diff/nu/BasicClasses.mls | 213 ++++++++++++------ shared/src/test/diff/nu/LetRec.mls | 2 +- .../src/test/scala/mlscript/DiffTests.scala | 21 +- 11 files changed, 271 insertions(+), 108 deletions(-) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index 19dd8c77e2..c836365da4 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -202,7 +202,7 @@ object Main { val curBlockTypeDefs = typeDefs.flatMap(td => ctx.tyDefs.get(td.nme.name)) typer.computeVariances(curBlockTypeDefs, ctx) - def getType(ty: typer.SimpleType): Type = { + def getType(ty: typer.SimpleType): mlscript.TypeLike = { object SimplifyPipeline extends typer.SimplifyPipeline { def debugOutput(msg: => Str): Unit = println(msg) } diff --git a/shared/src/main/scala/mlscript/Message.scala b/shared/src/main/scala/mlscript/Message.scala index eaea0679a0..be7342bfff 100644 --- a/shared/src/main/scala/mlscript/Message.scala +++ b/shared/src/main/scala/mlscript/Message.scala @@ -8,7 +8,7 @@ final case class Message(bits: Ls[Message.Bit]) { val ctx = ShowCtx.mk(typeBits) showIn(ctx) } - def typeBits: Ls[Type] = bits.collect{ case Message.Code(t) => t } + def typeBits: Ls[TypeLike] = bits.collect{ case Message.Code(t) => t } def showIn(ctx: ShowCtx): Str = { bits.map { case Message.Code(ty) => ty.showIn(ctx, 0) @@ -32,8 +32,8 @@ object Message { sealed abstract class Bit final case class Text(str: Str) extends Bit - final case class Code(ty: Type) extends Bit - implicit def fromType(ty: Type): Message = Message(Code(ty)::Nil) + final case class Code(ty: TypeLike) extends Bit + implicit def fromType(ty: TypeLike): Message = Message(Code(ty)::Nil) implicit def fromStr(str: Str): Message = Message(Text(str)::Nil) implicit class MessageContext(private val ctx: StringContext) { diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 6f5a022c97..9bc26b7fb6 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -116,7 +116,28 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuTypeDefBase with TypedNuDecl { def nme: TypeName // val tparams: Ls[TN -> TV] = Nil // TODO - override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = ??? + override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = + this match { + case m @ TypedNuMxn(td, thisTV, superTV, ttu) => + // println(">>",m.level) + // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) + // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) + TypedNuMxn(td, + thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], + superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], + ttu.freshenAbove(lim, rigidify)) + case TypedNuCls(level, td, ttu, tps, params, members) => + println(">>",level,ctx.lvl) + // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), + // params.mapValues(_.freshenAbove(level, rigidify)), + // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) + TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), + tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), + params.mapValues(_.freshenAbove(lim, rigidify)), + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap) + // case _ => ??? + // } + } // val prov: TP val td: NuTypeDef val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) @@ -171,7 +192,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) { + case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) extends OtherTypeLike { // def freshen(implicit ctx: Ctx): TypedTypingUnit = ??? def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ed289b4dc2..3ac52f621b 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1171,7 +1171,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) /** Convert an inferred SimpleType into the immutable Type representation. */ - def expandType(st: SimpleType, stopAtTyVars: Bool = false)(implicit ctx: Ctx): Type = { + def expandType(st: TypeLike, stopAtTyVars: Bool = false)(implicit ctx: Ctx): mlscript.TypeLike = { val expandType = () import Set.{empty => semp} @@ -1188,6 +1188,16 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Field(f.lb.map(go), go(f.ub)) } + def goLike(ty: TypeLike): mlscript.TypeLike = ty match { + case ty: SimpleType => + val res = go(ty) + if (bounds.isEmpty) res + else Constrained(res, bounds, Nil) + case OtherTypeLike(ttu) => + + Signature(Nil) + } + def go(st: SimpleType): Type = // trace(s"expand $st") { st.unwrapProvs match { @@ -1265,13 +1275,14 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // case DeclType(lvl, info) => - } // }(r => s"~> $r") - val res = go(st) - if (bounds.isEmpty) res - else Constrained(res, bounds, Nil) + // val res = go(st) + // if (bounds.isEmpty) res + // else Constrained(res, bounds, Nil) + + goLike(st) } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 7c1160bff2..b840daa3b5 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -482,8 +482,19 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => body.fold(PolymorphicType(MinLevel, errType))(b => PolymorphicType(level, ProvType(b._2)(prov))) } + sealed abstract class TypeLike { + def unwrapProvs: TypeLike + } + abstract class OtherTypeLike extends TypeLike { + this: TypedTypingUnit => def self: TypedTypingUnit = this + def unwrapProvs: TypeLike = this + } + object OtherTypeLike { + def unapply(ot: OtherTypeLike): S[TypedTypingUnit] = S(ot.self) + } + /** A general type form (TODO: rename to AnyType). */ - sealed abstract class SimpleType extends SimpleTypeImpl { + sealed abstract class SimpleType extends TypeLike with SimpleTypeImpl { val prov: TypeProvenance def level: Level def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 45eac02c69..fc710dfdb1 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -826,9 +826,9 @@ abstract class TyperHelpers { Typer: Typer => + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & "))) }.mkString - def expPos(implicit ctx: Ctx): Type = exp(S(true), this) - def expNeg(implicit ctx: Ctx): Type = exp(S(false), this) - def exp(pol: Opt[Bool], ty: ST)(implicit ctx: Ctx): Type = ( + def expPos(implicit ctx: Ctx): mlscript.TypeLike = exp(S(true), this) + def expNeg(implicit ctx: Ctx): mlscript.TypeLike = exp(S(false), this) + def exp(pol: Opt[Bool], ty: ST)(implicit ctx: Ctx): mlscript.TypeLike = ( ty // |> (_.normalize(false)) // |> (simplifyType(_, pol, removePolarVars = false, inlineBounds = false)) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index e837dfdb52..18ff3fb1a5 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -11,23 +11,11 @@ import mlscript.utils._, shorthands._ // Auxiliary definitions for types -abstract class TypeImpl extends Located { self: Type => - - lazy val typeVarsList: List[TypeVar] = this match { - case uv: TypeVar => uv :: Nil - case Recursive(n, b) => n :: b.typeVarsList - case _ => children.flatMap(_.typeVarsList) - } +trait SignatureImpl extends Located { self: Signature => + def children: List[Located] = members +} - /** - * @return - * set of free type variables in type - */ - lazy val freeTypeVariables: Set[TypeVar] = this match { - case Recursive(uv, body) => body.freeTypeVariables - uv - case t: TypeVar => Set.single(t) - case _ => this.children.foldRight(Set.empty[TypeVar])((ty, acc) => ty.freeTypeVariables ++ acc) - } +trait TypeLikeImpl extends Located { self: TypeLike => def show: Str = showIn(ShowCtx.mk(this :: Nil), 0) @@ -115,9 +103,18 @@ abstract class TypeImpl extends Located { self: Type => }.mkString}${ws.map{ case Bounds(lo, hi) => s"\n ${lo.showIn(ctx, 0)} <: ${hi.showIn(ctx, 0)}" // TODO print differently from bs? }.mkString}", outerPrec > 0) + case NuFunDef(isLetRec, nme, targs, rhs) => + s"${isLetRec match { + case S(false) => "let" + case S(true) => "let rec" + case N => "fun" + }} ${nme.name}[${targs.map(_.showIn(ctx, 0).mkString(", "))}]${rhs match { + case L(trm) => s" = ..." + case R(ty) => ty.showIn(ctx, 0) + }}" } - def children: List[Type] = this match { + def childrenTypes: List[TypeLike] = this match { case _: NullaryType => Nil case Function(l, r) => l :: r :: Nil case Bounds(l, r) => l :: r :: Nil @@ -133,8 +130,32 @@ abstract class TypeImpl extends Located { self: Type => case PolyType(targs, body) => targs.map(_.fold(identity, identity)) :+ body case Splice(fs) => fs.flatMap{ case L(l) => l :: Nil case R(r) => r.in.toList ++ (r.out :: Nil) } case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) + case Signature(xs) => xs + case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList } + + lazy val typeVarsList: List[TypeVar] = this match { + case uv: TypeVar => uv :: Nil + case Recursive(n, b) => n :: b.typeVarsList + case _ => childrenTypes.flatMap(_.typeVarsList) + } + + /** + * @return + * set of free type variables in type + */ + lazy val freeTypeVariables: Set[TypeVar] = this match { + case Recursive(uv, body) => body.freeTypeVariables - uv + case t: TypeVar => Set.single(t) + case _ => childrenTypes.foldRight(Set.empty[TypeVar])((ty, acc) => ty.freeTypeVariables ++ acc) + } + +} +trait TypeImpl extends Located { self: Type => + + def children: List[Located] = childrenTypes + /** * Collect fields recursively during code generation. * Note that the type checker will reject illegal cases. @@ -186,7 +207,7 @@ object ShowCtx { * completely new names. If same name exists increment counter suffix * in the name. */ - def mk(tys: IterableOnce[Type], _pre: Str = "'", debug: Bool = false): ShowCtx = { + def mk(tys: IterableOnce[TypeLike], _pre: Str = "'", debug: Bool = false): ShowCtx = { val (otherVars, namedVars) = tys.iterator.toList.flatMap(_.typeVarsList).distinct.partitionMap { tv => tv.identifier match { case L(_) => L(tv.nameHint -> tv); case R(nh) => R(nh -> tv) } } @@ -313,7 +334,7 @@ trait NuDeclImpl extends Located { self: NuDecl => case _: NuFunDef => "definition" case _: NuTypeDef => "type declaration" } - def show: Str = showHead + (this match { + def showDbg: Str = showHead + (this match { case NuFunDef(_, _, _, L(_)) => " = " case NuFunDef(_, _, _, R(_)) => ": " case NuTypeDef(_, _, _, _, _, _) => " " diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 9b0c4aeffc..3e6920ae44 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -117,7 +117,9 @@ sealed trait Terms extends DesugaredStatement // Types -sealed abstract class Type extends TypeImpl +sealed abstract class TypeLike extends TypeLikeImpl + +sealed abstract class Type extends TypeLike with TypeImpl sealed trait NamedType extends Type { val base: TypeName } @@ -164,8 +166,11 @@ final case class PolyType(targs: Ls[TypeName \/ TypeVar], body: Type) extends Ty // New Definitions AST final case class TypingUnit(entities: Ls[Statement]) extends PgrmOrTypingUnit with TypingUnitImpl +// final case class TypingUnit(entities: Ls[Statement]) extends TypeLike with PgrmOrTypingUnit with TypingUnitImpl + +final case class Signature(members: Ls[NuDecl]) extends TypeLike with SignatureImpl -sealed abstract class NuDecl extends Statement with NuDeclImpl +sealed abstract class NuDecl extends TypeLike with Statement with NuDeclImpl final case class NuTypeDef( kind: TypeDefKind, @@ -186,5 +191,5 @@ final case class NuFunDef( } -sealed abstract class PgrmOrTypingUnit // TODO rm +sealed trait PgrmOrTypingUnit // TODO rm diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 03eada7ce4..cdf02dc21c 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -8,6 +8,11 @@ class C { fun id(x) = x fun const(x) = id } +//│ class C +//│ fun id: (α27'' -> α27'') where +//│ [pretty-printed] id: 'a -> 'a +//│ fun const: (α28'' -> (α27'' -> α27'')) where +//│ [pretty-printed] const: 'a -> 'b -> 'b class Base0(n) { @@ -16,45 +21,97 @@ class Base0(n) { fun mine = my fun oops = this.my } -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing -//│ at: scala.Predef$.$qmark$qmark$qmark(Predef.scala:344) -//│ at: mlscript.NuTypeDefs$TypedNuTypeDef.freshenAbove(NuTypeDefs.scala:119) -//│ at: mlscript.ConstraintSolver.lookupNuTypeDef$1(ConstraintSolver.scala:486) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94(ConstraintSolver.scala:667) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94$adapted(ConstraintSolver.scala:666) -//│ at: scala.collection.immutable.List.foreach(List.scala:333) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93(ConstraintSolver.scala:666) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93$adapted(ConstraintSolver.scala:654) -//│ at: mlscript.utils.package$GenHelper$.$bar$greater$extension(package.scala:111) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$89(ConstraintSolver.scala:654) +//│ class Base0 +//│ fun me: this31' where +//│ | this31' :> Base0<> <: {my: my39_40'} & {n: n37_38'} +//│ | n37_38' :> n30_66 +//│ | my39_40' :> n37_46 +//│ | n37_46 :> n37_44 <: mine35_47 & my34_48 +//│ | mine35_47 :> n37_44 +//│ | my34_48 :> n37_44 +//│ [pretty-printed] me: 'this +//│ | where +//│ | 'this :> Base0 +//│ | <: {my: 'my} & {n: 'n} +//│ | 'n :> 'n0 +//│ | 'my :> 'n1 +//│ | 'n1 :> 'n2 +//│ | <: 'mine & 'my0 +//│ | 'my0 :> 'n2 +//│ | 'mine :> 'n2 +//│ fun my: n37'' where +//│ | my34'' :> n37_38' +//│ | mine35'' :> n37_38' +//│ | n37'' :> n37_38' <: mine35'' & my34'' +//│ | n37_38' :> n30_66 +//│ [pretty-printed] my: 'n +//│ | where +//│ | 'n :> 'n0 +//│ | <: 'mine & 'my +//│ | 'my :> 'n0 +//│ | 'mine :> 'n0 +//│ | 'n0 :> 'n1 +//│ fun mine: n37'' where +//│ | my34'' :> n37_38' +//│ | mine35'' :> n37_38' +//│ | n37'' :> n37_38' <: mine35'' & my34'' +//│ | n37_38' :> n30_66 +//│ [pretty-printed] mine: 'n +//│ | where +//│ | 'n :> 'n0 +//│ | <: 'mine & 'my +//│ | 'my :> 'n0 +//│ | 'mine :> 'n0 +//│ | 'n0 :> 'n1 +//│ fun oops: my39'' where +//│ | oops36'' :> my39_40' +//│ | my39'' :> my39_40' <: oops36'' +//│ | my39_40' :> n37_46 +//│ | n37_46 :> n37_44 <: mine35_47 & my34_48 +//│ | mine35_47 :> n37_44 +//│ | my34_48 :> n37_44 +//│ [pretty-printed] oops: 'my +//│ | where +//│ | 'my :> 'my0 +//│ | <: 'oops +//│ | 'oops :> 'my0 +//│ | 'my0 :> 'n +//│ | 'n :> 'n0 +//│ | <: 'mine & 'my1 +//│ | 'my1 :> 'n0 +//│ | 'mine :> 'n0 // :d // Base0 // Base0 let b1 = Base0(42) -//│ ╔══[ERROR] identifier not found: Base0 -//│ ║ l.35: let b1 = Base0(42) -//│ ╙── ^^^^^ +//│ let b1: α81 where +//│ | α81 :> Base0<> +//│ [pretty-printed] b1: 'a +//│ | where +//│ | 'a :> Base0 // :d let n1 = b1.n -//│ ╔══[ERROR] identifier not found: b1 -//│ ║ l.41: let n1 = b1.n -//│ ╙── ^^ +//│ let n1: n84 where +//│ [pretty-printed] n1: 'n // TODO n1 + 1 -//│ ╔══[ERROR] identifier not found: n1 -//│ ║ l.47: n1 + 1 -//│ ╙── ^^ +//│ Typed: int let b2 = Base0("hi") let n2 = b2.n -//│ ╔══[ERROR] identifier not found: Base0 -//│ ║ l.53: let b2 = Base0("hi") -//│ ╙── ^^^^^ +//│ let b2: α116 where +//│ | α116 :> Base0<> <: {n: n118} +//│ [pretty-printed] b2: 'a +//│ | where +//│ | 'a :> Base0 +//│ | <: {n: 'n} +//│ let n2: n118 where +//│ [pretty-printed] n2: 'n @@ -63,64 +120,78 @@ class Base1(base: int) { fun getBase2 = this.base fun foo(x) = this.base + x } -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing -//│ at: scala.Predef$.$qmark$qmark$qmark(Predef.scala:344) -//│ at: mlscript.NuTypeDefs$TypedNuTypeDef.freshenAbove(NuTypeDefs.scala:119) -//│ at: mlscript.ConstraintSolver.lookupNuTypeDef$1(ConstraintSolver.scala:486) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94(ConstraintSolver.scala:667) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$94$adapted(ConstraintSolver.scala:666) -//│ at: scala.collection.immutable.List.foreach(List.scala:333) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93(ConstraintSolver.scala:666) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$93$adapted(ConstraintSolver.scala:654) -//│ at: mlscript.utils.package$GenHelper$.$bar$greater$extension(package.scala:111) -//│ at: mlscript.ConstraintSolver.$anonfun$constrainImpl$89(ConstraintSolver.scala:654) +//│ class Base1 +//│ fun getBase1: Int where +//│ [pretty-printed] getBase1: int +//│ fun getBase2: base138'' where +//│ | getBase2136'' :> base138_139' +//│ | base138'' :> base138_139' <: getBase2136'' +//│ | base138_139' :> Int +//│ [pretty-printed] getBase2: 'base +//│ | where +//│ | 'base :> 'base0 +//│ | <: 'getBase2 +//│ | 'getBase2 :> 'base0 +//│ | 'base0 :> int +//│ fun foo: (α140'' -> α144'') where +//│ | α140'' <: int +//│ | α144'' :> int +//│ [pretty-printed] foo: 'a -> 'b +//│ | where +//│ | 'b :> int +//│ | 'a <: int class Base1(base: int) { fun getBase1 = base fun me = this fun foo(x) = base + x } +//│ class Base1 +//│ fun getBase1: Int where +//│ [pretty-printed] getBase1: int +//│ fun me: this162' where +//│ | this162' :> Base1<> +//│ [pretty-printed] me: 'this +//│ | where +//│ | 'this :> Base1 +//│ fun foo: (α167'' -> α169'') where +//│ | α167'' <: int +//│ | α169'' :> int +//│ [pretty-printed] foo: 'a -> 'b +//│ | where +//│ | 'b :> int +//│ | 'a <: int Base1 -//│ ╔══[ERROR] identifier not found: Base1 -//│ ║ l.84: Base1 -//│ ╙── ^^^^^ +//│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ ╔══[ERROR] identifier not found: Base1 -//│ ║ l.89: let b = Base1(1) -//│ ╙── ^^^^^ +//│ let b: α183 where +//│ | α183 :> Base1<> +//│ [pretty-printed] b: 'a +//│ | where +//│ | 'a :> Base1 b.base -//│ ╔══[ERROR] identifier not found: b -//│ ║ l.94: b.base -//│ ╙── ^ +//│ Typed: int b.getBase1 -//│ ╔══[ERROR] identifier not found: b -//│ ║ l.99: b.getBase1 -//│ ╙── ^ +//│ Typed: int // :d b.me -//│ ╔══[ERROR] identifier not found: b -//│ ║ l.105: b.me -//│ ╙── ^ +//│ Typed: Base1 :e b.getBaseTypo -//│ ╔══[ERROR] identifier not found: b -//│ ║ l.111: b.getBaseTypo -//│ ╙── ^ +//│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` +//│ ║ l.186: b.getBaseTypo +//│ ╙── ^^^^^^^^^^^^ +//│ Typed: error b : Base1 -//│ ╔══[ERROR] identifier not found: b -//│ ║ l.117: b : Base1 -//│ ╙── ^ -//│ ╔══[ERROR] type identifier not found: Base1 -//│ ║ l.117: b : Base1 -//│ ╙── ^^^^^ +//│ Typed: Base1 :e // TODO @@ -128,12 +199,21 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.127: class Rec(n) { +//│ ║ l.198: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.128: fun go = Rec(n + 1) +//│ ║ l.199: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.129: } +//│ ║ l.200: } //│ ╙── ^ +//│ class Rec +//│ fun go: α223'' where +//│ | go220'' :> error<> +//│ | α223'' :> error<> <: go220'' +//│ [pretty-printed] go: 'a +//│ | where +//│ | 'a :> error +//│ | <: 'go +//│ | 'go :> error @@ -144,17 +224,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.143: a: int +//│ ║ l.223: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.142: class Annots(base: 0 | 1) { +//│ ║ l.222: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.143: a: int +//│ ║ l.223: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.143: a: int +//│ ║ l.223: a: int //│ ╙── ^^^ +//│ class Annots +//│ fun a: ((0 | 1),) where +//│ [pretty-printed] a: (0 | 1,) diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index a1ca2c44a9..1bb24ae4d6 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -71,7 +71,7 @@ f :p let rec f = 1 //│ |#let| |#rec| |f| |#=| |1| -//│ Parsed: let rec f = 1; +//│ Parsed: let rec f[List()] = ...; //│ Desugared: rec def f: 1 //│ AST: Def(true, f, IntLit(1), false) //│ f: 1 diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 00593c523b..32d57964fb 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -462,7 +462,11 @@ class DiffTests val oldCtx = ctx - def getType(ty: typer.SimpleType): Type = { + def getType(ty: typer.SimpleType): Type = getTypeLike(ty) match { + case ty: Type => ty + case _ => die + } + def getTypeLike(ty: typer.SimpleType): TypeLike = { if (mode.isDebugging) output(s"⬤ Typed as: $ty") if (mode.isDebugging) output(s" where: ${ty.showBounds}") typer.dbg = mode.dbgSimplif @@ -491,12 +495,14 @@ class DiffTests val (typeDefs, stmts) = if (newDefs) { - /* + // /* val vars: Map[Str, typer.SimpleType] = Map.empty val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise, vars) tpd.force()(raise) + val exp = typer.expandType(tpd)(ctx) + // val sctx = ShowCtx.mk(tpd) def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { @@ -536,14 +542,16 @@ class DiffTests val exp = getType(typer.PolymorphicType(0, res_ty)) output(s"Typed: ${exp.show}") } - */ + // */ + /* import typer._ val mod = NuTypeDef(Nms, TypeName("ws"), Nil, Tup(Nil), Nil, TypingUnit(p.tops)) val info = new LazyTypeInfo(ctx.lvl, mod)(ctx, Map.empty) // val modTpe = DeclType(ctx.lvl, info) info.force()(raise) + */ // val tpd = info @@ -653,7 +661,10 @@ class DiffTests .withFilter { case (mthd, _) => mthd.rhs.isRight || !mthDeclSet.contains(mthd.nme.name) } - .map { case (mthd, mthdTy) => (mthd.nme.name, mthdTy) } + .map { + case (mthd, mthdTy: Type) => (mthd.nme.name, mthdTy) + case _ => die + } tsTypegenCodeBuilder.addTypeDef(td, methods) } @@ -703,7 +714,7 @@ class DiffTests ctx += nme.name -> typer.VarSymbol(ty_sch, nme) declared += nme.name -> ty_sch - val exp = getType(ty_sch) + val exp = getType(ty_sch).asInstanceOf[Type] if (mode.generateTsDeclarations) tsTypegenCodeBuilder.addTypeGenTermDefinition(exp, Some(nme.name)) S(nme.name -> (s"$nme: ${exp.show}" :: Nil)) From 083149f1f79d9dfef7ce0b32547acf5abf1bffc7 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 01:04:25 +0800 Subject: [PATCH 045/498] WIPIP --- .../mlscript/compiler/PrettyPrinter.scala | 2 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 7 +- shared/src/main/scala/mlscript/Typer.scala | 40 ++- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 33 +- shared/src/main/scala/mlscript/syntax.scala | 7 +- .../main/scala/mlscript/utils/package.scala | 6 +- shared/src/test/diff/nu/BasicClasses.mls | 202 ++++------- shared/src/test/diff/nu/BasicMixins.mls | 282 ++++++++-------- shared/src/test/diff/nu/ECOOP23.mls | 164 ++++----- shared/src/test/diff/nu/GenericClasses.mls | 221 ++++++------ shared/src/test/diff/nu/LetRec.mls | 2 +- shared/src/test/diff/nu/MutualRec.mls | 317 +++++++----------- shared/src/test/diff/nu/ParamOverriding.mls | 34 +- .../src/test/scala/mlscript/DiffTests.scala | 3 + 15 files changed, 610 insertions(+), 712 deletions(-) diff --git a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala index 9fbc95877b..f2a10bef01 100644 --- a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala @@ -40,7 +40,7 @@ object PrettyPrinter: then "" else funDef.targs.map(_.name).mkString("[", ", ", "]")) + " = " - + funDef.rhs.fold(_.toString, _.body.show) + + funDef.rhs.fold(_.toString, _.show) def showTypeDef(tyDef: NuTypeDef, indent: Int = 0): String = s"${tyDef.kind.str} ${tyDef.nme.name}" diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 9bc26b7fb6..f3fd3e7185 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -126,7 +126,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], ttu.freshenAbove(lim, rigidify)) - case TypedNuCls(level, td, ttu, tps, params, members) => + case TypedNuCls(level, td, ttu, tps, params, members, thisTy) => println(">>",level,ctx.lvl) // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), // params.mapValues(_.freshenAbove(level, rigidify)), @@ -134,7 +134,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), params.mapValues(_.freshenAbove(lim, rigidify)), - members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap) + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, + thisTy.freshenAbove(lim, rigidify)) // case _ => ??? // } } @@ -166,7 +167,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuCls(level: Level, td: NuTypeDef, ttu: TypedTypingUnit, tparams: Ls[TN -> TV], params: Ls[Var -> FieldType], // members: Map[Str, LazyTypeInfo]) - members: Map[Str, NuMember]) + members: Map[Str, NuMember], thisTy: ST) extends TypedNuTypeDef(Cls) with TypedNuTermDef { // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { def nme: TypeName = td.nme diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3ac52f621b..039824ef98 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1188,14 +1188,50 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Field(f.lb.map(go), go(f.ub)) } + def mkTypingUnit(thisTy: ST, members: Map[Str, NuMember]): TypingUnit = { + val sorted = members.toList.sortBy(_._1) + // def mkTypingUnit(members: Ls[Str -> NuMember]): TypingUnit = { + TypingUnit( + // Asc(Var("this"), go(thisTy)) :: + NuFunDef(S(false), Var("this"), Nil, R(go(thisTy))) :: + sorted.collect { + case (_, td: TypedNuDecl) => goDecl(td) + case (_, td: TypedNuFun) => ??? + // case (_, p: NuParam) => ??? + // case _ => die + }) + } + def goDecl(d: TypedNuDecl): NuDecl = d match { + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => + NuTypeDef(td.kind, td.nme, td.tparams, + // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) + Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + Nil,//TODO + mkTypingUnit(thisTy, members)) + // mkTypingUnit(() :: members.toList.sortBy(_._1))) + case TypedNuFun(level, fd, ty) => + NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(ty))) + } def goLike(ty: TypeLike): mlscript.TypeLike = ty match { case ty: SimpleType => val res = go(ty) if (bounds.isEmpty) res else Constrained(res, bounds, Nil) case OtherTypeLike(ttu) => - - Signature(Nil) + val mems = ttu.entities.map { lti => + lti.result match { + // // case S(td: TypedNuTermDef) => ??? + // case S(TypedNuCls(level, td, ttu, tparams, params, members)) => + // NuTypeDef(td.kind, td.nme, td.tparams, + // // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) + // Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + // Nil,//TODO + // members) + case S(d) => goDecl(d) + case N => lastWords("Cannot expand uncomputed type info.") + } + } + Signature(mems, ttu.result.map(go)) } def go(st: SimpleType): Type = diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index b840daa3b5..257b0a783c 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -271,7 +271,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // val mems = baseMems ++ paramMems ++ clsMems val mems = baseMems ++ clsMems TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems.map(d => d.name -> d).toMap) + tparams, typedParams, mems.map(d => d.name -> d).toMap, thisTV) } case Mxn => implicit val prov: TP = noProv // TODO diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 18ff3fb1a5..12a47c5813 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -108,10 +108,28 @@ trait TypeLikeImpl extends Located { self: TypeLike => case S(false) => "let" case S(true) => "let rec" case N => "fun" - }} ${nme.name}[${targs.map(_.showIn(ctx, 0).mkString(", "))}]${rhs match { - case L(trm) => s" = ..." - case R(ty) => ty.showIn(ctx, 0) + }} ${nme.name}${targs.map(_.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}${rhs match { + case L(trm) => " = ..." + case R(ty) => ": " + ty.showIn(ctx, 0) }}" + case Signature(decls, res) => + decls.map("\n" + _.showIn(ctx, 0)).mkString + (res match { + case S(ty) => "\n" + ty.showIn(ctx, 0) + case N => "" + }) + case NuTypeDef(kind, nme, tparams, params, parents, body) => + s"${kind.str} ${nme.name}${tparams.map(_.showIn(ctx, 0))mkStringOr(", ", "[", "]")}(${ + params.fields.map { + case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) + case (N, _) => "???" + case (S(nme), rhs) => nme.name + }.mkString(", ") + })${parents match { + case Nil => "" + case ps => ps.mkString(", ") // TODO pp + }}${if (body.entities.isEmpty) "" else + " {" + Signature(body.entities.collect { case d: NuDecl => d }, N).showIn(ctx, 0) + "\n}" + }" } def childrenTypes: List[TypeLike] = this match { @@ -130,8 +148,15 @@ trait TypeLikeImpl extends Located { self: TypeLike => case PolyType(targs, body) => targs.map(_.fold(identity, identity)) :+ body case Splice(fs) => fs.flatMap{ case L(l) => l :: Nil case R(r) => r.in.toList ++ (r.out :: Nil) } case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) - case Signature(xs) => xs + case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList + case NuTypeDef(kind, nme, tparams, params, parents, body) => + // TODO improve this mess + tparams ::: params.fields.collect { + case (_, Fld(_, _, Asc(_, ty))) => ty + } ::: Signature(body.entities.collect { + case d: NuDecl => d + }, N) :: Nil // TODO parents? } lazy val typeVarsList: List[TypeVar] = this match { diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 3e6920ae44..3a31f2beb0 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -8,7 +8,7 @@ import mlscript.utils._, shorthands._ final case class Pgrm(tops: Ls[Statement]) extends PgrmOrTypingUnit with PgrmImpl sealed abstract class Decl extends DesugaredStatement with DeclImpl -final case class Def(rec: Bool, nme: Var, rhs: Term \/ PolyType, isByname: Bool) extends Decl with Terms { +final case class Def(rec: Bool, nme: Var, rhs: Term \/ Type, isByname: Bool) extends Decl with Terms { val body: Located = rhs.fold(identity, identity) } final case class TypeDef( @@ -168,7 +168,7 @@ final case class PolyType(targs: Ls[TypeName \/ TypeVar], body: Type) extends Ty final case class TypingUnit(entities: Ls[Statement]) extends PgrmOrTypingUnit with TypingUnitImpl // final case class TypingUnit(entities: Ls[Statement]) extends TypeLike with PgrmOrTypingUnit with TypingUnitImpl -final case class Signature(members: Ls[NuDecl]) extends TypeLike with SignatureImpl +final case class Signature(members: Ls[NuDecl], result: Opt[Type]) extends TypeLike with SignatureImpl sealed abstract class NuDecl extends TypeLike with Statement with NuDeclImpl @@ -185,7 +185,8 @@ final case class NuFunDef( isLetRec: Opt[Bool], // None means it's a `fun`, which is always recursive; Some means it's a `let` nme: Var, targs: Ls[TypeName], - rhs: Term \/ PolyType, + // rhs: Term \/ PolyType, + rhs: Term \/ Type, ) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) } diff --git a/shared/src/main/scala/mlscript/utils/package.scala b/shared/src/main/scala/mlscript/utils/package.scala index 9af874e91f..266751c2ae 100644 --- a/shared/src/main/scala/mlscript/utils/package.scala +++ b/shared/src/main/scala/mlscript/utils/package.scala @@ -52,8 +52,10 @@ package object utils { implicit class IterableOps[A](private val self: IterableOnce[A]) extends AnyVal { def mkStringOr( sep: String = "", start: String = "", end: String = "", els: String = "" - ): String = - if (self.iterator.nonEmpty) self.iterator.mkString(start, sep, end) else els + ): String = { + val ite = self.iterator + if (ite.nonEmpty) ite.mkString(start, sep, end) else els + } def collectLast[B](f: Paf[A, B]): Opt[B] = self.iterator.collect(f).foldLeft[Opt[B]](N)((_, a) => S(a)) def toSortedSet(implicit ord: Ordering[A]): SortedSet[A] = SortedSet.from(self) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index cdf02dc21c..af9601163d 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -8,11 +8,11 @@ class C { fun id(x) = x fun const(x) = id } -//│ class C -//│ fun id: (α27'' -> α27'') where -//│ [pretty-printed] id: 'a -> 'a -//│ fun const: (α28'' -> (α27'' -> α27'')) where -//│ [pretty-printed] const: 'a -> 'b -> 'b +//│ +//│ class C() { +//│ fun const: 'a -> 'b -> 'b +//│ fun id: 'b -> 'b +//│ } class Base0(n) { @@ -21,97 +21,39 @@ class Base0(n) { fun mine = my fun oops = this.my } -//│ class Base0 -//│ fun me: this31' where -//│ | this31' :> Base0<> <: {my: my39_40'} & {n: n37_38'} -//│ | n37_38' :> n30_66 -//│ | my39_40' :> n37_46 -//│ | n37_46 :> n37_44 <: mine35_47 & my34_48 -//│ | mine35_47 :> n37_44 -//│ | my34_48 :> n37_44 -//│ [pretty-printed] me: 'this -//│ | where -//│ | 'this :> Base0 -//│ | <: {my: 'my} & {n: 'n} -//│ | 'n :> 'n0 -//│ | 'my :> 'n1 -//│ | 'n1 :> 'n2 -//│ | <: 'mine & 'my0 -//│ | 'my0 :> 'n2 -//│ | 'mine :> 'n2 -//│ fun my: n37'' where -//│ | my34'' :> n37_38' -//│ | mine35'' :> n37_38' -//│ | n37'' :> n37_38' <: mine35'' & my34'' -//│ | n37_38' :> n30_66 -//│ [pretty-printed] my: 'n -//│ | where -//│ | 'n :> 'n0 -//│ | <: 'mine & 'my -//│ | 'my :> 'n0 -//│ | 'mine :> 'n0 -//│ | 'n0 :> 'n1 -//│ fun mine: n37'' where -//│ | my34'' :> n37_38' -//│ | mine35'' :> n37_38' -//│ | n37'' :> n37_38' <: mine35'' & my34'' -//│ | n37_38' :> n30_66 -//│ [pretty-printed] mine: 'n -//│ | where -//│ | 'n :> 'n0 -//│ | <: 'mine & 'my -//│ | 'my :> 'n0 -//│ | 'mine :> 'n0 -//│ | 'n0 :> 'n1 -//│ fun oops: my39'' where -//│ | oops36'' :> my39_40' -//│ | my39'' :> my39_40' <: oops36'' -//│ | my39_40' :> n37_46 -//│ | n37_46 :> n37_44 <: mine35_47 & my34_48 -//│ | mine35_47 :> n37_44 -//│ | my34_48 :> n37_44 -//│ [pretty-printed] oops: 'my -//│ | where -//│ | 'my :> 'my0 -//│ | <: 'oops -//│ | 'oops :> 'my0 -//│ | 'my0 :> 'n -//│ | 'n :> 'n0 -//│ | <: 'mine & 'my1 -//│ | 'my1 :> 'n0 -//│ | 'mine :> 'n0 +//│ +//│ class Base0(n: 'n) { +//│ fun me: 'this +//│ fun mine: 'n0 +//│ fun my: 'n0 +//│ fun oops: 'my +//│ } // :d // Base0 // Base0 let b1 = Base0(42) -//│ let b1: α81 where -//│ | α81 :> Base0<> -//│ [pretty-printed] b1: 'a -//│ | where -//│ | 'a :> Base0 +//│ +//│ let b1: 'a // :d let n1 = b1.n -//│ let n1: n84 where -//│ [pretty-printed] n1: 'n +//│ +//│ let n1: 'n // TODO n1 + 1 +//│ +//│ 'a //│ Typed: int let b2 = Base0("hi") let n2 = b2.n -//│ let b2: α116 where -//│ | α116 :> Base0<> <: {n: n118} -//│ [pretty-printed] b2: 'a -//│ | where -//│ | 'a :> Base0 -//│ | <: {n: 'n} -//│ let n2: n118 where -//│ [pretty-printed] n2: 'n +//│ +//│ let b2: 'a +//│ let n2: 'n @@ -120,77 +62,63 @@ class Base1(base: int) { fun getBase2 = this.base fun foo(x) = this.base + x } -//│ class Base1 -//│ fun getBase1: Int where -//│ [pretty-printed] getBase1: int -//│ fun getBase2: base138'' where -//│ | getBase2136'' :> base138_139' -//│ | base138'' :> base138_139' <: getBase2136'' -//│ | base138_139' :> Int -//│ [pretty-printed] getBase2: 'base -//│ | where -//│ | 'base :> 'base0 -//│ | <: 'getBase2 -//│ | 'getBase2 :> 'base0 -//│ | 'base0 :> int -//│ fun foo: (α140'' -> α144'') where -//│ | α140'' <: int -//│ | α144'' :> int -//│ [pretty-printed] foo: 'a -> 'b -//│ | where -//│ | 'b :> int -//│ | 'a <: int +//│ +//│ class Base1(base: int) { +//│ fun foo: 'a -> 'b +//│ fun getBase1: int +//│ fun getBase2: 'base +//│ } class Base1(base: int) { fun getBase1 = base fun me = this fun foo(x) = base + x } -//│ class Base1 -//│ fun getBase1: Int where -//│ [pretty-printed] getBase1: int -//│ fun me: this162' where -//│ | this162' :> Base1<> -//│ [pretty-printed] me: 'this -//│ | where -//│ | 'this :> Base1 -//│ fun foo: (α167'' -> α169'') where -//│ | α167'' <: int -//│ | α169'' :> int -//│ [pretty-printed] foo: 'a -> 'b -//│ | where -//│ | 'b :> int -//│ | 'a <: int +//│ +//│ class Base1(base: int) { +//│ fun foo: 'a -> 'b +//│ fun getBase1: int +//│ fun me: 'this +//│ } Base1 +//│ +//│ (base: int,) -> Base1 //│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ let b: α183 where -//│ | α183 :> Base1<> -//│ [pretty-printed] b: 'a -//│ | where -//│ | 'a :> Base1 +//│ +//│ let b: 'a b.base +//│ +//│ 'base //│ Typed: int b.getBase1 +//│ +//│ 'getBase1 //│ Typed: int // :d b.me +//│ +//│ 'me //│ Typed: Base1 :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.186: b.getBaseTypo +//│ ║ l.110: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ +//│ +//│ 'getBaseTypo //│ Typed: error b : Base1 +//│ +//│ Base1 //│ Typed: Base1 @@ -199,21 +127,16 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.198: class Rec(n) { +//│ ║ l.126: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.199: fun go = Rec(n + 1) +//│ ║ l.127: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.200: } +//│ ║ l.128: } //│ ╙── ^ -//│ class Rec -//│ fun go: α223'' where -//│ | go220'' :> error<> -//│ | α223'' :> error<> <: go220'' -//│ [pretty-printed] go: 'a -//│ | where -//│ | 'a :> error -//│ | <: 'go -//│ | 'go :> error +//│ +//│ class Rec(n: 'n) { +//│ fun go: 'a +//│ } @@ -224,20 +147,21 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.223: a: int +//│ ║ l.146: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.222: class Annots(base: 0 | 1) { +//│ ║ l.145: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.223: a: int +//│ ║ l.146: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.223: a: int +//│ ║ l.146: a: int //│ ╙── ^^^ -//│ class Annots -//│ fun a: ((0 | 1),) where -//│ [pretty-printed] a: (0 | 1,) +//│ +//│ class Annots(base: (0 | 1,)) { +//│ fun a: (0 | 1,) +//│ } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 1bc89d9187..9ba9ee814e 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -7,87 +7,93 @@ mixin BaseTest { fun test = super.base } -//│ mixin BaseTest -//│ this: this23' -//│ super: super24' -//│ | super24' <: {base: base26_27'} -//│ fun test: base26'' where -//│ | test25'' :> base26_27' -//│ | base26'' :> base26_27' <: test25'' -//│ [pretty-printed] test: 'base -//│ | where -//│ | 'base :> 'base0 -//│ | <: 'test -//│ | 'test :> 'base0 +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() { +//│ fun test = ... +//│ },this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) mixin BaseInc { fun test = super.base + 1 fun test2 = this.base } -//│ mixin BaseInc -//│ this: this29' -//│ | this29' <: {base: base37_38'} -//│ super: super30' -//│ | super30' <: {base: base33_34'} -//│ | base33_34' <: int -//│ fun test: α36'' where -//│ | test31'' :> int -//│ | α36'' :> int <: test31'' -//│ [pretty-printed] test: 'a -//│ | where -//│ | 'a :> int -//│ | <: 'test -//│ | 'test :> int -//│ fun test2: base37'' where -//│ | test232'' :> base37_38' -//│ | base37'' :> base37_38' <: test232'' -//│ [pretty-printed] test2: 'base -//│ | where -//│ | 'base :> 'base0 -//│ | <: 'test2 -//│ | 'test2 :> 'base0 +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() { +//│ fun test = ... +//│ fun test2 = ... +//│ },this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,α36''), test2 ~> TypedNuFun(1,fun test2 = ...,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) // :d class Base1(base: int): BaseTest, BaseInc { fun test3 = [base, this.base] } -//│ class Base1 -//│ fun test3: (Int, base59'',) where -//│ | base59'' :> base59_60' -//│ | base59_60' :> Int -//│ [pretty-printed] test3: (int, 'base,) -//│ | where -//│ | 'base :> 'base0 -//│ | 'base0 :> int +//│ +//│ class Base1(base: int) { +//│ let this: 'this +//│ fun test: 'a +//│ fun test2: 'base +//│ fun test3: (int, 'base0,) +//│ } Base1(1).test +//│ +//│ 'test //│ Typed: int Base1(1).test2 +//│ +//│ 'test2 //│ Typed: int Base1(1).test3 +//│ +//│ 'test3 //│ Typed: (int, int,) class Base1(base): BaseTest -//│ class Base1 +//│ +//│ class Base1(base: 'base) { +//│ let this: 'this +//│ fun test: 'base0 +//│ } Base1 +//│ +//│ forall 'base 'base0. (base: 'base,) -> Base1 //│ Typed: (base: anything,) -> Base1 // TODO Base1(1).test +//│ +//│ 'test //│ Typed: nothing :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.85: class Base1(x): BaseTest +//│ ║ l.91: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.85: class Base1(x): BaseTest +//│ ║ l.91: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -95,9 +101,15 @@ class Base1(x): BaseTest //│ ╟── from reference: //│ ║ l.8: fun test = super.base //│ ╙── ^^^^^ -//│ class Base1 +//│ +//│ class Base1(x: 'x) { +//│ let this: 'this +//│ fun test: 'base +//│ } Base1 +//│ +//│ forall 'x. (x: 'x,) -> Base1 //│ Typed: (x: anything,) -> Base1 @@ -105,25 +117,30 @@ Base1 mixin Foo { fun test(x) = [super.base + x, x, super.misc] } -//│ mixin Foo -//│ this: this176' -//│ super: super177' -//│ | super177' <: {misc: misc184_185'} & {base: base180_181'} -//│ | base180_181' <: int -//│ fun test: (α179'' -> (α183'', α179'', misc184'',)) where -//│ | α179'' <: int -//│ | α183'' :> int -//│ | misc184'' :> misc184_185' -//│ [pretty-printed] test: 'a -> ('b, 'a, 'misc,) -//│ | where -//│ | 'misc :> 'misc0 -//│ | 'b :> int -//│ | 'a <: int +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() { +//│ fun test = ... +//│ },this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) module Base1(base: int, misc: string): Foo -//│ class Base1 +//│ +//│ namespace Base1(base: int, misc: string) { +//│ let this: 'this +//│ fun test: 'a -> ('b, 'a, 'misc,) +//│ } Base1.test +//│ +//│ 'test //│ Typed: (int & 'a) -> (int, 'a, string,) @@ -133,55 +150,67 @@ mixin WrapBase { fun wrapA(x: int) = x : int fun wrap(x) = x } -//│ mixin WrapBase -//│ this: this210' -//│ super: super211' -//│ fun wrapA: ((x: Int,) -> Int) where -//│ [pretty-printed] wrapA: (x: int,) -> int -//│ fun wrap: (α214'' -> α214'') where -//│ [pretty-printed] wrap: 'a -> 'a +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() { +//│ fun wrapA = ... +//│ fun wrap = ... +//│ },this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = ...,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = ...,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) // :d mixin Wrap { fun wrapA(x) = [super.wrapA(x)] fun wrap(x) = [super.wrap(x)] } -//│ mixin Wrap -//│ this: this216' -//│ super: super217' -//│ | super217' <: {wrap: wrap227_228'} & {wrapA: wrapA221_222'} -//│ | wrapA221_222' <: ((α220_224',) -> α223_225') -//│ | wrap227_228' <: ((α226_230',) -> α229_231') -//│ fun wrapA: (α220'' -> (α223'',)) where -//│ | α220'' <: α220_224' -//│ | α223'' :> α223_225' -//│ [pretty-printed] wrapA: 'a -> ('b,) -//│ | where -//│ | 'b :> 'c -//│ | 'a <: 'd -//│ fun wrap: (α226'' -> (α229'',)) where -//│ | α226'' <: α226_230' -//│ | α229'' :> α229_231' -//│ [pretty-printed] wrap: 'a -> ('b,) -//│ | where -//│ | 'b :> 'c -//│ | 'a <: 'd +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() { +//│ fun wrapA = ... +//│ fun wrap = ... +//│ },this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = ...,(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = ...,(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) // :d module WrapBase1: WrapBase, Wrap -//│ class WrapBase1 +//│ +//│ namespace WrapBase1() { +//│ let this: 'this +//│ fun wrap: 'a -> ('b,) +//│ fun wrapA: 'c -> ('d,) +//│ } WrapBase1 +//│ +//│ WrapBase1 //│ Typed: WrapBase1 // :d WrapBase1.wrapA +//│ +//│ 'wrapA //│ Typed: int -> (int,) WrapBase1.wrap +//│ +//│ 'wrap //│ Typed: 'a -> ('a,) // :d @@ -189,87 +218,60 @@ WrapBase1.wrap WrapBase1.wrap(1) +//│ +//│ 'a //│ Typed: (1,) WrapBase1.wrap("ok") +//│ +//│ 'a //│ Typed: ("ok",) WrapBase1.wrapA(1) +//│ +//│ 'a //│ Typed: (int,) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.202: WrapBase1.wrapA("ok") +//│ ║ l.237: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.202: WrapBase1.wrapA("ok") +//│ ║ l.237: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.133: fun wrapA(x: int) = x : int +//│ ║ l.150: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.146: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.170: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ +//│ +//│ 'a //│ Typed: (int,) | error module WrapBase2: WrapBase, Wrap, Wrap, Wrap -//│ class WrapBase2 +//│ +//│ namespace WrapBase2() { +//│ let this: 'this +//│ fun wrap: 'a -> ('b,) +//│ fun wrapA: 'c -> ('d,) +//│ } let w = WrapBase2.wrap -//│ let w: wrap394 where -//│ | wrap394 :> (α226_407 -> (α229_415,)) -//│ | α226_407 <: α226_408 -//│ | α226_408 <: α226_409 -//│ | α226_409 <: α226_410 -//│ | α226_410 <: α226_411 -//│ | α226_411 <: α226_412 -//│ | α226_412 <: α214_413 -//│ | α214_413 <: α229_414 -//│ | α229_415 :> α229_416 -//│ | α229_416 :> (α229_417,) -//│ | α229_417 :> α229_418 -//│ | α229_418 :> (α229_419,) -//│ | α229_419 :> α229_414 -//│ [pretty-printed] w: 'wrap -//│ | where -//│ | 'wrap :> 'a -> ('b,) -//│ | 'b :> 'c -//│ | 'c :> ('d,) -//│ | 'd :> 'e -//│ | 'e :> ('f,) -//│ | 'f :> 'g -//│ | 'a <: 'h -//│ | 'h <: 'i -//│ | 'i <: 'j -//│ | 'j <: 'k -//│ | 'k <: 'l -//│ | 'l <: 'm -//│ | 'm <: 'g +//│ +//│ let w: 'wrap let wd = w(1) -//│ let wd: α421 where -//│ | α229_414 :> 1 -//│ | α229_415 :> α229_416 -//│ | α229_416 :> (α229_417,) -//│ | α229_417 :> α229_418 -//│ | α229_418 :> (α229_419,) -//│ | α229_419 :> α229_414 -//│ | α421 :> (α229_415,) -//│ [pretty-printed] wd: 'a -//│ | where -//│ | 'a :> ('b,) -//│ | 'b :> 'c -//│ | 'c :> ('d,) -//│ | 'd :> 'e -//│ | 'e :> ('f,) -//│ | 'f :> 'g -//│ | 'g :> 1 +//│ +//│ let wd: 'a wd._1._1._1 + 1 +//│ +//│ 'a //│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index b9ed3fcbf0..9f1331e569 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -5,17 +5,17 @@ class Add(lhs: E, rhs: E) class Lit(n: int) -//│ class Add -//│ class Lit +//│ +//│ class Add[E](lhs: E, rhs: E) { +//│ let this: 'this +//│ } +//│ class Lit(n: int) { +//│ let this: 'this0 +//│ } let add11 = Add(Lit(1), Lit(2)) -//│ let add11: α33 where -//│ | α33 :> (Add<> & {Add#E: mut E24_34..E24_34}) -//│ | E24_34 :> Lit<> -//│ [pretty-printed] add11: 'a -//│ | where -//│ | 'a :> Add & {Add#E = 'E} -//│ | 'E :> Lit +//│ +//│ let add11: 'a mixin EvalBase { @@ -24,83 +24,50 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ mixin EvalBase -//│ this: this36' -//│ | this36' <: {eval: eval56_57'} & {eval: eval49_50'} -//│ | eval49_50' <: ((‹∀ 2. lhs45_52'''›,) -> α51_54') -//│ | lhs45_52''' :> lhs45_53' -//│ | α51_54' <: int -//│ | eval56_57' <: ((‹∀ 2. rhs47_59'''›,) -> α58_61') -//│ | rhs47_59''' :> rhs47_60' -//│ | α58_61' <: int -//│ super: super37' -//│ fun eval: (α39'' -> (Int | α62'')) where -//│ | α39'' <: ((Lit<> & α40'') | ((Add<> & α44'') & ~(Lit<>))) -//│ | α40'' <: {n: n41_42''} -//│ | n41_42'' <: int -//│ | α44'' <: {rhs: rhs47_48''} & {lhs: lhs45_46''} -//│ | lhs45_46'' <: lhs45_53' -//│ | rhs47_48'' <: rhs47_60' -//│ | α62'' :> int -//│ [pretty-printed] eval: 'a -> (int | 'b) -//│ | where -//│ | 'b :> int -//│ | 'a <: Lit & 'c | Add & 'd & ~Lit -//│ | 'd <: {rhs: 'rhs} & {lhs: 'lhs} -//│ | 'lhs <: 'lhs0 -//│ | 'rhs <: 'rhs0 -//│ | 'c <: {n: 'n} -//│ | 'n <: int +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() { +//│ fun eval = ... +//│ },this39',super40',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = ...,(α42'' -> (Int | α65'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) module TestLang: EvalBase -//│ class TestLang +//│ +//│ namespace TestLang() { +//│ let this: 'this +//│ fun eval: 'a -> (int | 'b) +//│ } TestLang.eval +//│ +//│ 'eval //│ Typed: 'rhs -> int //│ where //│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} TestLang.eval(add11) +//│ +//│ 'a //│ Typed: int class Neg(expr: A) -//│ class Neg +//│ +//│ class Neg[A](expr: A) { +//│ let this: 'this +//│ } let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: α137 where -//│ | E24_34 :> Lit<> <: lhs45_119 & rhs47_117 -//│ | lhs45_113 :> Lit<> <: ((Lit<> & α40_114) | ((Add<> & α44_116) & ~(Lit<>))) -//│ | α40_114 :> Lit<> <: {n: n41_115} -//│ | n41_115 :> Int <: int -//│ | α44_116 :> (Add<> & {Add#E: mut E24_34..E24_34}) <: {rhs: rhs47_117} & {lhs: lhs45_119} -//│ | rhs47_117 :> Lit<> <: rhs47_118 -//│ | rhs47_118 :> Lit<> <: ((Lit<> & α40_114) | ((Add<> & α44_116) & ~(Lit<>))) -//│ | lhs45_119 :> Lit<> <: lhs45_113 -//│ | A128_136 :> (Add<> & {Add#E: mut E24_34..E24_34}) -//│ | α137 :> (Add<> & {Add#E: mut E24_138..E24_138}) -//│ | E24_138 :> (Neg<> & {Neg#A: mut A128_136..A128_136}) | Lit<> -//│ [pretty-printed] add2negadd11: 'a -//│ | where -//│ | 'a :> Add & {Add#E = 'E} -//│ | 'E :> Neg & {Neg#A = 'A} | Lit -//│ | 'A :> Add & {Add#E = 'E0} -//│ | 'E0 :> Lit -//│ | <: 'lhs & 'rhs -//│ | 'lhs :> Lit -//│ | <: 'lhs0 -//│ | 'lhs0 :> Lit -//│ | <: Lit & 'b | Add & 'c & ~Lit -//│ | 'c :> Add & {Add#E = 'E0} -//│ | <: {rhs: 'rhs} & {lhs: 'lhs} -//│ | 'rhs :> Lit -//│ | <: 'rhs0 -//│ | 'rhs0 :> Lit -//│ | <: Lit & 'b | Add & 'c & ~Lit -//│ | 'b :> Lit -//│ | <: {n: 'n} -//│ | 'n := int +//│ +//│ let add2negadd11: 'a mixin EvalNeg { @@ -108,58 +75,65 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ mixin EvalNeg -//│ this: this140' -//│ | this140' <: {eval: eval148_149'} -//│ | eval148_149' <: ((‹∀ 2. expr145_151'''›,) -> α150_153') -//│ | expr145_151''' :> expr145_152' -//│ | α150_153' <: int -//│ super: super141' -//│ | super141' <: {eval: eval156_157'} -//│ | eval156_157' <: ((α155_159',) -> α158_160') -//│ fun eval: (α143'' -> (α154'' | α158'')) where -//│ | α143'' <: ((Neg<> & α144'') | (α155'' & ~(Neg<>))) -//│ | α144'' <: {expr: expr145_146''} -//│ | expr145_146'' <: expr145_152' -//│ | α154'' :> int -//│ | α155'' <: α155_159' -//│ | α158'' :> α158_160' -//│ [pretty-printed] eval: 'a -> ('b | 'c) -//│ | where -//│ | 'c :> 'd -//│ | 'b :> int -//│ | 'a <: Neg & 'e | 'f & ~Neg -//│ | 'f <: 'g -//│ | 'e <: {expr: 'expr} -//│ | 'expr <: 'expr0 +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() { +//│ fun eval = ... +//│ },this151',super152',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = ...,(α154'' -> (α165'' | α169'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) module TestLang: EvalBase, EvalNeg -//│ class TestLang +//│ +//│ namespace TestLang() { +//│ let this: 'this +//│ fun eval: 'a -> ('b | 'c) +//│ } TestLang.eval +//│ +//│ 'eval //│ Typed: 'rhs -> int //│ where //│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} | Neg & {expr: 'rhs} TestLang.eval(add11) +//│ +//│ 'a //│ Typed: int TestLang.eval(Neg(add11)) +//│ +//│ 'a //│ Typed: int TestLang.eval(Add(Lit(2), Neg(Lit(1)))) +//│ +//│ 'a //│ Typed: int TestLang.eval(Neg(Neg(add11))) +//│ +//│ 'a //│ Typed: int TestLang.eval(add2negadd11) +//│ +//│ 'a //│ Typed: int TestLang.eval(Add(Lit(2), Neg(add11))) +//│ +//│ 'a //│ Typed: int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 315d67b55b..4aac19f16f 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -9,30 +9,31 @@ class Some(value: A) { // fun mapBad(f) = Some(f(value)) // TODO // fun map(f : A => 'b) = Some(f(value)) // TODO } -//│ class Some -//│ fun get: ‘A23' where -//│ [pretty-printed] get: A -//│ fun toArray: (‘A23',) where -//│ [pretty-printed] toArray: (A,) +//│ +//│ class Some[A](value: A) { +//│ fun get: A +//│ fun toArray: (A,) +//│ } let s = Some(1) -//│ let s: α32 where -//│ | α32 :> (Some<> & {Some#A: mut A23_33..A23_33}) -//│ | A23_33 :> 1 -//│ [pretty-printed] s: 'a -//│ | where -//│ | 'a :> Some & {Some#A = 'A} -//│ | 'A :> 1 +//│ +//│ let s: 'a s.value +//│ +//│ 'value //│ Typed: 1 s.get +//│ +//│ 'get //│ Typed: 1 s.toArray +//│ +//│ 'toArray //│ Typed: (1,) @@ -54,14 +55,16 @@ module None { fun toArray = [] // fun mapBad(f) = None // TODO } -//│ class None -//│ fun get: ⊥ where -//│ [pretty-printed] get: nothing -//│ fun toArray: () where -//│ [pretty-printed] toArray: () +//│ +//│ namespace None() { +//│ fun get: nothing +//│ fun toArray: () +//│ } None.toArray +//│ +//│ 'toArray //│ Typed: () @@ -72,15 +75,12 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ let opt: (α68 | None<>) where -//│ | α68 :> (Some<> & {Some#A: mut A23_69..A23_69}) -//│ | A23_69 :> 123 -//│ [pretty-printed] opt: 'a | None -//│ | where -//│ | 'a :> Some & {Some#A = 'A} -//│ | 'A :> 123 +//│ +//│ let opt: 'a | None opt.toArray +//│ +//│ 'toArray //│ Typed: Array[123] @@ -93,43 +93,29 @@ opt.toArray if opt is Some then opt.value else 0 +//│ +//│ 'value | 0 //│ Typed: 0 | 123 if opt is Some(v) then v else 0 +//│ +//│ (forall 'value. 'value) | 0 //│ Typed: 0 | 123 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: ((α98', α99',) -> (None<> | α108')) where -//│ | α98' <: ((None<> & α100') | ((Some<> & α101') & ~(None<>))) -//│ | α99' <: ((‹∀ 1. value102''›,) -> α107') -//│ | α101' <: {value: value102_103'} -//│ | value102'' :> value102_103' -//│ | α107' <: A23_109' -//│ | α108' :> (Some<> & {Some#A: mut A23_109'..A23_109'}) -//│ [pretty-printed] map: ('a, 'b,) -> (None | 'c) -//│ | where -//│ | 'c :> Some & {Some#A = 'A} -//│ | 'b <: (forall 'value. 'value) -> 'd -//│ | 'd <: 'A -//│ | 'value :> 'value0 -//│ | 'a <: None & 'e | Some & 'f & ~None -//│ | 'f <: {value: 'value0} +//│ +//│ fun map: ('a, 'b,) -> (None | 'c) let mo = map(opt, succ) -//│ let mo: α111 where -//│ | α111 :> (None<> | α108_119) -//│ | α108_119 :> (Some<> & {Some#A: mut A23_120..A23_121}) -//│ | A23_121 :> A23_120 | int -//│ [pretty-printed] mo: 'a -//│ | where -//│ | 'a :> None | 'b -//│ | 'b :> Some & {Some#A :> 'A <: 'A0} -//│ | 'A0 :> 'A | int +//│ +//│ let mo: 'a mo.toArray +//│ +//│ 'toArray //│ Typed: Array[int] @@ -137,33 +123,32 @@ mo.toArray class Test(n) { fun foo = n + 1 } -//│ class Test -//│ fun foo: α138'' where -//│ | foo136'' :> int -//│ | α138'' :> int <: foo136'' -//│ [pretty-printed] foo: 'a -//│ | where -//│ | 'a :> int -//│ | <: 'foo -//│ | 'foo :> int +//│ +//│ class Test(n: 'n) { +//│ fun foo: 'a +//│ } Test(1) +//│ +//│ 'a //│ Typed: Test :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.154: Test(true) +//│ ║ l.137: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.154: Test(true) +//│ ║ l.137: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.138: fun foo = n + 1 +//│ ║ l.124: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.137: class Test(n) { +//│ ║ l.123: class Test(n) { //│ ╙── ^ +//│ +//│ 'a //│ Typed: Test | error @@ -172,30 +157,29 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.172: fun foo = n + 1 +//│ ║ l.157: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.172: fun foo = n + 1 +//│ ║ l.157: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.171: class Test(n: A) { +//│ ║ l.156: class Test(n: A) { //│ ╙── ^ -//│ class Test -//│ fun foo: α159'' where -//│ | foo157'' :> int | error<> -//│ | α159'' :> error<> | int <: foo157'' -//│ [pretty-printed] foo: 'a -//│ | where -//│ | 'a :> error | int -//│ | <: 'foo -//│ | 'foo :> int | error +//│ +//│ class Test[A](n: A) { +//│ fun foo: 'a +//│ } Test(1) +//│ +//│ 'a //│ Typed: Test & {Test#A = 'A} //│ where //│ 'A :> 1 Test(true) +//│ +//│ 'a //│ Typed: Test & {Test#A = 'A} //│ where //│ 'A :> true @@ -206,46 +190,54 @@ class Test(n: A) { fun foo1(x: A) = x fun id(x) = x } -//│ class Test -//│ fun foo: ‘A181' where -//│ [pretty-printed] foo: A -//│ fun foo1: ((x: ‘A181',) -> ‘A181') where -//│ [pretty-printed] foo1: (x: A,) -> A -//│ fun id: (α187'' -> α187'') where -//│ [pretty-printed] id: 'a -> 'a +//│ +//│ class Test[A](n: A) { +//│ fun foo: A +//│ fun foo1: (x: A,) -> A +//│ fun id: 'a -> 'a +//│ } Test(1) +//│ +//│ 'a //│ Typed: Test & {Test#A = 'A} //│ where //│ 'A :> 1 Test(1).foo +//│ +//│ 'foo //│ Typed: 1 Test("ok").foo +//│ +//│ 'foo //│ Typed: "ok" let t = Test(1) -//│ let t: α233 where -//│ | α233 :> (Test<> & {Test#A: mut A181_234..A181_234}) -//│ | A181_234 :> 1 -//│ [pretty-printed] t: 'a -//│ | where -//│ | 'a :> Test & {Test#A = 'A} -//│ | 'A :> 1 +//│ +//│ let t: 'a t.foo1(true) +//│ +//│ 'a //│ Typed: 1 | true t : Test<'a> +//│ +//│ Test['a] //│ Typed: Test['a] //│ where //│ 'a :> 1 | true t.id +//│ +//│ 'id //│ Typed: 'a -> 'a [t.id(1), t.id(true)] +//│ +//│ ('a, 'b,) //│ Typed: (1, true,) @@ -255,70 +247,79 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.255: fun foo2(x: A) = x + 1 +//│ ║ l.247: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.255: fun foo2(x: A) = x + 1 +//│ ║ l.247: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.253: class Test { +//│ ║ l.245: class Test { //│ ╙── ^ -//│ class Test -//│ fun foo1: ((x: ‘A281',) -> ‘A281') where -//│ [pretty-printed] foo1: (x: A,) -> A -//│ fun foo2: ((x: ‘A281',) -> α287'') where -//│ | α287'' :> error<> | int -//│ [pretty-printed] foo2: (x: A,) -> 'a -//│ | where -//│ | 'a :> error | int +//│ +//│ class Test[A]() { +//│ fun foo1: (x: A,) -> A +//│ fun foo2: (x: A,) -> 'a +//│ } Test().foo1 +//│ +//│ 'foo1 //│ Typed: (x: 'A,) -> 'A Test().foo1(1) +//│ +//│ 'a //│ Typed: 1 x => Test().foo1(x) +//│ +//│ 'a -> 'b //│ Typed: 'a -> 'a // :d let t = Test() -//│ let t: α340 where -//│ | α340 :> ‹∀ 0. (Test<> & {Test#A: mut A281_337'..A281_337'})› -//│ [pretty-printed] t: 'a -//│ | where -//│ | 'a :> forall 'A. Test & {Test#A = 'A} +//│ +//│ let t: 'a t.foo1 +//│ +//│ 'foo1 //│ Typed: (x: 'A,) -> 'A [t.foo1(0), t.foo1(true)] +//│ +//│ ('a, 'b,) //│ Typed: (0, true,) t.foo1(0) +//│ +//│ 'a //│ Typed: 0 t +//│ +//│ 'a //│ Typed: Test & {Test#A = 'A} fun foo(x: Test) = x.foo1 -//│ fun foo: ((x: Test[Int],) -> foo1381') where -//│ | foo1381' :> ((x: A382#,) -> A382#) -//│ | A382# := int..int -//│ [pretty-printed] foo: (x: Test[int],) -> 'foo1 -//│ | where -//│ | 'foo1 :> (x: 'A,) -> 'A -//│ | 'A := int +//│ +//│ fun foo: (x: Test[int],) -> 'foo1 foo(t) +//│ +//│ 'a //│ Typed: (x: int,) -> int foo(t)(1) +//│ +//│ 'a //│ Typed: int Test().foo2 +//│ +//│ 'foo2 //│ Typed: (x: anything,) -> (error | int) diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index 1bb24ae4d6..c8c1451fe3 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -71,7 +71,7 @@ f :p let rec f = 1 //│ |#let| |#rec| |f| |#=| |1| -//│ Parsed: let rec f[List()] = ...; +//│ Parsed: let rec f = ...; //│ Desugared: rec def f: 1 //│ AST: Def(true, f, IntLit(1), false) //│ f: 1 diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index ca1de79d51..73177aaf46 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -6,81 +6,75 @@ class Foo() 123 -//│ class Foo +//│ +//│ class Foo() { +//│ let this: 'this +//│ } +//│ 123 //│ Typed: 123 Foo +//│ +//│ () -> Foo //│ Typed: () -> Foo fun fooo(x) = class C(y, z) C(0, x) -//│ fun fooo: (α26' -> α34') where -//│ | α26' <: z29_36' -//│ | α34' :> C<> -//│ [pretty-printed] fooo: 'a -> 'b -//│ | where -//│ | 'b :> C -//│ | 'a <: 'z +//│ +//│ fun fooo: 'a -> 'b fun foo = bar fun bar = foo -//│ fun foo: foo37' where -//│ | foo37' <: bar38' -//│ [pretty-printed] foo: 'foo -//│ | where -//│ | 'foo <: 'bar -//│ fun bar: foo37' where -//│ | foo37' <: bar38' -//│ [pretty-printed] bar: 'foo -//│ | where -//│ | 'foo <: 'bar +//│ +//│ fun foo: 'foo +//│ fun bar: 'foo foo(bar) +//│ +//│ 'a //│ Typed: nothing fun foo = {x: foo} -//│ fun foo: {x: foo41'} where -//│ | foo41' :> {x: foo41'} -//│ [pretty-printed] foo: {x: 'foo} -//│ | where -//│ | 'foo :> {x: 'foo} +//│ +//│ fun foo: {x: 'foo} fun foo = {x: bar} fun bar = {y: foo} -//│ fun foo: {x: {y: foo42'}} where -//│ | foo42' :> {x: {y: foo42'}} -//│ [pretty-printed] foo: {x: {y: 'foo}} -//│ | where -//│ | 'foo :> {x: {y: 'foo}} -//│ fun bar: {y: foo42'} where -//│ | foo42' :> {x: {y: foo42'}} -//│ [pretty-printed] bar: {y: 'foo} -//│ | where -//│ | 'foo :> {x: {y: 'foo}} +//│ +//│ fun foo: {x: {y: 'foo}} +//│ fun bar: {y: 'foo} // FIXME pretty-printing? foo +//│ +//│ {x: {y: 'foo}} //│ Typed: 'foo //│ where //│ 'foo :> {x: {y: 'foo}} :ns foo +//│ +//│ {x: {y: 'foo}} //│ Typed: forall 'foo. {x: {y: 'foo}} //│ where //│ 'foo :> {x: {y: 'foo}} foo.x +//│ +//│ 'x //│ Typed: 'x //│ where //│ 'x :> {y: {x: 'x}} foo.x.y +//│ +//│ 'y //│ Typed: 'foo //│ where //│ 'foo :> {x: {y: 'foo}} @@ -88,61 +82,26 @@ foo.x.y fun foo(a) = {h: a, t: bar(a)} fun bar(b) = foo(b) -//│ fun foo: (α62' -> {h: α62', t: α65'}) where -//│ | α62' <: α63' -//│ | α63' <: α62' -//│ | α65' :> {h: α62', t: α65'} -//│ [pretty-printed] foo: 'a -> {h: 'a, t: 'b} -//│ | where -//│ | 'b :> {h: 'a, t: 'b} -//│ | 'a <: 'c -//│ | 'c <: 'a -//│ fun bar: (α63' -> α64') where -//│ | α62' <: α63' -//│ | α63' <: α62' -//│ | α64' :> {h: α62', t: α65'} <: α65' -//│ | α65' :> {h: α62', t: α65'} -//│ [pretty-printed] bar: 'a -> 'b -//│ | where -//│ | 'b :> {h: 'c, t: 'd} -//│ | <: 'd -//│ | 'd :> {h: 'c, t: 'd} -//│ | 'a <: 'c -//│ | 'c <: 'a +//│ +//│ fun foo: 'a -> {h: 'a, t: 'b} +//│ fun bar: 'c -> 'd :ns foo -//│ Typed: forall 'a 'b 'c. 'b -> {h: 'b, t: 'a} +//│ +//│ 'a -> {h: 'a, t: 'b} +//│ Typed: forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} //│ where -//│ 'a :> {h: 'b, t: 'a} -//│ 'b <: 'c -//│ 'c <: 'b +//│ 'c :> {h: 'a, t: 'c} +//│ 'a <: 'b +//│ 'b <: 'a fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} -//│ fun foo: (α68' -> {h1: α68', t1: α71'}) where -//│ | α68' <: α69' -//│ | α69' <: α68' -//│ | α70' :> {h1: α68', t1: α71'} -//│ | α71' :> {h2: α69', t2: α70'} -//│ [pretty-printed] foo: 'a -> {h1: 'a, t1: 'b} -//│ | where -//│ | 'b :> {h2: 'c, t2: 'd} -//│ | 'd :> {h1: 'a, t1: 'b} -//│ | 'a <: 'c -//│ | 'c <: 'a -//│ fun bar: (α69' -> {h2: α69', t2: α70'}) where -//│ | α68' <: α69' -//│ | α69' <: α68' -//│ | α70' :> {h1: α68', t1: α71'} -//│ | α71' :> {h2: α69', t2: α70'} -//│ [pretty-printed] bar: 'a -> {h2: 'a, t2: 'b} -//│ | where -//│ | 'b :> {h1: 'c, t1: 'd} -//│ | 'd :> {h2: 'a, t2: 'b} -//│ | 'a <: 'c -//│ | 'c <: 'a +//│ +//│ fun foo: 'a -> {h1: 'a, t1: 'b} +//│ fun bar: 'c -> {h2: 'c, t2: 'd} @@ -152,20 +111,19 @@ module Test0_1 { module Test0_2 { fun b = 123 } -//│ class Test0_1 -//│ fun a: b80'' where -//│ | a76'' :> 123 -//│ | b80'' :> 123 <: a76'' -//│ [pretty-printed] a: 'b -//│ | where -//│ | 'b :> 123 -//│ | <: 'a -//│ | 'a :> 123 -//│ class Test0_2 -//│ fun b: 123 where -//│ [pretty-printed] b: 123 +//│ +//│ namespace Test0_1() { +//│ let this: 'this +//│ fun a: 'b +//│ } +//│ namespace Test0_2() { +//│ let this: 'this0 +//│ fun b: 123 +//│ } Test0_1.a +//│ +//│ 'a //│ Typed: 123 class Test0_1 { @@ -174,18 +132,15 @@ class Test0_1 { class Test0_2() { fun b = 123 } -//│ class Test0_1 -//│ fun a: b97'' where -//│ | a91'' :> 123 -//│ | b97'' :> 123 <: a91'' -//│ [pretty-printed] a: 'b -//│ | where -//│ | 'b :> 123 -//│ | <: 'a -//│ | 'a :> 123 -//│ class Test0_2 -//│ fun b: 123 where -//│ [pretty-printed] b: 123 +//│ +//│ class Test0_1() { +//│ let this: 'this +//│ fun a: 'b +//│ } +//│ class Test0_2() { +//│ let this: 'this0 +//│ fun b: 123 +//│ } :e // TODO @@ -196,32 +151,25 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.192: module Test1_1 { +//│ ║ l.147: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.193: fun a = Test1_2.b +//│ ║ l.148: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.194: } +//│ ║ l.149: } //│ ╙── ^ -//│ class Test1_1 -//│ fun a: b108'' where -//│ | a103'' :> error<> -//│ | b108'' :> error<> <: a103'' -//│ [pretty-printed] a: 'b -//│ | where -//│ | 'b :> error -//│ | <: 'a -//│ | 'a :> error -//│ class Test1_2 -//│ fun b: a107'' where -//│ | b106'' :> error<> -//│ | a107'' :> error<> <: b106'' -//│ [pretty-printed] b: 'a -//│ | where -//│ | 'a :> error -//│ | <: 'b -//│ | 'b :> error +//│ +//│ namespace Test1_1() { +//│ let this: 'this +//│ fun a: 'b +//│ } +//│ namespace Test1_2() { +//│ let this: 'this0 +//│ fun b: 'a +//│ } Test1_1.a +//│ +//│ 'a //│ Typed: error @@ -233,30 +181,21 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.229: class Test1_1 { +//│ ║ l.177: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.230: fun a = Test1_2().b +//│ ║ l.178: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.231: } +//│ ║ l.179: } //│ ╙── ^ -//│ class Test1_1 -//│ fun a: b131'' where -//│ | a121'' :> error<> -//│ | b131'' :> error<> <: a121'' -//│ [pretty-printed] a: 'b -//│ | where -//│ | 'b :> error -//│ | <: 'a -//│ | 'a :> error -//│ class Test1_2 -//│ fun b: a126'' where -//│ | b124'' :> error<> -//│ | a126'' :> error<> <: b124'' -//│ [pretty-printed] b: 'a -//│ | where -//│ | 'a :> error -//│ | <: 'b -//│ | 'b :> error +//│ +//│ class Test1_1() { +//│ let this: 'this +//│ fun a: 'b +//│ } +//│ class Test1_2() { +//│ let this: 'this0 +//│ fun b: 'a +//│ } // TODO check TV hygiene @@ -272,82 +211,64 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.263: module Test2_1 { +//│ ║ l.202: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.264: fun t2 = Test2_2 +//│ ║ l.203: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.265: fun a = Test2_2.b +//│ ║ l.204: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.266: fun d = Test2_2.e +//│ ║ l.205: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.267: fun n = 456 +//│ ║ l.206: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.268: } +//│ ║ l.207: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.263: module Test2_1 { +//│ ║ l.202: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.264: fun t2 = Test2_2 +//│ ║ l.203: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.265: fun a = Test2_2.b +//│ ║ l.204: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.266: fun d = Test2_2.e +//│ ║ l.205: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.267: fun n = 456 +//│ ║ l.206: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.268: } +//│ ║ l.207: } //│ ╙── ^ -//│ class Test2_1 -//│ fun t2: Test2_2<> where -//│ [pretty-printed] t2: Test2_2 -//│ fun a: b150'' where -//│ | a140'' :> 123 -//│ | b150'' :> 123 <: a140'' -//│ [pretty-printed] a: 'b -//│ | where -//│ | 'b :> 123 -//│ | <: 'a -//│ | 'a :> 123 -//│ fun d: e158'' where -//│ | d141'' :> error<> -//│ | e158'' :> error<> <: d141'' -//│ [pretty-printed] d: 'e -//│ | where -//│ | 'e :> error -//│ | <: 'd -//│ | 'd :> error -//│ fun n: 456 where -//│ [pretty-printed] n: 456 -//│ class Test2_2 -//│ fun b: 123 where -//│ [pretty-printed] b: 123 -//│ fun c: a148'' where -//│ | c146'' :> error<> -//│ | a148'' :> error<> <: c146'' -//│ [pretty-printed] c: 'a -//│ | where -//│ | 'a :> error -//│ | <: 'c -//│ | 'c :> error -//│ fun e: n149'' where -//│ | e147'' :> error<> -//│ | n149'' :> error<> <: e147'' -//│ [pretty-printed] e: 'n -//│ | where -//│ | 'n :> error -//│ | <: 'e -//│ | 'e :> error +//│ +//│ namespace Test2_1() { +//│ let this: 'this +//│ fun a: 'b +//│ fun d: 'e +//│ fun n: 456 +//│ fun t2: Test2_2 +//│ } +//│ namespace Test2_2() { +//│ let this: 'this0 +//│ fun b: 123 +//│ fun c: 'a +//│ fun e: 'n +//│ } Test2_1.t2.b +//│ +//│ 'b //│ Typed: 123 Test2_1.a +//│ +//│ 'a //│ Typed: 123 // FIXME Test2_1.d +//│ +//│ 'd //│ Typed: error Test2_1.n +//│ +//│ 'n //│ Typed: 456 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index a26ae0fe4f..53f25fad39 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -6,28 +6,36 @@ mixin Over { fun p = "hi" } -//│ mixin Over -//│ this: this23' -//│ super: super24' -//│ fun p: "hi" where -//│ [pretty-printed] p: "hi" +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() { +//│ fun p = ... +//│ },this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = ...,"hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) +//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) class Base1(p: int): Over { fun test = [p, this.p] // fun test2 = super.p // TODO } -//│ class Base1 -//│ fun test: (Int, p33'',) where -//│ | p33'' :> p33_34' -//│ | p33_34' :> "hi" -//│ [pretty-printed] test: (int, 'p,) -//│ | where -//│ | 'p :> 'p0 -//│ | 'p0 :> "hi" +//│ +//│ class Base1(p: int) { +//│ let this: 'this +//│ fun p: "hi" +//│ fun test: (int, 'p,) +//│ } Base1(123).test +//│ +//│ 'test //│ Typed: (int, "hi",) // TODO diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 32d57964fb..1e3f549b9d 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -502,7 +502,9 @@ class DiffTests tpd.force()(raise) val exp = typer.expandType(tpd)(ctx) + output(exp.show) + /* // val sctx = ShowCtx.mk(tpd) def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { @@ -535,6 +537,7 @@ class DiffTests } } showTTU(tpd, 0) + */ // val exp = getType(typer.PolymorphicType(0, res_ty)) // output(s"Typed: ${exp}") From d6d8bcdc9dac16f941957d75bac1e1d5d7357a30 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 01:12:11 +0800 Subject: [PATCH 046/498] WIPIP --- .../src/main/scala/mlscript/NewParser.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 5 ++- .../main/scala/mlscript/codegen/Helpers.scala | 4 +- shared/src/main/scala/mlscript/helpers.scala | 25 ++++++----- shared/src/main/scala/mlscript/syntax.scala | 1 + shared/src/test/diff/nu/BasicClasses.mls | 22 ++++++---- shared/src/test/diff/nu/BasicMixins.mls | 42 +++++++++---------- shared/src/test/diff/nu/ECOOP23.mls | 22 +++++----- shared/src/test/diff/nu/GenericClasses.mls | 26 +++++++----- shared/src/test/diff/nu/MutualRec.mls | 22 +++++----- shared/src/test/diff/nu/ParamOverriding.mls | 8 ++-- 11 files changed, 98 insertions(+), 81 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 411a7bbbf8..f57d819e00 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -292,7 +292,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } val ps = parents(if (kind === Als) KEYWORD("=") else KEYWORD(":")) val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams, params, ps, body) + val res = NuTypeDef(kind, tn, tparams, params, ps, N, body) R(res.withLoc(S(l0 ++ res.getLoc))) // TODO make `fun` by-name and `let` by-value diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 039824ef98..7faa86bb28 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -335,7 +335,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case ti: LazyTypeInfo => // ti.complete() ti.decl match { - case NuTypeDef(Cls, _, tps, _, _, _) => + case NuTypeDef(Cls, _, tps, _, _, _, _) => S(Cls, tps.size) case _ => ??? } @@ -1193,7 +1193,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // def mkTypingUnit(members: Ls[Str -> NuMember]): TypingUnit = { TypingUnit( // Asc(Var("this"), go(thisTy)) :: - NuFunDef(S(false), Var("this"), Nil, R(go(thisTy))) :: + // NuFunDef(S(false), Var("this"), Nil, R(go(thisTy))) :: sorted.collect { case (_, td: TypedNuDecl) => goDecl(td) case (_, td: TypedNuFun) => ??? @@ -1207,6 +1207,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), Nil,//TODO + S(go(thisTy)), mkTypingUnit(thisTy, members)) // mkTypingUnit(() :: members.toList.sortBy(_._1))) case TypedNuFun(level, fd, ty) => diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 5fecc34a17..2176f94c7a 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -85,9 +85,9 @@ object Helpers { s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, ${inspect(term)})" case NuFunDef(lt, nme, targs, R(ty)) => s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, $ty)" - case NuTypeDef(kind, nme, tparams, params, parents, body) => + case NuTypeDef(kind, nme, tparams, params, parents, ths, body) => s"NuTypeDef(${kind.str}, ${nme.name}, ${tparams.mkString("(", ", ", ")")}, ${ - inspect(params)}, ${parents.map(inspect).mkString("(", ", ", ")")}, ${inspect(body)})" + inspect(params)}, ${parents.map(inspect).mkString("(", ", ", ")")}, $ths, ${inspect(body)})" case others => others.toString() } .mkString("TypingUnit(", ", ", ")") diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 12a47c5813..b9a4ed9ea2 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -117,7 +117,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case S(ty) => "\n" + ty.showIn(ctx, 0) case N => "" }) - case NuTypeDef(kind, nme, tparams, params, parents, body) => + case NuTypeDef(kind, nme, tparams, params, parents, ths, body) => s"${kind.str} ${nme.name}${tparams.map(_.showIn(ctx, 0))mkStringOr(", ", "[", "]")}(${ params.fields.map { case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) @@ -127,8 +127,9 @@ trait TypeLikeImpl extends Located { self: TypeLike => })${parents match { case Nil => "" case ps => ps.mkString(", ") // TODO pp - }}${if (body.entities.isEmpty) "" else - " {" + Signature(body.entities.collect { case d: NuDecl => d }, N).showIn(ctx, 0) + "\n}" + }}${if (body.entities.isEmpty && ths.isEmpty) "" else + " {" + ths.fold("")("\nthis: " + _.showIn(ctx, 0)) + + Signature(body.entities.collect { case d: NuDecl => d }, N).showIn(ctx, 0) + "\n}" }" } @@ -150,11 +151,11 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList - case NuTypeDef(kind, nme, tparams, params, parents, body) => + case NuTypeDef(kind, nme, tparams, params, parents, ths, body) => // TODO improve this mess tparams ::: params.fields.collect { case (_, Fld(_, _, Asc(_, ty))) => ty - } ::: Signature(body.entities.collect { + } ::: ths.toList ::: Signature(body.entities.collect { case d: NuDecl => d }, N) :: Nil // TODO parents? } @@ -362,13 +363,13 @@ trait NuDeclImpl extends Located { self: NuDecl => def showDbg: Str = showHead + (this match { case NuFunDef(_, _, _, L(_)) => " = " case NuFunDef(_, _, _, R(_)) => ": " - case NuTypeDef(_, _, _, _, _, _) => " " + case NuTypeDef(_, _, _, _, _, _, _) => " " }) + showBody def showHead: Str = this match { case NuFunDef(N, n, _, b) => s"fun $n" case NuFunDef(S(false), n, _, b) => s"let $n" case NuFunDef(S(true), n, _, b) => s"let rec $n" - case NuTypeDef(k, n, tps, sps, parents, bod) => + case NuTypeDef(k, n, tps, sps, parents, ths, bod) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_.name).mkString("‹", ", ", "›")}(${ // sps.mkString("(",",",")") sps})${if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" @@ -666,19 +667,20 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, unit) => + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, ths, unit) => ??? // TODO - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, unit) => + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) require(pars.size === 1, pars) + require(ths.isEmpty, ths) require(unit.entities.isEmpty, unit) val (diags, rhs) = pars.head.toType match { case L(ds) => (ds :: Nil) -> Top case R(ty) => Nil -> ty } diags -> (TypeDef(k, nme, tps, rhs, Nil, Nil, Nil) :: Nil) - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, unit) => + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, ths, unit) => val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { case L(ds) => diags += ds; Top @@ -811,7 +813,8 @@ trait StatementImpl extends Located { self: Statement => case Where(bod, wh) => bod :: wh case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil - case NuTypeDef(k, nme, tps, ps, pars, bod) => nme :: tps ::: ps :: pars ::: bod :: Nil + case NuTypeDef(k, nme, tps, ps, pars, ths, bod) => + nme :: tps ::: ps :: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 3a31f2beb0..516fb88f8b 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -178,6 +178,7 @@ final case class NuTypeDef( tparams: Ls[TypeName], params: Tup, // the specialized parameters for that type parents: Ls[Term], + thisAnnot: Opt[Type], body: TypingUnit ) extends NuDecl with Statement diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index af9601163d..79733a56b7 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -10,6 +10,7 @@ class C { } //│ //│ class C() { +//│ this: 'this //│ fun const: 'a -> 'b -> 'b //│ fun id: 'b -> 'b //│ } @@ -23,6 +24,7 @@ class Base0(n) { } //│ //│ class Base0(n: 'n) { +//│ this: 'this //│ fun me: 'this //│ fun mine: 'n0 //│ fun my: 'n0 @@ -64,6 +66,7 @@ class Base1(base: int) { } //│ //│ class Base1(base: int) { +//│ this: 'this //│ fun foo: 'a -> 'b //│ fun getBase1: int //│ fun getBase2: 'base @@ -76,6 +79,7 @@ class Base1(base: int) { } //│ //│ class Base1(base: int) { +//│ this: 'this //│ fun foo: 'a -> 'b //│ fun getBase1: int //│ fun me: 'this @@ -109,7 +113,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.110: b.getBaseTypo +//│ ║ l.114: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ //│ 'getBaseTypo @@ -127,14 +131,15 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.126: class Rec(n) { +//│ ║ l.130: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.127: fun go = Rec(n + 1) +//│ ║ l.131: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.128: } +//│ ║ l.132: } //│ ╙── ^ //│ //│ class Rec(n: 'n) { +//│ this: 'this //│ fun go: 'a //│ } @@ -147,19 +152,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.146: a: int +//│ ║ l.151: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.145: class Annots(base: 0 | 1) { +//│ ║ l.150: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.146: a: int +//│ ║ l.151: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.146: a: int +//│ ║ l.151: a: int //│ ╙── ^^^ //│ //│ class Annots(base: (0 | 1,)) { +//│ this: 'this //│ fun a: (0 | 1,) //│ } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 9ba9ee814e..3afbcb1225 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -11,10 +11,10 @@ mixin BaseTest { //│ fun test = ... //│ },this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -30,10 +30,10 @@ mixin BaseInc { //│ fun test2 = ... //│ },this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,α36''), test2 ~> TypedNuFun(1,fun test2 = ...,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -46,7 +46,7 @@ class Base1(base: int): BaseTest, BaseInc { } //│ //│ class Base1(base: int) { -//│ let this: 'this +//│ this: 'this //│ fun test: 'a //│ fun test2: 'base //│ fun test3: (int, 'base0,) @@ -71,7 +71,7 @@ Base1(1).test3 class Base1(base): BaseTest //│ //│ class Base1(base: 'base) { -//│ let this: 'this +//│ this: 'this //│ fun test: 'base0 //│ } @@ -103,7 +103,7 @@ class Base1(x): BaseTest //│ ╙── ^^^^^ //│ //│ class Base1(x: 'x) { -//│ let this: 'this +//│ this: 'this //│ fun test: 'base //│ } @@ -121,10 +121,10 @@ mixin Foo { //│ fun test = ... //│ },this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -134,7 +134,7 @@ mixin Foo { module Base1(base: int, misc: string): Foo //│ //│ namespace Base1(base: int, misc: string) { -//│ let this: 'this +//│ this: 'this //│ fun test: 'a -> ('b, 'a, 'misc,) //│ } @@ -155,10 +155,10 @@ mixin WrapBase { //│ fun wrap = ... //│ },this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = ...,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = ...,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -175,10 +175,10 @@ mixin Wrap { //│ fun wrap = ... //│ },this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = ...,(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = ...,(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -191,7 +191,7 @@ mixin Wrap { module WrapBase1: WrapBase, Wrap //│ //│ namespace WrapBase1() { -//│ let this: 'this +//│ this: 'this //│ fun wrap: 'a -> ('b,) //│ fun wrapA: 'c -> ('d,) //│ } @@ -256,7 +256,7 @@ WrapBase1.wrapA("ok") module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ //│ namespace WrapBase2() { -//│ let this: 'this +//│ this: 'this //│ fun wrap: 'a -> ('b,) //│ fun wrapA: 'c -> ('d,) //│ } diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 9f1331e569..0e88149c5d 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -7,10 +7,10 @@ class Add(lhs: E, rhs: E) class Lit(n: int) //│ //│ class Add[E](lhs: E, rhs: E) { -//│ let this: 'this +//│ this: 'this //│ } //│ class Lit(n: int) { -//│ let this: 'this0 +//│ this: 'this0 //│ } let add11 = Add(Lit(1), Lit(2)) @@ -28,10 +28,10 @@ mixin EvalBase { //│ fun eval = ... //│ },this39',super40',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = ...,(α42'' -> (Int | α65'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -42,7 +42,7 @@ mixin EvalBase { module TestLang: EvalBase //│ //│ namespace TestLang() { -//│ let this: 'this +//│ this: 'this //│ fun eval: 'a -> (int | 'b) //│ } @@ -62,7 +62,7 @@ TestLang.eval(add11) class Neg(expr: A) //│ //│ class Neg[A](expr: A) { -//│ let this: 'this +//│ this: 'this //│ } let add2negadd11 = Add(Lit(2), Neg(add11)) @@ -79,10 +79,10 @@ mixin EvalNeg { //│ fun eval = ... //│ },this151',super152',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = ...,(α154'' -> (α165'' | α169'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -93,7 +93,7 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg //│ //│ namespace TestLang() { -//│ let this: 'this +//│ this: 'this //│ fun eval: 'a -> ('b | 'c) //│ } diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 4aac19f16f..860f61c2bb 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -11,6 +11,7 @@ class Some(value: A) { } //│ //│ class Some[A](value: A) { +//│ this: 'this //│ fun get: A //│ fun toArray: (A,) //│ } @@ -57,6 +58,7 @@ module None { } //│ //│ namespace None() { +//│ this: 'this //│ fun get: nothing //│ fun toArray: () //│ } @@ -125,6 +127,7 @@ class Test(n) { } //│ //│ class Test(n: 'n) { +//│ this: 'this //│ fun foo: 'a //│ } @@ -136,16 +139,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.137: Test(true) +//│ ║ l.140: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.137: Test(true) +//│ ║ l.140: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.124: fun foo = n + 1 +//│ ║ l.126: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.123: class Test(n) { +//│ ║ l.125: class Test(n) { //│ ╙── ^ //│ //│ 'a @@ -157,16 +160,17 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.157: fun foo = n + 1 +//│ ║ l.160: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.157: fun foo = n + 1 +//│ ║ l.160: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.156: class Test(n: A) { +//│ ║ l.159: class Test(n: A) { //│ ╙── ^ //│ //│ class Test[A](n: A) { +//│ this: 'this //│ fun foo: 'a //│ } @@ -192,6 +196,7 @@ class Test(n: A) { } //│ //│ class Test[A](n: A) { +//│ this: 'this //│ fun foo: A //│ fun foo1: (x: A,) -> A //│ fun id: 'a -> 'a @@ -247,16 +252,17 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.247: fun foo2(x: A) = x + 1 +//│ ║ l.252: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.247: fun foo2(x: A) = x + 1 +//│ ║ l.252: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.245: class Test { +//│ ║ l.250: class Test { //│ ╙── ^ //│ //│ class Test[A]() { +//│ this: 'this //│ fun foo1: (x: A,) -> A //│ fun foo2: (x: A,) -> 'a //│ } diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 73177aaf46..0b583352be 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -8,7 +8,7 @@ class Foo() 123 //│ //│ class Foo() { -//│ let this: 'this +//│ this: 'this //│ } //│ 123 //│ Typed: 123 @@ -113,11 +113,11 @@ module Test0_2 { } //│ //│ namespace Test0_1() { -//│ let this: 'this +//│ this: 'this //│ fun a: 'b //│ } //│ namespace Test0_2() { -//│ let this: 'this0 +//│ this: 'this0 //│ fun b: 123 //│ } @@ -134,11 +134,11 @@ class Test0_2() { } //│ //│ class Test0_1() { -//│ let this: 'this +//│ this: 'this //│ fun a: 'b //│ } //│ class Test0_2() { -//│ let this: 'this0 +//│ this: 'this0 //│ fun b: 123 //│ } @@ -159,11 +159,11 @@ module Test1_2 { //│ ╙── ^ //│ //│ namespace Test1_1() { -//│ let this: 'this +//│ this: 'this //│ fun a: 'b //│ } //│ namespace Test1_2() { -//│ let this: 'this0 +//│ this: 'this0 //│ fun b: 'a //│ } @@ -189,11 +189,11 @@ class Test1_2 { //│ ╙── ^ //│ //│ class Test1_1() { -//│ let this: 'this +//│ this: 'this //│ fun a: 'b //│ } //│ class Test1_2() { -//│ let this: 'this0 +//│ this: 'this0 //│ fun b: 'a //│ } @@ -238,14 +238,14 @@ module Test2_2 { //│ ╙── ^ //│ //│ namespace Test2_1() { -//│ let this: 'this +//│ this: 'this //│ fun a: 'b //│ fun d: 'e //│ fun n: 456 //│ fun t2: Test2_2 //│ } //│ namespace Test2_2() { -//│ let this: 'this0 +//│ this: 'this0 //│ fun b: 123 //│ fun c: 'a //│ fun e: 'n diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 53f25fad39..e9d09886cf 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -10,10 +10,10 @@ mixin Over { //│ fun p = ... //│ },this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = ...,"hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1221) -//│ at: mlscript.Typer.expandType(Typer.scala:1321) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -27,7 +27,7 @@ class Base1(p: int): Over { } //│ //│ class Base1(p: int) { -//│ let this: 'this +//│ this: 'this //│ fun p: "hi" //│ fun test: (int, 'p,) //│ } From 5ad315bf0c1c1db32bd4e5bced128a89dc263e93 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 01:22:10 +0800 Subject: [PATCH 047/498] WIPIP --- shared/src/main/scala/mlscript/Typer.scala | 18 +++-- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/nu/BasicClasses.mls | 73 +++++++++++++++++-- shared/src/test/diff/nu/BasicMixins.mls | 10 +-- shared/src/test/diff/nu/ECOOP23.mls | 4 +- shared/src/test/diff/nu/ParamOverriding.mls | 2 +- .../src/test/scala/mlscript/DiffTests.scala | 6 +- 9 files changed, 90 insertions(+), 29 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 7faa86bb28..4b6fc3614a 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -456,7 +456,10 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) tv case Rem(base, fs) => Without(rec(base), fs.toSortedSet)(tyTp(ty.toLoc, "field removal type")) case Constrained(base, tvbs, where) => - val res = rec(base) + val res = rec(base match { + case ty: Type => ty + case _ => die + }) tvbs.foreach { case (tv, Bounds(lb, ub)) => constrain(rec(lb), tv)(raise, tp(lb.toLoc, "lower bound specifiation"), ctx) constrain(tv, rec(ub))(raise, tp(ub.toLoc, "upper bound specifiation"), ctx) @@ -1216,8 +1219,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goLike(ty: TypeLike): mlscript.TypeLike = ty match { case ty: SimpleType => val res = go(ty) - if (bounds.isEmpty) res - else Constrained(res, bounds, Nil) + // if (bounds.isEmpty) res + // else Constrained(res, bounds, Nil) + res case OtherTypeLike(ttu) => val mems = ttu.entities.map { lti => lti.result match { @@ -1315,11 +1319,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) } // }(r => s"~> $r") - // val res = go(st) - // if (bounds.isEmpty) res - // else Constrained(res, bounds, Nil) + val res = goLike(st) + if (bounds.isEmpty) res + else Constrained(res, bounds, Nil) - goLike(st) + // goLike(st) } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 257b0a783c..ba87a42aeb 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -67,7 +67,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") - else trace(s"Completing ${decl}") { + else trace(s"Completing ${decl.showDbg}") { // var res: ST = errType val res = try { isComputing = true diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index b9a4ed9ea2..7ae403dc3d 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -824,7 +824,7 @@ trait StatementImpl extends Located { self: Statement => case DataDefn(head) => s"data $head" case _: Term => super.toString case d: Decl => d.show - case d: NuDecl => d.show + case d: NuDecl => d.showDbg } } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 516fb88f8b..8f351cdadf 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -137,7 +137,7 @@ final case class Rem(base: Type, names: Ls[Var]) extends Type final case class Bounds(lb: Type, ub: Type) extends Type final case class WithExtension(base: Type, rcd: Record) extends Type final case class Splice(fields: Ls[Either[Type, Field]]) extends Type -final case class Constrained(base: Type, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds]) extends Type +final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds]) extends Type final case class FirstClassDefn(defn: NuTypeDef) extends Type final case class Field(in: Opt[Type], out: Type) extends FieldImpl diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 79733a56b7..ead3d2e7ce 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -14,6 +14,8 @@ class C { //│ fun const: 'a -> 'b -> 'b //│ fun id: 'b -> 'b //│ } +//│ where +//│ 'this :> C class Base0(n) { @@ -30,6 +32,22 @@ class Base0(n) { //│ fun my: 'n0 //│ fun oops: 'my //│ } +//│ where +//│ 'my :> 'my0 +//│ <: 'oops +//│ 'oops :> 'my0 +//│ 'n0 :> 'n1 +//│ <: 'mine & 'my1 +//│ 'my1 :> 'n1 +//│ 'mine :> 'n1 +//│ 'this :> Base0 +//│ <: {my: 'my0} & {n: 'n1} +//│ 'n1 :> 'n2 +//│ 'my0 :> 'n3 +//│ 'n3 :> 'n4 +//│ <: 'mine0 & 'my2 +//│ 'my2 :> 'n4 +//│ 'mine0 :> 'n4 // :d // Base0 @@ -38,6 +56,8 @@ class Base0(n) { let b1 = Base0(42) //│ //│ let b1: 'a +//│ where +//│ 'a :> Base0 // :d let n1 = b1.n @@ -48,6 +68,8 @@ let n1 = b1.n n1 + 1 //│ //│ 'a +//│ where +//│ 'a :> int //│ Typed: int @@ -56,6 +78,9 @@ let n2 = b2.n //│ //│ let b2: 'a //│ let n2: 'n +//│ where +//│ 'a :> Base0 +//│ <: {n: 'n} @@ -71,6 +96,16 @@ class Base1(base: int) { //│ fun getBase1: int //│ fun getBase2: 'base //│ } +//│ where +//│ 'base :> 'base0 +//│ <: 'getBase2 +//│ 'getBase2 :> 'base0 +//│ 'b :> int +//│ 'a <: int +//│ 'this :> Base1 +//│ <: {base: 'base1} & {base: 'base0} +//│ 'base0 :> int +//│ 'base1 := int class Base1(base: int) { fun getBase1 = base @@ -84,6 +119,10 @@ class Base1(base: int) { //│ fun getBase1: int //│ fun me: 'this //│ } +//│ where +//│ 'b :> int +//│ 'a <: int +//│ 'this :> Base1 Base1 //│ @@ -93,30 +132,40 @@ Base1 let b = Base1(1) //│ //│ let b: 'a +//│ where +//│ 'a :> Base1 b.base //│ //│ 'base +//│ where +//│ 'base :> int //│ Typed: int b.getBase1 //│ //│ 'getBase1 +//│ where +//│ 'getBase1 :> int //│ Typed: int // :d b.me //│ //│ 'me +//│ where +//│ 'me :> Base1 //│ Typed: Base1 :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.114: b.getBaseTypo +//│ ║ l.161: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ //│ 'getBaseTypo +//│ where +//│ 'getBaseTypo :> error //│ Typed: error @@ -131,17 +180,23 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.130: class Rec(n) { +//│ ║ l.179: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.131: fun go = Rec(n + 1) +//│ ║ l.180: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.132: } +//│ ║ l.181: } //│ ╙── ^ //│ //│ class Rec(n: 'n) { //│ this: 'this //│ fun go: 'a //│ } +//│ where +//│ 'a :> error +//│ <: 'go +//│ 'go :> error +//│ 'this :> Rec +//│ 'n <: int @@ -152,22 +207,24 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.151: a: int +//│ ║ l.206: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.150: class Annots(base: 0 | 1) { +//│ ║ l.205: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.151: a: int +//│ ║ l.206: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.151: a: int +//│ ║ l.206: a: int //│ ╙── ^^^ //│ //│ class Annots(base: (0 | 1,)) { //│ this: 'this //│ fun a: (0 | 1,) //│ } +//│ where +//│ 'this :> Annots diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 3afbcb1225..2f8c039716 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -16,7 +16,7 @@ mixin BaseTest { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -35,7 +35,7 @@ mixin BaseInc { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -126,7 +126,7 @@ mixin Foo { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -160,7 +160,7 @@ mixin WrapBase { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -180,7 +180,7 @@ mixin Wrap { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 0e88149c5d..524e05459a 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -33,7 +33,7 @@ mixin EvalBase { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -84,7 +84,7 @@ mixin EvalNeg { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index e9d09886cf..d80f700052 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -15,7 +15,7 @@ mixin Over { //│ at: mlscript.Typer.goLike$1(Typer.scala:1222) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 1e3f549b9d..7a1f147ad6 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -502,9 +502,9 @@ class DiffTests tpd.force()(raise) val exp = typer.expandType(tpd)(ctx) + // output(exp.toString) output(exp.show) - /* // val sctx = ShowCtx.mk(tpd) def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { @@ -536,8 +536,8 @@ class DiffTests .indentNewLines(indStr+"|")}") } } - showTTU(tpd, 0) - */ + if (mode.explainErrors) + showTTU(tpd, 0) // val exp = getType(typer.PolymorphicType(0, res_ty)) // output(s"Typed: ${exp}") From 924e03ebfb994143a18752d52c49b64d50f4582b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 09:41:05 +0800 Subject: [PATCH 048/498] WIPIP update tests --- shared/src/test/diff/nu/BasicMixins.mls | 212 +++++++++++++++----- shared/src/test/diff/nu/ECOOP23.mls | 182 +++++++++++++++-- shared/src/test/diff/nu/GenericClasses.mls | 169 +++++++++++++++- shared/src/test/diff/nu/LetRec.mls | 2 +- shared/src/test/diff/nu/MutualRec.mls | 130 ++++++++++-- shared/src/test/diff/nu/ParamOverriding.mls | 21 +- 6 files changed, 620 insertions(+), 96 deletions(-) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 2f8c039716..5505e799e8 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -7,16 +7,14 @@ mixin BaseTest { fun test = super.base } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() { -//│ fun test = ... -//│ },this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() {fun test = ...},this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (super).base,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -25,17 +23,14 @@ mixin BaseInc { fun test = super.base + 1 fun test2 = this.base } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() { -//│ fun test = ... -//│ fun test2 = ... -//│ },this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,α36''), test2 ~> TypedNuFun(1,fun test2 = ...,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() {fun test = ...; fun test2 = ...},this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = + ((super).base,) (1,),α36''), test2 ~> TypedNuFun(1,fun test2 = (this).base,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -51,20 +46,40 @@ class Base1(base: int): BaseTest, BaseInc { //│ fun test2: 'base //│ fun test3: (int, 'base0,) //│ } +//│ where +//│ 'base0 :> 'base1 +//│ 'base :> 'base2 +//│ <: 'test2 +//│ 'test2 :> 'base2 +//│ 'base2 :> int +//│ 'a :> int +//│ <: 'test +//│ 'test :> int +//│ 'this :> Base1 +//│ <: {base: 'base1} +//│ 'base1 :> int Base1(1).test //│ //│ 'test +//│ where +//│ 'test :> int //│ Typed: int Base1(1).test2 //│ //│ 'test2 +//│ where +//│ 'test2 :> int //│ Typed: int Base1(1).test3 //│ //│ 'test3 +//│ where +//│ 'test3 :> (int, 'base,) +//│ 'base :> 'base0 +//│ 'base0 :> int //│ Typed: (int, int,) @@ -74,10 +89,18 @@ class Base1(base): BaseTest //│ this: 'this //│ fun test: 'base0 //│ } +//│ where +//│ 'base0 :> 'base1 +//│ <: 'test +//│ 'test :> 'base1 +//│ 'this :> Base1 +//│ 'base <: 'base1 Base1 //│ //│ forall 'base 'base0. (base: 'base,) -> Base1 +//│ where +//│ 'base <: 'base0 //│ Typed: (base: anything,) -> Base1 // TODO @@ -90,11 +113,11 @@ Base1(1).test :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.91: class Base1(x): BaseTest -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.114: class Base1(x): BaseTest +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.91: class Base1(x): BaseTest -//│ ║ ^^^ +//│ ║ l.114: class Base1(x): BaseTest +//│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base //│ ║ ^^^^^^^^^^ @@ -106,6 +129,11 @@ class Base1(x): BaseTest //│ this: 'this //│ fun test: 'base //│ } +//│ where +//│ 'base :> 'base0 +//│ <: 'test +//│ 'test :> 'base0 +//│ 'this :> Base1 Base1 //│ @@ -117,16 +145,14 @@ Base1 mixin Foo { fun test(x) = [super.base + x, x, super.misc] } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() { -//│ fun test = ... -//│ },this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = ...,(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() {fun test = ...},this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (x,) => '(' + ((super).base,) (x,), x, (super).misc, ')',(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -137,10 +163,22 @@ module Base1(base: int, misc: string): Foo //│ this: 'this //│ fun test: 'a -> ('b, 'a, 'misc,) //│ } +//│ where +//│ 'misc :> 'misc0 +//│ 'misc0 :> string +//│ 'b :> int +//│ 'a <: int +//│ 'this :> Base1 Base1.test //│ //│ 'test +//│ where +//│ 'test :> 'a -> ('b, 'a, 'misc,) +//│ 'misc :> 'misc0 +//│ 'misc0 :> string +//│ 'b :> int +//│ 'a <: int //│ Typed: (int & 'a) -> (int, 'a, string,) @@ -150,17 +188,14 @@ mixin WrapBase { fun wrapA(x: int) = x : int fun wrap(x) = x } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() { -//│ fun wrapA = ... -//│ fun wrap = ... -//│ },this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = ...,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = ...,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() {fun wrapA = ...; fun wrap = ...},this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x: int,) => x : int,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = (x,) => x,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -170,17 +205,14 @@ mixin Wrap { fun wrapA(x) = [super.wrapA(x)] fun wrap(x) = [super.wrap(x)] } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() { -//│ fun wrapA = ... -//│ fun wrap = ... -//│ },this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = ...,(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = ...,(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() {fun wrapA = ...; fun wrap = ...},this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x,) => '(' (super).wrapA (x,), ')',(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -195,6 +227,16 @@ module WrapBase1: WrapBase, Wrap //│ fun wrap: 'a -> ('b,) //│ fun wrapA: 'c -> ('d,) //│ } +//│ where +//│ 'd :> 'e +//│ 'e :> int +//│ 'c <: 'f +//│ 'f <: int +//│ 'b :> 'g +//│ 'a <: 'h +//│ 'h <: 'i +//│ 'i <: 'g +//│ 'this :> WrapBase1 WrapBase1 @@ -206,11 +248,23 @@ WrapBase1 WrapBase1.wrapA //│ //│ 'wrapA +//│ where +//│ 'wrapA :> 'a -> ('b,) +//│ 'b :> 'c +//│ 'c :> int +//│ 'a <: 'd +//│ 'd <: int //│ Typed: int -> (int,) WrapBase1.wrap //│ //│ 'wrap +//│ where +//│ 'wrap :> 'a -> ('b,) +//│ 'b :> 'c +//│ 'a <: 'd +//│ 'd <: 'e +//│ 'e <: 'c //│ Typed: 'a -> ('a,) // :d @@ -220,35 +274,51 @@ WrapBase1.wrap WrapBase1.wrap(1) //│ //│ 'a +//│ where +//│ 'a :> ('b,) +//│ 'b :> 'c +//│ 'c :> 1 //│ Typed: (1,) WrapBase1.wrap("ok") //│ //│ 'a +//│ where +//│ 'a :> ('b,) +//│ 'b :> 'c +//│ 'c :> "ok" //│ Typed: ("ok",) WrapBase1.wrapA(1) //│ //│ 'a +//│ where +//│ 'a :> ('b,) +//│ 'b :> 'c +//│ 'c :> int //│ Typed: (int,) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.237: WrapBase1.wrapA("ok") +//│ ║ l.303: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.237: WrapBase1.wrapA("ok") +//│ ║ l.303: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.150: fun wrapA(x: int) = x : int +//│ ║ l.188: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.170: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.205: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ //│ 'a +//│ where +//│ 'a :> ('b,) | error +//│ 'b :> 'c +//│ 'c :> int //│ Typed: (int,) | error @@ -260,18 +330,68 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ fun wrap: 'a -> ('b,) //│ fun wrapA: 'c -> ('d,) //│ } +//│ where +//│ 'd :> 'e +//│ 'e :> ('f,) +//│ 'f :> 'g +//│ 'g :> ('h,) +//│ 'h :> 'i +//│ 'i :> int +//│ 'c <: 'j +//│ 'j <: 'k +//│ 'k <: 'l +//│ 'l <: 'm +//│ 'm <: 'n +//│ 'n <: int +//│ 'b :> 'o +//│ 'o :> ('p,) +//│ 'p :> 'q +//│ 'q :> ('r,) +//│ 'r :> 's +//│ 'a <: 't +//│ 't <: 'u +//│ 'u <: 'v +//│ 'v <: 'w +//│ 'w <: 'x +//│ 'x <: 'y +//│ 'y <: 's +//│ 'this :> WrapBase2 let w = WrapBase2.wrap //│ //│ let w: 'wrap +//│ where +//│ 'wrap :> 'a -> ('b,) +//│ 'b :> 'c +//│ 'c :> ('d,) +//│ 'd :> 'e +//│ 'e :> ('f,) +//│ 'f :> 'g +//│ 'a <: 'h +//│ 'h <: 'i +//│ 'i <: 'j +//│ 'j <: 'k +//│ 'k <: 'l +//│ 'l <: 'm +//│ 'm <: 'g let wd = w(1) //│ //│ let wd: 'a +//│ where +//│ 'a :> ('b,) +//│ 'b :> 'c +//│ 'c :> ('d,) +//│ 'd :> 'e +//│ 'e :> ('f,) +//│ 'f :> 'g +//│ 'g :> 1 wd._1._1._1 + 1 //│ //│ 'a +//│ where +//│ 'a :> int //│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 524e05459a..b338673216 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -12,10 +12,16 @@ class Lit(n: int) //│ class Lit(n: int) { //│ this: 'this0 //│ } +//│ where +//│ 'this0 :> Lit +//│ 'this :> Add let add11 = Add(Lit(1), Lit(2)) //│ //│ let add11: 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> Lit mixin EvalBase { @@ -24,16 +30,14 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() { -//│ fun eval = ... -//│ },this39',super40',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = ...,(α42'' -> (Int | α65'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this39',super40',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α42'' -> (Int | α65'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -45,10 +49,38 @@ module TestLang: EvalBase //│ this: 'this //│ fun eval: 'a -> (int | 'b) //│ } +//│ where +//│ 'b := int +//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) +//│ <: Lit & 'c | Add & 'd & ~Lit +//│ 'rhs :> 'rhs0 +//│ 'lhs :> 'lhs0 +//│ 'lhs0 <: Lit & 'c | Add & 'd & ~Lit +//│ 'd <: {rhs: 'rhs1} & {lhs: 'lhs1} +//│ 'lhs1 <: 'lhs0 +//│ 'rhs1 <: 'rhs0 +//│ 'rhs0 <: Lit & 'c | Add & 'd & ~Lit +//│ 'c <: {n: 'n} +//│ 'n <: int +//│ 'this :> TestLang TestLang.eval //│ //│ 'eval +//│ where +//│ 'eval :> 'a -> (int | 'b) +//│ 'b := int +//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) +//│ <: Lit & 'c | Add & 'd & ~Lit +//│ 'rhs :> 'rhs0 +//│ 'lhs :> 'lhs0 +//│ 'lhs0 <: Lit & 'c | Add & 'd & ~Lit +//│ 'd <: {rhs: 'rhs1} & {lhs: 'lhs1} +//│ 'lhs1 <: 'lhs0 +//│ 'rhs1 <: 'rhs0 +//│ 'rhs0 <: Lit & 'c | Add & 'd & ~Lit +//│ 'c <: {n: 'n} +//│ 'n <: int //│ Typed: 'rhs -> int //│ where //│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} @@ -56,6 +88,9 @@ TestLang.eval TestLang.eval(add11) //│ //│ 'a +//│ where +//│ 'a :> int | 'b +//│ 'b := int //│ Typed: int @@ -64,10 +99,31 @@ class Neg(expr: A) //│ class Neg[A](expr: A) { //│ this: 'this //│ } +//│ where +//│ 'this :> Neg let add2negadd11 = Add(Lit(2), Neg(add11)) //│ //│ let add2negadd11: 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> Neg & {Neg#A = 'A} | Lit +//│ 'A :> Add & {Add#E = 'E0} +//│ 'E0 :> Lit +//│ <: 'lhs & 'rhs +//│ 'lhs :> Lit +//│ <: 'lhs0 +//│ 'lhs0 :> Lit +//│ <: Lit & 'b | Add & 'c & ~Lit +//│ 'c :> Add & {Add#E = 'E0} +//│ <: {rhs: 'rhs} & {lhs: 'lhs} +//│ 'rhs :> Lit +//│ <: 'rhs0 +//│ 'rhs0 :> Lit +//│ <: Lit & 'b | Add & 'c & ~Lit +//│ 'b :> Lit +//│ <: {n: 'n} +//│ 'n := int mixin EvalNeg { @@ -75,16 +131,14 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() { -//│ fun eval = ... -//│ },this151',super152',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = ...,(α154'' -> (α165'' | α169'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this151',super152',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α154'' -> (α165'' | α169'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -96,10 +150,62 @@ module TestLang: EvalBase, EvalNeg //│ this: 'this //│ fun eval: 'a -> ('b | 'c) //│ } +//│ where +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) +//│ <: Neg & 'f | 'g & ~Neg +//│ 'expr :> 'expr0 +//│ 'rhs :> 'rhs0 +//│ 'lhs :> 'lhs0 +//│ 'lhs0 <: Neg & 'f | 'g & ~Neg +//│ 'f <: {expr: 'expr1} +//│ 'expr1 <: 'expr0 +//│ 'expr0 <: Neg & 'f | 'g & ~Neg +//│ 'g <: 'h +//│ 'h <: 'i +//│ 'i <: Lit & 'j | Add & 'k & ~Lit +//│ 'k <: {rhs: 'rhs1} & {lhs: 'lhs1} +//│ 'lhs1 <: 'lhs0 +//│ 'rhs1 <: 'rhs0 +//│ 'rhs0 <: Neg & 'f | 'g & ~Neg +//│ 'j <: {n: 'n} +//│ 'n <: int +//│ 'this :> TestLang TestLang.eval //│ //│ 'eval +//│ where +//│ 'eval :> 'a -> ('b | 'c) +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) +//│ <: Neg & 'f | 'g & ~Neg +//│ 'expr :> 'expr0 +//│ 'rhs :> 'rhs0 +//│ 'lhs :> 'lhs0 +//│ 'lhs0 <: Neg & 'f | 'g & ~Neg +//│ 'f <: {expr: 'expr1} +//│ 'expr1 <: 'expr0 +//│ 'expr0 <: Neg & 'f | 'g & ~Neg +//│ 'g <: 'h +//│ 'h <: 'i +//│ 'i <: Lit & 'j | Add & 'k & ~Lit +//│ 'k <: {rhs: 'rhs1} & {lhs: 'lhs1} +//│ 'lhs1 <: 'lhs0 +//│ 'rhs1 <: 'rhs0 +//│ 'rhs0 <: Neg & 'f | 'g & ~Neg +//│ 'j <: {n: 'n} +//│ 'n <: int //│ Typed: 'rhs -> int //│ where //│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} | Neg & {expr: 'rhs} @@ -108,32 +214,80 @@ TestLang.eval TestLang.eval(add11) //│ //│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int //│ Typed: int TestLang.eval(Neg(add11)) //│ //│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int //│ Typed: int TestLang.eval(Add(Lit(2), Neg(Lit(1)))) //│ //│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int //│ Typed: int TestLang.eval(Neg(Neg(add11))) //│ //│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int //│ Typed: int TestLang.eval(add2negadd11) //│ //│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int //│ Typed: int TestLang.eval(Add(Lit(2), Neg(add11))) //│ //│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int //│ Typed: int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 860f61c2bb..9f9ed5e194 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -15,26 +15,42 @@ class Some(value: A) { //│ fun get: A //│ fun toArray: (A,) //│ } +//│ where +//│ 'this :> Some let s = Some(1) //│ //│ let s: 'a +//│ where +//│ 'a :> Some & {Some#A = 'A} +//│ 'A :> 1 s.value //│ //│ 'value +//│ where +//│ 'value :> 1 //│ Typed: 1 s.get //│ //│ 'get +//│ where +//│ 'get :> 1 //│ Typed: 1 s.toArray //│ //│ 'toArray +//│ where +//│ 'toArray :> ('A,) +//│ 'A := 'A0 +//│ 'A0 :> 1 +//│ <: 'get & 'value +//│ 'value :> 1 +//│ 'get :> 1 //│ Typed: (1,) @@ -62,11 +78,15 @@ module None { //│ fun get: nothing //│ fun toArray: () //│ } +//│ where +//│ 'this :> None None.toArray //│ //│ 'toArray +//│ where +//│ 'toArray :> () //│ Typed: () @@ -79,10 +99,17 @@ type Option = Some | None let opt = if true then Some(123) else None //│ //│ let opt: 'a | None +//│ where +//│ 'a :> Some & {Some#A = 'A} +//│ 'A :> 123 opt.toArray //│ //│ 'toArray +//│ where +//│ 'toArray :> () | ('A,) +//│ 'A := 'A0 +//│ 'A0 :> 123 //│ Typed: Array[123] @@ -97,11 +124,16 @@ opt.toArray if opt is Some then opt.value else 0 //│ //│ 'value | 0 +//│ where +//│ 'value :> 123 //│ Typed: 0 | 123 if opt is Some(v) then v else 0 //│ //│ (forall 'value. 'value) | 0 +//│ where +//│ 'value :> 'value0 +//│ 'value0 :> 123 //│ Typed: 0 | 123 @@ -110,14 +142,29 @@ fun map(x, f) = if x is Some(v) then Some(f(v)) //│ //│ fun map: ('a, 'b,) -> (None | 'c) +//│ where +//│ 'c :> Some & {Some#A = 'A} +//│ 'b <: (forall 'value. 'value) -> 'd +//│ 'd <: 'A +//│ 'value :> 'value0 +//│ 'a <: None & 'e | Some & 'f & ~None +//│ 'f <: {value: 'value0} let mo = map(opt, succ) //│ //│ let mo: 'a +//│ where +//│ 'a :> None | 'b +//│ 'b :> Some & {Some#A :> 'A <: 'A0} +//│ 'A0 :> 'A | int mo.toArray //│ //│ 'toArray +//│ where +//│ 'toArray :> ('A,) | () +//│ 'A := in 'A0 out 'A1 +//│ 'A1 :> 'A0 | int //│ Typed: Array[int] @@ -130,28 +177,38 @@ class Test(n) { //│ this: 'this //│ fun foo: 'a //│ } +//│ where +//│ 'a :> int +//│ <: 'foo +//│ 'foo :> int +//│ 'this :> Test +//│ 'n <: int Test(1) //│ //│ 'a +//│ where +//│ 'a :> Test //│ Typed: Test :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.140: Test(true) +//│ ║ l.195: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.140: Test(true) +//│ ║ l.195: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.126: fun foo = n + 1 +//│ ║ l.173: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.125: class Test(n) { +//│ ║ l.172: class Test(n) { //│ ╙── ^ //│ //│ 'a +//│ where +//│ 'a :> Test | error //│ Typed: Test | error @@ -160,23 +217,31 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.160: fun foo = n + 1 +//│ ║ l.217: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.160: fun foo = n + 1 +//│ ║ l.217: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.159: class Test(n: A) { +//│ ║ l.216: class Test(n: A) { //│ ╙── ^ //│ //│ class Test[A](n: A) { //│ this: 'this //│ fun foo: 'a //│ } +//│ where +//│ 'a :> error | int +//│ <: 'foo +//│ 'foo :> int | error +//│ 'this :> Test Test(1) //│ //│ 'a +//│ where +//│ 'a :> Test & {Test#A = 'A} +//│ 'A :> 1 //│ Typed: Test & {Test#A = 'A} //│ where //│ 'A :> 1 @@ -184,6 +249,9 @@ Test(1) Test(true) //│ //│ 'a +//│ where +//│ 'a :> Test & {Test#A = 'A} +//│ 'A :> true //│ Typed: Test & {Test#A = 'A} //│ where //│ 'A :> true @@ -201,10 +269,15 @@ class Test(n: A) { //│ fun foo1: (x: A,) -> A //│ fun id: 'a -> 'a //│ } +//│ where +//│ 'this :> Test Test(1) //│ //│ 'a +//│ where +//│ 'a :> Test & {Test#A = 'A} +//│ 'A :> 1 //│ Typed: Test & {Test#A = 'A} //│ where //│ 'A :> 1 @@ -212,25 +285,40 @@ Test(1) Test(1).foo //│ //│ 'foo +//│ where +//│ 'foo :> 1 //│ Typed: 1 Test("ok").foo //│ //│ 'foo +//│ where +//│ 'foo :> "ok" //│ Typed: "ok" let t = Test(1) //│ //│ let t: 'a +//│ where +//│ 'a :> Test & {Test#A = 'A} +//│ 'A :> 1 t.foo1(true) //│ //│ 'a +//│ where +//│ 'a :> 1 | true //│ Typed: 1 | true t : Test<'a> //│ //│ Test['a] +//│ where +//│ 'a :> 1 | true +//│ <: 'A +//│ 'A :> true | 1 +//│ <: 'a & 'b +//│ 'b :> true | 1 //│ Typed: Test['a] //│ where //│ 'a :> 1 | true @@ -238,11 +326,16 @@ t : Test<'a> t.id //│ //│ 'id +//│ where +//│ 'id :> 'a -> 'a //│ Typed: 'a -> 'a [t.id(1), t.id(true)] //│ //│ ('a, 'b,) +//│ where +//│ 'b :> true +//│ 'a :> 1 //│ Typed: (1, true,) @@ -252,13 +345,13 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.252: fun foo2(x: A) = x + 1 +//│ ║ l.345: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.252: fun foo2(x: A) = x + 1 +//│ ║ l.345: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.250: class Test { +//│ ║ l.343: class Test { //│ ╙── ^ //│ //│ class Test[A]() { @@ -266,66 +359,122 @@ class Test { //│ fun foo1: (x: A,) -> A //│ fun foo2: (x: A,) -> 'a //│ } +//│ where +//│ 'a :> error | int +//│ 'this :> Test Test().foo1 //│ //│ 'foo1 +//│ where +//│ 'foo1 :> (x: 'A,) -> 'A +//│ 'A := 'A0 //│ Typed: (x: 'A,) -> 'A Test().foo1(1) //│ //│ 'a +//│ where +//│ 'a :> 1 //│ Typed: 1 x => Test().foo1(x) //│ //│ 'a -> 'b +//│ where +//│ 'a <: 'A +//│ 'A <: 'b //│ Typed: 'a -> 'a // :d let t = Test() //│ //│ let t: 'a +//│ where +//│ 'a :> forall 'A. Test & {Test#A = 'A} t.foo1 //│ //│ 'foo1 +//│ where +//│ 'foo1 :> (x: 'A,) -> 'A +//│ 'A := 'A0 //│ Typed: (x: 'A,) -> 'A [t.foo1(0), t.foo1(true)] //│ //│ ('a, 'b,) +//│ where +//│ 'b :> true +//│ 'a :> 0 //│ Typed: (0, true,) t.foo1(0) //│ //│ 'a +//│ where +//│ 'a :> 0 //│ Typed: 0 t //│ //│ 'a +//│ where +//│ 'a :> forall 'A. Test & {Test#A = 'A} +//│ <: {foo1: 'foo1} & {foo1: 'foo10} & {foo1: 'foo11} & {foo1: 'foo12} +//│ 'foo12 :> (x: 'A0,) -> 'A0 +//│ 'A0 := 'A1 +//│ 'foo11 :> (x: 'A2,) -> 'A2 +//│ <: 0 -> 'b +//│ 'A2 := 'A3 +//│ 'A3 :> 0 +//│ <: 'b +//│ 'b :> 0 +//│ 'foo10 :> (x: 'A4,) -> 'A4 +//│ <: true -> 'c +//│ 'A4 := 'A5 +//│ 'A5 :> true +//│ <: 'c +//│ 'c :> true +//│ 'foo1 :> (x: 'A6,) -> 'A6 +//│ <: 0 -> 'd +//│ 'A6 := 'A7 +//│ 'A7 :> 0 +//│ <: 'd +//│ 'd :> 0 //│ Typed: Test & {Test#A = 'A} fun foo(x: Test) = x.foo1 //│ //│ fun foo: (x: Test[int],) -> 'foo1 +//│ where +//│ 'foo1 :> (x: 'A,) -> 'A +//│ 'A := int foo(t) //│ //│ 'a +//│ where +//│ 'a :> (x: 'A,) -> 'A +//│ 'A := int //│ Typed: (x: int,) -> int foo(t)(1) //│ //│ 'a +//│ where +//│ 'a :> int //│ Typed: int Test().foo2 //│ //│ 'foo2 +//│ where +//│ 'foo2 :> (x: 'A,) -> 'a +//│ 'a :> error | int +//│ 'A := 'A0 //│ Typed: (x: anything,) -> (error | int) diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index c8c1451fe3..a1ca2c44a9 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -71,7 +71,7 @@ f :p let rec f = 1 //│ |#let| |#rec| |f| |#=| |1| -//│ Parsed: let rec f = ...; +//│ Parsed: let rec f = 1; //│ Desugared: rec def f: 1 //│ AST: Def(true, f, IntLit(1), false) //│ f: 1 diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 0b583352be..a322b2db59 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -11,6 +11,8 @@ class Foo() //│ this: 'this //│ } //│ 123 +//│ where +//│ 'this :> Foo //│ Typed: 123 Foo @@ -23,6 +25,9 @@ fun fooo(x) = C(0, x) //│ //│ fun fooo: 'a -> 'b +//│ where +//│ 'b :> C +//│ 'a <: 'z @@ -31,6 +36,8 @@ fun bar = foo //│ //│ fun foo: 'foo //│ fun bar: 'foo +//│ where +//│ 'foo <: 'bar foo(bar) //│ @@ -41,6 +48,8 @@ foo(bar) fun foo = {x: foo} //│ //│ fun foo: {x: 'foo} +//│ where +//│ 'foo :> {x: 'foo} fun foo = {x: bar} @@ -48,11 +57,15 @@ fun bar = {y: foo} //│ //│ fun foo: {x: {y: 'foo}} //│ fun bar: {y: 'foo} +//│ where +//│ 'foo :> {x: {y: 'foo}} // FIXME pretty-printing? foo //│ //│ {x: {y: 'foo}} +//│ where +//│ 'foo :> {x: {y: 'foo}} //│ Typed: 'foo //│ where //│ 'foo :> {x: {y: 'foo}} @@ -61,6 +74,8 @@ foo foo //│ //│ {x: {y: 'foo}} +//│ where +//│ 'foo :> {x: {y: 'foo}} //│ Typed: forall 'foo. {x: {y: 'foo}} //│ where //│ 'foo :> {x: {y: 'foo}} @@ -68,6 +83,9 @@ foo foo.x //│ //│ 'x +//│ where +//│ 'x :> {y: 'foo} +//│ 'foo :> {x: {y: 'foo}} //│ Typed: 'x //│ where //│ 'x :> {y: {x: 'x}} @@ -75,6 +93,10 @@ foo.x foo.x.y //│ //│ 'y +//│ where +//│ 'y :> {x: {y: 'foo}} +//│ 'foo :> {x: {y: 'foo}} +//│ <: 'y //│ Typed: 'foo //│ where //│ 'foo :> {x: {y: 'foo}} @@ -85,11 +107,21 @@ fun bar(b) = foo(b) //│ //│ fun foo: 'a -> {h: 'a, t: 'b} //│ fun bar: 'c -> 'd +//│ where +//│ 'd :> {h: 'a, t: 'b} +//│ <: 'b +//│ 'b :> {h: 'a, t: 'b} +//│ 'a <: 'c +//│ 'c <: 'a :ns foo //│ //│ 'a -> {h: 'a, t: 'b} +//│ where +//│ 'b :> {h: 'a, t: 'b} +//│ 'a <: 'c +//│ 'c <: 'a //│ Typed: forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} //│ where //│ 'c :> {h: 'a, t: 'c} @@ -102,6 +134,11 @@ fun bar(b) = {h2: b, t2: foo(b)} //│ //│ fun foo: 'a -> {h1: 'a, t1: 'b} //│ fun bar: 'c -> {h2: 'c, t2: 'd} +//│ where +//│ 'b :> {h2: 'c, t2: 'd} +//│ 'd :> {h1: 'a, t1: 'b} +//│ 'a <: 'c +//│ 'c <: 'a @@ -120,10 +157,18 @@ module Test0_2 { //│ this: 'this0 //│ fun b: 123 //│ } +//│ where +//│ 'this0 :> Test0_2 +//│ 'b :> 123 +//│ <: 'a +//│ 'a :> 123 +//│ 'this :> Test0_1 Test0_1.a //│ //│ 'a +//│ where +//│ 'a :> 123 //│ Typed: 123 class Test0_1 { @@ -141,6 +186,12 @@ class Test0_2() { //│ this: 'this0 //│ fun b: 123 //│ } +//│ where +//│ 'this0 :> Test0_2 +//│ 'b :> 123 +//│ <: 'a +//│ 'a :> 123 +//│ 'this :> Test0_1 :e // TODO @@ -151,11 +202,11 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.147: module Test1_1 { +//│ ║ l.198: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.148: fun a = Test1_2.b +//│ ║ l.199: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.149: } +//│ ║ l.200: } //│ ╙── ^ //│ //│ namespace Test1_1() { @@ -166,10 +217,21 @@ module Test1_2 { //│ this: 'this0 //│ fun b: 'a //│ } +//│ where +//│ 'a :> error +//│ <: 'b0 +//│ 'b0 :> error +//│ 'this0 :> Test1_2 +//│ 'b :> error +//│ <: 'a0 +//│ 'a0 :> error +//│ 'this :> Test1_1 Test1_1.a //│ //│ 'a +//│ where +//│ 'a :> error //│ Typed: error @@ -181,11 +243,11 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.177: class Test1_1 { +//│ ║ l.239: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.178: fun a = Test1_2().b +//│ ║ l.240: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.179: } +//│ ║ l.241: } //│ ╙── ^ //│ //│ class Test1_1() { @@ -196,6 +258,15 @@ class Test1_2 { //│ this: 'this0 //│ fun b: 'a //│ } +//│ where +//│ 'a :> error +//│ <: 'b0 +//│ 'b0 :> error +//│ 'this0 :> Test1_2 +//│ 'b :> error +//│ <: 'a0 +//│ 'a0 :> error +//│ 'this :> Test1_1 // TODO check TV hygiene @@ -211,30 +282,30 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.202: module Test2_1 { +//│ ║ l.273: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.203: fun t2 = Test2_2 +//│ ║ l.274: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.204: fun a = Test2_2.b +//│ ║ l.275: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.205: fun d = Test2_2.e +//│ ║ l.276: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.206: fun n = 456 +//│ ║ l.277: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.207: } +//│ ║ l.278: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.202: module Test2_1 { +//│ ║ l.273: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.203: fun t2 = Test2_2 +//│ ║ l.274: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.204: fun a = Test2_2.b +//│ ║ l.275: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.205: fun d = Test2_2.e +//│ ║ l.276: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.206: fun n = 456 +//│ ║ l.277: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.207: } +//│ ║ l.278: } //│ ╙── ^ //│ //│ namespace Test2_1() { @@ -250,25 +321,48 @@ module Test2_2 { //│ fun c: 'a //│ fun e: 'n //│ } +//│ where +//│ 'n :> error +//│ <: 'e0 +//│ 'e0 :> error +//│ 'a :> error +//│ <: 'c +//│ 'c :> error +//│ 'this0 :> Test2_2 +//│ 'e :> error +//│ <: 'd +//│ 'd :> error +//│ 'b :> 123 +//│ <: 'a0 +//│ 'a0 :> 123 +//│ 'this :> Test2_1 Test2_1.t2.b //│ //│ 'b +//│ where +//│ 'b :> 123 //│ Typed: 123 Test2_1.a //│ //│ 'a +//│ where +//│ 'a :> 123 //│ Typed: 123 // FIXME Test2_1.d //│ //│ 'd +//│ where +//│ 'd :> error //│ Typed: error Test2_1.n //│ //│ 'n +//│ where +//│ 'n :> 456 //│ Typed: 456 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index d80f700052..8bfa754f49 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -6,16 +6,14 @@ mixin Over { fun p = "hi" } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() { -//│ fun p = ... -//│ },this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = ...,"hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1204) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1231) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() {fun p = ...},this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = "hi","hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1222) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) //│ at: mlscript.Typer.expandType(Typer.scala:1322) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:942) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -31,11 +29,20 @@ class Base1(p: int): Over { //│ fun p: "hi" //│ fun test: (int, 'p,) //│ } +//│ where +//│ 'p :> 'p0 +//│ 'this :> Base1 +//│ <: {p: 'p0} +//│ 'p0 :> "hi" Base1(123).test //│ //│ 'test +//│ where +//│ 'test :> (int, 'p,) +//│ 'p :> 'p0 +//│ 'p0 :> "hi" //│ Typed: (int, "hi",) // TODO From 8e00b6dcd08786a8fa84542b79d1280e8a99e251 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 18:19:39 +0800 Subject: [PATCH 049/498] WIPIP try alt patmat approach --- shared/src/main/scala/mlscript/Typer.scala | 13 +- shared/src/test/diff/nu/BasicClasses.mls | 94 +++++++++++- shared/src/test/diff/nu/BasicMixins.mls | 40 ++--- shared/src/test/diff/nu/ECOOP23.mls | 161 ++++++++++---------- shared/src/test/diff/nu/GenericClasses.mls | 46 +++--- shared/src/test/diff/nu/New.mls | 24 ++- shared/src/test/diff/nu/ParamOverriding.mls | 8 +- 7 files changed, 241 insertions(+), 145 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 4b6fc3614a..5e6eee24cc 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1085,12 +1085,15 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val newCtx = ctx.nest val (req_ty, bod_ty, (tys, rest_ty)) = scrutVar match { case S(v) => - val tv = freshVar(tp(v.toLoc, "refined scrutinee"), N, - // S(v.name), // this one seems a bit excessive - ) - newCtx += v.name -> VarSymbol(tv, v) + // val tv = freshVar(tp(v.toLoc, "refined scrutinee"), N, + // // S(v.name), // this one seems a bit excessive + // ) + // newCtx += v.name -> VarSymbol(tv, v) + // val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) + // (patTy -> tv, bod_ty, typeArms(scrutVar, rest)) + newCtx += v.name -> VarSymbol(patTy, v) val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) - (patTy -> tv, bod_ty, typeArms(scrutVar, rest)) + (patTy -> patTy, bod_ty, typeArms(scrutVar, rest)) case N => val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) (patTy -> TopType, bod_ty, typeArms(scrutVar, rest)) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index ead3d2e7ce..bc718a19bb 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -3,6 +3,84 @@ :NoJS +class A(n: int) +//│ +//│ class A(n: int) { +//│ this: 'this +//│ } +//│ where +//│ 'this :> A + +let a = A(42) +//│ +//│ let a: 'a +//│ where +//│ 'a :> A + + +fun f(x: A) = x.n +//│ +//│ fun f: (x: A,) -> 'n +//│ where +//│ 'n :> int + +fun f(x: A) = if x is A then x.n +//│ +//│ fun f: (x: A,) -> 'n +//│ where +//│ 'n :> int + +// FIXedME no bounds on 'n... +fun f(x: A | 'b) = if x is A then x.n else 0 +//│ +//│ fun f: (x: (A | 'b,),) -> ('n | 0) +//│ where +//│ 'n :> int + + +fun f(x) = x.n +//│ +//│ fun f: 'a -> 'n +//│ where +//│ 'a <: {n: 'n} + +f(a) +//│ +//│ 'a +//│ where +//│ 'a :> int +//│ Typed: int + +fun f(x) = if x is A then x.n +//│ +//│ fun f: 'a -> 'n +//│ where +//│ 'n :> int +//│ 'a <: A + +f(a) +//│ +//│ 'a +//│ where +//│ 'a :> int +//│ Typed: int + +fun f(x) = if x is A then x.n else 0 +//│ +//│ fun f: 'a -> ('n | 0) +//│ where +//│ 'n :> int +//│ 'a <: A | 'b & ~A + +f(a) +//│ +//│ 'a +//│ where +//│ 'a :> 'n | 0 +//│ 'n :> int +//│ Typed: int + + class C { fun id(x) = x @@ -160,7 +238,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.161: b.getBaseTypo +//│ ║ l.239: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ //│ 'getBaseTypo @@ -180,11 +258,11 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.179: class Rec(n) { +//│ ║ l.257: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.180: fun go = Rec(n + 1) +//│ ║ l.258: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.181: } +//│ ║ l.259: } //│ ╙── ^ //│ //│ class Rec(n: 'n) { @@ -207,16 +285,16 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.206: a: int +//│ ║ l.284: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.205: class Annots(base: 0 | 1) { +//│ ║ l.283: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.206: a: int +//│ ║ l.284: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.206: a: int +//│ ║ l.284: a: int //│ ╙── ^^^ //│ //│ class Annots(base: (0 | 1,)) { diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 5505e799e8..7d623f9b87 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -8,11 +8,11 @@ mixin BaseTest { fun test = super.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() {fun test = ...},this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (super).base,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -24,11 +24,11 @@ mixin BaseInc { fun test2 = this.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() {fun test = ...; fun test2 = ...},this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = + ((super).base,) (1,),α36''), test2 ~> TypedNuFun(1,fun test2 = (this).base,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -146,11 +146,11 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() {fun test = ...},this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (x,) => '(' + ((super).base,) (x,), x, (super).misc, ')',(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -189,11 +189,11 @@ mixin WrapBase { fun wrap(x) = x } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() {fun wrapA = ...; fun wrap = ...},this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x: int,) => x : int,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = (x,) => x,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -206,11 +206,11 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() {fun wrapA = ...; fun wrap = ...},this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x,) => '(' (super).wrapA (x,), ')',(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index b338673216..a1c2bc4b34 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -23,6 +23,29 @@ let add11 = Add(Lit(1), Lit(2)) //│ 'a :> Add & {Add#E = 'E} //│ 'E :> Lit +fun eval(e) = + if e is + // Lit(n) then n: int + Add(l, r) then eval(l) + eval(r) +//│ ╔══[ERROR] Type mismatch in expression: +//│ ╟── reference of type `anything` is not an instance of type `Add` +//│ ║ l.27: if e is +//│ ║ ^ +//│ ╟── but it flows into type parameter with expected type `Add` +//│ ║ l.6: class Add(lhs: E, rhs: E) +//│ ╙── ^ +//│ +//│ fun eval: 'a -> 'b +//│ where +//│ 'b :> int +//│ <: 'c & 'd +//│ 'd := int +//│ 'c := int +//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) +//│ <: Add +//│ 'rhs :> anything +//│ 'lhs :> anything + mixin EvalBase { fun eval(e) = @@ -30,12 +53,12 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this39',super40',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α42'' -> (Int | α65'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this53',super54',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α56'' -> (Int | α75'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -44,6 +67,12 @@ mixin EvalBase { module TestLang: EvalBase +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.69: module TestLang: EvalBase +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── reference of type `anything` does not match type `Add | Lit` +//│ ║ l.52: if e is +//│ ╙── ^ //│ //│ namespace TestLang() { //│ this: 'this @@ -52,16 +81,9 @@ module TestLang: EvalBase //│ where //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Lit & 'c | Add & 'd & ~Lit -//│ 'rhs :> 'rhs0 -//│ 'lhs :> 'lhs0 -//│ 'lhs0 <: Lit & 'c | Add & 'd & ~Lit -//│ 'd <: {rhs: 'rhs1} & {lhs: 'lhs1} -//│ 'lhs1 <: 'lhs0 -//│ 'rhs1 <: 'rhs0 -//│ 'rhs0 <: Lit & 'c | Add & 'd & ~Lit -//│ 'c <: {n: 'n} -//│ 'n <: int +//│ <: Lit | Add & ~Lit +//│ 'rhs :> anything +//│ 'lhs :> anything //│ 'this :> TestLang TestLang.eval @@ -71,19 +93,10 @@ TestLang.eval //│ 'eval :> 'a -> (int | 'b) //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Lit & 'c | Add & 'd & ~Lit -//│ 'rhs :> 'rhs0 -//│ 'lhs :> 'lhs0 -//│ 'lhs0 <: Lit & 'c | Add & 'd & ~Lit -//│ 'd <: {rhs: 'rhs1} & {lhs: 'lhs1} -//│ 'lhs1 <: 'lhs0 -//│ 'rhs1 <: 'rhs0 -//│ 'rhs0 <: Lit & 'c | Add & 'd & ~Lit -//│ 'c <: {n: 'n} -//│ 'n <: int -//│ Typed: 'rhs -> int -//│ where -//│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} +//│ <: Lit | Add & ~Lit +//│ 'rhs :> anything +//│ 'lhs :> anything +//│ Typed: (Add | Lit) -> int TestLang.eval(add11) //│ @@ -110,20 +123,6 @@ let add2negadd11 = Add(Lit(2), Neg(add11)) //│ 'E :> Neg & {Neg#A = 'A} | Lit //│ 'A :> Add & {Add#E = 'E0} //│ 'E0 :> Lit -//│ <: 'lhs & 'rhs -//│ 'lhs :> Lit -//│ <: 'lhs0 -//│ 'lhs0 :> Lit -//│ <: Lit & 'b | Add & 'c & ~Lit -//│ 'c :> Add & {Add#E = 'E0} -//│ <: {rhs: 'rhs} & {lhs: 'lhs} -//│ 'rhs :> Lit -//│ <: 'rhs0 -//│ 'rhs0 :> Lit -//│ <: Lit & 'b | Add & 'c & ~Lit -//│ 'b :> Lit -//│ <: {n: 'n} -//│ 'n := int mixin EvalNeg { @@ -131,12 +130,12 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this151',super152',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α154'' -> (α165'' | α169'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this120',super121',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α123'' -> (α132'' | α136'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -145,6 +144,16 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.146: module TestLang: EvalBase, EvalNeg +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `~Neg` does not match type `Add | Lit` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.52: if e is +//│ ║ ^ +//│ ╟── from wildcard pattern: +//│ ║ l.131: else super.eval(e) +//│ ╙── ^^^^^^^^^^^^^ //│ //│ namespace TestLang() { //│ this: 'this @@ -158,23 +167,16 @@ module TestLang: EvalBase, EvalNeg //│ 'e := int //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) -//│ <: Neg & 'f | 'g & ~Neg -//│ 'expr :> 'expr0 -//│ 'rhs :> 'rhs0 -//│ 'lhs :> 'lhs0 -//│ 'lhs0 <: Neg & 'f | 'g & ~Neg -//│ 'f <: {expr: 'expr1} -//│ 'expr1 <: 'expr0 -//│ 'expr0 <: Neg & 'f | 'g & ~Neg -//│ 'g <: 'h -//│ 'h <: 'i -//│ 'i <: Lit & 'j | Add & 'k & ~Lit -//│ 'k <: {rhs: 'rhs1} & {lhs: 'lhs1} -//│ 'lhs1 <: 'lhs0 -//│ 'rhs1 <: 'rhs0 -//│ 'rhs0 <: Neg & 'f | 'g & ~Neg -//│ 'j <: {n: 'n} -//│ 'n <: int +//│ <: Neg | 'f & ~Neg +//│ 'f :> ~Neg +//│ <: 'g +//│ 'g :> ~Neg +//│ <: 'h +//│ 'h :> ~Neg +//│ <: Lit | Add & ~Lit +//│ 'expr :> anything +//│ 'rhs :> anything +//│ 'lhs :> anything //│ 'this :> TestLang TestLang.eval @@ -189,26 +191,17 @@ TestLang.eval //│ 'e := int //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) -//│ <: Neg & 'f | 'g & ~Neg -//│ 'expr :> 'expr0 -//│ 'rhs :> 'rhs0 -//│ 'lhs :> 'lhs0 -//│ 'lhs0 <: Neg & 'f | 'g & ~Neg -//│ 'f <: {expr: 'expr1} -//│ 'expr1 <: 'expr0 -//│ 'expr0 <: Neg & 'f | 'g & ~Neg -//│ 'g <: 'h -//│ 'h <: 'i -//│ 'i <: Lit & 'j | Add & 'k & ~Lit -//│ 'k <: {rhs: 'rhs1} & {lhs: 'lhs1} -//│ 'lhs1 <: 'lhs0 -//│ 'rhs1 <: 'rhs0 -//│ 'rhs0 <: Neg & 'f | 'g & ~Neg -//│ 'j <: {n: 'n} -//│ 'n <: int -//│ Typed: 'rhs -> int -//│ where -//│ 'rhs <: Add & {lhs: 'rhs, rhs: 'rhs} | Lit & {n: int} | Neg & {expr: 'rhs} +//│ <: Neg | 'f & ~Neg +//│ 'f :> ~Neg +//│ <: 'g +//│ 'g :> ~Neg +//│ <: 'h +//│ 'h :> ~Neg +//│ <: Lit | Add & ~Lit +//│ 'expr :> anything +//│ 'rhs :> anything +//│ 'lhs :> anything +//│ Typed: (Add | Lit | Neg) -> int TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 9f9ed5e194..3987b185e1 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -125,16 +125,15 @@ if opt is Some then opt.value else 0 //│ //│ 'value | 0 //│ where -//│ 'value :> 123 -//│ Typed: 0 | 123 +//│ 'value :> anything +//│ Typed: anything if opt is Some(v) then v else 0 //│ //│ (forall 'value. 'value) | 0 //│ where -//│ 'value :> 'value0 -//│ 'value0 :> 123 -//│ Typed: 0 | 123 +//│ 'value :> anything +//│ Typed: anything fun map(x, f) = if x is @@ -146,15 +145,20 @@ fun map(x, f) = if x is //│ 'c :> Some & {Some#A = 'A} //│ 'b <: (forall 'value. 'value) -> 'd //│ 'd <: 'A -//│ 'value :> 'value0 -//│ 'a <: None & 'e | Some & 'f & ~None -//│ 'f <: {value: 'value0} +//│ 'value :> anything +//│ 'a <: None | Some & ~None let mo = map(opt, succ) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.151: let mo = map(opt, succ) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── reference of type `anything` is not an instance of type `int` +//│ ║ l.139: fun map(x, f) = if x is +//│ ╙── ^ //│ //│ let mo: 'a //│ where -//│ 'a :> None | 'b +//│ 'a :> None | 'b | error //│ 'b :> Some & {Some#A :> 'A <: 'A0} //│ 'A0 :> 'A | int @@ -162,10 +166,10 @@ mo.toArray //│ //│ 'toArray //│ where -//│ 'toArray :> ('A,) | () +//│ 'toArray :> error | ('A,) | () //│ 'A := in 'A0 out 'A1 //│ 'A1 :> 'A0 | int -//│ Typed: Array[int] +//│ Typed: Array[int] | error @@ -194,16 +198,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.195: Test(true) +//│ ║ l.199: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.195: Test(true) +//│ ║ l.199: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.173: fun foo = n + 1 +//│ ║ l.177: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.172: class Test(n) { +//│ ║ l.176: class Test(n) { //│ ╙── ^ //│ //│ 'a @@ -217,13 +221,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.217: fun foo = n + 1 +//│ ║ l.221: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.217: fun foo = n + 1 +//│ ║ l.221: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.216: class Test(n: A) { +//│ ║ l.220: class Test(n: A) { //│ ╙── ^ //│ //│ class Test[A](n: A) { @@ -345,13 +349,13 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.345: fun foo2(x: A) = x + 1 +//│ ║ l.349: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.345: fun foo2(x: A) = x + 1 +//│ ║ l.349: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.343: class Test { +//│ ║ l.347: class Test { //│ ╙── ^ //│ //│ class Test[A]() { diff --git a/shared/src/test/diff/nu/New.mls b/shared/src/test/diff/nu/New.mls index bcddd0e045..da9c3c08ff 100644 --- a/shared/src/test/diff/nu/New.mls +++ b/shared/src/test/diff/nu/New.mls @@ -19,7 +19,16 @@ if f is Foo then 1 else 0 //│ = 1 if f is Foo(a) then a else 0 -//│ res: 0 | 1 +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.21: if f is Foo(a) then a else 0 +//│ ║ ^ +//│ ╟── class pattern of type `Foo` does not have field 'x' +//│ ║ l.21: if f is Foo(a) then a else 0 +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `{x: ?x}` +//│ ║ l.21: if f is Foo(a) then a else 0 +//│ ╙── ^ +//│ res: 0 | error //│ = 1 // case f of @@ -33,11 +42,20 @@ if f is Foo(a) then a else 0 fun test(x) = if x is Foo(a) then a -//│ test: (Foo & {x: 'x}) -> 'x +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.44: fun test(x) = if x is Foo(a) then a +//│ ║ ^ +//│ ╟── class pattern of type `Foo` does not have field 'x' +//│ ║ l.44: fun test(x) = if x is Foo(a) then a +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `{x: ?x}` +//│ ║ l.44: fun test(x) = if x is Foo(a) then a +//│ ╙── ^ +//│ test: Foo -> error //│ = [Function: test] test(f) -//│ res: 1 +//│ res: error //│ = 1 class Point(x, y) diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 8bfa754f49..687eca4e40 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -7,11 +7,11 @@ mixin Over { fun p = "hi" } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() {fun p = ...},this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = "hi","hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1207) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1235) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1226) -//│ at: mlscript.Typer.expandType(Typer.scala:1322) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) +//│ at: mlscript.Typer.expandType(Typer.scala:1325) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) From b17bc7073fe6067e72a41b0f3a8956d0706bbc5f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 23:47:40 +0800 Subject: [PATCH 050/498] WIPIP use fresh tparams in match patterns --- .../scala/mlscript/ConstraintSolver.scala | 162 +++++++-------- shared/src/main/scala/mlscript/TypeDefs.scala | 4 + shared/src/main/scala/mlscript/Typer.scala | 42 +++- shared/src/test/diff/nu/BasicMixins.mls | 40 ++-- shared/src/test/diff/nu/ECOOP23.mls | 191 +++++++++++------- shared/src/test/diff/nu/GenericClasses.mls | 52 ++--- shared/src/test/diff/nu/ParamOverriding.mls | 8 +- 7 files changed, 286 insertions(+), 213 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index c9d322e519..d81020773a 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -22,6 +22,87 @@ class ConstraintSolver extends NormalForms { self: Typer => protected var currentConstrainingRun = 0 + + // def lookupNuTypeDef(clsNme: Str, rfnt: Map[Var, FieldType]) + def lookupNuTypeDef(clsNme: Str, rfnt: Var => Opt[FieldType]) + // (implicit raise: Raise, cctx: ConCtx, ctx: Ctx, shadows: Shadows) + (implicit ctx: Ctx, raise: Raise) + : TypedNuCls = { + val info = ctx.tyDefs2(clsNme) + + // Option.when(info.isComputing) { + // ??? + // }.getOrElse + { info.complete() match { + case td: TypedNuCls => + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + // freshened ++= td.tparams.map(tp => tp._2 -> TopType) + + // /* + td.tparams.foreach { case (tn, _tv) => + // val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) + val targ = rfnt(Var(td.nme.name + "#" + tn.name)) match { + case S(fty) => + TypeBounds( + fty.lb.getOrElse(BotType), + fty.ub, + )(_tv.prov) + case N => + // FIXME type bounds are kind of wrong for this + TypeBounds( + _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + _tv.upperBounds.foldLeft(TopType: ST)(_ & _), + )(_tv.prov) + } + // println(s"Assigning ${_tv} ~> $tv := $targ where ${ + // targ.ub.showBounds}${targ.showBounds}") + // // targ.ub.showBounds}${targ.lb.fold("")(_.showBounds)}") + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) // TODO safe not to set original?! + println(s"Set ${_tv} ~> $tv") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + freshened += _tv -> tv + } + // */ + /* + td.tparams.foreach { case (tn, tv) => + assert(tv.assignedTo.isEmpty) + val targ = rfnt.get(Var(td.nme.name + "#" + tn.name)) match { + case S(fty) => + TypeBounds( + fty.lb.getOrElse(BotType), + fty.ub, + )(tv.prov) + case N => + // FIXME type bounds are kind of wrong for this + TypeBounds( + tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + tv.upperBounds.foldLeft(TopType: ST)(_ & _), + )(tv.prov) + } + println(s"Type param $tv := ${targ}") + freshened += tv -> targ + } + */ + + // println(td) + // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] + val res = + // td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] + td.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] + // println(res) + // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) + res + case _ => ??? + }} + } + + type ShadowSet = Set[ST -> ST] case class Shadows(current: ShadowSet, previous: ShadowSet) { def size: Int = current.size + previous.size @@ -362,7 +443,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case (LhsRefined(S(f: FunctionType), ts, r, trs), RhsBases(pts, _, _)) => annoying(Nil, LhsRefined(N, ts, r, trs), Nil, done_rs) case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if nme.isCapitalized => - val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap), fldNme) + val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) // ??? @@ -413,83 +494,6 @@ class ConstraintSolver extends NormalForms { self: Typer => } }() - def lookupNuTypeDef(clsNme: Str, rfnt: Map[Var, FieldType]) - // (implicit raise: Raise, cctx: ConCtx, ctx: Ctx, shadows: Shadows) - (implicit ctx: Ctx) - : TypedNuCls = { - val info = ctx.tyDefs2(clsNme) - - // Option.when(info.isComputing) { - // ??? - // }.getOrElse - { info.complete() match { - case td: TypedNuCls => - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - // freshened ++= td.tparams.map(tp => tp._2 -> TopType) - - // /* - td.tparams.foreach { case (tn, _tv) => - // val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) - val targ = rfnt.get(Var(td.nme.name + "#" + tn.name)) match { - case S(fty) => - TypeBounds( - fty.lb.getOrElse(BotType), - fty.ub, - )(_tv.prov) - case N => - // FIXME type bounds are kind of wrong for this - TypeBounds( - _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), - _tv.upperBounds.foldLeft(TopType: ST)(_ & _), - )(_tv.prov) - } - // println(s"Assigning ${_tv} ~> $tv := $targ where ${ - // targ.ub.showBounds}${targ.showBounds}") - // // targ.ub.showBounds}${targ.lb.fold("")(_.showBounds)}") - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) // TODO safe not to set original?! - println(s"Set ${_tv} ~> $tv") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - freshened += _tv -> tv - } - // */ - /* - td.tparams.foreach { case (tn, tv) => - assert(tv.assignedTo.isEmpty) - val targ = rfnt.get(Var(td.nme.name + "#" + tn.name)) match { - case S(fty) => - TypeBounds( - fty.lb.getOrElse(BotType), - fty.ub, - )(tv.prov) - case N => - // FIXME type bounds are kind of wrong for this - TypeBounds( - tv.lowerBounds.foldLeft(BotType: ST)(_ | _), - tv.upperBounds.foldLeft(TopType: ST)(_ & _), - )(tv.prov) - } - println(s"Type param $tv := ${targ}") - freshened += tv -> targ - } - */ - - // println(td) - // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] - val res = - // td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] - td.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] - // println(res) - // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) - res - case _ => ??? - }} - } def lookupNuTypeDefField(cls: TypedNuCls, fld: Var): FieldType = { // println(fld.name, cls.members) // println(s"Looking up $fld in ${cls.td.nme}") @@ -664,7 +668,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => rt.fields.foreach { case (fldNme, fldTy) => - val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, Map.empty), fldNme) + val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, _ => N), fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) } diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 7cc56984ad..034694a87d 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -110,6 +110,10 @@ class TypeDefs extends NuTypeDefs { self: Typer => def tparamField(clsNme: TypeName, tparamNme: TypeName): Var = Var(clsNme.name + "#" + tparamNme.name) + def clsNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { + require((td.kind is Cls) || (td.kind is Nms), td.kind) + ClassTag(Var(td.nme.name), ctx.allBaseClassesOf(td.nme.name))(prov) + } def clsNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { require(td.kind is Cls) ClassTag(Var(td.nme.name.decapitalize), ctx.allBaseClassesOf(td.nme.name))(prov) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 5e6eee24cc..9e3b20e94c 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1056,7 +1056,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) (fv -> TopType :: Nil) -> typeTerm(b) } case Case(pat, bod, rest) => - val patTy = pat match { + val (tagTy: ST, patTy: ST) = pat match { case lit: Lit => ClassTag(lit, lit.baseClasses)(tp(pat.toLoc, "literal pattern")) case v @ Var(nme) => @@ -1069,16 +1069,36 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val e = ClassTag(ErrTypeId, Set.empty)(tpr) return ((e -> e) :: Nil) -> e case S(td) => - ClassTag(v, - Set.empty//TODO - )(provTODO) + // ClassTag(v, + // Set.empty//TODO + // )(provTODO) + // td.complete() match { + // case cls: TypedNuCls => + // // lookupNuTypeDef(cls.td.nme.name, v => ???) + // clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) + // } + val cls = lookupNuTypeDef(nme, { v => + val fv = freshVar(provTODO, N, S(v.name.replaceAll("#", "_"))) + println(v, fv) + S(FieldType(S(fv), fv)(provTODO)) + }) + val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) + // val ty = tag & + val ty = + // RecordType.mk(cls.params)(provTODO) // TODO?! + RecordType.mk(cls.tparams.map{ + case (tn, tv) => + (Var(nme+"#"+tn.name).withLocOf(tn), FieldType(S(tv), tv)(provTODO)) + })(provTODO) + println(s"Match arm $nme : $ty") + tag -> ty } case Some(td) => td.kind match { - case Als => err(msg"can only match on classes and traits", pat.toLoc)(raise) - case Nms => err(msg"can only match on classes and traits", pat.toLoc)(raise) - case Cls => clsNameToNomTag(td)(tp(pat.toLoc, "class pattern"), ctx) - case Trt => trtNameToNomTag(td)(tp(pat.toLoc, "trait pattern"), ctx) + case Als => val t = err(msg"can only match on classes and traits", pat.toLoc)(raise); t -> t + case Nms => val t = err(msg"can only match on classes and traits", pat.toLoc)(raise); t -> t + case Cls => val t = clsNameToNomTag(td)(tp(pat.toLoc, "class pattern"), ctx); t -> t + case Trt => val t = trtNameToNomTag(td)(tp(pat.toLoc, "trait pattern"), ctx); t -> t } } } @@ -1091,12 +1111,12 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // newCtx += v.name -> VarSymbol(tv, v) // val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) // (patTy -> tv, bod_ty, typeArms(scrutVar, rest)) - newCtx += v.name -> VarSymbol(patTy, v) + newCtx += v.name -> VarSymbol(tagTy & patTy, v) val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) - (patTy -> patTy, bod_ty, typeArms(scrutVar, rest)) + (tagTy -> patTy, bod_ty, typeArms(scrutVar, rest)) case N => val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) - (patTy -> TopType, bod_ty, typeArms(scrutVar, rest)) + (tagTy -> TopType, bod_ty, typeArms(scrutVar, rest)) } (req_ty :: tys) -> (bod_ty | rest_ty) } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 7d623f9b87..3a68982c85 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -8,11 +8,11 @@ mixin BaseTest { fun test = super.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() {fun test = ...},this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (super).base,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -24,11 +24,11 @@ mixin BaseInc { fun test2 = this.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() {fun test = ...; fun test2 = ...},this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = + ((super).base,) (1,),α36''), test2 ~> TypedNuFun(1,fun test2 = (this).base,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -146,11 +146,11 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() {fun test = ...},this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (x,) => '(' + ((super).base,) (x,), x, (super).misc, ')',(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -189,11 +189,11 @@ mixin WrapBase { fun wrap(x) = x } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() {fun wrapA = ...; fun wrap = ...},this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x: int,) => x : int,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = (x,) => x,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -206,11 +206,11 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() {fun wrapA = ...; fun wrap = ...},this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x,) => '(' (super).wrapA (x,), ')',(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index a1c2bc4b34..0ce63ec948 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -27,13 +27,6 @@ fun eval(e) = if e is // Lit(n) then n: int Add(l, r) then eval(l) + eval(r) -//│ ╔══[ERROR] Type mismatch in expression: -//│ ╟── reference of type `anything` is not an instance of type `Add` -//│ ║ l.27: if e is -//│ ║ ^ -//│ ╟── but it flows into type parameter with expected type `Add` -//│ ║ l.6: class Add(lhs: E, rhs: E) -//│ ╙── ^ //│ //│ fun eval: 'a -> 'b //│ where @@ -42,9 +35,21 @@ fun eval(e) = //│ 'd := int //│ 'c := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Add -//│ 'rhs :> anything -//│ 'lhs :> anything +//│ <: Add & {Add#E = 'E} +//│ 'E := 'Add_E +//│ 'rhs :> 'Add_E +//│ 'lhs :> 'Add_E +//│ 'Add_E :> 'Add_E0 | 'Add_E1 +//│ <: {Add#E :> 'E0 <: 'E1} & 'Add_E2 & {Add#E :> 'E2 <: 'E3} & 'Add_E3 & Add +//│ 'Add_E0 <: {Add#E :> 'E0 <: 'E1} & 'Add_E2 & {Add#E :> 'E2 <: 'E3} & 'Add_E3 & Add +//│ 'E0 :> 'Add_E2 +//│ 'Add_E2 :> 'Add_E1 +//│ <: 'Add_E0 +//│ 'Add_E1 <: {Add#E :> 'E0 <: 'E1} & 'Add_E0 & {Add#E :> 'E2 <: 'E3} & 'Add_E3 & Add +//│ 'E3 <: 'E2 & 'Add_E1 +//│ 'E2 :> 'Add_E3 +//│ 'Add_E3 <: 'Add_E1 +//│ 'E1 <: 'E0 & 'Add_E0 mixin EvalBase { @@ -53,12 +58,12 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this53',super54',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α56'' -> (Int | α75'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this68',super69',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α71'' -> (Int | α98'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -67,12 +72,6 @@ mixin EvalBase { module TestLang: EvalBase -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.69: module TestLang: EvalBase -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── reference of type `anything` does not match type `Add | Lit` -//│ ║ l.52: if e is -//│ ╙── ^ //│ //│ namespace TestLang() { //│ this: 'this @@ -81,9 +80,13 @@ module TestLang: EvalBase //│ where //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Lit | Add & ~Lit -//│ 'rhs :> anything -//│ 'lhs :> anything +//│ <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'rhs :> 'Add_E +//│ 'lhs :> 'Add_E0 +//│ 'Add_E0 <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E := 'Add_E1 +//│ 'Add_E1 <: 'Add_E & 'Add_E0 +//│ 'Add_E <: Lit | Add & {Add#E = 'E} & ~Lit //│ 'this :> TestLang TestLang.eval @@ -93,10 +96,24 @@ TestLang.eval //│ 'eval :> 'a -> (int | 'b) //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Lit | Add & ~Lit -//│ 'rhs :> anything -//│ 'lhs :> anything -//│ Typed: (Add | Lit) -> int +//│ <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'rhs :> 'Add_E +//│ 'lhs :> 'Add_E0 +//│ 'Add_E0 <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E := 'Add_E1 +//│ 'Add_E1 <: 'Add_E & 'Add_E0 +//│ 'Add_E <: Lit | Add & {Add#E = 'E} & ~Lit +//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Should not be replacing an invariant type variable by its bound... +//│ at: mlscript.utils.package$.lastWords(package.scala:203) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$70(TypeSimplifier.scala:819) +//│ at: scala.Option.fold(Option.scala:263) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:829) +//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) +//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:886) +//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) +//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:886) TestLang.eval(add11) //│ @@ -123,6 +140,14 @@ let add2negadd11 = Add(Lit(2), Neg(add11)) //│ 'E :> Neg & {Neg#A = 'A} | Lit //│ 'A :> Add & {Add#E = 'E0} //│ 'E0 :> Lit +//│ <: 'Add_E +//│ 'Add_E :> Lit +//│ <: 'E0 & 'Add_E0 & 'Add_E1 +//│ 'Add_E1 :> Lit +//│ <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ 'Add_E0 :> Lit +//│ <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ 'E1 := 'Add_E mixin EvalNeg { @@ -130,12 +155,12 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this120',super121',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α123'' -> (α132'' | α136'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this168',super169',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α171'' -> (α185'' | α189'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -144,16 +169,6 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.146: module TestLang: EvalBase, EvalNeg -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `~Neg` does not match type `Add | Lit` -//│ ╟── Note: constraint arises from reference: -//│ ║ l.52: if e is -//│ ║ ^ -//│ ╟── from wildcard pattern: -//│ ║ l.131: else super.eval(e) -//│ ╙── ^^^^^^^^^^^^^ //│ //│ namespace TestLang() { //│ this: 'this @@ -167,16 +182,20 @@ module TestLang: EvalBase, EvalNeg //│ 'e := int //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) -//│ <: Neg | 'f & ~Neg -//│ 'f :> ~Neg -//│ <: 'g -//│ 'g :> ~Neg -//│ <: 'h -//│ 'h :> ~Neg -//│ <: Lit | Add & ~Lit -//│ 'expr :> anything -//│ 'rhs :> anything -//│ 'lhs :> anything +//│ <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'expr :> 'Neg_A +//│ 'rhs :> 'Add_E +//│ 'lhs :> 'Add_E0 +//│ 'Add_E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'A := 'Neg_A0 +//│ 'Neg_A0 <: 'Neg_A +//│ 'Neg_A <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'f <: 'g +//│ 'g <: 'h +//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E := 'Add_E1 +//│ 'Add_E1 <: 'Add_E & 'Add_E0 +//│ 'Add_E <: Neg & {Neg#A = 'A} | 'f & ~Neg //│ 'this :> TestLang TestLang.eval @@ -191,17 +210,31 @@ TestLang.eval //│ 'e := int //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) -//│ <: Neg | 'f & ~Neg -//│ 'f :> ~Neg -//│ <: 'g -//│ 'g :> ~Neg -//│ <: 'h -//│ 'h :> ~Neg -//│ <: Lit | Add & ~Lit -//│ 'expr :> anything -//│ 'rhs :> anything -//│ 'lhs :> anything -//│ Typed: (Add | Lit | Neg) -> int +//│ <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'expr :> 'Neg_A +//│ 'rhs :> 'Add_E +//│ 'lhs :> 'Add_E0 +//│ 'Add_E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'A := 'Neg_A0 +//│ 'Neg_A0 <: 'Neg_A +//│ 'Neg_A <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'f <: 'g +//│ 'g <: 'h +//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E := 'Add_E1 +//│ 'Add_E1 <: 'Add_E & 'Add_E0 +//│ 'Add_E <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Should not be replacing an invariant type variable by its bound... +//│ at: mlscript.utils.package$.lastWords(package.scala:203) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$70(TypeSimplifier.scala:819) +//│ at: scala.Option.fold(Option.scala:263) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:829) +//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) +//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:886) +//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) +//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) +//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:814) TestLang.eval(add11) @@ -258,29 +291,39 @@ TestLang.eval(Neg(Neg(add11))) TestLang.eval(add2negadd11) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.293: TestLang.eval(add2negadd11) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` +//│ ║ l.135: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.57: if e is +//│ ║ ^ +//│ ╟── Note: type parameter E is defined at: +//│ ║ l.6: class Add(lhs: E, rhs: E) +//│ ╙── ^ //│ //│ 'a //│ where -//│ 'a :> 'b | 'c +//│ 'a :> 'b | 'c | error //│ 'c :> 'd //│ <: int //│ 'd :> int | 'e //│ <: int //│ 'e := int //│ 'b := int -//│ Typed: int +//│ Typed: error | int TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: ?a -> ?b` exceeded recursion depth limit (250) +//│ ║ l.318: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. //│ //│ 'a //│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int -//│ Typed: int +//│ 'a :> error +//│ Typed: error diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 3987b185e1..cf4c0f2c9f 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -125,15 +125,22 @@ if opt is Some then opt.value else 0 //│ //│ 'value | 0 //│ where -//│ 'value :> anything -//│ Typed: anything +//│ 'value :> 123 +//│ Typed: 0 | 123 if opt is Some(v) then v else 0 //│ //│ (forall 'value. 'value) | 0 //│ where -//│ 'value :> anything -//│ Typed: anything +//│ 'value :> 'Some_A +//│ 'Some_A :> 123 +//│ <: 'A +//│ 'A :> 123 +//│ <: 'Some_A & 'Some_A0 +//│ 'Some_A0 :> 123 +//│ <: 'A & 'value0 +//│ 'value0 :> 123 +//│ Typed: 0 | 123 fun map(x, f) = if x is @@ -145,20 +152,15 @@ fun map(x, f) = if x is //│ 'c :> Some & {Some#A = 'A} //│ 'b <: (forall 'value. 'value) -> 'd //│ 'd <: 'A -//│ 'value :> anything -//│ 'a <: None | Some & ~None +//│ 'value :> 'Some_A +//│ 'a <: None | Some & {Some#A = 'A0} & ~None +//│ 'A0 := 'Some_A let mo = map(opt, succ) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.151: let mo = map(opt, succ) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── reference of type `anything` is not an instance of type `int` -//│ ║ l.139: fun map(x, f) = if x is -//│ ╙── ^ //│ //│ let mo: 'a //│ where -//│ 'a :> None | 'b | error +//│ 'a :> None | 'b //│ 'b :> Some & {Some#A :> 'A <: 'A0} //│ 'A0 :> 'A | int @@ -166,10 +168,10 @@ mo.toArray //│ //│ 'toArray //│ where -//│ 'toArray :> error | ('A,) | () +//│ 'toArray :> ('A,) | () //│ 'A := in 'A0 out 'A1 //│ 'A1 :> 'A0 | int -//│ Typed: Array[int] | error +//│ Typed: Array[int] @@ -198,16 +200,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.199: Test(true) +//│ ║ l.201: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.199: Test(true) +//│ ║ l.201: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.177: fun foo = n + 1 +//│ ║ l.179: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.176: class Test(n) { +//│ ║ l.178: class Test(n) { //│ ╙── ^ //│ //│ 'a @@ -221,13 +223,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.221: fun foo = n + 1 +//│ ║ l.223: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.221: fun foo = n + 1 +//│ ║ l.223: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.220: class Test(n: A) { +//│ ║ l.222: class Test(n: A) { //│ ╙── ^ //│ //│ class Test[A](n: A) { @@ -349,13 +351,13 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.349: fun foo2(x: A) = x + 1 +//│ ║ l.351: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.349: fun foo2(x: A) = x + 1 +//│ ║ l.351: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.347: class Test { +//│ ║ l.349: class Test { //│ ╙── ^ //│ //│ class Test[A]() { diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 687eca4e40..828abfd1d1 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -7,11 +7,11 @@ mixin Over { fun p = "hi" } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() {fun p = ...},this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = "hi","hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1210) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1238) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1229) -//│ at: mlscript.Typer.expandType(Typer.scala:1325) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) +//│ at: mlscript.Typer.expandType(Typer.scala:1345) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) From 5e73bb70777392fd7d0b5bcc539b352b33351370 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Feb 2023 23:56:32 +0800 Subject: [PATCH 051/498] WIPIP simplif --- shared/src/main/scala/mlscript/Typer.scala | 61 ++++--- shared/src/test/diff/nu/BasicMixins.mls | 40 ++--- shared/src/test/diff/nu/ECOOP23.mls | 190 +++++++++----------- shared/src/test/diff/nu/GenericClasses.mls | 35 ++-- shared/src/test/diff/nu/ParamOverriding.mls | 8 +- 5 files changed, 169 insertions(+), 165 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 9e3b20e94c..50869fd3d7 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1072,26 +1072,47 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // ClassTag(v, // Set.empty//TODO // )(provTODO) - // td.complete() match { - // case cls: TypedNuCls => - // // lookupNuTypeDef(cls.td.nme.name, v => ???) - // clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) - // } - val cls = lookupNuTypeDef(nme, { v => - val fv = freshVar(provTODO, N, S(v.name.replaceAll("#", "_"))) - println(v, fv) - S(FieldType(S(fv), fv)(provTODO)) - }) - val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) - // val ty = tag & - val ty = - // RecordType.mk(cls.params)(provTODO) // TODO?! - RecordType.mk(cls.tparams.map{ - case (tn, tv) => - (Var(nme+"#"+tn.name).withLocOf(tn), FieldType(S(tv), tv)(provTODO)) - })(provTODO) - println(s"Match arm $nme : $ty") - tag -> ty + td.complete() match { + case cls: TypedNuCls => + // lookupNuTypeDef(cls.td.nme.name, v => ???) + + val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) + + val fresh_cls = { + implicit val freshened: MutMap[TV, ST] = MutMap.empty + // cls.tparams.foreach { case (tn, tv) => + // val fv = freshVar(provTODO, N, S(v.name.replaceAll("#", "_"))) + // freshened += tv -> fv + // } + implicit val shadows: Shadows = Shadows.empty + cls.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] + } + + val ty = + // RecordType.mk(cls.params)(provTODO) // TODO?! + RecordType.mk(fresh_cls.tparams.map{ + case (tn, tv) => + (Var(nme+"#"+tn.name).withLocOf(tn), FieldType(S(tv), tv)(provTODO)) + })(provTODO) + println(s"Match arm $nme: $tag & $ty") + tag -> ty + + } + // val cls = lookupNuTypeDef(nme, { v => + // val fv = freshVar(provTODO, N, S(v.name.replaceAll("#", "_"))) + // println(v, fv) + // S(FieldType(S(fv), fv)(provTODO)) + // }) + // val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) + // // val ty = tag & + // val ty = + // // RecordType.mk(cls.params)(provTODO) // TODO?! + // RecordType.mk(cls.tparams.map{ + // case (tn, tv) => + // (Var(nme+"#"+tn.name).withLocOf(tn), FieldType(S(tv), tv)(provTODO)) + // })(provTODO) + // println(s"Match arm $nme : $ty") + // tag -> ty } case Some(td) => td.kind match { diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 3a68982c85..90501a6083 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -8,11 +8,11 @@ mixin BaseTest { fun test = super.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() {fun test = ...},this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (super).base,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -24,11 +24,11 @@ mixin BaseInc { fun test2 = this.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() {fun test = ...; fun test2 = ...},this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = + ((super).base,) (1,),α36''), test2 ~> TypedNuFun(1,fun test2 = (this).base,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -146,11 +146,11 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() {fun test = ...},this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (x,) => '(' + ((super).base,) (x,), x, (super).misc, ')',(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -189,11 +189,11 @@ mixin WrapBase { fun wrap(x) = x } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() {fun wrapA = ...; fun wrap = ...},this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x: int,) => x : int,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = (x,) => x,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -206,11 +206,11 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() {fun wrapA = ...; fun wrap = ...},this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x,) => '(' (super).wrapA (x,), ')',(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 0ce63ec948..7dd21b7db2 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -25,31 +25,21 @@ let add11 = Add(Lit(1), Lit(2)) fun eval(e) = if e is - // Lit(n) then n: int + Lit(n) then n: int Add(l, r) then eval(l) + eval(r) //│ -//│ fun eval: 'a -> 'b +//│ fun eval: 'a -> (int | 'b) //│ where -//│ 'b :> int -//│ <: 'c & 'd -//│ 'd := int -//│ 'c := int +//│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Add & {Add#E = 'E} -//│ 'E := 'Add_E -//│ 'rhs :> 'Add_E -//│ 'lhs :> 'Add_E -//│ 'Add_E :> 'Add_E0 | 'Add_E1 -//│ <: {Add#E :> 'E0 <: 'E1} & 'Add_E2 & {Add#E :> 'E2 <: 'E3} & 'Add_E3 & Add -//│ 'Add_E0 <: {Add#E :> 'E0 <: 'E1} & 'Add_E2 & {Add#E :> 'E2 <: 'E3} & 'Add_E3 & Add -//│ 'E0 :> 'Add_E2 -//│ 'Add_E2 :> 'Add_E1 -//│ <: 'Add_E0 -//│ 'Add_E1 <: {Add#E :> 'E0 <: 'E1} & 'Add_E0 & {Add#E :> 'E2 <: 'E3} & 'Add_E3 & Add -//│ 'E3 <: 'E2 & 'Add_E1 -//│ 'E2 :> 'Add_E3 -//│ 'Add_E3 <: 'Add_E1 -//│ 'E1 <: 'E0 & 'Add_E0 +//│ <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'rhs :> 'E +//│ 'lhs :> 'E +//│ 'E :> 'E0 | 'E1 +//│ <: (Lit | Add & {Add#E :> 'E2 <: 'E0} & ~Lit) & 'E2 & (Lit | Add & {Add#E :> 'E3 <: 'E1} & ~Lit) & 'E3 +//│ 'E0 <: (Lit | Add & {Add#E :> 'E2 <: 'E0} & ~Lit) & 'E2 & (Lit | Add & {Add#E :> 'E3 <: 'E1} & ~Lit) & 'E3 +//│ 'E2 :> 'E1 +//│ 'E1 <: (Lit | Add & {Add#E :> 'E2 <: 'E0} & ~Lit) & (Lit | Add & {Add#E :> 'E3 <: 'E1} & ~Lit) & 'E3 mixin EvalBase { @@ -58,12 +48,12 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this68',super69',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α71'' -> (Int | α98'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this63',super64',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α66'' -> (Int | α92'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -81,12 +71,11 @@ module TestLang: EvalBase //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) //│ <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'rhs :> 'Add_E -//│ 'lhs :> 'Add_E0 -//│ 'Add_E0 <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E := 'Add_E1 -//│ 'Add_E1 <: 'Add_E & 'Add_E0 -//│ 'Add_E <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'rhs :> 'E0 +//│ 'lhs :> 'E1 +//│ 'E1 <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'E0 & 'E1 +//│ 'E0 <: Lit | Add & {Add#E = 'E} & ~Lit //│ 'this :> TestLang TestLang.eval @@ -97,23 +86,15 @@ TestLang.eval //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) //│ <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'rhs :> 'Add_E -//│ 'lhs :> 'Add_E0 -//│ 'Add_E0 <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E := 'Add_E1 -//│ 'Add_E1 <: 'Add_E & 'Add_E0 -//│ 'Add_E <: Lit | Add & {Add#E = 'E} & ~Lit -//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Should not be replacing an invariant type variable by its bound... -//│ at: mlscript.utils.package$.lastWords(package.scala:203) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$70(TypeSimplifier.scala:819) -//│ at: scala.Option.fold(Option.scala:263) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:829) -//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) -//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:886) -//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) -//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:886) +//│ 'rhs :> 'E0 +//│ 'lhs :> 'E1 +//│ 'E1 <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'E0 & 'E1 +//│ 'E0 <: Lit | Add & {Add#E = 'E} & ~Lit +//│ Typed: 'E -> int +//│ where +//│ 'E <: Add & {Add#E = 'E0} | Lit +//│ 'E0 <: 'E TestLang.eval(add11) //│ @@ -140,14 +121,13 @@ let add2negadd11 = Add(Lit(2), Neg(add11)) //│ 'E :> Neg & {Neg#A = 'A} | Lit //│ 'A :> Add & {Add#E = 'E0} //│ 'E0 :> Lit -//│ <: 'Add_E -//│ 'Add_E :> Lit -//│ <: 'E0 & 'Add_E0 & 'Add_E1 -//│ 'Add_E1 :> Lit -//│ <: Lit | Add & {Add#E = 'E1} & ~Lit -//│ 'Add_E0 :> Lit -//│ <: Lit | Add & {Add#E = 'E1} & ~Lit -//│ 'E1 := 'Add_E +//│ <: 'E1 +//│ 'E1 :> Lit +//│ <: 'E0 & 'E2 & 'E3 +//│ 'E3 :> Lit +//│ <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ 'E2 :> Lit +//│ <: Lit | Add & {Add#E = 'E1} & ~Lit mixin EvalNeg { @@ -155,12 +135,12 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this168',super169',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α171'' -> (α185'' | α189'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this161',super162',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α164'' -> (α177'' | α181'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) @@ -183,19 +163,17 @@ module TestLang: EvalBase, EvalNeg //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) //│ <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'expr :> 'Neg_A -//│ 'rhs :> 'Add_E -//│ 'lhs :> 'Add_E0 -//│ 'Add_E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'A := 'Neg_A0 -//│ 'Neg_A0 <: 'Neg_A -//│ 'Neg_A <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'expr :> 'A0 +//│ 'rhs :> 'E +//│ 'lhs :> 'E0 +//│ 'E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'A <: 'A0 +//│ 'A0 <: Neg & {Neg#A = 'A} | 'f & ~Neg //│ 'f <: 'g //│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E := 'Add_E1 -//│ 'Add_E1 <: 'Add_E & 'Add_E0 -//│ 'Add_E <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'h <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ 'E1 <: 'E & 'E0 +//│ 'E <: Neg & {Neg#A = 'A} | 'f & ~Neg //│ 'this :> TestLang TestLang.eval @@ -211,30 +189,22 @@ TestLang.eval //│ 'b := int //│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) //│ <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'expr :> 'Neg_A -//│ 'rhs :> 'Add_E -//│ 'lhs :> 'Add_E0 -//│ 'Add_E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'A := 'Neg_A0 -//│ 'Neg_A0 <: 'Neg_A -//│ 'Neg_A <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'expr :> 'A0 +//│ 'rhs :> 'E +//│ 'lhs :> 'E0 +//│ 'E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'A <: 'A0 +//│ 'A0 <: Neg & {Neg#A = 'A} | 'f & ~Neg //│ 'f <: 'g //│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E := 'Add_E1 -//│ 'Add_E1 <: 'Add_E & 'Add_E0 -//│ 'Add_E <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Should not be replacing an invariant type variable by its bound... -//│ at: mlscript.utils.package$.lastWords(package.scala:203) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$70(TypeSimplifier.scala:819) -//│ at: scala.Option.fold(Option.scala:263) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:829) -//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) -//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:886) -//│ at: mlscript.TyperHelpers.trace(TyperHelpers.scala:32) -//│ at: mlscript.TypeSimplifier.transform$1(TypeSimplifier.scala:923) -//│ at: mlscript.TypeSimplifier.$anonfun$simplifyType$56(TypeSimplifier.scala:814) +//│ 'h <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ 'E1 <: 'E & 'E0 +//│ 'E <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ Typed: 'E -> int +//│ where +//│ 'E <: Add & {Add#E = 'E0} | Lit | Neg & {Neg#A = 'A} +//│ 'A <: 'E +//│ 'E0 <: 'E TestLang.eval(add11) @@ -292,13 +262,13 @@ TestLang.eval(Neg(Neg(add11))) TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.293: TestLang.eval(add2negadd11) +//│ ║ l.263: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.135: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.116: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.57: if e is +//│ ║ l.47: if e is //│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) @@ -316,14 +286,28 @@ TestLang.eval(add2negadd11) //│ Typed: error | int TestLang.eval(Add(Lit(2), Neg(add11))) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: ?a -> ?b` exceeded recursion depth limit (250) -//│ ║ l.318: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.288: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. +//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` +//│ ║ l.116: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.47: if e is +//│ ║ ^ +//│ ╟── Note: type parameter E is defined at: +//│ ║ l.6: class Add(lhs: E, rhs: E) +//│ ╙── ^ //│ //│ 'a //│ where -//│ 'a :> error -//│ Typed: error +//│ 'a :> 'b | 'c | error +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ Typed: error | int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index cf4c0f2c9f..4fd02607fe 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -132,13 +132,13 @@ if opt is Some(v) then v else 0 //│ //│ (forall 'value. 'value) | 0 //│ where -//│ 'value :> 'Some_A -//│ 'Some_A :> 123 -//│ <: 'A +//│ 'value :> 'A //│ 'A :> 123 -//│ <: 'Some_A & 'Some_A0 -//│ 'Some_A0 :> 123 -//│ <: 'A & 'value0 +//│ <: 'A0 +//│ 'A0 :> 123 +//│ <: 'A & 'A1 +//│ 'A1 :> 123 +//│ <: 'A0 & 'value0 //│ 'value0 :> 123 //│ Typed: 0 | 123 @@ -152,9 +152,8 @@ fun map(x, f) = if x is //│ 'c :> Some & {Some#A = 'A} //│ 'b <: (forall 'value. 'value) -> 'd //│ 'd <: 'A -//│ 'value :> 'Some_A +//│ 'value :> 'A0 //│ 'a <: None | Some & {Some#A = 'A0} & ~None -//│ 'A0 := 'Some_A let mo = map(opt, succ) //│ @@ -200,16 +199,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.201: Test(true) +//│ ║ l.200: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.201: Test(true) +//│ ║ l.200: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.179: fun foo = n + 1 +//│ ║ l.178: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.178: class Test(n) { +//│ ║ l.177: class Test(n) { //│ ╙── ^ //│ //│ 'a @@ -223,13 +222,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.223: fun foo = n + 1 +//│ ║ l.222: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.223: fun foo = n + 1 +//│ ║ l.222: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.222: class Test(n: A) { +//│ ║ l.221: class Test(n: A) { //│ ╙── ^ //│ //│ class Test[A](n: A) { @@ -351,13 +350,13 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.351: fun foo2(x: A) = x + 1 +//│ ║ l.350: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.351: fun foo2(x: A) = x + 1 +//│ ║ l.350: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.349: class Test { +//│ ║ l.348: class Test { //│ ╙── ^ //│ //│ class Test[A]() { diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 828abfd1d1..9fa9b4ea45 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -7,11 +7,11 @@ mixin Over { fun p = "hi" } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() {fun p = ...},this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = "hi","hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1230) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1258) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1249) -//│ at: mlscript.Typer.expandType(Typer.scala:1345) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) +//│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) //│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) From adc4162b2f15d20608597c1d6c4cba3ef6ed140a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 00:10:37 +0800 Subject: [PATCH 052/498] WIPIP constrain things at the correct level --- .../main/scala/mlscript/TyperDatatypes.scala | 7 +++-- shared/src/test/diff/nu/BasicMixins.mls | 10 +++---- shared/src/test/diff/nu/ECOOP23.mls | 30 ++++++++----------- shared/src/test/diff/nu/ParamOverriding.mls | 2 +- .../src/test/scala/mlscript/DiffTests.scala | 7 +++-- 5 files changed, 29 insertions(+), 27 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index ba87a42aeb..180c29647f 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -116,8 +116,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => TypedNuFun(ctx.lvl, fd, body_ty) } } - // subsume(res_ty, tv) - constrain(res_ty.ty, tv) + // // subsume(res_ty, tv) + // constrain(res_ty.ty, tv) + ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.ty, tv) } res_ty case td: NuTypeDef => td.kind match { @@ -194,6 +195,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => println(s"Fresh $mxn") + // FIXME constraining level?! constrain(superType, mxn.superTV) constrain(finalType, mxn.thisTV) @@ -235,6 +237,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => + // FIXME constraining level?! constrain(superType, finalType) members } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 90501a6083..a8089a3ca8 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -14,7 +14,7 @@ mixin BaseTest { //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -30,7 +30,7 @@ mixin BaseInc { //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -152,7 +152,7 @@ mixin Foo { //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -195,7 +195,7 @@ mixin WrapBase { //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -212,7 +212,7 @@ mixin Wrap { //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 7dd21b7db2..b21f73e6c0 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -35,11 +35,7 @@ fun eval(e) = //│ <: Lit | Add & {Add#E = 'E} & ~Lit //│ 'rhs :> 'E //│ 'lhs :> 'E -//│ 'E :> 'E0 | 'E1 -//│ <: (Lit | Add & {Add#E :> 'E2 <: 'E0} & ~Lit) & 'E2 & (Lit | Add & {Add#E :> 'E3 <: 'E1} & ~Lit) & 'E3 -//│ 'E0 <: (Lit | Add & {Add#E :> 'E2 <: 'E0} & ~Lit) & 'E2 & (Lit | Add & {Add#E :> 'E3 <: 'E1} & ~Lit) & 'E3 -//│ 'E2 :> 'E1 -//│ 'E1 <: (Lit | Add & {Add#E :> 'E2 <: 'E0} & ~Lit) & (Lit | Add & {Add#E :> 'E3 <: 'E1} & ~Lit) & 'E3 +//│ 'E <: Lit | Add & {Add#E = 'E} & ~Lit mixin EvalBase { @@ -48,14 +44,14 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this63',super64',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α66'' -> (Int | α92'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this59',super60',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α62'' -> (Int | α88'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) //│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -135,14 +131,14 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this161',super162',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α164'' -> (α177'' | α181'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this157',super158',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α160'' -> (α173'' | α177'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) //│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -262,14 +258,14 @@ TestLang.eval(Neg(Neg(add11))) TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.263: TestLang.eval(add2negadd11) +//│ ║ l.523: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.116: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.376: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.47: if e is -//│ ║ ^ +//│ ║ l.307: if e is +//│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) //│ ╙── ^ @@ -287,14 +283,14 @@ TestLang.eval(add2negadd11) TestLang.eval(Add(Lit(2), Neg(add11))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.288: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ║ l.548: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.116: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.376: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.47: if e is -//│ ║ ^ +//│ ║ l.307: if e is +//│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) //│ ╙── ^ diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 9fa9b4ea45..7a9c80b248 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -13,7 +13,7 @@ mixin Over { //│ at: mlscript.Typer.goLike$1(Typer.scala:1270) //│ at: mlscript.Typer.expandType(Typer.scala:1366) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:943) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 7a1f147ad6..3ebad3949a 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -503,7 +503,6 @@ class DiffTests val exp = typer.expandType(tpd)(ctx) // output(exp.toString) - output(exp.show) // val sctx = ShowCtx.mk(tpd) @@ -536,8 +535,12 @@ class DiffTests .indentNewLines(indStr+"|")}") } } - if (mode.explainErrors) + if (mode.dbg || mode.explainErrors) { + output("======== TYPED ========") showTTU(tpd, 0) + } + + output(exp.show) // val exp = getType(typer.PolymorphicType(0, res_ty)) // output(s"Typed: ${exp}") From 34cd5cf4d84794ccad4a45b523b189d2e86d386c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 01:09:19 +0800 Subject: [PATCH 053/498] WIPIP bad state of ecoop... --- shared/src/main/scala/mlscript/Typer.scala | 16 +- .../main/scala/mlscript/TyperDatatypes.scala | 6 +- shared/src/test/diff/nu/BasicMixins.mls | 50 +-- shared/src/test/diff/nu/ECOOP23.mls | 184 ++++---- shared/src/test/diff/nu/ECOOP23_min.mls | 89 ++++ shared/src/test/diff/nu/ECOOP23_repro.mls | 399 ++++++++++++++++++ shared/src/test/diff/nu/GenericClasses.mls | 35 +- shared/src/test/diff/nu/ParamOverriding.mls | 10 +- .../src/test/scala/mlscript/DiffTests.scala | 6 +- 9 files changed, 642 insertions(+), 153 deletions(-) create mode 100644 shared/src/test/diff/nu/ECOOP23_min.mls create mode 100644 shared/src/test/diff/nu/ECOOP23_repro.mls diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 50869fd3d7..0804f5c5e3 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -950,10 +950,18 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case _ => mthCallOrSel(obj, fieldName) } case Let(isrec, nme, rhs, bod) => - val n_ty = typeLetRhs(isrec, nme.name, rhs) - val newCtx = ctx.nest - newCtx += nme.name -> VarSymbol(n_ty, nme) - typeTerm(bod)(newCtx, raise, vars, genLambdas) + if (newDefs) { + if (isrec) ??? + val rhs_ty = typeTerm(rhs) + val newCtx = ctx.nest + newCtx += nme.name -> VarSymbol(rhs_ty, nme) + typeTerm(bod)(newCtx, raise, vars, genLambdas) + } else { + val n_ty = typeLetRhs(isrec, nme.name, rhs) + val newCtx = ctx.nest + newCtx += nme.name -> VarSymbol(n_ty, nme) + typeTerm(bod)(newCtx, raise, vars, genLambdas) + } // case Blk(s :: stmts) => // val (newCtx, ty) = typeStatement(s) // typeTerm(Blk(stmts))(newCtx, lvl, raise) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 180c29647f..c215bad044 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -195,7 +195,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => println(s"Fresh $mxn") - // FIXME constraining level?! + assert(finalType.level === lvl) + assert(mxn.superTV.level === lvl) + assert(mxn.thisTV.level === lvl) constrain(superType, mxn.superTV) constrain(finalType, mxn.thisTV) @@ -237,7 +239,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => - // FIXME constraining level?! + assert(finalType.level === lvl) constrain(superType, finalType) members } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index a8089a3ca8..bfabe53824 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -8,13 +8,13 @@ mixin BaseTest { fun test = super.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() {fun test = ...},this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (super).base,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -24,13 +24,13 @@ mixin BaseInc { fun test2 = this.base } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() {fun test = ...; fun test2 = ...},this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = + ((super).base,) (1,),α36''), test2 ~> TypedNuFun(1,fun test2 = (this).base,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -146,13 +146,13 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() {fun test = ...},this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (x,) => '(' + ((super).base,) (x,), x, (super).misc, ')',(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -189,13 +189,13 @@ mixin WrapBase { fun wrap(x) = x } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() {fun wrapA = ...; fun wrap = ...},this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x: int,) => x : int,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = (x,) => x,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -206,13 +206,13 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() {fun wrapA = ...; fun wrap = ...},this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x,) => '(' (super).wrapA (x,), ')',(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index b21f73e6c0..e87f3ba3aa 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -16,26 +16,28 @@ class Lit(n: int) //│ 'this0 :> Lit //│ 'this :> Add -let add11 = Add(Lit(1), Lit(2)) +fun add11 = Add(Lit(1), Lit(2)) //│ -//│ let add11: 'a +//│ fun add11: 'a //│ where //│ 'a :> Add & {Add#E = 'E} +//│ <: 'add11 +//│ 'add11 :> Add & {Add#E = 'E} //│ 'E :> Lit fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n Add(l, r) then eval(l) + eval(r) //│ -//│ fun eval: 'a -> (int | 'b) +//│ fun eval: 'a -> ('n | 'b) //│ where //│ 'b := int -//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'rhs :> 'E -//│ 'lhs :> 'E -//│ 'E <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'n := int +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'a +//│ 'rhs <: 'a mixin EvalBase { @@ -44,14 +46,14 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this59',super60',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α62'' -> (Int | α88'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this56',super57',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α59'' -> (Int | α82'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -65,13 +67,12 @@ module TestLang: EvalBase //│ } //│ where //│ 'b := int -//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'rhs :> 'E0 -//│ 'lhs :> 'E1 -//│ 'E1 <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'E0 & 'E1 -//│ 'E0 <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a //│ 'this :> TestLang TestLang.eval @@ -80,17 +81,16 @@ TestLang.eval //│ where //│ 'eval :> 'a -> (int | 'b) //│ 'b := int -//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) -//│ <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'rhs :> 'E0 -//│ 'lhs :> 'E1 -//│ 'E1 <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'E0 & 'E1 -//│ 'E0 <: Lit | Add & {Add#E = 'E} & ~Lit -//│ Typed: 'E -> int +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ Typed: 'a -> int //│ where -//│ 'E <: Add & {Add#E = 'E0} | Lit -//│ 'E0 <: 'E +//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'E <: 'a TestLang.eval(add11) //│ @@ -115,15 +115,25 @@ let add2negadd11 = Add(Lit(2), Neg(add11)) //│ where //│ 'a :> Add & {Add#E = 'E} //│ 'E :> Neg & {Neg#A = 'A} | Lit -//│ 'A :> Add & {Add#E = 'E0} -//│ 'E0 :> Lit -//│ <: 'E1 -//│ 'E1 :> Lit -//│ <: 'E0 & 'E2 & 'E3 -//│ 'E3 :> Lit -//│ <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ 'A :> Add & {Add#E :> 'E0 <: 'E1} +//│ 'E1 :> 'E0 | 'E2 | Lit +//│ 'E0 <: 'E3 +//│ 'E3 :> 'E2 | Lit +//│ <: 'E4 //│ 'E2 :> Lit -//│ <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ <: 'E4 +//│ 'E4 :> Lit +//│ <: 'E2 & 'rhs & 'lhs +//│ 'lhs :> Lit +//│ <: 'lhs0 +//│ 'lhs0 :> Lit +//│ <: 'b +//│ 'rhs :> Lit +//│ <: 'rhs0 +//│ 'rhs0 :> Lit +//│ <: 'b +//│ 'b :> Lit | Add & {Add#E :> 'E2 <: 'E3} +//│ <: Lit | Add & {Add#E = 'E4} & ~Lit mixin EvalNeg { @@ -131,14 +141,14 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this157',super158',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α160'' -> (α173'' | α177'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this156',super157',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α159'' -> (α171'' | α175'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -157,19 +167,18 @@ module TestLang: EvalBase, EvalNeg //│ <: int //│ 'e := int //│ 'b := int -//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) -//│ <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'expr :> 'A0 -//│ 'rhs :> 'E -//│ 'lhs :> 'E0 -//│ 'E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'A <: 'A0 -//│ 'A0 <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg //│ 'f <: 'g //│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E1} & ~Lit -//│ 'E1 <: 'E & 'E0 -//│ 'E <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ 'A <: 'expr +//│ 'expr <: 'expr0 +//│ 'expr0 <: 'a //│ 'this :> TestLang TestLang.eval @@ -183,24 +192,23 @@ TestLang.eval //│ <: int //│ 'e := int //│ 'b := int -//│ 'a :> (forall 'lhs. 'lhs) | (forall 'rhs. 'rhs) | (forall 'expr. 'expr) -//│ <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'expr :> 'A0 -//│ 'rhs :> 'E -//│ 'lhs :> 'E0 -//│ 'E0 <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'A <: 'A0 -//│ 'A0 <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg //│ 'f <: 'g //│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E1} & ~Lit -//│ 'E1 <: 'E & 'E0 -//│ 'E <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ Typed: 'E -> int +//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ 'A <: 'expr +//│ 'expr <: 'expr0 +//│ 'expr0 <: 'a +//│ Typed: 'a -> int //│ where -//│ 'E <: Add & {Add#E = 'E0} | Lit | Neg & {Neg#A = 'A} -//│ 'A <: 'E -//│ 'E0 <: 'E +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'A <: 'a +//│ 'E <: 'a TestLang.eval(add11) @@ -258,14 +266,14 @@ TestLang.eval(Neg(Neg(add11))) TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.523: TestLang.eval(add2negadd11) +//│ ║ l.267: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.376: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.112: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.307: if e is -//│ ║ ^ +//│ ║ l.45: if e is +//│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) //│ ╙── ^ @@ -282,28 +290,14 @@ TestLang.eval(add2negadd11) //│ Typed: error | int TestLang.eval(Add(Lit(2), Neg(add11))) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.548: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: ?a -> ?b` exceeded recursion depth limit (250) +//│ ║ l.292: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.376: let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ ║ ^^^^^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.307: if e is -//│ ║ ^ -//│ ╟── Note: type parameter E is defined at: -//│ ║ l.6: class Add(lhs: E, rhs: E) -//│ ╙── ^ +//│ ╙── Note: use flag `:ex` to see internal error info. //│ //│ 'a //│ where -//│ 'a :> 'b | 'c | error -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int -//│ Typed: error | int +//│ 'a :> error +//│ Typed: error diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls new file mode 100644 index 0000000000..ae80bf1216 --- /dev/null +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -0,0 +1,89 @@ +:NewParser +:NewDefs +:NoJS + + +class Add(lhs: E, rhs: E) +// class Lit(n: int) +//│ +//│ class Add[E](lhs: E, rhs: E) { +//│ this: 'this +//│ } +//│ where +//│ 'this :> Add + +let e = Add(1, 1) +//│ +//│ let e: 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> 1 + +:d +e +//│ 0. Typing TypingUnit(List(e)) +//│ | 0. Typing term e +//│ | 0. : α29 +//│ ======== TYPED ======== +//│ res: Some(α29) where +//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) +//│ E23_30 :> 1 +//│ +//│ 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> 1 +//│ ⬤ Typed as: ‹∀ 0. α29› +//│ where: +//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) +//│ E23_30 :> 1 +//│ Typed: Add & {Add#E = 'E} +//│ where +//│ 'E :> 1 + +e.lhs +//│ +//│ 'lhs +//│ where +//│ 'lhs :> 1 +//│ Typed: 1 + +:d +e +//│ 0. Typing TypingUnit(List(e)) +//│ | 0. Typing term e +//│ | 0. : α29 +//│ ======== TYPED ======== +//│ res: Some(α29) where +//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) <: {lhs: lhs35} +//│ E23_30 :> 1 <: lhs35 +//│ lhs35 :> 1 +//│ +//│ 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ <: {lhs: 'lhs} +//│ 'E :> 1 +//│ <: 'lhs +//│ 'lhs :> 1 +//│ ⬤ Typed as: ‹∀ 0. α29› +//│ where: +//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) <: {lhs: lhs35} +//│ E23_30 :> 1 <: lhs35 +//│ lhs35 :> 1 +//│ Typed: Add & {Add#E = 'E} +//│ where +//│ 'E :> 1 + + +Add(2, 2) +//│ +//│ 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> 2 +//│ Typed: Add & {Add#E = 'E} +//│ where +//│ 'E :> 2 + + diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls new file mode 100644 index 0000000000..d2119ba16f --- /dev/null +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -0,0 +1,399 @@ +:NewParser +:NewDefs +:NoJS + + +class Add(lhs: E, rhs: E) +class Lit(n: int) +//│ +//│ class Add[E](lhs: E, rhs: E) { +//│ this: 'this +//│ } +//│ class Lit(n: int) { +//│ this: 'this0 +//│ } +//│ where +//│ 'this0 :> Lit +//│ 'this :> Add + +let add11 = Add(Lit(1), Lit(2)) +//│ +//│ let add11: 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> Lit + +fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then eval(l) + eval(r) +//│ +//│ fun eval: 'a -> (int | 'b) +//│ where +//│ 'b := int +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'a +//│ 'rhs <: 'a + + +mixin EvalBase { + fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then this.eval(l) + this.eval(r) +} +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this56',super57',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α59'' -> (Int | α82'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) + + +module TestLang: EvalBase +//│ +//│ namespace TestLang() { +//│ this: 'this +//│ fun eval: 'a -> (int | 'b) +//│ } +//│ where +//│ 'b := int +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ 'this :> TestLang + +TestLang.eval +//│ +//│ 'eval +//│ where +//│ 'eval :> 'a -> (int | 'b) +//│ 'b := int +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ Typed: 'a -> int +//│ where +//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'E <: 'a + + + +add11 +//│ +//│ 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> Lit +//│ Typed: Add & {Add#E = 'E} +//│ where +//│ 'E :> Lit + +TestLang.eval(add11) +//│ +//│ 'a +//│ where +//│ 'a :> int | 'b +//│ 'b := int +//│ Typed: int + +add11 +//│ +//│ 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ <: 'b +//│ 'E :> Lit +//│ <: 'E0 +//│ 'E0 :> Lit +//│ <: 'E & 'rhs & 'lhs +//│ 'lhs :> Lit +//│ <: 'lhs0 +//│ 'lhs0 :> Lit +//│ <: 'b +//│ 'rhs :> Lit +//│ <: 'rhs0 +//│ 'rhs0 :> Lit +//│ <: 'b +//│ 'b :> Lit | Add & {Add#E = 'E} +//│ <: Lit | Add & {Add#E = 'E0} & ~Lit +//│ Typed: Add & {Add#E = 'E} +//│ where +//│ 'E :> Lit +//│ <: Add & {Add#E = 'E} | Lit + +TestLang.eval(add11) +//│ +//│ 'a +//│ where +//│ 'a :> int | 'b +//│ 'b := int +//│ Typed: int + +add11 +//│ +//│ 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ <: 'b & 'c +//│ 'E :> Lit +//│ <: 'E0 & 'E1 +//│ 'E1 :> Lit +//│ <: 'E & 'rhs & 'lhs +//│ 'lhs :> Lit +//│ <: 'lhs0 +//│ 'lhs0 :> Lit +//│ <: 'c +//│ 'rhs :> Lit +//│ <: 'rhs0 +//│ 'rhs0 :> Lit +//│ <: 'c +//│ 'c :> Lit | Add & {Add#E = 'E} +//│ <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ 'E0 :> Lit +//│ <: 'E & 'rhs1 & 'lhs1 +//│ 'lhs1 :> Lit +//│ <: 'lhs2 +//│ 'lhs2 :> Lit +//│ <: 'b +//│ 'rhs1 :> Lit +//│ <: 'rhs2 +//│ 'rhs2 :> Lit +//│ <: 'b +//│ 'b :> Lit | Add & {Add#E = 'E} +//│ <: Lit | Add & {Add#E = 'E0} & ~Lit +//│ Typed: Add & {Add#E = 'E} +//│ where +//│ 'E :> Lit +//│ <: Add & {Add#E = 'E} | Lit + + + +class Neg(expr: A) +//│ +//│ class Neg[A](expr: A) { +//│ this: 'this +//│ } +//│ where +//│ 'this :> Neg + +let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ +//│ let add2negadd11: 'a +//│ where +//│ 'a :> Add & {Add#E = 'E} +//│ 'E :> Neg & {Neg#A = 'A} | Lit +//│ 'A :> Add & {Add#E = 'E0} +//│ 'E0 :> Lit +//│ <: 'E1 & 'E2 +//│ 'E2 :> Lit +//│ <: 'E0 & 'rhs & 'lhs +//│ 'lhs :> Lit +//│ <: 'lhs0 +//│ 'lhs0 :> Lit +//│ <: 'b +//│ 'rhs :> Lit +//│ <: 'rhs0 +//│ 'rhs0 :> Lit +//│ <: 'b +//│ 'b :> Lit | Add & {Add#E = 'E0} +//│ <: Lit | Add & {Add#E = 'E2} & ~Lit +//│ 'E1 :> Lit +//│ <: 'E0 & 'rhs1 & 'lhs1 +//│ 'lhs1 :> Lit +//│ <: 'lhs2 +//│ 'lhs2 :> Lit +//│ <: 'c +//│ 'rhs1 :> Lit +//│ <: 'rhs2 +//│ 'rhs2 :> Lit +//│ <: 'c +//│ 'c :> Lit | Add & {Add#E = 'E0} +//│ <: Lit | Add & {Add#E = 'E1} & ~Lit + + +mixin EvalNeg { + fun eval(e) = + if e is Neg(d) then 0 - this.eval(d) + else super.eval(e) +} +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this197',super198',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α200'' -> (α212'' | α216'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) +//│ at: scala.collection.immutable.List.map(List.scala:246) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) +//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) +//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) + + +module TestLang: EvalBase, EvalNeg +//│ +//│ namespace TestLang() { +//│ this: 'this +//│ fun eval: 'a -> ('b | 'c) +//│ } +//│ where +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'f <: 'g +//│ 'g <: 'h +//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ 'A <: 'expr +//│ 'expr <: 'expr0 +//│ 'expr0 <: 'a +//│ 'this :> TestLang + +TestLang.eval +//│ +//│ 'eval +//│ where +//│ 'eval :> 'a -> ('b | 'c) +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg +//│ 'f <: 'g +//│ 'g <: 'h +//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ 'A <: 'expr +//│ 'expr <: 'expr0 +//│ 'expr0 <: 'a +//│ Typed: 'a -> int +//│ where +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'A <: 'a +//│ 'E <: 'a + + +TestLang.eval(add11) +//│ +//│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ Typed: int + +TestLang.eval(Neg(add11)) +//│ +//│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ Typed: int + +TestLang.eval(Add(Lit(2), Neg(Lit(1)))) +//│ +//│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ Typed: int + +TestLang.eval(Neg(Neg(add11))) +//│ +//│ 'a +//│ where +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ Typed: int + + +TestLang.eval(add2negadd11) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.355: TestLang.eval(add2negadd11) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` +//│ ║ l.192: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.42: if e is +//│ ║ ^ +//│ ╟── Note: type parameter E is defined at: +//│ ║ l.6: class Add(lhs: E, rhs: E) +//│ ╙── ^ +//│ +//│ 'a +//│ where +//│ 'a :> 'b | 'c | error +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ Typed: error | int + +TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.380: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` +//│ ║ l.192: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.42: if e is +//│ ║ ^ +//│ ╟── Note: type parameter E is defined at: +//│ ║ l.6: class Add(lhs: E, rhs: E) +//│ ╙── ^ +//│ +//│ 'a +//│ where +//│ 'a :> error +//│ Typed: error + + diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 4fd02607fe..95b369f5f8 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -130,16 +130,9 @@ if opt is Some then opt.value else 0 if opt is Some(v) then v else 0 //│ -//│ (forall 'value. 'value) | 0 +//│ 'value | 0 //│ where -//│ 'value :> 'A -//│ 'A :> 123 -//│ <: 'A0 -//│ 'A0 :> 123 -//│ <: 'A & 'A1 -//│ 'A1 :> 123 -//│ <: 'A0 & 'value0 -//│ 'value0 :> 123 +//│ 'value :> 123 //│ Typed: 0 | 123 @@ -150,10 +143,10 @@ fun map(x, f) = if x is //│ fun map: ('a, 'b,) -> (None | 'c) //│ where //│ 'c :> Some & {Some#A = 'A} -//│ 'b <: (forall 'value. 'value) -> 'd +//│ 'b <: 'value -> 'd //│ 'd <: 'A -//│ 'value :> 'A0 //│ 'a <: None | Some & {Some#A = 'A0} & ~None +//│ 'A0 <: 'value let mo = map(opt, succ) //│ @@ -199,16 +192,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.200: Test(true) +//│ ║ l.193: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.200: Test(true) +//│ ║ l.193: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.178: fun foo = n + 1 +//│ ║ l.171: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.177: class Test(n) { +//│ ║ l.170: class Test(n) { //│ ╙── ^ //│ //│ 'a @@ -222,13 +215,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.222: fun foo = n + 1 +//│ ║ l.215: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.222: fun foo = n + 1 +//│ ║ l.215: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.221: class Test(n: A) { +//│ ║ l.214: class Test(n: A) { //│ ╙── ^ //│ //│ class Test[A](n: A) { @@ -350,13 +343,13 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.350: fun foo2(x: A) = x + 1 +//│ ║ l.343: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.350: fun foo2(x: A) = x + 1 +//│ ║ l.343: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.348: class Test { +//│ ║ l.341: class Test { //│ ╙── ^ //│ //│ class Test[A]() { diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 7a9c80b248..0c56cc2217 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -7,13 +7,13 @@ mixin Over { fun p = "hi" } //│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() {fun p = ...},this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = "hi","hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1251) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1279) +//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) +//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1270) -//│ at: mlscript.Typer.expandType(Typer.scala:1366) +//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) +//│ at: mlscript.Typer.expandType(Typer.scala:1374) //│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:946) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 3ebad3949a..ca80ade7c2 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -538,13 +538,17 @@ class DiffTests if (mode.dbg || mode.explainErrors) { output("======== TYPED ========") showTTU(tpd, 0) + // output("res: " + tpd.result) + tpd.result.foreach { res_ty => + output("res: " + tpd.result + " where " + res_ty.showBounds) + } } output(exp.show) // val exp = getType(typer.PolymorphicType(0, res_ty)) // output(s"Typed: ${exp}") - tpd.result.foreach { res_ty => + tpd.result.foreach { res_ty => val exp = getType(typer.PolymorphicType(0, res_ty)) output(s"Typed: ${exp.show}") } From 797ed4de854233416aadedd05d73b05b9dd6955c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 11:25:03 +0800 Subject: [PATCH 054/498] WIPIP fix top-level difftest context --- shared/src/main/scala/mlscript/helpers.scala | 12 +++- shared/src/test/diff/nu/BasicClasses.mls | 21 +++--- shared/src/test/diff/nu/BasicMixins.mls | 20 +++--- shared/src/test/diff/nu/ECOOP23.mls | 71 +++++++------------ shared/src/test/diff/nu/ECOOP23_repro.mls | 8 +-- shared/src/test/diff/nu/GenericClasses.mls | 13 ++-- shared/src/test/diff/nu/MutualRec.mls | 12 ++-- shared/src/test/diff/nu/ParamOverriding.mls | 4 +- .../src/test/scala/mlscript/DiffTests.scala | 15 +++- 9 files changed, 90 insertions(+), 86 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 7ae403dc3d..b447aa844c 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -348,10 +348,15 @@ trait DeclImpl extends Located { self: Decl => trait NuDeclImpl extends Located { self: NuDecl => val body: Located - val name: Str = self match { - case td: NuTypeDef => td.nme.name - case fd: NuFunDef => fd.nme.name + // val name: Str = self match { + // case td: NuTypeDef => td.nme.name + // case fd: NuFunDef => fd.nme.name + // } + val nameVar: Var = self match { + case td: NuTypeDef => td.nme.toVar + case fd: NuFunDef => fd.nme } + def name: Str = nameVar.name def showBody: Str = this match { case NuFunDef(_, _, _, rhs) => rhs.fold(_.toString, _.show) case td: NuTypeDef => td.body.show @@ -387,6 +392,7 @@ trait TypingUnitImpl extends Located { self: TypingUnit => trait TypeNameImpl extends Ordered[TypeName] { self: TypeName => val base: TypeName = this def compare(that: TypeName): Int = this.name compare that.name + lazy val toVar: Var = Var(name).withLocOf(this) } trait TermImpl extends StatementImpl { self: Term => diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index bc718a19bb..7ca713e62f 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -62,7 +62,8 @@ f(a) //│ //│ 'a //│ where -//│ 'a :> int +//│ 'a :> forall 'n. 'n +//│ 'n :> int //│ Typed: int fun f(x) = if x is A then x.n else 0 @@ -76,7 +77,7 @@ f(a) //│ //│ 'a //│ where -//│ 'a :> 'n | 0 +//│ 'a :> forall 'n. 'n | 0 //│ 'n :> int //│ Typed: int @@ -238,7 +239,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.239: b.getBaseTypo +//│ ║ l.240: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ //│ 'getBaseTypo @@ -258,11 +259,11 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.257: class Rec(n) { +//│ ║ l.258: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.258: fun go = Rec(n + 1) +//│ ║ l.259: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.259: } +//│ ║ l.260: } //│ ╙── ^ //│ //│ class Rec(n: 'n) { @@ -285,16 +286,16 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.284: a: int +//│ ║ l.285: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.283: class Annots(base: 0 | 1) { +//│ ║ l.284: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.284: a: int +//│ ║ l.285: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.284: a: int +//│ ║ l.285: a: int //│ ╙── ^^^ //│ //│ class Annots(base: (0 | 1,)) { diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index bfabe53824..8d8c39b1d7 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -13,8 +13,8 @@ mixin BaseTest { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -29,8 +29,8 @@ mixin BaseInc { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -151,8 +151,8 @@ mixin Foo { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -194,8 +194,8 @@ mixin WrapBase { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -211,8 +211,8 @@ mixin Wrap { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index e87f3ba3aa..d07a4c59bb 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -25,6 +25,11 @@ fun add11 = Add(Lit(1), Lit(2)) //│ 'add11 :> Add & {Add#E = 'E} //│ 'E :> Lit +// add11 + 1 + +// add11 + + fun eval(e) = if e is Lit(n) then n @@ -52,8 +57,8 @@ mixin EvalBase { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -115,25 +120,11 @@ let add2negadd11 = Add(Lit(2), Neg(add11)) //│ where //│ 'a :> Add & {Add#E = 'E} //│ 'E :> Neg & {Neg#A = 'A} | Lit -//│ 'A :> Add & {Add#E :> 'E0 <: 'E1} -//│ 'E1 :> 'E0 | 'E2 | Lit -//│ 'E0 <: 'E3 -//│ 'E3 :> 'E2 | Lit -//│ <: 'E4 -//│ 'E2 :> Lit -//│ <: 'E4 -//│ 'E4 :> Lit -//│ <: 'E2 & 'rhs & 'lhs -//│ 'lhs :> Lit -//│ <: 'lhs0 -//│ 'lhs0 :> Lit -//│ <: 'b -//│ 'rhs :> Lit -//│ <: 'rhs0 -//│ 'rhs0 :> Lit -//│ <: 'b -//│ 'b :> Lit | Add & {Add#E :> 'E2 <: 'E3} -//│ <: Lit | Add & {Add#E = 'E4} & ~Lit +//│ 'A :> forall 'b 'E0 'add11. 'b +//│ 'b :> Add & {Add#E = 'E0} +//│ <: 'add11 +//│ 'add11 :> Add & {Add#E = 'E0} +//│ 'E0 :> Lit mixin EvalNeg { @@ -141,14 +132,14 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this156',super157',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α159'' -> (α171'' | α175'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) +//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this154',super155',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α157'' -> (α169'' | α173'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) //│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) //│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -265,39 +256,31 @@ TestLang.eval(Neg(Neg(add11))) TestLang.eval(add2negadd11) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.267: TestLang.eval(add2negadd11) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.112: let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ ║ ^^^^^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.45: if e is -//│ ║ ^ -//│ ╟── Note: type parameter E is defined at: -//│ ║ l.6: class Add(lhs: E, rhs: E) -//│ ╙── ^ //│ //│ 'a //│ where -//│ 'a :> 'b | 'c | error +//│ 'a :> 'b | 'c //│ 'c :> 'd //│ <: int //│ 'd :> int | 'e //│ <: int //│ 'e := int //│ 'b := int -//│ Typed: error | int +//│ Typed: int + +// add11 TestLang.eval(Add(Lit(2), Neg(add11))) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: ?a -> ?b` exceeded recursion depth limit (250) -//│ ║ l.292: TestLang.eval(Add(Lit(2), Neg(add11))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. //│ //│ 'a //│ where -//│ 'a :> error -//│ Typed: error +//│ 'a :> 'b | 'c +//│ 'c :> 'd +//│ <: int +//│ 'd :> int | 'e +//│ <: int +//│ 'e := int +//│ 'b := int +//│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index d2119ba16f..edaec58089 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -49,8 +49,8 @@ mixin EvalBase { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) @@ -235,8 +235,8 @@ mixin EvalNeg { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 95b369f5f8..63d353ec0b 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -152,17 +152,17 @@ let mo = map(opt, succ) //│ //│ let mo: 'a //│ where -//│ 'a :> None | 'b -//│ 'b :> Some & {Some#A :> 'A <: 'A0} -//│ 'A0 :> 'A | int +//│ 'a :> forall 'b. None | 'b +//│ 'b :> Some & {Some#A = 'A} +//│ 'A :> int mo.toArray //│ //│ 'toArray //│ where //│ 'toArray :> ('A,) | () -//│ 'A := in 'A0 out 'A1 -//│ 'A1 :> 'A0 | int +//│ 'A := 'A0 +//│ 'A0 :> int //│ Typed: Array[int] @@ -454,7 +454,8 @@ foo(t) //│ //│ 'a //│ where -//│ 'a :> (x: 'A,) -> 'A +//│ 'a :> forall 'foo1. 'foo1 +//│ 'foo1 :> (x: 'A,) -> 'A //│ 'A := int //│ Typed: (x: int,) -> int diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index a322b2db59..22ffdd8102 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -63,7 +63,7 @@ fun bar = {y: foo} // FIXME pretty-printing? foo //│ -//│ {x: {y: 'foo}} +//│ forall 'foo. {x: {y: 'foo}} //│ where //│ 'foo :> {x: {y: 'foo}} //│ Typed: 'foo @@ -73,7 +73,7 @@ foo :ns foo //│ -//│ {x: {y: 'foo}} +//│ forall 'foo. {x: {y: 'foo}} //│ where //│ 'foo :> {x: {y: 'foo}} //│ Typed: forall 'foo. {x: {y: 'foo}} @@ -117,11 +117,11 @@ fun bar(b) = foo(b) :ns foo //│ -//│ 'a -> {h: 'a, t: 'b} +//│ forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} //│ where -//│ 'b :> {h: 'a, t: 'b} -//│ 'a <: 'c -//│ 'c <: 'a +//│ 'c :> {h: 'a, t: 'c} +//│ 'a <: 'b +//│ 'b <: 'a //│ Typed: forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} //│ where //│ 'c :> {h: 'a, t: 'c} diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 0c56cc2217..7e05c6d9e5 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -12,8 +12,8 @@ mixin Over { //│ at: scala.collection.immutable.List.map(List.scala:246) //│ at: mlscript.Typer.goLike$1(Typer.scala:1278) //│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:504) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:950) +//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) +//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) //│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) //│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) //│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index ca80ade7c2..d6498a2c87 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -497,10 +497,23 @@ class DiffTests // /* val vars: Map[Str, typer.SimpleType] = Map.empty - val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise, vars) + val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx.nest, raise, vars) tpd.force()(raise) + tpd.entities.foreach { e => + e.complete()(raise) match { + case tf: typer.TypedNuFun => + val sign = typer.PolymorphicType.mk(ctx.lvl, tf.ty) + ctx += tf.fd.nme.name -> typer.VarSymbol(sign, tf.fd.nme) + case tt: typer.TypedNuTypeDef => + ctx += e.decl.name -> e + // ctx += e.decl.name -> + // typer.VarSymbol(e.typeSignature(raise), e.decl.nameVar) + // case tt: typer.TypedNuMxn => + } + } + val exp = typer.expandType(tpd)(ctx) // output(exp.toString) From 2b032ca0ace19aef0bb3f4188e14dfdaad6dbf9c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 11:40:46 +0800 Subject: [PATCH 055/498] WIP add mixin expansion --- .../src/main/scala/mlscript/NewParser.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 13 ++- .../main/scala/mlscript/codegen/Helpers.scala | 4 +- shared/src/main/scala/mlscript/helpers.scala | 23 ++-- shared/src/main/scala/mlscript/syntax.scala | 1 + shared/src/test/diff/nu/BasicMixins.mls | 105 ++++++++---------- shared/src/test/diff/nu/ECOOP23.mls | 44 ++++---- shared/src/test/diff/nu/ECOOP23_repro.mls | 50 +++++---- shared/src/test/diff/nu/ParamOverriding.mls | 16 +-- 9 files changed, 125 insertions(+), 133 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index f57d819e00..17599d381d 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -292,7 +292,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } val ps = parents(if (kind === Als) KEYWORD("=") else KEYWORD(":")) val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams, params, ps, N, body) + val res = NuTypeDef(kind, tn, tparams, params, ps, N, N, body) R(res.withLoc(S(l0 ++ res.getLoc))) // TODO make `fun` by-name and `let` by-value diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 0804f5c5e3..6e6b097ed3 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -335,7 +335,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case ti: LazyTypeInfo => // ti.complete() ti.decl match { - case NuTypeDef(Cls, _, tps, _, _, _, _) => + case NuTypeDef(Cls, _, tps, _, _, _, _, _) => S(Cls, tps.size) case _ => ??? } @@ -1257,11 +1257,22 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) }) } def goDecl(d: TypedNuDecl): NuDecl = d match { + case TypedNuMxn(td, thisTV, superTV, ttu) => + NuTypeDef(td.kind, td.nme, td.tparams, + Tup(Nil), + Nil,//TODO + S(go(superTV)), + S(go(thisTV)), + mkTypingUnit(thisTV, + // members + Map.empty + )) case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => NuTypeDef(td.kind, td.nme, td.tparams, // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), Nil,//TODO + N,//TODO S(go(thisTy)), mkTypingUnit(thisTy, members)) // mkTypingUnit(() :: members.toList.sortBy(_._1))) diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 2176f94c7a..5248eacfa6 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -85,9 +85,9 @@ object Helpers { s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, ${inspect(term)})" case NuFunDef(lt, nme, targs, R(ty)) => s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, $ty)" - case NuTypeDef(kind, nme, tparams, params, parents, ths, body) => + case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => s"NuTypeDef(${kind.str}, ${nme.name}, ${tparams.mkString("(", ", ", ")")}, ${ - inspect(params)}, ${parents.map(inspect).mkString("(", ", ", ")")}, $ths, ${inspect(body)})" + inspect(params)}, ${parents.map(inspect).mkString("(", ", ", ")")}, $sup, $ths, ${inspect(body)})" case others => others.toString() } .mkString("TypingUnit(", ", ", ")") diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index b447aa844c..8e238523a4 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -117,7 +117,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case S(ty) => "\n" + ty.showIn(ctx, 0) case N => "" }) - case NuTypeDef(kind, nme, tparams, params, parents, ths, body) => + case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => s"${kind.str} ${nme.name}${tparams.map(_.showIn(ctx, 0))mkStringOr(", ", "[", "]")}(${ params.fields.map { case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) @@ -127,8 +127,9 @@ trait TypeLikeImpl extends Located { self: TypeLike => })${parents match { case Nil => "" case ps => ps.mkString(", ") // TODO pp - }}${if (body.entities.isEmpty && ths.isEmpty) "" else - " {" + ths.fold("")("\nthis: " + _.showIn(ctx, 0)) + + }}${if (body.entities.isEmpty && sup.isEmpty && ths.isEmpty) "" else + " {" + sup.fold("")("\nsuper: " + _.showIn(ctx, 0)) + + ths.fold("")("\nthis: " + _.showIn(ctx, 0)) + Signature(body.entities.collect { case d: NuDecl => d }, N).showIn(ctx, 0) + "\n}" }" } @@ -151,11 +152,11 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList - case NuTypeDef(kind, nme, tparams, params, parents, ths, body) => + case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => // TODO improve this mess tparams ::: params.fields.collect { case (_, Fld(_, _, Asc(_, ty))) => ty - } ::: ths.toList ::: Signature(body.entities.collect { + } ::: sup.toList ::: ths.toList ::: Signature(body.entities.collect { case d: NuDecl => d }, N) :: Nil // TODO parents? } @@ -368,13 +369,13 @@ trait NuDeclImpl extends Located { self: NuDecl => def showDbg: Str = showHead + (this match { case NuFunDef(_, _, _, L(_)) => " = " case NuFunDef(_, _, _, R(_)) => ": " - case NuTypeDef(_, _, _, _, _, _, _) => " " + case NuTypeDef(_, _, _, _, _, _, _, _) => " " }) + showBody def showHead: Str = this match { case NuFunDef(N, n, _, b) => s"fun $n" case NuFunDef(S(false), n, _, b) => s"let $n" case NuFunDef(S(true), n, _, b) => s"let rec $n" - case NuTypeDef(k, n, tps, sps, parents, ths, bod) => + case NuTypeDef(k, n, tps, sps, parents, sup, ths, bod) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_.name).mkString("‹", ", ", "›")}(${ // sps.mkString("(",",",")") sps})${if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" @@ -673,9 +674,9 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, ths, unit) => + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => ??? // TODO - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, ths, unit) => + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) require(pars.size === 1, pars) @@ -686,7 +687,7 @@ trait StatementImpl extends Located { self: Statement => case R(ty) => Nil -> ty } diags -> (TypeDef(k, nme, tps, rhs, Nil, Nil, Nil) :: Nil) - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, ths, unit) => + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { case L(ds) => diags += ds; Top @@ -819,7 +820,7 @@ trait StatementImpl extends Located { self: Statement => case Where(bod, wh) => bod :: wh case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil - case NuTypeDef(k, nme, tps, ps, pars, ths, bod) => + case NuTypeDef(k, nme, tps, ps, pars, sup, ths, bod) => nme :: tps ::: ps :: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 8f351cdadf..bd6f000068 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -178,6 +178,7 @@ final case class NuTypeDef( tparams: Ls[TypeName], params: Tup, // the specialized parameters for that type parents: Ls[Term], + superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit ) extends NuDecl with Statement diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 8d8c39b1d7..8233750051 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -7,33 +7,27 @@ mixin BaseTest { fun test = super.base } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseTest() {fun test = ...},this23',super24',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (super).base,base26'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin BaseTest() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'super <: {base: 'base} mixin BaseInc { fun test = super.base + 1 fun test2 = this.base } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin BaseInc() {fun test = ...; fun test2 = ...},this29',super30',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = + ((super).base,) (1,),α36''), test2 ~> TypedNuFun(1,fun test2 = (this).base,base37'')),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin BaseInc() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'this <: {base: 'base} +//│ 'super <: {base: 'base0} +//│ 'base0 <: int // :d class Base1(base: int): BaseTest, BaseInc { @@ -113,10 +107,10 @@ Base1(1).test :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.114: class Base1(x): BaseTest +//│ ║ l.108: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.114: class Base1(x): BaseTest +//│ ║ l.108: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -145,17 +139,14 @@ Base1 mixin Foo { fun test(x) = [super.base + x, x, super.misc] } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Foo() {fun test = ...},this187',super188',TypedTypingUnit(List(test ~> TypedNuFun(1,fun test = (x,) => '(' + ((super).base,) (x,), x, (super).misc, ')',(α190'' -> (α194'', α190'', misc195'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin Foo() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'super <: {misc: 'misc} & {base: 'base} +//│ 'base <: int module Base1(base: int, misc: string): Foo //│ @@ -188,34 +179,26 @@ mixin WrapBase { fun wrapA(x: int) = x : int fun wrap(x) = x } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin WrapBase() {fun wrapA = ...; fun wrap = ...},this222',super223',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x: int,) => x : int,((x: Int,) -> Int)), wrap ~> TypedNuFun(1,fun wrap = (x,) => x,(α226'' -> α226''))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin WrapBase() { +//│ super: 'super +//│ this: 'this +//│ } // :d mixin Wrap { fun wrapA(x) = [super.wrapA(x)] fun wrap(x) = [super.wrap(x)] } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Wrap() {fun wrapA = ...; fun wrap = ...},this228',super229',TypedTypingUnit(List(wrapA ~> TypedNuFun(1,fun wrapA = (x,) => '(' (super).wrapA (x,), ')',(α232'' -> (α235'',))), wrap ~> TypedNuFun(1,fun wrap = (x,) => '(' (super).wrap (x,), ')',(α238'' -> (α241'',)))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin Wrap() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'super <: {wrap: 'wrap} & {wrapA: 'wrapA} +//│ 'wrapA <: 'a -> 'b +//│ 'wrap <: 'c -> 'd @@ -302,16 +285,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.303: WrapBase1.wrapA("ok") +//│ ║ l.286: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.303: WrapBase1.wrapA("ok") +//│ ║ l.286: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.188: fun wrapA(x: int) = x : int +//│ ║ l.179: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.205: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.190: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ //│ 'a diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index d07a4c59bb..f50b3c185b 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -51,17 +51,17 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this56',super57',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α59'' -> (Int | α82'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin EvalBase() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'this <: {eval: 'eval} & {eval: 'eval0} +//│ 'eval0 <: 'lhs -> 'a +//│ 'a <: int +//│ 'eval <: 'rhs -> 'b +//│ 'b <: int module TestLang: EvalBase @@ -132,17 +132,17 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this154',super155',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α157'' -> (α169'' | α173'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin EvalNeg() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'this <: {eval: 'eval} +//│ 'eval <: 'expr -> 'a +//│ 'a <: int +//│ 'super <: {eval: 'eval0} +//│ 'eval0 <: 'b -> 'c module TestLang: EvalBase, EvalNeg diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index edaec58089..fa2022601d 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -43,17 +43,17 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalBase() {fun eval = ...},this56',super57',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if e is ‹(Lit (n,)) then n : int; (Add (l, r,)) then + ((this).eval (l,),) ((this).eval (r,),)›},(α59'' -> (Int | α82'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin EvalBase() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'this <: {eval: 'eval} & {eval: 'eval0} +//│ 'eval0 <: 'lhs -> 'a +//│ 'a <: int +//│ 'eval <: 'rhs -> 'b +//│ 'b <: int module TestLang: EvalBase @@ -229,17 +229,17 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin EvalNeg() {fun eval = ...},this197',super198',TypedTypingUnit(List(eval ~> TypedNuFun(1,fun eval = (e,) => {if (is (e,) (Neg (d,),)) then - (0,) ((this).eval (d,),) else (super).eval (e,)},(α200'' -> (α212'' | α216'')))),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin EvalNeg() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'this <: {eval: 'eval} +//│ 'eval <: 'expr -> 'a +//│ 'a <: int +//│ 'super <: {eval: 'eval0} +//│ 'eval0 <: 'b -> 'c module TestLang: EvalBase, EvalNeg @@ -352,9 +352,10 @@ TestLang.eval(Neg(Neg(add11))) //│ Typed: int +:e TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.355: TestLang.eval(add2negadd11) +//│ ║ l.356: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` //│ ║ l.192: let add2negadd11 = Add(Lit(2), Neg(add11)) @@ -377,9 +378,10 @@ TestLang.eval(add2negadd11) //│ 'b := int //│ Typed: error | int +:e TestLang.eval(Add(Lit(2), Neg(add11))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.380: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ║ l.382: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` //│ ║ l.192: let add2negadd11 = Add(Lit(2), Neg(add11)) diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 7e05c6d9e5..5ad4dbc7bb 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -6,17 +6,11 @@ mixin Over { fun p = "hi" } -//│ /!!!\ Uncaught error: scala.MatchError: TypedNuMxn(mixin Over() {fun p = ...},this23',super24',TypedTypingUnit(List(p ~> TypedNuFun(1,fun p = "hi","hi")),None)) (of class mlscript.NuTypeDefs$TypedNuMxn) -//│ at: mlscript.Typer.mlscript$Typer$$goDecl$1(Typer.scala:1259) -//│ at: mlscript.Typer.$anonfun$expandType$4(Typer.scala:1287) -//│ at: scala.collection.immutable.List.map(List.scala:246) -//│ at: mlscript.Typer.goLike$1(Typer.scala:1278) -//│ at: mlscript.Typer.expandType(Typer.scala:1374) -//│ at: mlscript.DiffTests.rec$1(DiffTests.scala:517) -//│ at: mlscript.DiffTests.$anonfun$new$3(DiffTests.scala:963) -//│ at: org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85) -//│ at: org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83) -//│ at: org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104) +//│ +//│ mixin Over() { +//│ super: 'super +//│ this: 'this +//│ } class Base1(p: int): Over { From 5042565b1f60b4615ed5ac9b4ee7842b66b96ecb Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 11:42:01 +0800 Subject: [PATCH 056/498] Fix old defs patmat --- shared/src/main/scala/mlscript/Typer.scala | 24 ++++++++++++-------- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/test/diff/nu/New.mls | 24 +++----------------- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 6e6b097ed3..58e9a1e396 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1066,7 +1066,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case Case(pat, bod, rest) => val (tagTy: ST, patTy: ST) = pat match { case lit: Lit => - ClassTag(lit, lit.baseClasses)(tp(pat.toLoc, "literal pattern")) + val t = ClassTag(lit, lit.baseClasses)(tp(pat.toLoc, "literal pattern")) + t -> t case v @ Var(nme) => val tpr = tp(pat.toLoc, "type pattern") ctx.tyDefs.get(nme) match { @@ -1134,15 +1135,18 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val newCtx = ctx.nest val (req_ty, bod_ty, (tys, rest_ty)) = scrutVar match { case S(v) => - // val tv = freshVar(tp(v.toLoc, "refined scrutinee"), N, - // // S(v.name), // this one seems a bit excessive - // ) - // newCtx += v.name -> VarSymbol(tv, v) - // val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) - // (patTy -> tv, bod_ty, typeArms(scrutVar, rest)) - newCtx += v.name -> VarSymbol(tagTy & patTy, v) - val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) - (tagTy -> patTy, bod_ty, typeArms(scrutVar, rest)) + if (newDefs) { + newCtx += v.name -> VarSymbol(tagTy & patTy, v) + val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) + (tagTy -> patTy, bod_ty, typeArms(scrutVar, rest)) + } else { + val tv = freshVar(tp(v.toLoc, "refined scrutinee"), N, + // S(v.name), // this one seems a bit excessive + ) + newCtx += v.name -> VarSymbol(tv, v) + val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) + (patTy -> tv, bod_ty, typeArms(scrutVar, rest)) + } case N => val bod_ty = typeTerm(bod)(newCtx, raise, vars, genLambdas) (tagTy -> TopType, bod_ty, typeArms(scrutVar, rest)) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 8e238523a4..97ca62095f 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -384,7 +384,7 @@ trait NuDeclImpl extends Located { self: NuDecl => trait TypingUnitImpl extends Located { self: TypingUnit => def show: Str = entities.map { case t: Term => t.toString - case d: NuDecl => d.show + case d: NuDecl => d.showDbg case _ => die }.mkString("{", "; ", "}") lazy val children: List[Located] = entities diff --git a/shared/src/test/diff/nu/New.mls b/shared/src/test/diff/nu/New.mls index da9c3c08ff..bcddd0e045 100644 --- a/shared/src/test/diff/nu/New.mls +++ b/shared/src/test/diff/nu/New.mls @@ -19,16 +19,7 @@ if f is Foo then 1 else 0 //│ = 1 if f is Foo(a) then a else 0 -//│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.21: if f is Foo(a) then a else 0 -//│ ║ ^ -//│ ╟── class pattern of type `Foo` does not have field 'x' -//│ ║ l.21: if f is Foo(a) then a else 0 -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `{x: ?x}` -//│ ║ l.21: if f is Foo(a) then a else 0 -//│ ╙── ^ -//│ res: 0 | error +//│ res: 0 | 1 //│ = 1 // case f of @@ -42,20 +33,11 @@ if f is Foo(a) then a else 0 fun test(x) = if x is Foo(a) then a -//│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.44: fun test(x) = if x is Foo(a) then a -//│ ║ ^ -//│ ╟── class pattern of type `Foo` does not have field 'x' -//│ ║ l.44: fun test(x) = if x is Foo(a) then a -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `{x: ?x}` -//│ ║ l.44: fun test(x) = if x is Foo(a) then a -//│ ╙── ^ -//│ test: Foo -> error +//│ test: (Foo & {x: 'x}) -> 'x //│ = [Function: test] test(f) -//│ res: error +//│ res: 1 //│ = 1 class Point(x, y) From 4d43d6cca7c9c64c78eafc574b548f227a72e0df Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 12:23:26 +0800 Subject: [PATCH 057/498] WIP start adapting type simplifier --- .../main/scala/mlscript/TypeSimplifier.scala | 44 +++++--- .../main/scala/mlscript/TyperDatatypes.scala | 4 +- .../main/scala/mlscript/TyperHelpers.scala | 100 ++++++++++-------- 3 files changed, 87 insertions(+), 61 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 4dd180d637..b494be5db0 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -16,8 +16,8 @@ trait TypeSimplifier { self: Typer => /** Remove bounds that are not reachable by traversing the type following variances. * Note that doing this on annotated type signatures would need to use polarity None * because a type signature can both be used (positively) and checked against (negatively). */ - def removeIrrelevantBounds(ty: SimpleType, pol: Opt[Bool] = S(true), inPlace: Bool = false) - (implicit ctx: Ctx): SimpleType = + def removeIrrelevantBounds(ty: TypeLike, pol: Opt[Bool] = S(true), inPlace: Bool = false) + (implicit ctx: Ctx): TypeLike = { val _ctx = ctx @@ -31,6 +31,9 @@ trait TypeSimplifier { self: Typer => if (inPlace) tv else freshVar(noProv, S(tv), tv.nameHint)(tv.level) tap { fv => println(s"Renewed $tv ~> $fv") }) + def processLike(ty: TypeLike): TypeLike = ty match { + case ty: ST => process(ty, N) + } def process(ty: ST, parent: Opt[Bool -> TV], canDistribForall: Opt[Level] = N): ST = // trace(s"process($ty) $canDistribForall") { ty match { @@ -126,7 +129,7 @@ trait TypeSimplifier { self: Typer => } // }(r => s"= $r") - process(ty, N) + processLike(ty) } @@ -134,7 +137,7 @@ trait TypeSimplifier { self: Typer => /** Transform the type recursively, putting everything in Disjunctive Normal Forms and reconstructing class types * from their structural components. */ - def normalizeTypes_!(st: SimpleType, pol: Opt[Bool] = S(true))(implicit ctx: Ctx): SimpleType = + def normalizeTypes_!(st: TypeLike, pol: Opt[Bool] = S(true))(implicit ctx: Ctx): TypeLike = { val _ctx = ctx @@ -341,6 +344,10 @@ trait TypeSimplifier { self: Typer => } } + def goLike(ty: TL, pol: Opt[Bool], canDistribForall: Opt[Level] = N): ST = trace(s"normLike[${printPol(pol)}] $ty") { ty match { + case ty: ST => + go(ty, pol) + }}() def go(ty: ST, pol: Opt[Bool], canDistribForall: Opt[Level] = N): ST = trace(s"norm[${printPol(pol)}] $ty") { pol match { case S(p) => helper(DNF.mk(MaxLevel, Nil, ty, p)(ctx, ptr = true, etf = false), pol, canDistribForall) @@ -363,14 +370,14 @@ trait TypeSimplifier { self: Typer => } } - go(st, pol) + goLike(st, pol) } /** Remove polar type variables, unify indistinguishable ones, and inline the bounds of non-recursive ones. */ - def simplifyType(st: SimpleType, pol: Opt[Bool] = S(true), removePolarVars: Bool = true, inlineBounds: Bool = true)(implicit ctx: Ctx): SimpleType = { + def simplifyType(st: TypeLike, pol: Opt[Bool] = S(true), removePolarVars: Bool = true, inlineBounds: Bool = true)(implicit ctx: Ctx): TypeLike = { @@ -418,7 +425,7 @@ trait TypeSimplifier { self: Typer => } }() } - Analyze1(PolMap(pol))(st) + Analyze1.applyLike(PolMap(pol))(st) println(s"[inv] ${occursInvariantly.mkString(", ")}") println(s"[nums] ${occNums.iterator @@ -493,8 +500,8 @@ trait TypeSimplifier { self: Typer => */ - def analyze2(st: SimpleType, pol: PolMap): Unit = - Analyze2(pol)(st.unwrapProvs) + def analyze2(st: TL, pol: PolMap): Unit = + Analyze2.applyLike(pol)(st.unwrapProvs) object Analyze2 extends Traverser2 { override def apply(pol: PolMap)(st: ST): Unit = trace(s"analyze2[${(pol)}] $st") { @@ -784,6 +791,9 @@ trait TypeSimplifier { self: Typer => case N => merge(pol, if (pol) tv.lowerBounds else tv.upperBounds) }, polmap.at(tv.level, pol), parents, canDistribForall) + def transformLike(ty: TL, pol: PolMap): TL = ty match { + case ty: ST => transform(ty, pol, semp) + } def transform(st: SimpleType, pol: PolMap, parents: Set[TV], canDistribForall: Opt[Level] = N): SimpleType = trace(s"transform[${printPol(pol)}] $st (${parents.mkString(", ")}) $pol $canDistribForall") { def transformField(f: FieldType): FieldType = f match { @@ -922,7 +932,7 @@ trait TypeSimplifier { self: Typer => } }(r => s"~> $r") - transform(st, PolMap(pol), semp) + transformLike(st, PolMap(pol)) } @@ -935,7 +945,7 @@ trait TypeSimplifier { self: Typer => * So if no other upper bounds end up in ?a AND ?a is polar * (so that ?a occurrences are indistinguishable from `{x: ?a}`), * we'll eventually want to refactor ?b's recursive upper bound structure into just `?b } // }(r => s"~> $r") - process(S(pol), st, N) + def processLike(pol: Opt[Bool], ty: TL): ST = ty match { + case ty: ST => process(pol, ty, N) + } + + processLike(S(pol), st) } /** Unify polar recursive type variables that have the same structure. * For example, `?a <: {x: ?a}` and `?b <: {x: ?b}` will be unified if they are bith polar. */ - def factorRecursiveTypes_!(st: SimpleType, approximateRecTypes: Bool, pol: Opt[Bool] = S(true))(implicit ctx: Ctx): SimpleType = { + def factorRecursiveTypes_!(st: TypeLike, approximateRecTypes: Bool, pol: Opt[Bool] = S(true))(implicit ctx: Ctx): TypeLike = { val allVarPols = st.getVarsPol(PolMap(pol)) println(s"allVarPols: ${printPols(allVarPols)}") @@ -1077,7 +1091,7 @@ trait TypeSimplifier { self: Typer => println(s"[subs] ${varSubst}") - if (varSubst.nonEmpty) subst(st, varSubst.toMap, substInMap = true) else st + if (varSubst.nonEmpty) substLike(st, varSubst.toMap, substInMap = true) else st } @@ -1086,7 +1100,7 @@ trait TypeSimplifier { self: Typer => abstract class SimplifyPipeline { def debugOutput(msg: => Str): Unit - def apply(st: ST)(implicit ctx: Ctx): ST = { + def apply(st: TypeLike)(implicit ctx: Ctx): TypeLike = { var cur = st cur = removeIrrelevantBounds(cur, inPlace = false) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c215bad044..bab39c8726 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -487,9 +487,11 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => body.fold(PolymorphicType(MinLevel, errType))(b => PolymorphicType(level, ProvType(b._2)(prov))) } - sealed abstract class TypeLike { + sealed abstract class TypeLike extends TypeLikeImpl { def unwrapProvs: TypeLike } + type TL = TypeLike + abstract class OtherTypeLike extends TypeLike { this: TypedTypingUnit => def self: TypedTypingUnit = this def unwrapProvs: TypeLike = this diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index fc710dfdb1..c3e47aca6a 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -79,6 +79,9 @@ abstract class TyperHelpers { Typer: Typer => def subst(ts: PolymorphicType, map: Map[SimpleType, SimpleType]): PolymorphicType = PolymorphicType(ts.polymLevel, subst(ts.body, map)) + def substLike(ty: TL, map: Map[SimpleType, SimpleType], substInMap: Bool): TL = ty match { + case ty: ST => subst(ty, map, substInMap) + } def subst(st: SimpleType, map: Map[SimpleType, SimpleType], substInMap: Bool = false) (implicit cache: MutMap[TypeVariable, SimpleType] = MutMap.empty): SimpleType = // trace(s"subst($st)") { @@ -684,6 +687,53 @@ abstract class TyperHelpers { Typer: Typer => cs.flatMap(vbs => S(true) -> vbs._1 :: S(false) -> vbs._2 :: Nil) ::: pol -> bod :: Nil }} + /** (exclusive, inclusive) */ + def varsBetween(lb: Level, ub: Level): Set[TV] = { + val res = MutSet.empty[TypeVariable] + val traversed = MutSet.empty[TypeVariable] + def go(ty: ST, lb: Level, ub: Level): Unit = + if (lb < ub && ty.level > lb) { // * Don't traverse types with lower levels + // trace(s"varsBetween($ty, $lb, $ub)") { + ty match { + case tv: TypeVariable => + if (traversed(tv)) () + else { + traversed += tv + if (tv.level > lb && tv.level <= ub) { + // println(s"ADD $tv") + res += tv + } + tv.children(includeBounds = true) // * Note: `children` deals with `assignedTo` + .foreach(go(_, lb, ub)) + } + case pt: PolymorphicType => + go(pt.body, lb, pt.polymLevel min ub) + case ty => + ty.children(includeBounds = true) // * Q: is `includeBounds` useful here? + .foreach(go(_, lb, ub)) + } + // }() + } + go(this, lb, ub) + res.toSet + } + + def expPos(implicit ctx: Ctx): mlscript.TypeLike = exp(S(true), this) + def expNeg(implicit ctx: Ctx): mlscript.TypeLike = exp(S(false), this) + def exp(pol: Opt[Bool], ty: ST)(implicit ctx: Ctx): mlscript.TypeLike = ( + ty + // |> (_.normalize(false)) + // |> (simplifyType(_, pol, removePolarVars = false, inlineBounds = false)) + // |> (shallowCopy) + |> (subst(_, Map.empty)) // * Make a copy of the type and its TV graph – although we won't show the TV bounds, we still care about the bounds as they affect class type reconstruction in normalizeTypes_! + |> (normalizeTypes_!(_, pol)(ctx)) + |> (expandType(_, stopAtTyVars = true)) + ) + + } + + trait TypeLikeImpl { self: TypeLike => + def childrenPol(pol: PolMap)(implicit ctx: Ctx): List[PolMap -> SimpleType] = { def childrenPolField(fld: FieldType): List[PolMap -> SimpleType] = fld.lb.map(pol.contravar -> _).toList ::: pol.covar -> fld.ub :: Nil @@ -715,7 +765,7 @@ abstract class TyperHelpers { Typer: Typer => def getVarsPol(pol: PolMap)(implicit ctx: Ctx): SortedMap[TypeVariable, Opt[Bool]] = { val res = MutMap.empty[TV, Pol] val traversed = MutSet.empty[TV -> Bool] - def go(pol: PolMap)(ty: ST): Unit = { + def go(pol: PolMap)(ty: TypeLike): Unit = { // trace(s"getVarsPol[${printPol(pol.base)}] $ty ${pol(1)}") { // trace(s"getVarsPol[${printPol(pol.base)}] $ty ${pol}") { ty match { @@ -776,7 +826,7 @@ abstract class TyperHelpers { Typer: Typer => def getVars: SortedSet[TypeVariable] = { val res = MutSet.empty[TypeVariable] - @tailrec def rec(queue: List[SimpleType]): Unit = queue match { + @tailrec def rec(queue: List[TypeLike]): Unit = queue match { case (tv: TypeVariable) :: tys => if (res(tv)) rec(tys) else { res += tv; rec(tv.children(includeBounds = true) ::: tys) } @@ -787,37 +837,6 @@ abstract class TyperHelpers { Typer: Typer => SortedSet.from(res)(Ordering.by(_.uid)) } - /** (exclusive, inclusive) */ - def varsBetween(lb: Level, ub: Level): Set[TV] = { - val res = MutSet.empty[TypeVariable] - val traversed = MutSet.empty[TypeVariable] - def go(ty: ST, lb: Level, ub: Level): Unit = - if (lb < ub && ty.level > lb) { // * Don't traverse types with lower levels - // trace(s"varsBetween($ty, $lb, $ub)") { - ty match { - case tv: TypeVariable => - if (traversed(tv)) () - else { - traversed += tv - if (tv.level > lb && tv.level <= ub) { - // println(s"ADD $tv") - res += tv - } - tv.children(includeBounds = true) // * Note: `children` deals with `assignedTo` - .foreach(go(_, lb, ub)) - } - case pt: PolymorphicType => - go(pt.body, lb, pt.polymLevel min ub) - case ty => - ty.children(includeBounds = true) // * Q: is `includeBounds` useful here? - .foreach(go(_, lb, ub)) - } - // }() - } - go(this, lb, ub) - res.toSet - } - def showBounds: String = getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty).map { case tv @ AssignedVariable(ty) => "\n\t\t" + tv.toString + " := " + ty @@ -826,18 +845,6 @@ abstract class TyperHelpers { Typer: Typer => + (if (tv.upperBounds.isEmpty) "" else " <: " + tv.upperBounds.mkString(" & "))) }.mkString - def expPos(implicit ctx: Ctx): mlscript.TypeLike = exp(S(true), this) - def expNeg(implicit ctx: Ctx): mlscript.TypeLike = exp(S(false), this) - def exp(pol: Opt[Bool], ty: ST)(implicit ctx: Ctx): mlscript.TypeLike = ( - ty - // |> (_.normalize(false)) - // |> (simplifyType(_, pol, removePolarVars = false, inlineBounds = false)) - // |> (shallowCopy) - |> (subst(_, Map.empty)) // * Make a copy of the type and its TV graph – although we won't show the TV bounds, we still care about the bounds as they affect class type reconstruction in normalizeTypes_! - |> (normalizeTypes_!(_, pol)(ctx)) - |> (expandType(_, stopAtTyVars = true)) - ) - } @@ -891,6 +898,9 @@ abstract class TyperHelpers { Typer: Typer => } class Traverser2(implicit ctx: Ctx) { + def applyLike(pol: PolMap)(ty: TypeLike): Unit = ty match { + case ty: ST => apply(pol)(ty) + } def apply(pol: PolMap)(st: ST): Unit = st match { case tv @ AssignedVariable(ty) => apply(pol)(ty) case tv: TypeVariable => From 7ce33140a06a2b572f92945611c4395fe8faac4d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 12:27:59 +0800 Subject: [PATCH 058/498] WIP New twist on ECOOP test --- shared/src/test/diff/nu/ECOOP23.mls | 186 ++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index f50b3c185b..cefbdc71ab 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -284,3 +284,189 @@ TestLang.eval(Add(Lit(2), Neg(add11))) //│ Typed: int +mixin EvalNegNeg { + fun eval(e) = + if e is Neg(Neg(d)) then this.eval(d) + else super.eval(e) +} +//│ +//│ mixin EvalNegNeg() { +//│ super: 'super +//│ this: 'this +//│ } +//│ where +//│ 'this <: {eval: 'eval} +//│ 'eval <: 'expr -> 'a +//│ 'super <: {eval: 'eval0} & {eval: 'eval1} +//│ 'eval1 <: (Neg & {Neg#A :> 'A <: 'A0}) -> 'b +//│ 'A0 :> 'A +//│ 'A <: 'expr0 +//│ 'expr0 <: Neg & {Neg#A :> 'A1 <: 'A2} | 'c & ~Neg +//│ 'A2 <: 'A1 & 'expr1 +//│ 'expr1 <: 'expr +//│ 'eval0 <: 'd -> 'e + +module TestLang: EvalBase, EvalNeg, EvalNegNeg +//│ +//│ namespace TestLang() { +//│ this: 'this +//│ fun eval: 'a -> ('b | 'c | 'd) +//│ } +//│ where +//│ 'b :> 'e +//│ <: int +//│ 'e :> 'b | 'c | 'd +//│ <: int +//│ 'd :> 'f +//│ <: int +//│ 'f :> 'g | 'h +//│ <: int +//│ 'c :> 'i +//│ <: int +//│ 'i :> 'g | 'h +//│ <: int +//│ 'h :> 'j +//│ <: int +//│ 'j :> int | 'k +//│ <: int +//│ 'k := int +//│ 'g := int +//│ 'a <: Neg & {Neg#A = 'A} | 'l & ~Neg +//│ 'l <: 'm +//│ 'm <: 'n +//│ 'n :> Neg & {Neg#A :> 'A0 <: 'A1} +//│ <: Neg & {Neg#A = 'A2} | 'o & ~Neg +//│ 'o <: 'p +//│ 'p <: 'q +//│ 'q <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ 'A :> 'A0 +//│ <: 'A1 & 'expr +//│ 'expr :> 'expr0 +//│ <: Neg & {Neg#A = 'A3} | 'r & ~Neg +//│ 'r :> 's +//│ 'A3 :> 'A4 +//│ <: 'A5 & 'expr1 +//│ 'expr1 :> 'expr2 +//│ <: 'expr3 +//│ 'A1 :> 'A0 +//│ <: 'A2 +//│ 'A0 <: 'A2 & 'expr0 +//│ 'expr0 <: Neg & {Neg#A :> 'A5 <: 'A4} | 's & ~Neg +//│ 'A4 <: 'A5 & 'expr2 +//│ 'expr2 <: 'expr3 +//│ 'expr3 <: 'a +//│ 'A2 <: 'A0 & 'expr4 +//│ 'expr4 <: 'expr5 +//│ 'expr5 <: 'a +//│ 'this :> TestLang + +fun mk(n) = if n is + 0 then Lit(0) + 1 then Neg(mk(n)) + _ then Add(mk(n), mk(n)) +//│ +//│ fun mk: 'a -> ('b | 'c | 'd) +//│ where +//│ 'c :> Neg & {Neg#A = 'A} +//│ 'A :> 'b | 'c | 'd +//│ 'd :> Add & {Add#E = 'E} +//│ 'E :> 'b | 'c | 'd +//│ 'b :> Lit +//│ 'a <: number + +TestLang.eval +//│ +//│ 'eval +//│ where +//│ 'eval :> 'a -> ('b | 'c | 'd) +//│ 'b :> 'e +//│ <: int +//│ 'e :> 'b | 'c | 'd +//│ <: int +//│ 'd :> 'f +//│ <: int +//│ 'f :> 'g | 'h +//│ <: int +//│ 'c :> 'i +//│ <: int +//│ 'i :> 'g | 'h +//│ <: int +//│ 'h :> 'j +//│ <: int +//│ 'j :> int | 'k +//│ <: int +//│ 'k := int +//│ 'g := int +//│ 'a <: Neg & {Neg#A = 'A} | 'l & ~Neg +//│ 'l <: 'm +//│ 'm <: 'n +//│ 'n :> Neg & {Neg#A :> 'A0 <: 'A1} +//│ <: Neg & {Neg#A = 'A2} | 'o & ~Neg +//│ 'o <: 'p +//│ 'p <: 'q +//│ 'q <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'E <: 'rhs & 'lhs +//│ 'lhs <: 'lhs0 +//│ 'lhs0 <: 'a +//│ 'rhs <: 'rhs0 +//│ 'rhs0 <: 'a +//│ 'A :> 'A0 +//│ <: 'A1 & 'expr +//│ 'expr :> 'expr0 +//│ <: Neg & {Neg#A = 'A3} | 'r & ~Neg +//│ 'r :> 's +//│ 'A3 :> 'A4 +//│ <: 'A5 & 'expr1 +//│ 'expr1 :> 'expr2 +//│ <: 'expr3 +//│ 'A1 :> 'A0 +//│ <: 'A2 +//│ 'A0 <: 'A2 & 'expr0 +//│ 'expr0 <: Neg & {Neg#A :> 'A5 <: 'A4} | 's & ~Neg +//│ 'A4 <: 'A5 & 'expr2 +//│ 'expr2 <: 'expr3 +//│ 'expr3 <: 'a +//│ 'A2 <: 'A0 & 'expr4 +//│ 'expr4 <: 'expr5 +//│ 'expr5 <: 'a +//│ Typed: 'a -> int +//│ where +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'A :> 'A0 +//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) +//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a +//│ 'A1 <: 'A2 +//│ 'A2 <: 'a +//│ 'E <: 'a + +TestLang.eval(mk(0)) +//│ +//│ 'a +//│ where +//│ 'a :> 'b | 'c | 'd +//│ 'b :> 'e +//│ <: int +//│ 'e :> 'b | 'c | 'd +//│ <: int +//│ 'd :> 'f +//│ <: int +//│ 'f :> 'g | 'h +//│ <: int +//│ 'c :> 'i +//│ <: int +//│ 'i :> 'g | 'h +//│ <: int +//│ 'h :> 'j +//│ <: int +//│ 'j :> int | 'k +//│ <: int +//│ 'k := int +//│ 'g := int +//│ Typed: int + + From 3ecaa938de565dab31a7173f67241bb4fcbe3cf4 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 13:18:11 +0800 Subject: [PATCH 059/498] WIP Progress on simplif --- .../src/main/scala/mlscript/NuTypeDefs.scala | 86 ++++- .../main/scala/mlscript/TypeSimplifier.scala | 12 +- shared/src/main/scala/mlscript/Typer.scala | 44 +-- .../main/scala/mlscript/TyperDatatypes.scala | 12 +- .../main/scala/mlscript/TyperHelpers.scala | 48 ++- shared/src/test/diff/nu/BasicClasses.mls | 149 +++----- shared/src/test/diff/nu/BasicMixins.mls | 212 +++-------- shared/src/test/diff/nu/ECOOP23.mls | 340 ++++-------------- shared/src/test/diff/nu/ECOOP23_min.mls | 51 ++- shared/src/test/diff/nu/ECOOP23_repro.mls | 254 +++---------- shared/src/test/diff/nu/GenericClasses.mls | 220 +++--------- shared/src/test/diff/nu/GenericMixins.mls | 33 ++ shared/src/test/diff/nu/MutualRec.mls | 154 +++----- shared/src/test/diff/nu/ParamOverriding.mls | 13 +- .../src/test/scala/mlscript/DiffTests.scala | 15 +- 15 files changed, 531 insertions(+), 1112 deletions(-) create mode 100644 shared/src/test/diff/nu/GenericMixins.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index f3fd3e7185..8b24e9f928 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -27,6 +27,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuMember + + // TODO rm – just use `mapPolMap` + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember + + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember } @@ -37,6 +44,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuParam = NuParam(nme, ty.freshenAbove(lim, rigidify), isType) + + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember = + NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)), isType) + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember = + NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)), isType) } // case class NuTypeParam(nme: TN, ty: FieldType) extends NuMember { // def name: Str = nme.name @@ -73,6 +87,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => freshenAbove(level, rigidify = false).asInstanceOf[TypedNuDecl] } } + def map(f: ST => ST)(implicit ctx: Ctx): TypedNuTermDef = + mapPol(N, false)((_, ty) => f(ty)).asInstanceOf[TypedNuTermDef]//TODO + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef + // def childrenTypes: Ls[ST] /* def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) @@ -118,13 +139,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // val tparams: Ls[TN -> TV] = Nil // TODO override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = this match { - case m @ TypedNuMxn(td, thisTV, superTV, ttu) => + case m @ TypedNuMxn(td, thisTV, superTV, members, ttu) => // println(">>",m.level) // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) TypedNuMxn(td, thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) case TypedNuCls(level, td, ttu, tps, params, members, thisTy) => println(">>",level,ctx.lvl) @@ -161,24 +183,56 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // def freshenAbove(lim: Int, rigidify: Bool) // (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) // : TypedNuTypeDef = ??? + + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember = ??? + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember = ??? } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { case class TypedNuCls(level: Level, td: NuTypeDef, ttu: TypedTypingUnit, tparams: Ls[TN -> TV], params: Ls[Var -> FieldType], // members: Map[Str, LazyTypeInfo]) - members: Map[Str, NuMember], thisTy: ST) - extends TypedNuTypeDef(Cls) with TypedNuTermDef { + members: Map[Str, NuMember], + thisTy: ST + ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { def nme: TypeName = td.nme def name: Str = nme.name + + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + TypedNuCls(level, td, ttu, + tparams.map(tp => tp._1 -> f(N, tp._2).asInstanceOf[TV]), + // params.mapValues(_.mapPol(pol)(f)), + params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), + members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, + f(N, thisTy).asInstanceOf[TV] + ) + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + TypedNuCls(level, td, ttu, + tparams.map(tp => tp._1 -> f(pol.invar, tp._2).asInstanceOf[TV]), + // params.mapValues(_.mapPol(pol)(f)), + params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), + members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, + f(pol.invar, thisTy).asInstanceOf[TV] + ) } - case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { + case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, members: Map[Str, NuMember], ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { val level: Level = thisTV.level - 1 // TODO cleaner def nme: TypeName = td.nme def name: Str = nme.name // def freshen(implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, + + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + TypedNuMxn(td, f(N, thisTV), f(N, superTV), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + TypedNuMxn(td, f(pol.invar, thisTV), f(pol.invar, superTV), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) } /** Note: the type `ty` is stoed *without* its polymorphic wrapper! */ @@ -191,17 +245,35 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(level, rigidify)) TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) } + + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + // TypedNuFun(level, fd, ty.mapPol(pol, smart)(f)) + TypedNuFun(level, fd, f(pol, ty)) + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + TypedNuFun(level, fd, f(pol, ty)) } - case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) extends OtherTypeLike { + case class CompletedTypingUnit(entities: Ls[TypedNuTermDef], result: Opt[ST]) extends OtherTypeLike { + def map(f: ST => ST)(implicit ctx: Ctx): CompletedTypingUnit = + CompletedTypingUnit(entities.map(_.map(f)), result.map(f)) + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): CompletedTypingUnit = + CompletedTypingUnit(entities.map(_.mapPol(pol, smart)(f)), result.map(f(pol, _))) + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): CompletedTypingUnit = + CompletedTypingUnit(entities.map(_.mapPolMap(pol)(f)), result.map(f(pol, _))) + } + case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) /* extends OtherTypeLike */ { // def freshen(implicit ctx: Ctx): TypedTypingUnit = ??? def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = TypedTypingUnit(entities.map(_.map(_.freshenAbove(lim, rigidify).asInstanceOf[TypedNuTermDef])) , result.map(_.freshenAbove(lim, rigidify))) - def force()(implicit raise: Raise): Unit = { - entities.foreach(_.force()) + def force()(implicit raise: Raise): CompletedTypingUnit = { + CompletedTypingUnit(entities.map(_.force()), result) } } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index b494be5db0..c9db042864 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -33,6 +33,8 @@ trait TypeSimplifier { self: Typer => def processLike(ty: TypeLike): TypeLike = ty match { case ty: ST => process(ty, N) + case OtherTypeLike(tu) => + tu.map(process(_, N)) } def process(ty: ST, parent: Opt[Bool -> TV], canDistribForall: Opt[Level] = N): ST = // trace(s"process($ty) $canDistribForall") { @@ -793,6 +795,7 @@ trait TypeSimplifier { self: Typer => def transformLike(ty: TL, pol: PolMap): TL = ty match { case ty: ST => transform(ty, pol, semp) + case OtherTypeLike(tu) => tu.mapPolMap(pol)((p,t) => transform(t, p, semp)) } def transform(st: SimpleType, pol: PolMap, parents: Set[TV], canDistribForall: Opt[Level] = N): SimpleType = trace(s"transform[${printPol(pol)}] $st (${parents.mkString(", ")}) $pol $canDistribForall") { @@ -1003,8 +1006,9 @@ trait TypeSimplifier { self: Typer => } // }(r => s"~> $r") - def processLike(pol: Opt[Bool], ty: TL): ST = ty match { + def processLike(pol: Opt[Bool], ty: TL): TL = ty match { case ty: ST => process(pol, ty, N) + case OtherTypeLike(tu) => tu.mapPol(pol, smart = true)(process(_, _, N)) } processLike(S(pol), st) @@ -1100,7 +1104,7 @@ trait TypeSimplifier { self: Typer => abstract class SimplifyPipeline { def debugOutput(msg: => Str): Unit - def apply(st: TypeLike)(implicit ctx: Ctx): TypeLike = { + def apply(st: TypeLike, all: Bool = true)(implicit ctx: Ctx): TypeLike = { var cur = st cur = removeIrrelevantBounds(cur, inPlace = false) @@ -1119,7 +1123,7 @@ trait TypeSimplifier { self: Typer => // cur = factorRecursiveTypes_!(cur, approximateRecTypes = false) // debugOutput(s"⬤ Factored: ${cur}") // debugOutput(s" where: ${cur.showBounds}") - + if (all) { cur = normalizeTypes_!(cur) debugOutput(s"⬤ Normalized: ${cur}") debugOutput(s" where: ${cur.showBounds}") @@ -1143,7 +1147,7 @@ trait TypeSimplifier { self: Typer => cur = factorRecursiveTypes_!(cur, approximateRecTypes = false) debugOutput(s"⬤ Factored: ${cur}") debugOutput(s" where: ${cur.showBounds}") - + } cur } } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 58e9a1e396..03f01d1f5f 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1261,16 +1261,17 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) }) } def goDecl(d: TypedNuDecl): NuDecl = d match { - case TypedNuMxn(td, thisTV, superTV, ttu) => + case TypedNuMxn(td, thisTV, superTV, members, ttu) => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), Nil,//TODO S(go(superTV)), S(go(thisTV)), - mkTypingUnit(thisTV, - // members - Map.empty - )) + // mkTypingUnit(thisTV, + // // members + // Map.empty + // ) + mkTypingUnit(thisTV, members)) case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => NuTypeDef(td.kind, td.nme, td.tparams, // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) @@ -1289,21 +1290,24 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // if (bounds.isEmpty) res // else Constrained(res, bounds, Nil) res - case OtherTypeLike(ttu) => - val mems = ttu.entities.map { lti => - lti.result match { - // // case S(td: TypedNuTermDef) => ??? - // case S(TypedNuCls(level, td, ttu, tparams, params, members)) => - // NuTypeDef(td.kind, td.nme, td.tparams, - // // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) - // Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), - // Nil,//TODO - // members) - case S(d) => goDecl(d) - case N => lastWords("Cannot expand uncomputed type info.") - } - } - Signature(mems, ttu.result.map(go)) + case OtherTypeLike(tu) => + val mems = tu.entities.map(goDecl) + Signature(mems, tu.result.map(go)) + // case OtherTypeLike(ttu) => + // val mems = ttu.entities.map { lti => + // lti.result match { + // // // case S(td: TypedNuTermDef) => ??? + // // case S(TypedNuCls(level, td, ttu, tparams, params, members)) => + // // NuTypeDef(td.kind, td.nme, td.tparams, + // // // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) + // // Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + // // Nil,//TODO + // // members) + // case S(d) => goDecl(d) + // case N => lastWords("Cannot expand uncomputed type info.") + // } + // } + // Signature(mems, ttu.result.map(go)) } def go(st: SimpleType): Type = diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index bab39c8726..11d145f3ed 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -37,7 +37,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // } // case class DeclType() extends SimpleType { - protected abstract class TypedNuTypeDefBase extends SimpleType + protected abstract class TypedNuTypeDefBase + // protected abstract class TypedNuTypeDefBase extends SimpleType // TODO rm level? already in ctx class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx, vars: Map[Str, SimpleType]) extends TypeInfo { @@ -289,7 +290,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => ctx += "super" -> VarSymbol(superTV, Var("super")) // ctx |> { implicit ctx => val ttu = typeTypingUnit(td.body, allowPure = false) - TypedNuMxn(td, thisTV, superTV, ttu) + val mems = ttu.entities.map(_.complete()) + TypedNuMxn(td, thisTV, superTV, mems.map(m => m.name -> m).toMap, ttu) // } } case _ => ??? @@ -492,12 +494,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } type TL = TypeLike - abstract class OtherTypeLike extends TypeLike { - this: TypedTypingUnit => def self: TypedTypingUnit = this + abstract class OtherTypeLike extends TypeLike { this: CompletedTypingUnit => + def self: CompletedTypingUnit = this def unwrapProvs: TypeLike = this } object OtherTypeLike { - def unapply(ot: OtherTypeLike): S[TypedTypingUnit] = S(ot.self) + def unapply(ot: OtherTypeLike): S[CompletedTypingUnit] = S(ot.self) } /** A general type form (TODO: rename to AnyType). */ diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index c3e47aca6a..5bd3d3af43 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -735,8 +735,12 @@ abstract class TyperHelpers { Typer: Typer => trait TypeLikeImpl { self: TypeLike => def childrenPol(pol: PolMap)(implicit ctx: Ctx): List[PolMap -> SimpleType] = { - def childrenPolField(fld: FieldType): List[PolMap -> SimpleType] = + def childrenPolField(pol: PolMap)(fld: FieldType): List[PolMap -> SimpleType] = fld.lb.map(pol.contravar -> _).toList ::: pol.covar -> fld.ub :: Nil + def childrenPolMem(m: NuMember): List[PolMap -> SimpleType] = m match { + case NuParam(nme, ty, isType) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable + case TypedNuFun(level, fd, ty) => pol -> ty :: Nil + } this match { case tv @ AssignedVariable(ty) => pol -> ty :: Nil @@ -746,10 +750,10 @@ abstract class TyperHelpers { Typer: Typer => case FunctionType(l, r) => pol.contravar -> l :: pol.covar -> r :: Nil case Overload(as) => as.map(pol -> _) case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil - case RecordType(fs) => fs.unzip._2.flatMap(childrenPolField) - case TupleType(fs) => fs.unzip._2.flatMap(childrenPolField) - case ArrayType(fld) => childrenPolField(fld) - case SpliceType(elems) => elems flatMap {case L(l) => pol -> l :: Nil case R(r) => childrenPolField(r)} + case RecordType(fs) => fs.unzip._2.flatMap(childrenPolField(pol)) + case TupleType(fs) => fs.unzip._2.flatMap(childrenPolField(pol)) + case ArrayType(fld) => childrenPolField(pol)(fld) + case SpliceType(elems) => elems flatMap {case L(l) => pol -> l :: Nil case R(r) => childrenPolField(pol)(r)} case NegType(n) => pol.contravar -> n :: Nil case ExtrType(_) => Nil case ProxyType(und) => pol -> und :: Nil @@ -760,6 +764,23 @@ abstract class TyperHelpers { Typer: Typer => case PolymorphicType(_, und) => pol -> und :: Nil case ConstrainedType(cs, bod) => cs.flatMap(vbs => PolMap.pos -> vbs._1 :: PolMap.posAtNeg -> vbs._2 :: Nil) ::: pol -> bod :: Nil + case OtherTypeLike(tu) => + // tu.entities.flatMap(_.childrenPol) ::: tu.result.toList + val ents = tu.entities.flatMap { + case tf: TypedNuFun => + PolMap.pos -> tf.ty :: Nil + case mxn: TypedNuMxn => + mxn.members.valuesIterator.flatMap(childrenPolMem) ++ + S(pol.invar -> mxn.superTV) ++ + S(pol.invar -> mxn.thisTV) + case cls: TypedNuCls => + cls.tparams.iterator.map(PolMap.neu -> _._2) ++ + // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) + cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ + cls.members.valuesIterator.flatMap(childrenPolMem) ++ + S(pol.invar -> cls.thisTy) + } + ents ::: tu.result.toList.map(pol -> _) }} def getVarsPol(pol: PolMap)(implicit ctx: Ctx): SortedMap[TypeVariable, Opt[Bool]] = { @@ -900,6 +921,23 @@ abstract class TyperHelpers { Typer: Typer => class Traverser2(implicit ctx: Ctx) { def applyLike(pol: PolMap)(ty: TypeLike): Unit = ty match { case ty: ST => apply(pol)(ty) + case OtherTypeLike(tu) => + tu.entities.foreach(applyMem(pol)) + tu.result.foreach(apply(pol)) + } + def applyMem(pol: PolMap)(m: NuMember): Unit = m match { + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => + tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) + params.foreach(p => applyField(pol)(p._2)) + members.valuesIterator.foreach(applyMem(pol)) + // thisTy.foreach(apply(pol.invar)(_)) + apply(pol.invar)(thisTy) + case TypedNuMxn(td, thisTV, superTV, members, ttu) => + members.valuesIterator.foreach(applyMem(pol)) + apply(pol.invar)(thisTV) + apply(pol.invar)(superTV) + case NuParam(nme, ty, isType) => applyField(pol)(ty) + case TypedNuFun(level, fd, ty) => apply(pol)(ty) } def apply(pol: PolMap)(st: ST): Unit = st match { case tv @ AssignedVariable(ty) => apply(pol)(ty) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 7ca713e62f..cae7db9af7 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -13,72 +13,47 @@ class A(n: int) let a = A(42) //│ -//│ let a: 'a -//│ where -//│ 'a :> A +//│ let a: A fun f(x: A) = x.n //│ -//│ fun f: (x: A,) -> 'n -//│ where -//│ 'n :> int +//│ fun f: (x: A,) -> int fun f(x: A) = if x is A then x.n //│ -//│ fun f: (x: A,) -> 'n -//│ where -//│ 'n :> int +//│ fun f: (x: A,) -> int -// FIXedME no bounds on 'n... fun f(x: A | 'b) = if x is A then x.n else 0 //│ -//│ fun f: (x: (A | 'b,),) -> ('n | 0) -//│ where -//│ 'n :> int +//│ fun f: (x: (anything,),) -> (int | 0) fun f(x) = x.n //│ -//│ fun f: 'a -> 'n -//│ where -//│ 'a <: {n: 'n} +//│ fun f: {n: 'n} -> 'n f(a) //│ -//│ 'a -//│ where -//│ 'a :> int +//│ int //│ Typed: int fun f(x) = if x is A then x.n //│ -//│ fun f: 'a -> 'n -//│ where -//│ 'n :> int -//│ 'a <: A +//│ fun f: A -> int f(a) //│ -//│ 'a -//│ where -//│ 'a :> forall 'n. 'n -//│ 'n :> int +//│ int //│ Typed: int fun f(x) = if x is A then x.n else 0 //│ -//│ fun f: 'a -> ('n | 0) -//│ where -//│ 'n :> int -//│ 'a <: A | 'b & ~A +//│ fun f: anything -> (int | 0) f(a) //│ -//│ 'a -//│ where -//│ 'a :> forall 'n. 'n | 0 -//│ 'n :> int +//│ int | 0 //│ Typed: int @@ -90,8 +65,8 @@ class C { //│ //│ class C() { //│ this: 'this -//│ fun const: 'a -> 'b -> 'b -//│ fun id: 'b -> 'b +//│ fun const: anything -> 'a -> 'a +//│ fun id: 'a -> 'a //│ } //│ where //│ 'this :> C @@ -104,29 +79,16 @@ class Base0(n) { fun oops = this.my } //│ -//│ class Base0(n: 'n) { +//│ class Base0(n: nothing) { //│ this: 'this //│ fun me: 'this -//│ fun mine: 'n0 -//│ fun my: 'n0 +//│ fun mine: 'n +//│ fun my: 'n //│ fun oops: 'my //│ } //│ where -//│ 'my :> 'my0 -//│ <: 'oops -//│ 'oops :> 'my0 -//│ 'n0 :> 'n1 -//│ <: 'mine & 'my1 -//│ 'my1 :> 'n1 -//│ 'mine :> 'n1 //│ 'this :> Base0 -//│ <: {my: 'my0} & {n: 'n1} -//│ 'n1 :> 'n2 -//│ 'my0 :> 'n3 -//│ 'n3 :> 'n4 -//│ <: 'mine0 & 'my2 -//│ 'my2 :> 'n4 -//│ 'mine0 :> 'n4 +//│ <: {my: 'my, n: 'n} // :d // Base0 @@ -134,32 +96,25 @@ class Base0(n) { let b1 = Base0(42) //│ -//│ let b1: 'a -//│ where -//│ 'a :> Base0 +//│ let b1: Base0 // :d let n1 = b1.n //│ -//│ let n1: 'n +//│ let n1: nothing // TODO n1 + 1 //│ -//│ 'a -//│ where -//│ 'a :> int +//│ int //│ Typed: int let b2 = Base0("hi") let n2 = b2.n //│ -//│ let b2: 'a -//│ let n2: 'n -//│ where -//│ 'a :> Base0 -//│ <: {n: 'n} +//│ let b2: Base0 +//│ let n2: nothing @@ -171,20 +126,13 @@ class Base1(base: int) { //│ //│ class Base1(base: int) { //│ this: 'this -//│ fun foo: 'a -> 'b +//│ fun foo: int -> int //│ fun getBase1: int -//│ fun getBase2: 'base +//│ fun getBase2: int | 'base //│ } //│ where -//│ 'base :> 'base0 -//│ <: 'getBase2 -//│ 'getBase2 :> 'base0 -//│ 'b :> int -//│ 'a <: int //│ 'this :> Base1 -//│ <: {base: 'base1} & {base: 'base0} -//│ 'base0 :> int -//│ 'base1 := int +//│ <: {base: 'base & int} class Base1(base: int) { fun getBase1 = base @@ -194,13 +142,11 @@ class Base1(base: int) { //│ //│ class Base1(base: int) { //│ this: 'this -//│ fun foo: 'a -> 'b +//│ fun foo: int -> int //│ fun getBase1: int //│ fun me: 'this //│ } //│ where -//│ 'b :> int -//│ 'a <: int //│ 'this :> Base1 Base1 @@ -210,41 +156,31 @@ Base1 let b = Base1(1) //│ -//│ let b: 'a -//│ where -//│ 'a :> Base1 +//│ let b: Base1 b.base //│ -//│ 'base -//│ where -//│ 'base :> int +//│ int //│ Typed: int b.getBase1 //│ -//│ 'getBase1 -//│ where -//│ 'getBase1 :> int +//│ int //│ Typed: int // :d b.me //│ -//│ 'me -//│ where -//│ 'me :> Base1 +//│ Base1 //│ Typed: Base1 :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.240: b.getBaseTypo +//│ ║ l.178: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ -//│ 'getBaseTypo -//│ where -//│ 'getBaseTypo :> error +//│ error //│ Typed: error @@ -259,23 +195,19 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.258: class Rec(n) { +//│ ║ l.194: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.259: fun go = Rec(n + 1) +//│ ║ l.195: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.260: } +//│ ║ l.196: } //│ ╙── ^ //│ -//│ class Rec(n: 'n) { +//│ class Rec(n: nothing) { //│ this: 'this -//│ fun go: 'a +//│ fun go: error //│ } //│ where -//│ 'a :> error -//│ <: 'go -//│ 'go :> error //│ 'this :> Rec -//│ 'n <: int @@ -286,16 +218,16 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.285: a: int +//│ ║ l.217: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.284: class Annots(base: 0 | 1) { +//│ ║ l.216: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.285: a: int +//│ ║ l.217: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.285: a: int +//│ ║ l.217: a: int //│ ╙── ^^^ //│ //│ class Annots(base: (0 | 1,)) { @@ -307,3 +239,4 @@ class Annots(base: 0 | 1) { + diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 8233750051..b71a2c2cb2 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -11,6 +11,7 @@ mixin BaseTest { //│ mixin BaseTest() { //│ super: 'super //│ this: 'this +//│ fun test: 'base //│ } //│ where //│ 'super <: {base: 'base} @@ -23,11 +24,12 @@ mixin BaseInc { //│ mixin BaseInc() { //│ super: 'super //│ this: 'this +//│ fun test: int +//│ fun test2: 'base //│ } //│ where //│ 'this <: {base: 'base} -//│ 'super <: {base: 'base0} -//│ 'base0 <: int +//│ 'super <: {base: int} // :d class Base1(base: int): BaseTest, BaseInc { @@ -36,82 +38,59 @@ class Base1(base: int): BaseTest, BaseInc { //│ //│ class Base1(base: int) { //│ this: 'this -//│ fun test: 'a -//│ fun test2: 'base -//│ fun test3: (int, 'base0,) +//│ fun test: int +//│ fun test2: int +//│ fun test3: (int, int | 'base,) //│ } //│ where -//│ 'base0 :> 'base1 -//│ 'base :> 'base2 -//│ <: 'test2 -//│ 'test2 :> 'base2 -//│ 'base2 :> int -//│ 'a :> int -//│ <: 'test -//│ 'test :> int //│ 'this :> Base1 -//│ <: {base: 'base1} -//│ 'base1 :> int +//│ <: {base: 'base} Base1(1).test //│ -//│ 'test -//│ where -//│ 'test :> int +//│ int //│ Typed: int Base1(1).test2 //│ -//│ 'test2 -//│ where -//│ 'test2 :> int +//│ int //│ Typed: int Base1(1).test3 //│ -//│ 'test3 -//│ where -//│ 'test3 :> (int, 'base,) -//│ 'base :> 'base0 -//│ 'base0 :> int +//│ (int, int,) //│ Typed: (int, int,) class Base1(base): BaseTest //│ -//│ class Base1(base: 'base) { +//│ class Base1(base: nothing) { //│ this: 'this -//│ fun test: 'base0 +//│ fun test: nothing //│ } //│ where -//│ 'base0 :> 'base1 -//│ <: 'test -//│ 'test :> 'base1 //│ 'this :> Base1 -//│ 'base <: 'base1 Base1 //│ -//│ forall 'base 'base0. (base: 'base,) -> Base1 -//│ where -//│ 'base <: 'base0 +//│ (base: anything,) -> Base1 //│ Typed: (base: anything,) -> Base1 // TODO Base1(1).test //│ -//│ 'test +//│ nothing //│ Typed: nothing :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.108: class Base1(x): BaseTest -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.87: class Base1(x): BaseTest +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.108: class Base1(x): BaseTest -//│ ║ ^^^ +//│ ║ l.87: class Base1(x): BaseTest +//│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base //│ ║ ^^^^^^^^^^ @@ -119,19 +98,16 @@ class Base1(x): BaseTest //│ ║ l.8: fun test = super.base //│ ╙── ^^^^^ //│ -//│ class Base1(x: 'x) { +//│ class Base1(x: nothing) { //│ this: 'this -//│ fun test: 'base +//│ fun test: nothing //│ } //│ where -//│ 'base :> 'base0 -//│ <: 'test -//│ 'test :> 'base0 //│ 'this :> Base1 Base1 //│ -//│ forall 'x. (x: 'x,) -> Base1 +//│ (x: anything,) -> Base1 //│ Typed: (x: anything,) -> Base1 @@ -143,33 +119,23 @@ mixin Foo { //│ mixin Foo() { //│ super: 'super //│ this: 'this +//│ fun test: (int & 'a) -> (int, 'a, 'misc,) //│ } //│ where -//│ 'super <: {misc: 'misc} & {base: 'base} -//│ 'base <: int +//│ 'super <: {base: int, misc: 'misc} module Base1(base: int, misc: string): Foo //│ //│ namespace Base1(base: int, misc: string) { //│ this: 'this -//│ fun test: 'a -> ('b, 'a, 'misc,) +//│ fun test: (int & 'a) -> (int, 'a, string,) //│ } //│ where -//│ 'misc :> 'misc0 -//│ 'misc0 :> string -//│ 'b :> int -//│ 'a <: int //│ 'this :> Base1 Base1.test //│ -//│ 'test -//│ where -//│ 'test :> 'a -> ('b, 'a, 'misc,) -//│ 'misc :> 'misc0 -//│ 'misc0 :> string -//│ 'b :> int -//│ 'a <: int +//│ (int & 'a) -> (int, 'a, string,) //│ Typed: (int & 'a) -> (int, 'a, string,) @@ -183,6 +149,8 @@ mixin WrapBase { //│ mixin WrapBase() { //│ super: 'super //│ this: 'this +//│ fun wrap: 'a -> 'a +//│ fun wrapA: (x: int,) -> int //│ } // :d @@ -194,11 +162,11 @@ mixin Wrap { //│ mixin Wrap() { //│ super: 'super //│ this: 'this +//│ fun wrap: 'a -> ('b,) +//│ fun wrapA: 'c -> ('d,) //│ } //│ where -//│ 'super <: {wrap: 'wrap} & {wrapA: 'wrapA} -//│ 'wrapA <: 'a -> 'b -//│ 'wrap <: 'c -> 'd +//│ 'super <: {wrap: 'a -> 'b, wrapA: 'c -> 'd} @@ -207,18 +175,10 @@ module WrapBase1: WrapBase, Wrap //│ //│ namespace WrapBase1() { //│ this: 'this -//│ fun wrap: 'a -> ('b,) -//│ fun wrapA: 'c -> ('d,) +//│ fun wrap: 'a -> ('a,) +//│ fun wrapA: int -> (int,) //│ } //│ where -//│ 'd :> 'e -//│ 'e :> int -//│ 'c <: 'f -//│ 'f <: int -//│ 'b :> 'g -//│ 'a <: 'h -//│ 'h <: 'i -//│ 'i <: 'g //│ 'this :> WrapBase1 @@ -230,24 +190,12 @@ WrapBase1 // :d WrapBase1.wrapA //│ -//│ 'wrapA -//│ where -//│ 'wrapA :> 'a -> ('b,) -//│ 'b :> 'c -//│ 'c :> int -//│ 'a <: 'd -//│ 'd <: int +//│ int -> (int,) //│ Typed: int -> (int,) WrapBase1.wrap //│ -//│ 'wrap -//│ where -//│ 'wrap :> 'a -> ('b,) -//│ 'b :> 'c -//│ 'a <: 'd -//│ 'd <: 'e -//│ 'e <: 'c +//│ 'a -> ('a,) //│ Typed: 'a -> ('a,) // :d @@ -256,52 +204,36 @@ WrapBase1.wrap WrapBase1.wrap(1) //│ -//│ 'a -//│ where -//│ 'a :> ('b,) -//│ 'b :> 'c -//│ 'c :> 1 +//│ (1,) //│ Typed: (1,) WrapBase1.wrap("ok") //│ -//│ 'a -//│ where -//│ 'a :> ('b,) -//│ 'b :> 'c -//│ 'c :> "ok" +//│ ("ok",) //│ Typed: ("ok",) WrapBase1.wrapA(1) //│ -//│ 'a -//│ where -//│ 'a :> ('b,) -//│ 'b :> 'c -//│ 'c :> int +//│ (int,) //│ Typed: (int,) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.286: WrapBase1.wrapA("ok") +//│ ║ l.222: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.286: WrapBase1.wrapA("ok") +//│ ║ l.222: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.179: fun wrapA(x: int) = x : int +//│ ║ l.145: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.190: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.158: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ -//│ 'a -//│ where -//│ 'a :> ('b,) | error -//│ 'b :> 'c -//│ 'c :> int +//│ error | (int,) //│ Typed: (int,) | error @@ -310,71 +242,23 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ //│ namespace WrapBase2() { //│ this: 'this -//│ fun wrap: 'a -> ('b,) -//│ fun wrapA: 'c -> ('d,) +//│ fun wrap: 'a -> ((('a,),),) +//│ fun wrapA: int -> (((int,),),) //│ } //│ where -//│ 'd :> 'e -//│ 'e :> ('f,) -//│ 'f :> 'g -//│ 'g :> ('h,) -//│ 'h :> 'i -//│ 'i :> int -//│ 'c <: 'j -//│ 'j <: 'k -//│ 'k <: 'l -//│ 'l <: 'm -//│ 'm <: 'n -//│ 'n <: int -//│ 'b :> 'o -//│ 'o :> ('p,) -//│ 'p :> 'q -//│ 'q :> ('r,) -//│ 'r :> 's -//│ 'a <: 't -//│ 't <: 'u -//│ 'u <: 'v -//│ 'v <: 'w -//│ 'w <: 'x -//│ 'x <: 'y -//│ 'y <: 's //│ 'this :> WrapBase2 let w = WrapBase2.wrap //│ -//│ let w: 'wrap -//│ where -//│ 'wrap :> 'a -> ('b,) -//│ 'b :> 'c -//│ 'c :> ('d,) -//│ 'd :> 'e -//│ 'e :> ('f,) -//│ 'f :> 'g -//│ 'a <: 'h -//│ 'h <: 'i -//│ 'i <: 'j -//│ 'j <: 'k -//│ 'k <: 'l -//│ 'l <: 'm -//│ 'm <: 'g +//│ let w: 'a -> ((('a,),),) let wd = w(1) //│ -//│ let wd: 'a -//│ where -//│ 'a :> ('b,) -//│ 'b :> 'c -//│ 'c :> ('d,) -//│ 'd :> 'e -//│ 'e :> ('f,) -//│ 'f :> 'g -//│ 'g :> 1 +//│ let wd: (((1,),),) wd._1._1._1 + 1 //│ -//│ 'a -//│ where -//│ 'a :> int +//│ int //│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index cefbdc71ab..5244709255 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -18,11 +18,8 @@ class Lit(n: int) fun add11 = Add(Lit(1), Lit(2)) //│ -//│ fun add11: 'a +//│ fun add11: Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} -//│ <: 'add11 -//│ 'add11 :> Add & {Add#E = 'E} //│ 'E :> Lit // add11 + 1 @@ -35,14 +32,10 @@ fun eval(e) = Lit(n) then n Add(l, r) then eval(l) + eval(r) //│ -//│ fun eval: 'a -> ('n | 'b) +//│ fun eval: 'a -> int //│ where -//│ 'b := int -//│ 'n := int //│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'a -//│ 'rhs <: 'a +//│ 'E <: 'a mixin EvalBase { @@ -55,43 +48,30 @@ mixin EvalBase { //│ mixin EvalBase() { //│ super: 'super //│ this: 'this +//│ fun eval: (Lit | Add & {Add#E = 'E} & ~Lit) -> int //│ } //│ where -//│ 'this <: {eval: 'eval} & {eval: 'eval0} -//│ 'eval0 <: 'lhs -> 'a -//│ 'a <: int -//│ 'eval <: 'rhs -> 'b -//│ 'b <: int +//│ 'E <: 'lhs +//│ 'this <: {eval: 'lhs -> int} module TestLang: EvalBase //│ //│ namespace TestLang() { //│ this: 'this -//│ fun eval: 'a -> (int | 'b) +//│ fun eval: 'a -> int //│ } //│ where -//│ 'b := int //│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a +//│ 'E <: 'a //│ 'this :> TestLang TestLang.eval //│ -//│ 'eval +//│ 'a -> int //│ where -//│ 'eval :> 'a -> (int | 'b) -//│ 'b := int //│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a +//│ 'E <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit @@ -99,10 +79,7 @@ TestLang.eval TestLang.eval(add11) //│ -//│ 'a -//│ where -//│ 'a :> int | 'b -//│ 'b := int +//│ int //│ Typed: int @@ -116,14 +93,10 @@ class Neg(expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) //│ -//│ let add2negadd11: 'a +//│ let add2negadd11: Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} -//│ 'E :> Neg & {Neg#A = 'A} | Lit -//│ 'A :> forall 'b 'E0 'add11. 'b -//│ 'b :> Add & {Add#E = 'E0} -//│ <: 'add11 -//│ 'add11 :> Add & {Add#E = 'E0} +//│ 'E :> Lit | Neg & {Neg#A = 'A} +//│ 'A :> forall 'E0. Add & {Add#E = 'E0} //│ 'E0 :> Lit @@ -136,65 +109,33 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: 'super //│ this: 'this +//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> (int | 'b) //│ } //│ where -//│ 'this <: {eval: 'eval} -//│ 'eval <: 'expr -> 'a -//│ 'a <: int -//│ 'super <: {eval: 'eval0} -//│ 'eval0 <: 'b -> 'c +//│ 'A <: 'expr +//│ 'this <: {eval: 'expr -> int} +//│ 'super <: {eval: 'a -> 'b} module TestLang: EvalBase, EvalNeg //│ //│ namespace TestLang() { //│ this: 'this -//│ fun eval: 'a -> ('b | 'c) +//│ fun eval: 'a -> int //│ } //│ where -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int -//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'f <: 'g -//│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a -//│ 'A <: 'expr -//│ 'expr <: 'expr0 -//│ 'expr0 <: 'a +//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg +//│ 'E <: 'a +//│ 'A <: 'a //│ 'this :> TestLang TestLang.eval //│ -//│ 'eval +//│ 'a -> int //│ where -//│ 'eval :> 'a -> ('b | 'c) -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int -//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'f <: 'g -//│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a -//│ 'A <: 'expr -//│ 'expr <: 'expr0 -//│ 'expr0 <: 'a +//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg +//│ 'E <: 'a +//│ 'A <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} @@ -204,83 +145,35 @@ TestLang.eval TestLang.eval(add11) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int TestLang.eval(Neg(add11)) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int TestLang.eval(Add(Lit(2), Neg(Lit(1)))) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int TestLang.eval(Neg(Neg(add11))) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int TestLang.eval(add2negadd11) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int // add11 TestLang.eval(Add(Lit(2), Neg(add11))) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int @@ -293,76 +186,33 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: 'super //│ this: 'this +//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> 'b //│ } //│ where -//│ 'this <: {eval: 'eval} -//│ 'eval <: 'expr -> 'a -//│ 'super <: {eval: 'eval0} & {eval: 'eval1} -//│ 'eval1 <: (Neg & {Neg#A :> 'A <: 'A0}) -> 'b -//│ 'A0 :> 'A -//│ 'A <: 'expr0 -//│ 'expr0 <: Neg & {Neg#A :> 'A1 <: 'A2} | 'c & ~Neg -//│ 'A2 <: 'A1 & 'expr1 -//│ 'expr1 <: 'expr -//│ 'eval0 <: 'd -> 'e +//│ 'A :> 'A0 +//│ <: (Neg & {Neg#A = 'A1} | ~Neg) & 'A2 +//│ 'A1 :> 'A3 +//│ <: 'expr +//│ 'this <: {eval: 'expr -> 'b} +//│ 'super <: {eval: (Neg & {Neg#A :> (Neg & {Neg#A :> 'expr <: 'expr & 'A3} | ~Neg) & 'A0 <: 'A0 | 'A2}) -> 'b & 'a -> 'b} module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ //│ namespace TestLang() { //│ this: 'this -//│ fun eval: 'a -> ('b | 'c | 'd) +//│ fun eval: 'a -> 'b //│ } //│ where -//│ 'b :> 'e -//│ <: int -//│ 'e :> 'b | 'c | 'd -//│ <: int -//│ 'd :> 'f -//│ <: int -//│ 'f :> 'g | 'h -//│ <: int -//│ 'c :> 'i -//│ <: int -//│ 'i :> 'g | 'h -//│ <: int -//│ 'h :> 'j -//│ <: int -//│ 'j :> int | 'k -//│ <: int -//│ 'k := int -//│ 'g := int -//│ 'a <: Neg & {Neg#A = 'A} | 'l & ~Neg -//│ 'l <: 'm -//│ 'm <: 'n -//│ 'n :> Neg & {Neg#A :> 'A0 <: 'A1} -//│ <: Neg & {Neg#A = 'A2} | 'o & ~Neg -//│ 'o <: 'p -//│ 'p <: 'q -//│ 'q <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a +//│ 'b :> int +//│ 'a <: Neg & {Neg#A = 'A} | (Neg & {Neg#A = 'A0} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg) & ~Neg +//│ 'E <: 'a //│ 'A :> 'A0 -//│ <: 'A1 & 'expr -//│ 'expr :> 'expr0 -//│ <: Neg & {Neg#A = 'A3} | 'r & ~Neg -//│ 'r :> 's -//│ 'A3 :> 'A4 -//│ <: 'A5 & 'expr1 -//│ 'expr1 :> 'expr2 -//│ <: 'expr3 -//│ 'A1 :> 'A0 -//│ <: 'A2 -//│ 'A0 <: 'A2 & 'expr0 -//│ 'expr0 <: Neg & {Neg#A :> 'A5 <: 'A4} | 's & ~Neg -//│ 'A4 <: 'A5 & 'expr2 -//│ 'expr2 <: 'expr3 -//│ 'expr3 <: 'a -//│ 'A2 <: 'A0 & 'expr4 -//│ 'expr4 <: 'expr5 -//│ 'expr5 <: 'a +//│ <: (Neg & {Neg#A = 'A1} | ~Neg) & 'A0 +//│ 'A1 :> 'A2 +//│ <: 'A3 +//│ 'A0 <: 'a & (Neg & {Neg#A :> 'A3 <: 'A2} | ~Neg) +//│ 'A2 <: 'A3 +//│ 'A3 <: 'a //│ 'this :> TestLang fun mk(n) = if n is @@ -370,70 +220,26 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) //│ -//│ fun mk: 'a -> ('b | 'c | 'd) +//│ fun mk: number -> (Lit | 'a) //│ where -//│ 'c :> Neg & {Neg#A = 'A} -//│ 'A :> 'b | 'c | 'd -//│ 'd :> Add & {Add#E = 'E} -//│ 'E :> 'b | 'c | 'd -//│ 'b :> Lit -//│ 'a <: number +//│ 'a :> Add & {Add#E = 'E} | Neg & {Neg#A = 'A} +//│ 'A :> Lit | 'a +//│ 'E :> Lit | 'a TestLang.eval //│ -//│ 'eval +//│ 'a -> 'b //│ where -//│ 'eval :> 'a -> ('b | 'c | 'd) -//│ 'b :> 'e -//│ <: int -//│ 'e :> 'b | 'c | 'd -//│ <: int -//│ 'd :> 'f -//│ <: int -//│ 'f :> 'g | 'h -//│ <: int -//│ 'c :> 'i -//│ <: int -//│ 'i :> 'g | 'h -//│ <: int -//│ 'h :> 'j -//│ <: int -//│ 'j :> int | 'k -//│ <: int -//│ 'k := int -//│ 'g := int -//│ 'a <: Neg & {Neg#A = 'A} | 'l & ~Neg -//│ 'l <: 'm -//│ 'm <: 'n -//│ 'n :> Neg & {Neg#A :> 'A0 <: 'A1} -//│ <: Neg & {Neg#A = 'A2} | 'o & ~Neg -//│ 'o <: 'p -//│ 'p <: 'q -//│ 'q <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a +//│ 'b :> int +//│ 'a <: Neg & {Neg#A = 'A} | (Neg & {Neg#A = 'A0} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg) & ~Neg +//│ 'E <: 'a //│ 'A :> 'A0 -//│ <: 'A1 & 'expr -//│ 'expr :> 'expr0 -//│ <: Neg & {Neg#A = 'A3} | 'r & ~Neg -//│ 'r :> 's -//│ 'A3 :> 'A4 -//│ <: 'A5 & 'expr1 -//│ 'expr1 :> 'expr2 -//│ <: 'expr3 -//│ 'A1 :> 'A0 -//│ <: 'A2 -//│ 'A0 <: 'A2 & 'expr0 -//│ 'expr0 <: Neg & {Neg#A :> 'A5 <: 'A4} | 's & ~Neg -//│ 'A4 <: 'A5 & 'expr2 -//│ 'expr2 <: 'expr3 -//│ 'expr3 <: 'a -//│ 'A2 <: 'A0 & 'expr4 -//│ 'expr4 <: 'expr5 -//│ 'expr5 <: 'a +//│ <: (Neg & {Neg#A = 'A1} | ~Neg) & 'A0 +//│ 'A1 :> 'A2 +//│ <: 'A3 +//│ 'A0 <: 'a & (Neg & {Neg#A :> 'A3 <: 'A2} | ~Neg) +//│ 'A2 <: 'A3 +//│ 'A3 <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} @@ -448,25 +254,7 @@ TestLang.eval(mk(0)) //│ //│ 'a //│ where -//│ 'a :> 'b | 'c | 'd -//│ 'b :> 'e -//│ <: int -//│ 'e :> 'b | 'c | 'd -//│ <: int -//│ 'd :> 'f -//│ <: int -//│ 'f :> 'g | 'h -//│ <: int -//│ 'c :> 'i -//│ <: int -//│ 'i :> 'g | 'h -//│ <: int -//│ 'h :> 'j -//│ <: int -//│ 'j :> int | 'k -//│ <: int -//│ 'k := int -//│ 'g := int +//│ 'a :> int //│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index ae80bf1216..4b1f7373a5 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -14,63 +14,55 @@ class Add(lhs: E, rhs: E) let e = Add(1, 1) //│ -//│ let e: 'a +//│ let e: Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} //│ 'E :> 1 :d e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α29 +//│ | 0. : α33 //│ ======== TYPED ======== -//│ res: Some(α29) where -//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) -//│ E23_30 :> 1 +//│ res: Some(α33) where +//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) +//│ E23_34 :> 1 //│ -//│ 'a +//│ Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} //│ 'E :> 1 -//│ ⬤ Typed as: ‹∀ 0. α29› +//│ ⬤ Typed as: ‹∀ 0. α33› //│ where: -//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) -//│ E23_30 :> 1 +//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) +//│ E23_34 :> 1 //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> 1 e.lhs //│ -//│ 'lhs -//│ where -//│ 'lhs :> 1 +//│ 1 //│ Typed: 1 :d e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α29 +//│ | 0. : α33 //│ ======== TYPED ======== -//│ res: Some(α29) where -//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) <: {lhs: lhs35} -//│ E23_30 :> 1 <: lhs35 -//│ lhs35 :> 1 +//│ res: Some(α33) where +//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) <: {lhs: lhs45} +//│ E23_34 :> 1 <: lhs45 +//│ lhs45 :> 1 //│ -//│ 'a +//│ Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} -//│ <: {lhs: 'lhs} //│ 'E :> 1 -//│ <: 'lhs -//│ 'lhs :> 1 -//│ ⬤ Typed as: ‹∀ 0. α29› +//│ ⬤ Typed as: ‹∀ 0. α33› //│ where: -//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) <: {lhs: lhs35} -//│ E23_30 :> 1 <: lhs35 -//│ lhs35 :> 1 +//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) <: {lhs: lhs45} +//│ E23_34 :> 1 <: lhs45 +//│ lhs45 :> 1 //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> 1 @@ -78,9 +70,8 @@ e Add(2, 2) //│ -//│ 'a +//│ Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} //│ 'E :> 2 //│ Typed: Add & {Add#E = 'E} //│ where diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index fa2022601d..508df75429 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -18,9 +18,8 @@ class Lit(n: int) let add11 = Add(Lit(1), Lit(2)) //│ -//│ let add11: 'a +//│ let add11: Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} //│ 'E :> Lit fun eval(e) = @@ -28,13 +27,10 @@ fun eval(e) = Lit(n) then n: int Add(l, r) then eval(l) + eval(r) //│ -//│ fun eval: 'a -> (int | 'b) +//│ fun eval: 'a -> int //│ where -//│ 'b := int //│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'a -//│ 'rhs <: 'a +//│ 'E <: 'a mixin EvalBase { @@ -47,43 +43,30 @@ mixin EvalBase { //│ mixin EvalBase() { //│ super: 'super //│ this: 'this +//│ fun eval: (Lit | Add & {Add#E = 'E} & ~Lit) -> int //│ } //│ where -//│ 'this <: {eval: 'eval} & {eval: 'eval0} -//│ 'eval0 <: 'lhs -> 'a -//│ 'a <: int -//│ 'eval <: 'rhs -> 'b -//│ 'b <: int +//│ 'E <: 'lhs +//│ 'this <: {eval: 'lhs -> int} module TestLang: EvalBase //│ //│ namespace TestLang() { //│ this: 'this -//│ fun eval: 'a -> (int | 'b) +//│ fun eval: 'a -> int //│ } //│ where -//│ 'b := int //│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a +//│ 'E <: 'a //│ 'this :> TestLang TestLang.eval //│ -//│ 'eval +//│ 'a -> int //│ where -//│ 'eval :> 'a -> (int | 'b) -//│ 'b := int //│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a +//│ 'E <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit @@ -93,9 +76,8 @@ TestLang.eval add11 //│ -//│ 'a +//│ Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} //│ 'E :> Lit //│ Typed: Add & {Add#E = 'E} //│ where @@ -103,32 +85,16 @@ add11 TestLang.eval(add11) //│ -//│ 'a -//│ where -//│ 'a :> int | 'b -//│ 'b := int +//│ int //│ Typed: int add11 //│ -//│ 'a +//│ Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} -//│ <: 'b //│ 'E :> Lit -//│ <: 'E0 -//│ 'E0 :> Lit -//│ <: 'E & 'rhs & 'lhs -//│ 'lhs :> Lit -//│ <: 'lhs0 -//│ 'lhs0 :> Lit -//│ <: 'b -//│ 'rhs :> Lit -//│ <: 'rhs0 -//│ 'rhs0 :> Lit -//│ <: 'b -//│ 'b :> Lit | Add & {Add#E = 'E} -//│ <: Lit | Add & {Add#E = 'E0} & ~Lit +//│ <: 'a +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> Lit @@ -136,44 +102,16 @@ add11 TestLang.eval(add11) //│ -//│ 'a -//│ where -//│ 'a :> int | 'b -//│ 'b := int +//│ int //│ Typed: int add11 //│ -//│ 'a +//│ Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} -//│ <: 'b & 'c //│ 'E :> Lit -//│ <: 'E0 & 'E1 -//│ 'E1 :> Lit -//│ <: 'E & 'rhs & 'lhs -//│ 'lhs :> Lit -//│ <: 'lhs0 -//│ 'lhs0 :> Lit -//│ <: 'c -//│ 'rhs :> Lit -//│ <: 'rhs0 -//│ 'rhs0 :> Lit -//│ <: 'c -//│ 'c :> Lit | Add & {Add#E = 'E} -//│ <: Lit | Add & {Add#E = 'E1} & ~Lit -//│ 'E0 :> Lit -//│ <: 'E & 'rhs1 & 'lhs1 -//│ 'lhs1 :> Lit -//│ <: 'lhs2 -//│ 'lhs2 :> Lit -//│ <: 'b -//│ 'rhs1 :> Lit -//│ <: 'rhs2 -//│ 'rhs2 :> Lit -//│ <: 'b -//│ 'b :> Lit | Add & {Add#E = 'E} -//│ <: Lit | Add & {Add#E = 'E0} & ~Lit +//│ <: 'a +//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> Lit @@ -191,37 +129,13 @@ class Neg(expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) //│ -//│ let add2negadd11: 'a +//│ let add2negadd11: Add & {Add#E = 'E} //│ where -//│ 'a :> Add & {Add#E = 'E} -//│ 'E :> Neg & {Neg#A = 'A} | Lit +//│ 'E :> Lit | Neg & {Neg#A = 'A} //│ 'A :> Add & {Add#E = 'E0} //│ 'E0 :> Lit -//│ <: 'E1 & 'E2 -//│ 'E2 :> Lit -//│ <: 'E0 & 'rhs & 'lhs -//│ 'lhs :> Lit -//│ <: 'lhs0 -//│ 'lhs0 :> Lit -//│ <: 'b -//│ 'rhs :> Lit -//│ <: 'rhs0 -//│ 'rhs0 :> Lit -//│ <: 'b -//│ 'b :> Lit | Add & {Add#E = 'E0} -//│ <: Lit | Add & {Add#E = 'E2} & ~Lit -//│ 'E1 :> Lit -//│ <: 'E0 & 'rhs1 & 'lhs1 -//│ 'lhs1 :> Lit -//│ <: 'lhs2 -//│ 'lhs2 :> Lit -//│ <: 'c -//│ 'rhs1 :> Lit -//│ <: 'rhs2 -//│ 'rhs2 :> Lit -//│ <: 'c -//│ 'c :> Lit | Add & {Add#E = 'E0} -//│ <: Lit | Add & {Add#E = 'E1} & ~Lit +//│ <: 'a +//│ 'a <: Lit | Add & {Add#E = 'E0} & ~Lit mixin EvalNeg { @@ -233,65 +147,33 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: 'super //│ this: 'this +//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> (int | 'b) //│ } //│ where -//│ 'this <: {eval: 'eval} -//│ 'eval <: 'expr -> 'a -//│ 'a <: int -//│ 'super <: {eval: 'eval0} -//│ 'eval0 <: 'b -> 'c +//│ 'A <: 'expr +//│ 'this <: {eval: 'expr -> int} +//│ 'super <: {eval: 'a -> 'b} module TestLang: EvalBase, EvalNeg //│ //│ namespace TestLang() { //│ this: 'this -//│ fun eval: 'a -> ('b | 'c) +//│ fun eval: 'a -> int //│ } //│ where -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int -//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'f <: 'g -//│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a -//│ 'A <: 'expr -//│ 'expr <: 'expr0 -//│ 'expr0 <: 'a +//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg +//│ 'E <: 'a +//│ 'A <: 'a //│ 'this :> TestLang TestLang.eval //│ -//│ 'eval +//│ 'a -> int //│ where -//│ 'eval :> 'a -> ('b | 'c) -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int -//│ 'a <: Neg & {Neg#A = 'A} | 'f & ~Neg -//│ 'f <: 'g -//│ 'g <: 'h -//│ 'h <: Lit | Add & {Add#E = 'E} & ~Lit -//│ 'E <: 'rhs & 'lhs -//│ 'lhs <: 'lhs0 -//│ 'lhs0 <: 'a -//│ 'rhs <: 'rhs0 -//│ 'rhs0 <: 'a -//│ 'A <: 'expr -//│ 'expr <: 'expr0 -//│ 'expr0 <: 'a +//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg +//│ 'E <: 'a +//│ 'A <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} @@ -301,101 +183,59 @@ TestLang.eval TestLang.eval(add11) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int TestLang.eval(Neg(add11)) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int TestLang.eval(Add(Lit(2), Neg(Lit(1)))) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int TestLang.eval(Neg(Neg(add11))) //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ int //│ Typed: int :e TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.356: TestLang.eval(add2negadd11) +//│ ║ l.206: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.192: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.130: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.42: if e is +//│ ║ l.38: if e is //│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) //│ ╙── ^ //│ -//│ 'a -//│ where -//│ 'a :> 'b | 'c | error -//│ 'c :> 'd -//│ <: int -//│ 'd :> int | 'e -//│ <: int -//│ 'e := int -//│ 'b := int +//│ error | int //│ Typed: error | int :e TestLang.eval(Add(Lit(2), Neg(add11))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.382: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ║ l.224: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.192: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.130: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.42: if e is +//│ ║ l.38: if e is //│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) //│ ╙── ^ //│ -//│ 'a -//│ where -//│ 'a :> error +//│ error //│ Typed: error diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 63d353ec0b..f894136fff 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -21,36 +21,24 @@ class Some(value: A) { let s = Some(1) //│ -//│ let s: 'a +//│ let s: Some & {Some#A = 'A} //│ where -//│ 'a :> Some & {Some#A = 'A} //│ 'A :> 1 s.value //│ -//│ 'value -//│ where -//│ 'value :> 1 +//│ 1 //│ Typed: 1 s.get //│ -//│ 'get -//│ where -//│ 'get :> 1 +//│ 1 //│ Typed: 1 s.toArray //│ -//│ 'toArray -//│ where -//│ 'toArray :> ('A,) -//│ 'A := 'A0 -//│ 'A0 :> 1 -//│ <: 'get & 'value -//│ 'value :> 1 -//│ 'get :> 1 +//│ (1,) //│ Typed: (1,) @@ -84,9 +72,7 @@ module None { None.toArray //│ -//│ 'toArray -//│ where -//│ 'toArray :> () +//│ () //│ Typed: () @@ -98,18 +84,13 @@ type Option = Some | None let opt = if true then Some(123) else None //│ -//│ let opt: 'a | None +//│ let opt: Some & {Some#A = 'A} | None //│ where -//│ 'a :> Some & {Some#A = 'A} //│ 'A :> 123 opt.toArray //│ -//│ 'toArray -//│ where -//│ 'toArray :> () | ('A,) -//│ 'A := 'A0 -//│ 'A0 :> 123 +//│ (123,) | () //│ Typed: Array[123] @@ -123,16 +104,12 @@ opt.toArray if opt is Some then opt.value else 0 //│ -//│ 'value | 0 -//│ where -//│ 'value :> 123 +//│ 123 | 0 //│ Typed: 0 | 123 if opt is Some(v) then v else 0 //│ -//│ 'value | 0 -//│ where -//│ 'value :> 123 +//│ 123 | 0 //│ Typed: 0 | 123 @@ -140,29 +117,17 @@ fun map(x, f) = if x is None then None Some(v) then Some(f(v)) //│ -//│ fun map: ('a, 'b,) -> (None | 'c) -//│ where -//│ 'c :> Some & {Some#A = 'A} -//│ 'b <: 'value -> 'd -//│ 'd <: 'A -//│ 'a <: None | Some & {Some#A = 'A0} & ~None -//│ 'A0 <: 'value +//│ fun map: (None | Some & {Some#A = 'A} & ~None, 'A -> 'A0,) -> (None | Some & {Some#A = 'A0}) let mo = map(opt, succ) //│ -//│ let mo: 'a +//│ let mo: None | Some & {Some#A = 'A} //│ where -//│ 'a :> forall 'b. None | 'b -//│ 'b :> Some & {Some#A = 'A} //│ 'A :> int mo.toArray //│ -//│ 'toArray -//│ where -//│ 'toArray :> ('A,) | () -//│ 'A := 'A0 -//│ 'A0 :> int +//│ () | (int,) //│ Typed: Array[int] @@ -171,42 +136,34 @@ class Test(n) { fun foo = n + 1 } //│ -//│ class Test(n: 'n) { +//│ class Test(n: nothing) { //│ this: 'this -//│ fun foo: 'a +//│ fun foo: int //│ } //│ where -//│ 'a :> int -//│ <: 'foo -//│ 'foo :> int //│ 'this :> Test -//│ 'n <: int Test(1) //│ -//│ 'a -//│ where -//│ 'a :> Test +//│ Test //│ Typed: Test :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.193: Test(true) +//│ ║ l.152: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.193: Test(true) +//│ ║ l.152: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.171: fun foo = n + 1 +//│ ║ l.136: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.170: class Test(n) { +//│ ║ l.135: class Test(n) { //│ ╙── ^ //│ -//│ 'a -//│ where -//│ 'a :> Test | error +//│ error | Test //│ Typed: Test | error @@ -215,30 +172,26 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.215: fun foo = n + 1 +//│ ║ l.172: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.215: fun foo = n + 1 +//│ ║ l.172: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.214: class Test(n: A) { +//│ ║ l.171: class Test(n: A) { //│ ╙── ^ //│ //│ class Test[A](n: A) { //│ this: 'this -//│ fun foo: 'a +//│ fun foo: int | error //│ } //│ where -//│ 'a :> error | int -//│ <: 'foo -//│ 'foo :> int | error //│ 'this :> Test Test(1) //│ -//│ 'a +//│ Test & {Test#A = 'A} //│ where -//│ 'a :> Test & {Test#A = 'A} //│ 'A :> 1 //│ Typed: Test & {Test#A = 'A} //│ where @@ -246,9 +199,8 @@ Test(1) Test(true) //│ -//│ 'a +//│ Test & {Test#A = 'A} //│ where -//│ 'a :> Test & {Test#A = 'A} //│ 'A :> true //│ Typed: Test & {Test#A = 'A} //│ where @@ -272,9 +224,8 @@ class Test(n: A) { Test(1) //│ -//│ 'a +//│ Test & {Test#A = 'A} //│ where -//│ 'a :> Test & {Test#A = 'A} //│ 'A :> 1 //│ Typed: Test & {Test#A = 'A} //│ where @@ -282,58 +233,42 @@ Test(1) Test(1).foo //│ -//│ 'foo -//│ where -//│ 'foo :> 1 +//│ 1 //│ Typed: 1 Test("ok").foo //│ -//│ 'foo -//│ where -//│ 'foo :> "ok" +//│ "ok" //│ Typed: "ok" let t = Test(1) //│ -//│ let t: 'a +//│ let t: Test & {Test#A = 'A} //│ where -//│ 'a :> Test & {Test#A = 'A} //│ 'A :> 1 t.foo1(true) //│ -//│ 'a -//│ where -//│ 'a :> 1 | true +//│ true | 1 //│ Typed: 1 | true t : Test<'a> //│ //│ Test['a] //│ where -//│ 'a :> 1 | true -//│ <: 'A -//│ 'A :> true | 1 -//│ <: 'a & 'b -//│ 'b :> true | 1 +//│ 'a :> true | 1 //│ Typed: Test['a] //│ where //│ 'a :> 1 | true t.id //│ -//│ 'id -//│ where -//│ 'id :> 'a -> 'a +//│ 'a -> 'a //│ Typed: 'a -> 'a [t.id(1), t.id(true)] //│ -//│ ('a, 'b,) -//│ where -//│ 'b :> true -//│ 'a :> 1 +//│ (1, true,) //│ Typed: (1, true,) @@ -343,137 +278,82 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.343: fun foo2(x: A) = x + 1 +//│ ║ l.278: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.343: fun foo2(x: A) = x + 1 +//│ ║ l.278: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.341: class Test { +//│ ║ l.276: class Test { //│ ╙── ^ //│ //│ class Test[A]() { //│ this: 'this //│ fun foo1: (x: A,) -> A -//│ fun foo2: (x: A,) -> 'a +//│ fun foo2: (x: A,) -> (int | error) //│ } //│ where -//│ 'a :> error | int //│ 'this :> Test Test().foo1 //│ -//│ 'foo1 -//│ where -//│ 'foo1 :> (x: 'A,) -> 'A -//│ 'A := 'A0 +//│ (x: 'A,) -> 'A //│ Typed: (x: 'A,) -> 'A Test().foo1(1) //│ -//│ 'a -//│ where -//│ 'a :> 1 +//│ 1 //│ Typed: 1 x => Test().foo1(x) //│ -//│ 'a -> 'b -//│ where -//│ 'a <: 'A -//│ 'A <: 'b +//│ 'a -> 'a //│ Typed: 'a -> 'a // :d let t = Test() //│ -//│ let t: 'a -//│ where -//│ 'a :> forall 'A. Test & {Test#A = 'A} +//│ let t: forall 'A. Test & {Test#A = 'A} t.foo1 //│ -//│ 'foo1 -//│ where -//│ 'foo1 :> (x: 'A,) -> 'A -//│ 'A := 'A0 +//│ (x: 'A,) -> 'A //│ Typed: (x: 'A,) -> 'A [t.foo1(0), t.foo1(true)] //│ -//│ ('a, 'b,) -//│ where -//│ 'b :> true -//│ 'a :> 0 +//│ (0, true,) //│ Typed: (0, true,) t.foo1(0) //│ -//│ 'a -//│ where -//│ 'a :> 0 +//│ 0 //│ Typed: 0 t //│ -//│ 'a -//│ where -//│ 'a :> forall 'A. Test & {Test#A = 'A} -//│ <: {foo1: 'foo1} & {foo1: 'foo10} & {foo1: 'foo11} & {foo1: 'foo12} -//│ 'foo12 :> (x: 'A0,) -> 'A0 -//│ 'A0 := 'A1 -//│ 'foo11 :> (x: 'A2,) -> 'A2 -//│ <: 0 -> 'b -//│ 'A2 := 'A3 -//│ 'A3 :> 0 -//│ <: 'b -//│ 'b :> 0 -//│ 'foo10 :> (x: 'A4,) -> 'A4 -//│ <: true -> 'c -//│ 'A4 := 'A5 -//│ 'A5 :> true -//│ <: 'c -//│ 'c :> true -//│ 'foo1 :> (x: 'A6,) -> 'A6 -//│ <: 0 -> 'd -//│ 'A6 := 'A7 -//│ 'A7 :> 0 -//│ <: 'd -//│ 'd :> 0 +//│ forall 'A. Test & {Test#A = 'A} //│ Typed: Test & {Test#A = 'A} fun foo(x: Test) = x.foo1 //│ -//│ fun foo: (x: Test[int],) -> 'foo1 -//│ where -//│ 'foo1 :> (x: 'A,) -> 'A -//│ 'A := int +//│ fun foo: (x: Test[int],) -> (x: int & 'A,) -> (int | 'A) foo(t) //│ -//│ 'a -//│ where -//│ 'a :> forall 'foo1. 'foo1 -//│ 'foo1 :> (x: 'A,) -> 'A -//│ 'A := int +//│ (x: int & 'A,) -> (int | 'A) //│ Typed: (x: int,) -> int foo(t)(1) //│ -//│ 'a -//│ where -//│ 'a :> int +//│ int //│ Typed: int Test().foo2 //│ -//│ 'foo2 -//│ where -//│ 'foo2 :> (x: 'A,) -> 'a -//│ 'a :> error | int -//│ 'A := 'A0 +//│ (x: anything,) -> (int | error) //│ Typed: (x: anything,) -> (error | int) diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls new file mode 100644 index 0000000000..d012530e94 --- /dev/null +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -0,0 +1,33 @@ +:NewParser +:NewDefs +:NoJS + + +// TODO support +mixin BaseTest { + fun test(x: A) = x +} +//│ ╔══[ERROR] type identifier not found: A +//│ ║ l.8: fun test(x: A) = x +//│ ╙── ^ +//│ +//│ mixin BaseTest[A]() { +//│ super: 'super +//│ this: 'this +//│ fun test: (x: error,) -> error +//│ } + +// TODO support +mixin BaseTest(x: A) { + fun test = x +} +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.22: fun test = x +//│ ╙── ^ +//│ +//│ mixin BaseTest[A]() { +//│ super: 'super +//│ this: 'this +//│ fun test: error +//│ } + diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 22ffdd8102..c46cc116af 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -24,30 +24,25 @@ fun fooo(x) = class C(y, z) C(0, x) //│ -//│ fun fooo: 'a -> 'b -//│ where -//│ 'b :> C -//│ 'a <: 'z +//│ fun fooo: anything -> C fun foo = bar fun bar = foo //│ -//│ fun foo: 'foo -//│ fun bar: 'foo -//│ where -//│ 'foo <: 'bar +//│ fun foo: nothing +//│ fun bar: nothing foo(bar) //│ -//│ 'a +//│ nothing //│ Typed: nothing fun foo = {x: foo} //│ -//│ fun foo: {x: 'foo} +//│ fun foo: 'foo //│ where //│ 'foo :> {x: 'foo} @@ -55,7 +50,7 @@ fun foo = {x: foo} fun foo = {x: bar} fun bar = {y: foo} //│ -//│ fun foo: {x: {y: 'foo}} +//│ fun foo: 'foo //│ fun bar: {y: 'foo} //│ where //│ 'foo :> {x: {y: 'foo}} @@ -63,7 +58,7 @@ fun bar = {y: foo} // FIXME pretty-printing? foo //│ -//│ forall 'foo. {x: {y: 'foo}} +//│ forall 'foo. 'foo //│ where //│ 'foo :> {x: {y: 'foo}} //│ Typed: 'foo @@ -84,19 +79,16 @@ foo.x //│ //│ 'x //│ where -//│ 'x :> {y: 'foo} -//│ 'foo :> {x: {y: 'foo}} +//│ 'x :> {y: {x: 'x}} //│ Typed: 'x //│ where //│ 'x :> {y: {x: 'x}} foo.x.y //│ -//│ 'y +//│ 'foo //│ where -//│ 'y :> {x: {y: 'foo}} //│ 'foo :> {x: {y: 'foo}} -//│ <: 'y //│ Typed: 'foo //│ where //│ 'foo :> {x: {y: 'foo}} @@ -105,14 +97,10 @@ foo.x.y fun foo(a) = {h: a, t: bar(a)} fun bar(b) = foo(b) //│ -//│ fun foo: 'a -> {h: 'a, t: 'b} -//│ fun bar: 'c -> 'd +//│ fun foo: 'a -> 'b +//│ fun bar: 'a -> 'b //│ where -//│ 'd :> {h: 'a, t: 'b} -//│ <: 'b //│ 'b :> {h: 'a, t: 'b} -//│ 'a <: 'c -//│ 'c <: 'a :ns foo @@ -132,13 +120,11 @@ foo fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} //│ -//│ fun foo: 'a -> {h1: 'a, t1: 'b} -//│ fun bar: 'c -> {h2: 'c, t2: 'd} +//│ fun foo: 'a -> 'b +//│ fun bar: 'a -> 'c //│ where -//│ 'b :> {h2: 'c, t2: 'd} -//│ 'd :> {h1: 'a, t1: 'b} -//│ 'a <: 'c -//│ 'c <: 'a +//│ 'b :> {h1: 'a, t1: 'c} +//│ 'c :> {h2: 'a, t2: 'b} @@ -151,7 +137,7 @@ module Test0_2 { //│ //│ namespace Test0_1() { //│ this: 'this -//│ fun a: 'b +//│ fun a: 123 //│ } //│ namespace Test0_2() { //│ this: 'this0 @@ -159,16 +145,11 @@ module Test0_2 { //│ } //│ where //│ 'this0 :> Test0_2 -//│ 'b :> 123 -//│ <: 'a -//│ 'a :> 123 //│ 'this :> Test0_1 Test0_1.a //│ -//│ 'a -//│ where -//│ 'a :> 123 +//│ 123 //│ Typed: 123 class Test0_1 { @@ -180,7 +161,7 @@ class Test0_2() { //│ //│ class Test0_1() { //│ this: 'this -//│ fun a: 'b +//│ fun a: 123 //│ } //│ class Test0_2() { //│ this: 'this0 @@ -188,9 +169,6 @@ class Test0_2() { //│ } //│ where //│ 'this0 :> Test0_2 -//│ 'b :> 123 -//│ <: 'a -//│ 'a :> 123 //│ 'this :> Test0_1 @@ -202,36 +180,28 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.198: module Test1_1 { +//│ ║ l.176: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.199: fun a = Test1_2.b +//│ ║ l.177: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.200: } +//│ ║ l.178: } //│ ╙── ^ //│ //│ namespace Test1_1() { //│ this: 'this -//│ fun a: 'b +//│ fun a: error //│ } //│ namespace Test1_2() { //│ this: 'this0 -//│ fun b: 'a +//│ fun b: error //│ } //│ where -//│ 'a :> error -//│ <: 'b0 -//│ 'b0 :> error //│ 'this0 :> Test1_2 -//│ 'b :> error -//│ <: 'a0 -//│ 'a0 :> error //│ 'this :> Test1_1 Test1_1.a //│ -//│ 'a -//│ where -//│ 'a :> error +//│ error //│ Typed: error @@ -243,29 +213,23 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.239: class Test1_1 { +//│ ║ l.209: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.240: fun a = Test1_2().b +//│ ║ l.210: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.241: } +//│ ║ l.211: } //│ ╙── ^ //│ //│ class Test1_1() { //│ this: 'this -//│ fun a: 'b +//│ fun a: error //│ } //│ class Test1_2() { //│ this: 'this0 -//│ fun b: 'a +//│ fun b: error //│ } //│ where -//│ 'a :> error -//│ <: 'b0 -//│ 'b0 :> error //│ 'this0 :> Test1_2 -//│ 'b :> error -//│ <: 'a0 -//│ 'a0 :> error //│ 'this :> Test1_1 @@ -282,87 +246,67 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.273: module Test2_1 { +//│ ║ l.237: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.274: fun t2 = Test2_2 +//│ ║ l.238: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.275: fun a = Test2_2.b +//│ ║ l.239: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.276: fun d = Test2_2.e +//│ ║ l.240: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.277: fun n = 456 +//│ ║ l.241: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.278: } +//│ ║ l.242: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.273: module Test2_1 { +//│ ║ l.237: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.274: fun t2 = Test2_2 +//│ ║ l.238: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.275: fun a = Test2_2.b +//│ ║ l.239: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.276: fun d = Test2_2.e +//│ ║ l.240: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.277: fun n = 456 +//│ ║ l.241: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.278: } +//│ ║ l.242: } //│ ╙── ^ //│ //│ namespace Test2_1() { //│ this: 'this -//│ fun a: 'b -//│ fun d: 'e +//│ fun a: 123 +//│ fun d: error //│ fun n: 456 //│ fun t2: Test2_2 //│ } //│ namespace Test2_2() { //│ this: 'this0 //│ fun b: 123 -//│ fun c: 'a -//│ fun e: 'n +//│ fun c: error +//│ fun e: error //│ } //│ where -//│ 'n :> error -//│ <: 'e0 -//│ 'e0 :> error -//│ 'a :> error -//│ <: 'c -//│ 'c :> error //│ 'this0 :> Test2_2 -//│ 'e :> error -//│ <: 'd -//│ 'd :> error -//│ 'b :> 123 -//│ <: 'a0 -//│ 'a0 :> 123 //│ 'this :> Test2_1 Test2_1.t2.b //│ -//│ 'b -//│ where -//│ 'b :> 123 +//│ 123 //│ Typed: 123 Test2_1.a //│ -//│ 'a -//│ where -//│ 'a :> 123 +//│ 123 //│ Typed: 123 // FIXME Test2_1.d //│ -//│ 'd -//│ where -//│ 'd :> error +//│ error //│ Typed: error Test2_1.n //│ -//│ 'n -//│ where -//│ 'n :> 456 +//│ 456 //│ Typed: 456 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 5ad4dbc7bb..b6c21ff5ac 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -10,6 +10,7 @@ mixin Over { //│ mixin Over() { //│ super: 'super //│ this: 'this +//│ fun p: "hi" //│ } @@ -21,22 +22,16 @@ class Base1(p: int): Over { //│ class Base1(p: int) { //│ this: 'this //│ fun p: "hi" -//│ fun test: (int, 'p,) +//│ fun test: (int, "hi" | 'p,) //│ } //│ where -//│ 'p :> 'p0 //│ 'this :> Base1 -//│ <: {p: 'p0} -//│ 'p0 :> "hi" +//│ <: {p: 'p} Base1(123).test //│ -//│ 'test -//│ where -//│ 'test :> (int, 'p,) -//│ 'p :> 'p0 -//│ 'p0 :> "hi" +//│ (int, "hi",) //│ Typed: (int, "hi",) // TODO diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index d6498a2c87..5f70d59291 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -499,10 +499,11 @@ class DiffTests val vars: Map[Str, typer.SimpleType] = Map.empty val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx.nest, raise, vars) - tpd.force()(raise) + val comp = tpd.force()(raise) tpd.entities.foreach { e => e.complete()(raise) match { + // comp.entities.foreach { case tf: typer.TypedNuFun => val sign = typer.PolymorphicType.mk(ctx.lvl, tf.ty) ctx += tf.fd.nme.name -> typer.VarSymbol(sign, tf.fd.nme) @@ -514,7 +515,6 @@ class DiffTests } } - val exp = typer.expandType(tpd)(ctx) // output(exp.toString) // val sctx = ShowCtx.mk(tpd) @@ -557,6 +557,17 @@ class DiffTests } } + val sim = if (mode.noSimplification) comp else try { + typer.dbg = mode.dbgSimplif + object SimplifyPipeline extends typer.SimplifyPipeline { + def debugOutput(msg: => Str): Unit = + if (mode.dbgSimplif) output(msg) + } + SimplifyPipeline(comp, all = false)(ctx) + } finally typer.dbg = false + + val exp = typer.expandType(sim)(ctx) + output(exp.show) // val exp = getType(typer.PolymorphicType(0, res_ty)) From c5c64839511b17e4025ff762d2cf442475c519cd Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 13:53:19 +0800 Subject: [PATCH 060/498] WIP finish simplif passes progress --- .../main/scala/mlscript/TypeSimplifier.scala | 10 +-- shared/src/test/diff/nu/BasicClasses.mls | 10 +-- shared/src/test/diff/nu/BasicMixins.mls | 4 +- shared/src/test/diff/nu/ECOOP23.mls | 64 ++++++++----------- shared/src/test/diff/nu/ECOOP23_min.mls | 32 +++++----- shared/src/test/diff/nu/ECOOP23_repro.mls | 33 +++++----- shared/src/test/diff/nu/GenericClasses.mls | 28 ++++---- 7 files changed, 85 insertions(+), 96 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index c9db042864..faa2b50185 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -346,9 +346,9 @@ trait TypeSimplifier { self: Typer => } } - def goLike(ty: TL, pol: Opt[Bool], canDistribForall: Opt[Level] = N): ST = trace(s"normLike[${printPol(pol)}] $ty") { ty match { - case ty: ST => - go(ty, pol) + def goLike(ty: TL, pol: Opt[Bool], canDistribForall: Opt[Level] = N): TL = trace(s"normLike[${printPol(pol)}] $ty") { ty match { + case ty: ST => go(ty, pol) + case OtherTypeLike(tu) => tu.mapPol(pol, true)((p, t) => go(t, p)) }}() def go(ty: ST, pol: Opt[Bool], canDistribForall: Opt[Level] = N): ST = trace(s"norm[${printPol(pol)}] $ty") { pol match { @@ -1123,7 +1123,7 @@ trait TypeSimplifier { self: Typer => // cur = factorRecursiveTypes_!(cur, approximateRecTypes = false) // debugOutput(s"⬤ Factored: ${cur}") // debugOutput(s" where: ${cur.showBounds}") - if (all) { + cur = normalizeTypes_!(cur) debugOutput(s"⬤ Normalized: ${cur}") debugOutput(s" where: ${cur.showBounds}") @@ -1147,7 +1147,7 @@ trait TypeSimplifier { self: Typer => cur = factorRecursiveTypes_!(cur, approximateRecTypes = false) debugOutput(s"⬤ Factored: ${cur}") debugOutput(s" where: ${cur.showBounds}") - } + cur } } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index cae7db9af7..9858afee14 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -26,7 +26,7 @@ fun f(x: A) = if x is A then x.n fun f(x: A | 'b) = if x is A then x.n else 0 //│ -//│ fun f: (x: (anything,),) -> (int | 0) +//│ fun f: (x: (anything,),) -> int fun f(x) = x.n @@ -49,11 +49,11 @@ f(a) fun f(x) = if x is A then x.n else 0 //│ -//│ fun f: anything -> (int | 0) +//│ fun f: anything -> int f(a) //│ -//│ int | 0 +//│ int //│ Typed: int @@ -128,11 +128,11 @@ class Base1(base: int) { //│ this: 'this //│ fun foo: int -> int //│ fun getBase1: int -//│ fun getBase2: int | 'base +//│ fun getBase2: int //│ } //│ where //│ 'this :> Base1 -//│ <: {base: 'base & int} +//│ <: {base: int} class Base1(base: int) { fun getBase1 = base diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index b71a2c2cb2..5cea03d187 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -40,7 +40,7 @@ class Base1(base: int): BaseTest, BaseInc { //│ this: 'this //│ fun test: int //│ fun test2: int -//│ fun test3: (int, int | 'base,) +//│ fun test3: (int, 'base | int,) //│ } //│ where //│ 'this :> Base1 @@ -233,7 +233,7 @@ WrapBase1.wrapA("ok") //│ ║ l.158: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ -//│ error | (int,) +//│ (int,) | error //│ Typed: (int,) | error diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 5244709255..336b777a9c 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -34,7 +34,7 @@ fun eval(e) = //│ //│ fun eval: 'a -> int //│ where -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'a <: Add & {Add#E = 'E} | Lit //│ 'E <: 'a @@ -48,7 +48,7 @@ mixin EvalBase { //│ mixin EvalBase() { //│ super: 'super //│ this: 'this -//│ fun eval: (Lit | Add & {Add#E = 'E} & ~Lit) -> int +//│ fun eval: (Add & {Add#E = 'E} | Lit) -> int //│ } //│ where //│ 'E <: 'lhs @@ -62,7 +62,7 @@ module TestLang: EvalBase //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'a <: Add & {Add#E = 'E} | Lit //│ 'E <: 'a //│ 'this :> TestLang @@ -70,7 +70,7 @@ TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'a <: Add & {Add#E = 'E} | Lit //│ 'E <: 'a //│ Typed: 'a -> int //│ where @@ -124,18 +124,18 @@ module TestLang: EvalBase, EvalNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg -//│ 'E <: 'a +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} //│ 'A <: 'a +//│ 'E <: 'a //│ 'this :> TestLang TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg -//│ 'E <: 'a +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} //│ 'A <: 'a +//│ 'E <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} @@ -190,29 +190,26 @@ mixin EvalNegNeg { //│ } //│ where //│ 'A :> 'A0 -//│ <: (Neg & {Neg#A = 'A1} | ~Neg) & 'A2 -//│ 'A1 :> 'A3 +//│ <: 'A1 & (~Neg | Neg & {Neg#A = 'A2}) +//│ 'A2 :> 'A3 //│ <: 'expr //│ 'this <: {eval: 'expr -> 'b} -//│ 'super <: {eval: (Neg & {Neg#A :> (Neg & {Neg#A :> 'expr <: 'expr & 'A3} | ~Neg) & 'A0 <: 'A0 | 'A2}) -> 'b & 'a -> 'b} +//│ 'super <: {eval: (Neg & {Neg#A :> 'A0 & (~Neg | Neg & {Neg#A :> 'expr <: 'expr & 'A3}) <: 'A0 | 'A1} | 'a) -> 'b} module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ //│ namespace TestLang() { //│ this: 'this -//│ fun eval: 'a -> 'b +//│ fun eval: 'a -> int //│ } //│ where -//│ 'b :> int -//│ 'a <: Neg & {Neg#A = 'A} | (Neg & {Neg#A = 'A0} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg) & ~Neg -//│ 'E <: 'a +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} //│ 'A :> 'A0 -//│ <: (Neg & {Neg#A = 'A1} | ~Neg) & 'A0 -//│ 'A1 :> 'A2 -//│ <: 'A3 -//│ 'A0 <: 'a & (Neg & {Neg#A :> 'A3 <: 'A2} | ~Neg) -//│ 'A2 <: 'A3 -//│ 'A3 <: 'a +//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) +//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a +//│ 'A1 <: 'A2 +//│ 'A2 <: 'a +//│ 'E <: 'a //│ 'this :> TestLang fun mk(n) = if n is @@ -222,24 +219,21 @@ fun mk(n) = if n is //│ //│ fun mk: number -> (Lit | 'a) //│ where -//│ 'a :> Add & {Add#E = 'E} | Neg & {Neg#A = 'A} -//│ 'A :> Lit | 'a +//│ 'a :> Neg & {Neg#A = 'A} | Add & {Add#E = 'E} //│ 'E :> Lit | 'a +//│ 'A :> Lit | 'a TestLang.eval //│ -//│ 'a -> 'b +//│ 'a -> int //│ where -//│ 'b :> int -//│ 'a <: Neg & {Neg#A = 'A} | (Neg & {Neg#A = 'A0} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg) & ~Neg -//│ 'E <: 'a +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} //│ 'A :> 'A0 -//│ <: (Neg & {Neg#A = 'A1} | ~Neg) & 'A0 -//│ 'A1 :> 'A2 -//│ <: 'A3 -//│ 'A0 <: 'a & (Neg & {Neg#A :> 'A3 <: 'A2} | ~Neg) -//│ 'A2 <: 'A3 -//│ 'A3 <: 'a +//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) +//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a +//│ 'A1 <: 'A2 +//│ 'A2 <: 'a +//│ 'E <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} @@ -252,9 +246,7 @@ TestLang.eval TestLang.eval(mk(0)) //│ -//│ 'a -//│ where -//│ 'a :> int +//│ int //│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index 4b1f7373a5..fe372cc79c 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -22,19 +22,19 @@ let e = Add(1, 1) e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α33 +//│ | 0. : α35 //│ ======== TYPED ======== -//│ res: Some(α33) where -//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) -//│ E23_34 :> 1 +//│ res: Some(α35) where +//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) +//│ E23_36 :> 1 //│ //│ Add & {Add#E = 'E} //│ where //│ 'E :> 1 -//│ ⬤ Typed as: ‹∀ 0. α33› +//│ ⬤ Typed as: ‹∀ 0. α35› //│ where: -//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) -//│ E23_34 :> 1 +//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) +//│ E23_36 :> 1 //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> 1 @@ -48,21 +48,21 @@ e.lhs e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α33 +//│ | 0. : α35 //│ ======== TYPED ======== -//│ res: Some(α33) where -//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) <: {lhs: lhs45} -//│ E23_34 :> 1 <: lhs45 -//│ lhs45 :> 1 +//│ res: Some(α35) where +//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) <: {lhs: lhs49} +//│ E23_36 :> 1 <: lhs49 +//│ lhs49 :> 1 //│ //│ Add & {Add#E = 'E} //│ where //│ 'E :> 1 -//│ ⬤ Typed as: ‹∀ 0. α33› +//│ ⬤ Typed as: ‹∀ 0. α35› //│ where: -//│ α33 :> (Add<> & {Add#E: mut E23_34..E23_34}) <: {lhs: lhs45} -//│ E23_34 :> 1 <: lhs45 -//│ lhs45 :> 1 +//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) <: {lhs: lhs49} +//│ E23_36 :> 1 <: lhs49 +//│ lhs49 :> 1 //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> 1 diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 508df75429..33712d0286 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -29,7 +29,7 @@ fun eval(e) = //│ //│ fun eval: 'a -> int //│ where -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'a <: Add & {Add#E = 'E} | Lit //│ 'E <: 'a @@ -43,7 +43,7 @@ mixin EvalBase { //│ mixin EvalBase() { //│ super: 'super //│ this: 'this -//│ fun eval: (Lit | Add & {Add#E = 'E} & ~Lit) -> int +//│ fun eval: (Add & {Add#E = 'E} | Lit) -> int //│ } //│ where //│ 'E <: 'lhs @@ -57,7 +57,7 @@ module TestLang: EvalBase //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'a <: Add & {Add#E = 'E} | Lit //│ 'E <: 'a //│ 'this :> TestLang @@ -65,7 +65,7 @@ TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ 'a <: Add & {Add#E = 'E} | Lit //│ 'E <: 'a //│ Typed: 'a -> int //│ where @@ -93,8 +93,7 @@ add11 //│ Add & {Add#E = 'E} //│ where //│ 'E :> Lit -//│ <: 'a -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ <: Add & {Add#E = 'E} | Lit //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> Lit @@ -110,8 +109,7 @@ add11 //│ Add & {Add#E = 'E} //│ where //│ 'E :> Lit -//│ <: 'a -//│ 'a <: Lit | Add & {Add#E = 'E} & ~Lit +//│ <: Add & {Add#E = 'E} | Lit //│ Typed: Add & {Add#E = 'E} //│ where //│ 'E :> Lit @@ -134,8 +132,7 @@ let add2negadd11 = Add(Lit(2), Neg(add11)) //│ 'E :> Lit | Neg & {Neg#A = 'A} //│ 'A :> Add & {Add#E = 'E0} //│ 'E0 :> Lit -//│ <: 'a -//│ 'a <: Lit | Add & {Add#E = 'E0} & ~Lit +//│ <: Add & {Add#E = 'E0} | Lit mixin EvalNeg { @@ -162,18 +159,18 @@ module TestLang: EvalBase, EvalNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg -//│ 'E <: 'a +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} //│ 'A <: 'a +//│ 'E <: 'a //│ 'this :> TestLang TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Neg & {Neg#A = 'A} | (Lit | Add & {Add#E = 'E} & ~Lit) & ~Neg -//│ 'E <: 'a +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} //│ 'A <: 'a +//│ 'E <: 'a //│ Typed: 'a -> int //│ where //│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} @@ -205,10 +202,10 @@ TestLang.eval(Neg(Neg(add11))) :e TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.206: TestLang.eval(add2negadd11) +//│ ║ l.203: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.130: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.128: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.38: if e is @@ -223,10 +220,10 @@ TestLang.eval(add2negadd11) :e TestLang.eval(Add(Lit(2), Neg(add11))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.224: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ║ l.221: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` -//│ ║ l.130: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ l.128: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.38: if e is diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index f894136fff..a4caaf2b4a 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -84,13 +84,13 @@ type Option = Some | None let opt = if true then Some(123) else None //│ -//│ let opt: Some & {Some#A = 'A} | None +//│ let opt: None | Some & {Some#A = 'A} //│ where //│ 'A :> 123 opt.toArray //│ -//│ (123,) | () +//│ Array[123] //│ Typed: Array[123] @@ -104,12 +104,12 @@ opt.toArray if opt is Some then opt.value else 0 //│ -//│ 123 | 0 +//│ 0 | 123 //│ Typed: 0 | 123 if opt is Some(v) then v else 0 //│ -//│ 123 | 0 +//│ 0 | 123 //│ Typed: 0 | 123 @@ -117,7 +117,7 @@ fun map(x, f) = if x is None then None Some(v) then Some(f(v)) //│ -//│ fun map: (None | Some & {Some#A = 'A} & ~None, 'A -> 'A0,) -> (None | Some & {Some#A = 'A0}) +//│ fun map: (None | Some & {Some#A = 'A}, 'A -> 'A0,) -> (None | Some & {Some#A = 'A0}) let mo = map(opt, succ) //│ @@ -127,7 +127,7 @@ let mo = map(opt, succ) mo.toArray //│ -//│ () | (int,) +//│ Array[int] //│ Typed: Array[int] @@ -163,7 +163,7 @@ Test(true) //│ ║ l.135: class Test(n) { //│ ╙── ^ //│ -//│ error | Test +//│ Test | error //│ Typed: Test | error @@ -183,7 +183,7 @@ class Test(n: A) { //│ //│ class Test[A](n: A) { //│ this: 'this -//│ fun foo: int | error +//│ fun foo: error | int //│ } //│ where //│ 'this :> Test @@ -249,14 +249,14 @@ let t = Test(1) t.foo1(true) //│ -//│ true | 1 +//│ 1 | true //│ Typed: 1 | true t : Test<'a> //│ //│ Test['a] //│ where -//│ 'a :> true | 1 +//│ 'a :> 1 | true //│ Typed: Test['a] //│ where //│ 'a :> 1 | true @@ -290,7 +290,7 @@ class Test { //│ class Test[A]() { //│ this: 'this //│ fun foo1: (x: A,) -> A -//│ fun foo2: (x: A,) -> (int | error) +//│ fun foo2: (x: A,) -> (error | int) //│ } //│ where //│ 'this :> Test @@ -338,11 +338,11 @@ t fun foo(x: Test) = x.foo1 //│ -//│ fun foo: (x: Test[int],) -> (x: int & 'A,) -> (int | 'A) +//│ fun foo: (x: Test[int],) -> (x: int,) -> int foo(t) //│ -//│ (x: int & 'A,) -> (int | 'A) +//│ (x: int,) -> int //│ Typed: (x: int,) -> int foo(t)(1) @@ -353,7 +353,7 @@ foo(t)(1) Test().foo2 //│ -//│ (x: anything,) -> (int | error) +//│ (x: anything,) -> (error | int) //│ Typed: (x: anything,) -> (error | int) From 35d96737574883c76afd49c6da7e0388a968b1e3 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 20:28:55 +0800 Subject: [PATCH 061/498] WIP Reconstruct new class types too --- .../main/scala/mlscript/TypeSimplifier.scala | 84 +++++++++++++++++++ shared/src/test/diff/nu/BasicClasses.mls | 21 +++-- shared/src/test/diff/nu/ECOOP23.mls | 68 +++++++-------- shared/src/test/diff/nu/ECOOP23_min.mls | 16 ++-- shared/src/test/diff/nu/ECOOP23_repro.mls | 56 ++++++------- shared/src/test/diff/nu/GenericClasses.mls | 36 ++++---- 6 files changed, 183 insertions(+), 98 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index faa2b50185..8c73c21049 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -272,6 +272,90 @@ trait TypeSimplifier { self: Typer => trs3.valuesIterator.foldLeft(withTraits)(_ & _) + case S(cls @ ClassTag(Var(clsNme), ps)) + if !primitiveTypes.contains(clsNme) + && ctx.tyDefs2.contains(clsNme) + && ctx.tyDefs2(clsNme).result.isDefined + => + val clsTyNme = TypeName(clsNme) + val lti = ctx.tyDefs2(clsNme) + val defn = lti.result.getOrElse(die) + val cls = defn.asInstanceOf[TypedNuCls] + + val rcdMap = rcd.fields.toMap + + val rcd2 = rcd.copy(rcd.fields.mapValues(_.update(go(_, pol.map(!_)), go(_, pol))))(rcd.prov) + println(s"rcd2 ${rcd2}") + + val vs = + // td.getVariancesOrDefault + Map.empty[TV, VarianceInfo].withDefaultValue(VarianceInfo.in) + + // * Reconstruct a TypeRef from its current structural components + val typeRef = TypeRef(cls.td.nme, cls.tparams.zipWithIndex.map { case ((tp, tv), tpidx) => + val fieldTagNme = tparamField(clsTyNme, tp) + val fromTyRef = trs2.get(clsTyNme).map(_.targs(tpidx) |> { ta => FieldType(S(ta), ta)(noProv) }) + fromTyRef.++(rcd2.fields.iterator.filter(_._1 === fieldTagNme).map(_._2)) + .foldLeft((BotType: ST, TopType: ST)) { + case ((acc_lb, acc_ub), FieldType(lb, ub)) => + (acc_lb | lb.getOrElse(BotType), acc_ub & ub) + }.pipe { + case (lb, ub) => + vs(tv) match { + case VarianceInfo(true, true) => TypeBounds.mk(BotType, TopType) + case VarianceInfo(false, false) => TypeBounds.mk(lb, ub) + case VarianceInfo(co, contra) => + if (co) ub else lb + } + } + })(noProv) + println(s"typeRef ${typeRef}") + + val clsFields = fieldsOf(typeRef.expandWith(paramTags = true), paramTags = true) + println(s"clsFields ${clsFields.mkString(", ")}") + + val cleanPrefixes = ps.map(_.name.capitalize) + clsNme ++ traitPrefixes + + val cleanedRcd = RecordType( + rcd2.fields.filterNot { case (field, fty) => + // * This is a bit messy, but was the only way I was able to achieve maximal simplification: + // * We remove fields that are already inclued by definition of the class by testing for subtyping + // * with BOTH the new normalized type (from `clsFields`) AND the old one too (from `rcdMap`). + // * The reason there's a difference is probably because: + // * - Subtye checking with <:< is an imperfect heuristic and may stop working after normalizing. + // * - Recursive types will be normalized progressively... + // * at this point we may look at some bounds that have not yet been normalized. + clsFields.get(field).exists(cf => cf <:< fty || + rcdMap.get(field).exists(cf <:< _)) + } + )(rcd2.prov) + + val rcd2Fields = rcd2.fields.unzip._1.toSet + + // // * Which fields were NOT part of the original type, + // // * and should therefore be excluded from the reconstructed TypeRef: + // val removedFields = clsFields.keysIterator + // .filterNot(field => field.name.isCapitalized || rcd2Fields.contains(field)).toSortedSet + // val withoutType = if (removedFields.isEmpty) typeRef + // else typeRef.without(removedFields) + + // // * Whether we need a `with` (which overrides field types) + // // * as opposed to simply an intersection (which refines them): + // val needsWith = !rcd2.fields.forall { + // case (field, fty) => + // clsFields.get(field).forall(cf => fty <:< cf || rcdMap.get(field).exists(_ <:< cf)) + // } + // val withType = if (needsWith) if (cleanedRcd.fields.isEmpty) withoutType + // else WithType(withoutType, cleanedRcd.sorted)(noProv) else typeRef & cleanedRcd.sorted + + val withTraits = tts.toArray.sorted // TODO also filter out tts that are inherited by the class + .foldLeft(typeRef & cleanedRcd: ST)(_ & _) + + val trs3 = trs2 - cls.nme // TODO also filter out class refs that are inherited by the class + + trs3.valuesIterator.foldLeft(withTraits)(_ & _) + + case _ => lazy val nFields = rcd.fields .filterNot(traitPrefixes contains _._1.name.takeWhile(_ =/= '#')) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 9858afee14..e8cb14090d 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -11,6 +11,11 @@ class A(n: int) //│ where //│ 'this :> A +A +//│ +//│ (n: int,) -> A +//│ Typed: (n: int,) -> A + let a = A(42) //│ //│ let a: A @@ -177,7 +182,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.178: b.getBaseTypo +//│ ║ l.183: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ //│ error @@ -195,11 +200,11 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.194: class Rec(n) { +//│ ║ l.199: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.195: fun go = Rec(n + 1) +//│ ║ l.200: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.196: } +//│ ║ l.201: } //│ ╙── ^ //│ //│ class Rec(n: nothing) { @@ -218,16 +223,16 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.217: a: int +//│ ║ l.222: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.216: class Annots(base: 0 | 1) { +//│ ║ l.221: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.217: a: int +//│ ║ l.222: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.217: a: int +//│ ║ l.222: a: int //│ ╙── ^^^ //│ //│ class Annots(base: (0 | 1,)) { diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 336b777a9c..2b7d7d4dd5 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -14,11 +14,11 @@ class Lit(n: int) //│ } //│ where //│ 'this0 :> Lit -//│ 'this :> Add +//│ 'this :> Add[?] fun add11 = Add(Lit(1), Lit(2)) //│ -//│ fun add11: Add & {Add#E = 'E} +//│ fun add11: Add['E] //│ where //│ 'E :> Lit @@ -34,7 +34,7 @@ fun eval(e) = //│ //│ fun eval: 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a @@ -48,7 +48,7 @@ mixin EvalBase { //│ mixin EvalBase() { //│ super: 'super //│ this: 'this -//│ fun eval: (Add & {Add#E = 'E} | Lit) -> int +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where //│ 'E <: 'lhs @@ -62,7 +62,7 @@ module TestLang: EvalBase //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a //│ 'this :> TestLang @@ -70,11 +70,11 @@ TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a //│ Typed: 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a TestLang.eval(add11) @@ -89,14 +89,14 @@ class Neg(expr: A) //│ this: 'this //│ } //│ where -//│ 'this :> Neg +//│ 'this :> Neg[?] let add2negadd11 = Add(Lit(2), Neg(add11)) //│ -//│ let add2negadd11: Add & {Add#E = 'E} +//│ let add2negadd11: Add['E] //│ where -//│ 'E :> Lit | Neg & {Neg#A = 'A} -//│ 'A :> forall 'E0. Add & {Add#E = 'E0} +//│ 'E :> Lit | Neg['A] +//│ 'A :> forall 'E0. Add['E0] //│ 'E0 :> Lit @@ -109,7 +109,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: 'super //│ this: 'this -//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } //│ where //│ 'A <: 'expr @@ -124,7 +124,7 @@ module TestLang: EvalBase, EvalNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a //│ 'this :> TestLang @@ -133,12 +133,12 @@ TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a //│ Typed: 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a @@ -186,15 +186,14 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: 'super //│ this: 'this -//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> 'b +//│ fun eval: (Neg['A] | 'a & ~Neg) -> 'b //│ } //│ where //│ 'A :> 'A0 -//│ <: 'A1 & (~Neg | Neg & {Neg#A = 'A2}) -//│ 'A2 :> 'A3 -//│ <: 'expr +//│ <: 'A1 & (~Neg | Neg['A2]) +//│ 'A2 <: 'expr //│ 'this <: {eval: 'expr -> 'b} -//│ 'super <: {eval: (Neg & {Neg#A :> 'A0 & (~Neg | Neg & {Neg#A :> 'expr <: 'expr & 'A3}) <: 'A0 | 'A1} | 'a) -> 'b} +//│ 'super <: {eval: (Neg[in 'A0 & (~Neg | Neg[in 'expr out nothing]) out 'A0 | 'A1] & {Neg#A :> 'A0 & (~Neg | Neg[in 'expr out nothing]) <: 'A0 | 'A1} | 'a) -> 'b} module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ @@ -203,12 +202,11 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) -//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a -//│ 'A1 <: 'A2 -//│ 'A2 <: 'a +//│ <: 'A0 & (~Neg | Neg['A1]) +//│ 'A1 <: 'a +//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a //│ 'E <: 'a //│ 'this :> TestLang @@ -219,7 +217,7 @@ fun mk(n) = if n is //│ //│ fun mk: number -> (Lit | 'a) //│ where -//│ 'a :> Neg & {Neg#A = 'A} | Add & {Add#E = 'E} +//│ 'a :> Neg['A] | Add['E] //│ 'E :> Lit | 'a //│ 'A :> Lit | 'a @@ -227,21 +225,19 @@ TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) -//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a -//│ 'A1 <: 'A2 -//│ 'A2 <: 'a +//│ <: 'A0 & (~Neg | Neg['A1]) +//│ 'A1 <: 'a +//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a //│ 'E <: 'a //│ Typed: 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) -//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a -//│ 'A1 <: 'A2 -//│ 'A2 <: 'a +//│ <: 'A0 & (~Neg | Neg['A1]) +//│ 'A1 <: 'a +//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a //│ 'E <: 'a TestLang.eval(mk(0)) diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index fe372cc79c..ab461da9d3 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -10,11 +10,11 @@ class Add(lhs: E, rhs: E) //│ this: 'this //│ } //│ where -//│ 'this :> Add +//│ 'this :> Add[?] let e = Add(1, 1) //│ -//│ let e: Add & {Add#E = 'E} +//│ let e: Add['E] //│ where //│ 'E :> 1 @@ -28,14 +28,14 @@ e //│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) //│ E23_36 :> 1 //│ -//│ Add & {Add#E = 'E} +//│ Add['E] //│ where //│ 'E :> 1 //│ ⬤ Typed as: ‹∀ 0. α35› //│ where: //│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) //│ E23_36 :> 1 -//│ Typed: Add & {Add#E = 'E} +//│ Typed: Add['E] //│ where //│ 'E :> 1 @@ -55,7 +55,7 @@ e //│ E23_36 :> 1 <: lhs49 //│ lhs49 :> 1 //│ -//│ Add & {Add#E = 'E} +//│ Add['E] //│ where //│ 'E :> 1 //│ ⬤ Typed as: ‹∀ 0. α35› @@ -63,17 +63,17 @@ e //│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) <: {lhs: lhs49} //│ E23_36 :> 1 <: lhs49 //│ lhs49 :> 1 -//│ Typed: Add & {Add#E = 'E} +//│ Typed: Add['E] //│ where //│ 'E :> 1 Add(2, 2) //│ -//│ Add & {Add#E = 'E} +//│ Add['E] //│ where //│ 'E :> 2 -//│ Typed: Add & {Add#E = 'E} +//│ Typed: Add['E] //│ where //│ 'E :> 2 diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 33712d0286..1164a839b8 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -14,11 +14,11 @@ class Lit(n: int) //│ } //│ where //│ 'this0 :> Lit -//│ 'this :> Add +//│ 'this :> Add[?] let add11 = Add(Lit(1), Lit(2)) //│ -//│ let add11: Add & {Add#E = 'E} +//│ let add11: Add['E] //│ where //│ 'E :> Lit @@ -29,7 +29,7 @@ fun eval(e) = //│ //│ fun eval: 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a @@ -43,7 +43,7 @@ mixin EvalBase { //│ mixin EvalBase() { //│ super: 'super //│ this: 'this -//│ fun eval: (Add & {Add#E = 'E} | Lit) -> int +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where //│ 'E <: 'lhs @@ -57,7 +57,7 @@ module TestLang: EvalBase //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a //│ 'this :> TestLang @@ -65,21 +65,21 @@ TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a //│ Typed: 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit +//│ 'a <: Add['E] | Lit //│ 'E <: 'a add11 //│ -//│ Add & {Add#E = 'E} +//│ Add['E] //│ where //│ 'E :> Lit -//│ Typed: Add & {Add#E = 'E} +//│ Typed: Add['E] //│ where //│ 'E :> Lit @@ -90,14 +90,14 @@ TestLang.eval(add11) add11 //│ -//│ Add & {Add#E = 'E} +//│ Add['E] //│ where //│ 'E :> Lit -//│ <: Add & {Add#E = 'E} | Lit -//│ Typed: Add & {Add#E = 'E} +//│ <: Add['E] | Lit +//│ Typed: Add['E] //│ where //│ 'E :> Lit -//│ <: Add & {Add#E = 'E} | Lit +//│ <: Add['E] | Lit TestLang.eval(add11) //│ @@ -106,14 +106,14 @@ TestLang.eval(add11) add11 //│ -//│ Add & {Add#E = 'E} +//│ Add['E] //│ where //│ 'E :> Lit -//│ <: Add & {Add#E = 'E} | Lit -//│ Typed: Add & {Add#E = 'E} +//│ <: Add['E] | Lit +//│ Typed: Add['E] //│ where //│ 'E :> Lit -//│ <: Add & {Add#E = 'E} | Lit +//│ <: Add['E] | Lit @@ -123,16 +123,16 @@ class Neg(expr: A) //│ this: 'this //│ } //│ where -//│ 'this :> Neg +//│ 'this :> Neg[?] let add2negadd11 = Add(Lit(2), Neg(add11)) //│ -//│ let add2negadd11: Add & {Add#E = 'E} +//│ let add2negadd11: Add['E] //│ where -//│ 'E :> Lit | Neg & {Neg#A = 'A} -//│ 'A :> Add & {Add#E = 'E0} +//│ 'E :> Lit | Neg['A] +//│ 'A :> Add['E0] //│ 'E0 :> Lit -//│ <: Add & {Add#E = 'E0} | Lit +//│ <: Add['E0] | Lit mixin EvalNeg { @@ -144,7 +144,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: 'super //│ this: 'this -//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } //│ where //│ 'A <: 'expr @@ -159,7 +159,7 @@ module TestLang: EvalBase, EvalNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a //│ 'this :> TestLang @@ -168,12 +168,12 @@ TestLang.eval //│ //│ 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a //│ Typed: 'a -> int //│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a @@ -204,7 +204,7 @@ TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.203: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` +//│ ╟── application of type `Neg[?A]` does not match type `Add[?E] | Lit` //│ ║ l.128: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: @@ -222,7 +222,7 @@ TestLang.eval(Add(Lit(2), Neg(add11))) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.221: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Neg & {Neg#A = ?A}` does not match type `Add & {Add#E = ?E} | Lit` +//│ ╟── application of type `Neg[?A]` does not match type `Add[?E] | Lit` //│ ║ l.128: let add2negadd11 = Add(Lit(2), Neg(add11)) //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index a4caaf2b4a..df64e981f6 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -16,12 +16,12 @@ class Some(value: A) { //│ fun toArray: (A,) //│ } //│ where -//│ 'this :> Some +//│ 'this :> Some[?] let s = Some(1) //│ -//│ let s: Some & {Some#A = 'A} +//│ let s: Some['A] //│ where //│ 'A :> 1 @@ -84,7 +84,7 @@ type Option = Some | None let opt = if true then Some(123) else None //│ -//│ let opt: None | Some & {Some#A = 'A} +//│ let opt: None | Some['A] //│ where //│ 'A :> 123 @@ -117,11 +117,11 @@ fun map(x, f) = if x is None then None Some(v) then Some(f(v)) //│ -//│ fun map: (None | Some & {Some#A = 'A}, 'A -> 'A0,) -> (None | Some & {Some#A = 'A0}) +//│ fun map: (None | Some['A], 'A -> 'A0,) -> (None | Some['A0]) let mo = map(opt, succ) //│ -//│ let mo: None | Some & {Some#A = 'A} +//│ let mo: None | Some['A] //│ where //│ 'A :> int @@ -186,23 +186,23 @@ class Test(n: A) { //│ fun foo: error | int //│ } //│ where -//│ 'this :> Test +//│ 'this :> Test[?] Test(1) //│ -//│ Test & {Test#A = 'A} +//│ Test['A] //│ where //│ 'A :> 1 -//│ Typed: Test & {Test#A = 'A} +//│ Typed: Test['A] //│ where //│ 'A :> 1 Test(true) //│ -//│ Test & {Test#A = 'A} +//│ Test['A] //│ where //│ 'A :> true -//│ Typed: Test & {Test#A = 'A} +//│ Typed: Test['A] //│ where //│ 'A :> true @@ -220,14 +220,14 @@ class Test(n: A) { //│ fun id: 'a -> 'a //│ } //│ where -//│ 'this :> Test +//│ 'this :> Test[?] Test(1) //│ -//│ Test & {Test#A = 'A} +//│ Test['A] //│ where //│ 'A :> 1 -//│ Typed: Test & {Test#A = 'A} +//│ Typed: Test['A] //│ where //│ 'A :> 1 @@ -243,7 +243,7 @@ Test("ok").foo let t = Test(1) //│ -//│ let t: Test & {Test#A = 'A} +//│ let t: Test['A] //│ where //│ 'A :> 1 @@ -293,7 +293,7 @@ class Test { //│ fun foo2: (x: A,) -> (error | int) //│ } //│ where -//│ 'this :> Test +//│ 'this :> Test[?] Test().foo1 //│ @@ -313,7 +313,7 @@ x => Test().foo1(x) // :d let t = Test() //│ -//│ let t: forall 'A. Test & {Test#A = 'A} +//│ let t: forall 'A. Test['A] t.foo1 //│ @@ -332,8 +332,8 @@ t.foo1(0) t //│ -//│ forall 'A. Test & {Test#A = 'A} -//│ Typed: Test & {Test#A = 'A} +//│ forall 'A. Test['A] +//│ Typed: Test['A] fun foo(x: Test) = x.foo1 From 7908b9b307b4009643bca590360f6521ef11f1f9 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 20:54:54 +0800 Subject: [PATCH 062/498] WIP Fix formatting of signatures, using indentation --- shared/src/main/scala/mlscript/helpers.scala | 32 ++-- shared/src/test/diff/nu/BasicClasses.mls | 98 ++++-------- shared/src/test/diff/nu/BasicMixins.mls | 123 +++++---------- shared/src/test/diff/nu/ECOOP23.mls | 84 +++------- shared/src/test/diff/nu/ECOOP23_min.mls | 33 +--- shared/src/test/diff/nu/ECOOP23_repro.mls | 92 +++-------- shared/src/test/diff/nu/GenericClasses.mls | 133 ++++------------ shared/src/test/diff/nu/GenericMixins.mls | 16 +- shared/src/test/diff/nu/MutualRec.mls | 147 ++++++------------ shared/src/test/diff/nu/ParamOverriding.mls | 16 +- .../src/test/scala/mlscript/DiffTests.scala | 18 ++- 11 files changed, 232 insertions(+), 560 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 97ca62095f..034495a2af 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -89,7 +89,8 @@ trait TypeLikeImpl extends Located { self: TypeLike => .mkString("forall ", " ", ".")} ${body.showIn(ctx, 1)}", outerPrec > 1 // or 0? ) - case Constrained(b, bs, ws) => parensIf(s"${b.showIn(ctx, 0)}\n where${bs.map { + case Constrained(b, bs, ws) => parensIf(s"${ + b.showIn(ctx, 0).stripSuffix("\n")}\n${ctx.indStr} where${bs.map { case (uv, Bounds(Bot, ub)) => s"\n ${ctx.vs(uv)} <: ${ub.showIn(ctx, 0)}" case (uv, Bounds(lb, Top)) => @@ -113,11 +114,16 @@ trait TypeLikeImpl extends Located { self: TypeLike => case R(ty) => ": " + ty.showIn(ctx, 0) }}" case Signature(decls, res) => - decls.map("\n" + _.showIn(ctx, 0)).mkString + (res match { - case S(ty) => "\n" + ty.showIn(ctx, 0) - case N => "" - }) + // decls.map(ctx.indStr + (if (ctx.indentLevel === 0) "" else "\n") + _.showIn(ctx, 0)).mkString + + (decls.map(ctx.indStr + _.showIn(ctx, 0) + "\n") ::: (res match { + case S(ty) => ctx.indStr + ty.showIn(ctx, 0) + "\n" :: Nil + case N => Nil + // })).mkString(if (ctx.indentLevel === 0) "" else "\n", "\n", "") + // })).mkString("\n") + // })).mkString("", "\n", "\n") + })).mkString case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => + val bodyCtx = ctx.indent s"${kind.str} ${nme.name}${tparams.map(_.showIn(ctx, 0))mkStringOr(", ", "[", "]")}(${ params.fields.map { case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) @@ -128,9 +134,10 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Nil => "" case ps => ps.mkString(", ") // TODO pp }}${if (body.entities.isEmpty && sup.isEmpty && ths.isEmpty) "" else - " {" + sup.fold("")("\nsuper: " + _.showIn(ctx, 0)) + - ths.fold("")("\nthis: " + _.showIn(ctx, 0)) + - Signature(body.entities.collect { case d: NuDecl => d }, N).showIn(ctx, 0) + "\n}" + " {\n" + sup.fold("")(s"${bodyCtx.indStr}super: " + _.showIn(bodyCtx, 0) + "\n") + + ths.fold("")(s"${bodyCtx.indStr}this: " + _.showIn(bodyCtx, 0) + "\n") + + Signature(body.entities.collect { case d: NuDecl => d }, N).showIn(bodyCtx, 0) + + ctx.indStr + "}" }" } @@ -226,7 +233,12 @@ trait TypeImpl extends Located { self: Type => } -final case class ShowCtx(vs: Map[TypeVar, Str], debug: Bool) // TODO make use of `debug` or rm +final case class ShowCtx(vs: Map[TypeVar, Str], debug: Bool, indentLevel: Int) // TODO make use of `debug` or rm +{ + lazy val indStr: Str = " " * indentLevel + def lnIndStr: Str = "\n" + indStr + def indent: ShowCtx = copy(indentLevel = indentLevel + 1) +} object ShowCtx { /** * Create a context from a list of types. For named variables and @@ -269,7 +281,7 @@ object ShowCtx { S(('a' + idx % numLetters).toChar.toString + (if (postfix === 0) "" else postfix.toString), idx + 1) }.filterNot(used).map(assignName) - ShowCtx(namedMap ++ unnamedVars.zip(names), debug) + ShowCtx(namedMap ++ unnamedVars.zip(names), debug, 0) } } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index e8cb14090d..76329ae174 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -4,62 +4,46 @@ class A(n: int) -//│ //│ class A(n: int) { -//│ this: 'this +//│ this: 'this //│ } //│ where //│ 'this :> A A -//│ //│ (n: int,) -> A -//│ Typed: (n: int,) -> A let a = A(42) -//│ //│ let a: A fun f(x: A) = x.n -//│ //│ fun f: (x: A,) -> int fun f(x: A) = if x is A then x.n -//│ //│ fun f: (x: A,) -> int fun f(x: A | 'b) = if x is A then x.n else 0 -//│ //│ fun f: (x: (anything,),) -> int fun f(x) = x.n -//│ //│ fun f: {n: 'n} -> 'n f(a) -//│ //│ int -//│ Typed: int fun f(x) = if x is A then x.n -//│ //│ fun f: A -> int f(a) -//│ //│ int -//│ Typed: int fun f(x) = if x is A then x.n else 0 -//│ //│ fun f: anything -> int f(a) -//│ //│ int -//│ Typed: int @@ -67,11 +51,10 @@ class C { fun id(x) = x fun const(x) = id } -//│ //│ class C() { -//│ this: 'this -//│ fun const: anything -> 'a -> 'a -//│ fun id: 'a -> 'a +//│ this: 'this +//│ fun const: anything -> 'a -> 'a +//│ fun id: 'a -> 'a //│ } //│ where //│ 'this :> C @@ -83,13 +66,12 @@ class Base0(n) { fun mine = my fun oops = this.my } -//│ //│ class Base0(n: nothing) { -//│ this: 'this -//│ fun me: 'this -//│ fun mine: 'n -//│ fun my: 'n -//│ fun oops: 'my +//│ this: 'this +//│ fun me: 'this +//│ fun mine: 'n +//│ fun my: 'n +//│ fun oops: 'my //│ } //│ where //│ 'this :> Base0 @@ -100,24 +82,19 @@ class Base0(n) { // Base0 let b1 = Base0(42) -//│ //│ let b1: Base0 // :d let n1 = b1.n -//│ //│ let n1: nothing // TODO n1 + 1 -//│ //│ int -//│ Typed: int let b2 = Base0("hi") let n2 = b2.n -//│ //│ let b2: Base0 //│ let n2: nothing @@ -128,12 +105,11 @@ class Base1(base: int) { fun getBase2 = this.base fun foo(x) = this.base + x } -//│ //│ class Base1(base: int) { -//│ this: 'this -//│ fun foo: int -> int -//│ fun getBase1: int -//│ fun getBase2: int +//│ this: 'this +//│ fun foo: int -> int +//│ fun getBase1: int +//│ fun getBase2: int //│ } //│ where //│ 'this :> Base1 @@ -144,55 +120,41 @@ class Base1(base: int) { fun me = this fun foo(x) = base + x } -//│ //│ class Base1(base: int) { -//│ this: 'this -//│ fun foo: int -> int -//│ fun getBase1: int -//│ fun me: 'this +//│ this: 'this +//│ fun foo: int -> int +//│ fun getBase1: int +//│ fun me: 'this //│ } //│ where //│ 'this :> Base1 Base1 -//│ //│ (base: int,) -> Base1 -//│ Typed: (base: int,) -> Base1 let b = Base1(1) -//│ //│ let b: Base1 b.base -//│ //│ int -//│ Typed: int b.getBase1 -//│ //│ int -//│ Typed: int // :d b.me -//│ //│ Base1 -//│ Typed: Base1 :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.183: b.getBaseTypo +//│ ║ l.149: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ -//│ //│ error -//│ Typed: error b : Base1 -//│ //│ Base1 -//│ Typed: Base1 :e // TODO @@ -200,16 +162,15 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.199: class Rec(n) { +//│ ║ l.161: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.200: fun go = Rec(n + 1) +//│ ║ l.162: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.201: } +//│ ║ l.163: } //│ ╙── ^ -//│ //│ class Rec(n: nothing) { -//│ this: 'this -//│ fun go: error +//│ this: 'this +//│ fun go: error //│ } //│ where //│ 'this :> Rec @@ -223,21 +184,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.222: a: int +//│ ║ l.183: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.221: class Annots(base: 0 | 1) { +//│ ║ l.182: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.222: a: int +//│ ║ l.183: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.222: a: int +//│ ║ l.183: a: int //│ ╙── ^^^ -//│ //│ class Annots(base: (0 | 1,)) { -//│ this: 'this -//│ fun a: (0 | 1,) +//│ this: 'this +//│ fun a: (0 | 1,) //│ } //│ where //│ 'this :> Annots diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 5cea03d187..acbfa748f8 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -7,11 +7,10 @@ mixin BaseTest { fun test = super.base } -//│ //│ mixin BaseTest() { -//│ super: 'super -//│ this: 'this -//│ fun test: 'base +//│ super: 'super +//│ this: 'this +//│ fun test: 'base //│ } //│ where //│ 'super <: {base: 'base} @@ -20,12 +19,11 @@ mixin BaseInc { fun test = super.base + 1 fun test2 = this.base } -//│ //│ mixin BaseInc() { -//│ super: 'super -//│ this: 'this -//│ fun test: int -//│ fun test2: 'base +//│ super: 'super +//│ this: 'this +//│ fun test: int +//│ fun test2: 'base //│ } //│ where //│ 'this <: {base: 'base} @@ -35,61 +33,49 @@ mixin BaseInc { class Base1(base: int): BaseTest, BaseInc { fun test3 = [base, this.base] } -//│ //│ class Base1(base: int) { -//│ this: 'this -//│ fun test: int -//│ fun test2: int -//│ fun test3: (int, 'base | int,) +//│ this: 'this +//│ fun test: int +//│ fun test2: int +//│ fun test3: (int, 'base | int,) //│ } //│ where //│ 'this :> Base1 //│ <: {base: 'base} Base1(1).test -//│ //│ int -//│ Typed: int Base1(1).test2 -//│ //│ int -//│ Typed: int Base1(1).test3 -//│ //│ (int, int,) -//│ Typed: (int, int,) class Base1(base): BaseTest -//│ //│ class Base1(base: nothing) { -//│ this: 'this -//│ fun test: nothing +//│ this: 'this +//│ fun test: nothing //│ } //│ where //│ 'this :> Base1 Base1 -//│ //│ (base: anything,) -> Base1 -//│ Typed: (base: anything,) -> Base1 // TODO Base1(1).test -//│ //│ nothing -//│ Typed: nothing :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.87: class Base1(x): BaseTest +//│ ║ l.73: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.87: class Base1(x): BaseTest +//│ ║ l.73: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -97,46 +83,39 @@ class Base1(x): BaseTest //│ ╟── from reference: //│ ║ l.8: fun test = super.base //│ ╙── ^^^^^ -//│ //│ class Base1(x: nothing) { -//│ this: 'this -//│ fun test: nothing +//│ this: 'this +//│ fun test: nothing //│ } //│ where //│ 'this :> Base1 Base1 -//│ //│ (x: anything,) -> Base1 -//│ Typed: (x: anything,) -> Base1 // :ns mixin Foo { fun test(x) = [super.base + x, x, super.misc] } -//│ //│ mixin Foo() { -//│ super: 'super -//│ this: 'this -//│ fun test: (int & 'a) -> (int, 'a, 'misc,) +//│ super: 'super +//│ this: 'this +//│ fun test: (int & 'a) -> (int, 'a, 'misc,) //│ } //│ where //│ 'super <: {base: int, misc: 'misc} module Base1(base: int, misc: string): Foo -//│ //│ namespace Base1(base: int, misc: string) { -//│ this: 'this -//│ fun test: (int & 'a) -> (int, 'a, string,) +//│ this: 'this +//│ fun test: (int & 'a) -> (int, 'a, string,) //│ } //│ where //│ 'this :> Base1 Base1.test -//│ //│ (int & 'a) -> (int, 'a, string,) -//│ Typed: (int & 'a) -> (int, 'a, string,) mixin WrapBase { @@ -145,12 +124,11 @@ mixin WrapBase { fun wrapA(x: int) = x : int fun wrap(x) = x } -//│ //│ mixin WrapBase() { -//│ super: 'super -//│ this: 'this -//│ fun wrap: 'a -> 'a -//│ fun wrapA: (x: int,) -> int +//│ super: 'super +//│ this: 'this +//│ fun wrap: 'a -> 'a +//│ fun wrapA: (x: int,) -> int //│ } // :d @@ -158,12 +136,11 @@ mixin Wrap { fun wrapA(x) = [super.wrapA(x)] fun wrap(x) = [super.wrap(x)] } -//│ //│ mixin Wrap() { -//│ super: 'super -//│ this: 'this -//│ fun wrap: 'a -> ('b,) -//│ fun wrapA: 'c -> ('d,) +//│ super: 'super +//│ this: 'this +//│ fun wrap: 'a -> ('b,) +//│ fun wrapA: 'c -> ('d,) //│ } //│ where //│ 'super <: {wrap: 'a -> 'b, wrapA: 'c -> 'd} @@ -172,93 +149,73 @@ mixin Wrap { // :d module WrapBase1: WrapBase, Wrap -//│ //│ namespace WrapBase1() { -//│ this: 'this -//│ fun wrap: 'a -> ('a,) -//│ fun wrapA: int -> (int,) +//│ this: 'this +//│ fun wrap: 'a -> ('a,) +//│ fun wrapA: int -> (int,) //│ } //│ where //│ 'this :> WrapBase1 WrapBase1 -//│ //│ WrapBase1 -//│ Typed: WrapBase1 // :d WrapBase1.wrapA -//│ //│ int -> (int,) -//│ Typed: int -> (int,) WrapBase1.wrap -//│ //│ 'a -> ('a,) -//│ Typed: 'a -> ('a,) // :d // WrapBase1.wrap WrapBase1.wrap(1) -//│ //│ (1,) -//│ Typed: (1,) WrapBase1.wrap("ok") -//│ //│ ("ok",) -//│ Typed: ("ok",) WrapBase1.wrapA(1) -//│ //│ (int,) -//│ Typed: (int,) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.222: WrapBase1.wrapA("ok") +//│ ║ l.186: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.222: WrapBase1.wrapA("ok") +//│ ║ l.186: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.145: fun wrapA(x: int) = x : int +//│ ║ l.124: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.158: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.136: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ -//│ //│ (int,) | error -//│ Typed: (int,) | error module WrapBase2: WrapBase, Wrap, Wrap, Wrap -//│ //│ namespace WrapBase2() { -//│ this: 'this -//│ fun wrap: 'a -> ((('a,),),) -//│ fun wrapA: int -> (((int,),),) +//│ this: 'this +//│ fun wrap: 'a -> ((('a,),),) +//│ fun wrapA: int -> (((int,),),) //│ } //│ where //│ 'this :> WrapBase2 let w = WrapBase2.wrap -//│ //│ let w: 'a -> ((('a,),),) let wd = w(1) -//│ //│ let wd: (((1,),),) wd._1._1._1 + 1 -//│ //│ int -//│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 2b7d7d4dd5..06261544e1 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -5,19 +5,17 @@ class Add(lhs: E, rhs: E) class Lit(n: int) -//│ //│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this +//│ this: 'this //│ } //│ class Lit(n: int) { -//│ this: 'this0 +//│ this: 'this0 //│ } //│ where //│ 'this0 :> Lit //│ 'this :> Add[?] fun add11 = Add(Lit(1), Lit(2)) -//│ //│ fun add11: Add['E] //│ where //│ 'E :> Lit @@ -31,7 +29,6 @@ fun eval(e) = if e is Lit(n) then n Add(l, r) then eval(l) + eval(r) -//│ //│ fun eval: 'a -> int //│ where //│ 'a <: Add['E] | Lit @@ -44,11 +41,10 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ //│ mixin EvalBase() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Add['E] | Lit) -> int +//│ super: 'super +//│ this: 'this +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where //│ 'E <: 'lhs @@ -56,10 +52,9 @@ mixin EvalBase { module TestLang: EvalBase -//│ //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this +//│ fun eval: 'a -> int //│ } //│ where //│ 'a <: Add['E] | Lit @@ -67,32 +62,23 @@ module TestLang: EvalBase //│ 'this :> TestLang TestLang.eval -//│ //│ 'a -> int //│ where //│ 'a <: Add['E] | Lit //│ 'E <: 'a -//│ Typed: 'a -> int -//│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a TestLang.eval(add11) -//│ //│ int -//│ Typed: int class Neg(expr: A) -//│ //│ class Neg[A](expr: A) { -//│ this: 'this +//│ this: 'this //│ } //│ where //│ 'this :> Neg[?] let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ //│ let add2negadd11: Add['E] //│ where //│ 'E :> Lit | Neg['A] @@ -105,11 +91,10 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ //│ mixin EvalNeg() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) +//│ super: 'super +//│ this: 'this +//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } //│ where //│ 'A <: 'expr @@ -118,10 +103,9 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg -//│ //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this +//│ fun eval: 'a -> int //│ } //│ where //│ 'a <: Add['E] | Lit | Neg['A] @@ -130,51 +114,33 @@ module TestLang: EvalBase, EvalNeg //│ 'this :> TestLang TestLang.eval -//│ //│ 'a -> int //│ where //│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a -//│ Typed: 'a -> int -//│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a TestLang.eval(add11) -//│ //│ int -//│ Typed: int TestLang.eval(Neg(add11)) -//│ //│ int -//│ Typed: int TestLang.eval(Add(Lit(2), Neg(Lit(1)))) -//│ //│ int -//│ Typed: int TestLang.eval(Neg(Neg(add11))) -//│ //│ int -//│ Typed: int TestLang.eval(add2negadd11) -//│ //│ int -//│ Typed: int // add11 TestLang.eval(Add(Lit(2), Neg(add11))) -//│ //│ int -//│ Typed: int mixin EvalNegNeg { @@ -182,11 +148,10 @@ mixin EvalNegNeg { if e is Neg(Neg(d)) then this.eval(d) else super.eval(e) } -//│ //│ mixin EvalNegNeg() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Neg['A] | 'a & ~Neg) -> 'b +//│ super: 'super +//│ this: 'this +//│ fun eval: (Neg['A] | 'a & ~Neg) -> 'b //│ } //│ where //│ 'A :> 'A0 @@ -196,10 +161,9 @@ mixin EvalNegNeg { //│ 'super <: {eval: (Neg[in 'A0 & (~Neg | Neg[in 'expr out nothing]) out 'A0 | 'A1] & {Neg#A :> 'A0 & (~Neg | Neg[in 'expr out nothing]) <: 'A0 | 'A1} | 'a) -> 'b} module TestLang: EvalBase, EvalNeg, EvalNegNeg -//│ //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this +//│ fun eval: 'a -> int //│ } //│ where //│ 'a <: Add['E] | Lit | Neg['A] @@ -214,7 +178,6 @@ fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ //│ fun mk: number -> (Lit | 'a) //│ where //│ 'a :> Neg['A] | Add['E] @@ -222,7 +185,6 @@ fun mk(n) = if n is //│ 'A :> Lit | 'a TestLang.eval -//│ //│ 'a -> int //│ where //│ 'a <: Add['E] | Lit | Neg['A] @@ -231,18 +193,8 @@ TestLang.eval //│ 'A1 <: 'a //│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a //│ 'E <: 'a -//│ Typed: 'a -> int -//│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg['A1]) -//│ 'A1 <: 'a -//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a -//│ 'E <: 'a TestLang.eval(mk(0)) -//│ //│ int -//│ Typed: int diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index ab461da9d3..dfeb9e48bc 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -5,15 +5,13 @@ class Add(lhs: E, rhs: E) // class Lit(n: int) -//│ //│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this +//│ this: 'this //│ } //│ where //│ 'this :> Add[?] let e = Add(1, 1) -//│ //│ let e: Add['E] //│ where //│ 'E :> 1 @@ -27,22 +25,12 @@ e //│ res: Some(α35) where //│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) //│ E23_36 :> 1 -//│ //│ Add['E] //│ where //│ 'E :> 1 -//│ ⬤ Typed as: ‹∀ 0. α35› -//│ where: -//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) -//│ E23_36 :> 1 -//│ Typed: Add['E] -//│ where -//│ 'E :> 1 e.lhs -//│ //│ 1 -//│ Typed: 1 :d e @@ -51,30 +39,17 @@ e //│ | 0. : α35 //│ ======== TYPED ======== //│ res: Some(α35) where -//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) <: {lhs: lhs49} -//│ E23_36 :> 1 <: lhs49 -//│ lhs49 :> 1 -//│ +//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) <: {lhs: lhs45} +//│ E23_36 :> 1 <: lhs45 +//│ lhs45 :> 1 //│ Add['E] //│ where //│ 'E :> 1 -//│ ⬤ Typed as: ‹∀ 0. α35› -//│ where: -//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) <: {lhs: lhs49} -//│ E23_36 :> 1 <: lhs49 -//│ lhs49 :> 1 -//│ Typed: Add['E] -//│ where -//│ 'E :> 1 Add(2, 2) -//│ //│ Add['E] //│ where //│ 'E :> 2 -//│ Typed: Add['E] -//│ where -//│ 'E :> 2 diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 1164a839b8..637771d348 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -5,19 +5,17 @@ class Add(lhs: E, rhs: E) class Lit(n: int) -//│ //│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this +//│ this: 'this //│ } //│ class Lit(n: int) { -//│ this: 'this0 +//│ this: 'this0 //│ } //│ where //│ 'this0 :> Lit //│ 'this :> Add[?] let add11 = Add(Lit(1), Lit(2)) -//│ //│ let add11: Add['E] //│ where //│ 'E :> Lit @@ -26,7 +24,6 @@ fun eval(e) = if e is Lit(n) then n: int Add(l, r) then eval(l) + eval(r) -//│ //│ fun eval: 'a -> int //│ where //│ 'a <: Add['E] | Lit @@ -39,11 +36,10 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ //│ mixin EvalBase() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Add['E] | Lit) -> int +//│ super: 'super +//│ this: 'this +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where //│ 'E <: 'lhs @@ -51,10 +47,9 @@ mixin EvalBase { module TestLang: EvalBase -//│ //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this +//│ fun eval: 'a -> int //│ } //│ where //│ 'a <: Add['E] | Lit @@ -62,71 +57,46 @@ module TestLang: EvalBase //│ 'this :> TestLang TestLang.eval -//│ //│ 'a -> int //│ where //│ 'a <: Add['E] | Lit //│ 'E <: 'a -//│ Typed: 'a -> int -//│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a add11 -//│ //│ Add['E] //│ where //│ 'E :> Lit -//│ Typed: Add['E] -//│ where -//│ 'E :> Lit TestLang.eval(add11) -//│ //│ int -//│ Typed: int add11 -//│ //│ Add['E] //│ where //│ 'E :> Lit //│ <: Add['E] | Lit -//│ Typed: Add['E] -//│ where -//│ 'E :> Lit -//│ <: Add['E] | Lit TestLang.eval(add11) -//│ //│ int -//│ Typed: int add11 -//│ //│ Add['E] //│ where //│ 'E :> Lit //│ <: Add['E] | Lit -//│ Typed: Add['E] -//│ where -//│ 'E :> Lit -//│ <: Add['E] | Lit class Neg(expr: A) -//│ //│ class Neg[A](expr: A) { -//│ this: 'this +//│ this: 'this //│ } //│ where //│ 'this :> Neg[?] let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ //│ let add2negadd11: Add['E] //│ where //│ 'E :> Lit | Neg['A] @@ -140,11 +110,10 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ //│ mixin EvalNeg() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) +//│ super: 'super +//│ this: 'this +//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } //│ where //│ 'A <: 'expr @@ -153,10 +122,9 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg -//│ //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this +//│ fun eval: 'a -> int //│ } //│ where //│ 'a <: Add['E] | Lit | Neg['A] @@ -165,74 +133,56 @@ module TestLang: EvalBase, EvalNeg //│ 'this :> TestLang TestLang.eval -//│ //│ 'a -> int //│ where //│ 'a <: Add['E] | Lit | Neg['A] //│ 'A <: 'a //│ 'E <: 'a -//│ Typed: 'a -> int -//│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a TestLang.eval(add11) -//│ //│ int -//│ Typed: int TestLang.eval(Neg(add11)) -//│ //│ int -//│ Typed: int TestLang.eval(Add(Lit(2), Neg(Lit(1)))) -//│ //│ int -//│ Typed: int TestLang.eval(Neg(Neg(add11))) -//│ //│ int -//│ Typed: int :e TestLang.eval(add2negadd11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.203: TestLang.eval(add2negadd11) +//│ ║ l.157: TestLang.eval(add2negadd11) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg[?A]` does not match type `Add[?E] | Lit` -//│ ║ l.128: let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ ║ ^^^^^^^^^^ +//│ ║ l.99: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.38: if e is +//│ ║ l.35: if e is //│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) //│ ╙── ^ -//│ //│ error | int -//│ Typed: error | int :e TestLang.eval(Add(Lit(2), Neg(add11))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.221: TestLang.eval(Add(Lit(2), Neg(add11))) +//│ ║ l.173: TestLang.eval(Add(Lit(2), Neg(add11))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Neg[?A]` does not match type `Add[?E] | Lit` -//│ ║ l.128: let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ ║ ^^^^^^^^^^ +//│ ║ l.99: let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.38: if e is +//│ ║ l.35: if e is //│ ║ ^ //│ ╟── Note: type parameter E is defined at: //│ ║ l.6: class Add(lhs: E, rhs: E) //│ ╙── ^ -//│ //│ error -//│ Typed: error diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index df64e981f6..8f34bc674d 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -9,37 +9,29 @@ class Some(value: A) { // fun mapBad(f) = Some(f(value)) // TODO // fun map(f : A => 'b) = Some(f(value)) // TODO } -//│ //│ class Some[A](value: A) { -//│ this: 'this -//│ fun get: A -//│ fun toArray: (A,) +//│ this: 'this +//│ fun get: A +//│ fun toArray: (A,) //│ } //│ where //│ 'this :> Some[?] let s = Some(1) -//│ //│ let s: Some['A] //│ where //│ 'A :> 1 s.value -//│ //│ 1 -//│ Typed: 1 s.get -//│ //│ 1 -//│ Typed: 1 s.toArray -//│ //│ (1,) -//│ Typed: (1,) // TODO @@ -60,20 +52,17 @@ module None { fun toArray = [] // fun mapBad(f) = None // TODO } -//│ //│ namespace None() { -//│ this: 'this -//│ fun get: nothing -//│ fun toArray: () +//│ this: 'this +//│ fun get: nothing +//│ fun toArray: () //│ } //│ where //│ 'this :> None None.toArray -//│ //│ () -//│ Typed: () // TODO @@ -83,15 +72,12 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ //│ let opt: None | Some['A] //│ where //│ 'A :> 123 opt.toArray -//│ //│ Array[123] -//│ Typed: Array[123] // TODO @@ -103,68 +89,55 @@ opt.toArray if opt is Some then opt.value else 0 -//│ //│ 0 | 123 -//│ Typed: 0 | 123 if opt is Some(v) then v else 0 -//│ //│ 0 | 123 -//│ Typed: 0 | 123 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ //│ fun map: (None | Some['A], 'A -> 'A0,) -> (None | Some['A0]) let mo = map(opt, succ) -//│ //│ let mo: None | Some['A] //│ where //│ 'A :> int mo.toArray -//│ //│ Array[int] -//│ Typed: Array[int] class Test(n) { fun foo = n + 1 } -//│ //│ class Test(n: nothing) { -//│ this: 'this -//│ fun foo: int +//│ this: 'this +//│ fun foo: int //│ } //│ where //│ 'this :> Test Test(1) -//│ //│ Test -//│ Typed: Test :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.152: Test(true) +//│ ║ l.127: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.152: Test(true) +//│ ║ l.127: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.136: fun foo = n + 1 +//│ ║ l.114: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.135: class Test(n) { +//│ ║ l.113: class Test(n) { //│ ╙── ^ -//│ //│ Test | error -//│ Typed: Test | error :e @@ -172,39 +145,30 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.172: fun foo = n + 1 +//│ ║ l.145: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.172: fun foo = n + 1 +//│ ║ l.145: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.171: class Test(n: A) { +//│ ║ l.144: class Test(n: A) { //│ ╙── ^ -//│ //│ class Test[A](n: A) { -//│ this: 'this -//│ fun foo: error | int +//│ this: 'this +//│ fun foo: error | int //│ } //│ where //│ 'this :> Test[?] Test(1) -//│ //│ Test['A] //│ where //│ 'A :> 1 -//│ Typed: Test['A] -//│ where -//│ 'A :> 1 Test(true) -//│ //│ Test['A] //│ where //│ 'A :> true -//│ Typed: Test['A] -//│ where -//│ 'A :> true class Test(n: A) { @@ -212,64 +176,44 @@ class Test(n: A) { fun foo1(x: A) = x fun id(x) = x } -//│ //│ class Test[A](n: A) { -//│ this: 'this -//│ fun foo: A -//│ fun foo1: (x: A,) -> A -//│ fun id: 'a -> 'a +//│ this: 'this +//│ fun foo: A +//│ fun foo1: (x: A,) -> A +//│ fun id: 'a -> 'a //│ } //│ where //│ 'this :> Test[?] Test(1) -//│ //│ Test['A] //│ where //│ 'A :> 1 -//│ Typed: Test['A] -//│ where -//│ 'A :> 1 Test(1).foo -//│ //│ 1 -//│ Typed: 1 Test("ok").foo -//│ //│ "ok" -//│ Typed: "ok" let t = Test(1) -//│ //│ let t: Test['A] //│ where //│ 'A :> 1 t.foo1(true) -//│ //│ 1 | true -//│ Typed: 1 | true t : Test<'a> -//│ //│ Test['a] //│ where //│ 'a :> 1 | true -//│ Typed: Test['a] -//│ where -//│ 'a :> 1 | true t.id -//│ //│ 'a -> 'a -//│ Typed: 'a -> 'a [t.id(1), t.id(true)] -//│ //│ (1, true,) -//│ Typed: (1, true,) :e @@ -278,82 +222,59 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.278: fun foo2(x: A) = x + 1 +//│ ║ l.222: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.278: fun foo2(x: A) = x + 1 +//│ ║ l.222: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.276: class Test { +//│ ║ l.220: class Test { //│ ╙── ^ -//│ //│ class Test[A]() { -//│ this: 'this -//│ fun foo1: (x: A,) -> A -//│ fun foo2: (x: A,) -> (error | int) +//│ this: 'this +//│ fun foo1: (x: A,) -> A +//│ fun foo2: (x: A,) -> (error | int) //│ } //│ where //│ 'this :> Test[?] Test().foo1 -//│ //│ (x: 'A,) -> 'A -//│ Typed: (x: 'A,) -> 'A Test().foo1(1) -//│ //│ 1 -//│ Typed: 1 x => Test().foo1(x) -//│ //│ 'a -> 'a -//│ Typed: 'a -> 'a // :d let t = Test() -//│ //│ let t: forall 'A. Test['A] t.foo1 -//│ //│ (x: 'A,) -> 'A -//│ Typed: (x: 'A,) -> 'A [t.foo1(0), t.foo1(true)] -//│ //│ (0, true,) -//│ Typed: (0, true,) t.foo1(0) -//│ //│ 0 -//│ Typed: 0 t -//│ //│ forall 'A. Test['A] -//│ Typed: Test['A] fun foo(x: Test) = x.foo1 -//│ //│ fun foo: (x: Test[int],) -> (x: int,) -> int foo(t) -//│ //│ (x: int,) -> int -//│ Typed: (x: int,) -> int foo(t)(1) -//│ //│ int -//│ Typed: int Test().foo2 -//│ //│ (x: anything,) -> (error | int) -//│ Typed: (x: anything,) -> (error | int) diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index d012530e94..5b2a513ae5 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -10,11 +10,10 @@ mixin BaseTest { //│ ╔══[ERROR] type identifier not found: A //│ ║ l.8: fun test(x: A) = x //│ ╙── ^ -//│ //│ mixin BaseTest[A]() { -//│ super: 'super -//│ this: 'this -//│ fun test: (x: error,) -> error +//│ super: 'super +//│ this: 'this +//│ fun test: (x: error,) -> error //│ } // TODO support @@ -22,12 +21,11 @@ mixin BaseTest(x: A) { fun test = x } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.22: fun test = x +//│ ║ l.21: fun test = x //│ ╙── ^ -//│ //│ mixin BaseTest[A]() { -//│ super: 'super -//│ this: 'this -//│ fun test: error +//│ super: 'super +//│ this: 'this +//│ fun test: error //│ } diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index c46cc116af..cbc0857d1c 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -6,42 +6,33 @@ class Foo() 123 -//│ //│ class Foo() { -//│ this: 'this +//│ this: 'this //│ } //│ 123 //│ where //│ 'this :> Foo -//│ Typed: 123 Foo -//│ //│ () -> Foo -//│ Typed: () -> Foo fun fooo(x) = class C(y, z) C(0, x) -//│ //│ fun fooo: anything -> C fun foo = bar fun bar = foo -//│ //│ fun foo: nothing //│ fun bar: nothing foo(bar) -//│ //│ nothing -//│ Typed: nothing fun foo = {x: foo} -//│ //│ fun foo: 'foo //│ where //│ 'foo :> {x: 'foo} @@ -49,7 +40,6 @@ fun foo = {x: foo} fun foo = {x: bar} fun bar = {y: foo} -//│ //│ fun foo: 'foo //│ fun bar: {y: 'foo} //│ where @@ -57,46 +47,29 @@ fun bar = {y: foo} // FIXME pretty-printing? foo -//│ //│ forall 'foo. 'foo //│ where //│ 'foo :> {x: {y: 'foo}} -//│ Typed: 'foo -//│ where -//│ 'foo :> {x: {y: 'foo}} :ns foo -//│ //│ forall 'foo. {x: {y: 'foo}} //│ where //│ 'foo :> {x: {y: 'foo}} -//│ Typed: forall 'foo. {x: {y: 'foo}} -//│ where -//│ 'foo :> {x: {y: 'foo}} foo.x -//│ //│ 'x //│ where //│ 'x :> {y: {x: 'x}} -//│ Typed: 'x -//│ where -//│ 'x :> {y: {x: 'x}} foo.x.y -//│ //│ 'foo //│ where //│ 'foo :> {x: {y: 'foo}} -//│ Typed: 'foo -//│ where -//│ 'foo :> {x: {y: 'foo}} fun foo(a) = {h: a, t: bar(a)} fun bar(b) = foo(b) -//│ //│ fun foo: 'a -> 'b //│ fun bar: 'a -> 'b //│ where @@ -104,22 +77,15 @@ fun bar(b) = foo(b) :ns foo -//│ -//│ forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} -//│ where -//│ 'c :> {h: 'a, t: 'c} -//│ 'a <: 'b -//│ 'b <: 'a -//│ Typed: forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} +//│ forall 'a 'b 'c. 'c -> {h: 'c, t: 'b} //│ where -//│ 'c :> {h: 'a, t: 'c} -//│ 'a <: 'b -//│ 'b <: 'a +//│ 'b :> {h: 'c, t: 'b} +//│ 'c <: 'a +//│ 'a <: 'c fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} -//│ //│ fun foo: 'a -> 'b //│ fun bar: 'a -> 'c //│ where @@ -134,23 +100,20 @@ module Test0_1 { module Test0_2 { fun b = 123 } -//│ //│ namespace Test0_1() { -//│ this: 'this -//│ fun a: 123 +//│ this: 'this +//│ fun a: 123 //│ } //│ namespace Test0_2() { -//│ this: 'this0 -//│ fun b: 123 +//│ this: 'this0 +//│ fun b: 123 //│ } //│ where //│ 'this0 :> Test0_2 //│ 'this :> Test0_1 Test0_1.a -//│ //│ 123 -//│ Typed: 123 class Test0_1 { fun a = Test0_2().b @@ -158,14 +121,13 @@ class Test0_1 { class Test0_2() { fun b = 123 } -//│ //│ class Test0_1() { -//│ this: 'this -//│ fun a: 123 +//│ this: 'this +//│ fun a: 123 //│ } //│ class Test0_2() { -//│ this: 'this0 -//│ fun b: 123 +//│ this: 'this0 +//│ fun b: 123 //│ } //│ where //│ 'this0 :> Test0_2 @@ -180,29 +142,26 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.176: module Test1_1 { +//│ ║ l.138: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.177: fun a = Test1_2.b +//│ ║ l.139: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.178: } +//│ ║ l.140: } //│ ╙── ^ -//│ //│ namespace Test1_1() { -//│ this: 'this -//│ fun a: error +//│ this: 'this +//│ fun a: error //│ } //│ namespace Test1_2() { -//│ this: 'this0 -//│ fun b: error +//│ this: 'this0 +//│ fun b: error //│ } //│ where //│ 'this0 :> Test1_2 //│ 'this :> Test1_1 Test1_1.a -//│ //│ error -//│ Typed: error :e // TODO @@ -213,20 +172,19 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.209: class Test1_1 { +//│ ║ l.168: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.210: fun a = Test1_2().b +//│ ║ l.169: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.211: } +//│ ║ l.170: } //│ ╙── ^ -//│ //│ class Test1_1() { -//│ this: 'this -//│ fun a: error +//│ this: 'this +//│ fun a: error //│ } //│ class Test1_2() { -//│ this: 'this0 -//│ fun b: error +//│ this: 'this0 +//│ fun b: error //│ } //│ where //│ 'this0 :> Test1_2 @@ -246,67 +204,58 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.237: module Test2_1 { +//│ ║ l.195: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.238: fun t2 = Test2_2 +//│ ║ l.196: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.239: fun a = Test2_2.b +//│ ║ l.197: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.240: fun d = Test2_2.e +//│ ║ l.198: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.241: fun n = 456 +//│ ║ l.199: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.242: } +//│ ║ l.200: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.237: module Test2_1 { +//│ ║ l.195: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.238: fun t2 = Test2_2 +//│ ║ l.196: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.239: fun a = Test2_2.b +//│ ║ l.197: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.240: fun d = Test2_2.e +//│ ║ l.198: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.241: fun n = 456 +//│ ║ l.199: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.242: } +//│ ║ l.200: } //│ ╙── ^ -//│ //│ namespace Test2_1() { -//│ this: 'this -//│ fun a: 123 -//│ fun d: error -//│ fun n: 456 -//│ fun t2: Test2_2 +//│ this: 'this +//│ fun a: 123 +//│ fun d: error +//│ fun n: 456 +//│ fun t2: Test2_2 //│ } //│ namespace Test2_2() { -//│ this: 'this0 -//│ fun b: 123 -//│ fun c: error -//│ fun e: error +//│ this: 'this0 +//│ fun b: 123 +//│ fun c: error +//│ fun e: error //│ } //│ where //│ 'this0 :> Test2_2 //│ 'this :> Test2_1 Test2_1.t2.b -//│ //│ 123 -//│ Typed: 123 Test2_1.a -//│ //│ 123 -//│ Typed: 123 // FIXME Test2_1.d -//│ //│ error -//│ Typed: error Test2_1.n -//│ //│ 456 -//│ Typed: 456 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index b6c21ff5ac..75266de9c1 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -6,11 +6,10 @@ mixin Over { fun p = "hi" } -//│ //│ mixin Over() { -//│ super: 'super -//│ this: 'this -//│ fun p: "hi" +//│ super: 'super +//│ this: 'this +//│ fun p: "hi" //│ } @@ -18,11 +17,10 @@ class Base1(p: int): Over { fun test = [p, this.p] // fun test2 = super.p // TODO } -//│ //│ class Base1(p: int) { -//│ this: 'this -//│ fun p: "hi" -//│ fun test: (int, "hi" | 'p,) +//│ this: 'this +//│ fun p: "hi" +//│ fun test: (int, "hi" | 'p,) //│ } //│ where //│ 'this :> Base1 @@ -30,9 +28,7 @@ class Base1(p: int): Over { Base1(123).test -//│ //│ (int, "hi",) -//│ Typed: (int, "hi",) // TODO // Base1(123).test2 diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 5f70d59291..51c2814670 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -568,15 +568,17 @@ class DiffTests val exp = typer.expandType(sim)(ctx) - output(exp.show) + val expStr = exp.show - // val exp = getType(typer.PolymorphicType(0, res_ty)) - // output(s"Typed: ${exp}") - tpd.result.foreach { res_ty => - val exp = getType(typer.PolymorphicType(0, res_ty)) - output(s"Typed: ${exp.show}") - } - // */ + output(expStr.stripSuffix("\n")) + + // // val exp = getType(typer.PolymorphicType(0, res_ty)) + // // output(s"Typed: ${exp}") + // tpd.result.foreach { res_ty => + // val exp = getType(typer.PolymorphicType(0, res_ty)) + // output(s"Typed: ${exp.show}") + // } + // // */ /* import typer._ From b504a14ae041cf71cb1f8dbd2a12729fac0b91a4 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 24 Feb 2023 21:52:12 +0800 Subject: [PATCH 063/498] Try to generate mixin --- .../src/main/scala/mlscript/JSBackend.scala | 4 + .../main/scala/mlscript/codegen/Codegen.scala | 5 + .../main/scala/mlscript/codegen/Scope.scala | 6 + shared/src/main/scala/mlscript/helpers.scala | 22 ++- shared/src/main/scala/mlscript/syntax.scala | 1 + shared/src/test/diff/nu/ECOOP23_codegen.mls | 176 ++++++++++++++++++ 6 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 shared/src/test/diff/nu/ECOOP23_codegen.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index bf57079fe0..4014606531 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -254,6 +254,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case New(_, TypingUnit(_)) => throw CodeGenError("custom class body is not supported yet") case Forall(_, bod) => translateTerm(bod) + case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _)) => + val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) + JSClassExpr(translateClassDeclaration(clsBody, Some(ClassSymbol("base", "base", Ls(), baseType, Ls())))) case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") } @@ -441,6 +444,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } // Declare the alias for `this` before declaring parameters. val selfSymbol = memberScope.declareThisAlias() + val superSymbol = memberScope.declareSuper() // Declare parameters. val (memberParams, body) = method.rhs.value match { case Lam(params, body) => diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index ab88f7b6c0..f061c5450d 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -638,6 +638,11 @@ final case class JSRecord(entries: Ls[Str -> JSExpr]) extends JSExpr { }) } +final case class JSClassExpr(cls: JSClassDecl) extends JSExpr { + implicit def precedence: Int = 22 + def toSourceCode: SourceCode = cls.toSourceCode +} + abstract class JSStmt extends JSCode final case class JSExprStmt(expr: JSExpr) extends JSStmt { diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 52f11990f5..1fc3f08b2d 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -245,6 +245,12 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } + def declareSuper(): ValueSymbol = { + val symbol = ValueSymbol("super", "super", Some(false), false) + register(symbol) + symbol + } + def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean): ValueSymbol = { val runtimeName = lexicalValueSymbols.get(lexicalName) match { // If we are implementing a stub symbol and the stub symbol did not shadow any other diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 97ca62095f..a04250ce50 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -674,8 +674,21 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) + case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => + val (diags, ds) = + NuTypeDef(Cls, TypeName(mxName), tps, tup, pars :+ Var("base"), sup, ths, unit).desugared + ds match { + case (cls: TypeDef) :: _ => diags -> (NuFunDef(None, Var(mxName), List(), Left(Lam(Tup(Ls(None -> Fld(false, false, Var("base")))), ClassExpression(cls)))) :: Nil) + case _ => ??? + } case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - ??? // TODO + val (diags, ds) = + NuTypeDef(Cls, nme, tps, tup, pars, sup, ths, unit).desugared + // ds match { + // case (cls: TypeDef) :: _ => diags -> (cls :: Nil) + // case _ => ??? + // } + ??? case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) @@ -708,7 +721,12 @@ trait StatementImpl extends Located { self: Statement => case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld case _ => die })) :: Nil)))), true) - diags.toList -> (TypeDef(k, nme, tps, bod, Nil, Nil, pos) :: ctor :: Nil) + val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) + case _ => lst + }) + // TODO: mthDecls + diags.toList -> (TypeDef(k, nme, tps, bod, Nil, mthDefs, pos) :: ctor :: Nil) case d: DesugaredStatement => Nil -> (d :: Nil) } import Message._ diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index bd6f000068..ba9d0d77c3 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -78,6 +78,7 @@ final case class TyApp(lhs: Term, targs: Ls[Type]) extends Ter final case class Where(body: Term, where: Ls[Statement]) extends Term final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term +final case class ClassExpression(cls: TypeDef) extends Term sealed abstract class IfBody extends IfBodyImpl // final case class IfTerm(expr: Term) extends IfBody // rm? diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls new file mode 100644 index 0000000000..9c5e826b37 --- /dev/null +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -0,0 +1,176 @@ +:NewParser +:NewDefs + +class Add(lhs: E, rhs: E) +class Lit(n: int) +//│ +//│ class Add[E](lhs: E, rhs: E) { +//│ this: 'this +//│ } +//│ class Lit(n: int) { +//│ this: 'this0 +//│ } +//│ where +//│ 'this0 :> Lit +//│ 'this :> Add + +:js +mixin EvalBase { + fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then this.eval(l) + this.eval(r) +} +//│ +//│ mixin EvalBase() { +//│ super: 'super +//│ this: 'this +//│ fun eval: (Add & {Add#E = 'E} | Lit) -> int +//│ } +//│ where +//│ 'E <: 'lhs +//│ 'this <: {eval: 'lhs -> int} +//│ // Query 1 +//│ globalThis.EvalBase = function EvalBase(base) { +//│ return (class EvalBase extends base { +//│ constructor(fields) { +//│ super(fields); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })()); +//│ } +//│ }); +//│ }; +//│ // End of generated code + +class Neg(expr: A) +//│ +//│ class Neg[A](expr: A) { +//│ this: 'this +//│ } +//│ where +//│ 'this :> Neg + +:js +mixin EvalNeg { + fun eval(e) = + if e is Neg(d) then 0 - this.eval(d) + else super.eval(e) +} +//│ +//│ mixin EvalNeg() { +//│ super: 'super +//│ this: 'this +//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> (int | 'b) +//│ } +//│ where +//│ 'A <: 'expr +//│ 'this <: {eval: 'expr -> int} +//│ 'super <: {eval: 'a -> 'b} +//│ // Query 1 +//│ globalThis.EvalNeg = function EvalNeg(base) { +//│ return (class EvalNeg extends base { +//│ constructor(fields) { +//│ super(fields); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ }; +//│ // End of generated code + +:js +mixin EvalNegNeg { + fun eval(e) = + if e is Neg(Neg(d)) then this.eval(d) + else super.eval(e) +} +//│ +//│ mixin EvalNegNeg() { +//│ super: 'super +//│ this: 'this +//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> 'b +//│ } +//│ where +//│ 'A :> 'A0 +//│ <: 'A1 & (~Neg | Neg & {Neg#A = 'A2}) +//│ 'A2 :> 'A3 +//│ <: 'expr +//│ 'this <: {eval: 'expr -> 'b} +//│ 'super <: {eval: (Neg & {Neg#A :> 'A0 & (~Neg | Neg & {Neg#A :> 'expr <: 'expr & 'A3}) <: 'A0 | 'A1} | 'a) -> 'b} +//│ // Query 1 +//│ globalThis.EvalNegNeg = function EvalNegNeg(base) { +//│ return (class EvalNegNeg extends base { +//│ constructor(fields) { +//│ super(fields); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ }; +//│ // End of generated code + +:js +module TestLang: EvalBase, EvalNeg, EvalNegNeg +//│ +//│ namespace TestLang() { +//│ this: 'this +//│ fun eval: 'a -> int +//│ } +//│ where +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'A :> 'A0 +//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) +//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a +//│ 'A1 <: 'A2 +//│ 'A2 <: 'a +//│ 'E <: 'a +//│ 'this :> TestLang +//│ Code generation crashed: +//│ scala.NotImplementedError: an implementation is missing + + +:js +fun mk(n) = if n is + 0 then Lit(0) + 1 then Neg(mk(n)) + _ then Add(mk(n), mk(n)) +TestLang.eval(mk(0)) +//│ +//│ fun mk: number -> (Lit | 'a) +//│ int +//│ where +//│ 'a :> Neg & {Neg#A = 'A} | Add & {Add#E = 'E} +//│ 'E :> 'E0 | Lit | 'a +//│ <: 'E1 +//│ 'A :> 'A0 | Lit | 'a +//│ <: 'A1 +//│ 'A0 :> Lit | 'b +//│ <: 'A2 & 'c & (Neg & {Neg#A = 'A0} | ~Neg) +//│ 'b :> Neg & {Neg#A :> 'A0 <: 'A1} | Add & {Add#E :> 'E0 <: 'E1} +//│ 'E1 :> 'E0 | Lit | 'b +//│ <: 'E0 +//│ 'A1 :> 'A0 | Lit | 'b +//│ <: 'A0 & 'A2 +//│ 'A2 :> 'A0 | Lit | 'b +//│ <: 'A0 & 'c & (~Neg | Neg & {Neg#A = 'A2}) +//│ 'c <: Add & {Add#E = 'E0} | Lit | Neg & {Neg#A = 'A2} +//│ 'E0 :> Lit | 'b +//│ <: 'c +//│ Typed: int +//│ Code generation encountered an error: +//│ unresolved symbol TestLang From 783235be3938bc990187badf6aadc04c53c862be Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 23:27:07 +0800 Subject: [PATCH 064/498] WIP Indent and deparenthesize where clauses --- shared/src/main/scala/mlscript/helpers.scala | 42 ++-- shared/src/test/diff/basics/Simplesub1.fun | 40 ++-- .../src/test/diff/contys/AbstractBounds.mls | 24 +- .../test/diff/contys/ExplicitConstraints.mls | 22 +- shared/src/test/diff/fcp/Church_CT.mls | 220 +++++++++--------- shared/src/test/diff/fcp/FCPTony.mls | 42 ++-- shared/src/test/diff/fcp/NestedDataTypes.mls | 10 +- shared/src/test/diff/fcp/Proofs.mls | 8 +- .../test/diff/fcp/QML_exist_Classes_CT.mls | 136 +++++------ .../diff/fcp/QML_exist_Records_min_CT.mls | 4 +- shared/src/test/diff/fcp/SystemF_2.mls | 208 ++++++++--------- .../src/test/diff/fcp/ToChurchSimplif_CT.mls | 144 ++++++------ .../diff/mlf-examples/ex_casparticuliers.mls | 24 +- shared/src/test/diff/mlf-examples/ex_demo.mls | 62 ++--- .../test/diff/mlf-examples/ex_predicative.mls | 56 ++--- .../src/test/diff/mlf-examples/ex_shallow.mls | 26 +-- shared/src/test/diff/nu/BasicClasses.mls | 32 +-- shared/src/test/diff/nu/BasicMixins.mls | 44 ++-- shared/src/test/diff/nu/ECOOP23.mls | 70 +++--- shared/src/test/diff/nu/ECOOP23_min.mls | 4 +- shared/src/test/diff/nu/ECOOP23_repro.mls | 42 ++-- shared/src/test/diff/nu/GenericClasses.mls | 24 +- shared/src/test/diff/nu/MutualRec.mls | 48 ++-- shared/src/test/diff/nu/ParamOverriding.mls | 6 +- 24 files changed, 674 insertions(+), 664 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 034495a2af..c3d38e9137 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -86,24 +86,34 @@ trait TypeLikeImpl extends Located { self: TypeLike => case PolyType(Nil, body) => body.showIn(ctx, outerPrec) case PolyType(targs, body) => parensIf( s"${targs.iterator.map(_.fold(_.name, _.showIn(ctx, 0))) - .mkString("forall ", " ", ".")} ${body.showIn(ctx, 1)}", + .mkString("forall ", " ", ".")} ${body.showIn(ctx, 0)}", outerPrec > 1 // or 0? ) - case Constrained(b, bs, ws) => parensIf(s"${ - b.showIn(ctx, 0).stripSuffix("\n")}\n${ctx.indStr} where${bs.map { - case (uv, Bounds(Bot, ub)) => - s"\n ${ctx.vs(uv)} <: ${ub.showIn(ctx, 0)}" - case (uv, Bounds(lb, Top)) => - s"\n ${ctx.vs(uv)} :> ${lb.showIn(ctx, 0)}" - case (uv, Bounds(lb, ub)) if lb === ub => - s"\n ${ctx.vs(uv)} := ${lb.showIn(ctx, 0)}" - case (uv, Bounds(lb, ub)) => - val vstr = ctx.vs(uv) - s"\n ${vstr } :> ${lb.showIn(ctx, 0)}" + - s"\n ${" " * vstr.length} <: ${ub.showIn(ctx, 0)}" - }.mkString}${ws.map{ - case Bounds(lo, hi) => s"\n ${lo.showIn(ctx, 0)} <: ${hi.showIn(ctx, 0)}" // TODO print differently from bs? - }.mkString}", outerPrec > 0) + case Constrained(b, bs, ws) => + val oldCtx = ctx + val bStr = b.showIn(ctx, 0).stripSuffix("\n") + val multiline = bStr.contains('\n') + parensIf({ + val ctx = if (multiline) oldCtx.indent else oldCtx.indent.indent + s"${ + bStr + }\n${oldCtx.indStr}${if (multiline) "" else " "}where${ + bs.map { + case (uv, Bounds(Bot, ub)) => + s"\n${ctx.indStr}${ctx.vs(uv)} <: ${ub.showIn(ctx, 0)}" + case (uv, Bounds(lb, Top)) => + s"\n${ctx.indStr}${ctx.vs(uv)} :> ${lb.showIn(ctx, 0)}" + case (uv, Bounds(lb, ub)) if lb === ub => + s"\n${ctx.indStr}${ctx.vs(uv)} := ${lb.showIn(ctx, 0)}" + case (uv, Bounds(lb, ub)) => + val vstr = ctx.vs(uv) + s"\n${ctx.indStr}${vstr } :> ${lb.showIn(ctx, 0)}" + + s"\n${ctx.indStr}${" " * vstr.length} <: ${ub.showIn(ctx, 0)}" + }.mkString + }${ws.map{ + case Bounds(lo, hi) => s"\n${ctx.indStr}${lo.showIn(ctx, 0)} <: ${hi.showIn(ctx, 0)}" // TODO print differently from bs? + }.mkString}" + }, outerPrec > 0) case NuFunDef(isLetRec, nme, targs, rhs) => s"${isLetRec match { case S(false) => "let" diff --git a/shared/src/test/diff/basics/Simplesub1.fun b/shared/src/test/diff/basics/Simplesub1.fun index 143cc82a1c..6f9af685a4 100644 --- a/shared/src/test/diff/basics/Simplesub1.fun +++ b/shared/src/test/diff/basics/Simplesub1.fun @@ -435,32 +435,32 @@ let rec x = (let y = (x x); (z => z)) // * Z combinator: // :e // Works thanks to inconsistent constrained types... (f => (x => f (v => (x x) v)) (x => f (v => (x x) v))) -//│ res: ((forall 'a 'b. ('a -> 'b +//│ res: ((forall 'a 'b. 'a -> 'b //│ where -//│ forall 'c 'd. ('c -> 'd -//│ where -//│ 'e <: (forall 'f 'g. ('f -> 'g -//│ where -//│ 'c <: 'c -> 'f -> 'g)) -> 'd) <: (forall 'c 'd. ('c -> 'd -//│ where -//│ 'e <: (forall 'f 'g. ('f -> 'g -//│ where -//│ 'c <: 'c -> 'f -> 'g)) -> 'd)) -> 'a -> 'b)) -> 'h & 'e) -> 'h +//│ forall 'c 'd. 'c -> 'd +//│ where +//│ 'e <: (forall 'f 'g. 'f -> 'g +//│ where +//│ 'c <: 'c -> 'f -> 'g) -> 'd <: (forall 'c 'd. 'c -> 'd +//│ where +//│ 'e <: (forall 'f 'g. 'f -> 'g +//│ where +//│ 'c <: 'c -> 'f -> 'g) -> 'd) -> 'a -> 'b) -> 'h & 'e) -> 'h // * Function that takes arbitrarily many arguments: // :e // Works thanks to inconsistent constrained types... (f => (x => f (v => (x x) v)) (x => f (v => (x x) v))) (f => x => f) -//│ res: anything -> (forall 'a 'b. ('a -> 'b -//│ where -//│ forall 'c 'd. ('c -> 'd -//│ where -//│ forall 'e. 'e -> anything -> 'e <: (forall 'f 'g. ('f -> 'g -//│ where -//│ 'c <: 'c -> 'f -> 'g)) -> 'd) <: (forall 'c 'd. ('c -> 'd -//│ where -//│ forall 'e. 'e -> anything -> 'e <: (forall 'f 'g. ('f -> 'g +//│ res: anything -> (forall 'a 'b. 'a -> 'b //│ where -//│ 'c <: 'c -> 'f -> 'g)) -> 'd)) -> 'a -> 'b)) +//│ forall 'c 'd. 'c -> 'd +//│ where +//│ forall 'e. 'e -> anything -> 'e <: (forall 'f 'g. 'f -> 'g +//│ where +//│ 'c <: 'c -> 'f -> 'g) -> 'd <: (forall 'c 'd. 'c -> 'd +//│ where +//│ forall 'e. 'e -> anything -> 'e <: (forall 'f 'g. 'f -> 'g +//│ where +//│ 'c <: 'c -> 'f -> 'g) -> 'd) -> 'a -> 'b) diff --git a/shared/src/test/diff/contys/AbstractBounds.mls b/shared/src/test/diff/contys/AbstractBounds.mls index 91a9d56d51..3bd7069d74 100644 --- a/shared/src/test/diff/contys/AbstractBounds.mls +++ b/shared/src/test/diff/contys/AbstractBounds.mls @@ -83,9 +83,9 @@ class Test3[A, B] //│ Defined Test3.Bar3: Test3['A, 'B] -> 'A -> 'B fun x -> fun y -> x.Foo3 y -//│ res: 'a -> (forall 'b 'A. ('A -> 'b +//│ res: 'a -> (forall 'b 'A. 'A -> 'b //│ where -//│ 'a <: Test3['A, 'b])) +//│ 'a <: Test3['A, 'b]) //│ = [Function: res] @@ -95,27 +95,27 @@ class Test4[A, B] method Bar4 i (a: A) = i a : B method Baz4 = this.Bar4 id //│ Defined class Test4[=A, =B] -//│ Defined Test4.Bar4: Test4['A, 'B] -> (forall 'a. 'a -> (forall 'a. ('A -> 'B +//│ Defined Test4.Bar4: Test4['A, 'B] -> (forall 'a. 'a -> (forall 'a. 'A -> 'B //│ where -//│ 'a <: 'A -> 'B))) +//│ 'a <: 'A -> 'B)) //│ Defined Test4.Baz4: Test4['A, 'B] -> ('A -> 'B //│ where //│ forall 'a. 'a -> 'a <: 'A -> 'B) fun x -> fun y -> x.Bar4 y id -//│ res: 'a -> (forall 'A 'B. (('A -> 'B) -> 'B +//│ res: 'a -> (forall 'A 'B. ('A -> 'B) -> 'B //│ where -//│ 'a <: Test4['A, 'B])) -//│ where -//│ 'A :> forall 'b. 'b -> 'b +//│ 'a <: Test4['A, 'B]) +//│ where +//│ 'A :> forall 'b. 'b -> 'b //│ = [Function: res] fun x -> fun y -> x.Baz4 y -//│ res: 'a -> (forall 'A 'B. (('A & 'B) -> 'B -//│ where -//│ 'a <: Test4['A, 'B])) +//│ res: 'a -> (forall 'A 'B. ('A & 'B) -> 'B //│ where -//│ 'A <: 'B +//│ 'a <: Test4['A, 'B]) +//│ where +//│ 'A <: 'B //│ = [Function: res] diff --git a/shared/src/test/diff/contys/ExplicitConstraints.mls b/shared/src/test/diff/contys/ExplicitConstraints.mls index 7c8f04a403..25931ae7f9 100644 --- a/shared/src/test/diff/contys/ExplicitConstraints.mls +++ b/shared/src/test/diff/contys/ExplicitConstraints.mls @@ -103,11 +103,11 @@ fun f: 'a => forall 'b; 'a where :ns f -//│ res: forall 'a. 'a -> (forall 'b. ('a +//│ res: forall 'a. 'a -> (forall 'b. 'a //│ where -//│ 'a <: 'b -> 'b)) -//│ where -//│ 'a :> int +//│ 'a <: 'b -> 'b) +//│ where +//│ 'a :> int // * Note the first-class polymorphic type with impossible bound... let r = f(1) @@ -118,9 +118,9 @@ let r = f(1) r //│ res: forall 'c 'a. 'c //│ where -//│ 'c :> forall 'b. ('a -//│ where -//│ 'a <: 'b -> 'b) +//│ 'c :> forall 'b. 'a +//│ where +//│ 'a <: 'b -> 'b //│ 'a :> int :e @@ -159,11 +159,11 @@ fun f: 'a => forall 'b; 'b where :ns f -//│ res: forall 'a. 'a -> (forall 'b. ('b -//│ where -//│ 'a <: 'b -> 'b)) +//│ res: forall 'a. 'a -> (forall 'b. 'b //│ where -//│ 'a :> int +//│ 'a <: 'b -> 'b) +//│ where +//│ 'a :> int let r = f(1) //│ r: 'b diff --git a/shared/src/test/diff/fcp/Church_CT.mls b/shared/src/test/diff/fcp/Church_CT.mls index b518cc0ecc..b60309ccde 100644 --- a/shared/src/test/diff/fcp/Church_CT.mls +++ b/shared/src/test/diff/fcp/Church_CT.mls @@ -37,10 +37,10 @@ def succ: (forall 'N. ('N -> 'N) -> ('N -> 'N)) -> (forall 'M. ('M -> 'M) -> ('M :e // * Since "sound extrusion" def succ n f x = f (n f x) -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd))) +//│ 'a <: 'b -> 'c -> 'd)) //│ <: succ: //│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -67,10 +67,10 @@ def succ: ChurchInt -> ChurchInt :e // * Since "sound extrusion" def succ n f x = f (n f x) -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e))) +//│ 'b <: 'd -> 'e)) //│ <: succ: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -93,10 +93,10 @@ def succD: forall 'M. ChurchInt -> ('M -> 'M) -> ('M -> 'M) def succD n f x = f (n f x) //│ succD: ChurchInt -> ('M -> 'M) -> 'M -> 'M //│ = -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd))) +//│ 'a <: 'b -> 'c -> 'd)) //│ <: succD: //│ ChurchInt -> ('M -> 'M) -> 'M -> 'M //│ = [Function: succD] @@ -282,10 +282,10 @@ def z f x = x //│ = [Function: z] def s n f x = f (n f x) -//│ s: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ s: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e))) +//│ 'b <: 'd -> 'e)) //│ = [Function: s] zero = z @@ -296,10 +296,10 @@ zero = z :e // * Since "sound extrusion" succ = s -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e))) +//│ 'b <: 'd -> 'e)) //│ <: succ: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -359,33 +359,33 @@ s: ChurchInt -> ChurchInt n1 = s z -//│ n1: 'a -> (forall 'b 'c 'd. ('c -> 'b +//│ n1: 'a -> (forall 'b 'c 'd. 'c -> 'b //│ where //│ anything -> (forall 'e. 'e -> 'e) <: 'a -> 'c -> 'd -//│ 'a <: 'd -> 'b)) +//│ 'a <: 'd -> 'b) //│ = [Function (anonymous)] n2 = s (s z) -//│ n2: 'a -> (forall 'b 'c 'd. ('b -> 'd +//│ n2: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where //│ 'a <: 'c -> 'd -//│ forall 'e. 'e -> (forall 'f 'g 'h. ('f -> 'h -//│ where -//│ 'e <: 'g -> 'h -//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g)) <: 'a -> 'b -> 'c)) +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ where +//│ 'e <: 'g -> 'h +//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g) <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] n3 = s (s (s z)) -//│ n3: 'a -> (forall 'b 'c 'd. ('b -> 'd -//│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. ('g -> 'f -//│ where -//│ 'e <: 'h -> 'f -//│ forall 'i. 'i -> (forall 'j 'k 'l. ('j -> 'l -//│ where -//│ 'i <: 'k -> 'l -//│ anything -> (forall 'm. 'm -> 'm) <: 'i -> 'j -> 'k)) <: 'e -> 'g -> 'h)) <: 'a -> 'b -> 'c -//│ 'a <: 'c -> 'd)) +//│ n3: 'a -> (forall 'b 'c 'd. 'b -> 'd +//│ where +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'g -> 'f +//│ where +//│ 'e <: 'h -> 'f +//│ forall 'i. 'i -> (forall 'j 'k 'l. 'j -> 'l +//│ where +//│ 'i <: 'k -> 'l +//│ anything -> (forall 'm. 'm -> 'm) <: 'i -> 'j -> 'k) <: 'e -> 'g -> 'h) <: 'a -> 'b -> 'c +//│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] @@ -476,20 +476,20 @@ res.x.x.x + 1 sz = s zero -//│ sz: 'a -> (forall 'b 'c 'd. ('b -> 'd +//│ sz: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where //│ 'a <: 'c -> 'd -//│ ChurchInt <: 'a -> 'b -> 'c)) +//│ ChurchInt <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] :ns sz //│ res: forall 'a 'b. 'b //│ where -//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. ('e -> 'g -//│ where -//│ 'a <: 'c -> 'd -//│ 'c <: 'f -> 'g)) +//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'e -> 'g +//│ where +//│ 'a <: 'c -> 'd +//│ 'c <: 'f -> 'g) //│ 'd <: 'e -> 'f //│ 'a :> ChurchInt //│ = [Function (anonymous)] @@ -525,10 +525,10 @@ sz1 = sz 1 sz1 //│ res: forall 'a 'b 'c. 'c //│ where -//│ 'c :> forall 'd 'e 'f 'g. ('e -> 'g -//│ where -//│ 'a <: 'b -> 'd -//│ 'b <: 'f -> 'g) +//│ 'c :> forall 'd 'e 'f 'g. 'e -> 'g +//│ where +//│ 'a <: 'b -> 'd +//│ 'b <: 'f -> 'g //│ 'd <: 'e -> 'f //│ 'b :> 1 //│ 'a :> ChurchInt @@ -588,10 +588,10 @@ rec def to_ch_s n = else s (to_ch_s (n - 1)) //│ to_ch_s: int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'b 'e 'f. (('e & 'c) -> ('e | 'd) -//│ where -//│ 'a <: 'b -> 'c -> 'f -//│ 'b <: 'f -> 'd)) +//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'b 'e 'f. ('e & 'c) -> ('e | 'd) +//│ where +//│ 'a <: 'b -> 'c -> 'f +//│ 'b <: 'f -> 'd) //│ = [Function: to_ch_s] rec def to_ch n = @@ -599,20 +599,20 @@ rec def to_ch n = else s (to_ch (n - 1)) //│ to_ch: int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'b 'c 'd 'e 'f. (('d & 'c) -> ('d | 'e) -//│ where -//│ 'b <: 'f -> 'e -//│ 'a <: 'b -> 'c -> 'f)) +//│ 'a :> forall 'b. 'b -> (forall 'b 'c 'd 'e 'f. ('d & 'c) -> ('d | 'e) +//│ where +//│ 'b <: 'f -> 'e +//│ 'a <: 'b -> 'c -> 'f) //│ = [Function: to_ch] :e // * Needs distrib (see below) to_church_ty = to_ch //│ int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'b 'e 'f. (('e & 'c) -> ('e | 'd) -//│ where -//│ 'b <: 'f -> 'd -//│ 'a <: 'b -> 'c -> 'f)) +//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'b 'e 'f. ('e & 'c) -> ('e | 'd) +//│ where +//│ 'b <: 'f -> 'd +//│ 'a <: 'b -> 'c -> 'f) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?to_ch. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -624,20 +624,20 @@ to_church_ty = to_ch rec def to_ch_simplif n = s (to_ch_simplif n) //│ to_ch_simplif: anything -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e -//│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ where +//│ 'b <: 'd -> 'e +//│ 'a <: 'b -> 'c -> 'd) //│ = [Function: to_ch_simplif] :e to_church_ty = to_ch_simplif //│ anything -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e -//│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ where +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'd -> 'e) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch_simplif ?c ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -710,10 +710,10 @@ rec def to_ch_A1 n = //│ ╟── Note: constraint arises from application: //│ ║ l.284: def s n f x = f (n f x) //│ ╙── ^^^^^ -//│ to_ch_A1: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. (('e & 'b) -> ('b | 'c) +//│ to_ch_A1: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. ('e & 'b) -> ('b | 'c) //│ where //│ 'a <: 'd -> 'c -//│ ChurchInt <: 'a -> 'e -> 'd))) +//│ ChurchInt <: 'a -> 'e -> 'd)) //│ = [Function: to_ch_A1] :precise-rec-typing @@ -722,12 +722,12 @@ rec def to_ch_A1 n = else s (to_ch_A1 (n - 1) : ChurchInt) //│ to_ch_A1: 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. (int -> (forall 'a. 'a -> (forall 'b 'c 'd 'e 'a. (('d & 'b) -> ('b | 'e) -//│ where -//│ 'a <: 'c -> 'e -//│ ChurchInt <: 'a -> 'd -> 'c))) -//│ where -//│ 'to_ch_A1 <: int -> ChurchInt) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'd 'e 'a. ('d & 'b) -> ('b | 'e) +//│ where +//│ 'a <: 'c -> 'e +//│ ChurchInt <: 'a -> 'd -> 'c)) +//│ where +//│ 'to_ch_A1 <: int -> ChurchInt //│ = [Function: to_ch_A11] // * But we can't check the corresponding type @@ -735,12 +735,12 @@ rec def to_ch_A1 n = to_church_ty = to_ch_A1 //│ 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. (int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. (('b & 'd) -> ('d | 'e) -//│ where -//│ ChurchInt <: 'a -> 'b -> 'c -//│ 'a <: 'c -> 'e))) -//│ where -//│ 'to_ch_A1 <: int -> ChurchInt) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('b & 'd) -> ('d | 'e) +//│ where +//│ ChurchInt <: 'a -> 'b -> 'c +//│ 'a <: 'c -> 'e)) +//│ where +//│ 'to_ch_A1 <: int -> ChurchInt //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Cyclic-looking constraint while typing def definition; a type annotation may be required @@ -831,18 +831,18 @@ rec def to_ch_A2 n = ( ) : ChurchInt //│ to_ch_A2: 'to_ch_A2 //│ where -//│ 'to_ch_A2 :> forall 'to_ch_A2. (int -> ChurchInt -//│ where -//│ 'to_ch_A2 <: int -> (??N -> ??N0) -> ??N0 -> ??N) +//│ 'to_ch_A2 :> forall 'to_ch_A2. int -> ChurchInt +//│ where +//│ 'to_ch_A2 <: int -> (??N -> ??N0) -> ??N0 -> ??N //│ = [Function: to_ch_A21] :e // * Since the removal of "recursive definition hacks" to_church_ty = to_ch_A2 //│ 'to_ch_A2 //│ where -//│ 'to_ch_A2 :> forall 'to_ch_A2. (int -> ChurchInt -//│ where -//│ 'to_ch_A2 <: int -> (??N -> ??N0) -> ??N0 -> ??N) +//│ 'to_ch_A2 :> forall 'to_ch_A2. int -> ChurchInt +//│ where +//│ 'to_ch_A2 <: int -> (??N -> ??N0) -> ??N0 -> ??N //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Cyclic-looking constraint while typing def definition; a type annotation may be required @@ -856,18 +856,18 @@ to_church_ty = to_ch_A2 def to_church_mix n = if n == 0 then z else s (to_church (n - 1)) -//│ to_church_mix: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. (('e & 'b) -> ('b | 'c) +//│ to_church_mix: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. ('e & 'b) -> ('b | 'c) //│ where //│ ChurchInt <: 'a -> 'e -> 'd -//│ 'a <: 'd -> 'c))) +//│ 'a <: 'd -> 'c)) //│ = [Function: to_church_mix] :e to_church_ty = to_church_mix -//│ int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. (('d & 'e) -> ('e | 'b) +//│ int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. ('d & 'e) -> ('e | 'b) //│ where //│ ChurchInt <: 'a -> 'd -> 'c -//│ 'a <: 'c -> 'b))) +//│ 'a <: 'c -> 'b)) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -898,9 +898,9 @@ rec def to_chD n = succD (to_chD n) //│ to_chD: 'to_chD //│ where -//│ 'to_chD :> forall 'a 'M. ('a -> ('M -> 'M) -> 'M -> 'M -//│ where -//│ 'to_chD <: 'a -> ChurchInt) +//│ 'to_chD :> forall 'a 'M. 'a -> ('M -> 'M) -> 'M -> 'M +//│ where +//│ 'to_chD <: 'a -> ChurchInt //│ = [Function: to_chD] @@ -943,11 +943,11 @@ to_church_ty = to_ch //│ where //│ 'a <: 'd -> 'c //│ 'e <: 'a -> 'b -> 'd) -//│ where -//│ 'e :> forall 'f 'g 'h 'i 'j. 'h -> (('j & 'g) -> ('j | 'f) -//│ where -//│ 'h <: 'i -> 'f -//│ 'e <: 'h -> 'g -> 'i) +//│ where +//│ 'e :> forall 'f 'g 'h 'i 'j. 'h -> (('j & 'g) -> ('j | 'f) +//│ where +//│ 'h <: 'i -> 'f +//│ 'e <: 'h -> 'g -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?to_ch ?b ?c ?d. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -962,11 +962,11 @@ to_church_ty = to_ch_simplif //│ where //│ 'a <: 'd -> 'c //│ 'e <: 'a -> 'b -> 'd) -//│ where -//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i -//│ where -//│ 'e <: 'f -> 'g -> 'h -//│ 'f <: 'h -> 'i) +//│ where +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ where +//│ 'e <: 'f -> 'g -> 'h +//│ 'f <: 'h -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch_simplif ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -981,11 +981,11 @@ rec def to_ch_simplif n = s (to_ch_simplif n) //│ where //│ 'a <: 'd -> 'c //│ 'e <: 'a -> 'b -> 'd) -//│ where -//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i -//│ where -//│ 'e <: 'f -> 'g -> 'h -//│ 'f <: 'h -> 'i) +//│ where +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ where +//│ 'e <: 'f -> 'g -> 'h +//│ 'f <: 'h -> 'i) //│ = [Function: to_ch_simplif1] :e // * Since the removal of "recursive definition hacks" @@ -994,11 +994,11 @@ to_church_ty = to_ch_simplif //│ where //│ 'a <: 'd -> 'c //│ 'e <: 'a -> 'b -> 'd) -//│ where -//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i -//│ where -//│ 'e <: 'f -> 'g -> 'h -//│ 'f <: 'h -> 'i) +//│ where +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ where +//│ 'e <: 'f -> 'g -> 'h +//│ 'f <: 'h -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch_simplif ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -1012,12 +1012,12 @@ to_church_ty = to_ch_simplif to_church_ty = to_ch_A1 //│ 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. (int -> (forall 'a 'b 'c 'd 'e. 'c -> (('e & 'b) -> ('b | 'd) -//│ where -//│ 'c <: 'a -> 'd -//│ ChurchInt <: 'c -> 'e -> 'a)) -//│ where -//│ 'to_ch_A1 <: int -> ChurchInt) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. 'c -> (('e & 'b) -> ('b | 'd) +//│ where +//│ 'c <: 'a -> 'd +//│ ChurchInt <: 'c -> 'e -> 'a)) +//│ where +//│ 'to_ch_A1 <: int -> ChurchInt //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Cyclic-looking constraint while typing def definition; a type annotation may be required diff --git a/shared/src/test/diff/fcp/FCPTony.mls b/shared/src/test/diff/fcp/FCPTony.mls index dc3b08bef1..b4659058da 100644 --- a/shared/src/test/diff/fcp/FCPTony.mls +++ b/shared/src/test/diff/fcp/FCPTony.mls @@ -44,9 +44,9 @@ def app p q = p q def mul r s = r (app s) id //│ mul: 'a -> ('b -> 'c //│ where -//│ 'a <: (forall 'd 'e. ('d -> 'e -//│ where -//│ 'b <: 'd -> 'e)) -> (forall 'f. 'f -> 'f) -> 'c) +//│ 'a <: (forall 'd 'e. 'd -> 'e +//│ where +//│ 'b <: 'd -> 'e) -> (forall 'f. 'f -> 'f) -> 'c) //│ = [Function: mul] :e @@ -68,9 +68,9 @@ mul id {} //│ TypeError: p is not a function def fact t = mul t {} -//│ fact: ((forall 'a 'b. ('a -> 'b +//│ fact: ((forall 'a 'b. 'a -> 'b //│ where -//│ anything <: 'a -> 'b)) -> (forall 'c. 'c -> 'c) -> 'd) -> 'd +//│ anything <: 'a -> 'b) -> (forall 'c. 'c -> 'c) -> 'd) -> 'd //│ = [Function: fact] :e @@ -91,9 +91,9 @@ fact id def mul r s = r (app s) //│ mul: 'a -> ('b -> 'c //│ where -//│ 'a <: (forall 'd 'e. ('d -> 'e -//│ where -//│ 'b <: 'd -> 'e)) -> 'c) +//│ 'a <: (forall 'd 'e. 'd -> 'e +//│ where +//│ 'b <: 'd -> 'e) -> 'c) //│ = [Function: mul1] mul id id {} @@ -118,20 +118,20 @@ def succ n f x = f (n f x) //│ = //│ 'a -> 'b -> ('c -> 'd //│ where -//│ 'b <: (forall 'e. ('e -//│ where -//│ 'a <: 'b -> 'c -> 'e)) -> 'd) +//│ 'b <: (forall 'e. 'e +//│ where +//│ 'a <: 'b -> 'c -> 'e) -> 'd) //│ <: succ: //│ ChurchInt -> ChurchInt //│ = [Function: succ1] :ns def add n m = n succ m -//│ add: forall 'a. 'a -> (forall 'b 'c 'd. ('d -> 'c +//│ add: forall 'a. 'a -> (forall 'b 'c 'd. 'd -> 'c //│ where -//│ 'a <: (ChurchInt -> ChurchInt) -> 'b)) -//│ where -//│ 'b <: 'd -> 'c +//│ 'a <: (ChurchInt -> ChurchInt) -> 'b) +//│ where +//│ 'b <: 'd -> 'c //│ = [Function: add] add @@ -142,13 +142,13 @@ add :ns def f x y = add x y -//│ f: forall 'a. 'a -> (forall 'b 'c 'd 'e 'f. ('b -> 'c -//│ where -//│ 'a <: (ChurchInt -> ChurchInt) -> 'd)) +//│ f: forall 'a. 'a -> (forall 'b 'c 'd 'e 'f. 'b -> 'c //│ where -//│ 'b <: 'e -//│ 'd <: 'e -> 'f -//│ 'f <: 'c +//│ 'a <: (ChurchInt -> ChurchInt) -> 'd) +//│ where +//│ 'b <: 'e +//│ 'd <: 'e -> 'f +//│ 'f <: 'c //│ = [Function: f] // :ds diff --git a/shared/src/test/diff/fcp/NestedDataTypes.mls b/shared/src/test/diff/fcp/NestedDataTypes.mls index 92ee24a984..b02ecae949 100644 --- a/shared/src/test/diff/fcp/NestedDataTypes.mls +++ b/shared/src/test/diff/fcp/NestedDataTypes.mls @@ -231,11 +231,11 @@ rec def map f tree = case tree of { //│ map: 'map //│ where //│ 'map :> forall 'subTree 'A 'a 'subTree0 'value 'value0. 'a -> ((Leaf[?] & {value: 'value} | (Node[?] with {subTree: 'subTree})) -> (Leaf['value0] | (Node['A] with {subTree: 'subTree0})) -//│ where -//│ 'a <: 'value -> 'value0 -//│ 'map <: (forall 'b 'c 'd 'e. (('b, 'd,) -> ('c, 'e,) -//│ where -//│ 'a <: 'b -> 'c & 'd -> 'e)) -> 'subTree -> (PerfectTree[Two['A]] & 'subTree0)) +//│ where +//│ 'a <: 'value -> 'value0 +//│ 'map <: (forall 'b 'c 'd 'e. ('b, 'd,) -> ('c, 'e,) +//│ where +//│ 'a <: 'b -> 'c & 'd -> 'e) -> 'subTree -> (PerfectTree[Two['A]] & 'subTree0)) //│ = [Function: map1] :e diff --git a/shared/src/test/diff/fcp/Proofs.mls b/shared/src/test/diff/fcp/Proofs.mls index cfe4478fc1..a8fbf38e52 100644 --- a/shared/src/test/diff/fcp/Proofs.mls +++ b/shared/src/test/diff/fcp/Proofs.mls @@ -423,9 +423,9 @@ EM_to_DNE: EM -> DNE def EM_to_DNE em nna = case em of Left -> em.v, Right -> nna em.v -//│ EM_to_DNE: 'a -> (forall 'v 'v0. (('v0 -> 'v) -> 'v +//│ EM_to_DNE: 'a -> (forall 'v 'v0. ('v0 -> 'v) -> 'v //│ where -//│ 'a <: (Left with {v: 'v}) | (Right with {v: 'v0}))) +//│ 'a <: (Left with {v: 'v}) | (Right with {v: 'v0})) :e // * Still needs distrib! (after "sound extrusion") EM_to_DNE: EM -> DNE @@ -454,9 +454,9 @@ EM_to_DNE: EM -> DNE def DNE_to_EM dne = dne (fun not_em -> not_em (Right { v = fun a -> not_em (Left { v = a }) })) -//│ DNE_to_EM: ((forall 'a 'b. ((Right & {v: forall 'c 'v. ('v -> 'c +//│ DNE_to_EM: ((forall 'a 'b. ((Right & {v: forall 'c 'v. 'v -> 'c //│ where -//│ 'b <: (Left with {v: 'v}) -> 'c)}) -> 'a & 'b) -> 'a) -> 'd) -> 'd +//│ 'b <: (Left with {v: 'v}) -> 'c}) -> 'a & 'b) -> 'a) -> 'd) -> 'd :e // * Still needs distrib! (after "sound extrusion") DNE_to_EM: DNE -> EM diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls b/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls index 810a1863e4..2aca942c40 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls @@ -80,17 +80,17 @@ def simpleStepImpl arrImpl = ArraysImpl { //│ simpleStepImpl: (ArraysRep[in 'A | 'A0 & 'A1 | 'A2 | 'A1 & 'A3 out 'A & 'A0 & 'A2 & 'A3, in 'a & 'Rep & 'Rep0 | 'Rep | 'Rep1 out 'Rep0 & 'a & 'Rep & ('a | 'Rep1)] & 'c) -> (ArraysImpl['A1, 'Rep2] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b //│ where //│ 'd <: 'A4 -> 'b -> 'b -//│ 'c <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. ('A5 -> ('Rep4, "initialized",) +//│ 'c <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) //│ where -//│ 'c <: ArraysRep['A5, 'Rep4]), sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 +//│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 //│ where //│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where //│ 'c <: ArraysRep['A7, 'Rep6])}) -//│ where -//│ 'Rep2 :> ('a, "initialized" | "updated",) -//│ <: (nothing, anything,) -//│ 'A1 <: nothing +//│ where +//│ 'Rep2 :> ('a, "initialized" | "updated",) +//│ <: (nothing, anything,) +//│ 'A1 <: nothing //│ = [Function: simpleStepImpl] simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] @@ -110,34 +110,34 @@ def simpleStepImpl2 arr = arr simpleStepImpl //│ simpleStepImpl2: ((forall 'Rep 'a 'A 'Rep0 'A0 'Rep1 'A1 'c 'A2 'A3 'Rep2. (ArraysRep[in 'A | 'A0 & 'A1 | 'A3 | 'A1 & 'A2 out 'A & 'A0 & 'A3 & 'A2, in 'c & 'Rep1 & 'Rep | 'Rep1 | 'Rep0 out 'Rep & 'c & 'Rep1 & ('c | 'Rep0)] & 'a) -> (ArraysImpl['A1, 'Rep2] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b //│ where //│ 'd <: 'A4 -> 'b -> 'b -//│ 'a <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. ('A5 -> ('Rep4, "initialized",) +//│ 'a <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) //│ where -//│ 'a <: ArraysRep['A5, 'Rep4]), sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 +//│ 'a <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 //│ where //│ 'a <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where //│ 'a <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e -//│ where -//│ 'Rep2 :> ('c, "initialized" | "updated",) -//│ <: (nothing, anything,) -//│ 'A1 <: nothing +//│ where +//│ 'Rep2 :> ('c, "initialized" | "updated",) +//│ <: (nothing, anything,) +//│ 'A1 <: nothing //│ = [Function: simpleStepImpl2] simpleStepImpl2_ty = simpleStepImpl2 //│ ((forall 'a 'A 'Rep 'c 'A0 'A1 'Rep0 'Rep1 'A2 'A3 'Rep2. (ArraysRep[in 'A0 | 'A3 & 'A2 | 'A | 'A2 & 'A1 out 'A0 & 'A3 & 'A & 'A1, in 'c & 'Rep0 & 'Rep2 | 'Rep0 | 'Rep1 out 'Rep2 & 'c & 'Rep0 & ('c | 'Rep1)] & 'a) -> (ArraysImpl['A2, 'Rep] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b //│ where //│ 'a <: ArraysRep['A4, 'Rep3] -//│ 'd <: 'A4 -> 'b -> 'b), init: forall 'A5 'Rep4. ('A5 -> ('Rep4, "initialized",) +//│ 'd <: 'A4 -> 'b -> 'b), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) //│ where -//│ 'a <: ArraysRep['A5, 'Rep4]), sub: forall 'A6 'Rep5. ('Rep5, anything,) -> (int -> 'A6 +//│ 'a <: ArraysRep['A5, 'Rep4], sub: forall 'A6 'Rep5. ('Rep5, anything,) -> (int -> 'A6 //│ where //│ 'a <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where //│ 'a <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e -//│ where -//│ 'Rep :> ('c, "initialized" | "updated",) -//│ <: (nothing, anything,) -//│ 'A2 <: nothing +//│ where +//│ 'Rep :> ('c, "initialized" | "updated",) +//│ <: (nothing, anything,) +//│ 'A2 <: nothing //│ <: simpleStepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, string,)] //│ = [Function: simpleStepImpl2] @@ -184,19 +184,19 @@ def simpleStep arr f = f (simpleStepImpl2 arr) //│ 'a -> (('c -> 'd) -> 'd //│ where //│ 'a <: (forall 'A 'A0 'Rep 'e 'f. (ArraysRep[in anything out nothing, in 'A out nothing] & 'e) -> (ArraysImpl['A0, 'Rep] with {fold: forall 'g 'b 'A1 'Rep0. 'g -> 'b -> (('Rep0, 'A,) -> 'b -//│ where -//│ 'e <: ArraysRep['A1, 'Rep0] -//│ 'g <: 'A1 -> 'b -> 'b), init: forall 'A2 'Rep1. ('A2 -> ('Rep1, "initialized",) -//│ where -//│ 'e <: ArraysRep['A2, 'Rep1]), sub: forall 'Rep2 'A3. ('Rep2, 'A,) -> (int -> 'A3 -//│ where -//│ 'e <: ArraysRep['A3, 'Rep2]), update: forall 'Rep3 'A4. ('Rep3, 'A,) -> int -> ('A4 -> ('Rep3, "updated",) -//│ where -//│ 'e <: ArraysRep['A4, 'Rep3])})) -> 'c) -//│ where -//│ 'Rep :> ('f, "initialized" | "updated",) -//│ <: (nothing, 'A,) -//│ 'A0 <: nothing +//│ where +//│ 'e <: ArraysRep['A1, 'Rep0] +//│ 'g <: 'A1 -> 'b -> 'b), init: forall 'A2 'Rep1. 'A2 -> ('Rep1, "initialized",) +//│ where +//│ 'e <: ArraysRep['A2, 'Rep1], sub: forall 'Rep2 'A3. ('Rep2, 'A,) -> (int -> 'A3 +//│ where +//│ 'e <: ArraysRep['A3, 'Rep2]), update: forall 'Rep3 'A4. ('Rep3, 'A,) -> int -> ('A4 -> ('Rep3, "updated",) +//│ where +//│ 'e <: ArraysRep['A4, 'Rep3])})) -> 'c) +//│ where +//│ 'Rep :> ('f, "initialized" | "updated",) +//│ <: (nothing, 'A,) +//│ 'A0 <: nothing //│ <: simpleStep: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -358,19 +358,19 @@ def stepImpl arrImpl = ArraysImpl { //│ stepImpl: (ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 & 'A4 | 'A3 & 'A5 | 'A3 & ('A6 | 'A7) out 'A & 'A0 & 'A6 & 'A7 & 'A1 & 'A2 & 'A4 & 'A5, in 'a & 'Rep & 'Rep0 | 'Rep | 'c & 'Rep1 & 'Rep2 | 'Rep1 | 'Rep3 | 'Rep4 out 'Rep0 & 'a & 'Rep & 'Rep2 & 'c & 'Rep1 & ('a | 'Rep3) & ('c | 'Rep4)] & 'd) -> (ArraysImpl['A3, 'Rep5] with {fold: forall 'Rep6 'e 'b 'f 'Rep7 'A8 'b0 'A9. 'f -> 'e -> (('Rep7, 'Rep6,) -> ('e | 'b) //│ where //│ 'd <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7] -//│ 'f <: 'A9 -> ('e | 'b) -> 'b & 'A8 -> ('b0 | 'e) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. (('A10 & 'A11) -> ('Rep8, 'Rep9,) +//│ 'f <: 'A9 -> ('e | 'b) -> 'b & 'A8 -> ('b0 | 'e) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) //│ where -//│ 'd <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9]), sub: forall 'A12 'Rep10 'g 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g +//│ 'd <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'A12 'Rep10 'g 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g //│ where //│ 'd <: ArraysRep['A13, 'Rep10] & ArraysRep['A12, 'Rep11]), update: forall 'Rep12 'A14 'A15 'Rep13. ('Rep13, 'Rep12,) -> int -> (('A14 & 'A15) -> ('Rep13, 'Rep12,) //│ where //│ 'd <: ArraysRep['A14, 'Rep13] & ArraysRep['A15, 'Rep12])}) -//│ where -//│ 'A12 <: 'g -//│ 'A13 <: 'g -//│ 'Rep5 :> ('a, 'c,) -//│ <: (nothing, nothing,) -//│ 'A3 <: nothing +//│ where +//│ 'A12 <: 'g +//│ 'A13 <: 'g +//│ 'Rep5 :> ('a, 'c,) +//│ <: (nothing, nothing,) +//│ 'A3 <: nothing //│ = [Function: stepImpl] def stepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, 'Rep)] @@ -381,38 +381,38 @@ def stepImpl2 arr = arr stepImpl //│ stepImpl2: ((forall 'A 'a 'Rep 'A0 'Rep0 'c 'A1 'A2 'Rep1 'Rep2 'A3 'Rep3 'Rep4 'A4 'A5 'd 'Rep5 'A6 'A7. (ArraysRep[in 'A5 | 'A7 | 'A | 'A6 | 'A4 & 'A2 | 'A4 & 'A0 | 'A4 & ('A1 | 'A3) out 'A5 & 'A7 & 'A1 & 'A3 & 'A & 'A6 & 'A2 & 'A0, in 'c & 'Rep2 & 'Rep | 'Rep2 | 'd & 'Rep4 & 'Rep3 | 'Rep4 | 'Rep1 | 'Rep0 out 'Rep & 'c & 'Rep2 & 'Rep3 & 'd & 'Rep4 & ('c | 'Rep1) & ('d | 'Rep0)] & 'a) -> (ArraysImpl['A4, 'Rep5] with {fold: forall 'b 'Rep6 'e 'b0 'Rep7 'A8 'A9 'f. 'e -> 'f -> (('Rep7, 'Rep6,) -> ('f | 'b0) //│ where //│ 'a <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7] -//│ 'e <: 'A9 -> ('f | 'b0) -> 'b0 & 'A8 -> ('b | 'f) -> ('b0 & 'b)), init: forall 'Rep8 'A10 'Rep9 'A11. (('A11 & 'A10) -> ('Rep8, 'Rep9,) +//│ 'e <: 'A9 -> ('f | 'b0) -> 'b0 & 'A8 -> ('b | 'f) -> ('b0 & 'b)), init: forall 'Rep8 'A10 'Rep9 'A11. ('A11 & 'A10) -> ('Rep8, 'Rep9,) //│ where -//│ 'a <: ArraysRep['A11, 'Rep8] & ArraysRep['A10, 'Rep9]), sub: forall 'g 'Rep10 'Rep11 'A12 'A13. ('Rep11, 'Rep10,) -> (int -> 'g +//│ 'a <: ArraysRep['A11, 'Rep8] & ArraysRep['A10, 'Rep9], sub: forall 'g 'Rep10 'Rep11 'A12 'A13. ('Rep11, 'Rep10,) -> (int -> 'g //│ where //│ 'a <: ArraysRep['A12, 'Rep11] & ArraysRep['A13, 'Rep10]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where //│ 'a <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h -//│ where -//│ 'A13 <: 'g -//│ 'A12 <: 'g -//│ 'Rep5 :> ('c, 'd,) -//│ <: (nothing, nothing,) -//│ 'A4 <: nothing +//│ where +//│ 'A13 <: 'g +//│ 'A12 <: 'g +//│ 'Rep5 :> ('c, 'd,) +//│ <: (nothing, nothing,) +//│ 'A4 <: nothing //│ = [Function: stepImpl2] stepImpl2_ty = stepImpl2 //│ ((forall 'A 'Rep 'a 'Rep0 'A0 'Rep1 'A1 'A2 'A3 'c 'A4 'd 'A5 'A6 'Rep2 'A7 'Rep3 'Rep4 'Rep5. (ArraysRep[in 'A | 'A3 | 'A7 | 'A0 | 'A2 & 'A5 | 'A2 & 'A6 | 'A2 & ('A1 | 'A4) out 'A & 'A3 & 'A1 & 'A4 & 'A7 & 'A0 & 'A5 & 'A6, in 'c & 'Rep3 & 'Rep5 | 'Rep3 | 'd & 'Rep4 & 'Rep0 | 'Rep4 | 'Rep2 | 'Rep out 'Rep5 & 'c & 'Rep3 & 'Rep0 & 'd & 'Rep4 & ('c | 'Rep2) & ('d | 'Rep)] & 'a) -> (ArraysImpl['A2, 'Rep1] with {fold: forall 'Rep6 'A8 'Rep7 'b 'e 'A9 'f 'b0. 'e -> 'f -> (('Rep6, 'Rep7,) -> ('f | 'b) //│ where //│ 'a <: ArraysRep['A8, 'Rep7] & ArraysRep['A9, 'Rep6] -//│ 'e <: 'A8 -> ('f | 'b) -> 'b & 'A9 -> ('b0 | 'f) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. (('A10 & 'A11) -> ('Rep8, 'Rep9,) +//│ 'e <: 'A8 -> ('f | 'b) -> 'b & 'A9 -> ('b0 | 'f) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) //│ where -//│ 'a <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9]), sub: forall 'Rep10 'A12 'g 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g +//│ 'a <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'Rep10 'A12 'g 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g //│ where //│ 'a <: ArraysRep['A12, 'Rep10] & ArraysRep['A13, 'Rep11]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where //│ 'a <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h -//│ where -//│ 'A13 <: 'g -//│ 'A12 <: 'g -//│ 'Rep1 :> ('c, 'd,) -//│ <: (nothing, nothing,) -//│ 'A2 <: nothing +//│ where +//│ 'A13 <: 'g +//│ 'A12 <: 'g +//│ 'Rep1 :> ('c, 'd,) +//│ <: (nothing, nothing,) +//│ 'A2 <: nothing //│ <: stepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, 'Rep,)] //│ = [Function: stepImpl2] @@ -427,19 +427,19 @@ def step arr f = f (stepImpl2 arr) //│ 'a -> (('c -> 'd) -> 'd //│ where //│ 'a <: (forall 'A 'e 'f 'g. (ArraysRep[in anything out nothing, in anything out 'e & 'f] & 'g) -> (ArraysImpl['A, ('e, 'f,)] with {fold: forall 'A0 'Rep 'h 'b 'b0 'A1 'i 'Rep0. 'h -> 'i -> (('Rep, 'Rep0,) -> ('i | 'b) -//│ where -//│ 'g <: ArraysRep['A1, 'Rep0] & ArraysRep['A0, 'Rep] -//│ 'h <: 'A1 -> ('i | 'b) -> 'b & 'A0 -> ('b0 | 'i) -> ('b & 'b0)), init: forall 'A2 'Rep1 'A3 'Rep2. (('A2 & 'A3) -> ('Rep1, 'Rep2,) -//│ where -//│ 'g <: ArraysRep['A2, 'Rep1] & ArraysRep['A3, 'Rep2]), sub: forall 'A4 'j 'A5 'Rep3 'Rep4. ('Rep3, 'Rep4,) -> (int -> 'j -//│ where -//│ 'g <: ArraysRep['A5, 'Rep3] & ArraysRep['A4, 'Rep4]), update: forall 'A6 'Rep5 'Rep6 'A7. ('Rep5, 'Rep6,) -> int -> (('A7 & 'A6) -> ('Rep5, 'Rep6,) -//│ where -//│ 'g <: ArraysRep['A7, 'Rep5] & ArraysRep['A6, 'Rep6])})) -> 'c) -//│ where -//│ 'A4 <: 'j -//│ 'A5 <: 'j -//│ 'A <: nothing +//│ where +//│ 'g <: ArraysRep['A1, 'Rep0] & ArraysRep['A0, 'Rep] +//│ 'h <: 'A1 -> ('i | 'b) -> 'b & 'A0 -> ('b0 | 'i) -> ('b & 'b0)), init: forall 'A2 'Rep1 'A3 'Rep2. ('A2 & 'A3) -> ('Rep1, 'Rep2,) +//│ where +//│ 'g <: ArraysRep['A2, 'Rep1] & ArraysRep['A3, 'Rep2], sub: forall 'A4 'j 'A5 'Rep3 'Rep4. ('Rep3, 'Rep4,) -> (int -> 'j +//│ where +//│ 'g <: ArraysRep['A5, 'Rep3] & ArraysRep['A4, 'Rep4]), update: forall 'A6 'Rep5 'Rep6 'A7. ('Rep5, 'Rep6,) -> int -> (('A7 & 'A6) -> ('Rep5, 'Rep6,) +//│ where +//│ 'g <: ArraysRep['A7, 'Rep5] & ArraysRep['A6, 'Rep6])})) -> 'c) +//│ where +//│ 'A4 <: 'j +//│ 'A5 <: 'j +//│ 'A <: nothing //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition diff --git a/shared/src/test/diff/fcp/QML_exist_Records_min_CT.mls b/shared/src/test/diff/fcp/QML_exist_Records_min_CT.mls index ca58e0d819..78d36f45c4 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records_min_CT.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records_min_CT.mls @@ -36,8 +36,8 @@ def step arr g = g (stepImpl2 arr) //│ 'a -> (('b -> 'c) -> 'c //│ where //│ 'a <: (forall 'd. 'd -> {fold: forall 'e 'f 'g. 'e -> ('f -> 'g -//│ where -//│ 'd <: {fold: 'e -> 'f -> 'g})}) -> 'b) +//│ where +//│ 'd <: {fold: 'e -> 'f -> 'g})}) -> 'b) //│ <: step: //│ Arrays -> Arrays //│ ╔══[ERROR] Type error in def definition diff --git a/shared/src/test/diff/fcp/SystemF_2.mls b/shared/src/test/diff/fcp/SystemF_2.mls index 8caf6d174c..332c15e0c5 100644 --- a/shared/src/test/diff/fcp/SystemF_2.mls +++ b/shared/src/test/diff/fcp/SystemF_2.mls @@ -137,43 +137,43 @@ id x = x iter2 f x = f(f x) //│ id: 'a -> 'a //│ = [Function: id1] -//│ iter2: 'a -> (forall 'b 'c 'd. ('b -> 'd +//│ iter2: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ 'a <: 'b -> 'c & 'c -> 'd)) +//│ 'a <: 'b -> 'c & 'c -> 'd) //│ = [Function: iter21] iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. ('e -> 'd -//│ where -//│ 'c <: 'e -> 'f & 'f -> 'd)) <: 'a -> 'g & 'g -> 'b +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'e -> 'd +//│ where +//│ 'c <: 'e -> 'f & 'f -> 'd) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] id iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. ('d -> 'f -//│ where -//│ 'c <: 'd -> 'e & 'e -> 'f)) <: 'a -> 'g & 'g -> 'b +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ where +//│ 'c <: 'd -> 'e & 'e -> 'f) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] iter2 iter2 K //│ res: 'a -> 'b //│ where -//│ forall 'c 'd 'e. ('c -> 'e -//│ where -//│ forall 'f. 'f -> anything -> 'f <: 'c -> 'd & 'd -> 'e) <: 'a -> 'g & 'g -> 'b +//│ forall 'c 'd 'e. 'c -> 'e +//│ where +//│ forall 'f. 'f -> anything -> 'f <: 'c -> 'd & 'd -> 'e <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] // (λzy. y(zI)(zK))(λx. xx). foo = (fun z -> fun y -> y (z I) (z K)) -//│ foo: 'a -> (forall 'b 'c 'd. (('b -> 'c -> 'd) -> 'd +//│ foo: 'a -> (forall 'b 'c 'd. ('b -> 'c -> 'd) -> 'd //│ where -//│ 'a <: (forall 'e. 'e -> 'e) -> 'b & (forall 'f. 'f -> anything -> 'f) -> 'c)) +//│ 'a <: (forall 'e. 'e -> 'e) -> 'b & (forall 'f. 'f -> anything -> 'f) -> 'c) //│ = [Function: foo1] foo (fun x -> x x) @@ -196,19 +196,19 @@ n0 = n0_ succ_ n s z = s (n s z) def succ: (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X. ('X -> 'X) -> 'X -> 'X) -//│ succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e))) +//│ 'b <: 'd -> 'e)) //│ = [Function: succ_1] //│ succ: (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X0. ('X0 -> 'X0) -> 'X0 -> 'X0) //│ = :e // * Needs distrib succ = succ_ -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd))) +//│ 'a <: 'b -> 'c -> 'd)) //│ <: succ: //│ (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X0. ('X0 -> 'X0) -> 'X0 -> 'X0) //│ ╔══[ERROR] Type error in def definition @@ -243,119 +243,119 @@ c2 c2 K //│ = [Function (anonymous)] c2_ = succ_ (succ_ n0) -//│ c2_: 'a -> (forall 'b 'c 'd. ('c -> 'b -//│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. ('f -> 'h +//│ c2_: 'a -> (forall 'b 'c 'd. 'c -> 'b //│ where -//│ 'e <: 'g -> 'h -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'f -> 'g)) <: 'a -> 'c -> 'd -//│ 'a <: 'd -> 'b)) +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ where +//│ 'e <: 'g -> 'h +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'f -> 'g) <: 'a -> 'c -> 'd +//│ 'a <: 'd -> 'b) //│ = [Function (anonymous)] c2_ c2_ //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. ('d -> 'f -//│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i)) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f)) <: 'k -> 'b -//│ forall 'l. 'l -> (forall 'm 'n 'o. ('m -> 'o -//│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n -//│ 'l <: 'n -> 'o)) <: (forall 'c. 'c -> (forall 'd 'e 'f. ('d -> 'f -//│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i)) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f))) -> 'a -> 'k +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ where +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ 'g <: 'i -> 'j +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e +//│ 'c <: 'e -> 'f) <: 'k -> 'b +//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o +//│ where +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n +//│ 'l <: 'n -> 'o) <: (forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ where +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ 'g <: 'i -> 'j +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e +//│ 'c <: 'e -> 'f)) -> 'a -> 'k //│ = [Function (anonymous)] c2_ c2_ K //│ res: 'a -> 'b //│ where -//│ forall 'c 'd 'e. ('c -> 'e -//│ where -//│ 'f <: 'd -> 'e -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i)) <: 'f -> 'c -> 'd) <: 'k -> 'b -//│ forall 'l. 'l -> (forall 'm 'n 'o. ('m -> 'o -//│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n -//│ 'l <: 'n -> 'o)) <: (forall 'c 'd 'e. ('c -> 'e -//│ where -//│ 'f <: 'd -> 'e -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i)) <: 'f -> 'c -> 'd)) -> 'a -> 'k -//│ where -//│ 'f :> forall 'p 'q 'r 's. (('p & 's) -> (anything -> 's | 'r) -//│ where -//│ 'f <: 'q -> 'r -//│ forall 't. 't -> (forall 'u 'v 'w. ('u -> 'w -//│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'u -> 'v -//│ 't <: 'v -> 'w)) <: 'f -> 'p -> 'q) +//│ forall 'c 'd 'e. 'c -> 'e +//│ where +//│ 'f <: 'd -> 'e +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ 'g <: 'i -> 'j +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'f -> 'c -> 'd <: 'k -> 'b +//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o +//│ where +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n +//│ 'l <: 'n -> 'o) <: (forall 'c 'd 'e. 'c -> 'e +//│ where +//│ 'f <: 'd -> 'e +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ 'g <: 'i -> 'j +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'f -> 'c -> 'd) -> 'a -> 'k +//│ where +//│ 'f :> forall 'p 'q 'r 's. ('p & 's) -> (anything -> 's | 'r) +//│ where +//│ 'f <: 'q -> 'r +//│ forall 't. 't -> (forall 'u 'v 'w. 'u -> 'w +//│ where +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'u -> 'v +//│ 't <: 'v -> 'w) <: 'f -> 'p -> 'q //│ = [Function (anonymous)] c2__ = succ_ (succ_ n0_) -//│ c2__: 'a -> (forall 'b 'c 'd. ('b -> 'd +//│ c2__: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where //│ 'a <: 'c -> 'd -//│ forall 'e. 'e -> (forall 'f 'g 'h. ('f -> 'h -//│ where -//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g -//│ 'e <: 'g -> 'h)) <: 'a -> 'b -> 'c)) +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ where +//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g +//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] c2__ c2__ //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. ('d -> 'f -//│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i)) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f)) <: 'l -> 'b -//│ forall 'm. 'm -> (forall 'n 'o 'p. ('p -> 'o -//│ where -//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'p -> 'n -//│ 'm <: 'n -> 'o)) <: (forall 'c. 'c -> (forall 'd 'e 'f. ('d -> 'f -//│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i)) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f))) -> 'a -> 'l +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ where +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ 'g <: 'i -> 'j +//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e +//│ 'c <: 'e -> 'f) <: 'l -> 'b +//│ forall 'm. 'm -> (forall 'n 'o 'p. 'p -> 'o +//│ where +//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'p -> 'n +//│ 'm <: 'n -> 'o) <: (forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ where +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ 'g <: 'i -> 'j +//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e +//│ 'c <: 'e -> 'f)) -> 'a -> 'l //│ = [Function (anonymous)] c2__ c2__ K //│ res: 'a -> 'b //│ where -//│ forall 'c 'd 'e. ('c -> 'e -//│ where -//│ forall 'f. 'f -> anything -> 'f <: 'd -> 'e -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i -//│ 'g <: 'i -> 'j)) <: (forall 'f. 'f -> anything -> 'f) -> 'c -> 'd) <: 'l -> 'b -//│ forall 'm. 'm -> (forall 'n 'o 'p. ('n -> 'p -//│ where -//│ 'm <: 'o -> 'p -//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'n -> 'o)) <: (forall 'c 'd 'e. ('c -> 'e -//│ where -//│ forall 'f. 'f -> anything -> 'f <: 'd -> 'e -//│ forall 'g. 'g -> (forall 'h 'i 'j. ('h -> 'j -//│ where -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i -//│ 'g <: 'i -> 'j)) <: (forall 'f. 'f -> anything -> 'f) -> 'c -> 'd)) -> 'a -> 'l +//│ forall 'c 'd 'e. 'c -> 'e +//│ where +//│ forall 'f. 'f -> anything -> 'f <: 'd -> 'e +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i +//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'c -> 'd <: 'l -> 'b +//│ forall 'm. 'm -> (forall 'n 'o 'p. 'n -> 'p +//│ where +//│ 'm <: 'o -> 'p +//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'n -> 'o) <: (forall 'c 'd 'e. 'c -> 'e +//│ where +//│ forall 'f. 'f -> anything -> 'f <: 'd -> 'e +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ where +//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i +//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'c -> 'd) -> 'a -> 'l //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls index 8048dfc098..112f78e7fc 100644 --- a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls +++ b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls @@ -32,25 +32,25 @@ def z f x = x // def s n f = f (n f) def s n f x = (n f x) // def s n f = n f -//│ s: 'a -> (forall 'b. 'b -> (forall 'c 'd. ('c -> 'd +//│ s: 'a -> (forall 'b. 'b -> (forall 'c 'd. 'c -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'd))) +//│ 'a <: 'b -> 'c -> 'd)) //│ = [Function: s] :ns s -//│ res: forall 'a. 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ res: forall 'a. 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'a <: 'b -> 'd))) -//│ where -//│ 'd <: 'c -> 'e +//│ 'a <: 'b -> 'd)) +//│ where +//│ 'd <: 'c -> 'e //│ = [Function: s] :e // * Since "sound extrusion" succ = s -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd. ('d -> 'c +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd. 'd -> 'c //│ where -//│ 'a <: 'b -> 'd -> 'c))) +//│ 'a <: 'b -> 'd -> 'c)) //│ <: succ: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -73,9 +73,9 @@ succ = s :e // * Since "sound extrusion" succ n f = n f -//│ 'a -> (forall 'b 'c. ('b -> 'c +//│ 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ 'a <: 'b -> 'c)) +//│ 'a <: 'b -> 'c) //│ <: succ: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -105,9 +105,9 @@ def succ_min : (forall 'N. ('N -> 'N)) -> (forall 'M. ('M -> 'M)) :e // * Since "sound extrusion" succ_min n f = n f -//│ 'a -> (forall 'b 'c. ('c -> 'b +//│ 'a -> (forall 'b 'c. 'c -> 'b //│ where -//│ 'a <: 'c -> 'b)) +//│ 'a <: 'c -> 'b) //│ <: succ_min: //│ (forall 'N. 'N -> 'N) -> (forall 'M. 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -135,9 +135,9 @@ rec def to_ch n = else s (to_ch n) //│ to_ch: number -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd. ('c -> 'd -//│ where -//│ 'a <: 'b -> 'c -> 'd)) | ChurchInt +//│ 'a :> forall 'b. 'b -> (forall 'c 'd. 'c -> 'd +//│ where +//│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ = //│ zero is not implemented @@ -145,9 +145,9 @@ rec def to_ch n = to_church = to_ch //│ number -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd. ('c -> 'd -//│ where -//│ 'a <: 'b -> 'c -> 'd)) | ChurchInt +//│ 'a :> forall 'b. 'b -> (forall 'c 'd. 'c -> 'd +//│ where +//│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) @@ -163,9 +163,9 @@ rec def to_ch n = else s (to_ch n) //│ to_ch: anything -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd. ('c -> 'd -//│ where -//│ 'a <: 'b -> 'c -> 'd)) | ChurchInt +//│ 'a :> forall 'b. 'b -> (forall 'c 'd. 'c -> 'd +//│ where +//│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ = //│ zero is not implemented @@ -173,9 +173,9 @@ rec def to_ch n = to_church = to_ch //│ anything -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd. ('c -> 'd -//│ where -//│ 'a <: 'b -> 'c -> 'd)) | ChurchInt +//│ 'a :> forall 'b. 'b -> (forall 'c 'd. 'c -> 'd +//│ where +//│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch ?a ?b ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) @@ -189,17 +189,17 @@ to_church = to_ch rec def to_ch n = if true then zero else s (to_church n) -//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) | ChurchInt) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c) | ChurchInt) //│ = //│ zero is not implemented :e to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) | ChurchInt) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c) | ChurchInt) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -228,17 +228,17 @@ to_church = to_ch def to_ch n = if true then z else s (to_church n) -//│ to_ch: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd. (('b & 'd) -> ('d | 'c) +//│ to_ch: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd. ('b & 'd) -> ('d | 'c) //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ = //│ to_church, to_ch and zero are not implemented :e // * Since "sound extrusion" to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd. (('b & 'd) -> ('d | 'c) +//│ int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd. ('b & 'd) -> ('d | 'c) //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -267,17 +267,17 @@ to_church = to_ch def to_ch n = if true then zero else s (to_church n) -//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) | ChurchInt) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c) | ChurchInt) //│ = //│ zero is not implemented :e // * Since "sound extrusion" to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) | ChurchInt) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c) | ChurchInt) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -305,17 +305,17 @@ to_church = to_ch def to_ch n = s (to_church n) -//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ = //│ to_church, to_ch and zero are not implemented :e // * Since "sound extrusion" to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -343,17 +343,17 @@ to_church = to_ch rec def to_ch n = s (to_church n) -//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ = //│ to_church, to_ch, to_church, to_ch and zero are not implemented :e to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -381,17 +381,17 @@ to_church = to_ch def to_ch (n:int) = s (to_church n) -//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ = //│ to_church, to_ch, to_church, to_ch, to_church, to_ch and zero are not implemented :e // * Since "sound extrusion" to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -422,17 +422,17 @@ to_church = to_ch rec def to_ch n = s (to_church n) -//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ to_ch: int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ = //│ to_church, to_ch, to_church, to_ch, to_church, to_ch, to_church, to_ch and zero are not implemented :e to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'c. ('b -> 'c +//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c))) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -460,17 +460,17 @@ to_church = to_ch def to_ch = s (to_church 0) -//│ to_ch: 'a -> (forall 'b 'c. ('b -> 'c +//│ to_ch: 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c) //│ = //│ to_church, to_ch, to_church, to_ch, to_church, to_ch, to_church, to_ch, to_church, to_ch and zero are not implemented :e to_church = to_ch -//│ 'a -> (forall 'b 'c. ('b -> 'c +//│ 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type mismatch in def definition: @@ -529,10 +529,10 @@ rec def to_ch n = //│ to_ch: int -> 'a -> ('b -> ('b | 'c) //│ where //│ 'd <: 'a -> 'b -> 'c) -//│ where -//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) -//│ where -//│ 'd <: 'e -> 'f -> 'g) +//│ where +//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) +//│ where +//│ 'd <: 'e -> 'f -> 'g) //│ = [Function: to_ch7] :e // * Since the removal of "recursive definition hacks" @@ -540,10 +540,10 @@ to_church = to_ch //│ int -> 'a -> ('b -> ('b | 'c) //│ where //│ 'd <: 'a -> 'b -> 'c) -//│ where -//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) -//│ where -//│ 'd <: 'e -> 'f -> 'g) +//│ where +//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) +//│ where +//│ 'd <: 'e -> 'f -> 'g) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) @@ -558,10 +558,10 @@ rec def to_ch_weird n = //│ to_ch_weird: anything -> 'a -> ('b -> 'c //│ where //│ 'd <: 'a -> 'b -> 'c) -//│ where -//│ 'd :> forall 'e 'f 'g. 'e -> ('f -> 'g -//│ where -//│ 'd <: 'e -> 'f -> 'g) +//│ where +//│ 'd :> forall 'e 'f 'g. 'e -> ('f -> 'g +//│ where +//│ 'd <: 'e -> 'f -> 'g) //│ = [Function: to_ch_weird] :e // * Since the removal of "recursive definition hacks" @@ -569,10 +569,10 @@ to_church = to_ch //│ int -> 'a -> ('b -> ('b | 'c) //│ where //│ 'd <: 'a -> 'b -> 'c) -//│ where -//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) -//│ where -//│ 'd <: 'e -> 'f -> 'g) +//│ where +//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) +//│ where +//│ 'd <: 'e -> 'f -> 'g) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch ?a ?b ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) diff --git a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls index 9227ab2e3a..abe6093d35 100644 --- a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls +++ b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls @@ -523,22 +523,22 @@ def succ (n: ChurchInt) = fun f -> fun x -> f (n f x) def succ' n = fun f -> fun x -> f (n f x) //│ succ_ty: ChurchInt -> ChurchInt //│ = -//│ succ: ChurchInt -> (forall 'b. 'b -> (forall 'a 'c. ('a -> 'c +//│ succ: ChurchInt -> (forall 'b. 'b -> (forall 'a 'c. 'a -> 'c //│ where -//│ 'b <: 'a -> 'a & 'a -> 'c))) +//│ 'b <: 'a -> 'a & 'a -> 'c)) //│ = [Function: succ1] -//│ succ': 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ succ': 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd))) +//│ 'a <: 'b -> 'c -> 'd)) //│ = [Function: succ$1] // * Note: without constrained types we wouldn't get the principal type of succ' succ_ty = succ -//│ ChurchInt -> (forall 'b. 'b -> (forall 'a 'c. ('a -> 'c +//│ ChurchInt -> (forall 'b. 'b -> (forall 'a 'c. 'a -> 'c //│ where -//│ 'b <: 'a -> 'a & 'a -> 'c))) +//│ 'b <: 'a -> 'a & 'a -> 'c)) //│ <: succ_ty: //│ ChurchInt -> ChurchInt //│ = [Function: succ1] @@ -546,10 +546,10 @@ succ_ty = succ // * Still requires distributivity even with CT :e succ_ty = succ' -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd))) +//│ 'a <: 'b -> 'c -> 'd)) //│ <: succ_ty: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -581,18 +581,18 @@ succ_ty = succ' :DontDistributeForalls succ' -//│ res: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('c -> 'e +//│ res: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where //│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd))) +//│ 'a <: 'b -> 'c -> 'd)) //│ = [Function: succ$1] // :e // * Error delayed by inconsistent constrained types succ' {} -//│ res: 'a -> (forall 'b 'c 'd. ('b -> 'd +//│ res: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where //│ 'a <: 'c -> 'd -//│ anything <: 'a -> 'b -> 'c)) +//│ anything <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] // :e // * Error delayed by inconsistent constrained types diff --git a/shared/src/test/diff/mlf-examples/ex_demo.mls b/shared/src/test/diff/mlf-examples/ex_demo.mls index c72fd3962a..773a09261f 100644 --- a/shared/src/test/diff/mlf-examples/ex_demo.mls +++ b/shared/src/test/diff/mlf-examples/ex_demo.mls @@ -1295,58 +1295,58 @@ print_fact2_ 6 def c_succ (n: Fint) = fun f -> fun x -> n f (f x) def c_succ_ n = fun f -> fun x -> n f (f x) -//│ c_succ: Fint -> (forall 'b. 'b -> (forall 'a 'c. ('c -> 'a +//│ c_succ: Fint -> (forall 'b. 'b -> (forall 'a 'c. 'c -> 'a //│ where -//│ 'b <: 'a -> 'a & 'c -> 'a))) +//│ 'b <: 'a -> 'a & 'c -> 'a)) //│ = [Function: c_succ1] -//│ c_succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. ('e -> 'd +//│ c_succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where //│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'e -> 'c))) +//│ 'b <: 'e -> 'c)) //│ = [Function: c_succ_1] def c_add_ n m = m c_succ_ n -//│ c_add_: 'a -> (forall 'b. ((forall 'c. 'c -> (forall 'd. 'd -> (forall 'e 'f 'g. ('g -> 'f +//│ c_add_: 'a -> (forall 'b. ((forall 'c. 'c -> (forall 'd. 'd -> (forall 'e 'f 'g. 'g -> 'f //│ where //│ 'd <: 'g -> 'e -//│ 'c <: 'd -> 'e -> 'f)))) -> 'a -> 'b) -> 'b) +//│ 'c <: 'd -> 'e -> 'f))) -> 'a -> 'b) -> 'b) //│ = [Function: c_add_1] // let c_i1 = fun f x -> f x def c_i1 = fun f -> fun x -> f x -//│ c_i1: 'a -> (forall 'b 'c. ('b -> 'c +//│ c_i1: 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ 'a <: 'b -> 'c)) +//│ 'a <: 'b -> 'c) //│ = [Function: c_i11] // let c_i2 = c_succ c_i1 def c_i2 = c_succ c_i1 def c_i2_ = c_succ_ c_i1 -//│ c_i2: 'b -> (forall 'a 'c. ('c -> 'a +//│ c_i2: 'b -> (forall 'a 'c. 'c -> 'a //│ where -//│ 'b <: 'a -> 'a & 'c -> 'a)) +//│ 'b <: 'a -> 'a & 'c -> 'a) //│ = [Function: c_i22] -//│ c_i2_: 'a -> (forall 'b 'c 'd. ('d -> 'c +//│ c_i2_: 'a -> (forall 'b 'c 'd. 'd -> 'c //│ where -//│ forall 'e. 'e -> (forall 'f 'g. ('f -> 'g -//│ where -//│ 'e <: 'f -> 'g)) <: 'a -> 'b -> 'c -//│ 'a <: 'd -> 'b)) +//│ forall 'e. 'e -> (forall 'f 'g. 'f -> 'g +//│ where +//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c +//│ 'a <: 'd -> 'b) //│ = [Function: c_i2_1] // let c_i3 = c_succ c_i2 def c_i3 = c_succ c_i2 def c_i3_ = c_succ_ c_i2 -//│ c_i3: 'b -> (forall 'a 'c. ('c -> 'a +//│ c_i3: 'b -> (forall 'a 'c. 'c -> 'a //│ where -//│ 'b <: 'a -> 'a & 'c -> 'a)) +//│ 'b <: 'a -> 'a & 'c -> 'a) //│ = [Function: c_i31] -//│ c_i3_: 'b -> (forall 'c 'd 'e. ('e -> 'd +//│ c_i3_: 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where //│ 'b <: 'e -> 'c -//│ forall 'f. 'f -> (forall 'g 'a. ('g -> 'a -//│ where -//│ 'f <: 'a -> 'a & 'g -> 'a)) <: 'b -> 'c -> 'd)) +//│ forall 'f. 'f -> (forall 'g 'a. 'g -> 'a +//│ where +//│ 'f <: 'a -> 'a & 'g -> 'a) <: 'b -> 'c -> 'd) //│ = [Function: c_i3_1] @@ -1354,16 +1354,16 @@ def c_i3_ = c_succ_ c_i2 c_i5_ = c_add_ c_i3_ c_i2 //│ c_i5_: 'b //│ where -//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. ('e -> 'd -//│ where -//│ 'c <: 'e -> 'g & 'e -> 'f -//│ 'b <: 'c -> 'g -> 'd -//│ forall 'h. 'h -> (forall 'i 'j 'k. ('k -> 'j -//│ where -//│ forall 'l. 'l -> (forall 'a 'm. ('m -> 'a -//│ where -//│ 'l <: 'a -> 'a & 'm -> 'a)) <: 'h -> 'i -> 'j -//│ 'h <: 'k -> 'i)) <: 'c -> 'f -> 'd)) +//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'e -> 'd +//│ where +//│ 'c <: 'e -> 'g & 'e -> 'f +//│ 'b <: 'c -> 'g -> 'd +//│ forall 'h. 'h -> (forall 'i 'j 'k. 'k -> 'j +//│ where +//│ forall 'l. 'l -> (forall 'a 'm. 'm -> 'a +//│ where +//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j +//│ 'h <: 'k -> 'i) <: 'c -> 'f -> 'd) //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/mlf-examples/ex_predicative.mls b/shared/src/test/diff/mlf-examples/ex_predicative.mls index e2c794b8ad..9cae3ca6c4 100644 --- a/shared/src/test/diff/mlf-examples/ex_predicative.mls +++ b/shared/src/test/diff/mlf-examples/ex_predicative.mls @@ -238,28 +238,28 @@ def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) //│ t2: 'a -> 'b -> ('c -> 'd //│ where //│ forall 'e 'f 'g. ('e -> 'f & 'f -> 'g) -> 'e -> 'g <: (forall 'h 'i 'j. 'j -> (('h -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm -//│ where -//│ 'n <: 'l -> 'm -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'i) -> 'i -//│ where -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'h)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'r & 's -> 'c -> 'd +//│ where +//│ 'n <: 'l -> 'm +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'i) -> 'i +//│ where +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'h)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'r & 's -> 'c -> 'd //│ forall 't 'u. ((forall 'v. anything -> anything -> 'v -> 'v) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'y 'z 'a1 'b1 'c1. 'b1 -> ('z -> 'c1 -//│ where -//│ 't <: (forall 'd1 'j 'e1. 'j -> (('d1 -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm -//│ where -//│ 'n <: 'l -> 'm -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'e1) -> 'e1 -//│ where -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'd1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'y & 'a1 -> 'z -> 'c1 -//│ forall 'f1 'g1. ((forall 'h1. anything -> anything -> 'h1 -> 'h1) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'i1 'j1 'k1 'l1 'm1. 'i1 -> ('l1 -> 'j1 -//│ where -//│ 'g1 <: (forall 'n1 'j 'o1. 'j -> (('o1 -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm -//│ where -//│ 'n <: 'l -> 'm -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'n1) -> 'n1 -//│ where -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'o1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'm1 & 'k1 -> 'l1 -> 'j1 -//│ anything -> 'a <: 'm1 -> 'i1 -> 'k1)) -> 'f1 & 'g1) -> 'f1 <: 'y -> 'b1 -> 'a1)) -> 'u & 't) -> 'u <: 'r -> 'b -> 's) +//│ where +//│ 't <: (forall 'd1 'j 'e1. 'j -> (('d1 -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm +//│ where +//│ 'n <: 'l -> 'm +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'e1) -> 'e1 +//│ where +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'd1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'y & 'a1 -> 'z -> 'c1 +//│ forall 'f1 'g1. ((forall 'h1. anything -> anything -> 'h1 -> 'h1) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'i1 'j1 'k1 'l1 'm1. 'i1 -> ('l1 -> 'j1 +//│ where +//│ 'g1 <: (forall 'n1 'j 'o1. 'j -> (('o1 -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm +//│ where +//│ 'n <: 'l -> 'm +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'n1) -> 'n1 +//│ where +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'o1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'm1 & 'k1 -> 'l1 -> 'j1 +//│ anything -> 'a <: 'm1 -> 'i1 -> 'k1)) -> 'f1 & 'g1) -> 'f1 <: 'y -> 'b1 -> 'a1)) -> 'u & 't) -> 'u <: 'r -> 'b -> 's) //│ = [Function: t22] :NoConstrainedTypes @@ -418,13 +418,13 @@ def t (z: nothing) = let x = fun (y: forall 't. 'a -> 't) -> y z in x x (fun two -> fun k -> two two two k) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) //│ res: 'a -> 'b //│ where -//│ forall 'c 'd 'e. ('c -> 'e -//│ where -//│ forall 'f 'g 'h. ('f -> 'h -//│ where -//│ forall 'i 'j 'k. ('i -> 'k -//│ where -//│ forall 'l. 'l -> anything -> 'l <: 'i -> 'j & 'j -> 'k) <: 'f -> 'g & 'g -> 'h) <: 'c -> 'd & 'd -> 'e) <: 'a -> 'm & 'm -> 'b +//│ forall 'c 'd 'e. 'c -> 'e +//│ where +//│ forall 'f 'g 'h. 'f -> 'h +//│ where +//│ forall 'i 'j 'k. 'i -> 'k +//│ where +//│ forall 'l. 'l -> anything -> 'l <: 'i -> 'j & 'j -> 'k <: 'f -> 'g & 'g -> 'h <: 'c -> 'd & 'd -> 'e <: 'a -> 'm & 'm -> 'b //│ = [Function (anonymous)] :NoConstrainedTypes diff --git a/shared/src/test/diff/mlf-examples/ex_shallow.mls b/shared/src/test/diff/mlf-examples/ex_shallow.mls index 8c582e6ce2..10069fa7fd 100644 --- a/shared/src/test/diff/mlf-examples/ex_shallow.mls +++ b/shared/src/test/diff/mlf-examples/ex_shallow.mls @@ -318,17 +318,17 @@ def a2_ (x: A1) = ) a3 //│ a1: ((forall 'a. 'a -> 'a) -> 'b) -> 'b //│ = [Function: a11] -//│ a3: 'a -> (forall 'b. (anything -> 'b +//│ a3: 'a -> (forall 'b. anything -> 'b //│ where -//│ 'a <: (forall 'c 'd 'e. ('c -> 'd & 'd -> 'e) -> 'c -> 'e) -> 'b)) +//│ 'a <: (forall 'c 'd 'e. ('c -> 'd & 'd -> 'e) -> 'c -> 'e) -> 'b) //│ = [Function: a31] -//│ a2: A1 -> (forall 'a. (anything -> 'a +//│ a2: A1 -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a)) +//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a21] -//│ a2_: A1 -> (forall 'a. (anything -> 'a +//│ a2_: A1 -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a)) +//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a2_1] def a0 = a2 a1 @@ -344,9 +344,9 @@ def a0_ = a2_ a1 //│ = [Function: a0_1] def a1' = fun f -> fun x -> f (f (either id x)) -//│ a1': 'a -> (forall 'b 'c 'd. ('b -> 'd +//│ a1': 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ 'a <: (forall 'e. 'e -> 'e | 'b) -> 'c & 'c -> 'd)) +//│ 'a <: (forall 'e. 'e -> 'e | 'b) -> 'c & 'c -> 'd) //│ = [Function: a1$1] def a2' (x: A1') = @@ -355,9 +355,9 @@ def a2' (x: A1') = let _ = x y church_two in y church_succ ) a3 -//│ a2': A1' -> (forall 'a. (anything -> 'a +//│ a2': A1' -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a)) +//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a2$1] def a2'_ x = @@ -366,11 +366,11 @@ def a2'_ x = let _ = x y church_two in y church_succ ) a3 -//│ a2'_: ((forall 'a 'b. ('a -> 'b & 'a) -> 'b) -> (forall 'c. 'c -> 'c) -> anything & (forall 'd. 'd -> (forall 'e. (anything -> 'e +//│ a2'_: ((forall 'a 'b. ('a -> 'b & 'a) -> 'b) -> (forall 'c. 'c -> 'c) -> anything & (forall 'd. 'd -> (forall 'e. anything -> 'e //│ where -//│ 'd <: (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> 'e))) -> (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> anything) -> (forall 'i. (anything -> 'i +//│ 'd <: (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> 'e)) -> (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> anything) -> (forall 'i. anything -> 'i //│ where -//│ forall 'j 'k 'l 'm. ('j -> 'k -> 'l) -> ('l -> 'm & 'j) -> 'k -> 'm <: (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> 'i)) +//│ forall 'j 'k 'l 'm. ('j -> 'k -> 'l) -> ('l -> 'm & 'j) -> 'k -> 'm <: (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> 'i) //│ = [Function: a2$_1] :e // * [FCP-LIM] since polymorphic RHS DNF fix diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 76329ae174..32fa4f50b9 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -7,8 +7,8 @@ class A(n: int) //│ class A(n: int) { //│ this: 'this //│ } -//│ where -//│ 'this :> A +//│ where +//│ 'this :> A A //│ (n: int,) -> A @@ -56,8 +56,8 @@ class C { //│ fun const: anything -> 'a -> 'a //│ fun id: 'a -> 'a //│ } -//│ where -//│ 'this :> C +//│ where +//│ 'this :> C class Base0(n) { @@ -73,9 +73,9 @@ class Base0(n) { //│ fun my: 'n //│ fun oops: 'my //│ } -//│ where -//│ 'this :> Base0 -//│ <: {my: 'my, n: 'n} +//│ where +//│ 'this :> Base0 +//│ <: {my: 'my, n: 'n} // :d // Base0 @@ -111,9 +111,9 @@ class Base1(base: int) { //│ fun getBase1: int //│ fun getBase2: int //│ } -//│ where -//│ 'this :> Base1 -//│ <: {base: int} +//│ where +//│ 'this :> Base1 +//│ <: {base: int} class Base1(base: int) { fun getBase1 = base @@ -126,8 +126,8 @@ class Base1(base: int) { //│ fun getBase1: int //│ fun me: 'this //│ } -//│ where -//│ 'this :> Base1 +//│ where +//│ 'this :> Base1 Base1 //│ (base: int,) -> Base1 @@ -172,8 +172,8 @@ class Rec(n) { //│ this: 'this //│ fun go: error //│ } -//│ where -//│ 'this :> Rec +//│ where +//│ 'this :> Rec @@ -199,8 +199,8 @@ class Annots(base: 0 | 1) { //│ this: 'this //│ fun a: (0 | 1,) //│ } -//│ where -//│ 'this :> Annots +//│ where +//│ 'this :> Annots diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index acbfa748f8..7bdd3c43e5 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -12,8 +12,8 @@ mixin BaseTest { //│ this: 'this //│ fun test: 'base //│ } -//│ where -//│ 'super <: {base: 'base} +//│ where +//│ 'super <: {base: 'base} mixin BaseInc { fun test = super.base + 1 @@ -25,9 +25,9 @@ mixin BaseInc { //│ fun test: int //│ fun test2: 'base //│ } -//│ where -//│ 'this <: {base: 'base} -//│ 'super <: {base: int} +//│ where +//│ 'this <: {base: 'base} +//│ 'super <: {base: int} // :d class Base1(base: int): BaseTest, BaseInc { @@ -39,9 +39,9 @@ class Base1(base: int): BaseTest, BaseInc { //│ fun test2: int //│ fun test3: (int, 'base | int,) //│ } -//│ where -//│ 'this :> Base1 -//│ <: {base: 'base} +//│ where +//│ 'this :> Base1 +//│ <: {base: 'base} Base1(1).test //│ int @@ -58,8 +58,8 @@ class Base1(base): BaseTest //│ this: 'this //│ fun test: nothing //│ } -//│ where -//│ 'this :> Base1 +//│ where +//│ 'this :> Base1 Base1 //│ (base: anything,) -> Base1 @@ -87,8 +87,8 @@ class Base1(x): BaseTest //│ this: 'this //│ fun test: nothing //│ } -//│ where -//│ 'this :> Base1 +//│ where +//│ 'this :> Base1 Base1 //│ (x: anything,) -> Base1 @@ -103,16 +103,16 @@ mixin Foo { //│ this: 'this //│ fun test: (int & 'a) -> (int, 'a, 'misc,) //│ } -//│ where -//│ 'super <: {base: int, misc: 'misc} +//│ where +//│ 'super <: {base: int, misc: 'misc} module Base1(base: int, misc: string): Foo //│ namespace Base1(base: int, misc: string) { //│ this: 'this //│ fun test: (int & 'a) -> (int, 'a, string,) //│ } -//│ where -//│ 'this :> Base1 +//│ where +//│ 'this :> Base1 Base1.test //│ (int & 'a) -> (int, 'a, string,) @@ -142,8 +142,8 @@ mixin Wrap { //│ fun wrap: 'a -> ('b,) //│ fun wrapA: 'c -> ('d,) //│ } -//│ where -//│ 'super <: {wrap: 'a -> 'b, wrapA: 'c -> 'd} +//│ where +//│ 'super <: {wrap: 'a -> 'b, wrapA: 'c -> 'd} @@ -154,8 +154,8 @@ module WrapBase1: WrapBase, Wrap //│ fun wrap: 'a -> ('a,) //│ fun wrapA: int -> (int,) //│ } -//│ where -//│ 'this :> WrapBase1 +//│ where +//│ 'this :> WrapBase1 WrapBase1 @@ -206,8 +206,8 @@ module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ fun wrap: 'a -> ((('a,),),) //│ fun wrapA: int -> (((int,),),) //│ } -//│ where -//│ 'this :> WrapBase2 +//│ where +//│ 'this :> WrapBase2 let w = WrapBase2.wrap //│ let w: 'a -> ((('a,),),) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 06261544e1..f6670f1f93 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -11,9 +11,9 @@ class Lit(n: int) //│ class Lit(n: int) { //│ this: 'this0 //│ } -//│ where -//│ 'this0 :> Lit -//│ 'this :> Add[?] +//│ where +//│ 'this0 :> Lit +//│ 'this :> Add[?] fun add11 = Add(Lit(1), Lit(2)) //│ fun add11: Add['E] @@ -46,9 +46,9 @@ mixin EvalBase { //│ this: 'this //│ fun eval: (Add['E] | Lit) -> int //│ } -//│ where -//│ 'E <: 'lhs -//│ 'this <: {eval: 'lhs -> int} +//│ where +//│ 'E <: 'lhs +//│ 'this <: {eval: 'lhs -> int} module TestLang: EvalBase @@ -56,10 +56,10 @@ module TestLang: EvalBase //│ this: 'this //│ fun eval: 'a -> int //│ } -//│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a -//│ 'this :> TestLang +//│ where +//│ 'a <: Add['E] | Lit +//│ 'E <: 'a +//│ 'this :> TestLang TestLang.eval //│ 'a -> int @@ -75,8 +75,8 @@ class Neg(expr: A) //│ class Neg[A](expr: A) { //│ this: 'this //│ } -//│ where -//│ 'this :> Neg[?] +//│ where +//│ 'this :> Neg[?] let add2negadd11 = Add(Lit(2), Neg(add11)) //│ let add2negadd11: Add['E] @@ -96,10 +96,10 @@ mixin EvalNeg { //│ this: 'this //│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } -//│ where -//│ 'A <: 'expr -//│ 'this <: {eval: 'expr -> int} -//│ 'super <: {eval: 'a -> 'b} +//│ where +//│ 'A <: 'expr +//│ 'this <: {eval: 'expr -> int} +//│ 'super <: {eval: 'a -> 'b} module TestLang: EvalBase, EvalNeg @@ -107,11 +107,11 @@ module TestLang: EvalBase, EvalNeg //│ this: 'this //│ fun eval: 'a -> int //│ } -//│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a -//│ 'this :> TestLang +//│ where +//│ 'a <: Add['E] | Lit | Neg['A] +//│ 'A <: 'a +//│ 'E <: 'a +//│ 'this :> TestLang TestLang.eval //│ 'a -> int @@ -153,26 +153,26 @@ mixin EvalNegNeg { //│ this: 'this //│ fun eval: (Neg['A] | 'a & ~Neg) -> 'b //│ } -//│ where -//│ 'A :> 'A0 -//│ <: 'A1 & (~Neg | Neg['A2]) -//│ 'A2 <: 'expr -//│ 'this <: {eval: 'expr -> 'b} -//│ 'super <: {eval: (Neg[in 'A0 & (~Neg | Neg[in 'expr out nothing]) out 'A0 | 'A1] & {Neg#A :> 'A0 & (~Neg | Neg[in 'expr out nothing]) <: 'A0 | 'A1} | 'a) -> 'b} +//│ where +//│ 'A :> 'A0 +//│ <: 'A1 & (~Neg | Neg['A2]) +//│ 'A2 <: 'expr +//│ 'this <: {eval: 'expr -> 'b} +//│ 'super <: {eval: (Neg[in 'A0 & (~Neg | Neg[in 'expr out nothing]) out 'A0 | 'A1] & {Neg#A :> 'A0 & (~Neg | Neg[in 'expr out nothing]) <: 'A0 | 'A1} | 'a) -> 'b} module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ namespace TestLang() { //│ this: 'this //│ fun eval: 'a -> int //│ } -//│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg['A1]) -//│ 'A1 <: 'a -//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a -//│ 'E <: 'a -//│ 'this :> TestLang +//│ where +//│ 'a <: Add['E] | Lit | Neg['A] +//│ 'A :> 'A0 +//│ <: 'A0 & (~Neg | Neg['A1]) +//│ 'A1 <: 'a +//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a +//│ 'E <: 'a +//│ 'this :> TestLang fun mk(n) = if n is 0 then Lit(0) diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index dfeb9e48bc..285458314e 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -8,8 +8,8 @@ class Add(lhs: E, rhs: E) //│ class Add[E](lhs: E, rhs: E) { //│ this: 'this //│ } -//│ where -//│ 'this :> Add[?] +//│ where +//│ 'this :> Add[?] let e = Add(1, 1) //│ let e: Add['E] diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 637771d348..f194e53b1d 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -11,9 +11,9 @@ class Lit(n: int) //│ class Lit(n: int) { //│ this: 'this0 //│ } -//│ where -//│ 'this0 :> Lit -//│ 'this :> Add[?] +//│ where +//│ 'this0 :> Lit +//│ 'this :> Add[?] let add11 = Add(Lit(1), Lit(2)) //│ let add11: Add['E] @@ -41,9 +41,9 @@ mixin EvalBase { //│ this: 'this //│ fun eval: (Add['E] | Lit) -> int //│ } -//│ where -//│ 'E <: 'lhs -//│ 'this <: {eval: 'lhs -> int} +//│ where +//│ 'E <: 'lhs +//│ 'this <: {eval: 'lhs -> int} module TestLang: EvalBase @@ -51,10 +51,10 @@ module TestLang: EvalBase //│ this: 'this //│ fun eval: 'a -> int //│ } -//│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a -//│ 'this :> TestLang +//│ where +//│ 'a <: Add['E] | Lit +//│ 'E <: 'a +//│ 'this :> TestLang TestLang.eval //│ 'a -> int @@ -93,8 +93,8 @@ class Neg(expr: A) //│ class Neg[A](expr: A) { //│ this: 'this //│ } -//│ where -//│ 'this :> Neg[?] +//│ where +//│ 'this :> Neg[?] let add2negadd11 = Add(Lit(2), Neg(add11)) //│ let add2negadd11: Add['E] @@ -115,10 +115,10 @@ mixin EvalNeg { //│ this: 'this //│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } -//│ where -//│ 'A <: 'expr -//│ 'this <: {eval: 'expr -> int} -//│ 'super <: {eval: 'a -> 'b} +//│ where +//│ 'A <: 'expr +//│ 'this <: {eval: 'expr -> int} +//│ 'super <: {eval: 'a -> 'b} module TestLang: EvalBase, EvalNeg @@ -126,11 +126,11 @@ module TestLang: EvalBase, EvalNeg //│ this: 'this //│ fun eval: 'a -> int //│ } -//│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a -//│ 'this :> TestLang +//│ where +//│ 'a <: Add['E] | Lit | Neg['A] +//│ 'A <: 'a +//│ 'E <: 'a +//│ 'this :> TestLang TestLang.eval //│ 'a -> int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 8f34bc674d..b85a7aa5f6 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -14,8 +14,8 @@ class Some(value: A) { //│ fun get: A //│ fun toArray: (A,) //│ } -//│ where -//│ 'this :> Some[?] +//│ where +//│ 'this :> Some[?] let s = Some(1) @@ -57,8 +57,8 @@ module None { //│ fun get: nothing //│ fun toArray: () //│ } -//│ where -//│ 'this :> None +//│ where +//│ 'this :> None None.toArray @@ -117,8 +117,8 @@ class Test(n) { //│ this: 'this //│ fun foo: int //│ } -//│ where -//│ 'this :> Test +//│ where +//│ 'this :> Test Test(1) //│ Test @@ -157,8 +157,8 @@ class Test(n: A) { //│ this: 'this //│ fun foo: error | int //│ } -//│ where -//│ 'this :> Test[?] +//│ where +//│ 'this :> Test[?] Test(1) //│ Test['A] @@ -182,8 +182,8 @@ class Test(n: A) { //│ fun foo1: (x: A,) -> A //│ fun id: 'a -> 'a //│ } -//│ where -//│ 'this :> Test[?] +//│ where +//│ 'this :> Test[?] Test(1) //│ Test['A] @@ -235,8 +235,8 @@ class Test { //│ fun foo1: (x: A,) -> A //│ fun foo2: (x: A,) -> (error | int) //│ } -//│ where -//│ 'this :> Test[?] +//│ where +//│ 'this :> Test[?] Test().foo1 //│ (x: 'A,) -> 'A diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index cbc0857d1c..de04caedf8 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -10,8 +10,8 @@ class Foo() //│ this: 'this //│ } //│ 123 -//│ where -//│ 'this :> Foo +//│ where +//│ 'this :> Foo Foo //│ () -> Foo @@ -42,8 +42,8 @@ fun foo = {x: bar} fun bar = {y: foo} //│ fun foo: 'foo //│ fun bar: {y: 'foo} -//│ where -//│ 'foo :> {x: {y: 'foo}} +//│ where +//│ 'foo :> {x: {y: 'foo}} // FIXME pretty-printing? foo @@ -72,8 +72,8 @@ fun foo(a) = {h: a, t: bar(a)} fun bar(b) = foo(b) //│ fun foo: 'a -> 'b //│ fun bar: 'a -> 'b -//│ where -//│ 'b :> {h: 'a, t: 'b} +//│ where +//│ 'b :> {h: 'a, t: 'b} :ns foo @@ -88,9 +88,9 @@ fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} //│ fun foo: 'a -> 'b //│ fun bar: 'a -> 'c -//│ where -//│ 'b :> {h1: 'a, t1: 'c} -//│ 'c :> {h2: 'a, t2: 'b} +//│ where +//│ 'b :> {h1: 'a, t1: 'c} +//│ 'c :> {h2: 'a, t2: 'b} @@ -108,9 +108,9 @@ module Test0_2 { //│ this: 'this0 //│ fun b: 123 //│ } -//│ where -//│ 'this0 :> Test0_2 -//│ 'this :> Test0_1 +//│ where +//│ 'this0 :> Test0_2 +//│ 'this :> Test0_1 Test0_1.a //│ 123 @@ -129,9 +129,9 @@ class Test0_2() { //│ this: 'this0 //│ fun b: 123 //│ } -//│ where -//│ 'this0 :> Test0_2 -//│ 'this :> Test0_1 +//│ where +//│ 'this0 :> Test0_2 +//│ 'this :> Test0_1 :e // TODO @@ -156,9 +156,9 @@ module Test1_2 { //│ this: 'this0 //│ fun b: error //│ } -//│ where -//│ 'this0 :> Test1_2 -//│ 'this :> Test1_1 +//│ where +//│ 'this0 :> Test1_2 +//│ 'this :> Test1_1 Test1_1.a //│ error @@ -186,9 +186,9 @@ class Test1_2 { //│ this: 'this0 //│ fun b: error //│ } -//│ where -//│ 'this0 :> Test1_2 -//│ 'this :> Test1_1 +//│ where +//│ 'this0 :> Test1_2 +//│ 'this :> Test1_1 // TODO check TV hygiene @@ -242,9 +242,9 @@ module Test2_2 { //│ fun c: error //│ fun e: error //│ } -//│ where -//│ 'this0 :> Test2_2 -//│ 'this :> Test2_1 +//│ where +//│ 'this0 :> Test2_2 +//│ 'this :> Test2_1 Test2_1.t2.b //│ 123 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 75266de9c1..67bb9ff37f 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -22,9 +22,9 @@ class Base1(p: int): Over { //│ fun p: "hi" //│ fun test: (int, "hi" | 'p,) //│ } -//│ where -//│ 'this :> Base1 -//│ <: {p: 'p} +//│ where +//│ 'this :> Base1 +//│ <: {p: 'p} Base1(123).test From df22230b47ea1b5b9ef7a5f6c7bee5717c04f18b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Feb 2023 23:50:23 +0800 Subject: [PATCH 065/498] WIP Finalize inheritance with the complete type --- .../src/main/scala/mlscript/NuTypeDefs.scala | 10 +- .../main/scala/mlscript/TyperDatatypes.scala | 92 ++++++++++++++----- .../main/scala/mlscript/utils/package.scala | 2 + shared/src/test/diff/nu/BasicClasses.mls | 38 ++++---- shared/src/test/diff/nu/BasicMixins.mls | 28 +++--- shared/src/test/diff/nu/ECOOP23.mls | 85 +++++++++-------- shared/src/test/diff/nu/ECOOP23_min.mls | 22 ++--- shared/src/test/diff/nu/ECOOP23_repro.mls | 91 +++++++----------- shared/src/test/diff/nu/GenericClasses.mls | 52 ++++++----- shared/src/test/diff/nu/MutualRec.mls | 52 +++++------ shared/src/test/diff/nu/ParamOverriding.mls | 6 +- .../src/test/scala/mlscript/DiffTests.scala | 2 + 12 files changed, 261 insertions(+), 219 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8b24e9f928..bdebfc883e 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -148,7 +148,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) - case TypedNuCls(level, td, ttu, tps, params, members, thisTy) => + case cls @ TypedNuCls(level, td, ttu, tps, params, members, thisTy) => println(">>",level,ctx.lvl) // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), // params.mapValues(_.freshenAbove(level, rigidify)), @@ -157,7 +157,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - thisTy.freshenAbove(lim, rigidify)) + thisTy.freshenAbove(lim, rigidify))(cls.instanceType) // case _ => ??? // } } @@ -196,6 +196,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // members: Map[Str, LazyTypeInfo]) members: Map[Str, NuMember], thisTy: ST + )( + val instanceType: ST, // only meant to be used in `force` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { def nme: TypeName = td.nme @@ -209,7 +211,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(N, thisTy).asInstanceOf[TV] - ) + )(instanceType) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, ttu, @@ -218,7 +220,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.invar, thisTy).asInstanceOf[TV] - ) + )(instanceType) } case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, members: Map[Str, NuMember], ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 11d145f3ed..8cffad57c9 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -64,7 +64,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // TODO does this also need freshening in freshenAbove? private lazy val thisTV: TV = - freshVar(noProv/*FIXME*/, N, S("this"))(lvl + 1) + freshVar(noProv/*FIXME*/, N, S("this_"+decl.name))(lvl + 1) def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") @@ -121,9 +121,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // constrain(res_ty.ty, tv) ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.ty, tv) } res_ty + + case td: NuTypeDef => + td.kind match { + case Cls | Nms => + implicit val prov: TP = noProv // TODO ctx.nest.nextLevel { implicit ctx => @@ -134,6 +139,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => S(tp.name), true), N, S(tp.name))) + println(s"Type params ${tparams.mkString(" ")}") + implicit val vars: Map[Str, SimpleType] = // outerVars ++ tparams.iterator.mapKeys(_.name).toMap outerVars ++ tparams.iterator.map { @@ -174,9 +181,25 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) - val finalType = freshVar(noProv/*TODO*/, N, S("this")) + + // val finalType = freshVar(noProv/*TODO*/, N, S("this")) + val finalType = thisTV + + val tparamMems = tparams.map { case (tn, tv) => + val fldNme = td.nme.name + "#" + tn.name + NuParam(Var(fldNme).withLocOf(tn), FieldType(S(tv), tv)(tv.prov), isType = true) + } + // tparamMems.map(p => p.nme -> p.ty):Int + val tparamFields = tparamMems.map(p => p.nme -> p.ty) + assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) + + // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { - def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]): Ls[NuMember] = parents match { + + def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]) + // : Ls[NuMember] = + : (ST, Ls[NuMember]) = + parents match { // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { // case R(p) :: ps => ??? // case L(p) :: ps => @@ -240,18 +263,27 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => - assert(finalType.level === lvl) - constrain(superType, finalType) - members - } - val baseType = RecordType(typedParams)(ttp(td.params, isType = true)) - val tparamMems = tparams.map { case (tn, tv) => - val fldNme = td.nme.name + "#" + tn.name - NuParam(Var(fldNme).withLocOf(tn), FieldType(S(tv), tv)(tv.prov), isType = true) + val thisType = superType & + clsNameToNomTag(td)(provTODO, ctx) & + RecordType(tparamFields)(ttp(td.params, isType = true)) + // trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { + // assert(finalType.level === lvl) + // constrain(thisType, finalType) + // members + // }() + println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") + (thisType, members) } + + val baseType = + // clsNameToNomTag(td)(provTODO, ctx) & + // RecordType(tparamFields ::: typedParams)(ttp(td.params, isType = true)) + RecordType(typedParams)(ttp(td.params, isType = true)) val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) // val baseMems = inherit(td.parents, baseType, Nil) - val baseMems = inherit(td.parents, baseType, tparamMems ++ paramMems) + + val (thisType, baseMems) = + inherit(td.parents, baseType, tparamMems ++ paramMems) // ctx += thisTV @@ -274,10 +306,16 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // )(provTODO) // constrain(thisTy, thisTV) + // val thisType = superType & + // clsNameToNomTag(td)(provTODO, ctx) & + // RecordType(tparamFields)(ttp(td.params, isType = true)) + // val mems = baseMems ++ paramMems ++ clsMems val mems = baseMems ++ clsMems + TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems.map(d => d.name -> d).toMap, thisTV) + tparams, typedParams, mems.map(d => d.name -> d).toMap, thisTV + )(thisType) } case Mxn => implicit val prov: TP = noProv // TODO @@ -340,17 +378,23 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => def force()(implicit raise: Raise): TypedNuTermDef = { val res = complete() res.force() - decl match { - case td: NuTypeDef => - td.kind match { - case Cls | Nms => - implicit val prov: TP = noProv // TODO - val thisTy = ClassTag(Var(td.name), - Set.empty//TODO - )(provTODO) - constrain(thisTy, thisTV) - case _ => - } + // decl match { + // case td: NuTypeDef => + // td.kind match { + // case Cls | Nms => + // // implicit val prov: TP = noProv // TODO + // // val thisTy = ClassTag(Var(td.name), + // // Set.empty//TODO + // // )(provTODO) + // // constrain(thisTy, thisTV) + // case _ => + // } + // case _ => + // } + res match { + case cls: TypedNuCls => + implicit val prov: TP = noProv // TODO + constrain(cls.instanceType, thisTV) case _ => } res diff --git a/shared/src/main/scala/mlscript/utils/package.scala b/shared/src/main/scala/mlscript/utils/package.scala index 266751c2ae..fcf17596ed 100644 --- a/shared/src/main/scala/mlscript/utils/package.scala +++ b/shared/src/main/scala/mlscript/utils/package.scala @@ -68,6 +68,8 @@ package object utils { def mapValues[C](f: B => C): List[A -> C] = mapValuesIter(f).toList def mapKeysIter[C](f: A => C): Iterator[C -> B] = self.iterator.map(p => f(p._1) -> p._2) def mapValuesIter[C](f: B => C): Iterator[A -> C] = self.iterator.map(p => p._1 -> f(p._2)) + def keys: Iterator[A] = self.iterator.map(_._1) + def values: Iterator[B] = self.iterator.map(_._2) def toSortedMap(implicit ord: Ordering[A]): SortedMap[A, B] = SortedMap.from(self) } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 32fa4f50b9..b1506cdd7c 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -5,10 +5,10 @@ class A(n: int) //│ class A(n: int) { -//│ this: 'this +//│ this: 'this_A //│ } //│ where -//│ 'this :> A +//│ 'this_A :> A & {n: int} A //│ (n: int,) -> A @@ -52,12 +52,12 @@ class C { fun const(x) = id } //│ class C() { -//│ this: 'this +//│ this: 'this_C //│ fun const: anything -> 'a -> 'a //│ fun id: 'a -> 'a //│ } //│ where -//│ 'this :> C +//│ 'this_C :> C class Base0(n) { @@ -67,15 +67,15 @@ class Base0(n) { fun oops = this.my } //│ class Base0(n: nothing) { -//│ this: 'this -//│ fun me: 'this +//│ this: 'this_Base0 +//│ fun me: 'this_Base0 //│ fun mine: 'n //│ fun my: 'n //│ fun oops: 'my //│ } //│ where -//│ 'this :> Base0 -//│ <: {my: 'my, n: 'n} +//│ 'this_Base0 :> Base0 & {n: nothing} +//│ <: {my: 'my, n: 'n} // :d // Base0 @@ -106,14 +106,14 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1(base: int) { -//│ this: 'this +//│ this: 'this_Base1 //│ fun foo: int -> int //│ fun getBase1: int //│ fun getBase2: int //│ } //│ where -//│ 'this :> Base1 -//│ <: {base: int} +//│ 'this_Base1 :> Base1 & {base: int} +//│ <: {base: int} class Base1(base: int) { fun getBase1 = base @@ -121,13 +121,13 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1(base: int) { -//│ this: 'this +//│ this: 'this_Base1 //│ fun foo: int -> int //│ fun getBase1: int -//│ fun me: 'this +//│ fun me: 'this_Base1 //│ } //│ where -//│ 'this :> Base1 +//│ 'this_Base1 :> Base1 & {base: int} Base1 //│ (base: int,) -> Base1 @@ -143,7 +143,7 @@ b.getBase1 // :d b.me -//│ Base1 +//│ Base1 & {base: int} :e b.getBaseTypo @@ -169,11 +169,11 @@ class Rec(n) { //│ ║ l.163: } //│ ╙── ^ //│ class Rec(n: nothing) { -//│ this: 'this +//│ this: 'this_Rec //│ fun go: error //│ } //│ where -//│ 'this :> Rec +//│ 'this_Rec :> Rec & {n: nothing} @@ -196,11 +196,11 @@ class Annots(base: 0 | 1) { //│ ║ l.183: a: int //│ ╙── ^^^ //│ class Annots(base: (0 | 1,)) { -//│ this: 'this +//│ this: 'this_Annots //│ fun a: (0 | 1,) //│ } //│ where -//│ 'this :> Annots +//│ 'this_Annots :> Annots & {base: (0 | 1,)} diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 7bdd3c43e5..e646698dcc 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -34,14 +34,14 @@ class Base1(base: int): BaseTest, BaseInc { fun test3 = [base, this.base] } //│ class Base1(base: int) { -//│ this: 'this +//│ this: 'this_Base1 //│ fun test: int -//│ fun test2: int +//│ fun test2: 'base | int //│ fun test3: (int, 'base | int,) //│ } //│ where -//│ 'this :> Base1 -//│ <: {base: 'base} +//│ 'this_Base1 :> Base1 & {test2: 'base | int, test: int, base: int} +//│ <: {base: 'base} Base1(1).test //│ int @@ -55,11 +55,11 @@ Base1(1).test3 class Base1(base): BaseTest //│ class Base1(base: nothing) { -//│ this: 'this +//│ this: 'this_Base1 //│ fun test: nothing //│ } //│ where -//│ 'this :> Base1 +//│ 'this_Base1 :> Base1 & {test: nothing, base: nothing} Base1 //│ (base: anything,) -> Base1 @@ -84,11 +84,11 @@ class Base1(x): BaseTest //│ ║ l.8: fun test = super.base //│ ╙── ^^^^^ //│ class Base1(x: nothing) { -//│ this: 'this +//│ this: 'this_Base1 //│ fun test: nothing //│ } //│ where -//│ 'this :> Base1 +//│ 'this_Base1 :> Base1 & {test: nothing, x: nothing} Base1 //│ (x: anything,) -> Base1 @@ -108,11 +108,11 @@ mixin Foo { module Base1(base: int, misc: string): Foo //│ namespace Base1(base: int, misc: string) { -//│ this: 'this +//│ this: 'this_Base1 //│ fun test: (int & 'a) -> (int, 'a, string,) //│ } //│ where -//│ 'this :> Base1 +//│ 'this_Base1 :> Base1 & {misc: string, test: (int & 'a) -> (int, 'a, string,), base: int} Base1.test //│ (int & 'a) -> (int, 'a, string,) @@ -150,12 +150,12 @@ mixin Wrap { // :d module WrapBase1: WrapBase, Wrap //│ namespace WrapBase1() { -//│ this: 'this +//│ this: 'this_WrapBase1 //│ fun wrap: 'a -> ('a,) //│ fun wrapA: int -> (int,) //│ } //│ where -//│ 'this :> WrapBase1 +//│ 'this_WrapBase1 :> WrapBase1 & {wrap: 'a -> ('a,), wrapA: int -> (int,)} WrapBase1 @@ -202,12 +202,12 @@ WrapBase1.wrapA("ok") module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ namespace WrapBase2() { -//│ this: 'this +//│ this: 'this_WrapBase2 //│ fun wrap: 'a -> ((('a,),),) //│ fun wrapA: int -> (((int,),),) //│ } //│ where -//│ 'this :> WrapBase2 +//│ 'this_WrapBase2 :> WrapBase2 & {wrap: 'a -> ((('a,),),), wrapA: int -> (((int,),),)} let w = WrapBase2.wrap //│ let w: 'a -> ((('a,),),) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index f6670f1f93..6670afc509 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -6,14 +6,14 @@ class Add(lhs: E, rhs: E) class Lit(n: int) //│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this +//│ this: 'this_Add //│ } //│ class Lit(n: int) { -//│ this: 'this0 +//│ this: 'this_Lit //│ } //│ where -//│ 'this0 :> Lit -//│ 'this :> Add[?] +//│ 'this_Lit :> Lit & {n: int} +//│ 'this_Add :> Add['E] & {lhs: E, rhs: E} fun add11 = Add(Lit(1), Lit(2)) //│ fun add11: Add['E] @@ -53,19 +53,19 @@ mixin EvalBase { module TestLang: EvalBase //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this_TestLang +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a -//│ 'this :> TestLang +//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit) -> int} +//│ <: {eval: 'E -> int} +//│ 'E <: (Add['E0] | Lit) & (Add['E1] | Lit) +//│ 'E1 <: Add['E0] | Lit TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit) -> int //│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a +//│ 'E <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit TestLang.eval(add11) //│ int @@ -73,10 +73,10 @@ TestLang.eval(add11) class Neg(expr: A) //│ class Neg[A](expr: A) { -//│ this: 'this +//│ this: 'this_Neg //│ } //│ where -//│ 'this :> Neg[?] +//│ 'this_Neg :> Neg['A] & {expr: A} let add2negadd11 = Add(Lit(2), Neg(add11)) //│ let add2negadd11: Add['E] @@ -104,21 +104,24 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this_TestLang +//│ fun eval: (Add['E] | Lit | Neg['A]) -> int //│ } //│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a -//│ 'this :> TestLang +//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit | Neg['A]) -> int} +//│ <: {eval: ('A | 'E) -> int} +//│ 'A <: Add['E0] | Lit | Neg['A0] +//│ 'E <: (Add['E1] | Lit | Neg['A1]) & (Add['E2] | Lit | Neg['A2]) +//│ 'A1 <: Add['E0] | Lit | Neg['A0] +//│ 'E1 <: Add['E2] | Lit | Neg['A2] +//│ 'A2 <: Add['E0] | Lit | Neg['A0] TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit | Neg['A]) -> int //│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a +//│ 'A <: Add['E0] | Lit | Neg['A0] +//│ 'E <: Add[in (Add['E1] | Lit | Neg['A1]) & 'E2 | 'E1 out 'E2 & 'E1] | Lit | Neg[in (Add['E0] | Lit | Neg['A0]) & 'A2 | 'A1 out 'A2 & 'A1] +//│ 'A1 <: Add['E0] | Lit | Neg['A0] TestLang.eval(add11) @@ -162,17 +165,20 @@ mixin EvalNegNeg { module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this_TestLang +//│ fun eval: (Add['E] | Lit | Neg[Neg['A] & 'A0]) -> (int | 'a) //│ } //│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg['A1]) -//│ 'A1 <: 'a -//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a -//│ 'E <: 'a -//│ 'this :> TestLang +//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit | Neg[Neg['A] & 'A0]) -> (int | 'a)} +//│ <: {eval: 'E -> int & nothing -> 'a} +//│ 'A0 <: nothing +//│ 'A <: nothing +//│ 'E <: (Add['E0] | Lit | Neg[Neg['A1] & 'A2]) & (Add['E1] | Lit | Neg[Neg['A3] & 'A4]) +//│ 'A4 <: nothing +//│ 'A3 <: nothing +//│ 'E1 <: Add['E0] | Lit | Neg[Neg['A1] & 'A2] +//│ 'A2 <: nothing +//│ 'A1 <: nothing fun mk(n) = if n is 0 then Lit(0) @@ -185,14 +191,13 @@ fun mk(n) = if n is //│ 'A :> Lit | 'a TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit | Neg[Neg['A] & 'A0]) -> int //│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg['A1]) -//│ 'A1 <: 'a -//│ 'A0 <: (Neg[in 'a out nothing] | ~Neg[?]) & 'a -//│ 'E <: 'a +//│ 'A0 <: nothing +//│ 'A <: nothing +//│ 'E <: Add[in (Add['E0] | Lit | Neg[Neg['A1] & 'A2]) & 'E1 | 'E0 out 'E1 & 'E0] | Lit | Neg[Neg['A1] & 'A2] +//│ 'A2 <: nothing +//│ 'A1 <: nothing TestLang.eval(mk(0)) //│ int diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index 285458314e..b457fb7ffb 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -6,10 +6,10 @@ class Add(lhs: E, rhs: E) // class Lit(n: int) //│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this +//│ this: 'this_Add //│ } //│ where -//│ 'this :> Add[?] +//│ 'this_Add :> Add['E] & {lhs: E, rhs: E} let e = Add(1, 1) //│ let e: Add['E] @@ -20,11 +20,11 @@ let e = Add(1, 1) e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α35 +//│ | 0. : α34 //│ ======== TYPED ======== -//│ res: Some(α35) where -//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) -//│ E23_36 :> 1 +//│ res: Some(α34) where +//│ α34 :> (Add<> & {Add#E: mut E23_35..E23_35}) +//│ E23_35 :> 1 //│ Add['E] //│ where //│ 'E :> 1 @@ -36,12 +36,12 @@ e.lhs e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α35 +//│ | 0. : α34 //│ ======== TYPED ======== -//│ res: Some(α35) where -//│ α35 :> (Add<> & {Add#E: mut E23_36..E23_36}) <: {lhs: lhs45} -//│ E23_36 :> 1 <: lhs45 -//│ lhs45 :> 1 +//│ res: Some(α34) where +//│ α34 :> (Add<> & {Add#E: mut E23_35..E23_35}) <: {lhs: lhs44} +//│ E23_35 :> 1 <: lhs44 +//│ lhs44 :> 1 //│ Add['E] //│ where //│ 'E :> 1 diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index f194e53b1d..474bad63e4 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -6,14 +6,14 @@ class Add(lhs: E, rhs: E) class Lit(n: int) //│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this +//│ this: 'this_Add //│ } //│ class Lit(n: int) { -//│ this: 'this0 +//│ this: 'this_Lit //│ } //│ where -//│ 'this0 :> Lit -//│ 'this :> Add[?] +//│ 'this_Lit :> Lit & {n: int} +//│ 'this_Add :> Add['E] & {lhs: E, rhs: E} let add11 = Add(Lit(1), Lit(2)) //│ let add11: Add['E] @@ -48,19 +48,19 @@ mixin EvalBase { module TestLang: EvalBase //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this_TestLang +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a -//│ 'this :> TestLang +//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit) -> int} +//│ <: {eval: 'E -> int} +//│ 'E <: (Add['E0] | Lit) & (Add['E1] | Lit) +//│ 'E1 <: Add['E0] | Lit TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit) -> int //│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a +//│ 'E <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit @@ -76,7 +76,7 @@ add11 //│ Add['E] //│ where //│ 'E :> Lit -//│ <: Add['E] | Lit +//│ <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit TestLang.eval(add11) //│ int @@ -85,16 +85,16 @@ add11 //│ Add['E] //│ where //│ 'E :> Lit -//│ <: Add['E] | Lit +//│ <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit class Neg(expr: A) //│ class Neg[A](expr: A) { -//│ this: 'this +//│ this: 'this_Neg //│ } //│ where -//│ 'this :> Neg[?] +//│ 'this_Neg :> Neg['A] & {expr: A} let add2negadd11 = Add(Lit(2), Neg(add11)) //│ let add2negadd11: Add['E] @@ -102,7 +102,7 @@ let add2negadd11 = Add(Lit(2), Neg(add11)) //│ 'E :> Lit | Neg['A] //│ 'A :> Add['E0] //│ 'E0 :> Lit -//│ <: Add['E0] | Lit +//│ <: Add[in (Add['E1] | Lit) & 'E2 | 'E1 out 'E2 & 'E1] | Lit mixin EvalNeg { @@ -123,21 +123,24 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ this: 'this_TestLang +//│ fun eval: (Add['E] | Lit | Neg['A]) -> int //│ } //│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a -//│ 'this :> TestLang +//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit | Neg['A]) -> int} +//│ <: {eval: ('A | 'E) -> int} +//│ 'A <: Add['E0] | Lit | Neg['A0] +//│ 'E <: (Add['E1] | Lit | Neg['A1]) & (Add['E2] | Lit | Neg['A2]) +//│ 'A2 <: Add['E0] | Lit | Neg['A0] +//│ 'E2 <: Add['E1] | Lit | Neg['A1] +//│ 'A1 <: Add['E0] | Lit | Neg['A0] TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit | Neg['A]) -> int //│ where -//│ 'a <: Add['E] | Lit | Neg['A] -//│ 'A <: 'a -//│ 'E <: 'a +//│ 'A <: Add['E0] | Lit | Neg['A0] +//│ 'E <: Add[in (Add['E1] | Lit | Neg['A1]) & 'E2 | 'E1 out 'E2 & 'E1] | Lit | Neg[in (Add['E0] | Lit | Neg['A0]) & 'A2 | 'A1 out 'A2 & 'A1] +//│ 'A1 <: Add['E0] | Lit | Neg['A0] TestLang.eval(add11) @@ -153,36 +156,12 @@ TestLang.eval(Neg(Neg(add11))) //│ int -:e +// :e TestLang.eval(add2negadd11) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.157: TestLang.eval(add2negadd11) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Neg[?A]` does not match type `Add[?E] | Lit` -//│ ║ l.99: let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ ║ ^^^^^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.35: if e is -//│ ║ ^ -//│ ╟── Note: type parameter E is defined at: -//│ ║ l.6: class Add(lhs: E, rhs: E) -//│ ╙── ^ -//│ error | int - -:e +//│ int + +// :e TestLang.eval(Add(Lit(2), Neg(add11))) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.173: TestLang.eval(Add(Lit(2), Neg(add11))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Neg[?A]` does not match type `Add[?E] | Lit` -//│ ║ l.99: let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ ║ ^^^^^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.35: if e is -//│ ║ ^ -//│ ╟── Note: type parameter E is defined at: -//│ ║ l.6: class Add(lhs: E, rhs: E) -//│ ╙── ^ -//│ error +//│ int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index b85a7aa5f6..fded1ea662 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -3,6 +3,14 @@ :NoJS +class C +//│ class C[A]() { +//│ this: 'this_C +//│ } +//│ where +//│ 'this_C :> C['A] + + class Some(value: A) { fun get = value fun toArray = [value] @@ -10,12 +18,12 @@ class Some(value: A) { // fun map(f : A => 'b) = Some(f(value)) // TODO } //│ class Some[A](value: A) { -//│ this: 'this +//│ this: 'this_Some //│ fun get: A //│ fun toArray: (A,) //│ } //│ where -//│ 'this :> Some[?] +//│ 'this_Some :> Some['A] & {value: A} let s = Some(1) @@ -53,12 +61,12 @@ module None { // fun mapBad(f) = None // TODO } //│ namespace None() { -//│ this: 'this +//│ this: 'this_None //│ fun get: nothing //│ fun toArray: () //│ } //│ where -//│ 'this :> None +//│ 'this_None :> None None.toArray @@ -114,11 +122,11 @@ class Test(n) { fun foo = n + 1 } //│ class Test(n: nothing) { -//│ this: 'this +//│ this: 'this_Test //│ fun foo: int //│ } //│ where -//│ 'this :> Test +//│ 'this_Test :> Test & {n: nothing} Test(1) //│ Test @@ -126,16 +134,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.127: Test(true) +//│ ║ l.135: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.127: Test(true) +//│ ║ l.135: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.114: fun foo = n + 1 +//│ ║ l.122: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.113: class Test(n) { +//│ ║ l.121: class Test(n) { //│ ╙── ^ //│ Test | error @@ -145,20 +153,20 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.145: fun foo = n + 1 +//│ ║ l.153: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.145: fun foo = n + 1 +//│ ║ l.153: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.144: class Test(n: A) { +//│ ║ l.152: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { -//│ this: 'this +//│ this: 'this_Test //│ fun foo: error | int //│ } //│ where -//│ 'this :> Test[?] +//│ 'this_Test :> Test['A] & {n: A} Test(1) //│ Test['A] @@ -177,13 +185,13 @@ class Test(n: A) { fun id(x) = x } //│ class Test[A](n: A) { -//│ this: 'this +//│ this: 'this_Test //│ fun foo: A //│ fun foo1: (x: A,) -> A //│ fun id: 'a -> 'a //│ } //│ where -//│ 'this :> Test[?] +//│ 'this_Test :> Test['A] & {n: A} Test(1) //│ Test['A] @@ -222,21 +230,21 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.222: fun foo2(x: A) = x + 1 +//│ ║ l.230: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.222: fun foo2(x: A) = x + 1 +//│ ║ l.230: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.220: class Test { +//│ ║ l.228: class Test { //│ ╙── ^ //│ class Test[A]() { -//│ this: 'this +//│ this: 'this_Test //│ fun foo1: (x: A,) -> A //│ fun foo2: (x: A,) -> (error | int) //│ } //│ where -//│ 'this :> Test[?] +//│ 'this_Test :> Test['A] Test().foo1 //│ (x: 'A,) -> 'A diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index de04caedf8..2a3557d281 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -7,11 +7,11 @@ class Foo() 123 //│ class Foo() { -//│ this: 'this +//│ this: 'this_Foo //│ } //│ 123 //│ where -//│ 'this :> Foo +//│ 'this_Foo :> Foo Foo //│ () -> Foo @@ -77,11 +77,11 @@ fun bar(b) = foo(b) :ns foo -//│ forall 'a 'b 'c. 'c -> {h: 'c, t: 'b} +//│ forall 'a 'b 'c. 'b -> {h: 'b, t: 'a} //│ where -//│ 'b :> {h: 'c, t: 'b} -//│ 'c <: 'a -//│ 'a <: 'c +//│ 'a :> {h: 'b, t: 'a} +//│ 'b <: 'c +//│ 'c <: 'b fun foo(a) = {h1: a, t1: bar(a)} @@ -101,16 +101,16 @@ module Test0_2 { fun b = 123 } //│ namespace Test0_1() { -//│ this: 'this +//│ this: 'this_Test0_1 //│ fun a: 123 //│ } //│ namespace Test0_2() { -//│ this: 'this0 +//│ this: 'this_Test0_2 //│ fun b: 123 //│ } //│ where -//│ 'this0 :> Test0_2 -//│ 'this :> Test0_1 +//│ 'this_Test0_2 :> Test0_2 +//│ 'this_Test0_1 :> Test0_1 Test0_1.a //│ 123 @@ -122,16 +122,16 @@ class Test0_2() { fun b = 123 } //│ class Test0_1() { -//│ this: 'this +//│ this: 'this_Test0_1 //│ fun a: 123 //│ } //│ class Test0_2() { -//│ this: 'this0 +//│ this: 'this_Test0_2 //│ fun b: 123 //│ } //│ where -//│ 'this0 :> Test0_2 -//│ 'this :> Test0_1 +//│ 'this_Test0_2 :> Test0_2 +//│ 'this_Test0_1 :> Test0_1 :e // TODO @@ -149,16 +149,16 @@ module Test1_2 { //│ ║ l.140: } //│ ╙── ^ //│ namespace Test1_1() { -//│ this: 'this +//│ this: 'this_Test1_1 //│ fun a: error //│ } //│ namespace Test1_2() { -//│ this: 'this0 +//│ this: 'this_Test1_2 //│ fun b: error //│ } //│ where -//│ 'this0 :> Test1_2 -//│ 'this :> Test1_1 +//│ 'this_Test1_2 :> Test1_2 +//│ 'this_Test1_1 :> Test1_1 Test1_1.a //│ error @@ -179,16 +179,16 @@ class Test1_2 { //│ ║ l.170: } //│ ╙── ^ //│ class Test1_1() { -//│ this: 'this +//│ this: 'this_Test1_1 //│ fun a: error //│ } //│ class Test1_2() { -//│ this: 'this0 +//│ this: 'this_Test1_2 //│ fun b: error //│ } //│ where -//│ 'this0 :> Test1_2 -//│ 'this :> Test1_1 +//│ 'this_Test1_2 :> Test1_2 +//│ 'this_Test1_1 :> Test1_1 // TODO check TV hygiene @@ -230,21 +230,21 @@ module Test2_2 { //│ ║ l.200: } //│ ╙── ^ //│ namespace Test2_1() { -//│ this: 'this +//│ this: 'this_Test2_1 //│ fun a: 123 //│ fun d: error //│ fun n: 456 //│ fun t2: Test2_2 //│ } //│ namespace Test2_2() { -//│ this: 'this0 +//│ this: 'this_Test2_2 //│ fun b: 123 //│ fun c: error //│ fun e: error //│ } //│ where -//│ 'this0 :> Test2_2 -//│ 'this :> Test2_1 +//│ 'this_Test2_2 :> Test2_2 +//│ 'this_Test2_1 :> Test2_1 Test2_1.t2.b //│ 123 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 67bb9ff37f..dcf388844a 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -18,13 +18,13 @@ class Base1(p: int): Over { // fun test2 = super.p // TODO } //│ class Base1(p: int) { -//│ this: 'this +//│ this: 'this_Base1 //│ fun p: "hi" //│ fun test: (int, "hi" | 'p,) //│ } //│ where -//│ 'this :> Base1 -//│ <: {p: 'p} +//│ 'this_Base1 :> Base1 & {p: "hi"} +//│ <: {p: 'p} Base1(123).test diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 51c2814670..2378105c05 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -524,6 +524,8 @@ class DiffTests ttu.entities.map(_.complete()(raise)).foreach { case tc: typer.TypedNuCls => output(s"${indStr}class ${tc.name}") + output(s"${indStr} this: ${tc.thisTy} ${tc.thisTy.showBounds + .indentNewLines(indStr+" |")}") showTTU(tc.ttu, ind + 1) case tm: typer.TypedNuMxn => output(s"${indStr}mixin ${tm.name}") From 984da8e16c7a23a5e34def7410a0e22b647c85e9 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 00:13:50 +0800 Subject: [PATCH 066/498] WIP Give thisType and superType proper contravariance --- .../src/main/scala/mlscript/NuTypeDefs.scala | 8 +- shared/src/main/scala/mlscript/Typer.scala | 14 ++-- .../main/scala/mlscript/TyperDatatypes.scala | 3 +- .../main/scala/mlscript/TyperHelpers.scala | 12 +-- shared/src/test/diff/nu/BasicClasses.mls | 49 ++++-------- shared/src/test/diff/nu/BasicMixins.mls | 56 +++----------- shared/src/test/diff/nu/ECOOP23.mls | 61 +++++---------- shared/src/test/diff/nu/ECOOP23_min.mls | 24 +++--- shared/src/test/diff/nu/ECOOP23_repro.mls | 47 ++++-------- shared/src/test/diff/nu/GenericClasses.mls | 44 +++-------- shared/src/test/diff/nu/GenericMixins.mls | 6 +- shared/src/test/diff/nu/MutualRec.mls | 75 ++++++------------- shared/src/test/diff/nu/ParamOverriding.mls | 7 +- 13 files changed, 125 insertions(+), 281 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index bdebfc883e..8ad82e8571 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -210,7 +210,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // params.mapValues(_.mapPol(pol)(f)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, - f(N, thisTy).asInstanceOf[TV] + f(pol.map(!_), thisTy)//.asInstanceOf[TV] )(instanceType) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -219,7 +219,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // params.mapValues(_.mapPol(pol)(f)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, - f(pol.invar, thisTy).asInstanceOf[TV] + f(pol.contravar, thisTy)//.asInstanceOf[TV] )(instanceType) } @@ -231,10 +231,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuMxn(td, f(N, thisTV), f(N, superTV), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) + TypedNuMxn(td, f(pol.map(!_), thisTV), f(pol.map(!_), superTV), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuMxn(td, f(pol.invar, thisTV), f(pol.invar, superTV), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) + TypedNuMxn(td, f(pol.contravar, thisTV), f(pol.contravar, superTV), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) } /** Note: the type `ty` is stoed *without* its polymorphic wrapper! */ diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 03f01d1f5f..a1d15ebd5c 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1261,24 +1261,26 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) }) } def goDecl(d: TypedNuDecl): NuDecl = d match { - case TypedNuMxn(td, thisTV, superTV, members, ttu) => + case TypedNuMxn(td, thisTy, superTy, members, ttu) => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), Nil,//TODO - S(go(superTV)), - S(go(thisTV)), - // mkTypingUnit(thisTV, + // S(go(superTy)), + // S(go(thisTy)), + Option.when(!(TopType <:< superTy))(go(superTy)), + Option.when(!(TopType <:< thisTy))(go(thisTy)), + // mkTypingUnit(thisTy, // // members // Map.empty // ) - mkTypingUnit(thisTV, members)) + mkTypingUnit(thisTy, members)) case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => NuTypeDef(td.kind, td.nme, td.tparams, // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), Nil,//TODO N,//TODO - S(go(thisTy)), + Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members)) // mkTypingUnit(() :: members.toList.sortBy(_._1))) case TypedNuFun(level, fd, ty) => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 8cffad57c9..cc982353a2 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -64,7 +64,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // TODO does this also need freshening in freshenAbove? private lazy val thisTV: TV = - freshVar(noProv/*FIXME*/, N, S("this_"+decl.name))(lvl + 1) + // freshVar(noProv/*FIXME*/, N, S("this_"+decl.name))(lvl + 1) + freshVar(noProv/*FIXME*/, N, S(decl.name.decapitalize))(lvl + 1) def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 5bd3d3af43..554f7f037f 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -771,14 +771,14 @@ abstract class TyperHelpers { Typer: Typer => PolMap.pos -> tf.ty :: Nil case mxn: TypedNuMxn => mxn.members.valuesIterator.flatMap(childrenPolMem) ++ - S(pol.invar -> mxn.superTV) ++ - S(pol.invar -> mxn.thisTV) + S(pol.contravar -> mxn.superTV) ++ + S(pol.contravar -> mxn.thisTV) case cls: TypedNuCls => cls.tparams.iterator.map(PolMap.neu -> _._2) ++ // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ - S(pol.invar -> cls.thisTy) + S(pol.contravar -> cls.thisTy) } ents ::: tu.result.toList.map(pol -> _) }} @@ -931,11 +931,11 @@ abstract class TyperHelpers { Typer: Typer => params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) - apply(pol.invar)(thisTy) + apply(pol.contravar)(thisTy) case TypedNuMxn(td, thisTV, superTV, members, ttu) => members.valuesIterator.foreach(applyMem(pol)) - apply(pol.invar)(thisTV) - apply(pol.invar)(superTV) + apply(pol.contravar)(thisTV) + apply(pol.contravar)(superTV) case NuParam(nme, ty, isType) => applyField(pol)(ty) case TypedNuFun(level, fd, ty) => apply(pol)(ty) } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index b1506cdd7c..8855e7c851 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -4,11 +4,7 @@ class A(n: int) -//│ class A(n: int) { -//│ this: 'this_A -//│ } -//│ where -//│ 'this_A :> A & {n: int} +//│ class A(n: int) A //│ (n: int,) -> A @@ -52,12 +48,9 @@ class C { fun const(x) = id } //│ class C() { -//│ this: 'this_C //│ fun const: anything -> 'a -> 'a //│ fun id: 'a -> 'a //│ } -//│ where -//│ 'this_C :> C class Base0(n) { @@ -67,15 +60,12 @@ class Base0(n) { fun oops = this.my } //│ class Base0(n: nothing) { -//│ this: 'this_Base0 -//│ fun me: 'this_Base0 +//│ this: {my: 'my, n: 'n} & 'base0 +//│ fun me: Base0 & {n: nothing} | 'base0 //│ fun mine: 'n //│ fun my: 'n //│ fun oops: 'my //│ } -//│ where -//│ 'this_Base0 :> Base0 & {n: nothing} -//│ <: {my: 'my, n: 'n} // :d // Base0 @@ -106,14 +96,11 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1(base: int) { -//│ this: 'this_Base1 +//│ this: {base: int} //│ fun foo: int -> int //│ fun getBase1: int //│ fun getBase2: int //│ } -//│ where -//│ 'this_Base1 :> Base1 & {base: int} -//│ <: {base: int} class Base1(base: int) { fun getBase1 = base @@ -121,13 +108,11 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1(base: int) { -//│ this: 'this_Base1 +//│ this: 'base1 //│ fun foo: int -> int //│ fun getBase1: int -//│ fun me: 'this_Base1 +//│ fun me: Base1 & {base: int} | 'base1 //│ } -//│ where -//│ 'this_Base1 :> Base1 & {base: int} Base1 //│ (base: int,) -> Base1 @@ -148,7 +133,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.149: b.getBaseTypo +//│ ║ l.134: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error @@ -162,18 +147,15 @@ class Rec(n) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.161: class Rec(n) { +//│ ║ l.146: class Rec(n) { //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.162: fun go = Rec(n + 1) +//│ ║ l.147: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.163: } +//│ ║ l.148: } //│ ╙── ^ //│ class Rec(n: nothing) { -//│ this: 'this_Rec //│ fun go: error //│ } -//│ where -//│ 'this_Rec :> Rec & {n: nothing} @@ -184,23 +166,20 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.183: a: int +//│ ║ l.165: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.182: class Annots(base: 0 | 1) { +//│ ║ l.164: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.183: a: int +//│ ║ l.165: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.183: a: int +//│ ║ l.165: a: int //│ ╙── ^^^ //│ class Annots(base: (0 | 1,)) { -//│ this: 'this_Annots //│ fun a: (0 | 1,) //│ } -//│ where -//│ 'this_Annots :> Annots & {base: (0 | 1,)} diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index e646698dcc..ef4f4c3574 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -8,40 +8,31 @@ mixin BaseTest { fun test = super.base } //│ mixin BaseTest() { -//│ super: 'super -//│ this: 'this +//│ super: {base: 'base} //│ fun test: 'base //│ } -//│ where -//│ 'super <: {base: 'base} mixin BaseInc { fun test = super.base + 1 fun test2 = this.base } //│ mixin BaseInc() { -//│ super: 'super -//│ this: 'this +//│ super: {base: int} +//│ this: {base: 'base} //│ fun test: int //│ fun test2: 'base //│ } -//│ where -//│ 'this <: {base: 'base} -//│ 'super <: {base: int} // :d class Base1(base: int): BaseTest, BaseInc { fun test3 = [base, this.base] } //│ class Base1(base: int) { -//│ this: 'this_Base1 +//│ this: {base: 'base} //│ fun test: int //│ fun test2: 'base | int //│ fun test3: (int, 'base | int,) //│ } -//│ where -//│ 'this_Base1 :> Base1 & {test2: 'base | int, test: int, base: int} -//│ <: {base: 'base} Base1(1).test //│ int @@ -55,11 +46,8 @@ Base1(1).test3 class Base1(base): BaseTest //│ class Base1(base: nothing) { -//│ this: 'this_Base1 //│ fun test: nothing //│ } -//│ where -//│ 'this_Base1 :> Base1 & {test: nothing, base: nothing} Base1 //│ (base: anything,) -> Base1 @@ -72,10 +60,10 @@ Base1(1).test :e class Base1(x): BaseTest //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.73: class Base1(x): BaseTest +//│ ║ l.61: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.73: class Base1(x): BaseTest +//│ ║ l.61: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -84,11 +72,8 @@ class Base1(x): BaseTest //│ ║ l.8: fun test = super.base //│ ╙── ^^^^^ //│ class Base1(x: nothing) { -//│ this: 'this_Base1 //│ fun test: nothing //│ } -//│ where -//│ 'this_Base1 :> Base1 & {test: nothing, x: nothing} Base1 //│ (x: anything,) -> Base1 @@ -99,20 +84,14 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo() { -//│ super: 'super -//│ this: 'this +//│ super: {base: int, misc: 'misc} //│ fun test: (int & 'a) -> (int, 'a, 'misc,) //│ } -//│ where -//│ 'super <: {base: int, misc: 'misc} module Base1(base: int, misc: string): Foo //│ namespace Base1(base: int, misc: string) { -//│ this: 'this_Base1 //│ fun test: (int & 'a) -> (int, 'a, string,) //│ } -//│ where -//│ 'this_Base1 :> Base1 & {misc: string, test: (int & 'a) -> (int, 'a, string,), base: int} Base1.test //│ (int & 'a) -> (int, 'a, string,) @@ -125,8 +104,6 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase() { -//│ super: 'super -//│ this: 'this //│ fun wrap: 'a -> 'a //│ fun wrapA: (x: int,) -> int //│ } @@ -137,25 +114,19 @@ mixin Wrap { fun wrap(x) = [super.wrap(x)] } //│ mixin Wrap() { -//│ super: 'super -//│ this: 'this +//│ super: {wrap: 'a -> 'b, wrapA: 'c -> 'd} //│ fun wrap: 'a -> ('b,) //│ fun wrapA: 'c -> ('d,) //│ } -//│ where -//│ 'super <: {wrap: 'a -> 'b, wrapA: 'c -> 'd} // :d module WrapBase1: WrapBase, Wrap //│ namespace WrapBase1() { -//│ this: 'this_WrapBase1 //│ fun wrap: 'a -> ('a,) //│ fun wrapA: int -> (int,) //│ } -//│ where -//│ 'this_WrapBase1 :> WrapBase1 & {wrap: 'a -> ('a,), wrapA: int -> (int,)} WrapBase1 @@ -185,16 +156,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.186: WrapBase1.wrapA("ok") +//│ ║ l.157: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.186: WrapBase1.wrapA("ok") +//│ ║ l.157: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.124: fun wrapA(x: int) = x : int +//│ ║ l.103: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.136: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.113: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error @@ -202,12 +173,9 @@ WrapBase1.wrapA("ok") module WrapBase2: WrapBase, Wrap, Wrap, Wrap //│ namespace WrapBase2() { -//│ this: 'this_WrapBase2 //│ fun wrap: 'a -> ((('a,),),) //│ fun wrapA: int -> (((int,),),) //│ } -//│ where -//│ 'this_WrapBase2 :> WrapBase2 & {wrap: 'a -> ((('a,),),), wrapA: int -> (((int,),),)} let w = WrapBase2.wrap //│ let w: 'a -> ((('a,),),) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 6670afc509..39f903f619 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -5,15 +5,8 @@ class Add(lhs: E, rhs: E) class Lit(n: int) -//│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this_Add -//│ } -//│ class Lit(n: int) { -//│ this: 'this_Lit -//│ } -//│ where -//│ 'this_Lit :> Lit & {n: int} -//│ 'this_Add :> Add['E] & {lhs: E, rhs: E} +//│ class Add[E](lhs: E, rhs: E) +//│ class Lit(n: int) fun add11 = Add(Lit(1), Lit(2)) //│ fun add11: Add['E] @@ -42,23 +35,19 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ super: 'super -//│ this: 'this +//│ this: {eval: 'lhs -> int} //│ fun eval: (Add['E] | Lit) -> int //│ } //│ where //│ 'E <: 'lhs -//│ 'this <: {eval: 'lhs -> int} module TestLang: EvalBase //│ namespace TestLang() { -//│ this: 'this_TestLang +//│ this: {eval: 'E -> int} //│ fun eval: (Add['E] | Lit) -> int //│ } //│ where -//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit) -> int} -//│ <: {eval: 'E -> int} //│ 'E <: (Add['E0] | Lit) & (Add['E1] | Lit) //│ 'E1 <: Add['E0] | Lit @@ -72,11 +61,7 @@ TestLang.eval(add11) class Neg(expr: A) -//│ class Neg[A](expr: A) { -//│ this: 'this_Neg -//│ } -//│ where -//│ 'this_Neg :> Neg['A] & {expr: A} +//│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) //│ let add2negadd11: Add['E] @@ -92,29 +77,25 @@ mixin EvalNeg { else super.eval(e) } //│ mixin EvalNeg() { -//│ super: 'super -//│ this: 'this +//│ super: {eval: 'a -> 'b} +//│ this: {eval: 'expr -> int} //│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } //│ where //│ 'A <: 'expr -//│ 'this <: {eval: 'expr -> int} -//│ 'super <: {eval: 'a -> 'b} module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: 'this_TestLang +//│ this: {eval: ('A | 'E) -> int} //│ fun eval: (Add['E] | Lit | Neg['A]) -> int //│ } //│ where -//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit | Neg['A]) -> int} -//│ <: {eval: ('A | 'E) -> int} -//│ 'A <: Add['E0] | Lit | Neg['A0] -//│ 'E <: (Add['E1] | Lit | Neg['A1]) & (Add['E2] | Lit | Neg['A2]) -//│ 'A1 <: Add['E0] | Lit | Neg['A0] -//│ 'E1 <: Add['E2] | Lit | Neg['A2] -//│ 'A2 <: Add['E0] | Lit | Neg['A0] +//│ 'E <: (Add['E0] | Lit | Neg['A0]) & (Add['E1] | Lit | Neg['A1]) +//│ 'A0 <: Add['E2] | Lit | Neg['A2] +//│ 'E0 <: Add['E1] | Lit | Neg['A1] +//│ 'A1 <: Add['E2] | Lit | Neg['A2] +//│ 'A <: Add['E2] | Lit | Neg['A2] TestLang.eval //│ (Add['E] | Lit | Neg['A]) -> int @@ -152,25 +133,21 @@ mixin EvalNegNeg { else super.eval(e) } //│ mixin EvalNegNeg() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Neg['A] | 'a & ~Neg) -> 'b +//│ super: {eval: (Neg[in 'A & (~Neg | Neg[in 'expr out nothing]) out 'A | 'A0] & {Neg#A :> 'A & (~Neg | Neg[in 'expr out nothing]) <: 'A | 'A0} | 'a) -> 'b} +//│ this: {eval: 'expr -> 'b} +//│ fun eval: (Neg['A1] | 'a & ~Neg) -> 'b //│ } //│ where -//│ 'A :> 'A0 -//│ <: 'A1 & (~Neg | Neg['A2]) +//│ 'A1 :> 'A +//│ <: 'A0 & (~Neg | Neg['A2]) //│ 'A2 <: 'expr -//│ 'this <: {eval: 'expr -> 'b} -//│ 'super <: {eval: (Neg[in 'A0 & (~Neg | Neg[in 'expr out nothing]) out 'A0 | 'A1] & {Neg#A :> 'A0 & (~Neg | Neg[in 'expr out nothing]) <: 'A0 | 'A1} | 'a) -> 'b} module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ namespace TestLang() { -//│ this: 'this_TestLang +//│ this: {eval: 'E -> int & nothing -> 'a} //│ fun eval: (Add['E] | Lit | Neg[Neg['A] & 'A0]) -> (int | 'a) //│ } //│ where -//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit | Neg[Neg['A] & 'A0]) -> (int | 'a)} -//│ <: {eval: 'E -> int & nothing -> 'a} //│ 'A0 <: nothing //│ 'A <: nothing //│ 'E <: (Add['E0] | Lit | Neg[Neg['A1] & 'A2]) & (Add['E1] | Lit | Neg[Neg['A3] & 'A4]) diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index b457fb7ffb..f13602820b 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -5,11 +5,7 @@ class Add(lhs: E, rhs: E) // class Lit(n: int) -//│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this_Add -//│ } -//│ where -//│ 'this_Add :> Add['E] & {lhs: E, rhs: E} +//│ class Add[E](lhs: E, rhs: E) let e = Add(1, 1) //│ let e: Add['E] @@ -20,11 +16,11 @@ let e = Add(1, 1) e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α34 +//│ | 0. : α32 //│ ======== TYPED ======== -//│ res: Some(α34) where -//│ α34 :> (Add<> & {Add#E: mut E23_35..E23_35}) -//│ E23_35 :> 1 +//│ res: Some(α32) where +//│ α32 :> (Add<> & {Add#E: mut E23_33..E23_33}) +//│ E23_33 :> 1 //│ Add['E] //│ where //│ 'E :> 1 @@ -36,12 +32,12 @@ e.lhs e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α34 +//│ | 0. : α32 //│ ======== TYPED ======== -//│ res: Some(α34) where -//│ α34 :> (Add<> & {Add#E: mut E23_35..E23_35}) <: {lhs: lhs44} -//│ E23_35 :> 1 <: lhs44 -//│ lhs44 :> 1 +//│ res: Some(α32) where +//│ α32 :> (Add<> & {Add#E: mut E23_33..E23_33}) <: {lhs: lhs42} +//│ E23_33 :> 1 <: lhs42 +//│ lhs42 :> 1 //│ Add['E] //│ where //│ 'E :> 1 diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 474bad63e4..b01e723e1a 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -5,15 +5,8 @@ class Add(lhs: E, rhs: E) class Lit(n: int) -//│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this_Add -//│ } -//│ class Lit(n: int) { -//│ this: 'this_Lit -//│ } -//│ where -//│ 'this_Lit :> Lit & {n: int} -//│ 'this_Add :> Add['E] & {lhs: E, rhs: E} +//│ class Add[E](lhs: E, rhs: E) +//│ class Lit(n: int) let add11 = Add(Lit(1), Lit(2)) //│ let add11: Add['E] @@ -37,25 +30,21 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ super: 'super -//│ this: 'this +//│ this: {eval: 'lhs -> int} //│ fun eval: (Add['E] | Lit) -> int //│ } //│ where //│ 'E <: 'lhs -//│ 'this <: {eval: 'lhs -> int} module TestLang: EvalBase //│ namespace TestLang() { -//│ this: 'this_TestLang +//│ this: {eval: 'E -> int} //│ fun eval: (Add['E] | Lit) -> int //│ } //│ where -//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit) -> int} -//│ <: {eval: 'E -> int} //│ 'E <: (Add['E0] | Lit) & (Add['E1] | Lit) -//│ 'E1 <: Add['E0] | Lit +//│ 'E0 <: Add['E1] | Lit TestLang.eval //│ (Add['E] | Lit) -> int @@ -90,11 +79,7 @@ add11 class Neg(expr: A) -//│ class Neg[A](expr: A) { -//│ this: 'this_Neg -//│ } -//│ where -//│ 'this_Neg :> Neg['A] & {expr: A} +//│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) //│ let add2negadd11: Add['E] @@ -111,29 +96,25 @@ mixin EvalNeg { else super.eval(e) } //│ mixin EvalNeg() { -//│ super: 'super -//│ this: 'this +//│ super: {eval: 'a -> 'b} +//│ this: {eval: 'expr -> int} //│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) //│ } //│ where //│ 'A <: 'expr -//│ 'this <: {eval: 'expr -> int} -//│ 'super <: {eval: 'a -> 'b} module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: 'this_TestLang +//│ this: {eval: ('A | 'E) -> int} //│ fun eval: (Add['E] | Lit | Neg['A]) -> int //│ } //│ where -//│ 'this_TestLang :> TestLang & {eval: (Add['E] | Lit | Neg['A]) -> int} -//│ <: {eval: ('A | 'E) -> int} -//│ 'A <: Add['E0] | Lit | Neg['A0] -//│ 'E <: (Add['E1] | Lit | Neg['A1]) & (Add['E2] | Lit | Neg['A2]) -//│ 'A2 <: Add['E0] | Lit | Neg['A0] -//│ 'E2 <: Add['E1] | Lit | Neg['A1] -//│ 'A1 <: Add['E0] | Lit | Neg['A0] +//│ 'E <: (Add['E0] | Lit | Neg['A0]) & (Add['E1] | Lit | Neg['A1]) +//│ 'A1 <: Add['E2] | Lit | Neg['A2] +//│ 'E1 <: Add['E0] | Lit | Neg['A0] +//│ 'A0 <: Add['E2] | Lit | Neg['A2] +//│ 'A <: Add['E2] | Lit | Neg['A2] TestLang.eval //│ (Add['E] | Lit | Neg['A]) -> int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index fded1ea662..a4b85aba8e 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -4,11 +4,7 @@ class C -//│ class C[A]() { -//│ this: 'this_C -//│ } -//│ where -//│ 'this_C :> C['A] +//│ class C[A]() class Some(value: A) { @@ -18,12 +14,9 @@ class Some(value: A) { // fun map(f : A => 'b) = Some(f(value)) // TODO } //│ class Some[A](value: A) { -//│ this: 'this_Some //│ fun get: A //│ fun toArray: (A,) //│ } -//│ where -//│ 'this_Some :> Some['A] & {value: A} let s = Some(1) @@ -61,12 +54,9 @@ module None { // fun mapBad(f) = None // TODO } //│ namespace None() { -//│ this: 'this_None //│ fun get: nothing //│ fun toArray: () //│ } -//│ where -//│ 'this_None :> None None.toArray @@ -122,11 +112,8 @@ class Test(n) { fun foo = n + 1 } //│ class Test(n: nothing) { -//│ this: 'this_Test //│ fun foo: int //│ } -//│ where -//│ 'this_Test :> Test & {n: nothing} Test(1) //│ Test @@ -134,16 +121,16 @@ Test(1) :e Test(true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.135: Test(true) +//│ ║ l.122: Test(true) //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.135: Test(true) +//│ ║ l.122: Test(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.122: fun foo = n + 1 +//│ ║ l.112: fun foo = n + 1 //│ ║ ^ //│ ╟── from reference: -//│ ║ l.121: class Test(n) { +//│ ║ l.111: class Test(n) { //│ ╙── ^ //│ Test | error @@ -153,20 +140,17 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.153: fun foo = n + 1 +//│ ║ l.140: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.153: fun foo = n + 1 +//│ ║ l.140: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.152: class Test(n: A) { +//│ ║ l.139: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { -//│ this: 'this_Test //│ fun foo: error | int //│ } -//│ where -//│ 'this_Test :> Test['A] & {n: A} Test(1) //│ Test['A] @@ -185,13 +169,10 @@ class Test(n: A) { fun id(x) = x } //│ class Test[A](n: A) { -//│ this: 'this_Test //│ fun foo: A //│ fun foo1: (x: A,) -> A //│ fun id: 'a -> 'a //│ } -//│ where -//│ 'this_Test :> Test['A] & {n: A} Test(1) //│ Test['A] @@ -230,21 +211,18 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.230: fun foo2(x: A) = x + 1 +//│ ║ l.211: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.230: fun foo2(x: A) = x + 1 +//│ ║ l.211: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.228: class Test { +//│ ║ l.209: class Test { //│ ╙── ^ //│ class Test[A]() { -//│ this: 'this_Test //│ fun foo1: (x: A,) -> A //│ fun foo2: (x: A,) -> (error | int) //│ } -//│ where -//│ 'this_Test :> Test['A] Test().foo1 //│ (x: 'A,) -> 'A diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 5b2a513ae5..b11f844036 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -11,8 +11,6 @@ mixin BaseTest { //│ ║ l.8: fun test(x: A) = x //│ ╙── ^ //│ mixin BaseTest[A]() { -//│ super: 'super -//│ this: 'this //│ fun test: (x: error,) -> error //│ } @@ -21,11 +19,9 @@ mixin BaseTest(x: A) { fun test = x } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.21: fun test = x +//│ ║ l.19: fun test = x //│ ╙── ^ //│ mixin BaseTest[A]() { -//│ super: 'super -//│ this: 'this //│ fun test: error //│ } diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 2a3557d281..326be6beb4 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -6,12 +6,8 @@ class Foo() 123 -//│ class Foo() { -//│ this: 'this_Foo -//│ } +//│ class Foo() //│ 123 -//│ where -//│ 'this_Foo :> Foo Foo //│ () -> Foo @@ -77,11 +73,11 @@ fun bar(b) = foo(b) :ns foo -//│ forall 'a 'b 'c. 'b -> {h: 'b, t: 'a} +//│ forall 'a 'b 'c. 'a -> {h: 'a, t: 'c} //│ where -//│ 'a :> {h: 'b, t: 'a} -//│ 'b <: 'c -//│ 'c <: 'b +//│ 'c :> {h: 'a, t: 'c} +//│ 'a <: 'b +//│ 'b <: 'a fun foo(a) = {h1: a, t1: bar(a)} @@ -101,16 +97,11 @@ module Test0_2 { fun b = 123 } //│ namespace Test0_1() { -//│ this: 'this_Test0_1 //│ fun a: 123 //│ } //│ namespace Test0_2() { -//│ this: 'this_Test0_2 //│ fun b: 123 //│ } -//│ where -//│ 'this_Test0_2 :> Test0_2 -//│ 'this_Test0_1 :> Test0_1 Test0_1.a //│ 123 @@ -122,16 +113,11 @@ class Test0_2() { fun b = 123 } //│ class Test0_1() { -//│ this: 'this_Test0_1 //│ fun a: 123 //│ } //│ class Test0_2() { -//│ this: 'this_Test0_2 //│ fun b: 123 //│ } -//│ where -//│ 'this_Test0_2 :> Test0_2 -//│ 'this_Test0_1 :> Test0_1 :e // TODO @@ -142,23 +128,18 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.138: module Test1_1 { +//│ ║ l.124: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.139: fun a = Test1_2.b +//│ ║ l.125: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.140: } +//│ ║ l.126: } //│ ╙── ^ //│ namespace Test1_1() { -//│ this: 'this_Test1_1 //│ fun a: error //│ } //│ namespace Test1_2() { -//│ this: 'this_Test1_2 //│ fun b: error //│ } -//│ where -//│ 'this_Test1_2 :> Test1_2 -//│ 'this_Test1_1 :> Test1_1 Test1_1.a //│ error @@ -172,23 +153,18 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.168: class Test1_1 { +//│ ║ l.149: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.169: fun a = Test1_2().b +//│ ║ l.150: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.170: } +//│ ║ l.151: } //│ ╙── ^ //│ class Test1_1() { -//│ this: 'this_Test1_1 //│ fun a: error //│ } //│ class Test1_2() { -//│ this: 'this_Test1_2 //│ fun b: error //│ } -//│ where -//│ 'this_Test1_2 :> Test1_2 -//│ 'this_Test1_1 :> Test1_1 // TODO check TV hygiene @@ -204,47 +180,42 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.195: module Test2_1 { +//│ ║ l.171: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.196: fun t2 = Test2_2 +//│ ║ l.172: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.197: fun a = Test2_2.b +//│ ║ l.173: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.198: fun d = Test2_2.e +//│ ║ l.174: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.199: fun n = 456 +//│ ║ l.175: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.200: } +//│ ║ l.176: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.195: module Test2_1 { +//│ ║ l.171: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.196: fun t2 = Test2_2 +//│ ║ l.172: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.197: fun a = Test2_2.b +//│ ║ l.173: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.198: fun d = Test2_2.e +//│ ║ l.174: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.199: fun n = 456 +//│ ║ l.175: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.200: } +//│ ║ l.176: } //│ ╙── ^ //│ namespace Test2_1() { -//│ this: 'this_Test2_1 //│ fun a: 123 //│ fun d: error //│ fun n: 456 //│ fun t2: Test2_2 //│ } //│ namespace Test2_2() { -//│ this: 'this_Test2_2 //│ fun b: 123 //│ fun c: error //│ fun e: error //│ } -//│ where -//│ 'this_Test2_2 :> Test2_2 -//│ 'this_Test2_1 :> Test2_1 Test2_1.t2.b //│ 123 diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index dcf388844a..fbb9792777 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -7,8 +7,6 @@ mixin Over { fun p = "hi" } //│ mixin Over() { -//│ super: 'super -//│ this: 'this //│ fun p: "hi" //│ } @@ -18,13 +16,10 @@ class Base1(p: int): Over { // fun test2 = super.p // TODO } //│ class Base1(p: int) { -//│ this: 'this_Base1 +//│ this: {p: 'p} //│ fun p: "hi" //│ fun test: (int, "hi" | 'p,) //│ } -//│ where -//│ 'this_Base1 :> Base1 & {p: "hi"} -//│ <: {p: 'p} Base1(123).test From 54b2a2eebd7b0a3e6b476655e37d8a6549f97c3e Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 00:34:35 +0800 Subject: [PATCH 067/498] WIP add some tests & error messages --- .../main/scala/mlscript/TyperDatatypes.scala | 13 +++--- .../test/diff/nu/BasicClassInheritance.mls | 28 ++++++++++++ shared/src/test/diff/nu/BasicClasses.mls | 38 +++++++++------- shared/src/test/diff/nu/BasicMixins.mls | 33 ++++++++------ shared/src/test/diff/nu/ECOOP23.mls | 41 ++++++++++++++++- shared/src/test/diff/nu/GenericClasses.mls | 36 +++++++-------- shared/src/test/diff/nu/MixinParameters.mls | 28 ++++++++++++ shared/src/test/diff/nu/MutualRec.mls | 45 +++++++++++-------- 8 files changed, 185 insertions(+), 77 deletions(-) create mode 100644 shared/src/test/diff/nu/BasicClassInheritance.mls create mode 100644 shared/src/test/diff/nu/MixinParameters.mls diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index cc982353a2..f376a34c72 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -159,8 +159,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case _ => ??? } case (N, Fld(mut, spec, nme: Var)) => - assert(!mut && !spec, "TODO") // TODO - nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) + // assert(!mut && !spec, "TODO") // TODO + // nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) + nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) case _ => ??? } // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) @@ -233,13 +234,15 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case _ => ??? } case cls: TypedNuCls => - ??? + err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO + Nil case als: TypedNuAls => // TODO dealias first? err(msg"Cannot inherit from a type alias", p.toLoc) Nil case cls: TypedNuFun => - ??? + err(msg"Cannot inherit from this", p.toLoc) + Nil } case S(_) => err(msg"Cannot inherit from this", p.toLoc) @@ -249,7 +252,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => Nil } case _ => - err(msg"Illegal parent specification", p.toLoc) + err(msg"Unsupported parent specification", p.toLoc) // TODO Nil } }() diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls new file mode 100644 index 0000000000..2cb76e135c --- /dev/null +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -0,0 +1,28 @@ +:NewParser +:NewDefs +:NoJS + + +class A +//│ class A() + +// TODO +class B(m: int): A +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.10: class B(m: int): A +//│ ╙── ^ +//│ class B(m: int) + + +class A(n: int) +//│ class A(n: int) + +// TODO +class B(m: int): A(n + 1) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.21: class B(m: int): A(n + 1) +//│ ╙── ^^^^^^^^ +//│ class B(m: int) + + + diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 8855e7c851..d1a670983f 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -53,17 +53,21 @@ class C { //│ } +// TODO class Base0(n) { fun me = this fun my = this.n fun mine = my fun oops = this.my } -//│ class Base0(n: nothing) { +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.57: class Base0(n) { +//│ ╙── ^ +//│ class Base0(n: error) { //│ this: {my: 'my, n: 'n} & 'base0 -//│ fun me: Base0 & {n: nothing} | 'base0 -//│ fun mine: 'n -//│ fun my: 'n +//│ fun me: Base0 & {n: error} | 'base0 +//│ fun mine: error | 'n +//│ fun my: error | 'n //│ fun oops: 'my //│ } @@ -76,7 +80,7 @@ let b1 = Base0(42) // :d let n1 = b1.n -//│ let n1: nothing +//│ let n1: error // TODO n1 + 1 @@ -86,7 +90,7 @@ n1 + 1 let b2 = Base0("hi") let n2 = b2.n //│ let b2: Base0 -//│ let n2: nothing +//│ let n2: error @@ -133,7 +137,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.134: b.getBaseTypo +//│ ║ l.138: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error @@ -143,17 +147,17 @@ b : Base1 :e // TODO -class Rec(n) { +class Rec(n: int) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.146: class Rec(n) { -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.147: fun go = Rec(n + 1) +//│ ║ l.150: class Rec(n: int) { +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.151: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.148: } +//│ ║ l.152: } //│ ╙── ^ -//│ class Rec(n: nothing) { +//│ class Rec(n: int) { //│ fun go: error //│ } @@ -166,16 +170,16 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.165: a: int +//│ ║ l.169: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.164: class Annots(base: 0 | 1) { +//│ ║ l.168: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.165: a: int +//│ ║ l.169: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.165: a: int +//│ ║ l.169: a: int //│ ╙── ^^^ //│ class Annots(base: (0 | 1,)) { //│ fun a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index ef4f4c3574..f47d8515a9 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -44,26 +44,33 @@ Base1(1).test3 //│ (int, int,) +// TODO class Base1(base): BaseTest -//│ class Base1(base: nothing) { -//│ fun test: nothing +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.48: class Base1(base): BaseTest +//│ ╙── ^^^^ +//│ class Base1(base: error) { +//│ fun test: error //│ } Base1 -//│ (base: anything,) -> Base1 +//│ (base: error,) -> Base1 // TODO Base1(1).test -//│ nothing +//│ error :e class Base1(x): BaseTest +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.65: class Base1(x): BaseTest +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.61: class Base1(x): BaseTest +//│ ║ l.65: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `{x: ?x}` does not have field 'base' -//│ ║ l.61: class Base1(x): BaseTest +//│ ╟── type `{x: error}` does not have field 'base' +//│ ║ l.65: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -71,12 +78,12 @@ class Base1(x): BaseTest //│ ╟── from reference: //│ ║ l.8: fun test = super.base //│ ╙── ^^^^^ -//│ class Base1(x: nothing) { +//│ class Base1(x: error) { //│ fun test: nothing //│ } Base1 -//│ (x: anything,) -> Base1 +//│ (x: error,) -> Base1 // :ns @@ -156,16 +163,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.157: WrapBase1.wrapA("ok") +//│ ║ l.164: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.157: WrapBase1.wrapA("ok") +//│ ║ l.164: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.103: fun wrapA(x: int) = x : int +//│ ║ l.110: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.113: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.120: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 39f903f619..80a5e67b8b 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -60,6 +60,43 @@ TestLang.eval(add11) //│ int +mixin EvalNothing { + fun eval(e) = e : nothing +} +mixin EvalAddLit { + fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then this.eval(l) + this.eval(r) + else super.eval(e) +} +module TestLang: EvalNothing, EvalAddLit +//│ mixin EvalNothing() { +//│ fun eval: nothing -> nothing +//│ } +//│ mixin EvalAddLit() { +//│ super: {eval: 'a -> 'b} +//│ this: {eval: 'lhs -> int} +//│ fun eval: (Add['E] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ } +//│ namespace TestLang() { +//│ this: {eval: 'E0 -> int} +//│ fun eval: (Add['E0] | Lit) -> int +//│ } +//│ where +//│ 'E0 <: (Add['E1] | Lit) & (Add['E2] | Lit) +//│ 'E1 <: Add['E2] | Lit +//│ 'E <: 'lhs + +TestLang.eval +//│ (Add['E] | Lit) -> int +//│ where +//│ 'E <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit + +TestLang.eval(add11) +//│ int + + class Neg(expr: A) //│ class Neg[A](expr: A) @@ -92,9 +129,9 @@ module TestLang: EvalBase, EvalNeg //│ } //│ where //│ 'E <: (Add['E0] | Lit | Neg['A0]) & (Add['E1] | Lit | Neg['A1]) -//│ 'A0 <: Add['E2] | Lit | Neg['A2] -//│ 'E0 <: Add['E1] | Lit | Neg['A1] //│ 'A1 <: Add['E2] | Lit | Neg['A2] +//│ 'E1 <: Add['E0] | Lit | Neg['A0] +//│ 'A0 <: Add['E2] | Lit | Neg['A2] //│ 'A <: Add['E2] | Lit | Neg['A2] TestLang.eval diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index a4b85aba8e..bceaad3243 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -108,31 +108,25 @@ mo.toArray +// TODO class Test(n) { fun foo = n + 1 + fun bar = n } -//│ class Test(n: nothing) { +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.112: class Test(n) { +//│ ╙── ^ +//│ class Test(n: error) { +//│ fun bar: error //│ fun foo: int //│ } Test(1) //│ Test -:e +// :e Test(true) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.122: Test(true) -//│ ║ ^^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.122: Test(true) -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.112: fun foo = n + 1 -//│ ║ ^ -//│ ╟── from reference: -//│ ║ l.111: class Test(n) { -//│ ╙── ^ -//│ Test | error +//│ Test :e @@ -140,13 +134,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.140: fun foo = n + 1 +//│ ║ l.134: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.140: fun foo = n + 1 +//│ ║ l.134: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.139: class Test(n: A) { +//│ ║ l.133: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int @@ -211,13 +205,13 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.211: fun foo2(x: A) = x + 1 +//│ ║ l.205: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.211: fun foo2(x: A) = x + 1 +//│ ║ l.205: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.209: class Test { +//│ ║ l.203: class Test { //│ ╙── ^ //│ class Test[A]() { //│ fun foo1: (x: A,) -> A diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls new file mode 100644 index 0000000000..d2a3e32d67 --- /dev/null +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -0,0 +1,28 @@ +:NewParser +:NewDefs +:NoJS + + +// TODO +mixin BaseTest(x: int) { + fun test = x +} +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.8: fun test = x +//│ ╙── ^ +//│ mixin BaseTest() { +//│ fun test: error +//│ } + +// TODO +mixin BaseTest(x) { + fun test = x +} +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.19: fun test = x +//│ ╙── ^ +//│ mixin BaseTest() { +//│ fun test: error +//│ } + + diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 326be6beb4..8d4b6f90bf 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -12,10 +12,17 @@ class Foo() Foo //│ () -> Foo +// TODO fun fooo(x) = class C(y, z) C(0, x) -//│ fun fooo: anything -> C +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.17: class C(y, z) +//│ ╙── ^ +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.17: class C(y, z) +//│ ╙── ^ +//│ fun fooo: error -> C @@ -128,11 +135,11 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.124: module Test1_1 { +//│ ║ l.131: module Test1_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.125: fun a = Test1_2.b +//│ ║ l.132: fun a = Test1_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.126: } +//│ ║ l.133: } //│ ╙── ^ //│ namespace Test1_1() { //│ fun a: error @@ -153,11 +160,11 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.149: class Test1_1 { +//│ ║ l.156: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.150: fun a = Test1_2().b +//│ ║ l.157: fun a = Test1_2().b //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.151: } +//│ ║ l.158: } //│ ╙── ^ //│ class Test1_1() { //│ fun a: error @@ -180,30 +187,30 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.171: module Test2_1 { +//│ ║ l.178: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.172: fun t2 = Test2_2 +//│ ║ l.179: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.173: fun a = Test2_2.b +//│ ║ l.180: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.174: fun d = Test2_2.e +//│ ║ l.181: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.175: fun n = 456 +//│ ║ l.182: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.176: } +//│ ║ l.183: } //│ ╙── ^ //│ ╔══[ERROR] Cyclic definition -//│ ║ l.171: module Test2_1 { +//│ ║ l.178: module Test2_1 { //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.172: fun t2 = Test2_2 +//│ ║ l.179: fun t2 = Test2_2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.173: fun a = Test2_2.b +//│ ║ l.180: fun a = Test2_2.b //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.174: fun d = Test2_2.e +//│ ║ l.181: fun d = Test2_2.e //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.175: fun n = 456 +//│ ║ l.182: fun n = 456 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.176: } +//│ ║ l.183: } //│ ╙── ^ //│ namespace Test2_1() { //│ fun a: 123 From 64ef0960a8e2db9aeb526bd05b9141e60daa040a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 01:30:31 +0800 Subject: [PATCH 068/498] WIPIP --- .../src/main/scala/mlscript/NuTypeDefs.scala | 50 +++++++++++++++++-- shared/src/main/scala/mlscript/TypeDefs.scala | 2 + .../main/scala/mlscript/TypeSimplifier.scala | 1 + .../main/scala/mlscript/TyperDatatypes.scala | 1 + .../main/scala/mlscript/TyperHelpers.scala | 41 +++++++++++++-- shared/src/test/diff/nu/GenericClasses.mls | 3 ++ .../src/test/scala/mlscript/DiffTests.scala | 3 +- 7 files changed, 91 insertions(+), 10 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8ad82e8571..98d40c500d 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -157,7 +157,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - thisTy.freshenAbove(lim, rigidify))(cls.instanceType) + thisTy.freshenAbove(lim, rigidify))( + cls.instanceType.freshenAbove(lim, rigidify)) // case _ => ??? // } } @@ -197,12 +198,53 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members: Map[Str, NuMember], thisTy: ST )( - val instanceType: ST, // only meant to be used in `force` + val instanceType: ST, // only meant to be used in `force` and `variances` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { def nme: TypeName = td.nme def name: Str = nme.name + private var _variances: Opt[VarianceStore] = N + def variances(implicit ctx: Ctx): VarianceStore = { + _variances match { + case S(res) => res + case N => + // CompletedTypingUnit(this :: Nil, N).childrenPol(PolMap.pos) + + // val vars = CompletedTypingUnit(this :: Nil, N).getVarsPol(PolMap.pos) + // MutMap.from(vars.iterator.mapValues { + // case S(true) => VarianceInfo.co + // case S(false) => VarianceInfo.contra + // case N => VarianceInfo.in + // }) + + val store = VarianceStore.empty + object Trav extends Traverser2.InvariantFields { + override def apply(pol: PolMap)(ty: ST): Unit = + trace(s"Trav($pol)($ty)") { + ty match { + case tv: TypeVariable => + store(tv) = store.getOrElse(tv, VarianceInfo.bi) && (pol(tv) match { + case S(true) => VarianceInfo.co + case S(false) => VarianceInfo.contra + case N => VarianceInfo.in + }) + super.apply(pol)(ty) + case ty @ RecordType(fs) => + // Ignore type param members such as `C#A` in `{C#A: mut A30'..A30'}` + super.apply(pol)(RecordType(fs.filterNot(_._1.name.contains('#')))(ty.prov)) + case _ => super.apply(pol)(ty) + } + }() + } + // Trav.applyLike(PolMap.pos)(CompletedTypingUnit(this :: Nil, N)) + Trav(PolMap.pos)(instanceType) + // println(store) + store + + } + } + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, ttu, @@ -211,7 +253,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy)//.asInstanceOf[TV] - )(instanceType) + )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, ttu, @@ -220,7 +262,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy)//.asInstanceOf[TV] - )(instanceType) + )(f(pol, instanceType)) } case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, members: Map[Str, NuMember], ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 034694a87d..17d2c3198f 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -795,4 +795,6 @@ class TypeDefs extends NuTypeDefs { self: Typer => } type VarianceStore = MutMap[TypeVariable, VarianceInfo] + object VarianceStore { def empty: VarianceStore = MutMap.empty } + } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 8c73c21049..b8f7bdfa3b 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -22,6 +22,7 @@ trait TypeSimplifier { self: Typer => val _ctx = ctx val allVarPols = ty.getVarsPol(PolMap(pol)) + println("!!"+ty.childrenPol(PolMap(pol))) println(s"allVarPols: ${printPols(allVarPols)}") val renewed = MutMap.empty[TypeVariable, TypeVariable] diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index f376a34c72..7197ef896e 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -399,6 +399,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case cls: TypedNuCls => implicit val prov: TP = noProv // TODO constrain(cls.instanceType, thisTV) + println(cls.variances) case _ => } res diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 554f7f037f..409c9c1e18 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -678,7 +678,9 @@ abstract class TyperHelpers { Typer: Typer => case NegType(n) => pol.map(!_) -> n :: Nil case ExtrType(_) => Nil case ProxyType(und) => pol -> und :: Nil - case _: TypeTag => Nil + // case _: TypeTag => Nil + case _: ObjectTag | _: Extruded => Nil + case SkolemTag(_, tv) => pol -> tv :: Nil case tr: TypeRef => tr.mapTargs(pol)(_ -> _) case Without(b, ns) => pol -> b :: Nil case TypeBounds(lb, ub) => S(false) -> lb :: S(true) -> ub :: Nil @@ -757,7 +759,9 @@ abstract class TyperHelpers { Typer: Typer => case NegType(n) => pol.contravar -> n :: Nil case ExtrType(_) => Nil case ProxyType(und) => pol -> und :: Nil - case _: TypeTag => Nil + // case _: TypeTag => Nil + case _: ObjectTag | _: Extruded => Nil + case SkolemTag(_, tv) => pol -> tv :: Nil case tr: TypeRef => tr.mapTargs(pol)(_ -> _) case Without(b, ns) => pol -> b :: Nil case TypeBounds(lb, ub) => PolMap.neg -> lb :: PolMap.pos -> ub :: Nil @@ -778,7 +782,8 @@ abstract class TyperHelpers { Typer: Typer => // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ - S(pol.contravar -> cls.thisTy) + S(pol.contravar -> cls.thisTy) ++ + S(pol.covar -> cls.instanceType) } ents ::: tu.result.toList.map(pol -> _) }} @@ -824,6 +829,10 @@ abstract class TyperHelpers { Typer: Typer => res.toSortedMap } + private def childrenMem(m: NuMember): List[ST] = m match { + case NuParam(nme, ty, isType) => ty.lb.toList ::: ty.ub :: Nil + case TypedNuFun(level, fd, ty) => ty :: Nil + } def children(includeBounds: Bool): List[SimpleType] = this match { case tv @ AssignedVariable(ty) => if (includeBounds) ty :: Nil else Nil case tv: TypeVariable => if (includeBounds) tv.lowerBounds ::: tv.upperBounds else Nil @@ -836,13 +845,33 @@ abstract class TyperHelpers { Typer: Typer => case NegType(n) => n :: Nil case ExtrType(_) => Nil case ProxyType(und) => und :: Nil - case _: TypeTag => Nil + // case _: TypeTag => Nil + case _: ObjectTag | _: Extruded => Nil + case SkolemTag(_, tv) => tv :: Nil case TypeRef(d, ts) => ts case Without(b, ns) => b :: Nil case TypeBounds(lb, ub) => lb :: ub :: Nil case PolymorphicType(_, und) => und :: Nil case ConstrainedType(cs, und) => cs.flatMap(lu => lu._1 :: lu._2 :: Nil) ::: und :: Nil case SpliceType(fs) => fs.flatMap{ case L(l) => l :: Nil case R(r) => r.lb.toList ::: r.ub :: Nil} + case OtherTypeLike(tu) => + // tu.childrenPol(PolMap.neu).map(tp => tp._1) + val ents = tu.entities.flatMap { + case tf: TypedNuFun => + tf.ty :: Nil + case mxn: TypedNuMxn => + mxn.members.valuesIterator.flatMap(childrenMem) ++ + S(mxn.superTV) ++ + S(mxn.thisTV) + case cls: TypedNuCls => + cls.tparams.iterator.map(_._2) ++ + // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) + cls.params.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil) ++ + cls.members.valuesIterator.flatMap(childrenMem) ++ + S(cls.thisTy) ++ + S(cls.instanceType) + } + ents ::: tu.result.toList } def getVars: SortedSet[TypeVariable] = { @@ -954,7 +983,9 @@ abstract class TyperHelpers { Typer: Typer => case NegType(n) => apply(pol.contravar)(n) case ExtrType(_) => () case ProxyType(und) => apply(pol)(und) - case _: TypeTag => () + // case _: TypeTag => () + case _: ObjectTag | _: Extruded => () + case SkolemTag(_, tv) => apply(pol)(tv) case tr: TypeRef => tr.mapTargs(pol)(apply(_)(_)); () case Without(b, ns) => apply(pol)(b) case TypeBounds(lb, ub) => pol.traverseBounds(lb, ub)(apply(_)(_)) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index bceaad3243..0f79eac35b 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -7,6 +7,9 @@ class C //│ class C[A]() +class C(a: A) + + class Some(value: A) { fun get = value fun toArray = [value] diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 2378105c05..70980d677c 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -559,6 +559,7 @@ class DiffTests } } + val oldDbg = typer.dbg val sim = if (mode.noSimplification) comp else try { typer.dbg = mode.dbgSimplif object SimplifyPipeline extends typer.SimplifyPipeline { @@ -566,7 +567,7 @@ class DiffTests if (mode.dbgSimplif) output(msg) } SimplifyPipeline(comp, all = false)(ctx) - } finally typer.dbg = false + } finally typer.dbg = oldDbg val exp = typer.expandType(sim)(ctx) From 32c5f9d7c99ee637d03e61876b19285406edec21 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 01:50:57 +0800 Subject: [PATCH 069/498] WIP Prepare the grounds for variance analysis --- .../scala/mlscript/ConstraintSolver.scala | 2 +- .../src/main/scala/mlscript/NewParser.scala | 2 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 9 +++--- shared/src/main/scala/mlscript/TypeDefs.scala | 28 ---------------- .../main/scala/mlscript/TypeSimplifier.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 23 ++++++------- shared/src/main/scala/mlscript/helpers.scala | 12 +++---- shared/src/main/scala/mlscript/syntax.scala | 32 ++++++++++++++++++- shared/src/test/diff/nu/GenericClasses.mls | 16 ++++++---- .../src/test/scala/mlscript/DiffTests.scala | 2 +- 11 files changed, 68 insertions(+), 62 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index d81020773a..432aeb4875 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -40,7 +40,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // freshened ++= td.tparams.map(tp => tp._2 -> TopType) // /* - td.tparams.foreach { case (tn, _tv) => + td.tparams.foreach { case (tn, _tv, vi) => // val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) val targ = rfnt(Var(td.nme.name + "#" + tn.name)) match { case S(fty) => diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 17599d381d..0863b12c5e 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -292,7 +292,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } val ps = parents(if (kind === Als) KEYWORD("=") else KEYWORD(":")) val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams, params, ps, N, N, body) + val res = NuTypeDef(kind, tn, tparams.map(N -> _), params, ps, N, N, body) R(res.withLoc(S(l0 ++ res.getLoc))) // TODO make `fun` by-name and `let` by-value diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 98d40c500d..463546d160 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -154,7 +154,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // params.mapValues(_.freshenAbove(level, rigidify)), // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), - tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), + // tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), + tps.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).asInstanceOf[TV], tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify))( @@ -193,7 +194,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { case class TypedNuCls(level: Level, td: NuTypeDef, ttu: TypedTypingUnit, - tparams: Ls[TN -> TV], params: Ls[Var -> FieldType], + tparams: Ls[(TN, TV, Opt[VarianceInfo])], params: Ls[Var -> FieldType], // members: Map[Str, LazyTypeInfo]) members: Map[Str, NuMember], thisTy: ST @@ -248,7 +249,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, ttu, - tparams.map(tp => tp._1 -> f(N, tp._2).asInstanceOf[TV]), + tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), // params.mapValues(_.mapPol(pol)(f)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, @@ -257,7 +258,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, ttu, - tparams.map(tp => tp._1 -> f(pol.invar, tp._2).asInstanceOf[TV]), + tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), // params.mapValues(_.mapPol(pol)(f)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 17d2c3198f..94f40e4a65 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -766,34 +766,6 @@ class TypeDefs extends NuTypeDefs { self: Typer => println(s"DONE") } - case class VarianceInfo(isCovariant: Bool, isContravariant: Bool) { - - /** Combine two pieces of variance information together - */ - def &&(that: VarianceInfo): VarianceInfo = - VarianceInfo(isCovariant && that.isCovariant, isContravariant && that.isContravariant) - - /* Flip the current variance if it encounters a contravariant position - */ - def flip: VarianceInfo = VarianceInfo(isContravariant, isCovariant) - - override def toString: Str = show - - def show: Str = this match { - case (VarianceInfo(true, true)) => "±" - case (VarianceInfo(false, true)) => "-" - case (VarianceInfo(true, false)) => "+" - case (VarianceInfo(false, false)) => "=" - } - } - - object VarianceInfo { - val bi: VarianceInfo = VarianceInfo(true, true) - val co: VarianceInfo = VarianceInfo(true, false) - val contra: VarianceInfo = VarianceInfo(false, true) - val in: VarianceInfo = VarianceInfo(false, false) - } - type VarianceStore = MutMap[TypeVariable, VarianceInfo] object VarianceStore { def empty: VarianceStore = MutMap.empty } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index b8f7bdfa3b..21c502a317 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -293,7 +293,7 @@ trait TypeSimplifier { self: Typer => Map.empty[TV, VarianceInfo].withDefaultValue(VarianceInfo.in) // * Reconstruct a TypeRef from its current structural components - val typeRef = TypeRef(cls.td.nme, cls.tparams.zipWithIndex.map { case ((tp, tv), tpidx) => + val typeRef = TypeRef(cls.td.nme, cls.tparams.zipWithIndex.map { case ((tp, tv, vi), tpidx) => val fieldTagNme = tparamField(clsTyNme, tp) val fromTyRef = trs2.get(clsTyNme).map(_.targs(tpidx) |> { ta => FieldType(S(ta), ta)(noProv) }) fromTyRef.++(rcd2.fields.iterator.filter(_._1 === fieldTagNme).map(_._2)) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index a1d15ebd5c..00399eecab 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1100,7 +1100,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val ty = // RecordType.mk(cls.params)(provTODO) // TODO?! RecordType.mk(fresh_cls.tparams.map{ - case (tn, tv) => + case (tn, tv, vi) => // TODO use variances (Var(nme+"#"+tn.name).withLocOf(tn), FieldType(S(tv), tv)(provTODO)) })(provTODO) println(s"Match arm $nme: $tag & $ty") diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 7197ef896e..cb49aa2dd8 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -45,7 +45,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { private def outerCtx = ctx private def outerVars = vars - val tparams: Ls[TN -> TV] = Nil // TODO + val tparams: Ls[(TN, TV)] = Nil // TODO + // val tparams: Ls[(TN, TV, VarianceInfo)] = Nil // TODO var isComputing: Bool = false // TODO replace by a Ctx entry var result: Opt[TypedNuTermDef] = N // var result: Opt[A] = N @@ -134,18 +135,18 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => ctx.nest.nextLevel { implicit ctx => val tparams = td.tparams.map(tp => - tp -> freshVar(TypeProvenance( - tp.toLoc, + (tp._2, freshVar(TypeProvenance( + tp._2.toLoc, "type parameter", - S(tp.name), - true), N, S(tp.name))) + S(tp._2.name), + true), N, S(tp._2.name)), tp._1)) println(s"Type params ${tparams.mkString(" ")}") implicit val vars: Map[Str, SimpleType] = // outerVars ++ tparams.iterator.mapKeys(_.name).toMap outerVars ++ tparams.iterator.map { - case (tp, tv) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) + case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) } val typedParams = td.params.fields.map { @@ -187,9 +188,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // val finalType = freshVar(noProv/*TODO*/, N, S("this")) val finalType = thisTV - val tparamMems = tparams.map { case (tn, tv) => - val fldNme = td.nme.name + "#" + tn.name - NuParam(Var(fldNme).withLocOf(tn), FieldType(S(tv), tv)(tv.prov), isType = true) + val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi + val fldNme = td.nme.name + "#" + tp.name + NuParam(Var(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isType = true) } // tparamMems.map(p => p.nme -> p.ty):Int val tparamFields = tparamMems.map(p => p.nme -> p.ty) @@ -369,7 +370,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) // ) { case (acc, (tn, tv)) => acc & } ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( - cls.tparams.map { case (tn, tv) => + cls.tparams.map { case (tn, tv, vi) => // TODO use vi Var(cls.td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } )(provTODO) )(provTODO) @@ -789,7 +790,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => ClassTag(Var(td.nme.name).withLocOf(td.nme), Set.empty//TODO )(provTODO) & RecordType(td.tparams.lazyZip(targs).map { - case ((tn, tv), ta) => + case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.td.nme.name + "#" + tn.name Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) })(provTODO) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index c3d38e9137..2e0eb03847 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -134,7 +134,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => })).mkString case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => val bodyCtx = ctx.indent - s"${kind.str} ${nme.name}${tparams.map(_.showIn(ctx, 0))mkStringOr(", ", "[", "]")}(${ + s"${kind.str} ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}(${ params.fields.map { case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) case (N, _) => "???" @@ -171,7 +171,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => // TODO improve this mess - tparams ::: params.fields.collect { + tparams.map(_._2) ::: params.fields.collect { case (_, Fld(_, _, Asc(_, ty))) => ty } ::: sup.toList ::: ths.toList ::: Signature(body.entities.collect { case d: NuDecl => d @@ -398,7 +398,7 @@ trait NuDeclImpl extends Located { self: NuDecl => case NuFunDef(S(false), n, _, b) => s"let $n" case NuFunDef(S(true), n, _, b) => s"let rec $n" case NuTypeDef(k, n, tps, sps, parents, sup, ths, bod) => - s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_.name).mkString("‹", ", ", "›")}(${ + s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}(${ // sps.mkString("(",",",")") sps})${if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" } @@ -708,7 +708,7 @@ trait StatementImpl extends Located { self: Statement => case L(ds) => (ds :: Nil) -> Top case R(ty) => Nil -> ty } - diags -> (TypeDef(k, nme, tps, rhs, Nil, Nil, Nil) :: Nil) + diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { @@ -730,7 +730,7 @@ trait StatementImpl extends Located { self: Statement => case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld case _ => die })) :: Nil)))), true) - diags.toList -> (TypeDef(k, nme, tps, bod, Nil, Nil, pos) :: ctor :: Nil) + diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, Nil, pos) :: ctor :: Nil) case d: DesugaredStatement => Nil -> (d :: Nil) } import Message._ @@ -843,7 +843,7 @@ trait StatementImpl extends Located { self: Statement => case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil case NuTypeDef(k, nme, tps, ps, pars, sup, ths, bod) => - nme :: tps ::: ps :: pars ::: ths.toList ::: bod :: Nil + nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index bd6f000068..840d7e59fa 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -175,7 +175,7 @@ sealed abstract class NuDecl extends TypeLike with Statement with NuDeclImpl final case class NuTypeDef( kind: TypeDefKind, nme: TypeName, - tparams: Ls[TypeName], + tparams: Ls[(Opt[VarianceInfo], TypeName)], params: Tup, // the specialized parameters for that type parents: Ls[Term], superAnnot: Opt[Type], @@ -196,3 +196,33 @@ final case class NuFunDef( sealed trait PgrmOrTypingUnit // TODO rm + + +final case class VarianceInfo(isCovariant: Bool, isContravariant: Bool) { + + /** Combine two pieces of variance information together + */ + def &&(that: VarianceInfo): VarianceInfo = + VarianceInfo(isCovariant && that.isCovariant, isContravariant && that.isContravariant) + + /* Flip the current variance if it encounters a contravariant position + */ + def flip: VarianceInfo = VarianceInfo(isContravariant, isCovariant) + + override def toString: Str = show + + def show: Str = this match { + case (VarianceInfo(true, true)) => "±" + case (VarianceInfo(false, true)) => "-" + case (VarianceInfo(true, false)) => "+" + case (VarianceInfo(false, false)) => "=" + } +} + +object VarianceInfo { + val bi: VarianceInfo = VarianceInfo(true, true) + val co: VarianceInfo = VarianceInfo(true, false) + val contra: VarianceInfo = VarianceInfo(false, true) + val in: VarianceInfo = VarianceInfo(false, false) +} + diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 0f79eac35b..d1a48cc7e5 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -7,7 +7,9 @@ class C //│ class C[A]() +// :d class C(a: A) +//│ class C[A](a: A) class Some(value: A) { @@ -117,7 +119,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.112: class Test(n) { +//│ ║ l.117: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -137,13 +139,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.134: fun foo = n + 1 +//│ ║ l.139: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.134: fun foo = n + 1 +//│ ║ l.139: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.133: class Test(n: A) { +//│ ║ l.138: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int @@ -208,13 +210,13 @@ class Test { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.205: fun foo2(x: A) = x + 1 +//│ ║ l.210: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.205: fun foo2(x: A) = x + 1 +//│ ║ l.210: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.203: class Test { +//│ ║ l.208: class Test { //│ ╙── ^ //│ class Test[A]() { //│ fun foo1: (x: A,) -> A diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 70980d677c..74a82f6a6f 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -656,7 +656,7 @@ class DiffTests // generate warnings for bivariant type variables val bivariantTypeVars = ttd.tparamsargs.iterator.filter{ case (tname, tvar) => - tvv.get(tvar).contains(typer.VarianceInfo.bi) + tvv.get(tvar).contains(VarianceInfo.bi) }.map(_._1).toList if (!bivariantTypeVars.isEmpty) { varianceWarnings.put(td.nme, bivariantTypeVars) From 427e27ee26429e2f9680c696e28ea9e322df342d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 02:08:15 +0800 Subject: [PATCH 070/498] WIP Start using primitive variance analysis to improve types; uncover problem in class typing --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 + .../main/scala/mlscript/TypeSimplifier.scala | 28 ++++- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 8 ++ shared/src/test/diff/nu/ECOOP23.mls | 97 ++++------------- shared/src/test/diff/nu/ECOOP23_min.mls | 22 ++-- shared/src/test/diff/nu/ECOOP23_repro.mls | 103 +++++++++--------- shared/src/test/diff/nu/ECOOP23_small.mls | 53 +++++++++ shared/src/test/diff/nu/GenericClasses.mls | 95 +++++++++------- 9 files changed, 223 insertions(+), 189 deletions(-) create mode 100644 shared/src/test/diff/nu/ECOOP23_small.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 463546d160..5f5bdf839e 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -245,6 +245,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } + def varianceOf(tv: TV)(implicit ctx: Ctx): VarianceInfo = + variances.getOrElse(tv, VarianceInfo.in) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 21c502a317..3d75ca558f 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -106,8 +106,23 @@ trait TypeSimplifier { self: Typer => else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil else v -> default :: Nil }) - case N => // TODO look into ctx.tyDefs2 - v -> default :: Nil + case N => + // v -> default :: Nil + ctx.tyDefs2.get(prefix) match { + case S(td) => + td.result match { + case S(cls: TypedNuCls) => + cls.varianceOf(cls.tparams.find(_._1.name === postfix).getOrElse(die)._2) match { + case VarianceInfo(true, true) => Nil + case VarianceInfo(co, contra) => + if (co) v -> FieldType(S(BotType), process(fty.ub, N))(fty.prov) :: Nil + else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil + else v -> default :: Nil + } + case _ => die + } + case N => die + } } })(ty.prov) @@ -288,9 +303,10 @@ trait TypeSimplifier { self: Typer => val rcd2 = rcd.copy(rcd.fields.mapValues(_.update(go(_, pol.map(!_)), go(_, pol))))(rcd.prov) println(s"rcd2 ${rcd2}") - val vs = - // td.getVariancesOrDefault - Map.empty[TV, VarianceInfo].withDefaultValue(VarianceInfo.in) + // val vs = + // // td.getVariancesOrDefault + // // Map.empty[TV, VarianceInfo].withDefaultValue(VarianceInfo.in) + // cls.variances // * Reconstruct a TypeRef from its current structural components val typeRef = TypeRef(cls.td.nme, cls.tparams.zipWithIndex.map { case ((tp, tv, vi), tpidx) => @@ -302,7 +318,7 @@ trait TypeSimplifier { self: Typer => (acc_lb | lb.getOrElse(BotType), acc_ub & ub) }.pipe { case (lb, ub) => - vs(tv) match { + cls.varianceOf(tv) match { case VarianceInfo(true, true) => TypeBounds.mk(BotType, TopType) case VarianceInfo(false, false) => TypeBounds.mk(lb, ub) case VarianceInfo(co, contra) => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 00399eecab..e360ee141a 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1101,7 +1101,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // RecordType.mk(cls.params)(provTODO) // TODO?! RecordType.mk(fresh_cls.tparams.map{ case (tn, tv, vi) => // TODO use variances - (Var(nme+"#"+tn.name).withLocOf(tn), FieldType(S(tv), tv)(provTODO)) + // println("VVV"+fresh_cls.variances.get(tv)) + (Var(nme+"#"+tn.name).withLocOf(tn), + FieldType.mk(fresh_cls.varianceOf(tv), tv, tv)(provTODO)) })(provTODO) println(s"Match arm $nme: $tag & $ty") tag -> ty diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index cb49aa2dd8..572fb39ffd 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -972,6 +972,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => override def toString = lb.fold(s"$ub")(lb => s"mut ${if (lb === BotType) "" else lb}..$ub") } + object FieldType { + def mk(vi: VarianceInfo, lb: ST, ub: ST)(prov: TP): FieldType = vi match { + case VarianceInfo(true, true) => FieldType(N, TopType)(prov) + case VarianceInfo(true, false) => FieldType(N, ub)(prov) + case VarianceInfo(false, true) => FieldType(S(lb), TopType)(prov) + case VarianceInfo(false, false) => FieldType(S(lb), ub)(prov) + } + } /** A type variable living at a certain polymorphism level `level`, with mutable bounds. * Invariant: Types appearing in the bounds never have a level higher than this variable's `level`. */ diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 80a5e67b8b..1e20c06cb6 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -9,9 +9,7 @@ class Lit(n: int) //│ class Lit(n: int) fun add11 = Add(Lit(1), Lit(2)) -//│ fun add11: Add['E] -//│ where -//│ 'E :> Lit +//│ fun add11: Add[Lit] // add11 + 1 @@ -24,8 +22,7 @@ fun eval(e) = Add(l, r) then eval(l) + eval(r) //│ fun eval: 'a -> int //│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a +//│ 'a <: Add['a] | Lit mixin EvalBase { @@ -36,25 +33,18 @@ mixin EvalBase { } //│ mixin EvalBase() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['E] | Lit) -> int +//│ fun eval: (Add['lhs] | Lit) -> int //│ } -//│ where -//│ 'E <: 'lhs module TestLang: EvalBase //│ namespace TestLang() { -//│ this: {eval: 'E -> int} -//│ fun eval: (Add['E] | Lit) -> int +//│ this: {eval: 'lhs -> int} +//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit] | Lit)] | Lit) -> int //│ } -//│ where -//│ 'E <: (Add['E0] | Lit) & (Add['E1] | Lit) -//│ 'E1 <: Add['E0] | Lit TestLang.eval -//│ (Add['E] | Lit) -> int -//│ where -//│ 'E <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit +//│ (Add[Add[Add[anything] | Lit] | Lit] | Lit) -> int TestLang.eval(add11) //│ int @@ -77,21 +67,15 @@ module TestLang: EvalNothing, EvalAddLit //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['E] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) //│ } //│ namespace TestLang() { -//│ this: {eval: 'E0 -> int} -//│ fun eval: (Add['E0] | Lit) -> int +//│ this: {eval: 'lhs0 -> int} +//│ fun eval: (Add['lhs0 & (Add[Add[anything] | Lit] | Lit)] | Lit) -> int //│ } -//│ where -//│ 'E0 <: (Add['E1] | Lit) & (Add['E2] | Lit) -//│ 'E1 <: Add['E2] | Lit -//│ 'E <: 'lhs TestLang.eval -//│ (Add['E] | Lit) -> int -//│ where -//│ 'E <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit +//│ (Add[Add[Add[anything] | Lit] | Lit] | Lit) -> int TestLang.eval(add11) //│ int @@ -101,11 +85,7 @@ class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: Add['E] -//│ where -//│ 'E :> Lit | Neg['A] -//│ 'A :> forall 'E0. Add['E0] -//│ 'E0 :> Lit +//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] mixin EvalNeg { @@ -116,30 +96,18 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } -//│ where -//│ 'A <: 'expr module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: {eval: ('A | 'E) -> int} -//│ fun eval: (Add['E] | Lit | Neg['A]) -> int +//│ this: {eval: ('expr | 'lhs) -> int} +//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Lit | Neg['expr & (Add[anything] | Lit | Neg[anything])]) -> int //│ } -//│ where -//│ 'E <: (Add['E0] | Lit | Neg['A0]) & (Add['E1] | Lit | Neg['A1]) -//│ 'A1 <: Add['E2] | Lit | Neg['A2] -//│ 'E1 <: Add['E0] | Lit | Neg['A0] -//│ 'A0 <: Add['E2] | Lit | Neg['A2] -//│ 'A <: Add['E2] | Lit | Neg['A2] TestLang.eval -//│ (Add['E] | Lit | Neg['A]) -> int -//│ where -//│ 'A <: Add['E0] | Lit | Neg['A0] -//│ 'E <: Add[in (Add['E1] | Lit | Neg['A1]) & 'E2 | 'E1 out 'E2 & 'E1] | Lit | Neg[in (Add['E0] | Lit | Neg['A0]) & 'A2 | 'A1 out 'A2 & 'A1] -//│ 'A1 <: Add['E0] | Lit | Neg['A0] +//│ (Add[Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]) -> int TestLang.eval(add11) @@ -170,48 +138,27 @@ mixin EvalNegNeg { else super.eval(e) } //│ mixin EvalNegNeg() { -//│ super: {eval: (Neg[in 'A & (~Neg | Neg[in 'expr out nothing]) out 'A | 'A0] & {Neg#A :> 'A & (~Neg | Neg[in 'expr out nothing]) <: 'A | 'A0} | 'a) -> 'b} +//│ super: {eval: (Neg['A] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A1] | 'a & ~Neg) -> 'b +//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } -//│ where -//│ 'A1 :> 'A -//│ <: 'A0 & (~Neg | Neg['A2]) -//│ 'A2 <: 'expr module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ namespace TestLang() { -//│ this: {eval: 'E -> int & nothing -> 'a} -//│ fun eval: (Add['E] | Lit | Neg[Neg['A] & 'A0]) -> (int | 'a) +//│ this: {eval: ('expr | 'lhs) -> int & 'expr0 -> 'a} +//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg])] | Lit | Neg['expr & (Add[anything] | Lit | Neg['expr0 & (Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg)]) -> (int | 'a) //│ } -//│ where -//│ 'A0 <: nothing -//│ 'A <: nothing -//│ 'E <: (Add['E0] | Lit | Neg[Neg['A1] & 'A2]) & (Add['E1] | Lit | Neg[Neg['A3] & 'A4]) -//│ 'A4 <: nothing -//│ 'A3 <: nothing -//│ 'E1 <: Add['E0] | Lit | Neg[Neg['A1] & 'A2] -//│ 'A2 <: nothing -//│ 'A1 <: nothing fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ fun mk: number -> (Lit | 'a) +//│ fun mk: number -> 'E //│ where -//│ 'a :> Neg['A] | Add['E] -//│ 'E :> Lit | 'a -//│ 'A :> Lit | 'a +//│ 'E :> Add['E] | Lit | Neg['E] TestLang.eval -//│ (Add['E] | Lit | Neg[Neg['A] & 'A0]) -> int -//│ where -//│ 'A0 <: nothing -//│ 'A <: nothing -//│ 'E <: Add[in (Add['E0] | Lit | Neg[Neg['A1] & 'A2]) & 'E1 | 'E0 out 'E1 & 'E0] | Lit | Neg[Neg['A1] & 'A2] -//│ 'A2 <: nothing -//│ 'A1 <: nothing +//│ (Add[Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]) -> int TestLang.eval(mk(0)) //│ int diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index f13602820b..8414fcf7d2 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -8,9 +8,7 @@ class Add(lhs: E, rhs: E) //│ class Add[E](lhs: E, rhs: E) let e = Add(1, 1) -//│ let e: Add['E] -//│ where -//│ 'E :> 1 +//│ let e: Add[1] :d e @@ -21,9 +19,7 @@ e //│ res: Some(α32) where //│ α32 :> (Add<> & {Add#E: mut E23_33..E23_33}) //│ E23_33 :> 1 -//│ Add['E] -//│ where -//│ 'E :> 1 +//│ Add[1] e.lhs //│ 1 @@ -35,17 +31,13 @@ e //│ | 0. : α32 //│ ======== TYPED ======== //│ res: Some(α32) where -//│ α32 :> (Add<> & {Add#E: mut E23_33..E23_33}) <: {lhs: lhs42} -//│ E23_33 :> 1 <: lhs42 -//│ lhs42 :> 1 -//│ Add['E] -//│ where -//│ 'E :> 1 +//│ α32 :> (Add<> & {Add#E: mut E23_33..E23_33}) <: {lhs: lhs38} +//│ E23_33 :> 1 <: lhs38 +//│ lhs38 :> 1 +//│ Add[1] Add(2, 2) -//│ Add['E] -//│ where -//│ 'E :> 2 +//│ Add[2] diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index b01e723e1a..dc3984620a 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -4,14 +4,12 @@ class Add(lhs: E, rhs: E) -class Lit(n: int) +class Lit(value: int) //│ class Add[E](lhs: E, rhs: E) -//│ class Lit(n: int) +//│ class Lit(value: int) let add11 = Add(Lit(1), Lit(2)) -//│ let add11: Add['E] -//│ where -//│ 'E :> Lit +//│ let add11: Add[Lit] fun eval(e) = if e is @@ -19,8 +17,43 @@ fun eval(e) = Add(l, r) then eval(l) + eval(r) //│ fun eval: 'a -> int //│ where -//│ 'a <: Add['E] | Lit -//│ 'E <: 'a +//│ 'a <: Add['a] | Lit + + +mixin EvalLit { + fun eval(e) = + if e is + Lit(n) then n +} +//│ mixin EvalLit() { +//│ fun eval: Lit -> int +//│ } + +mixin EvalLit { + fun eval(e: Lit) = e.value +} +//│ mixin EvalLit() { +//│ fun eval: (e: Lit,) -> int +//│ } + + +mixin EvalAdd { + fun eval(e) = + if e is + Add(l, r) then this.eval(l) +} +//│ mixin EvalAdd() { +//│ this: {eval: 'lhs -> 'a} +//│ fun eval: Add['lhs] -> 'a +//│ } + +// FIXME type vars are wrongly refreshed when tying the knot +module TestLang: EvalAdd +//│ namespace TestLang() { +//│ this: {eval: 'lhs -> 'a} +//│ fun eval: Add[Add[anything] & 'lhs] -> 'a +//│ } + mixin EvalBase { @@ -31,50 +64,35 @@ mixin EvalBase { } //│ mixin EvalBase() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['E] | Lit) -> int +//│ fun eval: (Add['lhs] | Lit) -> int //│ } -//│ where -//│ 'E <: 'lhs module TestLang: EvalBase //│ namespace TestLang() { -//│ this: {eval: 'E -> int} -//│ fun eval: (Add['E] | Lit) -> int +//│ this: {eval: 'lhs -> int} +//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit] | Lit)] | Lit) -> int //│ } -//│ where -//│ 'E <: (Add['E0] | Lit) & (Add['E1] | Lit) -//│ 'E0 <: Add['E1] | Lit TestLang.eval -//│ (Add['E] | Lit) -> int -//│ where -//│ 'E <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit +//│ (Add[Add[Add[anything] | Lit] | Lit] | Lit) -> int add11 -//│ Add['E] -//│ where -//│ 'E :> Lit +//│ Add[Lit] TestLang.eval(add11) //│ int add11 -//│ Add['E] -//│ where -//│ 'E :> Lit -//│ <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit +//│ Add[Lit] TestLang.eval(add11) //│ int add11 -//│ Add['E] -//│ where -//│ 'E :> Lit -//│ <: Add[in (Add['E0] | Lit) & 'E1 | 'E0 out 'E1 & 'E0] | Lit +//│ Add[Lit] @@ -82,12 +100,7 @@ class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: Add['E] -//│ where -//│ 'E :> Lit | Neg['A] -//│ 'A :> Add['E0] -//│ 'E0 :> Lit -//│ <: Add[in (Add['E1] | Lit) & 'E2 | 'E1 out 'E2 & 'E1] | Lit +//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] mixin EvalNeg { @@ -98,30 +111,18 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['A] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } -//│ where -//│ 'A <: 'expr module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: {eval: ('A | 'E) -> int} -//│ fun eval: (Add['E] | Lit | Neg['A]) -> int +//│ this: {eval: ('expr | 'lhs) -> int} +//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Lit | Neg['expr & (Add[anything] | Lit | Neg[anything])]) -> int //│ } -//│ where -//│ 'E <: (Add['E0] | Lit | Neg['A0]) & (Add['E1] | Lit | Neg['A1]) -//│ 'A1 <: Add['E2] | Lit | Neg['A2] -//│ 'E1 <: Add['E0] | Lit | Neg['A0] -//│ 'A0 <: Add['E2] | Lit | Neg['A2] -//│ 'A <: Add['E2] | Lit | Neg['A2] TestLang.eval -//│ (Add['E] | Lit | Neg['A]) -> int -//│ where -//│ 'A <: Add['E0] | Lit | Neg['A0] -//│ 'E <: Add[in (Add['E1] | Lit | Neg['A1]) & 'E2 | 'E1 out 'E2 & 'E1] | Lit | Neg[in (Add['E0] | Lit | Neg['A0]) & 'A2 | 'A1 out 'A2 & 'A1] -//│ 'A1 <: Add['E0] | Lit | Neg['A0] +//│ (Add[Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]) -> int TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/ECOOP23_small.mls b/shared/src/test/diff/nu/ECOOP23_small.mls new file mode 100644 index 0000000000..b560f2eb2f --- /dev/null +++ b/shared/src/test/diff/nu/ECOOP23_small.mls @@ -0,0 +1,53 @@ +:NewParser +:NewDefs +:NoJS + + +class Neg(expr: A) +class Add(lhs: E, rhs: E) +class Lit(n: int) +//│ class Neg[A](expr: A) +//│ class Add[E](lhs: E, rhs: E) +//│ class Lit(n: int) + +let add11 = Add(Lit(1), Lit(2)) +let add2negadd11 = Add(Lit(2), Neg(add11)) +//│ let add11: Add[Lit] +//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] + +mixin EvalNothing { + fun eval(e: nothing) = e +} +mixin EvalAddLit { + fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then this.eval(l) + this.eval(r) + else super.eval(e) +} +mixin EvalNeg { + fun eval(e) = + if e is Neg(d) then 0 - this.eval(d) + else super.eval(e) +} +//│ mixin EvalNothing() { +//│ fun eval: (e: nothing,) -> nothing +//│ } +//│ mixin EvalAddLit() { +//│ super: {eval: 'a -> 'b} +//│ this: {eval: 'lhs -> int} +//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ } +//│ mixin EvalNeg() { +//│ super: {eval: 'c -> 'd} +//│ this: {eval: 'expr -> int} +//│ fun eval: (Neg['expr] | 'c & ~Neg) -> (int | 'd) +//│ } + +module TestLang: EvalNothing, EvalAddLit, EvalNeg +//│ namespace TestLang() { +//│ this: {eval: ('expr | 'lhs) -> int} +//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Lit | Neg['expr & (Add[anything] | Lit | Neg[anything])]) -> int +//│ } + + diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index d1a48cc7e5..b1f7a3e82f 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -6,11 +6,23 @@ class C //│ class C[A]() +fun f(x) = if x is C then x +//│ fun f: C['A] -> C['A] + // :d class C(a: A) //│ class C[A](a: A) +fun f(x) = if x is C(a) then a +//│ fun f: C['a] -> 'a + +let c = C(1) +//│ let c: C[1] + +f(c) +//│ 1 + class Some(value: A) { fun get = value @@ -25,9 +37,7 @@ class Some(value: A) { let s = Some(1) -//│ let s: Some['A] -//│ where -//│ 'A :> 1 +//│ let s: Some[1] s.value @@ -75,9 +85,7 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ let opt: None | Some['A] -//│ where -//│ 'A :> 123 +//│ let opt: None | Some[123] opt.toArray //│ Array[123] @@ -101,12 +109,10 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: (None | Some['A], 'A -> 'A0,) -> (None | Some['A0]) +//│ fun map: (None | Some['value], 'value -> 'A,) -> (None | Some['A]) let mo = map(opt, succ) -//│ let mo: None | Some['A] -//│ where -//│ 'A :> int +//│ let mo: None | Some[int] mo.toArray //│ Array[int] @@ -119,7 +125,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.117: class Test(n) { +//│ ║ l.123: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -139,27 +145,23 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.139: fun foo = n + 1 +//│ ║ l.145: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.139: fun foo = n + 1 +//│ ║ l.145: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.138: class Test(n: A) { +//│ ║ l.144: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int //│ } Test(1) -//│ Test['A] -//│ where -//│ 'A :> 1 +//│ Test[1] Test(true) -//│ Test['A] -//│ where -//│ 'A :> true +//│ Test[true] class Test(n: A) { @@ -174,9 +176,7 @@ class Test(n: A) { //│ } Test(1) -//│ Test['A] -//│ where -//│ 'A :> 1 +//│ Test[1] Test(1).foo //│ 1 @@ -185,9 +185,7 @@ Test("ok").foo //│ "ok" let t = Test(1) -//│ let t: Test['A] -//│ where -//│ 'A :> 1 +//│ let t: Test[1] t.foo1(true) //│ 1 | true @@ -205,36 +203,36 @@ t.id :e -class Test { +class TestBad { fun foo1(x: A) = x fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.210: fun foo2(x: A) = x + 1 +//│ ║ l.208: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.210: fun foo2(x: A) = x + 1 +//│ ║ l.208: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.208: class Test { -//│ ╙── ^ -//│ class Test[A]() { +//│ ║ l.206: class TestBad { +//│ ╙── ^ +//│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A //│ fun foo2: (x: A,) -> (error | int) //│ } -Test().foo1 +TestBad().foo1 //│ (x: 'A,) -> 'A -Test().foo1(1) +TestBad().foo1(1) //│ 1 -x => Test().foo1(x) +x => TestBad().foo1(x) //│ 'a -> 'a // :d -let t = Test() -//│ let t: forall 'A. Test['A] +let t = TestBad() +//│ let t: forall 'A. TestBad['A] t.foo1 //│ (x: 'A,) -> 'A @@ -246,11 +244,11 @@ t.foo1(0) //│ 0 t -//│ forall 'A. Test['A] +//│ forall 'A. TestBad['A] -fun foo(x: Test) = x.foo1 -//│ fun foo: (x: Test[int],) -> (x: int,) -> int +fun foo(x: TestBad) = x.foo1 +//│ fun foo: (x: TestBad[int],) -> (x: int,) -> int foo(t) //│ (x: int,) -> int @@ -259,7 +257,22 @@ foo(t)(1) //│ int -Test().foo2 +TestBad().foo2 //│ (x: anything,) -> (error | int) + +class Weird(x: C<'a>) +//│ class Weird(x: C['a]) + +let w = Weird(c) +//│ let w: Weird + +w.x +//│ C['a] + +// FIXME +not(w.x.a) +//│ bool + + From 743c72f1e46fe740b68b59059d388fa339b23a0f Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sat, 25 Feb 2023 11:11:22 +0800 Subject: [PATCH 071/498] Apply new constrcutor translation --- .../src/main/scala/mlscript/JSBackend.scala | 10 +++++++- .../main/scala/mlscript/codegen/Codegen.scala | 19 +++++++++----- shared/src/main/scala/mlscript/helpers.scala | 8 +++--- shared/src/test/diff/nu/ECOOP23_codegen.mls | 25 +++++++++++++------ 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 4014606531..6435d7a70c 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -418,6 +418,11 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Collect class fields. val fields = classSymbol.body.collectFields ++ classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + + val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") + fields.foreach(constructorScope.declareValue(_, Some(false), false)) + val rest = constructorScope.declareValue("rest", Some(false), false) + val base = baseClassSymbol.map { sym => JSIdent(sym.runtimeName) } val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { @@ -427,7 +432,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case N => N } } - JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) + if (base.isDefined) + JSClassDecl(classSymbol.runtimeName, fields :+ rest.runtimeName, base, members, traits) + else + JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) } /** diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index f061c5450d..6b6000d552 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -790,15 +790,22 @@ final case class JSClassDecl( def toSourceCode: SourceCode = { val constructor: SourceCode = { val buffer = new ListBuffer[Str]() - buffer += " constructor(fields) {" - if (`extends`.isDefined) - buffer += " super(fields);" + val params = fields.iterator.zipWithIndex.foldLeft("")((s, p) => + if (p._2 === fields.length - 1) (if(`extends`.isDefined) s"$s...${p._1}" else s"$s${p._1}") + else s"$s${p._1}, ") + buffer += s" constructor($params) {" + if (`extends`.isDefined) { + val restName = if (fields.length > 0) fields.last else ??? // TODO: throw? + buffer += s" super(...$restName);" + } implements.foreach { name => buffer += s" $name.implement(this);" } - fields.foreach { name => - val innerName = if (JSField.isValidIdentifier(name)) s".${name}" else s"[${JSLit.makeStringLiteral(name)}]" - buffer += s" this$innerName = fields$innerName;" + fields.iterator.zipWithIndex.foreach { pair => + if (`extends`.isEmpty || pair._2 < fields.length - 1) { + // val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" + buffer += s" this.${pair._1} = ${pair._1};" // TODO: invalid name? + } } buffer += " }" SourceCode(buffer.toList) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index a04250ce50..63c25e0e84 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -716,11 +716,11 @@ trait StatementImpl extends Located { self: Statement => val pos = params.unzip._1 val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) val termName = Var(nme.name).withLocOf(nme) - val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(false, false, Rcd(fs.map { - case (S(nme), fld) => nme -> Fld(false, false, nme) - case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld + val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(fs.map { + case (S(nme), fld) => N -> Fld(false, false, nme) + case (N, fld @ Fld(mut, spec, nme: Var)) => N -> Fld(false, false, nme) case _ => die - })) :: Nil)))), true) + })))), true) val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) case _ => lst diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 9c5e826b37..32b35e6aff 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -33,8 +33,8 @@ mixin EvalBase { //│ // Query 1 //│ globalThis.EvalBase = function EvalBase(base) { //│ return (class EvalBase extends base { -//│ constructor(fields) { -//│ super(fields); +//│ constructor(...rest) { +//│ super(...rest); //│ } //│ eval(e) { //│ const self = this; @@ -49,6 +49,7 @@ mixin EvalBase { //│ }; //│ // End of generated code +:js class Neg(expr: A) //│ //│ class Neg[A](expr: A) { @@ -56,6 +57,17 @@ class Neg(expr: A) //│ } //│ where //│ 'this :> Neg +//│ // Prelude +//│ class Neg { +//│ constructor(expr) { +//│ this.expr = expr; +//│ } +//│ } +//│ // Query 1 +//│ globalThis.Neg1 = function Neg1(expr) { +//│ return new Neg(expr); +//│ }; +//│ // End of generated code :js mixin EvalNeg { @@ -76,8 +88,8 @@ mixin EvalNeg { //│ // Query 1 //│ globalThis.EvalNeg = function EvalNeg(base) { //│ return (class EvalNeg extends base { -//│ constructor(fields) { -//│ super(fields); +//│ constructor(...rest) { +//│ super(...rest); //│ } //│ eval(e) { //│ const self = this; @@ -111,8 +123,8 @@ mixin EvalNegNeg { //│ // Query 1 //│ globalThis.EvalNegNeg = function EvalNegNeg(base) { //│ return (class EvalNegNeg extends base { -//│ constructor(fields) { -//│ super(fields); +//│ constructor(...rest) { +//│ super(...rest); //│ } //│ eval(e) { //│ const self = this; @@ -143,7 +155,6 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ Code generation crashed: //│ scala.NotImplementedError: an implementation is missing - :js fun mk(n) = if n is 0 then Lit(0) From 420c9a8ebc7a633c0ef1ba10059f3aac96ff87d9 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 11:19:55 +0800 Subject: [PATCH 072/498] WIP Fix knot-tying of class types --- .../scala/mlscript/ConstraintSolver.scala | 22 +++++----- .../main/scala/mlscript/TyperDatatypes.scala | 18 ++++---- shared/src/test/diff/nu/BasicClasses.mls | 24 +++++++---- shared/src/test/diff/nu/ECOOP23.mls | 42 +++++++++++++++---- shared/src/test/diff/nu/ECOOP23_repro.mls | 30 ++++++++++--- shared/src/test/diff/nu/ECOOP23_small.mls | 6 ++- 6 files changed, 99 insertions(+), 43 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 432aeb4875..82a79910fa 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -30,10 +30,7 @@ class ConstraintSolver extends NormalForms { self: Typer => : TypedNuCls = { val info = ctx.tyDefs2(clsNme) - // Option.when(info.isComputing) { - // ??? - // }.getOrElse - { info.complete() match { + info.complete() match { case td: TypedNuCls => implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty @@ -99,7 +96,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) res case _ => ??? - }} + } } @@ -442,11 +439,16 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(f0, f1, true) case (LhsRefined(S(f: FunctionType), ts, r, trs), RhsBases(pts, _, _)) => annoying(Nil, LhsRefined(N, ts, r, trs), Nil, done_rs) - case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if nme.isCapitalized => - val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) - rec(fty.ub, fldTy.ub, false) - recLb(fldTy, fty) - // ??? + case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, trs0), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) + if nme.isCapitalized => + val lti = ctx.tyDefs2(nme) + if (lti.isComputing) + annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? + else { + val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) + rec(fty.ub, fldTy.ub, false) + recLb(fldTy, fty) + } case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => if (pts.contains(pt) || pts.exists(p => pt.parentsST.contains(p.id))) println(s"OK $pt <: ${pts.mkString(" | ")}") diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 572fb39ffd..3be6460f08 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -271,12 +271,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val thisType = superType & clsNameToNomTag(td)(provTODO, ctx) & RecordType(tparamFields)(ttp(td.params, isType = true)) - // trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { - // assert(finalType.level === lvl) - // constrain(thisType, finalType) - // members - // }() - println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") + trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { + assert(finalType.level === lvl) + constrain(thisType, finalType) + members + }() + // println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") (thisType, members) } @@ -398,9 +398,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // } res match { case cls: TypedNuCls => - implicit val prov: TP = noProv // TODO - constrain(cls.instanceType, thisTV) - println(cls.variances) + // implicit val prov: TP = noProv // TODO + // constrain(cls.instanceType, thisTV) + // println(cls.variances) case _ => } res diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index d1a670983f..3f2f155af1 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -63,12 +63,18 @@ class Base0(n) { //│ ╔══[ERROR] Class parameters currently need type annotations //│ ║ l.57: class Base0(n) { //│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.61: fun oops = this.my +//│ ║ ^^^^^^^ +//│ ╟── reference of type `Base0 & {n: error}` does not have field 'my' +//│ ║ l.61: fun oops = this.my +//│ ╙── ^^^^ //│ class Base0(n: error) { //│ this: {my: 'my, n: 'n} & 'base0 //│ fun me: Base0 & {n: error} | 'base0 //│ fun mine: error | 'n //│ fun my: error | 'n -//│ fun oops: 'my +//│ fun oops: error | 'my //│ } // :d @@ -137,7 +143,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.138: b.getBaseTypo +//│ ║ l.144: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error @@ -151,11 +157,11 @@ class Rec(n: int) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.150: class Rec(n: int) { +//│ ║ l.156: class Rec(n: int) { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.151: fun go = Rec(n + 1) +//│ ║ l.157: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.152: } +//│ ║ l.158: } //│ ╙── ^ //│ class Rec(n: int) { //│ fun go: error @@ -170,16 +176,16 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.169: a: int +//│ ║ l.175: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.168: class Annots(base: 0 | 1) { +//│ ║ l.174: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.169: a: int +//│ ║ l.175: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.169: a: int +//│ ║ l.175: a: int //│ ╙── ^^^ //│ class Annots(base: (0 | 1,)) { //│ fun a: (0 | 1,) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 1e20c06cb6..ab4aa0fec1 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -40,11 +40,16 @@ mixin EvalBase { module TestLang: EvalBase //│ namespace TestLang() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit] | Lit)] | Lit) -> int +//│ fun eval: 'a -> int //│ } +//│ where +//│ 'lhs <: 'a +//│ 'a <: Add['lhs] | Lit TestLang.eval -//│ (Add[Add[Add[anything] | Lit] | Lit] | Lit) -> int +//│ 'a -> int +//│ where +//│ 'a <: Add['a] | Lit TestLang.eval(add11) //│ int @@ -71,11 +76,16 @@ module TestLang: EvalNothing, EvalAddLit //│ } //│ namespace TestLang() { //│ this: {eval: 'lhs0 -> int} -//│ fun eval: (Add['lhs0 & (Add[Add[anything] | Lit] | Lit)] | Lit) -> int +//│ fun eval: 'c -> int //│ } +//│ where +//│ 'lhs0 <: 'c +//│ 'c <: Add['lhs0] | Lit TestLang.eval -//│ (Add[Add[Add[anything] | Lit] | Lit] | Lit) -> int +//│ 'a -> int +//│ where +//│ 'a <: Add['a] | Lit TestLang.eval(add11) //│ int @@ -103,11 +113,17 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { //│ this: {eval: ('expr | 'lhs) -> int} -//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Lit | Neg['expr & (Add[anything] | Lit | Neg[anything])]) -> int +//│ fun eval: 'a -> int //│ } +//│ where +//│ 'expr <: 'a +//│ 'a <: Add['lhs] | Lit | Neg['expr] +//│ 'lhs <: 'a TestLang.eval -//│ (Add[Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]) -> int +//│ 'a -> int +//│ where +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval(add11) @@ -145,9 +161,14 @@ mixin EvalNegNeg { module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ namespace TestLang() { -//│ this: {eval: ('expr | 'lhs) -> int & 'expr0 -> 'a} -//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg])] | Lit | Neg['expr & (Add[anything] | Lit | Neg['expr0 & (Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg)]) -> (int | 'a) +//│ this: {eval: ('A | 'expr | 'lhs) -> int} +//│ fun eval: 'a -> int //│ } +//│ where +//│ 'A <: 'a +//│ 'a <: Add['lhs] | Lit | Neg['A & (~Neg | Neg['expr])] +//│ 'expr <: 'a +//│ 'lhs <: 'a fun mk(n) = if n is 0 then Lit(0) @@ -158,7 +179,10 @@ fun mk(n) = if n is //│ 'E :> Add['E] | Lit | Neg['E] TestLang.eval -//│ (Add[Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Neg[Neg[Add[anything] | Lit | Neg[anything]] | ~Neg[anything]] & ~Neg]) -> int +//│ 'a -> int +//│ where +//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'A <: 'a TestLang.eval(mk(0)) //│ int diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index dc3984620a..5616bff5a0 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -48,11 +48,20 @@ mixin EvalAdd { //│ } // FIXME type vars are wrongly refreshed when tying the knot + module TestLang: EvalAdd //│ namespace TestLang() { //│ this: {eval: 'lhs -> 'a} -//│ fun eval: Add[Add[anything] & 'lhs] -> 'a +//│ fun eval: 'b -> 'a //│ } +//│ where +//│ 'lhs <: 'b +//│ 'b <: Add['lhs] + +TestLang.eval +//│ 'a -> nothing +//│ where +//│ 'a <: Add['a] @@ -71,11 +80,16 @@ mixin EvalBase { module TestLang: EvalBase //│ namespace TestLang() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit] | Lit)] | Lit) -> int +//│ fun eval: 'a -> int //│ } +//│ where +//│ 'lhs <: 'a +//│ 'a <: Add['lhs] | Lit TestLang.eval -//│ (Add[Add[Add[anything] | Lit] | Lit] | Lit) -> int +//│ 'a -> int +//│ where +//│ 'a <: Add['a] | Lit @@ -118,11 +132,17 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { //│ this: {eval: ('expr | 'lhs) -> int} -//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Lit | Neg['expr & (Add[anything] | Lit | Neg[anything])]) -> int +//│ fun eval: 'a -> int //│ } +//│ where +//│ 'expr <: 'a +//│ 'a <: Add['lhs] | Lit | Neg['expr] +//│ 'lhs <: 'a TestLang.eval -//│ (Add[Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]]) -> int +//│ 'a -> int +//│ where +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/ECOOP23_small.mls b/shared/src/test/diff/nu/ECOOP23_small.mls index b560f2eb2f..99c440218d 100644 --- a/shared/src/test/diff/nu/ECOOP23_small.mls +++ b/shared/src/test/diff/nu/ECOOP23_small.mls @@ -47,7 +47,11 @@ mixin EvalNeg { module TestLang: EvalNothing, EvalAddLit, EvalNeg //│ namespace TestLang() { //│ this: {eval: ('expr | 'lhs) -> int} -//│ fun eval: (Add['lhs & (Add[Add[anything] | Lit | Neg[Add[anything] | Lit | Neg[anything]]] | Lit | Neg[Add[anything] | Lit | Neg[anything]])] | Lit | Neg['expr & (Add[anything] | Lit | Neg[anything])]) -> int +//│ fun eval: 'a -> int //│ } +//│ where +//│ 'expr <: 'a +//│ 'a <: Add['lhs] | Lit | Neg['expr] +//│ 'lhs <: 'a From 33830faaef35f25c51bb9be2e648479ae5782f90 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 11:39:53 +0800 Subject: [PATCH 073/498] WIP Remove inferred `this` annotations from classes and modules --- .../main/scala/mlscript/TyperDatatypes.scala | 12 +++- shared/src/test/diff/nu/BasicClasses.mls | 29 ++++----- shared/src/test/diff/nu/BasicMixins.mls | 21 +++--- shared/src/test/diff/nu/ECOOP23.mls | 18 ++---- shared/src/test/diff/nu/ECOOP23_min.mls | 18 +++--- shared/src/test/diff/nu/ECOOP23_repro.mls | 15 ++--- shared/src/test/diff/nu/ECOOP23_small.mls | 12 ++-- shared/src/test/diff/nu/ParamOverriding.mls | 3 +- .../src/test/diff/nu/ThisRefinedClasses.mls | 64 +++++++++++++++++++ 9 files changed, 121 insertions(+), 71 deletions(-) create mode 100644 shared/src/test/diff/nu/ThisRefinedClasses.mls diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 3be6460f08..4288772cac 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -69,8 +69,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => freshVar(noProv/*FIXME*/, N, S(decl.name.decapitalize))(lvl + 1) def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { - if (isComputing) lastWords(s"TODO cyclic defition ${decl.name}") - else trace(s"Completing ${decl.showDbg}") { + if (isComputing) { + // lastWords(s"TODO cyclic defition ${decl.name}") + err(msg"Unhandled cyclic definition", decl.toLoc) // TODO better loc/explanation + } + // else // TODO avert infinite completion recursion here? + trace(s"Completing ${decl.showDbg}") { // var res: ST = errType val res = try { isComputing = true @@ -319,7 +323,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val mems = baseMems ++ clsMems TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems.map(d => d.name -> d).toMap, thisTV + tparams, typedParams, mems.map(d => d.name -> d).toMap, + // if (td.kind is Nms) TopType else thisTV + TopType )(thisType) } case Mxn => diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 3f2f155af1..c8a323e710 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -70,11 +70,10 @@ class Base0(n) { //│ ║ l.61: fun oops = this.my //│ ╙── ^^^^ //│ class Base0(n: error) { -//│ this: {my: 'my, n: 'n} & 'base0 -//│ fun me: Base0 & {n: error} | 'base0 -//│ fun mine: error | 'n -//│ fun my: error | 'n -//│ fun oops: error | 'my +//│ fun me: Base0 & {n: error} +//│ fun mine: error +//│ fun my: error +//│ fun oops: error //│ } // :d @@ -106,7 +105,6 @@ class Base1(base: int) { fun foo(x) = this.base + x } //│ class Base1(base: int) { -//│ this: {base: int} //│ fun foo: int -> int //│ fun getBase1: int //│ fun getBase2: int @@ -118,10 +116,9 @@ class Base1(base: int) { fun foo(x) = base + x } //│ class Base1(base: int) { -//│ this: 'base1 //│ fun foo: int -> int //│ fun getBase1: int -//│ fun me: Base1 & {base: int} | 'base1 +//│ fun me: Base1 & {base: int} //│ } Base1 @@ -143,7 +140,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.144: b.getBaseTypo +//│ ║ l.141: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error @@ -157,11 +154,11 @@ class Rec(n: int) { fun go = Rec(n + 1) } //│ ╔══[ERROR] Cyclic definition -//│ ║ l.156: class Rec(n: int) { +//│ ║ l.153: class Rec(n: int) { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.157: fun go = Rec(n + 1) +//│ ║ l.154: fun go = Rec(n + 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.158: } +//│ ║ l.155: } //│ ╙── ^ //│ class Rec(n: int) { //│ fun go: error @@ -176,16 +173,16 @@ class Annots(base: 0 | 1) { fun a = base } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.175: a: int +//│ ║ l.172: a: int //│ ║ ^ //│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.174: class Annots(base: 0 | 1) { +//│ ║ l.171: class Annots(base: 0 | 1) { //│ ║ ^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.175: a: int +//│ ║ l.172: a: int //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.175: a: int +//│ ║ l.172: a: int //│ ╙── ^^^ //│ class Annots(base: (0 | 1,)) { //│ fun a: (0 | 1,) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index f47d8515a9..a133b6bb09 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -28,10 +28,9 @@ class Base1(base: int): BaseTest, BaseInc { fun test3 = [base, this.base] } //│ class Base1(base: int) { -//│ this: {base: 'base} //│ fun test: int -//│ fun test2: 'base | int -//│ fun test3: (int, 'base | int,) +//│ fun test2: int +//│ fun test3: (int, int,) //│ } Base1(1).test @@ -47,7 +46,7 @@ Base1(1).test3 // TODO class Base1(base): BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.48: class Base1(base): BaseTest +//│ ║ l.47: class Base1(base): BaseTest //│ ╙── ^^^^ //│ class Base1(base: error) { //│ fun test: error @@ -64,13 +63,13 @@ Base1(1).test :e class Base1(x): BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.65: class Base1(x): BaseTest +//│ ║ l.64: class Base1(x): BaseTest //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.65: class Base1(x): BaseTest +//│ ║ l.64: class Base1(x): BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: error}` does not have field 'base' -//│ ║ l.65: class Base1(x): BaseTest +//│ ║ l.64: class Base1(x): BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -163,16 +162,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.164: WrapBase1.wrapA("ok") +//│ ║ l.163: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.164: WrapBase1.wrapA("ok") +//│ ║ l.163: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.110: fun wrapA(x: int) = x : int +//│ ║ l.109: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.120: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.119: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index ab4aa0fec1..6b01cc96a5 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -39,12 +39,10 @@ mixin EvalBase { module TestLang: EvalBase //│ namespace TestLang() { -//│ this: {eval: 'lhs -> int} //│ fun eval: 'a -> int //│ } //│ where -//│ 'lhs <: 'a -//│ 'a <: Add['lhs] | Lit +//│ 'a <: Add['a] | Lit TestLang.eval //│ 'a -> int @@ -75,12 +73,10 @@ module TestLang: EvalNothing, EvalAddLit //│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) //│ } //│ namespace TestLang() { -//│ this: {eval: 'lhs0 -> int} //│ fun eval: 'c -> int //│ } //│ where -//│ 'lhs0 <: 'c -//│ 'c <: Add['lhs0] | Lit +//│ 'c <: Add['c] | Lit TestLang.eval //│ 'a -> int @@ -112,13 +108,10 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: {eval: ('expr | 'lhs) -> int} //│ fun eval: 'a -> int //│ } //│ where -//│ 'expr <: 'a -//│ 'a <: Add['lhs] | Lit | Neg['expr] -//│ 'lhs <: 'a +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval //│ 'a -> int @@ -161,14 +154,11 @@ mixin EvalNegNeg { module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ namespace TestLang() { -//│ this: {eval: ('A | 'expr | 'lhs) -> int} //│ fun eval: 'a -> int //│ } //│ where +//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] //│ 'A <: 'a -//│ 'a <: Add['lhs] | Lit | Neg['A & (~Neg | Neg['expr])] -//│ 'expr <: 'a -//│ 'lhs <: 'a fun mk(n) = if n is 0 then Lit(0) diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index 8414fcf7d2..ba1fddfc6f 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -14,11 +14,11 @@ let e = Add(1, 1) e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α32 +//│ | 0. : α30 //│ ======== TYPED ======== -//│ res: Some(α32) where -//│ α32 :> (Add<> & {Add#E: mut E23_33..E23_33}) -//│ E23_33 :> 1 +//│ res: Some(α30) where +//│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) +//│ E23_31 :> 1 //│ Add[1] e.lhs @@ -28,12 +28,12 @@ e.lhs e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α32 +//│ | 0. : α30 //│ ======== TYPED ======== -//│ res: Some(α32) where -//│ α32 :> (Add<> & {Add#E: mut E23_33..E23_33}) <: {lhs: lhs38} -//│ E23_33 :> 1 <: lhs38 -//│ lhs38 :> 1 +//│ res: Some(α30) where +//│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) <: {lhs: lhs36} +//│ E23_31 :> 1 <: lhs36 +//│ lhs36 :> 1 //│ Add[1] diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 5616bff5a0..dcbf3920be 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -51,12 +51,10 @@ mixin EvalAdd { module TestLang: EvalAdd //│ namespace TestLang() { -//│ this: {eval: 'lhs -> 'a} -//│ fun eval: 'b -> 'a +//│ fun eval: 'a -> nothing //│ } //│ where -//│ 'lhs <: 'b -//│ 'b <: Add['lhs] +//│ 'a <: Add['a] TestLang.eval //│ 'a -> nothing @@ -79,12 +77,10 @@ mixin EvalBase { module TestLang: EvalBase //│ namespace TestLang() { -//│ this: {eval: 'lhs -> int} //│ fun eval: 'a -> int //│ } //│ where -//│ 'lhs <: 'a -//│ 'a <: Add['lhs] | Lit +//│ 'a <: Add['a] | Lit TestLang.eval //│ 'a -> int @@ -131,13 +127,10 @@ mixin EvalNeg { module TestLang: EvalBase, EvalNeg //│ namespace TestLang() { -//│ this: {eval: ('expr | 'lhs) -> int} //│ fun eval: 'a -> int //│ } //│ where -//│ 'expr <: 'a -//│ 'a <: Add['lhs] | Lit | Neg['expr] -//│ 'lhs <: 'a +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval //│ 'a -> int diff --git a/shared/src/test/diff/nu/ECOOP23_small.mls b/shared/src/test/diff/nu/ECOOP23_small.mls index 99c440218d..0cec2de06b 100644 --- a/shared/src/test/diff/nu/ECOOP23_small.mls +++ b/shared/src/test/diff/nu/ECOOP23_small.mls @@ -21,7 +21,7 @@ mixin EvalNothing { mixin EvalAddLit { fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n Add(l, r) then this.eval(l) + this.eval(r) else super.eval(e) } @@ -46,12 +46,14 @@ mixin EvalNeg { module TestLang: EvalNothing, EvalAddLit, EvalNeg //│ namespace TestLang() { -//│ this: {eval: ('expr | 'lhs) -> int} //│ fun eval: 'a -> int //│ } //│ where -//│ 'expr <: 'a -//│ 'a <: Add['lhs] | Lit | Neg['expr] -//│ 'lhs <: 'a +//│ 'a <: Add['a] | Lit | Neg['a] + +TestLang.eval +//│ 'a -> int +//│ where +//│ 'a <: Add['a] | Lit | Neg['a] diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index fbb9792777..65545672a4 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -16,9 +16,8 @@ class Base1(p: int): Over { // fun test2 = super.p // TODO } //│ class Base1(p: int) { -//│ this: {p: 'p} //│ fun p: "hi" -//│ fun test: (int, "hi" | 'p,) +//│ fun test: (int, "hi",) //│ } diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls new file mode 100644 index 0000000000..26d85e259d --- /dev/null +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -0,0 +1,64 @@ +:NewParser +:NewDefs +:NoJS + + + +// * I don't think it's a good idea to generate `this` refinements for classes, +// * as this could easily lead to typos and delayed error reporting. +// * Instead, we should require explicit `this` annotations by users when needed. + + +:e +class Foo { fun test = this.x } +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.13: class Foo { fun test = this.x } +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ class Foo() { +//│ fun test: error +//│ } + + +:e +class Foo(n: int) { fun test = this.x } +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.23: class Foo(n: int) { fun test = this.x } +//│ ║ ^^^^^^ +//│ ╟── reference of type `Foo & {n: int}` does not have field 'x' +//│ ║ l.23: class Foo(n: int) { fun test = this.x } +//│ ╙── ^^^^ +//│ class Foo(n: int) { +//│ fun test: error +//│ } + + +:e +class Foo(n: A) { fun test = this.x } +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.36: class Foo(n: A) { fun test = this.x } +//│ ║ ^^^^^^ +//│ ╟── reference of type `Foo & {Foo#A = ?A, n: A}` does not have field 'x' +//│ ║ l.36: class Foo(n: A) { fun test = this.x } +//│ ╙── ^^^^ +//│ class Foo[A](n: A) { +//│ fun test: error +//│ } + + + +// TODO support: (treat `this` annot not like a term ascription) +class Foo { + this: { x: 'a } + // fun test = this.x +} +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.50: class Foo { +//│ ║ ^^^^^^^^^^^ +//│ ║ l.51: this: { x: 'a } +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.52: // fun test = this.x +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.53: } +//│ ╙── ^ +//│ class Foo() + From d6ec85b7ea7ac8002b14e1036e332b1e3e2dd46a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 11:42:44 +0800 Subject: [PATCH 074/498] WIP (weird) --- shared/src/test/diff/fcp/ForallTerms.mls | 2 +- shared/src/test/diff/fcp/QML_exist_Records.mls | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/src/test/diff/fcp/ForallTerms.mls b/shared/src/test/diff/fcp/ForallTerms.mls index f33c0a818e..9045eeb01f 100644 --- a/shared/src/test/diff/fcp/ForallTerms.mls +++ b/shared/src/test/diff/fcp/ForallTerms.mls @@ -23,7 +23,7 @@ f: forall 'X. 'X -> 'X r = { f = forall 'A. fun (x: 'A) -> x } -//│ r: {f: 'A -> 'A} +//│ r: {f: forall 'A. 'A -> 'A} //│ = { f: [Function: f] } r.f 0 diff --git a/shared/src/test/diff/fcp/QML_exist_Records.mls b/shared/src/test/diff/fcp/QML_exist_Records.mls index 3c608f29b2..4df757dc78 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records.mls @@ -291,7 +291,7 @@ def step arr f = f (stepImpl2 arr) :e // * Since "sound extrusion" def step arr f = f (stepImpl2_Ann_2 arr) -//│ ((forall 'r 'a. ArraysRep['a, 'r] -> {fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> ('r, anything,) -> 'b, init: 'a -> ('r, "hi",), sub: ('r, anything,) -> int -> 'a, update: ('r, anything,) -> int -> 'a -> ('r, "hey",)}) -> 'c) -> ('c -> 'd) -> 'd +//│ ((forall 'a 'r. ArraysRep['a, 'r] -> {fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> ('r, anything,) -> 'b, init: 'a -> ('r, "hi",), sub: ('r, anything,) -> int -> 'a, update: ('r, anything,) -> int -> 'a -> ('r, "hey",)}) -> 'c) -> ('c -> 'd) -> 'd //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -330,7 +330,7 @@ def step arr f = f (stepImpl2_Ann_2 arr) :e def step arr f = f (stepImpl2_Ann_3 arr) -//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'i -> 'g, sub: 'a -> 'f -> 'd, update: 'b -> 'h -> 'e -> 'c} -> {fold: Fold[nothing, (anything, string,)], init: 'i -> ('g, "hi",), sub: ('a, anything,) -> 'f -> 'd, update: ('b, anything,) -> 'h -> 'e -> ('c, "hey",)}) -> 'j) -> ('j -> 'k) -> 'k +//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'a -> 'g, sub: 'e -> 'b -> 'h, update: 'f -> 'd -> 'c -> 'i} -> {fold: Fold[nothing, (anything, string,)], init: 'a -> ('g, "hi",), sub: ('e, anything,) -> 'b -> 'h, update: ('f, anything,) -> 'd -> 'c -> ('i, "hey",)}) -> 'j) -> ('j -> 'k) -> 'k //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition From a7375b9cd5112dcc6db94f8391c86279126b0340 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 11:49:14 +0800 Subject: [PATCH 075/498] WIP Make newdefs pretty-printing more consistent --- shared/src/main/scala/mlscript/helpers.scala | 14 +++++-- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/nu/BasicMixins.mls | 6 +-- shared/src/test/diff/nu/ECOOP23.mls | 42 +++++++++---------- shared/src/test/diff/nu/ECOOP23_min.mls | 8 ++-- shared/src/test/diff/nu/ECOOP23_repro.mls | 36 ++++++++-------- shared/src/test/diff/nu/ECOOP23_small.mls | 14 +++---- shared/src/test/diff/nu/GenericClasses.mls | 40 +++++++++--------- shared/src/test/diff/nu/MutualRec.mls | 12 +++--- .../src/test/scala/mlscript/DiffTests.scala | 3 +- 10 files changed, 93 insertions(+), 84 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 2e0eb03847..53caf8e95f 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -77,7 +77,8 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Bounds(lb, Top) => s"in ${lb.showIn(ctx, 0)}" case Bounds(lb, ub) => s"in ${lb.showIn(ctx, 0)} out ${ub.showIn(ctx, 0)}" // - case AppliedType(n, args) => s"${n.name}[${args.map(_.showIn(ctx, 0)).mkString(", ")}]" + case AppliedType(n, args) => + s"${n.name}${args.map(_.showIn(ctx, 0)).mkString(ctx.<, ", ", ctx.>)}" case Rem(b, ns) => s"${b.showIn(ctx, 90)}${ns.map("\\"+_).mkString}" case Literal(IntLit(n)) => n.toString case Literal(DecLit(n)) => n.toString @@ -243,11 +244,18 @@ trait TypeImpl extends Located { self: Type => } -final case class ShowCtx(vs: Map[TypeVar, Str], debug: Bool, indentLevel: Int) // TODO make use of `debug` or rm +final case class ShowCtx( + vs: Map[TypeVar, Str], + debug: Bool, // TODO make use of `debug` or rm + indentLevel: Int, + newDefs: Bool, + ) { lazy val indStr: Str = " " * indentLevel def lnIndStr: Str = "\n" + indStr def indent: ShowCtx = copy(indentLevel = indentLevel + 1) + def < : Str = if (newDefs) "<" else "[" + def > : Str = if (newDefs) ">" else "]" } object ShowCtx { /** @@ -291,7 +299,7 @@ object ShowCtx { S(('a' + idx % numLetters).toChar.toString + (if (postfix === 0) "" else postfix.toString), idx + 1) }.filterNot(used).map(assignName) - ShowCtx(namedMap ++ unnamedVars.zip(names), debug, 0) + ShowCtx(namedMap ++ unnamedVars.zip(names), debug, indentLevel = 0, newDefs = false) } } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 840d7e59fa..c2cfae297f 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -51,7 +51,7 @@ case object Cls extends TypeDefKind("class") with ObjDefKind case object Trt extends TypeDefKind("trait") with ObjDefKind case object Mxn extends TypeDefKind("mixin") case object Als extends TypeDefKind("type alias") -case object Nms extends TypeDefKind("namespace") +case object Nms extends TypeDefKind("module") sealed abstract class Term extends Terms with TermImpl sealed abstract class Lit extends SimpleTerm with LitImpl diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index a133b6bb09..3d41937b1f 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -95,7 +95,7 @@ mixin Foo { //│ } module Base1(base: int, misc: string): Foo -//│ namespace Base1(base: int, misc: string) { +//│ module Base1(base: int, misc: string) { //│ fun test: (int & 'a) -> (int, 'a, string,) //│ } @@ -129,7 +129,7 @@ mixin Wrap { // :d module WrapBase1: WrapBase, Wrap -//│ namespace WrapBase1() { +//│ module WrapBase1() { //│ fun wrap: 'a -> ('a,) //│ fun wrapA: int -> (int,) //│ } @@ -178,7 +178,7 @@ WrapBase1.wrapA("ok") module WrapBase2: WrapBase, Wrap, Wrap, Wrap -//│ namespace WrapBase2() { +//│ module WrapBase2() { //│ fun wrap: 'a -> ((('a,),),) //│ fun wrapA: int -> (((int,),),) //│ } diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 6b01cc96a5..9695ae1cdf 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -9,7 +9,7 @@ class Lit(n: int) //│ class Lit(n: int) fun add11 = Add(Lit(1), Lit(2)) -//│ fun add11: Add[Lit] +//│ fun add11: Add // add11 + 1 @@ -22,7 +22,7 @@ fun eval(e) = Add(l, r) then eval(l) + eval(r) //│ fun eval: 'a -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'a <: Add<'a> | Lit mixin EvalBase { @@ -33,21 +33,21 @@ mixin EvalBase { } //│ mixin EvalBase() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit) -> int +//│ fun eval: (Add<'lhs> | Lit) -> int //│ } module TestLang: EvalBase -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit +//│ 'a <: Add<'a> | Lit TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'a <: Add<'a> | Lit TestLang.eval(add11) //│ int @@ -70,18 +70,18 @@ module TestLang: EvalNothing, EvalAddLit //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ fun eval: (Add<'lhs> | Lit | 'a & ~Add & ~Lit) -> (int | 'b) //│ } -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'c -> int //│ } //│ where -//│ 'c <: Add['c] | Lit +//│ 'c <: Add<'c> | Lit TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'a <: Add<'a> | Lit TestLang.eval(add11) //│ int @@ -91,7 +91,7 @@ class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] +//│ let add2negadd11: Add>> mixin EvalNeg { @@ -102,21 +102,21 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg<'expr> | 'a & ~Neg) -> (int | 'b) //│ } module TestLang: EvalBase, EvalNeg -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'a <: Add<'a> | Lit | Neg<'a> TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'a <: Add<'a> | Lit | Neg<'a> TestLang.eval(add11) @@ -147,17 +147,17 @@ mixin EvalNegNeg { else super.eval(e) } //│ mixin EvalNegNeg() { -//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ super: {eval: (Neg<'A> | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b +//│ fun eval: (Neg<'A & (~Neg | Neg<'expr>)> | 'a & ~Neg) -> 'b //│ } module TestLang: EvalBase, EvalNeg, EvalNegNeg -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'a <: Add<'a> | Lit | Neg<'A & (~Neg | Neg<'a>)> //│ 'A <: 'a fun mk(n) = if n is @@ -166,12 +166,12 @@ fun mk(n) = if n is _ then Add(mk(n), mk(n)) //│ fun mk: number -> 'E //│ where -//│ 'E :> Add['E] | Lit | Neg['E] +//│ 'E :> Add<'E> | Lit | Neg<'E> TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'a <: Add<'a> | Lit | Neg<'A & (~Neg | Neg<'a>)> //│ 'A <: 'a TestLang.eval(mk(0)) diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index ba1fddfc6f..1806a98b53 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -8,7 +8,7 @@ class Add(lhs: E, rhs: E) //│ class Add[E](lhs: E, rhs: E) let e = Add(1, 1) -//│ let e: Add[1] +//│ let e: Add<1> :d e @@ -19,7 +19,7 @@ e //│ res: Some(α30) where //│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) //│ E23_31 :> 1 -//│ Add[1] +//│ Add<1> e.lhs //│ 1 @@ -34,10 +34,10 @@ e //│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) <: {lhs: lhs36} //│ E23_31 :> 1 <: lhs36 //│ lhs36 :> 1 -//│ Add[1] +//│ Add<1> Add(2, 2) -//│ Add[2] +//│ Add<2> diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index dcbf3920be..6adfbf5db7 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -9,7 +9,7 @@ class Lit(value: int) //│ class Lit(value: int) let add11 = Add(Lit(1), Lit(2)) -//│ let add11: Add[Lit] +//│ let add11: Add fun eval(e) = if e is @@ -17,7 +17,7 @@ fun eval(e) = Add(l, r) then eval(l) + eval(r) //│ fun eval: 'a -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'a <: Add<'a> | Lit mixin EvalLit { @@ -44,22 +44,22 @@ mixin EvalAdd { } //│ mixin EvalAdd() { //│ this: {eval: 'lhs -> 'a} -//│ fun eval: Add['lhs] -> 'a +//│ fun eval: Add<'lhs> -> 'a //│ } // FIXME type vars are wrongly refreshed when tying the knot module TestLang: EvalAdd -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'a -> nothing //│ } //│ where -//│ 'a <: Add['a] +//│ 'a <: Add<'a> TestLang.eval //│ 'a -> nothing //│ where -//│ 'a <: Add['a] +//│ 'a <: Add<'a> @@ -71,38 +71,38 @@ mixin EvalBase { } //│ mixin EvalBase() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit) -> int +//│ fun eval: (Add<'lhs> | Lit) -> int //│ } module TestLang: EvalBase -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit +//│ 'a <: Add<'a> | Lit TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'a <: Add<'a> | Lit add11 -//│ Add[Lit] +//│ Add TestLang.eval(add11) //│ int add11 -//│ Add[Lit] +//│ Add TestLang.eval(add11) //│ int add11 -//│ Add[Lit] +//│ Add @@ -110,7 +110,7 @@ class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] +//│ let add2negadd11: Add>> mixin EvalNeg { @@ -121,21 +121,21 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg<'expr> | 'a & ~Neg) -> (int | 'b) //│ } module TestLang: EvalBase, EvalNeg -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'a <: Add<'a> | Lit | Neg<'a> TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'a <: Add<'a> | Lit | Neg<'a> TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/ECOOP23_small.mls b/shared/src/test/diff/nu/ECOOP23_small.mls index 0cec2de06b..64ed68014c 100644 --- a/shared/src/test/diff/nu/ECOOP23_small.mls +++ b/shared/src/test/diff/nu/ECOOP23_small.mls @@ -12,8 +12,8 @@ class Lit(n: int) let add11 = Add(Lit(1), Lit(2)) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add11: Add[Lit] -//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] +//│ let add11: Add +//│ let add2negadd11: Add>> mixin EvalNothing { fun eval(e: nothing) = e @@ -36,24 +36,24 @@ mixin EvalNeg { //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ fun eval: (Add<'lhs> | Lit | 'a & ~Add & ~Lit) -> (int | 'b) //│ } //│ mixin EvalNeg() { //│ super: {eval: 'c -> 'd} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'c & ~Neg) -> (int | 'd) +//│ fun eval: (Neg<'expr> | 'c & ~Neg) -> (int | 'd) //│ } module TestLang: EvalNothing, EvalAddLit, EvalNeg -//│ namespace TestLang() { +//│ module TestLang() { //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'a <: Add<'a> | Lit | Neg<'a> TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'a <: Add<'a> | Lit | Neg<'a> diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index b1f7a3e82f..1483e37ebd 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -7,7 +7,7 @@ class C //│ class C[A]() fun f(x) = if x is C then x -//│ fun f: C['A] -> C['A] +//│ fun f: C<'A> -> C<'A> // :d @@ -15,10 +15,10 @@ class C(a: A) //│ class C[A](a: A) fun f(x) = if x is C(a) then a -//│ fun f: C['a] -> 'a +//│ fun f: C<'a> -> 'a let c = C(1) -//│ let c: C[1] +//│ let c: C<1> f(c) //│ 1 @@ -37,7 +37,7 @@ class Some(value: A) { let s = Some(1) -//│ let s: Some[1] +//│ let s: Some<1> s.value @@ -68,7 +68,7 @@ module None { fun toArray = [] // fun mapBad(f) = None // TODO } -//│ namespace None() { +//│ module None() { //│ fun get: nothing //│ fun toArray: () //│ } @@ -85,10 +85,10 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ let opt: None | Some[123] +//│ let opt: None | Some<123> opt.toArray -//│ Array[123] +//│ Array<123> // TODO @@ -109,13 +109,13 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: (None | Some['value], 'value -> 'A,) -> (None | Some['A]) +//│ fun map: (None | Some<'value>, 'value -> 'A,) -> (None | Some<'A>) let mo = map(opt, succ) -//│ let mo: None | Some[int] +//│ let mo: None | Some mo.toArray -//│ Array[int] +//│ Array @@ -158,10 +158,10 @@ class Test(n: A) { //│ } Test(1) -//│ Test[1] +//│ Test<1> Test(true) -//│ Test[true] +//│ Test class Test(n: A) { @@ -176,7 +176,7 @@ class Test(n: A) { //│ } Test(1) -//│ Test[1] +//│ Test<1> Test(1).foo //│ 1 @@ -185,13 +185,13 @@ Test("ok").foo //│ "ok" let t = Test(1) -//│ let t: Test[1] +//│ let t: Test<1> t.foo1(true) //│ 1 | true t : Test<'a> -//│ Test['a] +//│ Test<'a> //│ where //│ 'a :> 1 | true @@ -232,7 +232,7 @@ x => TestBad().foo1(x) // :d let t = TestBad() -//│ let t: forall 'A. TestBad['A] +//│ let t: forall 'A. TestBad<'A> t.foo1 //│ (x: 'A,) -> 'A @@ -244,11 +244,11 @@ t.foo1(0) //│ 0 t -//│ forall 'A. TestBad['A] +//│ forall 'A. TestBad<'A> fun foo(x: TestBad) = x.foo1 -//│ fun foo: (x: TestBad[int],) -> (x: int,) -> int +//│ fun foo: (x: TestBad,) -> (x: int,) -> int foo(t) //│ (x: int,) -> int @@ -263,13 +263,13 @@ TestBad().foo2 class Weird(x: C<'a>) -//│ class Weird(x: C['a]) +//│ class Weird(x: C<'a>) let w = Weird(c) //│ let w: Weird w.x -//│ C['a] +//│ C<'a> // FIXME not(w.x.a) diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 8d4b6f90bf..2890121cb4 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -103,10 +103,10 @@ module Test0_1 { module Test0_2 { fun b = 123 } -//│ namespace Test0_1() { +//│ module Test0_1() { //│ fun a: 123 //│ } -//│ namespace Test0_2() { +//│ module Test0_2() { //│ fun b: 123 //│ } @@ -141,10 +141,10 @@ module Test1_2 { //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ║ l.133: } //│ ╙── ^ -//│ namespace Test1_1() { +//│ module Test1_1() { //│ fun a: error //│ } -//│ namespace Test1_2() { +//│ module Test1_2() { //│ fun b: error //│ } @@ -212,13 +212,13 @@ module Test2_2 { //│ ║ ^^^^^^^^^^^^^ //│ ║ l.183: } //│ ╙── ^ -//│ namespace Test2_1() { +//│ module Test2_1() { //│ fun a: 123 //│ fun d: error //│ fun n: 456 //│ fun t2: Test2_2 //│ } -//│ namespace Test2_2() { +//│ module Test2_2() { //│ fun b: 123 //│ fun c: error //│ fun e: error diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 74a82f6a6f..f6a848efc6 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -571,7 +571,8 @@ class DiffTests val exp = typer.expandType(sim)(ctx) - val expStr = exp.show + val expStr = + exp.showIn(ShowCtx.mk(exp :: Nil).copy(newDefs = true), 0) output(expStr.stripSuffix("\n")) From 01ee0e6571717b3f0c8c08d51e31ee7e5032d7bd Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 11:54:30 +0800 Subject: [PATCH 076/498] WIP For now conform with syntax shown in paper --- .../src/main/scala/mlscript/NewParser.scala | 6 +-- shared/src/test/diff/nu/ECOOP23.mls | 34 ++++++++--------- shared/src/test/diff/nu/ECOOP23_min.mls | 8 ++-- shared/src/test/diff/nu/ECOOP23_repro.mls | 30 +++++++-------- shared/src/test/diff/nu/ECOOP23_small.mls | 16 ++++---- shared/src/test/diff/nu/GenericClasses.mls | 38 +++++++++---------- shared/src/test/diff/nu/TypeAliases.mls | 21 +++------- .../src/test/scala/mlscript/DiffTests.scala | 4 +- 8 files changed, 75 insertions(+), 82 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 0863b12c5e..f5103b1a86 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -267,7 +267,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D (TypeName("").withLoc(curLoc.map(_.left)), false) } val tparams = yeetSpaces match { - case (br @ BRACKETS(Angle, toks), loc) :: _ => + case (br @ BRACKETS(Angle | Square, toks), loc) :: _ => consume val ts = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()).map { case (N, Fld(false, false, v @ Var(nme))) => @@ -319,7 +319,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } foundErr || !success pipe { implicit fe => val tparams = if (kwStr === "let") Ls[TypeName]() else yeetSpaces match { - case (br @ BRACKETS(Angle, toks), loc) :: _ => + case (br @ BRACKETS(Angle | Square, toks), loc) :: _ => consume val ts = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()).map { case (N, Fld(false, false, v @ Var(nme))) => @@ -665,7 +665,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case R(res) => exprCont(res, 0, allowNewlines) } - case (br @ BRACKETS(Angle, toks), loc) :: _ => + case (br @ BRACKETS(Angle | Square, toks), loc) :: _ => consume val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // val res = TyApp(acc, as.map(_.mapSecond.to)) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 9695ae1cdf..63cb22a724 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -9,7 +9,7 @@ class Lit(n: int) //│ class Lit(n: int) fun add11 = Add(Lit(1), Lit(2)) -//│ fun add11: Add +//│ fun add11: Add[Lit] // add11 + 1 @@ -22,7 +22,7 @@ fun eval(e) = Add(l, r) then eval(l) + eval(r) //│ fun eval: 'a -> int //│ where -//│ 'a <: Add<'a> | Lit +//│ 'a <: Add['a] | Lit mixin EvalBase { @@ -33,7 +33,7 @@ mixin EvalBase { } //│ mixin EvalBase() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add<'lhs> | Lit) -> int +//│ fun eval: (Add['lhs] | Lit) -> int //│ } @@ -42,12 +42,12 @@ module TestLang: EvalBase //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add<'a> | Lit +//│ 'a <: Add['a] | Lit TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add<'a> | Lit +//│ 'a <: Add['a] | Lit TestLang.eval(add11) //│ int @@ -70,18 +70,18 @@ module TestLang: EvalNothing, EvalAddLit //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add<'lhs> | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) //│ } //│ module TestLang() { //│ fun eval: 'c -> int //│ } //│ where -//│ 'c <: Add<'c> | Lit +//│ 'c <: Add['c] | Lit TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add<'a> | Lit +//│ 'a <: Add['a] | Lit TestLang.eval(add11) //│ int @@ -91,7 +91,7 @@ class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: Add>> +//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] mixin EvalNeg { @@ -102,7 +102,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg<'expr> | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } @@ -111,12 +111,12 @@ module TestLang: EvalBase, EvalNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add<'a> | Lit | Neg<'a> +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add<'a> | Lit | Neg<'a> +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval(add11) @@ -147,9 +147,9 @@ mixin EvalNegNeg { else super.eval(e) } //│ mixin EvalNegNeg() { -//│ super: {eval: (Neg<'A> | 'a) -> 'b} +//│ super: {eval: (Neg['A] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg<'A & (~Neg | Neg<'expr>)> | 'a & ~Neg) -> 'b +//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } module TestLang: EvalBase, EvalNeg, EvalNegNeg @@ -157,7 +157,7 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add<'a> | Lit | Neg<'A & (~Neg | Neg<'a>)> +//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] //│ 'A <: 'a fun mk(n) = if n is @@ -166,12 +166,12 @@ fun mk(n) = if n is _ then Add(mk(n), mk(n)) //│ fun mk: number -> 'E //│ where -//│ 'E :> Add<'E> | Lit | Neg<'E> +//│ 'E :> Add['E] | Lit | Neg['E] TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add<'a> | Lit | Neg<'A & (~Neg | Neg<'a>)> +//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] //│ 'A <: 'a TestLang.eval(mk(0)) diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index 1806a98b53..ba1fddfc6f 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -8,7 +8,7 @@ class Add(lhs: E, rhs: E) //│ class Add[E](lhs: E, rhs: E) let e = Add(1, 1) -//│ let e: Add<1> +//│ let e: Add[1] :d e @@ -19,7 +19,7 @@ e //│ res: Some(α30) where //│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) //│ E23_31 :> 1 -//│ Add<1> +//│ Add[1] e.lhs //│ 1 @@ -34,10 +34,10 @@ e //│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) <: {lhs: lhs36} //│ E23_31 :> 1 <: lhs36 //│ lhs36 :> 1 -//│ Add<1> +//│ Add[1] Add(2, 2) -//│ Add<2> +//│ Add[2] diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 6adfbf5db7..68626f554d 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -9,7 +9,7 @@ class Lit(value: int) //│ class Lit(value: int) let add11 = Add(Lit(1), Lit(2)) -//│ let add11: Add +//│ let add11: Add[Lit] fun eval(e) = if e is @@ -17,7 +17,7 @@ fun eval(e) = Add(l, r) then eval(l) + eval(r) //│ fun eval: 'a -> int //│ where -//│ 'a <: Add<'a> | Lit +//│ 'a <: Add['a] | Lit mixin EvalLit { @@ -44,7 +44,7 @@ mixin EvalAdd { } //│ mixin EvalAdd() { //│ this: {eval: 'lhs -> 'a} -//│ fun eval: Add<'lhs> -> 'a +//│ fun eval: Add['lhs] -> 'a //│ } // FIXME type vars are wrongly refreshed when tying the knot @@ -54,12 +54,12 @@ module TestLang: EvalAdd //│ fun eval: 'a -> nothing //│ } //│ where -//│ 'a <: Add<'a> +//│ 'a <: Add['a] TestLang.eval //│ 'a -> nothing //│ where -//│ 'a <: Add<'a> +//│ 'a <: Add['a] @@ -71,7 +71,7 @@ mixin EvalBase { } //│ mixin EvalBase() { //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add<'lhs> | Lit) -> int +//│ fun eval: (Add['lhs] | Lit) -> int //│ } @@ -80,29 +80,29 @@ module TestLang: EvalBase //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add<'a> | Lit +//│ 'a <: Add['a] | Lit TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add<'a> | Lit +//│ 'a <: Add['a] | Lit add11 -//│ Add +//│ Add[Lit] TestLang.eval(add11) //│ int add11 -//│ Add +//│ Add[Lit] TestLang.eval(add11) //│ int add11 -//│ Add +//│ Add[Lit] @@ -110,7 +110,7 @@ class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add2negadd11: Add>> +//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] mixin EvalNeg { @@ -121,7 +121,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg<'expr> | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } @@ -130,12 +130,12 @@ module TestLang: EvalBase, EvalNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add<'a> | Lit | Neg<'a> +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add<'a> | Lit | Neg<'a> +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/ECOOP23_small.mls b/shared/src/test/diff/nu/ECOOP23_small.mls index 64ed68014c..cc1b520841 100644 --- a/shared/src/test/diff/nu/ECOOP23_small.mls +++ b/shared/src/test/diff/nu/ECOOP23_small.mls @@ -3,8 +3,8 @@ :NoJS -class Neg(expr: A) -class Add(lhs: E, rhs: E) +class Neg[A](expr: A) +class Add[E](lhs: E, rhs: E) class Lit(n: int) //│ class Neg[A](expr: A) //│ class Add[E](lhs: E, rhs: E) @@ -12,8 +12,8 @@ class Lit(n: int) let add11 = Add(Lit(1), Lit(2)) let add2negadd11 = Add(Lit(2), Neg(add11)) -//│ let add11: Add -//│ let add2negadd11: Add>> +//│ let add11: Add[Lit] +//│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] mixin EvalNothing { fun eval(e: nothing) = e @@ -36,12 +36,12 @@ mixin EvalNeg { //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add<'lhs> | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) //│ } //│ mixin EvalNeg() { //│ super: {eval: 'c -> 'd} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg<'expr> | 'c & ~Neg) -> (int | 'd) +//│ fun eval: (Neg['expr] | 'c & ~Neg) -> (int | 'd) //│ } module TestLang: EvalNothing, EvalAddLit, EvalNeg @@ -49,11 +49,11 @@ module TestLang: EvalNothing, EvalAddLit, EvalNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add<'a> | Lit | Neg<'a> +//│ 'a <: Add['a] | Lit | Neg['a] TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add<'a> | Lit | Neg<'a> +//│ 'a <: Add['a] | Lit | Neg['a] diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 1483e37ebd..b2ce246c01 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -7,7 +7,7 @@ class C //│ class C[A]() fun f(x) = if x is C then x -//│ fun f: C<'A> -> C<'A> +//│ fun f: C['A] -> C['A] // :d @@ -15,10 +15,10 @@ class C(a: A) //│ class C[A](a: A) fun f(x) = if x is C(a) then a -//│ fun f: C<'a> -> 'a +//│ fun f: C['a] -> 'a let c = C(1) -//│ let c: C<1> +//│ let c: C[1] f(c) //│ 1 @@ -37,7 +37,7 @@ class Some(value: A) { let s = Some(1) -//│ let s: Some<1> +//│ let s: Some[1] s.value @@ -85,10 +85,10 @@ type Option = Some | None let opt = if true then Some(123) else None -//│ let opt: None | Some<123> +//│ let opt: None | Some[123] opt.toArray -//│ Array<123> +//│ Array[123] // TODO @@ -109,13 +109,13 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: (None | Some<'value>, 'value -> 'A,) -> (None | Some<'A>) +//│ fun map: (None | Some['value], 'value -> 'A,) -> (None | Some['A]) let mo = map(opt, succ) -//│ let mo: None | Some +//│ let mo: None | Some[int] mo.toArray -//│ Array +//│ Array[int] @@ -158,10 +158,10 @@ class Test(n: A) { //│ } Test(1) -//│ Test<1> +//│ Test[1] Test(true) -//│ Test +//│ Test[true] class Test(n: A) { @@ -176,7 +176,7 @@ class Test(n: A) { //│ } Test(1) -//│ Test<1> +//│ Test[1] Test(1).foo //│ 1 @@ -185,13 +185,13 @@ Test("ok").foo //│ "ok" let t = Test(1) -//│ let t: Test<1> +//│ let t: Test[1] t.foo1(true) //│ 1 | true t : Test<'a> -//│ Test<'a> +//│ Test['a] //│ where //│ 'a :> 1 | true @@ -232,7 +232,7 @@ x => TestBad().foo1(x) // :d let t = TestBad() -//│ let t: forall 'A. TestBad<'A> +//│ let t: forall 'A. TestBad['A] t.foo1 //│ (x: 'A,) -> 'A @@ -244,11 +244,11 @@ t.foo1(0) //│ 0 t -//│ forall 'A. TestBad<'A> +//│ forall 'A. TestBad['A] fun foo(x: TestBad) = x.foo1 -//│ fun foo: (x: TestBad,) -> (x: int,) -> int +//│ fun foo: (x: TestBad[int],) -> (x: int,) -> int foo(t) //│ (x: int,) -> int @@ -263,13 +263,13 @@ TestBad().foo2 class Weird(x: C<'a>) -//│ class Weird(x: C<'a>) +//│ class Weird(x: C['a]) let w = Weird(c) //│ let w: Weird w.x -//│ C<'a> +//│ C['a] // FIXME not(w.x.a) diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index 25bbcdb5c6..fc560405b1 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -8,28 +8,22 @@ class CI1 //│ CI1: () -> CI1 //│ = [Function: CI11] -:e +// :e type AI1 = Array[int] -//│ ╔══[ERROR] not a recognized type: (Array)[int] -//│ ║ l.12: type AI1 = Array[int] -//│ ╙── ^^^^^^^^^^ //│ Defined type alias AI1 type AI2 = Array //│ Defined type alias AI2 // TODO fail gracefully -:e +// :e type AI3(n) = Array[int] //│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: List((None,Fld(false,false,n))) // TODO fail gracefully -:e +// :e type AI3[A] = Array -//│ ╔══[PARSE ERROR] Expected end of input; found square bracket section instead -//│ ║ l.28: type AI3[A] = Array -//│ ╙── ^^^ -//│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: List() +//│ Defined type alias AI3[+A] type AI4 = Array //│ Defined type alias AI4[+A] @@ -54,12 +48,9 @@ a : AI2 //│ res: AI2 //│ = [ 123, 123, 123 ] -:e +// :e a : AI3[int] -//│ ╔══[ERROR] not a recognized type: (AI3)[int] -//│ ║ l.58: a : AI3[int] -//│ ╙── ^^^^^^^^ -//│ res: anything +//│ res: AI3[int] //│ = [ 123, 123, 123 ] a : AI4 diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index f6a848efc6..32931726a6 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -572,7 +572,9 @@ class DiffTests val exp = typer.expandType(sim)(ctx) val expStr = - exp.showIn(ShowCtx.mk(exp :: Nil).copy(newDefs = true), 0) + exp.showIn(ShowCtx.mk(exp :: Nil) + // .copy(newDefs = true) // TODO later + , 0) output(expStr.stripSuffix("\n")) From 4f15e808b3c0f7171d64e177cb156e4f829ad51c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 12:45:26 +0800 Subject: [PATCH 077/498] WIP Support generic methods and `let rec` --- .../src/main/scala/mlscript/NewParser.scala | 11 +- shared/src/main/scala/mlscript/Typer.scala | 8 +- .../main/scala/mlscript/TyperDatatypes.scala | 33 +++++- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/nu/GenericMethods.mls | 105 ++++++++++++++++++ shared/src/test/diff/nu/LetRec.mls | 66 +++-------- shared/src/test/diff/parser/Arrays.mls | 7 +- shared/src/test/diff/parser/BasicSyntax.mls | 60 +++++----- shared/src/test/diff/parser/Subscripts.mls | 28 ++--- shared/src/test/diff/parser/TypeParams.mls | 7 +- 10 files changed, 208 insertions(+), 119 deletions(-) create mode 100644 shared/src/test/diff/nu/GenericMethods.mls diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index f5103b1a86..40666afdad 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -441,13 +441,18 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D consume val as = argsMaybeIndented() skip(KEYWORD(";")) + // yeetSpaces match { + // case (KEYWORD(";" | "."), _) :: _ => + // consume + // case _ => ??? + // } val e = expr(0) R(Forall(as.flatMap { // case S(Var(nme)) -> Fld(false, false, trm) => case N -> Fld(false, false, v: Var) => TypeVar(R(v.name), N).withLocOf(v) :: Nil case v -> f => - err(msg"illegal `forall` quantifiee" -> f.value.toLoc :: Nil) + err(msg"illegal `forall` quantifier body" -> f.value.toLoc :: Nil) Nil }, e)) case (KEYWORD("let"), l0) :: _ => @@ -675,10 +680,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case R(ty) => ty } case _ => ??? - }) + }).withLoc(acc.toLoc.fold(some(loc))(_ ++ loc |> some)) exprCont(res, prec, allowNewlines) - case (br @ BRACKETS(Square, toks), loc) :: _ => + case (br @ BRACKETS(Square, toks), loc) :: _ => // * Currently unreachable because we match Square brackets as tparams consume val idx = rec(toks, S(br.innerLoc), "subscript").concludeWith(_.expr(0)) val res = Subs(acc, idx.withLoc(S(loc))) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index e360ee141a..87ee6b5749 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -950,8 +950,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case _ => mthCallOrSel(obj, fieldName) } case Let(isrec, nme, rhs, bod) => - if (newDefs) { - if (isrec) ??? + if (newDefs && !isrec) { + // if (isrec) ??? val rhs_ty = typeTerm(rhs) val newCtx = ctx.nest newCtx += nme.name -> VarSymbol(rhs_ty, nme) @@ -1015,7 +1015,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case New(S((nmedTy, trm)), TypingUnit(Nil)) => typeMonomorphicTerm(App(Var(nmedTy.base.name).withLocOf(nmedTy), trm)) case New(base, args) => ??? - case TyApp(_, _) => ??? // TODO handle + case TyApp(_, _) => + // ??? // TODO handle + err(msg"Type application syntax is not yet supported", term.toLoc) case Where(bod, sts) => typeTerms(sts :+ bod, false, Nil, allowPure = true) case Forall(vs, bod) => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 4288772cac..422e652f3d 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -83,13 +83,22 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case fd: NuFunDef => // assert(fd.isLetRec.isEmpty, fd.isLetRec) implicit val prov: TP = noProv // TODO + def checkNoTyParams() = + if (fd.tparams.nonEmpty) + err(msg"Type parameters here are not yet supported in this position", + fd.tparams.head.toLoc) val res_ty = fd.rhs match { case R(PolyType(tps, ty)) => + checkNoTyParams() // val body_ty = typeType(ty)(ctx.nextLevel, raise, // vars = tps.map(tp => tp.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) - val body_ty = ctx.nextLevel { implicit ctx: Ctx => // TODO use poly instead! + val body_ty = + // ctx.nextLevel { implicit ctx: Ctx => + // // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods + // // * in the current typing unit are quantified together. + ctx.poly { implicit ctx: Ctx => typeType(ty)(ctx, raise, - vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) + vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) } // TODO check against `tv` TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) @@ -98,8 +107,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // implicit val vars: Map[Str, SimpleType] = // outerVars ++ Map.empty // TODO tparams fd.isLetRec match { - case S(true) => ??? - case S(false) => + case S(true) => // * Let rec bindings + checkNoTyParams() + implicit val gl: GenLambdas = true + TypedNuFun(ctx.lvl, fd, typeTerm( + Let(true, fd.nme, body, fd.nme) + )) + case S(false) => // * Let bindings + checkNoTyParams() implicit val gl: GenLambdas = true TypedNuFun(ctx.lvl, fd, typeTerm(body)) case N => @@ -118,7 +133,15 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // * and polymorphically wrt to non-recursive users of them. implicit val gl: GenLambdas = false val body_ty = ctx.nextLevel { implicit ctx: Ctx => - typeTerm(body) + // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods + // * in the current typing unit are quantified together. + vars ++ fd.tparams.map { tn => + tn.name -> freshVar(TypeProvenance(tn.toLoc, "method type parameter", + originName = S(tn.name), + isType = true), N) + } |> { implicit vars => + typeTerm(body) + } } TypedNuFun(ctx.lvl, fd, body_ty) } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index c2cfae297f..a4ea490580 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -186,7 +186,7 @@ final case class NuTypeDef( final case class NuFunDef( isLetRec: Opt[Bool], // None means it's a `fun`, which is always recursive; Some means it's a `let` nme: Var, - targs: Ls[TypeName], + tparams: Ls[TypeName], // rhs: Term \/ PolyType, rhs: Term \/ Type, ) extends NuDecl with DesugaredStatement { diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls new file mode 100644 index 0000000000..3327c6d5ab --- /dev/null +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -0,0 +1,105 @@ +:NewParser +:NewDefs +:NoJS + + +fun foo1 = forall 'A; (x: 'A) => x +//│ fun foo1: forall 'A. (x: 'A,) -> 'A + +foo1(42) +//│ 42 + +:e +foo1[int](42) +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.13: foo1[int](42) +//│ ╙── ^^^^^^^^^ +//│ error + + +fun foo2(x: A) = x +//│ fun foo2: (x: 'a,) -> 'a + +foo2(42) +//│ 42 + +:e +foo2(42) +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.27: foo2(42) +//│ ╙── ^^^^^^^^^ +//│ error + + +fun foo3[A](x: A) = x +//│ fun foo3: (x: 'a,) -> 'a + +foo3(42) +//│ 42 + +:e +foo3[int](42) +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.41: foo3[int](42) +//│ ╙── ^^^^^^^^^ +//│ error + + +fun bar: forall 'A; 'A => 'A +//│ fun bar: forall 'A. 'A -> 'A + +:e +fun bar : A => A +//│ ╔══[ERROR] Type parameters here are not yet supported in this position +//│ ║ l.52: fun bar : A => A +//│ ╙── ^ +//│ ╔══[ERROR] type identifier not found: A +//│ ║ l.52: fun bar : A => A +//│ ╙── ^ +//│ ╔══[ERROR] type identifier not found: A +//│ ║ l.52: fun bar : A => A +//│ ╙── ^ +//│ fun bar: error -> error + +:pe +:e +:w +fun bar: A => A +//│ ╔══[PARSE ERROR] Unmatched opening angle bracket +//│ ║ l.67: fun bar: A => A +//│ ║ ^ +//│ ╙── Note that `<` without spaces around it is considered as an angle bracket and not as an operator +//│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position +//│ ║ l.67: fun bar: A => A +//│ ╙── ^^^ +//│ ╔══[WARNING] Paren-less applications should use the 'of' keyword +//│ ║ l.67: fun bar: A => A +//│ ╙── ^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Unsupported pattern shape: +//│ ║ l.67: fun bar: A => A +//│ ╙── ^^^^^ +//│ ╔══[ERROR] identifier not found: A +//│ ║ l.67: fun bar: A => A +//│ ╙── ^ +//│ error -> error + + +module Test { + fun foo: 'A => 'A + fun bar: 'A + fun test(x: A) = x +} +//│ module Test() { +//│ fun bar: nothing +//│ fun foo: forall 'A. 'A -> 'A +//│ fun test: (x: 'a,) -> 'a +//│ } + +class Test(n: A) { + fun test(x: A) = [x, n] +} +//│ class Test[A](n: A) { +//│ fun test: (x: 'a,) -> ('a, A,) +//│ } + + diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index a1ca2c44a9..e086659b48 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -1,83 +1,49 @@ :NewParser +:NewDefs +:NoJS // TODO rm + :js fun f(x) = x > 0 && f(x - 1) -//│ // Prelude -//│ let res; -//│ // Query 1 -//│ globalThis.f = function f(x) { -//│ return x > 0 && f(x - 1); -//│ }; -//│ // End of generated code -//│ f: int -> bool -//│ = [Function: f] +//│ fun f: int -> bool f(12) -//│ res: bool -//│ = false +//│ bool :js let rec f(x) = x > 0 && f(x - 1) -//│ // Query 1 -//│ globalThis.f1 = function f1(x) { -//│ return x > 0 && f1(x - 1); -//│ }; -//│ // End of generated code -//│ f: int -> bool -//│ = [Function: f1] +//│ let rec f: int -> bool f(12) -//│ res: bool -//│ = false +//│ bool :js let rec f() = f() -//│ // Query 1 -//│ globalThis.f2 = function f2() { -//│ return ((() => { -//│ return f2(); -//│ })()); -//│ }; -//│ // End of generated code -//│ f: () -> nothing -//│ = [Function: f2] +//│ let rec f: () -> nothing -:re +// :re f() -//│ res: nothing -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ nothing // TODO (for later) this should be rejected by the type checker -:ge +// :ge :js let rec f = f -//│ f: nothing -//│ Code generation encountered an error: -//│ unguarded recursive use of by-value binding f +//│ let rec f: nothing -:re +// :re :js f -//│ // Query 1 -//│ res = f3; -//│ // End of generated code -//│ res: nothing -//│ Runtime error: -//│ ReferenceError: f3 is not defined +//│ nothing :p let rec f = 1 //│ |#let| |#rec| |f| |#=| |1| //│ Parsed: let rec f = 1; -//│ Desugared: rec def f: 1 -//│ AST: Def(true, f, IntLit(1), false) -//│ f: 1 -//│ = 1 +//│ let rec f: 1 let rec f = 1 -//│ f: 1 -//│ = 1 +//│ let rec f: 1 diff --git a/shared/src/test/diff/parser/Arrays.mls b/shared/src/test/diff/parser/Arrays.mls index 3b297fb2df..cd209a30ca 100644 --- a/shared/src/test/diff/parser/Arrays.mls +++ b/shared/src/test/diff/parser/Arrays.mls @@ -108,13 +108,10 @@ let arr = [ //│ |#let| |arr| |#=| |[|→|1|,|↵|2|←|↵|]| //│ Parsed: {let arr = '(' 1, 2, ')'} -:pe +// :pe f [1, 2, 3] //│ |f| |[|1|,| |2|,| |3|]| -//│ ╔══[PARSE ERROR] Unexpected comma here -//│ ║ l.112: f [1, 2, 3] -//│ ╙── ^ -//│ Parsed: {(f)[1]} +//│ Parsed: {f‹1, 2, 3›} f([1, 2, 3]) //│ |f|(|[|1|,| |2|,| |3|]|)| diff --git a/shared/src/test/diff/parser/BasicSyntax.mls b/shared/src/test/diff/parser/BasicSyntax.mls index 766c419518..49c44cc2dc 100644 --- a/shared/src/test/diff/parser/BasicSyntax.mls +++ b/shared/src/test/diff/parser/BasicSyntax.mls @@ -301,43 +301,37 @@ f(1, 2, 3) //│ |f|(|1|,| |2|,| |3|)| //│ Parsed: {f (1, 2, 3,)} -:pe +// :pe f[] //│ |f|[||]| -//│ ╔══[PARSE ERROR] Unexpected end of subscript; an expression was expected here -//│ ║ l.305: f[] -//│ ╙── ^ -//│ Parsed: {(f)[undefined]} +//│ Parsed: {f‹›} f[1] //│ |f|[|1|]| -//│ Parsed: {(f)[1]} +//│ Parsed: {f‹1›} f[1, 2, 3] //│ |f|[|1|,| |2|,| |3|]| -//│ ╔══[PARSE ERROR] Unexpected comma here -//│ ║ l.316: f[1, 2, 3] -//│ ╙── ^ -//│ Parsed: {(f)[1]} +//│ Parsed: {f‹1, 2, 3›} f{} //│ |f|{||}| //│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.323: f{} +//│ ║ l.317: f{} //│ ╙── ^^ //│ Parsed: {f} f{1} //│ |f|{|1|}| //│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.330: f{1} +//│ ║ l.324: f{1} //│ ╙── ^^^ //│ Parsed: {f} f{1, 2, 3} //│ |f|{|1|,| |2|,| |3|}| //│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.337: f{1, 2, 3} +//│ ║ l.331: f{1, 2, 3} //│ ╙── ^^^^^^^^^ //│ Parsed: {f} @@ -345,10 +339,10 @@ f{1, 2, 3} f 1,, 2 //│ |f| |1|,|,| |2| //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.345: f 1,, 2 +//│ ║ l.339: f 1,, 2 //│ ╙── ^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.345: f 1,, 2 +//│ ║ l.339: f 1,, 2 //│ ╙── ^^^^^^^ //│ Parsed: {f (1, 2,)} @@ -360,10 +354,10 @@ f of x f g x //│ |f| |g| |x| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.360: f g x +//│ ║ l.354: f g x //│ ╙── ^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.360: f g x +//│ ║ l.354: f g x //│ ╙── ^^^^^ //│ Parsed: {f (g (x,),)} @@ -374,7 +368,7 @@ f of g of x f of of g //│ |f| |#of| |#of| |g| //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position -//│ ║ l.374: f of of g +//│ ║ l.368: f of of g //│ ╙── ^^ //│ Parsed: {f (g,)} @@ -382,52 +376,52 @@ f of of g f x: 1 //│ |f| |x|#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.382: f x: 1 +//│ ║ l.376: f x: 1 //│ ╙── ^^^^^^ //│ Parsed: {f (x: 1,)} f x: 1, //│ |f| |x|#:| |1|,| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.389: f x: 1, +//│ ║ l.383: f x: 1, //│ ╙── ^^^^^^ //│ Parsed: {f (x: 1,)} f x : 1 //│ |f| |x| |#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.396: f x : 1 +//│ ║ l.390: f x : 1 //│ ╙── ^^^ //│ Parsed: {f (x : 1,)} f x: 1, y: 2 //│ |f| |x|#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.403: f x: 1, y: 2 +//│ ║ l.397: f x: 1, y: 2 //│ ╙── ^^^^^^^^^^^^ //│ Parsed: {f (x: 1, y: 2,)} f x : 1, y: 2 //│ |f| |x| |#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.410: f x : 1, y: 2 +//│ ║ l.404: f x : 1, y: 2 //│ ╙── ^^^^^^^^^^^^^ //│ Parsed: {f (x : 1, y: 2,)} f x: 1, y: 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.417: f x: 1, y: 2, z: 3 +//│ ║ l.411: f x: 1, y: 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ Parsed: {f (x: 1, y: 2, z: 3,)} f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.424: f x: 1, y: g 2, z: 3 +//│ ║ l.418: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.424: f x: 1, y: g 2, z: 3 +//│ ║ l.418: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f (x: 1, y: g (2, z: 3,),)} @@ -442,10 +436,10 @@ f(x: 1, y: g(2), z: 3) f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.442: f x: 1, y: g 2, z: 3 +//│ ║ l.436: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.442: f x: 1, y: g 2, z: 3 +//│ ║ l.436: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f (x: 1, y: g (2, z: 3,),)} @@ -456,13 +450,13 @@ f of x: 1, y: g of 2, z: 3 f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ |f| |x|#:| |1| |+| |1|,| |y|#:| |2| |2|,| |z|#:| |3| |+| |2| |4| |-| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.456: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.450: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.456: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.450: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.456: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.450: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f (x: + (1,) (1,), y: 2 (2, z: + (3,) (2 (- (4,) (1,),),),),)} @@ -474,10 +468,10 @@ x.y .y //│ |.y| //│ ╔══[PARSE ERROR] Unexpected selector in expression position -//│ ║ l.474: .y +//│ ║ l.468: .y //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.474: .y +//│ ║ l.468: .y //│ ╙── ^ //│ Parsed: {undefined} diff --git a/shared/src/test/diff/parser/Subscripts.mls b/shared/src/test/diff/parser/Subscripts.mls index 3adeb01ad9..2ab3b1bee5 100644 --- a/shared/src/test/diff/parser/Subscripts.mls +++ b/shared/src/test/diff/parser/Subscripts.mls @@ -1,66 +1,66 @@ a[0] //│ |a|[|0|]| -//│ Parsed: {(a)[0]} +//│ Parsed: {a‹0›} a[0][1] //│ |a|[|0|]|[|1|]| -//│ Parsed: {((a)[0])[1]} +//│ Parsed: {a‹0›‹1›} a.x[0].y[1].z //│ |a|.x|[|0|]|.y|[|1|]|.z| -//│ Parsed: {(((((a).x)[0]).y)[1]).z} +//│ Parsed: {(((a).x‹0›).y‹1›).z} a + b [0] * 2 //│ |a| |+| |b| |[|0|]| |*| |2| -//│ Parsed: {+ (a,) (* ((b)[0],) (2,),)} +//│ Parsed: {+ (a,) (* (b‹0›,) (2,),)} foo [1] //│ |foo|→|[|1|]|←| -//│ Parsed: {(foo)[1]} +//│ Parsed: {foo‹1›} Foo(bar) + 1 ["hello"] //│ |Foo|(|bar|)| |+| |1|→|[|"hello"|]|←| -//│ Parsed: {(+ (Foo (bar,),) (1,))["hello"]} +//│ Parsed: {+ (Foo (bar,),) (1,)‹"hello"›} Foo(bar) + 1["hello"] //│ |Foo|(|bar|)| |+|→|1|[|"hello"|]|←| -//│ Parsed: {+ (Foo (bar,),) ({(1)["hello"]},)} +//│ Parsed: {+ (Foo (bar,),) ({1‹"hello"›},)} Foo(bar) + 1 ["hello"] //│ |Foo|(|bar|)| |+|→|1|→|[|"hello"|]|←|←| -//│ Parsed: {+ (Foo (bar,),) ({(1)["hello"]},)} +//│ Parsed: {+ (Foo (bar,),) ({1‹"hello"›},)} Foo(bar) + 1 [1] [2] //│ |Foo|(|bar|)| |+| |1|→|[|1|]|↵|[|2|]|←| -//│ Parsed: {((+ (Foo (bar,),) (1,))[1])[2]} +//│ Parsed: {+ (Foo (bar,),) (1,)‹1›‹2›} Foo(bar) + 1 [1] [2] //│ |Foo|(|bar|)| |+| |1|→|[|1|]|→|[|2|]|←|←| -//│ Parsed: {((+ (Foo (bar,),) (1,))[1])[2]} +//│ Parsed: {+ (Foo (bar,),) (1,)‹1›‹2›} a + 111 [22] [333] //│ |a| |+|→|111|→|[|22|]|←|↵|[|333|]|←| -//│ Parsed: {+ (a,) ({(111)[22]; '(' 333, ')'},)} +//│ Parsed: {+ (a,) ({111‹22›; '(' 333, ')'},)} Foo(bar) + 1 [1] [2] //│ |Foo|(|bar|)| |+|→|1|→|[|1|]|←|↵|[|2|]|←| -//│ Parsed: {+ (Foo (bar,),) ({(1)[1]; '(' 2, ')'},)} +//│ Parsed: {+ (Foo (bar,),) ({1‹1›; '(' 2, ')'},)} a of [333] //│ |a| |#of| |[|333|]| @@ -76,7 +76,7 @@ a of [22] [333] //│ |a| |#of|→|111|→|[|22|]|←|↵|[|333|]|←| -//│ Parsed: {a ({(111)[22]; '(' 333, ')'},)} +//│ Parsed: {a ({111‹22›; '(' 333, ')'},)} a( 111 @@ -84,5 +84,5 @@ a( [333] ) //│ |a|(|→|111|→|[|22|]|←|↵|[|333|]|←|↵|)| -//│ Parsed: {a ({(111)[22]; '(' 333, ')'},)} +//│ Parsed: {a ({111‹22›; '(' 333, ')'},)} diff --git a/shared/src/test/diff/parser/TypeParams.mls b/shared/src/test/diff/parser/TypeParams.mls index 5d8c02b609..d0d2c1f1f8 100644 --- a/shared/src/test/diff/parser/TypeParams.mls +++ b/shared/src/test/diff/parser/TypeParams.mls @@ -107,13 +107,10 @@ foo(2 + 3) & Bar("ok") //│ |foo|‹|Str|,| |Int|›|(|2| |+| |3|)| |&| |Bar|‹|MyClass|›|(|"ok"|)| //│ Parsed: {& (foo‹Str, Int› (+ (2,) (3,),),) (Bar‹MyClass› ("ok",),)} -:pe +// :pe foo[S, T](1, 2, 3) & Bar[U]("ok") //│ |foo|[|S|,| |T|]|(|1|,| |2|,| |3|)| |&| |Bar|[|U|]|(|"ok"|)| -//│ ╔══[PARSE ERROR] Unexpected comma here -//│ ║ l.111: foo[S, T](1, 2, 3) & Bar[U]("ok") -//│ ╙── ^ -//│ Parsed: {& ((foo)[S] (1, 2, 3,),) ((Bar)[U] ("ok",),)} +//│ Parsed: {& (foo‹S, T› (1, 2, 3,),) (Bar‹U› ("ok",),)} class Foo {} //│ |#class| |Foo|‹|T|›| |{||}| From a5630e411b7e72c49e71528cda2959eeca27c567 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 13:14:34 +0800 Subject: [PATCH 078/498] WIP Test generic modules and fix subtle type simplification problem --- .../main/scala/mlscript/TypeSimplifier.scala | 22 +++++-- shared/src/test/diff/mlscript/With.mls | 2 +- shared/src/test/diff/nu/GenericModules.mls | 59 +++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 shared/src/test/diff/nu/GenericModules.mls diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 3d75ca558f..248926a763 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -952,9 +952,11 @@ trait TypeSimplifier { self: Typer => pol(tv) match { case S(p) if inlineBounds && !occursInvariantly(tv) && !recVars.contains(tv) => // * Inline the bounds of non-rec non-invar-occ type variables - println(s"Inlining bounds of $tv (~> $res)") + println(s"Inlining bounds of $tv (~> $res) ${printPol(p)}") + // if (p) mergeTransform(true, pol, tv, Set.single(tv), canDistribForall) | res + // else mergeTransform(false, pol.contravar, tv, Set.single(tv), canDistribForall) & res if (p) mergeTransform(true, pol, tv, Set.single(tv), canDistribForall) | res - else mergeTransform(false, pol.contravar, tv, Set.single(tv), canDistribForall) & res + else mergeTransform(false, pol, tv, Set.single(tv), canDistribForall) & res case _ if (!wasDefined) => def setBounds = { trace(s"Setting bounds of $res...") { @@ -1012,9 +1014,17 @@ trait TypeSimplifier { self: Typer => pol.base.fold[ST](TypeBounds.mk( transform(lb, PolMap.neg, parents, canDistribForall), transform(ub, PolMap.pos, parents, canDistribForall), + // transform(lb, pol, parents, canDistribForall), + // transform(ub, pol, parents, canDistribForall), + // transform(lb, pol.contravar, parents, canDistribForall), + // transform(ub, pol.covar, parents, canDistribForall), noProv - ))(pol => - if (pol) transform(ub, PolMap.pos, parents) else transform(lb, PolMap.neg, parents)) + ))(p => + // if (p) transform(ub, PolMap.pos, parents) else transform(lb, PolMap.neg, parents) + if (p) transform(ub, pol, parents) else transform(lb, pol, parents) + // if (p) transform(ub, pol.covar, parents) + // else transform(lb, pol.contravar, parents) + ) case PolymorphicType(plvl, bod) => val res = transform(bod, pol.enter(plvl), parents, canDistribForall = S(plvl)) canDistribForall match { @@ -1075,7 +1085,8 @@ trait TypeSimplifier { self: Typer => st.unwrapProvs match { case tv @ AssignedVariable(ty) => processed.setAndIfUnset(tv) { - tv.assignedTo = S(process(pol, ty, S(tv))) + // tv.assignedTo = S(process(pol, ty, S(tv))) // * WRONG! + tv.assignedTo = S(process(N, ty, S(tv))) } tv case tv: TV => @@ -1086,6 +1097,7 @@ trait TypeSimplifier { self: Typer => tv case _ => lazy val mapped = st.mapPol(pol, smart = true)(process(_, _, parent)) + // println(s"mapped $mapped") pol match { case S(p) => // println(s"!1! ${st} ${consed.get(p -> st)}") diff --git a/shared/src/test/diff/mlscript/With.mls b/shared/src/test/diff/mlscript/With.mls index 644ff2f887..45b330a5bb 100644 --- a/shared/src/test/diff/mlscript/With.mls +++ b/shared/src/test/diff/mlscript/With.mls @@ -116,7 +116,7 @@ def foo x = def foo x = let xf = x with { f = 42 } in { l = getf xf; r = getf x; s = x } -//│ foo: ('a & ({f: 'b}\f & {f: 'c} | ~{f: 42}\f & {f: 'c})) -> {l: 'b, r: 'c, s: 'a} +//│ foo: (({f: 'a} | ~{f: 42})\f & {f: 'b} & 'c) -> {l: 'a, r: 'b, s: 'c} //│ = [Function: foo2] :e diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls new file mode 100644 index 0000000000..6b4e276f2b --- /dev/null +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -0,0 +1,59 @@ +:NewParser +:NewDefs +:NoJS + + +module Test { + fun foo: A => A +} +//│ module Test[A]() { +//│ fun foo: A -> A +//│ } + +Test.foo +//│ nothing -> anything + +:e +Test.foo(1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.17: Test.foo(1) +//│ ║ ^^^^^^^^^^^ +//│ ╟── integer literal of type `1` does not match type `nothing` +//│ ║ l.17: Test.foo(1) +//│ ║ ^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.6: module Test { +//│ ╙── ^ +//│ anything + +:e +Test.foo(error) + 1 +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.30: Test.foo(error) + 1 +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `anything` is not an instance of type `int` +//│ ║ l.30: Test.foo(error) + 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ error | int + +:e +Test .foo +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.40: Test .foo +//│ ╙── ^^^^^^^^^ +//│ error + +:e +(Test).foo +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.47: (Test).foo +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.47: (Test).foo +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── receiver of type `{_1: error}` does not have field 'foo' +//│ ║ l.47: (Test).foo +//│ ╙── ^^^^^^^^^^^ +//│ error + + From 4593b4c419201622685198c922ea003f8f4ce08a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 13:25:41 +0800 Subject: [PATCH 079/498] WIP Improve class/module type param scope extrusion handling --- .../scala/mlscript/ConstraintSolver.scala | 12 +++++-- shared/src/test/diff/nu/GenericClasses.mls | 17 ++++++---- shared/src/test/diff/nu/GenericModules.mls | 32 +++++++++---------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 82a79910fa..79ddf630df 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -48,8 +48,16 @@ class ConstraintSolver extends NormalForms { self: Typer => case N => // FIXME type bounds are kind of wrong for this TypeBounds( - _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), - _tv.upperBounds.foldLeft(TopType: ST)(_ & _), + // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), + _tv.lowerBounds.foldLeft( + Extruded(false, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ | _), + _tv.upperBounds.foldLeft( + Extruded(true, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ & _), )(_tv.prov) } // println(s"Assigning ${_tv} ~> $tv := $targ where ${ diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index b2ce246c01..7771e49b93 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -9,6 +9,9 @@ class C fun f(x) = if x is C then x //│ fun f: C['A] -> C['A] +// * TODO parse class tags? +// f(C : #C) + // :d class C(a: A) @@ -125,7 +128,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.123: class Test(n) { +//│ ║ l.126: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -145,13 +148,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.145: fun foo = n + 1 +//│ ║ l.148: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.145: fun foo = n + 1 +//│ ║ l.148: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.144: class Test(n: A) { +//│ ║ l.147: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int @@ -208,13 +211,13 @@ class TestBad { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.208: fun foo2(x: A) = x + 1 +//│ ║ l.211: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.208: fun foo2(x: A) = x + 1 +//│ ║ l.211: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.206: class TestBad { +//│ ║ l.209: class TestBad { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 6b4e276f2b..3fd9e94b53 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -11,48 +11,46 @@ module Test { //│ } Test.foo -//│ nothing -> anything +//│ (??A & 'A) -> ('A | ??A0) :e Test.foo(1) -//│ ╔══[ERROR] Type mismatch in application: +//│ ╔══[ERROR] Type error in application //│ ║ l.17: Test.foo(1) //│ ║ ^^^^^^^^^^^ -//│ ╟── integer literal of type `1` does not match type `nothing` +//│ ╟── type variable `A` leaks out of its scope //│ ║ l.17: Test.foo(1) -//│ ║ ^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.6: module Test { -//│ ╙── ^ -//│ anything +//│ ╙── ^ +//│ error | ??A :e Test.foo(error) + 1 -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.30: Test.foo(error) + 1 +//│ ╔══[ERROR] Type error in operator application +//│ ║ l.27: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `anything` is not an instance of type `int` -//│ ║ l.30: Test.foo(error) + 1 -//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.27: Test.foo(error) + 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╙── into type `int` //│ error | int :e Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.40: Test .foo +//│ ║ l.38: Test .foo //│ ╙── ^^^^^^^^^ //│ error :e (Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.47: (Test).foo +//│ ║ l.45: (Test).foo //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.47: (Test).foo +//│ ║ l.45: (Test).foo //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── receiver of type `{_1: error}` does not have field 'foo' -//│ ║ l.47: (Test).foo +//│ ║ l.45: (Test).foo //│ ╙── ^^^^^^^^^^^ //│ error From fcfc914bd35fbf784af1629015e13a5828656335 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 13:37:30 +0800 Subject: [PATCH 080/498] WIP Don't parse simple parenthesized expressions as tuples --- .../src/main/scala/mlscript/NewParser.scala | 25 ++++++++++++------- .../test/diff/contys/ExplicitConstraints.mls | 6 ++--- shared/src/test/diff/nu/GenericModules.mls | 6 ----- shared/src/test/diff/nu/NuScratch.mls | 0 shared/src/test/diff/nu/Parens.mls | 18 ++++++------- shared/src/test/diff/parser/Arrays.mls | 4 +-- shared/src/test/diff/parser/BasicSyntax.mls | 4 +-- shared/src/test/diff/parser/Blocks.mls | 2 +- shared/src/test/diff/parser/Brackets.mls | 4 +-- shared/src/test/diff/parser/IfThenElse.mls | 4 +-- shared/src/test/diff/parser/Lambdas.mls | 8 +++--- shared/src/test/diff/parser/New.mls | 2 +- shared/src/test/diff/parser/TypeParams.mls | 2 +- 13 files changed, 43 insertions(+), 42 deletions(-) create mode 100644 shared/src/test/diff/nu/NuScratch.mls diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 40666afdad..4f6bedca6e 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -427,15 +427,22 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (br @ BRACKETS(bk @ (Round | Square | Curly), toks), loc) :: _ => consume val res = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO - val bra = if (bk === Curly) Bra(true, Rcd(res.map { - case S(n) -> fld => n -> fld - case N -> (fld @ Fld(_, _, v: Var)) => v -> fld - case N -> fld => - err(( - msg"Record field should have a name" -> fld.value.toLoc :: Nil)) - Var("") -> fld - })) - else Bra(false, Tup(res)) + val bra = (bk, res) match { + case (Curly, _) => + Bra(true, Rcd(res.map { + case S(n) -> fld => n -> fld + case N -> (fld @ Fld(_, _, v: Var)) => v -> fld + case N -> fld => + err(( + msg"Record field should have a name" -> fld.value.toLoc :: Nil)) + Var("") -> fld + })) + case (Round, (N, Fld(false, false, elt)) :: Nil) => + Bra(false, elt) + case _ => + // TODO actually reject round tuples? (except for function arg lists) + Bra(false, Tup(res)) + } exprCont(bra.withLoc(S(loc)), prec, allowNewlines = false) case (KEYWORD("forall"), l0) :: _ => consume diff --git a/shared/src/test/diff/contys/ExplicitConstraints.mls b/shared/src/test/diff/contys/ExplicitConstraints.mls index 25931ae7f9..995e5b321f 100644 --- a/shared/src/test/diff/contys/ExplicitConstraints.mls +++ b/shared/src/test/diff/contys/ExplicitConstraints.mls @@ -31,10 +31,10 @@ fun f: int => (int where int : string) //│ ╟── Note: constraint arises from type reference: //│ ║ l.24: fun f: int => (int where int : string) //│ ╙── ^^^^^^ -//│ f: int -> (int,) +//│ f: int -> int fun f: 'a => ('a where 'a : string) -//│ f: (string & 'a) -> ('a,) +//│ f: (string & 'a) -> 'a :e @@ -51,7 +51,7 @@ fun f: 'a => ('a where 'a : string) where int : 'a //│ ╟── from type variable: //│ ║ l.41: fun f: 'a => ('a where 'a : string) where int : 'a //│ ╙── ^^ -//│ f: (string & 'a) -> ('a | int,) +//│ f: (string & 'a) -> ('a | int) :e diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 3fd9e94b53..6d5ac347b9 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -46,12 +46,6 @@ Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.45: (Test).foo //│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.45: (Test).foo -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── receiver of type `{_1: error}` does not have field 'foo' -//│ ║ l.45: (Test).foo -//│ ╙── ^^^^^^^^^^^ //│ error diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared/src/test/diff/nu/Parens.mls b/shared/src/test/diff/nu/Parens.mls index d2fb018fad..9a3bfc8f6a 100644 --- a/shared/src/test/diff/nu/Parens.mls +++ b/shared/src/test/diff/nu/Parens.mls @@ -13,17 +13,17 @@ //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.9: (,) //│ ╙── ^ -//│ res: (undefined,) -//│ = [ undefined ] +//│ res: undefined +//│ = undefined // FIXME shouldn't parse like a 1-tuple... (1) -//│ res: (1,) -//│ = [ 1 ] +//│ res: 1 +//│ = 1 (1,) -//│ res: (1,) -//│ = [ 1 ] +//│ res: 1 +//│ = 1 (1, 2) //│ res: (1, 2,) @@ -46,15 +46,15 @@ let x: (,) //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.42: let x: (,) //│ ╙── ^ -//│ x: (undefined,) +//│ x: undefined //│ = let x: (1) -//│ x: (1,) +//│ x: 1 //│ = let x: (1,) -//│ x: (1,) +//│ x: 1 //│ = let x: (1, 2) diff --git a/shared/src/test/diff/parser/Arrays.mls b/shared/src/test/diff/parser/Arrays.mls index cd209a30ca..f117263646 100644 --- a/shared/src/test/diff/parser/Arrays.mls +++ b/shared/src/test/diff/parser/Arrays.mls @@ -23,11 +23,11 @@ (1) //│ |(|1|)| -//│ Parsed: {'(' 1, ')'} +//│ Parsed: {'(' 1 ')'} (1,) //│ |(|1|,|)| -//│ Parsed: {'(' 1, ')'} +//│ Parsed: {'(' 1 ')'} (1, 2, 3) //│ |(|1|,| |2|,| |3|)| diff --git a/shared/src/test/diff/parser/BasicSyntax.mls b/shared/src/test/diff/parser/BasicSyntax.mls index 49c44cc2dc..0eda5558c7 100644 --- a/shared/src/test/diff/parser/BasicSyntax.mls +++ b/shared/src/test/diff/parser/BasicSyntax.mls @@ -222,7 +222,7 @@ foo (1) //│ |(|1|)| -//│ Parsed: {'(' 1, ')'} +//│ Parsed: {'(' 1 ')'} (1 //│ ╔══[PARSE ERROR] Unmatched opening parenthesis @@ -236,7 +236,7 @@ foo //│ ║ l.234: (1)) //│ ╙── ^ //│ |(|1|)| -//│ Parsed: {'(' 1, ')'} +//│ Parsed: {'(' 1 ')'} ( //│ ╔══[PARSE ERROR] Unmatched opening parenthesis diff --git a/shared/src/test/diff/parser/Blocks.mls b/shared/src/test/diff/parser/Blocks.mls index 72be1cae4f..4da3f6eea1 100644 --- a/shared/src/test/diff/parser/Blocks.mls +++ b/shared/src/test/diff/parser/Blocks.mls @@ -161,6 +161,6 @@ fun foo = print of local of 0 + local of 1 fun tmp = 2 //│ |#fun| |foo| |#=|→|#fun| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| -//│ Parsed: {fun foo = {fun local = (x,) => {class Foo() {fun bar = + (x,) (1,)}; (Foo ()).bar}; print (+ (local (0,),) (local (1,),),); print (+ (local (0,),) (local (1,),),); fun tmp = 1; print (local (+ (0,) (local (1,),),),); fun tmp = 2}} +//│ Parsed: {fun foo = {fun local = (x,) => {class Foo() {fun bar = + (x,) (1,)}; (Foo ()).bar}; print (+ (local (0,),) (local (1,),),); print (+ ('(' local (0,) ')',) (local (1,),),); fun tmp = 1; print (local (+ (0,) (local (1,),),),); fun tmp = 2}} diff --git a/shared/src/test/diff/parser/Brackets.mls b/shared/src/test/diff/parser/Brackets.mls index 03264709ae..18f339b85c 100644 --- a/shared/src/test/diff/parser/Brackets.mls +++ b/shared/src/test/diff/parser/Brackets.mls @@ -24,7 +24,7 @@ (([{}])) //│ |(|(|[|{||}|]|)|)| -//│ Parsed: {'(' '(' '(' '{' {} '}', ')', ')', ')'} +//│ Parsed: {'(' '(' '(' '{' {} '}', ')' ')' ')'} :pe (([{})]) @@ -41,7 +41,7 @@ //│ ║ l.30: (([{})]) //│ ╙── ^ //│ |(|(|[|{||}|]|)|)| -//│ Parsed: {'(' '(' '(' '{' {} '}', ')', ')', ')'} +//│ Parsed: {'(' '(' '(' '{' {} '}', ')' ')' ')'} fun f = () diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 136efc2454..7b13482762 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -541,7 +541,7 @@ if true //│ ╟── Note: 'if' expression started here: //│ ║ l.536: (if true) //│ ╙── ^^ -//│ Parsed: {'(' if (true) then undefined, ')'} +//│ Parsed: {'(' if (true) then undefined ')'} :pe (if true then) @@ -549,7 +549,7 @@ if true //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.547: (if true then) //│ ╙── ^ -//│ Parsed: {'(' if (true) then undefined, ')'} +//│ Parsed: {'(' if (true) then undefined ')'} :pe if true then; diff --git a/shared/src/test/diff/parser/Lambdas.mls b/shared/src/test/diff/parser/Lambdas.mls index b868476532..cd5a95ff33 100644 --- a/shared/src/test/diff/parser/Lambdas.mls +++ b/shared/src/test/diff/parser/Lambdas.mls @@ -7,7 +7,7 @@ x => x (x) => x //│ |(|x|)| |=>| |x| -//│ Parsed: {(x,) => x} +//│ Parsed: {('(' x ')',) => x} // TODO fun x => x @@ -61,7 +61,7 @@ x => //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.59: (x =>) //│ ╙── ^ -//│ Parsed: {'(' (x,) => undefined, ')'} +//│ Parsed: {'(' (x,) => undefined ')'} a --> b --> c //│ |a| |-->| |b| |-->| |c| @@ -73,11 +73,11 @@ a => b => c (a => b) => c //│ |(|a| |=>| |b|)| |=>| |c| -//│ Parsed: {((a,) => b,) => c} +//│ Parsed: {('(' (a,) => b ')',) => c} a => (b => c) //│ |a| |=>| |(|b| |=>| |c|)| -//│ Parsed: {(a,) => '(' (b,) => c, ')'} +//│ Parsed: {(a,) => '(' (b,) => c ')'} xs.forall(x => x > 0) //│ |xs|.forall|(|x| |=>| |x| |>| |0|)| diff --git a/shared/src/test/diff/parser/New.mls b/shared/src/test/diff/parser/New.mls index cd4c5b540b..249164a5f3 100644 --- a/shared/src/test/diff/parser/New.mls +++ b/shared/src/test/diff/parser/New.mls @@ -14,7 +14,7 @@ new //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.12: (new) //│ ╙── ^ -//│ Parsed: {'(' new {}, ')'} +//│ Parsed: {'(' new {} ')'} :pe new {} diff --git a/shared/src/test/diff/parser/TypeParams.mls b/shared/src/test/diff/parser/TypeParams.mls index d0d2c1f1f8..6a624b55b2 100644 --- a/shared/src/test/diff/parser/TypeParams.mls +++ b/shared/src/test/diff/parser/TypeParams.mls @@ -13,7 +13,7 @@ class Foo‹A› (1) //│ |(|1|)| -//│ Parsed: {'(' 1, ')'} +//│ Parsed: {'(' 1 ')'} foo<1,2,3> From 4b15f19a5575759b16149f454d490d53cb2bd671 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 24 Feb 2023 21:52:12 +0800 Subject: [PATCH 081/498] Try to generate mixin --- .../src/main/scala/mlscript/JSBackend.scala | 4 + .../main/scala/mlscript/codegen/Codegen.scala | 5 + .../main/scala/mlscript/codegen/Scope.scala | 6 + shared/src/main/scala/mlscript/helpers.scala | 22 ++- shared/src/main/scala/mlscript/syntax.scala | 1 + shared/src/test/diff/nu/ECOOP23_codegen.mls | 176 ++++++++++++++++++ 6 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 shared/src/test/diff/nu/ECOOP23_codegen.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index bf57079fe0..4014606531 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -254,6 +254,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case New(_, TypingUnit(_)) => throw CodeGenError("custom class body is not supported yet") case Forall(_, bod) => translateTerm(bod) + case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _)) => + val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) + JSClassExpr(translateClassDeclaration(clsBody, Some(ClassSymbol("base", "base", Ls(), baseType, Ls())))) case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") } @@ -441,6 +444,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } // Declare the alias for `this` before declaring parameters. val selfSymbol = memberScope.declareThisAlias() + val superSymbol = memberScope.declareSuper() // Declare parameters. val (memberParams, body) = method.rhs.value match { case Lam(params, body) => diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index ab88f7b6c0..f061c5450d 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -638,6 +638,11 @@ final case class JSRecord(entries: Ls[Str -> JSExpr]) extends JSExpr { }) } +final case class JSClassExpr(cls: JSClassDecl) extends JSExpr { + implicit def precedence: Int = 22 + def toSourceCode: SourceCode = cls.toSourceCode +} + abstract class JSStmt extends JSCode final case class JSExprStmt(expr: JSExpr) extends JSStmt { diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 52f11990f5..1fc3f08b2d 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -245,6 +245,12 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } + def declareSuper(): ValueSymbol = { + val symbol = ValueSymbol("super", "super", Some(false), false) + register(symbol) + symbol + } + def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean): ValueSymbol = { val runtimeName = lexicalValueSymbols.get(lexicalName) match { // If we are implementing a stub symbol and the stub symbol did not shadow any other diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 53caf8e95f..a5c957514a 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -704,8 +704,21 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) + case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => + val (diags, ds) = + NuTypeDef(Cls, TypeName(mxName), tps, tup, pars :+ Var("base"), sup, ths, unit).desugared + ds match { + case (cls: TypeDef) :: _ => diags -> (NuFunDef(None, Var(mxName), List(), Left(Lam(Tup(Ls(None -> Fld(false, false, Var("base")))), ClassExpression(cls)))) :: Nil) + case _ => ??? + } case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - ??? // TODO + val (diags, ds) = + NuTypeDef(Cls, nme, tps, tup, pars, sup, ths, unit).desugared + // ds match { + // case (cls: TypeDef) :: _ => diags -> (cls :: Nil) + // case _ => ??? + // } + ??? case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) @@ -738,7 +751,12 @@ trait StatementImpl extends Located { self: Statement => case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld case _ => die })) :: Nil)))), true) - diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, Nil, pos) :: ctor :: Nil) + val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) + case _ => lst + }) + // TODO: mthDecls + diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, mthDefs, pos) :: ctor :: Nil) case d: DesugaredStatement => Nil -> (d :: Nil) } import Message._ diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index a4ea490580..614390d092 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -78,6 +78,7 @@ final case class TyApp(lhs: Term, targs: Ls[Type]) extends Ter final case class Where(body: Term, where: Ls[Statement]) extends Term final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term +final case class ClassExpression(cls: TypeDef) extends Term sealed abstract class IfBody extends IfBodyImpl // final case class IfTerm(expr: Term) extends IfBody // rm? diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls new file mode 100644 index 0000000000..9c5e826b37 --- /dev/null +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -0,0 +1,176 @@ +:NewParser +:NewDefs + +class Add(lhs: E, rhs: E) +class Lit(n: int) +//│ +//│ class Add[E](lhs: E, rhs: E) { +//│ this: 'this +//│ } +//│ class Lit(n: int) { +//│ this: 'this0 +//│ } +//│ where +//│ 'this0 :> Lit +//│ 'this :> Add + +:js +mixin EvalBase { + fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then this.eval(l) + this.eval(r) +} +//│ +//│ mixin EvalBase() { +//│ super: 'super +//│ this: 'this +//│ fun eval: (Add & {Add#E = 'E} | Lit) -> int +//│ } +//│ where +//│ 'E <: 'lhs +//│ 'this <: {eval: 'lhs -> int} +//│ // Query 1 +//│ globalThis.EvalBase = function EvalBase(base) { +//│ return (class EvalBase extends base { +//│ constructor(fields) { +//│ super(fields); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })()); +//│ } +//│ }); +//│ }; +//│ // End of generated code + +class Neg(expr: A) +//│ +//│ class Neg[A](expr: A) { +//│ this: 'this +//│ } +//│ where +//│ 'this :> Neg + +:js +mixin EvalNeg { + fun eval(e) = + if e is Neg(d) then 0 - this.eval(d) + else super.eval(e) +} +//│ +//│ mixin EvalNeg() { +//│ super: 'super +//│ this: 'this +//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> (int | 'b) +//│ } +//│ where +//│ 'A <: 'expr +//│ 'this <: {eval: 'expr -> int} +//│ 'super <: {eval: 'a -> 'b} +//│ // Query 1 +//│ globalThis.EvalNeg = function EvalNeg(base) { +//│ return (class EvalNeg extends base { +//│ constructor(fields) { +//│ super(fields); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ }; +//│ // End of generated code + +:js +mixin EvalNegNeg { + fun eval(e) = + if e is Neg(Neg(d)) then this.eval(d) + else super.eval(e) +} +//│ +//│ mixin EvalNegNeg() { +//│ super: 'super +//│ this: 'this +//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> 'b +//│ } +//│ where +//│ 'A :> 'A0 +//│ <: 'A1 & (~Neg | Neg & {Neg#A = 'A2}) +//│ 'A2 :> 'A3 +//│ <: 'expr +//│ 'this <: {eval: 'expr -> 'b} +//│ 'super <: {eval: (Neg & {Neg#A :> 'A0 & (~Neg | Neg & {Neg#A :> 'expr <: 'expr & 'A3}) <: 'A0 | 'A1} | 'a) -> 'b} +//│ // Query 1 +//│ globalThis.EvalNegNeg = function EvalNegNeg(base) { +//│ return (class EvalNegNeg extends base { +//│ constructor(fields) { +//│ super(fields); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ }; +//│ // End of generated code + +:js +module TestLang: EvalBase, EvalNeg, EvalNegNeg +//│ +//│ namespace TestLang() { +//│ this: 'this +//│ fun eval: 'a -> int +//│ } +//│ where +//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} +//│ 'A :> 'A0 +//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) +//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a +//│ 'A1 <: 'A2 +//│ 'A2 <: 'a +//│ 'E <: 'a +//│ 'this :> TestLang +//│ Code generation crashed: +//│ scala.NotImplementedError: an implementation is missing + + +:js +fun mk(n) = if n is + 0 then Lit(0) + 1 then Neg(mk(n)) + _ then Add(mk(n), mk(n)) +TestLang.eval(mk(0)) +//│ +//│ fun mk: number -> (Lit | 'a) +//│ int +//│ where +//│ 'a :> Neg & {Neg#A = 'A} | Add & {Add#E = 'E} +//│ 'E :> 'E0 | Lit | 'a +//│ <: 'E1 +//│ 'A :> 'A0 | Lit | 'a +//│ <: 'A1 +//│ 'A0 :> Lit | 'b +//│ <: 'A2 & 'c & (Neg & {Neg#A = 'A0} | ~Neg) +//│ 'b :> Neg & {Neg#A :> 'A0 <: 'A1} | Add & {Add#E :> 'E0 <: 'E1} +//│ 'E1 :> 'E0 | Lit | 'b +//│ <: 'E0 +//│ 'A1 :> 'A0 | Lit | 'b +//│ <: 'A0 & 'A2 +//│ 'A2 :> 'A0 | Lit | 'b +//│ <: 'A0 & 'c & (~Neg | Neg & {Neg#A = 'A2}) +//│ 'c <: Add & {Add#E = 'E0} | Lit | Neg & {Neg#A = 'A2} +//│ 'E0 :> Lit | 'b +//│ <: 'c +//│ Typed: int +//│ Code generation encountered an error: +//│ unresolved symbol TestLang From 339985280ca3742e50054512c322029bb94c3d76 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sat, 25 Feb 2023 11:11:22 +0800 Subject: [PATCH 082/498] Apply new constrcutor translation --- .../src/main/scala/mlscript/JSBackend.scala | 10 +++++++- .../main/scala/mlscript/codegen/Codegen.scala | 19 +++++++++----- shared/src/main/scala/mlscript/helpers.scala | 8 +++--- shared/src/test/diff/nu/ECOOP23_codegen.mls | 25 +++++++++++++------ 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 4014606531..6435d7a70c 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -418,6 +418,11 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Collect class fields. val fields = classSymbol.body.collectFields ++ classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + + val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") + fields.foreach(constructorScope.declareValue(_, Some(false), false)) + val rest = constructorScope.declareValue("rest", Some(false), false) + val base = baseClassSymbol.map { sym => JSIdent(sym.runtimeName) } val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { @@ -427,7 +432,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case N => N } } - JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) + if (base.isDefined) + JSClassDecl(classSymbol.runtimeName, fields :+ rest.runtimeName, base, members, traits) + else + JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) } /** diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index f061c5450d..6b6000d552 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -790,15 +790,22 @@ final case class JSClassDecl( def toSourceCode: SourceCode = { val constructor: SourceCode = { val buffer = new ListBuffer[Str]() - buffer += " constructor(fields) {" - if (`extends`.isDefined) - buffer += " super(fields);" + val params = fields.iterator.zipWithIndex.foldLeft("")((s, p) => + if (p._2 === fields.length - 1) (if(`extends`.isDefined) s"$s...${p._1}" else s"$s${p._1}") + else s"$s${p._1}, ") + buffer += s" constructor($params) {" + if (`extends`.isDefined) { + val restName = if (fields.length > 0) fields.last else ??? // TODO: throw? + buffer += s" super(...$restName);" + } implements.foreach { name => buffer += s" $name.implement(this);" } - fields.foreach { name => - val innerName = if (JSField.isValidIdentifier(name)) s".${name}" else s"[${JSLit.makeStringLiteral(name)}]" - buffer += s" this$innerName = fields$innerName;" + fields.iterator.zipWithIndex.foreach { pair => + if (`extends`.isEmpty || pair._2 < fields.length - 1) { + // val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" + buffer += s" this.${pair._1} = ${pair._1};" // TODO: invalid name? + } } buffer += " }" SourceCode(buffer.toList) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index a5c957514a..6fa4ea9d8f 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -746,11 +746,11 @@ trait StatementImpl extends Located { self: Statement => val pos = params.unzip._1 val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) val termName = Var(nme.name).withLocOf(nme) - val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(false, false, Rcd(fs.map { - case (S(nme), fld) => nme -> Fld(false, false, nme) - case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld + val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(fs.map { + case (S(nme), fld) => N -> Fld(false, false, nme) + case (N, fld @ Fld(mut, spec, nme: Var)) => N -> Fld(false, false, nme) case _ => die - })) :: Nil)))), true) + })))), true) val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) case _ => lst diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 9c5e826b37..32b35e6aff 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -33,8 +33,8 @@ mixin EvalBase { //│ // Query 1 //│ globalThis.EvalBase = function EvalBase(base) { //│ return (class EvalBase extends base { -//│ constructor(fields) { -//│ super(fields); +//│ constructor(...rest) { +//│ super(...rest); //│ } //│ eval(e) { //│ const self = this; @@ -49,6 +49,7 @@ mixin EvalBase { //│ }; //│ // End of generated code +:js class Neg(expr: A) //│ //│ class Neg[A](expr: A) { @@ -56,6 +57,17 @@ class Neg(expr: A) //│ } //│ where //│ 'this :> Neg +//│ // Prelude +//│ class Neg { +//│ constructor(expr) { +//│ this.expr = expr; +//│ } +//│ } +//│ // Query 1 +//│ globalThis.Neg1 = function Neg1(expr) { +//│ return new Neg(expr); +//│ }; +//│ // End of generated code :js mixin EvalNeg { @@ -76,8 +88,8 @@ mixin EvalNeg { //│ // Query 1 //│ globalThis.EvalNeg = function EvalNeg(base) { //│ return (class EvalNeg extends base { -//│ constructor(fields) { -//│ super(fields); +//│ constructor(...rest) { +//│ super(...rest); //│ } //│ eval(e) { //│ const self = this; @@ -111,8 +123,8 @@ mixin EvalNegNeg { //│ // Query 1 //│ globalThis.EvalNegNeg = function EvalNegNeg(base) { //│ return (class EvalNegNeg extends base { -//│ constructor(fields) { -//│ super(fields); +//│ constructor(...rest) { +//│ super(...rest); //│ } //│ eval(e) { //│ const self = this; @@ -143,7 +155,6 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ Code generation crashed: //│ scala.NotImplementedError: an implementation is missing - :js fun mk(n) = if n is 0 then Lit(0) From 5149f33d5d1160ad7e84591292c34fe45e8b4448 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sat, 25 Feb 2023 17:00:39 +0800 Subject: [PATCH 083/498] Try to generate modules --- .../src/main/scala/mlscript/JSBackend.scala | 26 ++-- .../main/scala/mlscript/codegen/Codegen.scala | 4 +- shared/src/main/scala/mlscript/helpers.scala | 29 ++-- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/nu/ECOOP23_codegen.mls | 133 ++++++++---------- 5 files changed, 97 insertions(+), 97 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 6435d7a70c..60f8755cc3 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -129,6 +129,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case App(App(App(Var("if"), Tup((_, Fld(_, _, tst)) :: Nil)), Tup((_, Fld(_, _, con)) :: Nil)), Tup((_, Fld(_, _, alt)) :: Nil)) => JSTenary(translateTerm(tst), translateTerm(con), translateTerm(alt)) case App(App(App(Var("if"), tst), con), alt) => die + case App(ce: ClassExpression, _) => JSNew(translateTerm(ce)) // Function invocation case App(trm, Tup(args)) => val callee = trm match { @@ -254,9 +255,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case New(_, TypingUnit(_)) => throw CodeGenError("custom class body is not supported yet") case Forall(_, bod) => translateTerm(bod) - case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _)) => + case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _), parents) => val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) - JSClassExpr(translateClassDeclaration(clsBody, Some(ClassSymbol("base", "base", Ls(), baseType, Ls())))) + parents match { + case Some(p) => JSClassExpr(translateClassDeclaration(clsBody, Some(translateTerm(p)))) + case _ => JSClassExpr(translateClassDeclaration(clsBody, N)) + } case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") } @@ -408,7 +412,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { */ protected def translateClassDeclaration( classSymbol: ClassSymbol, - baseClassSymbol: Opt[ClassSymbol] + base: Opt[JSExpr] )(implicit scope: Scope): JSClassDecl = { // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") @@ -423,7 +427,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { fields.foreach(constructorScope.declareValue(_, Some(false), false)) val rest = constructorScope.declareValue("rest", Some(false), false) - val base = baseClassSymbol.map { sym => JSIdent(sym.runtimeName) } + // val base = baseClassSymbol.map { sym => JSIdent(sym.runtimeName) } val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) @@ -573,8 +577,11 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ - sortClassSymbols(classSymbols).map { case (derived, base) => - translateClassDeclaration(derived, base)(topLevelScope) + sortClassSymbols(classSymbols).map { + case (derived, Some(base)) => + translateClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) + case (derived, None) => + translateClassDeclaration(derived, None)(topLevelScope) }.toList val resultsIdent = JSIdent(resultsName) @@ -648,8 +655,11 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ - sortClassSymbols(classSymbols).map { case (derived, base) => - translateClassDeclaration(derived, base)(topLevelScope) + sortClassSymbols(classSymbols).map { + case (derived, Some(base)) => + translateClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) + case (derived, None) => + translateClassDeclaration(derived, None)(topLevelScope) }.toList val zeroWidthSpace = JSLit("\"\\u200B\"") diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 6b6000d552..05de0b25cb 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -803,8 +803,8 @@ final case class JSClassDecl( } fields.iterator.zipWithIndex.foreach { pair => if (`extends`.isEmpty || pair._2 < fields.length - 1) { - // val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" - buffer += s" this.${pair._1} = ${pair._1};" // TODO: invalid name? + val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" + buffer += s" this${innerName} = ${pair._1};" // TODO: invalid name? } } buffer += " }" diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 6fa4ea9d8f..13ecb6f5fb 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -705,20 +705,31 @@ trait StatementImpl extends Located { self: Statement => dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => + val bases = pars.foldLeft(Var("base"): Term)((res, p) => p match { + case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) + case _ => ??? + }) val (diags, ds) = - NuTypeDef(Cls, TypeName(mxName), tps, tup, pars :+ Var("base"), sup, ths, unit).desugared + NuTypeDef(Cls, TypeName(mxName), tps, tup, Ls(bases), sup, ths, unit).desugared ds match { - case (cls: TypeDef) :: _ => diags -> (NuFunDef(None, Var(mxName), List(), Left(Lam(Tup(Ls(None -> Fld(false, false, Var("base")))), ClassExpression(cls)))) :: Nil) + case (cls: TypeDef) :: _ => diags -> (NuFunDef(None, Var(mxName), List(), Left(Lam(Tup(Ls(None -> Fld(false, false, Var("base")))), ClassExpression(cls, S(bases))))) :: Nil) case _ => ??? } case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - val (diags, ds) = - NuTypeDef(Cls, nme, tps, tup, pars, sup, ths, unit).desugared - // ds match { - // case (cls: TypeDef) :: _ => diags -> (cls :: Nil) - // case _ => ??? - // } - ??? + if (pars.length > 0) { + val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { + case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) + case _ => ??? + }) + val (diags, ds) = + NuTypeDef(Cls, nme, tps, tup, Ls(bases), sup, ths, unit).desugared + val termName = Var(nme.name).withLocOf(nme) + ds match { + case (cls: TypeDef) :: _ => diags -> (Def(false, termName, Left(App(ClassExpression(cls, S(bases)), Tup(Ls()))), true) :: Nil) + case _ => ??? + } + } + else ??? case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 614390d092..baf5c9b307 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -78,7 +78,7 @@ final case class TyApp(lhs: Term, targs: Ls[Type]) extends Ter final case class Where(body: Term, where: Ls[Statement]) extends Term final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term -final case class ClassExpression(cls: TypeDef) extends Term +final case class ClassExpression(cls: TypeDef, parents: Opt[Term]) extends Term sealed abstract class IfBody extends IfBodyImpl // final case class IfTerm(expr: Term) extends IfBody // rm? diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 32b35e6aff..44156fe5ef 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -1,18 +1,33 @@ :NewParser :NewDefs +:js class Add(lhs: E, rhs: E) class Lit(n: int) -//│ -//│ class Add[E](lhs: E, rhs: E) { -//│ this: 'this +//│ class Add[E](lhs: E, rhs: E) +//│ class Lit(n: int) +//│ // Prelude +//│ let res; +//│ class Add { +//│ constructor(lhs, rhs) { +//│ this.lhs = lhs; +//│ this.rhs = rhs; +//│ } //│ } -//│ class Lit(n: int) { -//│ this: 'this0 +//│ class Lit { +//│ constructor(n) { +//│ this.n = n; +//│ } //│ } -//│ where -//│ 'this0 :> Lit -//│ 'this :> Add +//│ // Query 1 +//│ globalThis.Add1 = function Add1(lhs, rhs) { +//│ return new Add(lhs, rhs); +//│ }; +//│ // Query 2 +//│ globalThis.Lit1 = function Lit1(n) { +//│ return new Lit(n); +//│ }; +//│ // End of generated code :js mixin EvalBase { @@ -21,15 +36,10 @@ mixin EvalBase { Lit(n) then n: int Add(l, r) then this.eval(l) + this.eval(r) } -//│ //│ mixin EvalBase() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Add & {Add#E = 'E} | Lit) -> int +//│ this: {eval: 'lhs -> int} +//│ fun eval: (Add['lhs] | Lit) -> int //│ } -//│ where -//│ 'E <: 'lhs -//│ 'this <: {eval: 'lhs -> int} //│ // Query 1 //│ globalThis.EvalBase = function EvalBase(base) { //│ return (class EvalBase extends base { @@ -51,12 +61,7 @@ mixin EvalBase { :js class Neg(expr: A) -//│ -//│ class Neg[A](expr: A) { -//│ this: 'this -//│ } -//│ where -//│ 'this :> Neg +//│ class Neg[A](expr: A) //│ // Prelude //│ class Neg { //│ constructor(expr) { @@ -75,16 +80,11 @@ mixin EvalNeg { if e is Neg(d) then 0 - this.eval(d) else super.eval(e) } -//│ //│ mixin EvalNeg() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> (int | 'b) +//│ super: {eval: 'a -> 'b} +//│ this: {eval: 'expr -> int} +//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } -//│ where -//│ 'A <: 'expr -//│ 'this <: {eval: 'expr -> int} -//│ 'super <: {eval: 'a -> 'b} //│ // Query 1 //│ globalThis.EvalNeg = function EvalNeg(base) { //│ return (class EvalNeg extends base { @@ -107,19 +107,11 @@ mixin EvalNegNeg { if e is Neg(Neg(d)) then this.eval(d) else super.eval(e) } -//│ //│ mixin EvalNegNeg() { -//│ super: 'super -//│ this: 'this -//│ fun eval: (Neg & {Neg#A = 'A} | 'a & ~Neg) -> 'b +//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ this: {eval: 'expr -> 'b} +//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } -//│ where -//│ 'A :> 'A0 -//│ <: 'A1 & (~Neg | Neg & {Neg#A = 'A2}) -//│ 'A2 :> 'A3 -//│ <: 'expr -//│ 'this <: {eval: 'expr -> 'b} -//│ 'super <: {eval: (Neg & {Neg#A :> 'A0 & (~Neg | Neg & {Neg#A :> 'expr <: 'expr & 'A3}) <: 'A0 | 'A1} | 'a) -> 'b} //│ // Query 1 //│ globalThis.EvalNegNeg = function EvalNegNeg(base) { //│ return (class EvalNegNeg extends base { @@ -138,22 +130,21 @@ mixin EvalNegNeg { :js module TestLang: EvalBase, EvalNeg, EvalNegNeg -//│ -//│ namespace TestLang() { -//│ this: 'this -//│ fun eval: 'a -> int +//│ module TestLang() { +//│ fun eval: 'a -> int //│ } -//│ where -//│ 'a <: Add & {Add#E = 'E} | Lit | Neg & {Neg#A = 'A} -//│ 'A :> 'A0 -//│ <: 'A0 & (~Neg | Neg & {Neg#A = 'A1}) -//│ 'A0 <: (Neg & {Neg#A :> 'A2 <: 'A1} | ~Neg) & 'a -//│ 'A1 <: 'A2 -//│ 'A2 <: 'a -//│ 'E <: 'a -//│ 'this :> TestLang -//│ Code generation crashed: -//│ scala.NotImplementedError: an implementation is missing +//│ where +//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'A <: 'a +//│ // Query 1 +//│ globalThis.TestLang1 = function TestLang1() { +//│ return (new class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ }); +//│ }; +//│ // End of generated code :js fun mk(n) = if n is @@ -161,27 +152,15 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) TestLang.eval(mk(0)) -//│ //│ fun mk: number -> (Lit | 'a) //│ int -//│ where -//│ 'a :> Neg & {Neg#A = 'A} | Add & {Add#E = 'E} -//│ 'E :> 'E0 | Lit | 'a -//│ <: 'E1 -//│ 'A :> 'A0 | Lit | 'a -//│ <: 'A1 -//│ 'A0 :> Lit | 'b -//│ <: 'A2 & 'c & (Neg & {Neg#A = 'A0} | ~Neg) -//│ 'b :> Neg & {Neg#A :> 'A0 <: 'A1} | Add & {Add#E :> 'E0 <: 'E1} -//│ 'E1 :> 'E0 | Lit | 'b -//│ <: 'E0 -//│ 'A1 :> 'A0 | Lit | 'b -//│ <: 'A0 & 'A2 -//│ 'A2 :> 'A0 | Lit | 'b -//│ <: 'A0 & 'c & (~Neg | Neg & {Neg#A = 'A2}) -//│ 'c <: Add & {Add#E = 'E0} | Lit | Neg & {Neg#A = 'A2} -//│ 'E0 :> Lit | 'b -//│ <: 'c -//│ Typed: int -//│ Code generation encountered an error: -//│ unresolved symbol TestLang +//│ where +//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] +//│ // Query 1 +//│ globalThis.mk = function mk(n) { +//│ return n == 0 === true ? Lit1(0) : n == 1 === true ? Neg1(mk(n)) : Add1(mk(n), mk(n)); +//│ }; +//│ // Query 2 +//│ res = TestLang1().eval(mk(0)); +//│ // End of generated code + From 20d6b56cb5fde6181e5910b62d0c5fa0fa4a3d58 Mon Sep 17 00:00:00 2001 From: Andong Fan Date: Sat, 25 Feb 2023 18:45:06 +0800 Subject: [PATCH 084/498] Add CP DSL example --- shared/src/test/diff/nu/Andong.mls | 11 + shared/src/test/diff/nu/SimpleRegionDSL.mls | 335 ++++++++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 shared/src/test/diff/nu/Andong.mls create mode 100644 shared/src/test/diff/nu/SimpleRegionDSL.mls diff --git a/shared/src/test/diff/nu/Andong.mls b/shared/src/test/diff/nu/Andong.mls new file mode 100644 index 0000000000..405c384ac4 --- /dev/null +++ b/shared/src/test/diff/nu/Andong.mls @@ -0,0 +1,11 @@ +:NewParser +:NewDefs +:NoJS + +class Union(a: Region, b: Region) +//│ class Union[Region](a: Region, b: Region) + +// ? x is shadowed. Why is b required? +fun hmm(x) = + if x is Union(x, y) then x +//│ fun hmm: Union[{b: anything} & 'a] -> 'a diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls new file mode 100644 index 0000000000..b0c7430aac --- /dev/null +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -0,0 +1,335 @@ +:NewParser +:NewDefs +:NoJS + +// Adopted from Compositional Embeddings of Domain-Specific Languages (OOPSLA 2022) +// ******************* Initial System ******************* + +class Vector(x: int, y: int) +//│ class Vector(x: int, y: int) + +class Circle(radius: int) +class Outside(a: Region) +class Union(a: Region, b: Region) +class Intersect(a: Region, b: Region) +class Translate(v: Vector, a: Region) +//│ class Circle(radius: int) +//│ class Outside[Region](a: Region) +//│ class Union[Region](a: Region, b: Region) +//│ class Intersect[Region](a: Region, b: Region) +//│ class Translate[Region](v: Vector, a: Region) + +mixin SizeBase { + fun size(r) = + if r is + Circle(_) then 1 + Outside(a) then this.size(a) + 1 + Union(a, b) then this.size(a) + this.size(b) + 1 + Intersect(a, b) then this.size(a) + this.size(b) + 1 + Translate(_, a) then this.size(a) + 1 +} +//│ mixin SizeBase() { +//│ this: {size: ('a | 'a0 | 'a1 | 'a2) -> int} +//│ fun size: (Circle | Intersect['a2] | Outside['a0] | Translate['a] | Union['a1]) -> int +//│ } + +// ******************* Linguistic Reuse and Meta-Language Optimizations ******************* + +// FIXME: number or int? +fun go(x, offset) = + if x is 0 then Circle(1) + else + let shared = go(x - 1, offset / 2) + Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) +//│ ╔══[ERROR] Type mismatch in expression: +//│ ╟── operator application of type `number` is not an instance of type `int` +//│ ║ l.42: let shared = go(x - 1, offset / 2) +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.43: Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) +//│ ╙── ^^^^^^ +//│ fun go: (int, int,) -> 'Region +//│ where +//│ 'Region :> Circle | Union[Translate['Region]] + +// ? forall 'Region. 'Region +let circles = go(20, 1024) +//│ let circles: forall 'Region. 'Region +//│ where +//│ 'Region :> Circle | Union[Translate['Region]] + +// ******************* Adding More Language Constructs ******************* + +class Univ +class Empty +class Scale(v: Vector, a: Region) +//│ class Univ() +//│ class Empty() +//│ class Scale[Region](v: Vector, a: Region) + +mixin SizeExt { + fun size(a) = + if a is + Univ then 1 + Empty then 1 + Scale(_, a) then this.size(a) + 1 + else super.size(a) +} +//│ mixin SizeExt() { +//│ super: {size: 'b -> 'c} +//│ this: {size: 'a -> int} +//│ fun size: (Empty | Scale['a] | Univ | 'b & ~Empty & ~Scale & ~Univ) -> (int | 'c) +//│ } + +module TestSize: SizeBase, SizeExt +//│ module TestSize() { +//│ fun size: 'a -> int +//│ } +//│ where +//│ 'a <: Circle | Empty | Intersect['a] | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ + +TestSize.size(Empty()) +//│ int + +TestSize.size(circles) +//│ int + +TestSize.size(Scale(Vector(1, 1), circles)) +//│ int + +// ******************* Adding a New Interpretation ******************* +// a stupid power (int ** int) implementation +fun pow(x, a) = + if a is 0 then 1 + else x * pow(x, a - 1) +//│ fun pow: (int, int,) -> int + +mixin Contains { + fun contains(a, p) = + if a is + Circle(r) then pow(p.x, 2) + pow(p.y, 2) <= pow(r, 2) + Outside(a) then not (this.contains(a, p)) + Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) + Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) + Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) +} +//│ mixin Contains() { +//│ this: {contains: ('a | 'a0 | 'a1, 'b,) -> bool & ('a2, Vector,) -> 'c} +//│ fun contains: (Circle | Intersect['a1] | Outside['a] | Translate['a2] | Union['a0], {x: int, y: int} & 'b,) -> (bool | 'c) +//│ } + +module TestContains: Contains +//│ module TestContains() { +//│ fun contains: ('a, {x: int, y: int},) -> bool +//│ } +//│ where +//│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] + +TestContains.contains(Translate(Vector(0, 0), Circle(1)), Vector(0, 0)) +//│ bool + +TestContains.contains(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1)), Vector(0, 0)) +//│ bool + +TestContains.contains(circles, Vector(0, 0)) +//│ bool + +// ******************* Dependencies, Complex Interpretations, and Domain-Specific Optimizations ******************* + +fun toString(a: int): string +fun concat(a: string, b: string): string +//│ fun toString: (a: int,) -> string +//│ fun concat: (a: string, b: string,) -> string + +mixin Text { + fun text(e) = + if e is + Circle(r) then concat("a circular region of radius ", toString(r)) + Outside(a) then concat("outside a region of size ", toString(this.size(a))) + Union(_, _) then concat("the union of two regions of size ", toString(this.size(e))) + Intersect(_, _) then concat("the intersection of two regions of size ", toString(this.size(e))) + Translate(_, _) then concat("a translated region of size ", toString(this.size(e))) +} +//│ mixin Text() { +//│ this: {size: (Intersect['Region] | Translate['Region0] | Union['Region1] | 'a) -> int} +//│ fun text: (Circle | Intersect['Region] | Outside['a] | Translate['Region0] | Union['Region1]) -> string +//│ } + +:e +module SizeText: Text +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.159: module SizeText: Text +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.151: Translate(_, _) then concat("a translated region of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.151: Translate(_, _) then concat("a translated region of size ", toString(this.size(e))) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.159: module SizeText: Text +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.150: Intersect(_, _) then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.150: Intersect(_, _) then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.159: module SizeText: Text +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.149: Union(_, _) then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.149: Union(_, _) then concat("the union of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.159: module SizeText: Text +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.148: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ ^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.148: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ╙── ^^^^ +//│ module SizeText() { +//│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string +//│ } + +module SizeText: SizeBase, Text +//│ module SizeText() { +//│ fun size: 'a -> int +//│ fun text: (Circle | Intersect['Region] | Outside['a] | Translate['Region0] | Union['Region1]) -> string +//│ } +//│ where +//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['Region0] | Union['Region1] +//│ 'Region1 <: 'a +//│ 'Region0 <: 'a +//│ 'Region <: 'a + +SizeText.text(circles) +//│ string + +SizeText.size(circles) +//│ int + +SizeText.text(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) +//│ string + +SizeText.size(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) +//│ int + +mixin IsUniv { + fun isUniv(e) = + if e is + Univ then true + Outside(a) then this.isEmpty(a) + Union(a, b) then this.isUniv(a) || this.isUniv(b) + Intersect(a, b) then this.isUniv(a) && this.isUniv(b) + Translate(_, a) then this.isUniv(a) + Scale(_, a) then this.isUniv(a) + else false +} +//│ mixin IsUniv() { +//│ this: {isEmpty: 'a -> 'b, isUniv: ('a0 | 'a1) -> bool & ('a2 | 'a3) -> 'b} +//│ fun isUniv: (Intersect['a1] | Outside['a] | Scale['a3] | Translate['a2] | Union['a0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ } + +mixin IsEmpty { + fun isEmpty(e) = + if e is + Univ then true + Outside(a) then this.isUniv(a) + Union(a, b) then this.isEmpty(a) || this.isEmpty(b) + Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) + Translate(_, a) then this.isEmpty(a) + Scale(_, a) then this.isEmpty(a) + else false +} +//│ mixin IsEmpty() { +//│ this: {isEmpty: ('a | 'a0) -> bool & ('a1 | 'a2) -> 'b, isUniv: 'a3 -> 'b} +//│ fun isEmpty: (Intersect['a0] | Outside['a3] | Scale['a2] | Translate['a1] | Union['a] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ } + +module IsUnivIsEmpty: IsUniv, IsEmpty +//│ module IsUnivIsEmpty() { +//│ fun isEmpty: 'a -> bool +//│ fun isUniv: 'b -> bool +//│ } +//│ where +//│ 'a <: Intersect['a] | Outside['b] | Scale['a] | Translate['a] | Union['a] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'b <: Intersect['b] | Outside['a] | Scale['b] | Translate['b] | Union['b] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ + +module IsUnivIsEmpty: IsEmpty, IsUniv +//│ module IsUnivIsEmpty() { +//│ fun isEmpty: 'a -> bool +//│ fun isUniv: 'b -> bool +//│ } +//│ where +//│ 'a <: Intersect['a] | Outside['b] | Scale['a] | Translate['a] | Union['a] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'b <: Intersect['b] | Outside['a] | Scale['b] | Translate['b] | Union['b] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ + +IsUnivIsEmpty.isUniv(circles) +//│ bool + +IsUnivIsEmpty.isEmpty(circles) +//│ bool + +class Foo +IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ class Foo() +//│ bool + +mixin Eliminate { + fun eliminate(e) = + if e is + Outside(Outside(a)) then this.eliminate(a) + Outside(a) then Outside(this.eliminate(a)) + Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) + Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) + Translate(v, a) then Translate(v, this.eliminate(a)) + Scale(v, a) then Scale(v, this.eliminate(a)) + else e +} +//│ mixin Eliminate() { +//│ this: {eliminate: 'a -> 'b & 'a0 -> 'c & 'a1 -> 'd & 'a2 -> 'e & 'a3 -> 'f & 'a4 -> 'g} +//│ fun eliminate: (Intersect['a2] | Outside['a0 & (Outside['a] | ~Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'h & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union) -> (Intersect['e] | Outside['c] | Scale['g] | Translate['f] | Union['d] | 'b | 'h) +//│ } + +module TestElim: Eliminate +//│ module TestElim() { +//│ fun eliminate: 'a -> 'b +//│ } +//│ where +//│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union +//│ 'b :> Union['b] | Intersect['b] | Translate['b] | Scale['b] | Outside['b] + +TestElim.eliminate(Outside(Outside(Univ()))) +//│ 'a +//│ where +//│ 'a :> Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] + +TestElim.eliminate(circles) +//│ 'a +//│ where +//│ 'a :> Union['a] | Intersect['a] | Translate['a] | Scale['a] | Circle | Outside['a] + +fun mk(n) = if n is + 1 then Outside(mk(n)) + 2 then Union(mk(n), mk(n)) + 3 then Intersect(mk(n), mk(n)) + 4 then Translate(Vector(0, 0), mk(n)) + _ then Scale(Vector(0, 0), mk(n)) +//│ fun mk: number -> 'Region +//│ where +//│ 'Region :> Intersect['Region] | Outside['Region] | Scale['Region] | Translate['Region] | Union['Region] + +TestElim.eliminate(mk(100)) +//│ 'a +//│ where +//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] From 186a1a073cfb9108f6b86db2fd246d7a6433585a Mon Sep 17 00:00:00 2001 From: Andong Fan Date: Sat, 25 Feb 2023 19:48:18 +0800 Subject: [PATCH 085/498] Minor --- shared/src/test/diff/nu/SimpleRegionDSL.mls | 115 +++++++++++++++++--- 1 file changed, 100 insertions(+), 15 deletions(-) diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index b0c7430aac..34103332f8 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -146,9 +146,9 @@ mixin Text { if e is Circle(r) then concat("a circular region of radius ", toString(r)) Outside(a) then concat("outside a region of size ", toString(this.size(a))) - Union(_, _) then concat("the union of two regions of size ", toString(this.size(e))) - Intersect(_, _) then concat("the intersection of two regions of size ", toString(this.size(e))) - Translate(_, _) then concat("a translated region of size ", toString(this.size(e))) + Union then concat("the union of two regions of size ", toString(this.size(e))) + Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) + Translate then concat("a translated region of size ", toString(this.size(e))) } //│ mixin Text() { //│ this: {size: (Intersect['Region] | Translate['Region0] | Union['Region1] | 'a) -> int} @@ -162,31 +162,31 @@ module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.151: Translate(_, _) then concat("a translated region of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^ +//│ ║ l.151: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.151: Translate(_, _) then concat("a translated region of size ", toString(this.size(e))) -//│ ╙── ^^^^ +//│ ║ l.151: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.159: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.150: Intersect(_, _) then concat("the intersection of two regions of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^ +//│ ║ l.150: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.150: Intersect(_, _) then concat("the intersection of two regions of size ", toString(this.size(e))) -//│ ╙── ^^^^ +//│ ║ l.150: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.159: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.149: Union(_, _) then concat("the union of two regions of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^ +//│ ║ l.149: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.149: Union(_, _) then concat("the union of two regions of size ", toString(this.size(e))) -//│ ╙── ^^^^ +//│ ║ l.149: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.159: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ @@ -333,3 +333,88 @@ TestElim.eliminate(mk(100)) //│ 'a //│ where //│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] + +// ************************************************************************* + +module Lang: SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate +//│ module Lang() { +//│ fun contains: ('a, {x: int, y: int},) -> bool +//│ fun eliminate: 'b -> 'c +//│ fun isEmpty: 'd -> bool +//│ fun isUniv: 'e -> bool +//│ fun size: 'f -> int +//│ fun text: (Circle | Intersect['Region] | Outside['f] | Translate['Region0] | Union['Region1]) -> string +//│ } +//│ where +//│ 'f <: Circle | Empty | Intersect['Region] | Outside['f] | Scale['f] | Translate['Region0] | Union['Region1] | Univ +//│ 'Region1 <: 'f +//│ 'Region0 <: 'f +//│ 'Region <: 'f +//│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union +//│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] +//│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] + + +Lang.size(circles) +//│ int + +Lang.contains(circles, Vector(0, 0)) +//│ bool + +Lang.text(circles) +//│ string + +Lang.isUniv(circles) +//│ bool + +Lang.isEmpty(circles) +//│ bool + +Lang.size(Lang.eliminate(circles)) +//│ int + +Lang.size(mk(100)) +//│ int + +:e +Lang.contains(mk(100), Vector(0, 0)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.382: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` +//│ ║ l.327: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` +//│ ║ l.382: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.109: if a is +//│ ╙── ^ +//│ error | bool + +:e +Lang.text(mk(100)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.398: Lang.text(mk(100)) +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` +//│ ║ l.327: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` +//│ ║ l.398: Lang.text(mk(100)) +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.146: if e is +//│ ╙── ^ +//│ error | string + +Lang.isUniv(mk(100)) +//│ bool + +Lang.isEmpty(mk(100)) +//│ bool + +Lang.size(Lang.eliminate(mk(100))) +//│ int From b84091d44e66f6cee4cf57da9b170346ccac30da Mon Sep 17 00:00:00 2001 From: Andong Fan Date: Sat, 25 Feb 2023 22:26:41 +0800 Subject: [PATCH 086/498] Typo --- shared/src/test/diff/nu/SimpleRegionDSL.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index 34103332f8..3f6bacb77e 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -2,7 +2,7 @@ :NewDefs :NoJS -// Adopted from Compositional Embeddings of Domain-Specific Languages (OOPSLA 2022) +// Adapted example from Compositional Embeddings of Domain-Specific Languages (OOPSLA 2022) // ******************* Initial System ******************* class Vector(x: int, y: int) From 80564cf21de9ed617f470b6f2786b416149b3378 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 23:42:58 +0800 Subject: [PATCH 087/498] Add basic classes-in-mixin test + fix some missing impls --- .../main/scala/mlscript/TyperDatatypes.scala | 4 +- .../main/scala/mlscript/TyperHelpers.scala | 1 + shared/src/test/diff/nu/ClassesInMixins.mls | 78 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 shared/src/test/diff/nu/ClassesInMixins.mls diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 422e652f3d..30711070af 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -259,6 +259,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => mxn.ttu.entities.map(_.complete()).map { case fun @ TypedNuFun(_, fd, ty) => fun + case m: NuMember => m case _ => ??? } case cls: TypedNuCls => @@ -290,7 +291,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => superType, RecordType( // newMembs.foldLeft(TopType.toUpper(provTODO))(_ && _.ty.toUpper(provTODO)) - newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) + // newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) + newMembs.collect{case m: TypedNuFun => m.fd.nme -> m.ty.toUpper(provTODO)} )(provTODO) )(provTODO) inherit(ps, newSuperType, members ++ newMembs) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 409c9c1e18..3c8d85227e 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -742,6 +742,7 @@ abstract class TyperHelpers { Typer: Typer => def childrenPolMem(m: NuMember): List[PolMap -> SimpleType] = m match { case NuParam(nme, ty, isType) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable case TypedNuFun(level, fd, ty) => pol -> ty :: Nil + case td: TypedNuTermDef => CompletedTypingUnit(td :: Nil, N).childrenPol(pol: PolMap) // TODO refactor } this match { case tv @ AssignedVariable(ty) => diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls new file mode 100644 index 0000000000..69646e179b --- /dev/null +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -0,0 +1,78 @@ +:NewParser +:NewDefs +:NoJS + + + +mixin Test { + class Foo(n: int) + let f = Foo(123) +} +//│ mixin Test() { +//│ class Foo(n: int) +//│ let f: Foo +//│ } + +module M: Test +//│ module M() { +//│ class Foo(n: int) +//│ let f: Foo +//│ } + +M.f +//│ Foo + +M.f.n +//│ int + +:e +M.Foo +//│ ╔══[ERROR] Method Foo not found +//│ ║ l.29: M.Foo +//│ ╙── ^^^^^ +//│ error + +:e +mixin Test2 { let f = Foo(1) } +//│ ╔══[ERROR] identifier not found: Foo +//│ ║ l.36: mixin Test2 { let f = Foo(1) } +//│ ╙── ^^^ +//│ mixin Test2() { +//│ let f: error +//│ } + +// FIXME the `Foo` class is not in scope here +mixin Test3 { fun f(x) = if x is Foo then 1 } +//│ mixin Test3() { +//│ fun f: Foo -> 1 +//│ } + + + +:e // TODO +mixin Test { + class Lit(n: int) + class Add(lhs: A, rhs: A) { + let cached = size(this) + } + fun size(x) = if x is + Foo then 1 + Add(l, r) then this.size(l) + this.size(r) +} +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.55: class Add(lhs: A, rhs: A) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.56: let cached = size(this) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.57: } +//│ ╙── ^^^ +//│ mixin Test() { +//│ this: {size: 'lhs -> int} +//│ class Add[A](lhs: A, rhs: A) { +//│ let cached: int +//│ } +//│ class Lit(n: int) +//│ fun size: (Add['lhs] | Foo) -> int +//│ } + + From 3937432a0bad44843a091b02604dd2727b751142 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Feb 2023 23:49:48 +0800 Subject: [PATCH 088/498] Make minor changes to Andong's tests --- shared/src/main/scala/mlscript/Typer.scala | 1 + shared/src/test/diff/nu/Andong.mls | 9 +++- shared/src/test/diff/nu/SimpleRegionDSL.mls | 56 +++++++++------------ 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 87ee6b5749..05607c60ff 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -253,6 +253,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) "log" -> PolymorphicType(MinLevel, fun(singleTup(tv), UnitType)(noProv)), "discard" -> PolymorphicType(MinLevel, fun(singleTup(tv), UnitType)(noProv)), "negate" -> fun(singleTup(IntType), IntType)(noProv), + "round" -> fun(singleTup(DecType), IntType)(noProv), "add" -> intBinOpTy, "sub" -> intBinOpTy, "mul" -> intBinOpTy, diff --git a/shared/src/test/diff/nu/Andong.mls b/shared/src/test/diff/nu/Andong.mls index 405c384ac4..97ed28c23b 100644 --- a/shared/src/test/diff/nu/Andong.mls +++ b/shared/src/test/diff/nu/Andong.mls @@ -2,10 +2,17 @@ :NewDefs :NoJS + class Union(a: Region, b: Region) //│ class Union[Region](a: Region, b: Region) -// ? x is shadowed. Why is b required? +// * [FIXME:UCS] unhygienically desugars to: +// | | | | Desugared term: case x of { Union => let x = (x).a in let y = (x).b in x } fun hmm(x) = if x is Union(x, y) then x //│ fun hmm: Union[{b: anything} & 'a] -> 'a + +fun hmm(x) = + if x is Union(z, y) then x +//│ fun hmm: Union['Region] -> Union['Region] + diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index 3f6bacb77e..f418cc89d0 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -35,24 +35,16 @@ mixin SizeBase { // ******************* Linguistic Reuse and Meta-Language Optimizations ******************* -// FIXME: number or int? fun go(x, offset) = if x is 0 then Circle(1) else - let shared = go(x - 1, offset / 2) + let shared = go(x - 1, round(offset / 2)) Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) -//│ ╔══[ERROR] Type mismatch in expression: -//│ ╟── operator application of type `number` is not an instance of type `int` -//│ ║ l.42: let shared = go(x - 1, offset / 2) -//│ ║ ^^^^^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.43: Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) -//│ ╙── ^^^^^^ //│ fun go: (int, int,) -> 'Region //│ where //│ 'Region :> Circle | Union[Translate['Region]] -// ? forall 'Region. 'Region +// * Note that first-class polymorphism manages (correctly) to preserve que universal quantification let circles = go(20, 1024) //│ let circles: forall 'Region. 'Region //│ where @@ -158,44 +150,44 @@ mixin Text { :e module SizeText: Text //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.159: module SizeText: Text +//│ ║ l.151: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.151: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.143: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.151: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.143: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.159: module SizeText: Text +//│ ║ l.151: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.150: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.142: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.150: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.142: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.159: module SizeText: Text +//│ ║ l.151: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.149: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.141: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.149: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.141: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.159: module SizeText: Text +//│ ║ l.151: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.148: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.140: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.148: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.140: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -307,7 +299,7 @@ module TestElim: Eliminate //│ } //│ where //│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union -//│ 'b :> Union['b] | Intersect['b] | Translate['b] | Scale['b] | Outside['b] +//│ 'b :> Outside['b] | Union['b] | Intersect['b] | Translate['b] | Scale['b] TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a @@ -332,7 +324,7 @@ fun mk(n) = if n is TestElim.eliminate(mk(100)) //│ 'a //│ where -//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ 'a :> Scale['a] | Outside['a] | Union['a] | Intersect['a] | Translate['a] // ************************************************************************* @@ -381,32 +373,32 @@ Lang.size(mk(100)) :e Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.382: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.374: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.327: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.319: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.382: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.374: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.109: if a is +//│ ║ l.101: if a is //│ ╙── ^ //│ error | bool :e Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.398: Lang.text(mk(100)) +//│ ║ l.390: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.327: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.319: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.398: Lang.text(mk(100)) +//│ ║ l.390: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.146: if e is +//│ ║ l.138: if e is //│ ╙── ^ //│ error | string From 850b52f9b56d58d22fa920b38523e0b3dce21144 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 09:11:30 +0800 Subject: [PATCH 089/498] Fix some problems --- .../src/main/scala/mlscript/JSBackend.scala | 193 ++++++++++++++++-- .../main/scala/mlscript/codegen/Codegen.scala | 48 ++++- .../src/test/scala/mlscript/DiffTests.scala | 2 +- 3 files changed, 222 insertions(+), 21 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 60f8755cc3..023ccfc5da 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -258,8 +258,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _), parents) => val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) parents match { - case Some(p) => JSClassExpr(translateClassDeclaration(clsBody, Some(translateTerm(p)))) - case _ => JSClassExpr(translateClassDeclaration(clsBody, N)) + case Some(p) => JSClassExpr(translateNewClassDeclaration(clsBody, Some(translateTerm(p)))) + case _ => JSClassExpr(translateNewClassDeclaration(clsBody, N)) } case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") @@ -412,14 +412,38 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { */ protected def translateClassDeclaration( classSymbol: ClassSymbol, - base: Opt[JSExpr] + baseClassSymbol: Opt[ClassSymbol] )(implicit scope: Scope): JSClassDecl = { - // Translate class methods and getters. + // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") val members = classSymbol.methods.map { translateClassMember(_)(classScope) } // Collect class fields. + val fields = classSymbol.body.collectFields ++ + classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + val base = baseClassSymbol.map { sym => JSIdent(sym.runtimeName) } + val traits = classSymbol.body.collectTypeNames.flatMap { + name => scope.getType(name) match { + case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) + case S(_: ClassSymbol) => N + case S(_: TypeSymbol) => N + case N => N + } + } + JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) + } + + protected def translateNewClassDeclaration( + classSymbol: ClassSymbol, + base: Opt[JSExpr] + )(implicit scope: Scope): JSClassNewDecl = { + // Translate class methods and getters. + val classScope = scope.derive(s"class ${classSymbol.lexicalName}") + val members = classSymbol.methods.map { + translateNewClassMember(_)(classScope) + } + // Collect class fields. val fields = classSymbol.body.collectFields ++ classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) @@ -437,9 +461,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } } if (base.isDefined) - JSClassDecl(classSymbol.runtimeName, fields :+ rest.runtimeName, base, members, traits) + JSClassNewDecl(classSymbol.runtimeName, fields :+ rest.runtimeName, base, members, traits) else - JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) + JSClassNewDecl(classSymbol.runtimeName, fields, base, members, traits) } /** @@ -447,6 +471,42 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { */ private def translateClassMember( method: MethodDef[Left[Term, Type]], + )(implicit scope: Scope): JSClassMemberDecl = { + val name = method.nme.name + // Create the method/getter scope. + val memberScope = method.rhs.value match { + case _: Lam => scope.derive(s"method $name") + case _ => scope.derive(s"getter $name") + } + // Declare the alias for `this` before declaring parameters. + val selfSymbol = memberScope.declareThisAlias() + // Declare parameters. + val (memberParams, body) = method.rhs.value match { + case Lam(params, body) => + val methodParams = translateParams(params)(memberScope) + (S(methodParams), body) + case term => + (N, term) + } + // Translate class member body. + val bodyResult = translateTerm(body)(memberScope).`return` + // If `this` is accessed, add `const self = this`. + val bodyStmts = if (visitedSymbols(selfSymbol)) { + val thisDecl = JSConstDecl(selfSymbol.runtimeName, JSIdent("this")) + visitedSymbols -= selfSymbol + R(thisDecl :: bodyResult :: Nil) + } else { + R(bodyResult :: Nil) + } + // Returns members depending on what it is. + memberParams match { + case S(memberParams) => JSClassMethod(name, memberParams, bodyStmts) + case N => JSClassGetter(name, bodyStmts) + } + } + + private def translateNewClassMember( + method: MethodDef[Left[Term, Type]], )(implicit scope: Scope): JSClassMemberDecl = { val name = method.nme.name // Create the method/getter scope. @@ -577,11 +637,8 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ - sortClassSymbols(classSymbols).map { - case (derived, Some(base)) => - translateClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) - case (derived, None) => - translateClassDeclaration(derived, None)(topLevelScope) + sortClassSymbols(classSymbols).map { case (derived, base) => + translateClassDeclaration(derived, base)(topLevelScope) }.toList val resultsIdent = JSIdent(resultsName) @@ -633,12 +690,19 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { /** * Generate a piece of code for test purpose. It can be invoked repeatedly. */ - def apply(pgrm: Pgrm, allowEscape: Bool): JSTestBackend.Result = - try generate(pgrm)(topLevelScope, allowEscape) catch { - case e: CodeGenError => JSTestBackend.IllFormedCode(e.getMessage()) - case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage()) - case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) - } + def apply(pgrm: Pgrm, allowEscape: Bool, isNewDef: Boolean): JSTestBackend.Result = + if (!isNewDef) + try generate(pgrm)(topLevelScope, allowEscape) catch { + case e: CodeGenError => JSTestBackend.IllFormedCode(e.getMessage()) + case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage()) + case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) + } + else + try generateNewDef(pgrm)(topLevelScope, allowEscape) catch { + case e: CodeGenError => JSTestBackend.IllFormedCode(e.getMessage()) + case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage()) + case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) + } // generate(pgrm)(topLevelScope, allowEscape) /** @@ -652,14 +716,105 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { private def generate(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { val (diags, (typeDefs, otherStmts)) = pgrm.desugared + val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) + val defStmts = + traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ + sortClassSymbols(classSymbols).map { case (derived, base) => + translateClassDeclaration(derived, base)(topLevelScope) + }.toList + + val zeroWidthSpace = JSLit("\"\\u200B\"") + val catchClause = JSCatchClause( + JSIdent("e"), + (zeroWidthSpace + JSIdent("e") + zeroWidthSpace).log() :: Nil + ) + + // Generate statements. + val queries = otherStmts.map { + case Def(recursive, Var(name), L(body), isByname) => + val bodyIsLam = body match { case _: Lam => true case _ => false } + (if (recursive) { + val isByvalueRecIn = if (isByname) None else Some(true) + val sym = scope.declareValue(name, isByvalueRecIn, bodyIsLam) + try { + val translated = translateTerm(body) + scope.unregisterSymbol(sym) + val isByvalueRecOut = if (isByname) None else Some(false) + R((translated, scope.declareValue(name, isByvalueRecOut, bodyIsLam))) + } catch { + case e: UnimplementedError => + scope.stubize(sym, e.symbol) + L(e.getMessage()) + case e: Throwable => + scope.unregisterSymbol(sym) + val isByvalueRecOut = if (isByname) None else Some(false) + scope.declareValue(name, isByvalueRecOut, bodyIsLam) + throw e + } + } else { + (try R(translateTerm(body)) catch { + case e: UnimplementedError => + scope.declareStubValue(name, e.symbol) + L(e.getMessage()) + case e: Throwable => throw e + }) map { + val isByvalueRec = if (isByname) None else Some(false) + expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam)) + } + }) match { + case R((originalExpr, sym)) => + val expr = + if (sym.isByvalueRec.isEmpty && !sym.isLam) + JSArrowFn(Nil, L(originalExpr)) + else + originalExpr + JSTestBackend.CodeQuery( + scope.tempVars.emit(), + ((JSIdent("globalThis").member(sym.runtimeName) := (expr match { + case t: JSArrowFn => t.toFuncExpr(S(sym.runtimeName)) + case t => t + })) :: Nil), + sym.runtimeName + ) + case L(reason) => JSTestBackend.AbortedQuery(reason) + } + case Def(_, Var(name), _, _) => + scope.declareStubValue(name) + JSTestBackend.EmptyQuery + case term: Term => + try { + val body = translateTerm(term)(scope) + val res = JSTestBackend.CodeQuery(scope.tempVars.emit(), (resultIdent := body) :: Nil) + scope.refreshRes() + res + } catch { + case e: UnimplementedError => JSTestBackend.AbortedQuery(e.getMessage()) + case e: Throwable => throw e + } + } + + // If this is the first time, insert the declaration of `res`. + var prelude: Ls[JSStmt] = defStmts + if (numRun === 0) + prelude = JSLetDecl(lastResultSymbol.runtimeName -> N :: Nil) :: prelude + + // Increase the run number. + numRun = numRun + 1 + + JSTestBackend.TestCode(SourceCode.fromStmts(polyfill.emit() ::: prelude).toLines, queries) + } + + private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { + val (diags, (typeDefs, otherStmts)) = pgrm.desugared + val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ sortClassSymbols(classSymbols).map { case (derived, Some(base)) => - translateClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) + translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) case (derived, None) => - translateClassDeclaration(derived, None)(topLevelScope) + translateNewClassDeclaration(derived, None)(topLevelScope) }.toList val zeroWidthSpace = JSLit("\"\\u200B\"") diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 05de0b25cb..728194d710 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -638,7 +638,7 @@ final case class JSRecord(entries: Ls[Str -> JSExpr]) extends JSExpr { }) } -final case class JSClassExpr(cls: JSClassDecl) extends JSExpr { +final case class JSClassExpr(cls: JSClassNewDecl) extends JSExpr { implicit def precedence: Int = 22 def toSourceCode: SourceCode = cls.toSourceCode } @@ -786,6 +786,52 @@ final case class JSClassDecl( `extends`: Opt[JSExpr] = N, methods: Ls[JSClassMemberDecl] = Nil, implements: Ls[Str] = Nil, +) extends JSStmt { + def toSourceCode: SourceCode = { + val constructor: SourceCode = { + val buffer = new ListBuffer[Str]() + buffer += " constructor(fields) {" + if (`extends`.isDefined) + buffer += " super(fields);" + implements.foreach { name => + buffer += s" $name.implement(this);" + } + fields.foreach { name => + val innerName = if (JSField.isValidIdentifier(name)) s".${name}" else s"[${JSLit.makeStringLiteral(name)}]" + buffer += s" this$innerName = fields$innerName;" + } + buffer += " }" + SourceCode(buffer.toList) + } + val methodsSourceCode = + methods.foldLeft(SourceCode.empty) { case (x, y) => + x + y.toSourceCode.indented + } + val epilogue = SourceCode("}") + `extends` match { + case Some(base) => + SourceCode(s"class $name extends ") ++ base.toSourceCode ++ + SourceCode(" {") + constructor + methodsSourceCode + epilogue + case None => + if (fields.isEmpty && methods.isEmpty && implements.isEmpty) { + SourceCode(s"class $name {}") + } else { + SourceCode( + s"class $name {" :: Nil + ) + constructor + methodsSourceCode + epilogue + } + } + } + + private val fieldsSet = collection.immutable.HashSet.from(fields) +} + +final case class JSClassNewDecl( + name: Str, + fields: Ls[Str], + `extends`: Opt[JSExpr] = N, + methods: Ls[JSClassMemberDecl] = Nil, + implements: Ls[Str] = Nil, ) extends JSStmt { def toSourceCode: SourceCode = { val constructor: SourceCode = { diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 32931726a6..92523840c7 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -824,7 +824,7 @@ class DiffTests val executionResults: Result \/ Ls[(ReplHost.Reply, Str)] = if (!allowTypeErrors && file.ext =:= "mls" && !mode.noGeneration && !noJavaScript) { import codeGenTestHelpers._ - backend(p, mode.allowEscape) match { + backend(p, mode.allowEscape, newDefs && newParser) match { case testCode @ TestCode(prelude, queries) => { // Display the generated code. if (mode.showGeneratedJS) showGeneratedCode(testCode) From d2443a2c4585206f476a0db643860afe2b29e764 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 09:33:29 +0800 Subject: [PATCH 090/498] Keep original tests untouched --- .../src/main/scala/mlscript/JSBackend.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 188 ++++++++++++------ 2 files changed, 125 insertions(+), 65 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 023ccfc5da..a969e08886 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -805,7 +805,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { } private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { - val (diags, (typeDefs, otherStmts)) = pgrm.desugared + val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) val defStmts = diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 13ecb6f5fb..e506c24faa 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -343,7 +343,96 @@ trait PgrmImpl { self: Pgrm => } diags.toList -> res } + lazy val newDesugared: (Ls[Diagnostic] -> (Ls[TypeDef], Ls[Terms])) = { + val diags = Buffer.empty[Diagnostic] + val res = tops.flatMap { s => s match { + case nd: NuTypeDef => { + val (ds, d) = desugaredNewDec(nd) + diags ++= ds + d + } + case _ => { + val (ds, d) = s.desugared + diags ++= ds + d + } + } + }.partitionMap { + case td: TypeDef => L(td) + case ot: Terms => R(ot) + case NuFunDef(isLetRec, nme, tys, rhs) => + R(Def(isLetRec.getOrElse(true), nme, rhs, isLetRec.isEmpty)) + } + diags.toList -> res + } override def toString = tops.map("" + _ + ";").mkString(" ") + + private def desugaredNewDec(nd: NuTypeDef): Ls[Diagnostic] -> Ls[DesugaredStatement] = nd match { + case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => + val bases = pars.foldLeft(Var("base"): Term)((res, p) => p match { + case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) + case _ => ??? + }) + val (diags, ds) = + desugaredNewDec(NuTypeDef(Cls, TypeName(mxName), tps, tup, Ls(bases), sup, ths, unit)) + ds match { + case (cls: TypeDef) :: _ => diags -> (NuFunDef(None, Var(mxName), List(), Left(Lam(Tup(Ls(None -> Fld(false, false, Var("base")))), ClassExpression(cls, S(bases))))) :: Nil) + case _ => ??? + } + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + if (pars.length > 0) { + val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { + case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) + case _ => ??? + }) + val (diags, ds) = + desugaredNewDec(NuTypeDef(Cls, nme, tps, tup, Ls(bases), sup, ths, unit)) + val termName = Var(nme.name).withLocOf(nme) + ds match { + case (cls: TypeDef) :: _ => diags -> (Def(false, termName, Left(App(ClassExpression(cls, S(bases)), Tup(Ls()))), true) :: Nil) + case _ => ??? + } + } + else ??? + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + // TODO properly check: + require(fs.isEmpty, fs) + require(pars.size === 1, pars) + require(ths.isEmpty, ths) + require(unit.entities.isEmpty, unit) + val (diags, rhs) = pars.head.toType match { + case L(ds) => (ds :: Nil) -> Top + case R(ty) => Nil -> ty + } + diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + val diags = Buffer.empty[Diagnostic] + def tt(trm: Term): Type = trm.toType match { + case L(ds) => diags += ds; Top + case R(ty) => ty + } + val params = fs.map { + case (S(nme), Fld(mut, spec, trm)) => + val ty = tt(trm) + nme -> Field(if (mut) S(ty) else N, ty) + case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) + case _ => die + } + val pos = params.unzip._1 + val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) + val termName = Var(nme.name).withLocOf(nme) + val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(fs.map { + case (S(nme), fld) => N -> Fld(false, false, nme) + case (N, fld @ Fld(mut, spec, nme: Var)) => N -> Fld(false, false, nme) + case _ => die + })))), true) + val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) + case _ => lst + }) + // TODO: mthDecls + diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, mthDefs, pos) :: ctor :: Nil) + } } object OpApp { @@ -704,70 +793,41 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => - val bases = pars.foldLeft(Var("base"): Term)((res, p) => p match { - case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) - case _ => ??? - }) - val (diags, ds) = - NuTypeDef(Cls, TypeName(mxName), tps, tup, Ls(bases), sup, ths, unit).desugared - ds match { - case (cls: TypeDef) :: _ => diags -> (NuFunDef(None, Var(mxName), List(), Left(Lam(Tup(Ls(None -> Fld(false, false, Var("base")))), ClassExpression(cls, S(bases))))) :: Nil) - case _ => ??? - } - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - if (pars.length > 0) { - val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { - case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) - case _ => ??? - }) - val (diags, ds) = - NuTypeDef(Cls, nme, tps, tup, Ls(bases), sup, ths, unit).desugared - val termName = Var(nme.name).withLocOf(nme) - ds match { - case (cls: TypeDef) :: _ => diags -> (Def(false, termName, Left(App(ClassExpression(cls, S(bases)), Tup(Ls()))), true) :: Nil) - case _ => ??? - } - } - else ??? - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - // TODO properly check: - require(fs.isEmpty, fs) - require(pars.size === 1, pars) - require(ths.isEmpty, ths) - require(unit.entities.isEmpty, unit) - val (diags, rhs) = pars.head.toType match { - case L(ds) => (ds :: Nil) -> Top - case R(ty) => Nil -> ty - } - diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - val diags = Buffer.empty[Diagnostic] - def tt(trm: Term): Type = trm.toType match { - case L(ds) => diags += ds; Top - case R(ty) => ty - } - val params = fs.map { - case (S(nme), Fld(mut, spec, trm)) => - val ty = tt(trm) - nme -> Field(if (mut) S(ty) else N, ty) - case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) - case _ => die - } - val pos = params.unzip._1 - val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) - val termName = Var(nme.name).withLocOf(nme) - val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(fs.map { - case (S(nme), fld) => N -> Fld(false, false, nme) - case (N, fld @ Fld(mut, spec, nme: Var)) => N -> Fld(false, false, nme) - case _ => die - })))), true) - val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { - case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) - case _ => lst - }) - // TODO: mthDecls - diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, mthDefs, pos) :: ctor :: Nil) + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + ??? // TODO + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + // TODO properly check: + require(fs.isEmpty, fs) + require(pars.size === 1, pars) + require(ths.isEmpty, ths) + require(unit.entities.isEmpty, unit) + val (diags, rhs) = pars.head.toType match { + case L(ds) => (ds :: Nil) -> Top + case R(ty) => Nil -> ty + } + diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + val diags = Buffer.empty[Diagnostic] + def tt(trm: Term): Type = trm.toType match { + case L(ds) => diags += ds; Top + case R(ty) => ty + } + val params = fs.map { + case (S(nme), Fld(mut, spec, trm)) => + val ty = tt(trm) + nme -> Field(if (mut) S(ty) else N, ty) + case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) + case _ => die + } + val pos = params.unzip._1 + val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) + val termName = Var(nme.name).withLocOf(nme) + val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(false, false, Rcd(fs.map { + case (S(nme), fld) => nme -> Fld(false, false, nme) + case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld + case _ => die + })) :: Nil)))), true) + diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, Nil, pos) :: ctor :: Nil) case d: DesugaredStatement => Nil -> (d :: Nil) } import Message._ From 72992905ad251a07baae205d845c94ecf5307105 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 14:16:49 +0800 Subject: [PATCH 091/498] Add new style class --- .../src/main/scala/mlscript/JSBackend.scala | 49 ++++++++++-- shared/src/main/scala/mlscript/helpers.scala | 7 +- shared/src/test/diff/nu/ECOOP23_codegen.mls | 74 +++++++++++-------- 3 files changed, 87 insertions(+), 43 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index a969e08886..a780b9f5f9 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -20,6 +20,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected val polyfill = Polyfill() protected val visitedSymbols = MutSet[ValueSymbol]() + protected val moduleName = "" /** * This function translates parameter destructions in `def` declarations. @@ -99,9 +100,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: ClassSymbol) => if (isCallee) - JSNew(JSIdent(sym.runtimeName)) + JSNew(JSIdent(s"$moduleName${sym.runtimeName}")) else - JSArrowFn(JSNamePattern("x") :: Nil, L(JSNew(JSIdent(sym.runtimeName))(JSIdent("x")))) + JSArrowFn(JSNamePattern("x") :: Nil, L(JSNew(JSIdent(s"$moduleName${sym.runtimeName}"))(JSIdent("x")))) case S(sym: TraitSymbol) => JSIdent(sym.lexicalName)("build") case N => scope.getType(name) match { @@ -258,8 +259,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _), parents) => val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) parents match { - case Some(p) => JSClassExpr(translateNewClassDeclaration(clsBody, Some(translateTerm(p)))) - case _ => JSClassExpr(translateNewClassDeclaration(clsBody, N)) + case Some(p) => JSClassExpr(translateNewClassExpression(clsBody, Some(translateTerm(p)))) + case _ => JSClassExpr(translateNewClassExpression(clsBody, N)) } case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") @@ -290,7 +291,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // JS is dumb so `instanceof String` won't actually work on "primitive" strings... JSBinary("===", scrut.member("constructor"), JSLit("String")) case Var(name) => topLevelScope.getType(name) match { - case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(runtimeName)) + case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(s"$moduleName$runtimeName")) case S(TraitSymbol(_, runtimeName, _, _, _)) => JSIdent(runtimeName)("is")(scrut) case S(_: TypeAliasSymbol) => throw new CodeGenError(s"cannot match type alias $name") case N => throw new CodeGenError(s"unknown match case: $name") @@ -435,6 +436,35 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def translateNewClassDeclaration( + classSymbol: ClassSymbol, + base: Opt[JSExpr], + module: Str + )(implicit scope: Scope): JSExprStmt = { + val getterScope = scope.derive(s"${classSymbol.lexicalName} getter") + val classBody = translateNewClassExpression(classSymbol, base)(getterScope) + val constructor = classBody match { + case JSClassNewDecl(_, fields, _, _, _) => fields.map(JSNamePattern(_)) + } + val params = classBody match { + case JSClassNewDecl(_, fields, _, _, _) => fields.map(JSIdent(_)) + } + + JSExprStmt(JSInvoke(JSField(JSIdent("Object"), "defineProperty"), + Ls(JSIdent(module), JSLit(JSLit.makeStringLiteral(classSymbol.lexicalName)), JSRecord(Ls( + "get" -> JSFuncExpr(N, Ls(), Ls( + JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSIdent("undefined")), Ls( + JSExprStmt(JSClassExpr(classBody)), + JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), + JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), + JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(classSymbol.lexicalName))) + )), + JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName))) + )) + ))) + )) + } + + protected def translateNewClassExpression( classSymbol: ClassSymbol, base: Opt[JSExpr] )(implicit scope: Scope): JSClassNewDecl = { @@ -684,9 +714,12 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { private val lastResultSymbol = topLevelScope.declareValue("res", Some(false), false) private val resultIdent = JSIdent(lastResultSymbol.runtimeName) + private val mlsModule = topLevelScope.declareValue("__mls_modules__", Some(false), false) private var numRun = 0 + override protected val moduleName: String = s"${mlsModule.runtimeName}." + /** * Generate a piece of code for test purpose. It can be invoked repeatedly. */ @@ -812,9 +845,9 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ sortClassSymbols(classSymbols).map { case (derived, Some(base)) => - translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) + translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), mlsModule.runtimeName)(topLevelScope) case (derived, None) => - translateNewClassDeclaration(derived, None)(topLevelScope) + translateNewClassDeclaration(derived, None, mlsModule.runtimeName)(topLevelScope) }.toList val zeroWidthSpace = JSLit("\"\\u200B\"") @@ -890,7 +923,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { // If this is the first time, insert the declaration of `res`. var prelude: Ls[JSStmt] = defStmts if (numRun === 0) - prelude = JSLetDecl(lastResultSymbol.runtimeName -> N :: Nil) :: prelude + prelude = JSLetDecl(lastResultSymbol.runtimeName -> N :: Nil) :: JSLetDecl(Ls(mlsModule.runtimeName -> S(JSRecord(Ls("cache" -> JSRecord(Ls())))))) :: prelude // Increase the run number. numRun = numRun + 1 diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index e506c24faa..6e81c63872 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -421,17 +421,12 @@ trait PgrmImpl { self: Pgrm => val pos = params.unzip._1 val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) val termName = Var(nme.name).withLocOf(nme) - val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(fs.map { - case (S(nme), fld) => N -> Fld(false, false, nme) - case (N, fld @ Fld(mut, spec, nme: Var)) => N -> Fld(false, false, nme) - case _ => die - })))), true) val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) case _ => lst }) // TODO: mthDecls - diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, mthDefs, pos) :: ctor :: Nil) + diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, mthDefs, pos) :: Nil) } } diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 44156fe5ef..c2e18f6ae2 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -8,25 +8,36 @@ class Lit(n: int) //│ class Lit(n: int) //│ // Prelude //│ let res; -//│ class Add { -//│ constructor(lhs, rhs) { -//│ this.lhs = lhs; -//│ this.rhs = rhs; +//│ let __mls_modules__ = { cache: {} }; +//│ Object.defineProperty(__mls_modules__, "Add", { +//│ get: function () { +//│ if (this.cache.Add === undefined) { +//│ class Add { +//│ constructor(lhs, rhs) { +//│ this.lhs = lhs; +//│ this.rhs = rhs; +//│ } +//│ }; +//│ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ this.cache.Add["class"] = Add; +//│ } +//│ return this.cache.Add; //│ } -//│ } -//│ class Lit { -//│ constructor(n) { -//│ this.n = n; +//│ }); +//│ Object.defineProperty(__mls_modules__, "Lit", { +//│ get: function () { +//│ if (this.cache.Lit === undefined) { +//│ class Lit { +//│ constructor(n) { +//│ this.n = n; +//│ } +//│ }; +//│ this.cache.Lit = ((n) => new Lit(n)); +//│ this.cache.Lit["class"] = Lit; +//│ } +//│ return this.cache.Lit; //│ } -//│ } -//│ // Query 1 -//│ globalThis.Add1 = function Add1(lhs, rhs) { -//│ return new Add(lhs, rhs); -//│ }; -//│ // Query 2 -//│ globalThis.Lit1 = function Lit1(n) { -//│ return new Lit(n); -//│ }; +//│ }); //│ // End of generated code :js @@ -50,7 +61,7 @@ mixin EvalBase { //│ const self = this; //│ return ((() => { //│ let a; -//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ return (a = e, a instanceof __mls_modules__.Lit ? ((n) => n)(e.n) : a instanceof __mls_modules__.Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { //│ throw new Error("non-exhaustive case expression"); //│ })()); //│ })()); @@ -63,15 +74,20 @@ mixin EvalBase { class Neg(expr: A) //│ class Neg[A](expr: A) //│ // Prelude -//│ class Neg { -//│ constructor(expr) { -//│ this.expr = expr; +//│ Object.defineProperty(__mls_modules__, "Neg", { +//│ get: function () { +//│ if (this.cache.Neg === undefined) { +//│ class Neg { +//│ constructor(expr) { +//│ this.expr = expr; +//│ } +//│ }; +//│ this.cache.Neg = ((expr) => new Neg(expr)); +//│ this.cache.Neg["class"] = Neg; +//│ } +//│ return this.cache.Neg; //│ } -//│ } -//│ // Query 1 -//│ globalThis.Neg1 = function Neg1(expr) { -//│ return new Neg(expr); -//│ }; +//│ }); //│ // End of generated code :js @@ -94,7 +110,7 @@ mixin EvalNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ return e instanceof __mls_modules__.Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); @@ -121,7 +137,7 @@ mixin EvalNegNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ return e instanceof __mls_modules__.Neg ? ((tmp0) => tmp0 instanceof __mls_modules__.Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); @@ -158,7 +174,7 @@ TestLang.eval(mk(0)) //│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] //│ // Query 1 //│ globalThis.mk = function mk(n) { -//│ return n == 0 === true ? Lit1(0) : n == 1 === true ? Neg1(mk(n)) : Add1(mk(n), mk(n)); +//│ return n == 0 === true ? new __mls_modules__.Lit(0) : n == 1 === true ? new __mls_modules__.Neg(mk(n)) : new __mls_modules__.Add(mk(n), mk(n)); //│ }; //│ // Query 2 //│ res = TestLang1().eval(mk(0)); From f886c4d7216bbb244dbc73b19e9e921d0c0b2347 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 14:21:43 +0800 Subject: [PATCH 092/498] Fix wrong override --- shared/src/main/scala/mlscript/JSBackend.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index a780b9f5f9..56a6fcdb95 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -20,7 +20,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected val polyfill = Polyfill() protected val visitedSymbols = MutSet[ValueSymbol]() - protected val moduleName = "" + protected var moduleName = "" /** * This function translates parameter destructions in `def` declarations. @@ -718,8 +718,6 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { private var numRun = 0 - override protected val moduleName: String = s"${mlsModule.runtimeName}." - /** * Generate a piece of code for test purpose. It can be invoked repeatedly. */ @@ -838,6 +836,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { } private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { + moduleName = s"${mlsModule.runtimeName}." // enable new def val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) From 3ab30b31e7d7c87128e25f69fc7aba45b52a12c6 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 16:33:56 +0800 Subject: [PATCH 093/498] Add new constructor --- .../src/main/scala/mlscript/JSBackend.scala | 98 ++++++++++++++++--- .../main/scala/mlscript/codegen/Codegen.scala | 14 ++- shared/src/main/scala/mlscript/helpers.scala | 34 +++---- shared/src/test/diff/nu/Super.mls | 49 ++++++++++ 4 files changed, 156 insertions(+), 39 deletions(-) create mode 100644 shared/src/test/diff/nu/Super.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 56a6fcdb95..61445e500b 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -3,7 +3,7 @@ package mlscript import mlscript.utils._, shorthands._, algorithms._ import mlscript.codegen.Helpers._ import mlscript.codegen._ -import scala.collection.mutable.ListBuffer +import scala.collection.mutable.{ListBuffer, HashMap} import mlscript.{JSField, JSLit} import scala.collection.mutable.{Set => MutSet} import scala.util.control.NonFatal @@ -438,15 +438,17 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateNewClassDeclaration( classSymbol: ClassSymbol, base: Opt[JSExpr], - module: Str + module: Str, + superFields: Ls[Term] = Nil, + rest: Opt[Str] = N )(implicit scope: Scope): JSExprStmt = { val getterScope = scope.derive(s"${classSymbol.lexicalName} getter") - val classBody = translateNewClassExpression(classSymbol, base)(getterScope) + val classBody = translateNewClassExpression(classSymbol, base, superFields, rest)(getterScope) val constructor = classBody match { - case JSClassNewDecl(_, fields, _, _, _) => fields.map(JSNamePattern(_)) + case JSClassNewDecl(_, fields, _, _, _, _, _) => fields.map(JSNamePattern(_)) } val params = classBody match { - case JSClassNewDecl(_, fields, _, _, _) => fields.map(JSIdent(_)) + case JSClassNewDecl(_, fields, _, _, _, _, _) => fields.map(JSIdent(_)) } JSExprStmt(JSInvoke(JSField(JSIdent("Object"), "defineProperty"), @@ -466,7 +468,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateNewClassExpression( classSymbol: ClassSymbol, - base: Opt[JSExpr] + base: Opt[JSExpr], + superFields: Ls[Term] = Nil, + rest: Opt[Str] = N )(implicit scope: Scope): JSClassNewDecl = { // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") @@ -479,7 +483,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") fields.foreach(constructorScope.declareValue(_, Some(false), false)) - val rest = constructorScope.declareValue("rest", Some(false), false) + val restRuntime = rest.flatMap(name => S(constructorScope.declareValue(name, Some(false), false).runtimeName)) // val base = baseClassSymbol.map { sym => JSIdent(sym.runtimeName) } val traits = classSymbol.body.collectTypeNames.flatMap { @@ -490,10 +494,18 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case N => N } } - if (base.isDefined) - JSClassNewDecl(classSymbol.runtimeName, fields :+ rest.runtimeName, base, members, traits) - else - JSClassNewDecl(classSymbol.runtimeName, fields, base, members, traits) + + val superParameters = (superFields map { + case App(lhs, Tup(rhs)) => rhs map { + case (_, Fld(mut, spec, trm)) => translateTerm(trm)(constructorScope) + } + case _ => ??? // TODO: throw? + }).flatten + + JSClassNewDecl(classSymbol.runtimeName, fields, base, restRuntime match { + case Some(restRuntime) => superParameters :+ JSIdent(s"...$restRuntime") + case _ => superParameters + }, restRuntime, members, traits) } /** @@ -593,6 +605,60 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { (traits.toList, classes.toList) } + protected def declareNewTypeDefs(typeDefs: Ls[NuTypeDef]): (Ls[TraitSymbol], Ls[ClassSymbol], HashMap[String, Ls[Term]]) = { + val traits = new ListBuffer[TraitSymbol]() + val classes = new ListBuffer[ClassSymbol]() + val superParameters = HashMap[String, Ls[Term]]() + def tt(trm: Term): Type = trm.toType match { + case L(ds) => Top + case R(ty) => ty + } + + typeDefs.foreach { + case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => ??? + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => ??? + case NuTypeDef(Als, TypeName(nme), tps, _, pars, _, _, _) => { + val body = tt(pars.head) + topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, body) + } + case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + val params = fs.map { + case (S(nme), Fld(mut, spec, trm)) => + val ty = tt(trm) + nme -> Field(if (mut) S(ty) else N, ty) + case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) + case _ => die + } + val body = pars.map(tt).foldRight(Record(params): Type)(Inter) + val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) + case _ => lst + }) + val sym = topLevelScope.declareClass(nme, tps map { _._2.name }, body, members) + classes += sym + superParameters.put(sym.lexicalName, pars) + } + case NuTypeDef(k @ Trt, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + val params = fs.map { + case (S(nme), Fld(mut, spec, trm)) => + val ty = tt(trm) + nme -> Field(if (mut) S(ty) else N, ty) + case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) + case _ => die + } + val body = pars.map(tt).foldRight(Record(params): Type)(Inter) + val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) + case _ => lst + }) + val sym = topLevelScope.declareTrait(nme, tps map { _._2.name }, body, members) + traits += sym + superParameters.put(sym.lexicalName, pars) + } + } + (traits.toList, classes.toList, superParameters) + } + /** * Recursively collect fields from trait definitions. * Caveat: this might cause stack overflow if cyclic inheritance exists. @@ -839,12 +905,16 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { moduleName = s"${mlsModule.runtimeName}." // enable new def val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared - val (traitSymbols, classSymbols) = declareTypeDefs(typeDefs) + val (traitSymbols, classSymbols, superParameters) = declareNewTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ sortClassSymbols(classSymbols).map { - case (derived, Some(base)) => - translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), mlsModule.runtimeName)(topLevelScope) + case (derived, Some(base)) => { + superParameters.get(derived.lexicalName) match { + case Some(sp) => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), mlsModule.runtimeName, sp)(topLevelScope) + case _ => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), mlsModule.runtimeName)(topLevelScope) + } + } case (derived, None) => translateNewClassDeclaration(derived, None, mlsModule.runtimeName)(topLevelScope) }.toList diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 728194d710..e69cfdb5a6 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -830,6 +830,8 @@ final case class JSClassNewDecl( name: Str, fields: Ls[Str], `extends`: Opt[JSExpr] = N, + superFields: Ls[JSExpr] = Nil, + rest: Opt[Str] = N, methods: Ls[JSClassMemberDecl] = Nil, implements: Ls[Str] = Nil, ) extends JSStmt { @@ -837,12 +839,18 @@ final case class JSClassNewDecl( val constructor: SourceCode = { val buffer = new ListBuffer[Str]() val params = fields.iterator.zipWithIndex.foldLeft("")((s, p) => - if (p._2 === fields.length - 1) (if(`extends`.isDefined) s"$s...${p._1}" else s"$s${p._1}") + if (p._2 === fields.length - 1) (rest match { + case Some(rest) => s"$s${p._1}, ...$rest" + case _ => s"$s${p._1}" + }) else s"$s${p._1}, ") buffer += s" constructor($params) {" if (`extends`.isDefined) { - val restName = if (fields.length > 0) fields.last else ??? // TODO: throw? - buffer += s" super(...$restName);" + val sf = superFields.iterator.zipWithIndex.foldLeft("")((res, p) => + if (p._2 === superFields.length - 1) s"$res${p._1.toSourceCode}" + else s"$res${p._1.toSourceCode}, " + ) + buffer += s" super($sf);" } implements.foreach { name => buffer += s" $name.implement(this);" diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 6e81c63872..b89bf9f891 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -343,13 +343,12 @@ trait PgrmImpl { self: Pgrm => } diags.toList -> res } - lazy val newDesugared: (Ls[Diagnostic] -> (Ls[TypeDef], Ls[Terms])) = { + lazy val newDesugared: (Ls[Diagnostic] -> (Ls[NuTypeDef], Ls[Terms])) = { val diags = Buffer.empty[Diagnostic] val res = tops.flatMap { s => s match { case nd: NuTypeDef => { - val (ds, d) = desugaredNewDec(nd) - diags ++= ds - d + diags ++= tryDesugaredNewDec(nd) + Ls(nd) } case _ => { val (ds, d) = s.desugared @@ -358,8 +357,8 @@ trait PgrmImpl { self: Pgrm => } } }.partitionMap { - case td: TypeDef => L(td) case ot: Terms => R(ot) + case nd: NuTypeDef => L(nd) case NuFunDef(isLetRec, nme, tys, rhs) => R(Def(isLetRec.getOrElse(true), nme, rhs, isLetRec.isEmpty)) } @@ -367,33 +366,24 @@ trait PgrmImpl { self: Pgrm => } override def toString = tops.map("" + _ + ";").mkString(" ") - private def desugaredNewDec(nd: NuTypeDef): Ls[Diagnostic] -> Ls[DesugaredStatement] = nd match { + private def tryDesugaredNewDec(nd: NuTypeDef): Ls[Diagnostic] = nd match { case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => val bases = pars.foldLeft(Var("base"): Term)((res, p) => p match { case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) case _ => ??? }) - val (diags, ds) = - desugaredNewDec(NuTypeDef(Cls, TypeName(mxName), tps, tup, Ls(bases), sup, ths, unit)) - ds match { - case (cls: TypeDef) :: _ => diags -> (NuFunDef(None, Var(mxName), List(), Left(Lam(Tup(Ls(None -> Fld(false, false, Var("base")))), ClassExpression(cls, S(bases))))) :: Nil) - case _ => ??? - } + tryDesugaredNewDec(NuTypeDef(Cls, TypeName(mxName), tps, tup, Ls(bases), sup, ths, unit)) case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => if (pars.length > 0) { val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) case _ => ??? }) - val (diags, ds) = - desugaredNewDec(NuTypeDef(Cls, nme, tps, tup, Ls(bases), sup, ths, unit)) - val termName = Var(nme.name).withLocOf(nme) - ds match { - case (cls: TypeDef) :: _ => diags -> (Def(false, termName, Left(App(ClassExpression(cls, S(bases)), Tup(Ls()))), true) :: Nil) - case _ => ??? - } + tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, Ls(bases), sup, ths, unit)) + } + else { + tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, Ls(), sup, ths, unit)) } - else ??? case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) @@ -404,7 +394,7 @@ trait PgrmImpl { self: Pgrm => case L(ds) => (ds :: Nil) -> Top case R(ty) => Nil -> ty } - diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) + diags case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { @@ -426,7 +416,7 @@ trait PgrmImpl { self: Pgrm => case _ => lst }) // TODO: mthDecls - diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, mthDefs, pos) :: Nil) + diags.toList } } diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls new file mode 100644 index 0000000000..76fd90a863 --- /dev/null +++ b/shared/src/test/diff/nu/Super.mls @@ -0,0 +1,49 @@ +:NewParser +:NewDefs + +:js +class Foo(x: int) +//│ class Foo(x: int) +//│ // Prelude +//│ let res; +//│ let __mls_modules__ = { cache: {} }; +//│ Object.defineProperty(__mls_modules__, "Foo", { +//│ get: function () { +//│ if (this.cache.Foo === undefined) { +//│ class Foo { +//│ constructor(x) { +//│ this.x = x; +//│ } +//│ }; +//│ this.cache.Foo = ((x) => new Foo(x)); +//│ this.cache.Foo["class"] = Foo; +//│ } +//│ return this.cache.Foo; +//│ } +//│ }); +//│ // End of generated code + +:js +:e +class Bar(x: int, y: int): Foo(x + y) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.28: class Bar(x: int, y: int): Foo(x + y) +//│ ╙── ^^^^^^^^^^ +//│ class Bar(x: int, y: int) +//│ // Prelude +//│ Object.defineProperty(__mls_modules__, "Bar", { +//│ get: function () { +//│ if (this.cache.Bar === undefined) { +//│ class Bar extends Foo { +//│ constructor(x, y) { +//│ super(x + y); +//│ this.x = x; +//│ } +//│ }; +//│ this.cache.Bar = ((x, y) => new Bar(x, y)); +//│ this.cache.Bar["class"] = Bar; +//│ } +//│ return this.cache.Bar; +//│ } +//│ }); +//│ // End of generated code From 43fb7239b59f29be75d9ffe65084c9d0b61915c3 Mon Sep 17 00:00:00 2001 From: Andong Fan Date: Sun, 26 Feb 2023 16:40:43 +0800 Subject: [PATCH 094/498] WIP Add poly variants example --- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls new file mode 100644 index 0000000000..5097508ded --- /dev/null +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -0,0 +1,165 @@ +:NewParser +:NewDefs +:NoJS + +// Adapted example from Code reuse through polymorphic variants (FOSE 2000) +class Nil +//│ class Nil() + +// ? why tuple type (Cons[A] | Nil,) +class Cons(head: A, tail: Cons | Nil) +//│ class Cons[A](head: A, tail: (Cons[A] | Nil,)) + +// FIXME +let l = Cons(1, Nil()) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.14: let l = Cons(1, Nil()) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── application of type `Nil` is not a 1-element tuple +//│ ║ l.14: let l = Cons(1, Nil()) +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from tuple type: +//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) +//│ ╙── ^^^^^^^ +//│ let l: Cons['A] | error +//│ where +//│ 'A :> 1 + +class NotFound +class Success(result: A) +//│ class NotFound() +//│ class Success[A](result: A) + +fun eq(l: string, r: string): bool +//│ fun eq: (l: string, r: string,) -> bool + +// FIXME +fun list_assoc(s, l) = + if l is + Cons(h, t) then + if eq(s, h._1) then Success(h._2) + else list_assoc(s, t) + Nil then NotFound() +//│ ╔══[ERROR] Type mismatch in expression: +//│ ╟── type `(Cons[?A] | Nil,)` does not match type `Cons[?A0] | Nil` +//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) +//│ ║ ^^^^^^^ +//│ ╟── but it flows into reference with expected type `Cons[?A1] | Nil` +//│ ║ l.38: if l is +//│ ╙── ^ +//│ fun list_assoc: (string, Cons['A] | Nil,) -> (NotFound | Success['A0]) +//│ where +//│ 'A <: {_1: string, _2: 'A0} + +// fun list_assoc(s: string, l: Cons<{ _1: string, _2: 'b }> | Nil): NotFound | Success['b] + +class Var(s: string) +//│ class Var(s: string) + +mixin EvalVar { + fun eval(sub, v) = + if v is Var(s) then + if list_assoc(s, sub) is + NotFound then v + Success(r) then r +} +//│ mixin EvalVar() { +//│ fun eval: (Cons['A] | Nil, Var,) -> (Var | 'result) +//│ } +//│ where +//│ 'A <: {_1: string, _2: 'result} + +class Abs(x: string, t: A) +class App(s: A, t: A) +//│ class Abs[A](x: string, t: A) +//│ class App[A](s: A, t: A) + +fun incr(x: {a: int}): unit +//│ fun incr: (x: {a: int},) -> unit + +fun gensym(): string +//│ fun gensym: () -> string + +fun int_to_string(x: int): string +//│ fun int_to_string: (x: int,) -> string + +// FIXME +mixin EvalLambda { + fun eval(sub, v) = + if v is + App(t1, t2) then + let l1 = this.eval(sub, t1) + let l2 = this.eval(sub, t2) + if t1 is + Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) + else + App(l1, l2) + Abs(x, t) then + let s = gensym() + Abs(s, this.eval(Cons((x, Var(s)), sub), t)) + else + super.eval(sub, v) +} +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.94: Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Nil` is not a 1-element tuple +//│ ║ l.94: Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from tuple type: +//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) +//│ ╙── ^^^^^^^ +//│ mixin EvalLambda() { +//│ super: {eval: ('a, 'b,) -> 'c} +//│ this: {eval: (Cons[in 'A out (string, 'd,) | 'A] | error, 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[in 'A0 out (string, Var,) | 'A0 | 'A1], 't1,) -> 'f} +//│ fun eval: ((Cons['A2] | Nil,) & 'a, Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) +//│ } +//│ where +//│ 'A2 :> (string, Var,) | 'A0 +//│ <: 'A1 + +// def eval_lambda eval_rec subst v = case v of { +// | Var -> eval_var subst v +// | App -> let l2 = eval_rec subst v.lhs in +// let l1 = eval_rec subst v.rhs in +// case l1 of { +// | Abs -> eval_rec (Cons (Tuple l1.name l2) Nil) l1.body +// | _ -> App { lhs = l1; rhs = l2 } +// } +// | Abs -> let new_name = int_to_string ((gensym ())._2.a) in +// Abs { name = new_name; +// body = eval_rec (Cons (Tuple v.name (Var { name = new_name })) subst) v.body } +// } + +// FIXME +module Test1: EvalVar, EvalLambda +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.135: module Test1: EvalVar, EvalLambda +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Cons[in ?A out ?A0]` is not a 1-element tuple +//│ ║ l.99: Abs(s, this.eval(Cons((x, Var(s)), sub), t)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple type: +//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) +//│ ║ ^^^^^^^ +//│ ╟── from reference: +//│ ║ l.99: Abs(s, this.eval(Cons((x, Var(s)), sub), t)) +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.135: module Test1: EvalVar, EvalLambda +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Cons[in ?A out ?A0]` is not a 1-element tuple +//│ ║ l.94: Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple type: +//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) +//│ ║ ^^^^^^^ +//│ ╟── from reference: +//│ ║ l.99: Abs(s, this.eval(Cons((x, Var(s)), sub), t)) +//│ ╙── ^^^ +//│ module Test1() { +//│ fun eval: (nothing, 'a,) -> 'result +//│ } +//│ where +//│ 'result :> Var | App['result] | Abs['result] +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | Var From f1c3118c4cae2eb8919836a00f74bc676f2d308b Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 19:28:32 +0800 Subject: [PATCH 095/498] Finish refactor --- .../src/main/scala/mlscript/JSBackend.scala | 172 +++++++++++++++--- .../main/scala/mlscript/codegen/Codegen.scala | 13 +- .../main/scala/mlscript/codegen/Scope.scala | 27 ++- .../main/scala/mlscript/codegen/Symbol.scala | 32 ++++ shared/src/test/diff/nu/ECOOP23_codegen.mls | 33 ++-- 5 files changed, 229 insertions(+), 48 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 61445e500b..ad224a38b7 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -98,6 +98,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { visitedSymbols += sym val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident + case S(sym: MixinSymbol) => + JSIdent(s"$moduleName${sym.runtimeName}") + case S(sym: ModuleSymbol) => + JSIdent(s"$moduleName${sym.runtimeName}") case S(sym: ClassSymbol) => if (isCallee) JSNew(JSIdent(s"$moduleName${sym.runtimeName}")) @@ -435,6 +439,84 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) } + protected def translateMixinDeclaration( + mixinSymbol: MixinSymbol, + module: Str + )(implicit scope: Scope): JSExprStmt = { + val getterScope = scope.derive(s"getter ${mixinSymbol.lexicalName}") + val mixinScope = getterScope.derive(s"mixin ${mixinSymbol.lexicalName}") + mixinScope.declareSuper() + val members = mixinSymbol.methods.map { + translateClassMember(_)(mixinScope) + } + // Collect class fields. + val fields = mixinSymbol.body.collectFields ++ + mixinSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + val constructorScope = mixinScope.derive(s"${mixinSymbol.lexicalName} constructor") + fields.foreach(constructorScope.declareValue(_, Some(false), false)) + val rest = constructorScope.declareValue("rest", Some(false), false) + val base = getterScope.declareValue("base", Some(false), false) + + val traits = mixinSymbol.body.collectTypeNames.flatMap { + name => scope.getType(name) match { + case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) + case S(_: ClassSymbol) => N + case S(_: TypeSymbol) => N + case N => N + } + } + + val classBody = JSClassNewDecl(mixinSymbol.runtimeName, fields, S(JSIdent(base.runtimeName)), + Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, traits) + JSExprStmt(JSAssignExpr(JSField(JSIdent(module), mixinSymbol.lexicalName), JSFuncExpr(N, Ls(JSNamePattern(base.runtimeName)), Ls( + JSReturnStmt(S(JSClassExpr(classBody))) + )))) + } + + protected def translateModuleDeclaration( + moduleSymbol: ModuleSymbol, + base: Opt[Term], + module: Str + )(implicit scope: Scope): JSExprStmt = { + val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") + val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") + val constructorScope = moduleScope.derive(s"${moduleSymbol.lexicalName} constructor") + val members = moduleSymbol.methods.map { + translateClassMember(_)(moduleScope) + } + // Collect class fields. + val fields = moduleSymbol.body.collectFields ++ + moduleSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + val traits = moduleSymbol.body.collectTypeNames.flatMap { + name => scope.getType(name) match { + case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) + case S(_: ClassSymbol) => N + case S(_: TypeSymbol) => N + case N => N + } + } + val rest = constructorScope.declareValue("rest", Some(false), false) + val decl = JSClassNewDecl(moduleSymbol.runtimeName, + fields, + base.flatMap((b) => S(translateTerm(b))), + Ls(JSIdent(s"...${rest.runtimeName}")), + S(rest.runtimeName), + members, + traits) + + JSExprStmt(JSInvoke(JSField(JSIdent("Object"), "defineProperty"), + Ls(JSIdent(module), JSLit(JSLit.makeStringLiteral(moduleSymbol.lexicalName)), JSRecord(Ls( + "get" -> JSFuncExpr(N, Ls(), Ls( + JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), JSIdent("undefined")), Ls( + JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), + JSNew(JSClassExpr(decl)))) + )), + JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName))) + )) + ))) + )) + } + protected def translateNewClassDeclaration( classSymbol: ClassSymbol, base: Opt[JSExpr], @@ -605,23 +687,43 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { (traits.toList, classes.toList) } - protected def declareNewTypeDefs(typeDefs: Ls[NuTypeDef]): (Ls[TraitSymbol], Ls[ClassSymbol], HashMap[String, Ls[Term]]) = { + protected def declareNewTypeDefs(typeDefs: Ls[NuTypeDef]): + (Ls[TraitSymbol], Ls[ClassSymbol], Ls[MixinSymbol], Ls[ModuleSymbol], HashMap[String, Ls[Term]]) = { val traits = new ListBuffer[TraitSymbol]() val classes = new ListBuffer[ClassSymbol]() + val mixins = new ListBuffer[MixinSymbol]() + val modules = new ListBuffer[ModuleSymbol]() val superParameters = HashMap[String, Ls[Term]]() def tt(trm: Term): Type = trm.toType match { case L(ds) => Top case R(ty) => ty } + def prepare(nme: Str, fs: Ls[Opt[Var] -> Fld], pars: Ls[Term], unit: TypingUnit) = { + val params = fs.map { + case (S(nme), Fld(mut, spec, trm)) => + val ty = tt(trm) + nme -> Field(if (mut) S(ty) else N, ty) + case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) + case _ => die + } + val body = pars.map(tt).foldRight(Record(params): Type)(Inter) + val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) + case _ => lst + }) + + (body, members) + } + typeDefs.foreach { - case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => ??? - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => ??? - case NuTypeDef(Als, TypeName(nme), tps, _, pars, _, _, _) => { - val body = tt(pars.head) - topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, body) + case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + val (body, members) = prepare(mxName, fs, pars, unit) + val sym = topLevelScope.declareMixin(mxName, tps map { _._2.name }, body, members) + mixins += sym + superParameters.put(sym.lexicalName, pars) } - case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + case NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { val params = fs.map { case (S(nme), Fld(mut, spec, trm)) => val ty = tt(trm) @@ -629,34 +731,45 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) case _ => die } - val body = pars.map(tt).foldRight(Record(params): Type)(Inter) - val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { - case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) - case _ => lst - }) + if (pars.length > 0) { + val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { + case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) + case _ => ??? + }) + val body = pars.map(tt).foldRight(Record(params): Type)(Inter) + val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) + case _ => lst + }) + val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members) + modules += sym + superParameters.put(sym.lexicalName, Ls(bases)) + } + else { + val (body, members) = prepare(nme, fs, pars, unit) + val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members) + modules += sym + superParameters.put(sym.lexicalName, pars) + } + } + case NuTypeDef(Als, TypeName(nme), tps, _, pars, _, _, _) => { + val body = tt(pars.head) + topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, body) + } + case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + val (body, members) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareClass(nme, tps map { _._2.name }, body, members) classes += sym superParameters.put(sym.lexicalName, pars) } case NuTypeDef(k @ Trt, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { - val params = fs.map { - case (S(nme), Fld(mut, spec, trm)) => - val ty = tt(trm) - nme -> Field(if (mut) S(ty) else N, ty) - case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) - case _ => die - } - val body = pars.map(tt).foldRight(Record(params): Type)(Inter) - val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { - case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) - case _ => lst - }) + val (body, members) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareTrait(nme, tps map { _._2.name }, body, members) traits += sym superParameters.put(sym.lexicalName, pars) } } - (traits.toList, classes.toList, superParameters) + (traits.toList, classes.toList, mixins.toList, modules.toList, superParameters) } /** @@ -905,9 +1018,16 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { moduleName = s"${mlsModule.runtimeName}." // enable new def val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared - val (traitSymbols, classSymbols, superParameters) = declareNewTypeDefs(typeDefs) + val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols, superParameters) = declareNewTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ + mixinSymbols.map { translateMixinDeclaration(_, mlsModule.runtimeName)(topLevelScope) } ++ + moduleSymbols.map((m) => + translateModuleDeclaration(m, superParameters.get(m.lexicalName) match { + case Some(head :: _) => Some(head) + case _ => None + }, mlsModule.runtimeName)(topLevelScope) + ) ++ sortClassSymbols(classSymbols).map { case (derived, Some(base)) => { superParameters.get(derived.lexicalName) match { diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index e69cfdb5a6..46db404f73 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -838,12 +838,13 @@ final case class JSClassNewDecl( def toSourceCode: SourceCode = { val constructor: SourceCode = { val buffer = new ListBuffer[Str]() - val params = fields.iterator.zipWithIndex.foldLeft("")((s, p) => - if (p._2 === fields.length - 1) (rest match { - case Some(rest) => s"$s${p._1}, ...$rest" - case _ => s"$s${p._1}" - }) - else s"$s${p._1}, ") + val params = + fields.iterator.zipWithIndex.foldRight(rest match { + case Some(rest) => s"...$rest" + case _ => "" + })((p, s) => + if (s.isEmpty) s"${p._1}" + else s"${p._1}, $s") buffer += s" constructor($params) {" if (`extends`.isDefined) { val sf = superFields.iterator.zipWithIndex.foldLeft("")((res, p) => diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 1fc3f08b2d..4d876841b2 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -220,6 +220,30 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } + def declareMixin( + lexicalName: Str, + params: Ls[Str], + base: Type, + methods: Ls[MethodDef[Left[Term, Type]]] + ): MixinSymbol = { + val runtimeName = allocateRuntimeName(lexicalName) + val symbol = MixinSymbol(lexicalName, runtimeName, params.sorted, base, methods) + register(symbol) + symbol + } + + def declareModule( + lexicalName: Str, + params: Ls[Str], + base: Type, + methods: Ls[MethodDef[Left[Term, Type]]] + ): ModuleSymbol = { + val runtimeName = allocateRuntimeName(lexicalName) + val symbol = ModuleSymbol(lexicalName, runtimeName, params.sorted, base, methods) + register(symbol) + symbol + } + def declareTrait( lexicalName: Str, params: Ls[Str], @@ -245,10 +269,9 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } - def declareSuper(): ValueSymbol = { + def declareSuper(): Unit = { val symbol = ValueSymbol("super", "super", Some(false), false) register(symbol) - symbol } def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean): ValueSymbol = { diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index 316461ece5..7d5d701848 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -85,6 +85,38 @@ final case class ClassSymbol( override def toString: Str = s"class $lexicalName ($runtimeName)" } +final case class MixinSymbol( + lexicalName: Str, + runtimeName: Str, + params: Ls[Str], + body: Type, + methods: Ls[MethodDef[Left[Term, Type]]], +) extends TypeSymbol + with RuntimeSymbol with Ordered[ClassSymbol] { + + import scala.math.Ordered.orderingToOrdered + + override def compare(that: ClassSymbol): Int = lexicalName.compare(that.lexicalName) + + override def toString: Str = s"mixin $lexicalName ($runtimeName)" +} + +final case class ModuleSymbol( + lexicalName: Str, + runtimeName: Str, + params: Ls[Str], + body: Type, + methods: Ls[MethodDef[Left[Term, Type]]], +) extends TypeSymbol + with RuntimeSymbol with Ordered[ClassSymbol] { + + import scala.math.Ordered.orderingToOrdered + + override def compare(that: ClassSymbol): Int = lexicalName.compare(that.lexicalName) + + override def toString: Str = s"mixin $lexicalName ($runtimeName)" +} + final case class TraitSymbol( lexicalName: Str, runtimeName: Str, diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index c2e18f6ae2..d414dedc19 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -51,8 +51,8 @@ mixin EvalBase { //│ this: {eval: 'lhs -> int} //│ fun eval: (Add['lhs] | Lit) -> int //│ } -//│ // Query 1 -//│ globalThis.EvalBase = function EvalBase(base) { +//│ // Prelude +//│ __mls_modules__.EvalBase = function (base) { //│ return (class EvalBase extends base { //│ constructor(...rest) { //│ super(...rest); @@ -101,8 +101,8 @@ mixin EvalNeg { //│ this: {eval: 'expr -> int} //│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } -//│ // Query 1 -//│ globalThis.EvalNeg = function EvalNeg(base) { +//│ // Prelude +//│ __mls_modules__.EvalNeg = function (base) { //│ return (class EvalNeg extends base { //│ constructor(...rest) { //│ super(...rest); @@ -128,8 +128,8 @@ mixin EvalNegNeg { //│ this: {eval: 'expr -> 'b} //│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } -//│ // Query 1 -//│ globalThis.EvalNegNeg = function EvalNegNeg(base) { +//│ // Prelude +//│ __mls_modules__.EvalNegNeg = function (base) { //│ return (class EvalNegNeg extends base { //│ constructor(...rest) { //│ super(...rest); @@ -152,14 +152,19 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ where //│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] //│ 'A <: 'a -//│ // Query 1 -//│ globalThis.TestLang1 = function TestLang1() { -//│ return (new class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { -//│ constructor(...rest) { -//│ super(...rest); +//│ // Prelude +//│ Object.defineProperty(__mls_modules__, "TestLang", { +//│ get: function () { +//│ if (this.cache.TestLang === undefined) { +//│ this.cache.TestLang = new class TestLang extends __mls_modules__.EvalNegNeg(__mls_modules__.EvalNeg(__mls_modules__.EvalBase())) { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ }; //│ } -//│ }); -//│ }; +//│ return this.cache.TestLang; +//│ } +//│ }); //│ // End of generated code :js @@ -177,6 +182,6 @@ TestLang.eval(mk(0)) //│ return n == 0 === true ? new __mls_modules__.Lit(0) : n == 1 === true ? new __mls_modules__.Neg(mk(n)) : new __mls_modules__.Add(mk(n), mk(n)); //│ }; //│ // Query 2 -//│ res = TestLang1().eval(mk(0)); +//│ res = __mls_modules__.TestLang.eval(mk(0)); //│ // End of generated code From dc3bfaca299e6f4cd7106f50db603f7c8e575ace Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sun, 26 Feb 2023 21:00:15 +0800 Subject: [PATCH 096/498] WIP Fix parsing of unions and intersections --- .../src/main/scala/mlscript/NuTypeDefs.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 3 +- shared/src/main/scala/mlscript/helpers.scala | 2 + shared/src/test/diff/nu/EncodedLists.mls | 34 +++++++++ shared/src/test/diff/nu/LocalLets.mls | 10 +++ .../test/diff/nu/NewPolyVariantCodeReuse.mls | 72 ++++--------------- shared/src/test/diff/nu/NuTypeAliases.mls | 10 +++ 7 files changed, 73 insertions(+), 62 deletions(-) create mode 100644 shared/src/test/diff/nu/EncodedLists.mls create mode 100644 shared/src/test/diff/nu/NuTypeAliases.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 5f5bdf839e..dbccbb990a 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -349,7 +349,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // def registerTerm = named.updateWith(decl.name) { case sv @ S(v) => - ??? + // * TODO allow defining a previously given signature + err(msg"Refininition of ${decl.name}", decl.toLoc) + S(lti) case N => S(lti) } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 30711070af..d39894ec18 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -368,7 +368,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => TypedNuMxn(td, thisTV, superTV, mems.map(m => m.name -> m).toMap, ttu) // } } - case _ => ??? + // case Als => ??? + // case _ => ??? } } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 53caf8e95f..cf80e7a267 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -541,6 +541,8 @@ trait TermImpl extends StatementImpl { self: Term => case Var(name) if name.startsWith("'") => TypeVar(R(name), N) case Var(name) => TypeName(name) case lit: Lit => Literal(lit) + case App(App(Var("|"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Union(lhs.toType_!, rhs.toType_!) + case App(App(Var("&"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Inter(lhs.toType_!, rhs.toType_!) case App(App(Var("|"), lhs), rhs) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), lhs), rhs) => Inter(lhs.toType_!, rhs.toType_!) case Lam(lhs, rhs) => Function(lhs.toType_!, rhs.toType_!) diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls new file mode 100644 index 0000000000..b694e0bb9f --- /dev/null +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -0,0 +1,34 @@ +:NewParser +:NewDefs +:NoJS + + +class List { + fun match: forall 'res; (ifNil: () => 'res, ifCons: ('res, List[A]) => 'res) => 'res +} +let Nil: List +let Cons: (head: 'a, tail: List<'a>) => List<'a> +//│ class List[A]() { +//│ fun match: forall 'res. (ifNil: () -> 'res, ifCons: ('res, List[A],) -> 'res,) -> 'res +//│ } +//│ let Nil: List[nothing] +//│ let Cons: forall 'a. (head: 'a, tail: List['a],) -> List['a] + +let x: List +//│ let x: List[int] + +// FIXME +x: List +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.21: x: List +//│ ║ ^ +//│ ╟── expression of type `anything` is not an instance of type `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.17: let x: List +//│ ║ ^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.6: class List { +//│ ╙── ^ +//│ List[anything] + + diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index cbccb80778..0d7e5e0c76 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -13,3 +13,13 @@ let f = //│ unsupported definitions in blocks +// TODO allow +let x : int | string +let x = 1 +//│ x: int | string +//│ = +//│ 1 +//│ <: x: +//│ int | string +//│ = 1 + diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 5097508ded..f9398cf3b0 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -6,22 +6,11 @@ class Nil //│ class Nil() -// ? why tuple type (Cons[A] | Nil,) class Cons(head: A, tail: Cons | Nil) -//│ class Cons[A](head: A, tail: (Cons[A] | Nil,)) +//│ class Cons[A](head: A, tail: Cons[A] | Nil) -// FIXME let l = Cons(1, Nil()) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.14: let l = Cons(1, Nil()) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── application of type `Nil` is not a 1-element tuple -//│ ║ l.14: let l = Cons(1, Nil()) -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from tuple type: -//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) -//│ ╙── ^^^^^^^ -//│ let l: Cons['A] | error +//│ let l: Cons['A] //│ where //│ 'A :> 1 @@ -33,20 +22,12 @@ class Success(result: A) fun eq(l: string, r: string): bool //│ fun eq: (l: string, r: string,) -> bool -// FIXME fun list_assoc(s, l) = if l is Cons(h, t) then if eq(s, h._1) then Success(h._2) else list_assoc(s, t) Nil then NotFound() -//│ ╔══[ERROR] Type mismatch in expression: -//│ ╟── type `(Cons[?A] | Nil,)` does not match type `Cons[?A0] | Nil` -//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) -//│ ║ ^^^^^^^ -//│ ╟── but it flows into reference with expected type `Cons[?A1] | Nil` -//│ ║ l.38: if l is -//│ ╙── ^ //│ fun list_assoc: (string, Cons['A] | Nil,) -> (NotFound | Success['A0]) //│ where //│ 'A <: {_1: string, _2: 'A0} @@ -83,7 +64,6 @@ fun gensym(): string fun int_to_string(x: int): string //│ fun int_to_string: (x: int,) -> string -// FIXME mixin EvalLambda { fun eval(sub, v) = if v is @@ -100,19 +80,10 @@ mixin EvalLambda { else super.eval(sub, v) } -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.94: Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) -//│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Nil` is not a 1-element tuple -//│ ║ l.94: Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from tuple type: -//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) -//│ ╙── ^^^^^^^ //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b,) -> 'c} -//│ this: {eval: (Cons[in 'A out (string, 'd,) | 'A] | error, 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[in 'A0 out (string, Var,) | 'A0 | 'A1], 't1,) -> 'f} -//│ fun eval: ((Cons['A2] | Nil,) & 'a, Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) +//│ this: {eval: (Cons[in 'A out (string, 'd,) | 'A], 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[in 'A0 out (string, Var,) | 'A0 | 'A1], 't1,) -> 'f} +//│ fun eval: ('a & (Cons['A2] | Nil), Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) //│ } //│ where //│ 'A2 :> (string, Var,) | 'A0 @@ -131,35 +102,16 @@ mixin EvalLambda { // body = eval_rec (Cons (Tuple v.name (Var { name = new_name })) subst) v.body } // } -// FIXME module Test1: EvalVar, EvalLambda -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.135: module Test1: EvalVar, EvalLambda -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Cons[in ?A out ?A0]` is not a 1-element tuple -//│ ║ l.99: Abs(s, this.eval(Cons((x, Var(s)), sub), t)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Note: constraint arises from tuple type: -//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) -//│ ║ ^^^^^^^ -//│ ╟── from reference: -//│ ║ l.99: Abs(s, this.eval(Cons((x, Var(s)), sub), t)) -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.135: module Test1: EvalVar, EvalLambda -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Cons[in ?A out ?A0]` is not a 1-element tuple -//│ ║ l.94: Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) -//│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Note: constraint arises from tuple type: -//│ ║ l.10: class Cons(head: A, tail: Cons | Nil) -//│ ║ ^^^^^^^ -//│ ╟── from reference: -//│ ║ l.99: Abs(s, this.eval(Cons((x, Var(s)), sub), t)) -//│ ╙── ^^^ //│ module Test1() { -//│ fun eval: (nothing, 'a,) -> 'result +//│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> 'result //│ } //│ where -//│ 'result :> Var | App['result] | Abs['result] //│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | Var +//│ 'A :> 'A0 +//│ <: 'A0 & 'A1 +//│ 'A0 :> (string, 'result,) +//│ <: 'A1 & {_1: string, _2: 'result} +//│ 'A1 <: 'A & 'A0 +//│ 'result :> Var | App['result] | Abs['result] + diff --git a/shared/src/test/diff/nu/NuTypeAliases.mls b/shared/src/test/diff/nu/NuTypeAliases.mls new file mode 100644 index 0000000000..bd3d07934f --- /dev/null +++ b/shared/src/test/diff/nu/NuTypeAliases.mls @@ -0,0 +1,10 @@ +:NewParser +:NewDefs +:NoJS + + +// TODO +type A = int +//│ /!!!\ Uncaught error: scala.MatchError: Als (of class mlscript.Als$) + + From 6fc1d68d8a5f9f1eba737defc0323c7999c6a782 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 21:34:43 +0800 Subject: [PATCH 097/498] Fix getter --- .../src/main/scala/mlscript/JSBackend.scala | 93 ++++++------- .../main/scala/mlscript/codegen/Codegen.scala | 6 +- .../main/scala/mlscript/codegen/Symbol.scala | 2 +- shared/src/test/diff/nu/ECOOP23_codegen.mls | 128 ++++++++++-------- shared/src/test/diff/nu/Super.mls | 19 +-- 5 files changed, 131 insertions(+), 117 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index ad224a38b7..530c576b4e 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -20,7 +20,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected val polyfill = Polyfill() protected val visitedSymbols = MutSet[ValueSymbol]() - protected var moduleName = "" /** * This function translates parameter destructions in `def` declarations. @@ -99,14 +98,14 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: MixinSymbol) => - JSIdent(s"$moduleName${sym.runtimeName}") + JSIdent(sym.runtimeName) case S(sym: ModuleSymbol) => - JSIdent(s"$moduleName${sym.runtimeName}") + JSIdent(sym.runtimeName) case S(sym: ClassSymbol) => if (isCallee) - JSNew(JSIdent(s"$moduleName${sym.runtimeName}")) + JSNew(JSIdent(sym.runtimeName)) else - JSArrowFn(JSNamePattern("x") :: Nil, L(JSNew(JSIdent(s"$moduleName${sym.runtimeName}"))(JSIdent("x")))) + JSArrowFn(JSNamePattern("x") :: Nil, L(JSNew(JSIdent(sym.runtimeName))(JSIdent("x")))) case S(sym: TraitSymbol) => JSIdent(sym.lexicalName)("build") case N => scope.getType(name) match { @@ -295,7 +294,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // JS is dumb so `instanceof String` won't actually work on "primitive" strings... JSBinary("===", scrut.member("constructor"), JSLit("String")) case Var(name) => topLevelScope.getType(name) match { - case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(s"$moduleName$runtimeName")) + case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(runtimeName)) case S(TraitSymbol(_, runtimeName, _, _, _)) => JSIdent(runtimeName)("is")(scrut) case S(_: TypeAliasSymbol) => throw new CodeGenError(s"cannot match type alias $name") case N => throw new CodeGenError(s"unknown match case: $name") @@ -440,9 +439,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def translateMixinDeclaration( - mixinSymbol: MixinSymbol, - module: Str - )(implicit scope: Scope): JSExprStmt = { + mixinSymbol: MixinSymbol + )(implicit scope: Scope): JSClassMethod = { val getterScope = scope.derive(s"getter ${mixinSymbol.lexicalName}") val mixinScope = getterScope.derive(s"mixin ${mixinSymbol.lexicalName}") mixinScope.declareSuper() @@ -468,16 +466,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val classBody = JSClassNewDecl(mixinSymbol.runtimeName, fields, S(JSIdent(base.runtimeName)), Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, traits) - JSExprStmt(JSAssignExpr(JSField(JSIdent(module), mixinSymbol.lexicalName), JSFuncExpr(N, Ls(JSNamePattern(base.runtimeName)), Ls( - JSReturnStmt(S(JSClassExpr(classBody))) - )))) + JSClassMethod(mixinSymbol.lexicalName, Ls(JSNamePattern(base.runtimeName)), R(Ls(JSReturnStmt(S(JSClassExpr(classBody)))))) } protected def translateModuleDeclaration( moduleSymbol: ModuleSymbol, - base: Opt[Term], - module: Str - )(implicit scope: Scope): JSExprStmt = { + base: Opt[Term] + )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") val constructorScope = moduleScope.derive(s"${moduleSymbol.lexicalName} constructor") @@ -504,26 +499,21 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { members, traits) - JSExprStmt(JSInvoke(JSField(JSIdent("Object"), "defineProperty"), - Ls(JSIdent(module), JSLit(JSLit.makeStringLiteral(moduleSymbol.lexicalName)), JSRecord(Ls( - "get" -> JSFuncExpr(N, Ls(), Ls( - JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), JSIdent("undefined")), Ls( - JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), - JSNew(JSClassExpr(decl)))) - )), - JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName))) - )) - ))) - )) + JSClassGetter(moduleSymbol.lexicalName, R(Ls( + JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), JSIdent("undefined")), Ls( + JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), + JSNew(JSClassExpr(decl)))) + )), + JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName))) + ))) } protected def translateNewClassDeclaration( classSymbol: ClassSymbol, base: Opt[JSExpr], - module: Str, superFields: Ls[Term] = Nil, rest: Opt[Str] = N - )(implicit scope: Scope): JSExprStmt = { + )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"${classSymbol.lexicalName} getter") val classBody = translateNewClassExpression(classSymbol, base, superFields, rest)(getterScope) val constructor = classBody match { @@ -533,19 +523,15 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case JSClassNewDecl(_, fields, _, _, _, _, _) => fields.map(JSIdent(_)) } - JSExprStmt(JSInvoke(JSField(JSIdent("Object"), "defineProperty"), - Ls(JSIdent(module), JSLit(JSLit.makeStringLiteral(classSymbol.lexicalName)), JSRecord(Ls( - "get" -> JSFuncExpr(N, Ls(), Ls( - JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSIdent("undefined")), Ls( - JSExprStmt(JSClassExpr(classBody)), - JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), - JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), - JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(classSymbol.lexicalName))) - )), - JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName))) - )) - ))) - )) + JSClassGetter(classSymbol.lexicalName, R(Ls( + JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSIdent("undefined")), Ls( + JSExprStmt(JSClassExpr(classBody)), + JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), + JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), + JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(classSymbol.lexicalName))) + )), + JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName))) + ))) } protected def translateNewClassExpression( @@ -893,7 +879,6 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { private val lastResultSymbol = topLevelScope.declareValue("res", Some(false), false) private val resultIdent = JSIdent(lastResultSymbol.runtimeName) - private val mlsModule = topLevelScope.declareValue("__mls_modules__", Some(false), false) private var numRun = 0 @@ -1015,30 +1000,38 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { } private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { - moduleName = s"${mlsModule.runtimeName}." // enable new def + val mlsModule = topLevelScope.declareValue("typing_unit", Some(false), false) val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols, superParameters) = declareNewTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ - mixinSymbols.map { translateMixinDeclaration(_, mlsModule.runtimeName)(topLevelScope) } ++ + mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ moduleSymbols.map((m) => translateModuleDeclaration(m, superParameters.get(m.lexicalName) match { case Some(head :: _) => Some(head) case _ => None - }, mlsModule.runtimeName)(topLevelScope) + })(topLevelScope) ) ++ sortClassSymbols(classSymbols).map { case (derived, Some(base)) => { superParameters.get(derived.lexicalName) match { - case Some(sp) => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), mlsModule.runtimeName, sp)(topLevelScope) - case _ => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), mlsModule.runtimeName)(topLevelScope) + case Some(sp) => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), sp)(topLevelScope) + case _ => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) } } case (derived, None) => - translateNewClassDeclaration(derived, None, mlsModule.runtimeName)(topLevelScope) + translateNewClassDeclaration(derived, None)(topLevelScope) }.toList + def include(typeName: Str, moduleName: Str) = + JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) + val includes = + traitSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ + mixinSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ + moduleSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ + classSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)).toList + val zeroWidthSpace = JSLit("\"\\u200B\"") val catchClause = JSCatchClause( JSIdent("e"), @@ -1110,9 +1103,9 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { } // If this is the first time, insert the declaration of `res`. - var prelude: Ls[JSStmt] = defStmts + var prelude: Ls[JSStmt] = JSLetDecl(Ls(mlsModule.runtimeName -> S(JSRecord(Ls("cache" -> JSRecord(Ls())), defStmts)))) :: includes if (numRun === 0) - prelude = JSLetDecl(lastResultSymbol.runtimeName -> N :: Nil) :: JSLetDecl(Ls(mlsModule.runtimeName -> S(JSRecord(Ls("cache" -> JSRecord(Ls())))))) :: prelude + prelude = JSLetDecl(lastResultSymbol.runtimeName -> N :: Nil) :: prelude // Increase the run number. numRun = numRun + 1 diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 46db404f73..d2ff140629 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -629,13 +629,13 @@ final case class JSArray(items: Ls[JSExpr]) extends JSExpr { SourceCode.array(items map { _.embed(JSCommaExpr.outerPrecedence) }) } -final case class JSRecord(entries: Ls[Str -> JSExpr]) extends JSExpr { +final case class JSRecord(entries: Ls[Str -> JSExpr], methods: Ls[JSStmt] = Nil) extends JSExpr { override def precedence: Int = 22 // Make override def toSourceCode: SourceCode = SourceCode - .record(entries map { case (key, value) => + .record((entries map { case (key, value) => SourceCode(JSField.emitValidFieldName(key) + ": ") ++ value.embed(JSCommaExpr.outerPrecedence) - }) + }) ++ (methods.map((m) => m.toSourceCode))) } final case class JSClassExpr(cls: JSClassNewDecl) extends JSExpr { diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index 7d5d701848..6bd700e25d 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -114,7 +114,7 @@ final case class ModuleSymbol( override def compare(that: ClassSymbol): Int = lexicalName.compare(that.lexicalName) - override def toString: Str = s"mixin $lexicalName ($runtimeName)" + override def toString: Str = s"module $lexicalName ($runtimeName)" } final case class TraitSymbol( diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index d414dedc19..cc8510ea69 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -8,9 +8,9 @@ class Lit(n: int) //│ class Lit(n: int) //│ // Prelude //│ let res; -//│ let __mls_modules__ = { cache: {} }; -//│ Object.defineProperty(__mls_modules__, "Add", { -//│ get: function () { +//│ let typing_unit = { +//│ cache: {}, +//│ get Add() { //│ if (this.cache.Add === undefined) { //│ class Add { //│ constructor(lhs, rhs) { @@ -22,10 +22,8 @@ class Lit(n: int) //│ this.cache.Add["class"] = Add; //│ } //│ return this.cache.Add; -//│ } -//│ }); -//│ Object.defineProperty(__mls_modules__, "Lit", { -//│ get: function () { +//│ }, +//│ get Lit() { //│ if (this.cache.Lit === undefined) { //│ class Lit { //│ constructor(n) { @@ -37,7 +35,9 @@ class Lit(n: int) //│ } //│ return this.cache.Lit; //│ } -//│ }); +//│ }; +//│ globalThis.Add = typing_unit.Add; +//│ globalThis.Lit = typing_unit.Lit; //│ // End of generated code :js @@ -52,30 +52,35 @@ mixin EvalBase { //│ fun eval: (Add['lhs] | Lit) -> int //│ } //│ // Prelude -//│ __mls_modules__.EvalBase = function (base) { -//│ return (class EvalBase extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = e, a instanceof __mls_modules__.Lit ? ((n) => n)(e.n) : a instanceof __mls_modules__.Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ throw new Error("non-exhaustive case expression"); +//│ let typing_unit1 = { +//│ cache: {}, +//│ EvalBase(base) { +//│ return (class EvalBase extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); //│ })()); -//│ })()); -//│ } -//│ }); +//│ } +//│ }); +//│ } //│ }; +//│ globalThis.EvalBase = typing_unit1.EvalBase; //│ // End of generated code :js class Neg(expr: A) //│ class Neg[A](expr: A) //│ // Prelude -//│ Object.defineProperty(__mls_modules__, "Neg", { -//│ get: function () { +//│ let typing_unit2 = { +//│ cache: {}, +//│ get Neg() { //│ if (this.cache.Neg === undefined) { //│ class Neg { //│ constructor(expr) { @@ -87,7 +92,8 @@ class Neg(expr: A) //│ } //│ return this.cache.Neg; //│ } -//│ }); +//│ }; +//│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code :js @@ -102,19 +108,23 @@ mixin EvalNeg { //│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } //│ // Prelude -//│ __mls_modules__.EvalNeg = function (base) { -//│ return (class EvalNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof __mls_modules__.Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); +//│ let typing_unit3 = { +//│ cache: {}, +//│ EvalNeg(base) { +//│ return (class EvalNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } //│ }; +//│ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ // End of generated code :js @@ -129,19 +139,23 @@ mixin EvalNegNeg { //│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } //│ // Prelude -//│ __mls_modules__.EvalNegNeg = function (base) { -//│ return (class EvalNegNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof __mls_modules__.Neg ? ((tmp0) => tmp0 instanceof __mls_modules__.Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); +//│ let typing_unit4 = { +//│ cache: {}, +//│ EvalNegNeg(base) { +//│ return (class EvalNegNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } //│ }; +//│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ // End of generated code :js @@ -153,10 +167,11 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] //│ 'A <: 'a //│ // Prelude -//│ Object.defineProperty(__mls_modules__, "TestLang", { -//│ get: function () { +//│ let typing_unit5 = { +//│ cache: {}, +//│ get TestLang() { //│ if (this.cache.TestLang === undefined) { -//│ this.cache.TestLang = new class TestLang extends __mls_modules__.EvalNegNeg(__mls_modules__.EvalNeg(__mls_modules__.EvalBase())) { +//│ this.cache.TestLang = new class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { //│ constructor(...rest) { //│ super(...rest); //│ } @@ -164,7 +179,8 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ } //│ return this.cache.TestLang; //│ } -//│ }); +//│ }; +//│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code :js @@ -177,11 +193,13 @@ TestLang.eval(mk(0)) //│ int //│ where //│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] +//│ // Prelude +//│ let typing_unit6 = { cache: {} }; //│ // Query 1 //│ globalThis.mk = function mk(n) { -//│ return n == 0 === true ? new __mls_modules__.Lit(0) : n == 1 === true ? new __mls_modules__.Neg(mk(n)) : new __mls_modules__.Add(mk(n), mk(n)); +//│ return n == 0 === true ? new Lit(0) : n == 1 === true ? new Neg(mk(n)) : new Add(mk(n), mk(n)); //│ }; //│ // Query 2 -//│ res = __mls_modules__.TestLang.eval(mk(0)); +//│ res = TestLang.eval(mk(0)); //│ // End of generated code diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index 76fd90a863..7e6b71692f 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -6,9 +6,9 @@ class Foo(x: int) //│ class Foo(x: int) //│ // Prelude //│ let res; -//│ let __mls_modules__ = { cache: {} }; -//│ Object.defineProperty(__mls_modules__, "Foo", { -//│ get: function () { +//│ let typing_unit = { +//│ cache: {}, +//│ get Foo() { //│ if (this.cache.Foo === undefined) { //│ class Foo { //│ constructor(x) { @@ -20,19 +20,21 @@ class Foo(x: int) //│ } //│ return this.cache.Foo; //│ } -//│ }); +//│ }; +//│ globalThis.Foo = typing_unit.Foo; //│ // End of generated code :js :e class Bar(x: int, y: int): Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.28: class Bar(x: int, y: int): Foo(x + y) +//│ ║ l.29: class Bar(x: int, y: int): Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) //│ // Prelude -//│ Object.defineProperty(__mls_modules__, "Bar", { -//│ get: function () { +//│ let typing_unit1 = { +//│ cache: {}, +//│ get Bar() { //│ if (this.cache.Bar === undefined) { //│ class Bar extends Foo { //│ constructor(x, y) { @@ -45,5 +47,6 @@ class Bar(x: int, y: int): Foo(x + y) //│ } //│ return this.cache.Bar; //│ } -//│ }); +//│ }; +//│ globalThis.Bar = typing_unit1.Bar; //│ // End of generated code From 7e24e3fe55d538f4f376d22e9352accf83773b02 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 22:44:28 +0800 Subject: [PATCH 098/498] Fix some problems --- .../src/main/scala/mlscript/JSBackend.scala | 32 ++--- .../main/scala/mlscript/codegen/Codegen.scala | 2 +- shared/src/test/diff/nu/ECOOP23_codegen.mls | 113 ++++++++++++------ shared/src/test/diff/nu/Super.mls | 78 +++++++++++- 4 files changed, 173 insertions(+), 52 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 530c576b4e..817af1cd81 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -262,7 +262,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _), parents) => val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) parents match { - case Some(p) => JSClassExpr(translateNewClassExpression(clsBody, Some(translateTerm(p)))) + case Some(p) => JSClassExpr(translateNewClassExpression(clsBody, Some(p))) case _ => JSClassExpr(translateNewClassExpression(clsBody, N)) } case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => @@ -466,7 +466,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val classBody = JSClassNewDecl(mixinSymbol.runtimeName, fields, S(JSIdent(base.runtimeName)), Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, traits) - JSClassMethod(mixinSymbol.lexicalName, Ls(JSNamePattern(base.runtimeName)), R(Ls(JSReturnStmt(S(JSClassExpr(classBody)))))) + val baseClassBody = JSClassNewDecl(mixinSymbol.runtimeName, fields, N, + Ls(), N, members, traits) + JSClassMethod(mixinSymbol.lexicalName, Ls(JSNamePattern(base.runtimeName)), R(Ls( + JSIfStmt(JSBinary("===", JSIdent(base.runtimeName), JSIdent("undefined")), + Ls(JSReturnStmt(S(JSClassExpr(baseClassBody)))), Ls(JSReturnStmt(S(JSClassExpr(classBody))))) + ))) } protected def translateModuleDeclaration( @@ -510,7 +515,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateNewClassDeclaration( classSymbol: ClassSymbol, - base: Opt[JSExpr], + base: Opt[Term], superFields: Ls[Term] = Nil, rest: Opt[Str] = N )(implicit scope: Scope): JSClassGetter = { @@ -536,7 +541,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateNewClassExpression( classSymbol: ClassSymbol, - base: Opt[JSExpr], + base: Opt[Term], superFields: Ls[Term] = Nil, rest: Opt[Str] = N )(implicit scope: Scope): JSClassNewDecl = { @@ -553,7 +558,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { fields.foreach(constructorScope.declareValue(_, Some(false), false)) val restRuntime = rest.flatMap(name => S(constructorScope.declareValue(name, Some(false), false).runtimeName)) - // val base = baseClassSymbol.map { sym => JSIdent(sym.runtimeName) } + val baseJS = base.flatMap { sym => S(translateTerm(sym)(constructorScope)) } val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) @@ -570,7 +575,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case _ => ??? // TODO: throw? }).flatten - JSClassNewDecl(classSymbol.runtimeName, fields, base, restRuntime match { + JSClassNewDecl(classSymbol.runtimeName, fields, baseJS, restRuntime match { case Some(restRuntime) => superParameters :+ JSIdent(s"...$restRuntime") case _ => superParameters }, restRuntime, members, traits) @@ -1013,15 +1018,14 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case _ => None })(topLevelScope) ) ++ - sortClassSymbols(classSymbols).map { - case (derived, Some(base)) => { - superParameters.get(derived.lexicalName) match { - case Some(sp) => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)), sp)(topLevelScope) - case _ => translateNewClassDeclaration(derived, Some(JSIdent(base.runtimeName)))(topLevelScope) - } + classSymbols.map { sym => + superParameters.get(sym.lexicalName) match { + case Some(sp) => translateNewClassDeclaration(sym, sp match { + case head :: _ => Some(head) + case _ => None + }, sp)(topLevelScope) + case _ => translateNewClassDeclaration(sym, None)(topLevelScope) } - case (derived, None) => - translateNewClassDeclaration(derived, None)(topLevelScope) }.toList def include(typeName: Str, moduleName: Str) = diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index d2ff140629..7c8029877c 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -857,7 +857,7 @@ final case class JSClassNewDecl( buffer += s" $name.implement(this);" } fields.iterator.zipWithIndex.foreach { pair => - if (`extends`.isEmpty || pair._2 < fields.length - 1) { + if (rest.isEmpty || pair._2 < fields.length - 1) { val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" buffer += s" this${innerName} = ${pair._1};" // TODO: invalid name? } diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index cc8510ea69..5afdb528c8 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -55,20 +55,36 @@ mixin EvalBase { //│ let typing_unit1 = { //│ cache: {}, //│ EvalBase(base) { -//│ return (class EvalBase extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ throw new Error("non-exhaustive case expression"); +//│ if (base === undefined) { +//│ return (class EvalBase { +//│ constructor() { +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); //│ })()); -//│ })()); -//│ } -//│ }); +//│ } +//│ }); +//│ } else { +//│ return (class EvalBase extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })()); +//│ } +//│ }); +//│ } //│ } //│ }; //│ globalThis.EvalBase = typing_unit1.EvalBase; @@ -111,17 +127,30 @@ mixin EvalNeg { //│ let typing_unit3 = { //│ cache: {}, //│ EvalNeg(base) { -//│ return (class EvalNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); +//│ if (base === undefined) { +//│ return (class EvalNeg { +//│ constructor() { +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } else { +//│ return (class EvalNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } //│ } //│ }; //│ globalThis.EvalNeg = typing_unit3.EvalNeg; @@ -142,17 +171,30 @@ mixin EvalNegNeg { //│ let typing_unit4 = { //│ cache: {}, //│ EvalNegNeg(base) { -//│ return (class EvalNegNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); +//│ if (base === undefined) { +//│ return (class EvalNegNeg { +//│ constructor() { +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } else { +//│ return (class EvalNegNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } //│ } //│ }; //│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; @@ -202,4 +244,3 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code - diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index 7e6b71692f..945686bea8 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -36,10 +36,11 @@ class Bar(x: int, y: int): Foo(x + y) //│ cache: {}, //│ get Bar() { //│ if (this.cache.Bar === undefined) { -//│ class Bar extends Foo { +//│ class Bar extends new Foo(x + y) { //│ constructor(x, y) { //│ super(x + y); //│ this.x = x; +//│ this.y = y; //│ } //│ }; //│ this.cache.Bar = ((x, y) => new Bar(x, y)); @@ -50,3 +51,78 @@ class Bar(x: int, y: int): Foo(x + y) //│ }; //│ globalThis.Bar = typing_unit1.Bar; //│ // End of generated code + + +:js +mixin AA(a: int) { +} +//│ mixin AA() +//│ // Prelude +//│ let typing_unit2 = { +//│ cache: {}, +//│ AA(base) { +//│ if (base === undefined) { +//│ return (class AA { +//│ constructor(a) { +//│ this.a = a; +//│ } +//│ }); +//│ } else { +//│ return (class AA extends base { +//│ constructor(a, ...rest) { +//│ super(...rest); +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.AA = typing_unit2.AA; +//│ // End of generated code + +:js +mixin BB {} +//│ mixin BB() +//│ // Prelude +//│ let typing_unit3 = { +//│ cache: {}, +//│ BB(base) { +//│ if (base === undefined) { +//│ return class BB {}; +//│ } else { +//│ return (class BB extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.BB = typing_unit3.BB; +//│ // End of generated code + +:js +:e +class C(x: int): BB() +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.105: class C(x: int): BB() +//│ ╙── ^^^^ +//│ class C(x: int) +//│ // Prelude +//│ let typing_unit4 = { +//│ cache: {}, +//│ get C() { +//│ if (this.cache.C === undefined) { +//│ class C extends BB() { +//│ constructor(x) { +//│ super(); +//│ this.x = x; +//│ } +//│ }; +//│ this.cache.C = ((x) => new C(x)); +//│ this.cache.C["class"] = C; +//│ } +//│ return this.cache.C; +//│ } +//│ }; +//│ globalThis.C = typing_unit4.C; +//│ // End of generated code From 509690e9a78c169565de629c4738c8b2ed23c162 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 26 Feb 2023 23:47:00 +0800 Subject: [PATCH 099/498] Fix something --- .../src/main/scala/mlscript/JSBackend.scala | 52 +++++++++++----- shared/src/test/diff/nu/Super.mls | 62 +++++++++++++++++-- 2 files changed, 94 insertions(+), 20 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 817af1cd81..f078d51cfa 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -262,8 +262,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _), parents) => val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) parents match { - case Some(p) => JSClassExpr(translateNewClassExpression(clsBody, Some(p))) - case _ => JSClassExpr(translateNewClassExpression(clsBody, N)) + case Some(p) => JSClassExpr(translateNewClassExpression(clsBody, Ls(p))) + case _ => JSClassExpr(translateNewClassExpression(clsBody)) } case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") @@ -515,12 +515,11 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateNewClassDeclaration( classSymbol: ClassSymbol, - base: Opt[Term], superFields: Ls[Term] = Nil, rest: Opt[Str] = N )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"${classSymbol.lexicalName} getter") - val classBody = translateNewClassExpression(classSymbol, base, superFields, rest)(getterScope) + val classBody = translateNewClassExpression(classSymbol, superFields, rest)(getterScope) val constructor = classBody match { case JSClassNewDecl(_, fields, _, _, _, _, _) => fields.map(JSNamePattern(_)) } @@ -541,7 +540,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateNewClassExpression( classSymbol: ClassSymbol, - base: Opt[Term], superFields: Ls[Term] = Nil, rest: Opt[Str] = N )(implicit scope: Scope): JSClassNewDecl = { @@ -558,7 +556,36 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { fields.foreach(constructorScope.declareValue(_, Some(false), false)) val restRuntime = rest.flatMap(name => S(constructorScope.declareValue(name, Some(false), false).runtimeName)) - val baseJS = base.flatMap { sym => S(translateTerm(sym)(constructorScope)) } + val bases = superFields.map { sym => sym match { + case App(lhs, _) => S(translateTerm(App(lhs, Tup(Ls())))(constructorScope)) + case _ => S(translateTerm(sym)(constructorScope)) + } } + val base: Opt[JSExpr] = + if (bases.length === 0) N + else if (bases.length === 1) bases.head match { + case Some(JSIdent(nme)) => scope.resolveValue(nme) match { + case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) + case Some(_) => Some(JSIdent(nme)) + case _ => ??? + } + case Some(inv: JSInvoke) => Some(inv) + case _ => ??? + } + else bases.reduceLeft((res, call) => (res, call) match { + case (S(JSIdent(res)), S(JSIdent(call))) => scope.resolveValue(res) match { + case Some(sym: MixinSymbol) => S(JSInvoke(JSIdent(call), Ls(JSInvoke(JSIdent(res), Ls())))) + case Some(_) => S(JSInvoke(JSIdent(call), Ls(JSIdent(res)))) + case _ => ??? + } + case (S(res), S(JSIdent(call))) => S(JSInvoke(JSIdent(call), Ls(res))) + case (S(JSIdent(res)), S(JSInvoke(call, _))) => scope.resolveValue(res) match { + case Some(sym: MixinSymbol) => S(JSInvoke(call, Ls(JSInvoke(JSIdent(res), Ls())))) + case Some(_) => S(JSInvoke(call, Ls(JSIdent(res)))) + case _ => ??? + } + case (S(res), S(JSInvoke(call, _))) => S(JSInvoke(call, Ls(res))) + case _ => ??? + }) val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) @@ -571,11 +598,11 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val superParameters = (superFields map { case App(lhs, Tup(rhs)) => rhs map { case (_, Fld(mut, spec, trm)) => translateTerm(trm)(constructorScope) - } - case _ => ??? // TODO: throw? + } + case _ => Nil }).flatten - JSClassNewDecl(classSymbol.runtimeName, fields, baseJS, restRuntime match { + JSClassNewDecl(classSymbol.lexicalName, fields, base, restRuntime match { case Some(restRuntime) => superParameters :+ JSIdent(s"...$restRuntime") case _ => superParameters }, restRuntime, members, traits) @@ -1020,11 +1047,8 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { ) ++ classSymbols.map { sym => superParameters.get(sym.lexicalName) match { - case Some(sp) => translateNewClassDeclaration(sym, sp match { - case head :: _ => Some(head) - case _ => None - }, sp)(topLevelScope) - case _ => translateNewClassDeclaration(sym, None)(topLevelScope) + case Some(sp) => translateNewClassDeclaration(sym, sp)(topLevelScope) + case _ => translateNewClassDeclaration(sym)(topLevelScope) } }.toList diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index 945686bea8..7877af5090 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -36,7 +36,7 @@ class Bar(x: int, y: int): Foo(x + y) //│ cache: {}, //│ get Bar() { //│ if (this.cache.Bar === undefined) { -//│ class Bar extends new Foo(x + y) { +//│ class Bar extends new Foo() { //│ constructor(x, y) { //│ super(x + y); //│ this.x = x; @@ -101,11 +101,7 @@ mixin BB {} //│ // End of generated code :js -:e -class C(x: int): BB() -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.105: class C(x: int): BB() -//│ ╙── ^^^^ +class C(x: int): BB //│ class C(x: int) //│ // Prelude //│ let typing_unit4 = { @@ -126,3 +122,57 @@ class C(x: int): BB() //│ }; //│ globalThis.C = typing_unit4.C; //│ // End of generated code + +:js +:e +class D(x: int): AA(x) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.128: class D(x: int): AA(x) +//│ ╙── ^^^^^ +//│ class D(x: int) +//│ // Prelude +//│ let typing_unit5 = { +//│ cache: {}, +//│ get D() { +//│ if (this.cache.D === undefined) { +//│ class D extends AA() { +//│ constructor(x) { +//│ super(x); +//│ this.x = x; +//│ } +//│ }; +//│ this.cache.D = ((x) => new D(x)); +//│ this.cache.D["class"] = D; +//│ } +//│ return this.cache.D; +//│ } +//│ }; +//│ globalThis.D = typing_unit5.D; +//│ // End of generated code + +:js +:e +class E(x: int): BB, AA(x) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.155: class E(x: int): BB, AA(x) +//│ ╙── ^^^^^ +//│ class E(x: int) +//│ // Prelude +//│ let typing_unit6 = { +//│ cache: {}, +//│ get E() { +//│ if (this.cache.E === undefined) { +//│ class E extends AA(BB()) { +//│ constructor(x) { +//│ super(x); +//│ this.x = x; +//│ } +//│ }; +//│ this.cache.E = ((x) => new E(x)); +//│ this.cache.E["class"] = E; +//│ } +//│ return this.cache.E; +//│ } +//│ }; +//│ globalThis.E = typing_unit6.E; +//│ // End of generated code From c2590537c734e225891b2d8d726f709d36571f03 Mon Sep 17 00:00:00 2001 From: Andong Fan Date: Mon, 27 Feb 2023 00:13:14 +0800 Subject: [PATCH 100/498] Finish poly variants example --- shared/src/test/diff/nu/BasicClasses.mls | 18 +- shared/src/test/diff/nu/GenericClasses.mls | 2 +- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 159 ++++++++++++++++-- 3 files changed, 150 insertions(+), 29 deletions(-) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index c8a323e710..0c230bfa97 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -20,7 +20,7 @@ fun f(x: A) = if x is A then x.n //│ fun f: (x: A,) -> int fun f(x: A | 'b) = if x is A then x.n else 0 -//│ fun f: (x: (anything,),) -> int +//│ fun f: (x: anything,) -> int fun f(x) = x.n @@ -172,20 +172,8 @@ class Annots(base: 0 | 1) { a: int fun a = base } -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.172: a: int -//│ ║ ^ -//│ ╟── type `(0 | 1,)` is not an instance of type `int` -//│ ║ l.171: class Annots(base: 0 | 1) { -//│ ║ ^ -//│ ╟── but it flows into reference with expected type `int` -//│ ║ l.172: a: int -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.172: a: int -//│ ╙── ^^^ -//│ class Annots(base: (0 | 1,)) { -//│ fun a: (0 | 1,) +//│ class Annots(base: 0 | 1) { +//│ fun a: 0 | 1 //│ } diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 7771e49b93..3706e2e6a9 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -83,7 +83,7 @@ None.toArray // TODO type Option = Some | None -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ /!!!\ Uncaught error: scala.MatchError: Als (of class mlscript.Als$) diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index f9398cf3b0..1a9e63bd2b 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -89,19 +89,6 @@ mixin EvalLambda { //│ 'A2 :> (string, Var,) | 'A0 //│ <: 'A1 -// def eval_lambda eval_rec subst v = case v of { -// | Var -> eval_var subst v -// | App -> let l2 = eval_rec subst v.lhs in -// let l1 = eval_rec subst v.rhs in -// case l1 of { -// | Abs -> eval_rec (Cons (Tuple l1.name l2) Nil) l1.body -// | _ -> App { lhs = l1; rhs = l2 } -// } -// | Abs -> let new_name = int_to_string ((gensym ())._2.a) in -// Abs { name = new_name; -// body = eval_rec (Cons (Tuple v.name (Var { name = new_name })) subst) v.body } -// } - module Test1: EvalVar, EvalLambda //│ module Test1() { //│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> 'result @@ -115,3 +102,149 @@ module Test1: EvalVar, EvalLambda //│ 'A1 <: 'A & 'A0 //│ 'result :> Var | App['result] | Abs['result] +Test1.eval(Nil(), Var("a")) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Var + +Test1.eval(Nil(), Abs("b", Var("a"))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Var + +Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Var + +Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var + +class Num(n: int) +class Add(l: A, r: A) +class Mul(l: A, r: A) +//│ class Num(n: int) +//│ class Add[A](l: A, r: A) +//│ class Mul[A](l: A, r: A) + +fun map_expr(f, v) = + if v is + Var then v + Num then v + Add(l, r) then Add(f(l), f(r)) + Mul(l, r) then Mul(f(l), f(r)) +//│ fun map_expr: ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) + +mixin EvalExpr { + fun eval(sub, v) = + fun eta(e) = this.eval(sub, e) + let vv = map_expr(eta, v) + if vv is + Var then super.eval(sub, vv) + Add(Num(l), Num(r)) then Num(l + r) + Mul(Num(l), Num(r)) then Num(l * r) + else v +} +//│ mixin EvalExpr() { +//│ super: {eval: ('a, Var,) -> 'b} +//│ this: {eval: ('a, 'c,) -> anything} +//│ fun eval: ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) +//│ } + +module Test2: EvalVar, EvalExpr +//│ module Test2() { +//│ fun eval: (Cons['A] | Nil, 'a,) -> (Num | Var | 'result | 'a) +//│ } +//│ where +//│ 'a <: Add['b] | Mul['b] | Num | Var +//│ 'b <: 'a +//│ 'A <: {_1: string, _2: 'result} + +Test2.eval(Nil(), Var("a")) +//│ Num | Var + +Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Var("a")) +//│ Abs[Var] | Num | Var + +Test2.eval(Cons(("a", Num(1)), Nil()), Var("a")) +//│ Num | Var + +:e +Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.175: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` +//│ ║ l.175: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.133: if v is +//│ ║ ^ +//│ ╟── from reference: +//│ ║ l.143: let vv = map_expr(eta, v) +//│ ╙── ^ +//│ Abs[Var] | Num | Var | error + +Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) +//│ Abs[Var] | Add[Num | Var] | Num | Var + +module Test3: EvalVar, EvalExpr, EvalLambda +//│ module Test3() { +//│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> 'result +//│ } +//│ where +//│ 'A :> 'A0 +//│ <: 'A0 & 'A1 +//│ 'A0 :> (string, 'result,) +//│ <: 'A1 & {_1: string, _2: 'result} +//│ 'A1 <: 'A & 'A0 +//│ 'result :> App['result] | Abs['result] | Num | 'b | Var +//│ 'b <: Add['c] | Mul['c] | Num | Var +//│ 'c <: 'a +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | 'b & ~Abs & ~App + +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Num | Var + +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var + +module Test3: EvalVar, EvalLambda, EvalExpr +//│ module Test3() { +//│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> ('a | 'result) +//│ } +//│ where +//│ 'A :> 'A0 +//│ <: 'A0 & 'A1 +//│ 'A0 :> (string, 'result,) +//│ <: 'A1 & {_1: string, _2: 'result} +//│ 'A1 <: 'A & 'A0 +//│ 'result :> Abs['result] | App['result] | Num | 'a | Var +//│ 'a <: Add['b] | Mul['b] | Num | Var +//│ 'b <: 'a + +// Because EvalExpr does not dispatch lambdas to super and map_expr only +// handles exprs +:e +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` +//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.133: if v is +//│ ║ ^ +//│ ╟── from reference: +//│ ║ l.143: let vv = map_expr(eta, v) +//│ ╙── ^ +//│ error | 'a +//│ where +//│ 'a :> Abs['a] | App['a] | Var | Abs[Var] | Num From 99feeb47e92305c6634e8b30eb1ca29f74569fb3 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Feb 2023 01:09:16 +0800 Subject: [PATCH 101/498] WIP Add alternative test + minor changes --- .../scala/mlscript/ConstraintSolver.scala | 25 ++- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 67 +++--- .../test/diff/nu/NewPolyVariantCodeReuse2.mls | 212 ++++++++++++++++++ 4 files changed, 268 insertions(+), 40 deletions(-) create mode 100644 shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 79ddf630df..ead731204b 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -800,12 +800,25 @@ class ConstraintSolver extends NormalForms { self: Typer => case (tr1: TypeRef, tr2: TypeRef) if tr1.defn.name =/= "Array" => if (tr1.defn === tr2.defn) { assert(tr1.targs.sizeCompare(tr2.targs) === 0) - val td = ctx.tyDefs(tr1.defn.name) - val tvv = td.getVariancesOrDefault - td.tparamsargs.unzip._2.lazyZip(tr1.targs).lazyZip(tr2.targs).foreach { (tv, targ1, targ2) => - val v = tvv(tv) - if (!v.isContravariant) rec(targ1, targ2, false) - if (!v.isCovariant) rec(targ2, targ1, false) + ctx.tyDefs.get(tr1.defn.name) match { + case S(td) => + val tvv = td.getVariancesOrDefault + td.tparamsargs.unzip._2.lazyZip(tr1.targs).lazyZip(tr2.targs).foreach { (tv, targ1, targ2) => + val v = tvv(tv) + if (!v.isContravariant) rec(targ1, targ2, false) + if (!v.isCovariant) rec(targ2, targ1, false) + } + case N => + ctx.tyDefs2(tr1.defn.name).complete() match { + case cls: TypedNuCls => + cls.tparams.map(_._2).lazyZip(tr1.targs).lazyZip(tr2.targs).foreach { + (tv, targ1, targ2) => + val v = cls.varianceOf(tv) + if (!v.isContravariant) rec(targ1, targ2, false) + if (!v.isCovariant) rec(targ2, targ1, false) + } + case _ => ??? + } } } else { (tr1.mkTag, tr2.mkTag) match { diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 05607c60ff..396028e9cd 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -336,8 +336,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case ti: LazyTypeInfo => // ti.complete() ti.decl match { - case NuTypeDef(Cls, _, tps, _, _, _, _, _) => - S(Cls, tps.size) + case NuTypeDef(k @ (Cls | Nms), _, tps, _, _, _, _, _) => + S(k, tps.size) case _ => ??? } case _ => N diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 1a9e63bd2b..861e809af9 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -2,14 +2,17 @@ :NewDefs :NoJS -// Adapted example from Code reuse through polymorphic variants (FOSE 2000) -class Nil -//│ class Nil() + +// * Adapted example from Code reuse through polymorphic variants (FOSE 2000) + + +module Nil +//│ module Nil() class Cons(head: A, tail: Cons | Nil) //│ class Cons[A](head: A, tail: Cons[A] | Nil) -let l = Cons(1, Nil()) +let l = Cons(1, Nil) //│ let l: Cons['A] //│ where //│ 'A :> 1 @@ -71,7 +74,7 @@ mixin EvalLambda { let l1 = this.eval(sub, t1) let l2 = this.eval(sub, t2) if t1 is - Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) + Abs(x, t) then this.eval(Cons((x, l2), Nil), t) else App(l1, l2) Abs(x, t) then @@ -100,27 +103,27 @@ module Test1: EvalVar, EvalLambda //│ 'A0 :> (string, 'result,) //│ <: 'A1 & {_1: string, _2: 'result} //│ 'A1 <: 'A & 'A0 -//│ 'result :> Var | App['result] | Abs['result] +//│ 'result :> Var | Abs['result] | App['result] -Test1.eval(Nil(), Var("a")) +Test1.eval(Nil, Var("a")) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var -Test1.eval(Nil(), Abs("b", Var("a"))) +Test1.eval(Nil, Abs("b", Var("a"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var -Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) +Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var -Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) +Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var +//│ 'a :> Abs['a] | Abs[Var] | Var | App['a] class Num(n: int) class Add(l: A, r: A) @@ -162,32 +165,32 @@ module Test2: EvalVar, EvalExpr //│ 'b <: 'a //│ 'A <: {_1: string, _2: 'result} -Test2.eval(Nil(), Var("a")) +Test2.eval(Nil, Var("a")) //│ Num | Var -Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Var("a")) +Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Var("a")) //│ Abs[Var] | Num | Var -Test2.eval(Cons(("a", Num(1)), Nil()), Var("a")) +Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) //│ Num | Var :e -Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.175: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.175: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.133: if v is +//│ ║ l.136: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.143: let vv = map_expr(eta, v) +//│ ║ l.146: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error -Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) +Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) //│ Abs[Var] | Add[Num | Var] | Num | Var module Test3: EvalVar, EvalExpr, EvalLambda @@ -205,15 +208,15 @@ module Test3: EvalVar, EvalExpr, EvalLambda //│ 'c <: 'a //│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | 'b & ~Abs & ~App -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Abs[Var] | Num | Var -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var +//│ 'a :> Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var | App['a] module Test3: EvalVar, EvalLambda, EvalExpr //│ module Test3() { @@ -232,18 +235,18 @@ module Test3: EvalVar, EvalLambda, EvalExpr // Because EvalExpr does not dispatch lambdas to super and map_expr only // handles exprs :e -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.238: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.238: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.133: if v is +//│ ║ l.136: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.143: let vv = map_expr(eta, v) +//│ ║ l.146: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls new file mode 100644 index 0000000000..80615b0761 --- /dev/null +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls @@ -0,0 +1,212 @@ +:NewParser +:NewDefs +:NoJS + + +// * Adapted example from Code reuse through polymorphic variants (FOSE 2000) +// * This time with a List class. + +// FIXME: +// - simplification problem or constraint bug: `'result :> anything <: Num` +// - constraining loop with unannotated `list_assoc` ascription +// - still a number of quite ugly types + + +class List { + fun match: forall 'res; (ifNil: () => 'res, ifCons: (A, List[A]) => 'res) => 'res +} +let Nil: () => List<'a> +let Cons: (head: 'a, tail: List<'a>) => List<'a> +//│ class List[A]() { +//│ fun match: forall 'res. (ifNil: () -> 'res, ifCons: (A, List[A],) -> 'res,) -> 'res +//│ } +//│ let Nil: forall 'a. () -> List['a] +//│ let Cons: forall 'a0. (head: 'a0, tail: List['a0],) -> List['a0] + +class NotFound +class Success(result: A) +//│ class NotFound() +//│ class Success[A](result: A) + +fun eq(l: string, r: string): bool +//│ fun eq: (l: string, r: string,) -> bool + +// * Annotation currently needed to avoid later ascription loop (due to excessive TV refreshing?) +// fun list_assoc(s, l) = +fun list_assoc(s, l: List<'a>) = + l.match( + ifNil: () => NotFound(), + ifCons: (h, t) => + if eq(s, h._1) then Success(h._2) + else list_assoc(s, t) + ) +//│ fun list_assoc: (string, l: List['a],) -> (NotFound | Success['A]) +//│ where +//│ 'a <: {_1: string, _2: 'A} + +list_assoc : (string, List<{ _1: string, _2: 'b }>) => (NotFound | Success['b]) +//│ (string, List[{_1: string, _2: 'b}],) -> (NotFound | Success['b]) + +fun list_assoc(s: string, l: List<{ _1: string, _2: 'b }>): NotFound | Success['b] +//│ fun list_assoc: forall 'b. (s: string, l: List[{_1: string, _2: 'b}],) -> (NotFound | Success['b]) + +class Var(s: string) +//│ class Var(s: string) + +mixin EvalVar { + fun eval(sub, v) = + if v is Var(s) then + if list_assoc(s, sub) is + NotFound then v + Success(r) then r +} +//│ mixin EvalVar() { +//│ fun eval: (List[{_1: string, _2: 'b}], Var,) -> ('b | Var) +//│ } + +class Abs(x: string, t: A) +class App(s: A, t: A) +//│ class Abs[A](x: string, t: A) +//│ class App[A](s: A, t: A) + +fun incr(x: {a: int}): unit +//│ fun incr: (x: {a: int},) -> unit + +fun gensym(): string +//│ fun gensym: () -> string + +fun int_to_string(x: int): string +//│ fun int_to_string: (x: int,) -> string + +mixin EvalLambda { + fun eval(sub, v) = + if v is + App(t1, t2) then + let l1 = this.eval(sub, t1) + let l2 = this.eval(sub, t2) + if t1 is + Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) + else + App(l1, l2) + Abs(x, t) then + let s = gensym() + Abs(s, this.eval(Cons((x, Var(s)), sub), t)) + else + super.eval(sub, v) +} +//│ mixin EvalLambda() { +//│ super: {eval: ('b, 'c,) -> 'd} +//│ this: {eval: (List[out (string, 'e,)], 't,) -> 'd & ('b, 't0,) -> ('e & 'f) & (List[in 'a out 'a | 'a0 | (string, Var,)], 't1,) -> 'g} +//│ fun eval: (List['a1] & 'b, Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'c & ~Abs & ~App,) -> (Abs['g] | App['e | 'f] | 'd) +//│ } +//│ where +//│ 'a1 :> 'a | (string, Var,) +//│ <: 'a0 + +module Test1: EvalVar, EvalLambda +//│ module Test1() { +//│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> 'result +//│ } +//│ where +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | Var +//│ 'result :> anything + +Test1.eval(Nil(), Var("a")) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Var + +Test1.eval(Nil(), Abs("b", Var("a"))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Var + +Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Var + +Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) +//│ 'a +//│ where +//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] + +class Num(n: int) +class Add(l: A, r: A) +class Mul(l: A, r: A) +//│ class Num(n: int) +//│ class Add[A](l: A, r: A) +//│ class Mul[A](l: A, r: A) + +fun map_expr(f, v) = + if v is + Var then v + Num then v + Add(l, r) then Add(f(l), f(r)) + Mul(l, r) then Mul(f(l), f(r)) +//│ fun map_expr: ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) + +mixin EvalExpr { + fun eval(sub, v) = + fun eta(e) = this.eval(sub, e) + let vv = map_expr(eta, v) + if vv is + Var then super.eval(sub, vv) + Add(Num(l), Num(r)) then Num(l + r) + Mul(Num(l), Num(r)) then Num(l * r) + else v +} +//│ mixin EvalExpr() { +//│ super: {eval: ('a, Var,) -> 'b} +//│ this: {eval: ('a, 'c,) -> anything} +//│ fun eval: ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) +//│ } + +module Test2: EvalVar, EvalExpr +//│ module Test2() { +//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> ('b | Num | Var | 'a) +//│ } +//│ where +//│ 'a <: Add['c] | Mul['c] | Num | Var +//│ 'c <: 'a + +Test2.eval(Nil(), Var("a")) +//│ Num | Var + +Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Var("a")) +//│ Abs[Var] | Num | Var + +Test2.eval(Cons(("a", Num(1)), Nil()), Var("a")) +//│ Num | Var + +Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) +//│ Abs[Var] | Add[Num | Var] | Num | Var + +module Test3: EvalVar, EvalExpr, EvalLambda +//│ module Test3() { +//│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> anything +//│ } +//│ where +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | (Add['b] | Mul['b] | Num | Var) & ~Abs & ~App +//│ 'b <: 'a +//│ 'result :> anything +//│ <: Num + +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Num | Var + +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) +//│ 'a +//│ where +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var + +module Test3: EvalVar, EvalLambda, EvalExpr +//│ module Test3() { +//│ fun eval: (List[{_1: string, _2: 'result}], nothing,) -> anything +//│ } +//│ where +//│ 'result :> anything +//│ <: Num + From b644211b7f1b973a7e56370f1a26d37c4740db69 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 27 Feb 2023 08:47:29 +0800 Subject: [PATCH 102/498] Refactor --- .../src/main/scala/mlscript/JSBackend.scala | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index f078d51cfa..ba2e433990 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -476,7 +476,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateModuleDeclaration( moduleSymbol: ModuleSymbol, - base: Opt[Term] + superFields: Ls[Term] = Nil )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") @@ -496,9 +496,41 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } } val rest = constructorScope.declareValue("rest", Some(false), false) + + val bases = superFields.map { sym => sym match { + case App(lhs, _) => S(translateTerm(App(lhs, Tup(Ls())))(constructorScope)) + case _ => S(translateTerm(sym)(constructorScope)) + } } + val base: Opt[JSExpr] = + if (bases.length === 0) N + else if (bases.length === 1) bases.head match { + case Some(JSIdent(nme)) => scope.resolveValue(nme) match { + case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) + case Some(_) => Some(JSIdent(nme)) + case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") + } + case Some(inv: JSInvoke) => Some(inv) + case _ => throw CodeGenError("unresolved parents.") + } + else bases.reduceLeft((res, call) => (res, call) match { + case (S(JSIdent(res)), S(JSIdent(call))) => scope.resolveValue(res) match { + case Some(sym: MixinSymbol) => S(JSInvoke(JSIdent(call), Ls(JSInvoke(JSIdent(res), Ls())))) + case Some(_) => S(JSInvoke(JSIdent(call), Ls(JSIdent(res)))) + case _ => throw CodeGenError(s"unresolved symbol in parents: $res") + } + case (S(res), S(JSIdent(call))) => S(JSInvoke(JSIdent(call), Ls(res))) + case (S(JSIdent(res)), S(JSInvoke(call, _))) => scope.resolveValue(res) match { + case Some(sym: MixinSymbol) => S(JSInvoke(call, Ls(JSInvoke(JSIdent(res), Ls())))) + case Some(_) => S(JSInvoke(call, Ls(JSIdent(res)))) + case _ => throw CodeGenError(s"unresolved symbol in parents: $res") + } + case (S(res), S(JSInvoke(call, _))) => S(JSInvoke(call, Ls(res))) + case _ => throw CodeGenError("unresolved parents.") + }) + val decl = JSClassNewDecl(moduleSymbol.runtimeName, fields, - base.flatMap((b) => S(translateTerm(b))), + base, Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, @@ -566,25 +598,25 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case Some(JSIdent(nme)) => scope.resolveValue(nme) match { case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) case Some(_) => Some(JSIdent(nme)) - case _ => ??? + case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") } case Some(inv: JSInvoke) => Some(inv) - case _ => ??? + case _ => throw CodeGenError("unresolved parents.") } else bases.reduceLeft((res, call) => (res, call) match { case (S(JSIdent(res)), S(JSIdent(call))) => scope.resolveValue(res) match { case Some(sym: MixinSymbol) => S(JSInvoke(JSIdent(call), Ls(JSInvoke(JSIdent(res), Ls())))) case Some(_) => S(JSInvoke(JSIdent(call), Ls(JSIdent(res)))) - case _ => ??? + case _ => throw CodeGenError(s"unresolved symbol in parents: $res") } case (S(res), S(JSIdent(call))) => S(JSInvoke(JSIdent(call), Ls(res))) case (S(JSIdent(res)), S(JSInvoke(call, _))) => scope.resolveValue(res) match { case Some(sym: MixinSymbol) => S(JSInvoke(call, Ls(JSInvoke(JSIdent(res), Ls())))) case Some(_) => S(JSInvoke(call, Ls(JSIdent(res)))) - case _ => ??? + case _ => throw CodeGenError(s"unresolved symbol in parents: $res") } case (S(res), S(JSInvoke(call, _))) => S(JSInvoke(call, Ls(res))) - case _ => ??? + case _ => throw CodeGenError("unresolved parents.") }) val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { @@ -742,33 +774,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { superParameters.put(sym.lexicalName, pars) } case NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { - val params = fs.map { - case (S(nme), Fld(mut, spec, trm)) => - val ty = tt(trm) - nme -> Field(if (mut) S(ty) else N, ty) - case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) - case _ => die - } - if (pars.length > 0) { - val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { - case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) - case _ => ??? - }) - val body = pars.map(tt).foldRight(Record(params): Type)(Inter) - val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { - case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) - case _ => lst - }) - val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members) - modules += sym - superParameters.put(sym.lexicalName, Ls(bases)) - } - else { - val (body, members) = prepare(nme, fs, pars, unit) - val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members) - modules += sym - superParameters.put(sym.lexicalName, pars) - } + val (body, members) = prepare(nme, fs, pars, unit) + val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members) + modules += sym + superParameters.put(sym.lexicalName, pars) } case NuTypeDef(Als, TypeName(nme), tps, _, pars, _, _, _) => { val body = tt(pars.head) @@ -1041,8 +1050,8 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ moduleSymbols.map((m) => translateModuleDeclaration(m, superParameters.get(m.lexicalName) match { - case Some(head :: _) => Some(head) - case _ => None + case Some(lst) => lst + case _ => Nil })(topLevelScope) ) ++ classSymbols.map { sym => From fcde188587bb1e2c1baca4cb472955859744cc17 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 27 Feb 2023 08:52:20 +0800 Subject: [PATCH 103/498] Remove unused parts --- shared/src/main/scala/mlscript/JSBackend.scala | 7 ------- shared/src/main/scala/mlscript/syntax.scala | 1 - 2 files changed, 8 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index ba2e433990..3a9a17252a 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -133,7 +133,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case App(App(App(Var("if"), Tup((_, Fld(_, _, tst)) :: Nil)), Tup((_, Fld(_, _, con)) :: Nil)), Tup((_, Fld(_, _, alt)) :: Nil)) => JSTenary(translateTerm(tst), translateTerm(con), translateTerm(alt)) case App(App(App(Var("if"), tst), con), alt) => die - case App(ce: ClassExpression, _) => JSNew(translateTerm(ce)) // Function invocation case App(trm, Tup(args)) => val callee = trm match { @@ -259,12 +258,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case New(_, TypingUnit(_)) => throw CodeGenError("custom class body is not supported yet") case Forall(_, bod) => translateTerm(bod) - case ClassExpression(TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _), parents) => - val clsBody = scope.declareClass(name, tparams map { _.name }, baseType, members) - parents match { - case Some(p) => JSClassExpr(translateNewClassExpression(clsBody, Ls(p))) - case _ => JSClassExpr(translateNewClassExpression(clsBody)) - } case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index baf5c9b307..a4ea490580 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -78,7 +78,6 @@ final case class TyApp(lhs: Term, targs: Ls[Type]) extends Ter final case class Where(body: Term, where: Ls[Statement]) extends Term final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term -final case class ClassExpression(cls: TypeDef, parents: Opt[Term]) extends Term sealed abstract class IfBody extends IfBodyImpl // final case class IfTerm(expr: Term) extends IfBody // rm? From b33281ecac352b060ce3c2316bfc0f951625eb75 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Feb 2023 10:34:15 +0800 Subject: [PATCH 104/498] WIP Minor fixes --- .../scala/mlscript/ConstraintSolver.scala | 4 +- .../src/main/scala/mlscript/NewParser.scala | 3 +- shared/src/main/scala/mlscript/Token.scala | 3 +- shared/src/test/diff/nu/FunSigs.mls | 2 +- shared/src/test/diff/nu/Mut.mls | 2 +- shared/src/test/diff/nu/NuScratch.mls | 4 ++ .../src/test/diff/nu/ThisRefinedClasses.mls | 53 +++++++++++++------ 7 files changed, 51 insertions(+), 20 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index ead731204b..6c72ac1acb 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -677,7 +677,9 @@ class ConstraintSolver extends NormalForms { self: Typer => case (NegType(lhs), NegType(rhs)) => rec(rhs, lhs, true) case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => - rt.fields.foreach { case (fldNme, fldTy) => + val lti = ctx.tyDefs2(nme) + if (lti.isComputing) reportError() + else rt.fields.foreach { case (fldNme, fldTy) => val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, _ => N), fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 4f6bedca6e..08a6a866b2 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -363,7 +363,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => exprOrIf(0, allowSpace = false) } - cur match { + yeetSpaces match { + case (KEYWORD(";"), _) :: _ => consume; t :: block case (NEWLINE, _) :: _ => consume; t :: block case _ => t :: Nil } diff --git a/shared/src/main/scala/mlscript/Token.scala b/shared/src/main/scala/mlscript/Token.scala index d3af89a7f4..d90bd6f207 100644 --- a/shared/src/main/scala/mlscript/Token.scala +++ b/shared/src/main/scala/mlscript/Token.scala @@ -13,7 +13,8 @@ sealed abstract class Token { case DEINDENT => "deindentation" case ERROR => "error" case LITVAL(value) => "literal" - case KEYWORD(name) => s"'$name' keyword" + case KEYWORD(name) => + if (name.headOption.exists(_.isLetter)) s"'$name' keyword" else s"'$name'" case IDENT(name, symbolic) => if (symbolic) "operator" else "identifier" case SELECT(name) => "selector" case OPEN_BRACKET(k) => s"opening ${k.name}" diff --git a/shared/src/test/diff/nu/FunSigs.mls b/shared/src/test/diff/nu/FunSigs.mls index c8dba5a11d..11c76ef790 100644 --- a/shared/src/test/diff/nu/FunSigs.mls +++ b/shared/src/test/diff/nu/FunSigs.mls @@ -14,7 +14,7 @@ let f = // FIXME fun log: string -> unit -//│ ╔══[PARSE ERROR] Unexpected '->' keyword in expression position +//│ ╔══[PARSE ERROR] Unexpected '->' in expression position //│ ║ l.16: fun log: string -> unit //│ ╙── ^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword diff --git a/shared/src/test/diff/nu/Mut.mls b/shared/src/test/diff/nu/Mut.mls index 3ad49c8659..00e6299c5b 100644 --- a/shared/src/test/diff/nu/Mut.mls +++ b/shared/src/test/diff/nu/Mut.mls @@ -59,7 +59,7 @@ let v1 = {mut x: 1} // * TODO: support this syntax? :pe v1.x = 1 -//│ ╔══[PARSE ERROR] Expected end of input; found '=' keyword instead +//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead //│ ║ l.61: v1.x = 1 //│ ╙── ^ //│ res: int diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index e69de29bb2..391f11a1d5 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -0,0 +1,4 @@ +:NewParser +:NewDefs +:NoJS + diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 26d85e259d..f464abb805 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -11,9 +11,12 @@ :e class Foo { fun test = this.x } -//│ ╔══[ERROR] Unhandled cyclic definition +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.13: class Foo { fun test = this.x } +//│ ║ ^^^^^^ +//│ ╟── reference of type `Foo` does not have field 'x' //│ ║ l.13: class Foo { fun test = this.x } -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^ //│ class Foo() { //│ fun test: error //│ } @@ -22,10 +25,10 @@ class Foo { fun test = this.x } :e class Foo(n: int) { fun test = this.x } //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.23: class Foo(n: int) { fun test = this.x } +//│ ║ l.26: class Foo(n: int) { fun test = this.x } //│ ║ ^^^^^^ //│ ╟── reference of type `Foo & {n: int}` does not have field 'x' -//│ ║ l.23: class Foo(n: int) { fun test = this.x } +//│ ║ l.26: class Foo(n: int) { fun test = this.x } //│ ╙── ^^^^ //│ class Foo(n: int) { //│ fun test: error @@ -35,10 +38,10 @@ class Foo(n: int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.36: class Foo(n: A) { fun test = this.x } +//│ ║ l.39: class Foo(n: A) { fun test = this.x } //│ ║ ^^^^^^ //│ ╟── reference of type `Foo & {Foo#A = ?A, n: A}` does not have field 'x' -//│ ║ l.36: class Foo(n: A) { fun test = this.x } +//│ ║ l.39: class Foo(n: A) { fun test = this.x } //│ ╙── ^^^^ //│ class Foo[A](n: A) { //│ fun test: error @@ -51,14 +54,34 @@ class Foo { this: { x: 'a } // fun test = this.x } -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.50: class Foo { -//│ ║ ^^^^^^^^^^^ -//│ ║ l.51: this: { x: 'a } -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.52: // fun test = this.x -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.53: } -//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.54: this: { x: 'a } +//│ ║ ^^^^ +//│ ╟── reference of type `Foo` does not have field 'x' +//│ ╟── Note: constraint arises from record type: +//│ ║ l.54: this: { x: 'a } +//│ ╙── ^^^^^^^^^ //│ class Foo() + +// TODO +// * All on one line: +class Test { this: { x: int}; fun test = this.x } +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } +//│ ║ ^^^^ +//│ ╟── reference of type `Test` does not have field 'x' +//│ ╟── Note: constraint arises from record type: +//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } +//│ ║ ^^^^^^ +//│ ╟── reference of type `Test` does not have field 'x' +//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } +//│ ╙── ^^^^ +//│ class Test() { +//│ fun test: error +//│ } + + From 48568ebabee7fe49a79212c4b74b6143217bb109 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Feb 2023 10:37:10 +0800 Subject: [PATCH 105/498] WIP Support `->` for function types --- shared/src/main/scala/mlscript/NewLexer.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 1 + shared/src/test/diff/nu/FunSigs.mls | 12 +----------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 98550d0126..dbd4b5b51f 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -33,7 +33,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { ) private val isSymKeyword = Set( - "->", + // "->", "=", ":", ";", diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index cf80e7a267..57452c4162 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -543,6 +543,7 @@ trait TermImpl extends StatementImpl { self: Term => case lit: Lit => Literal(lit) case App(App(Var("|"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Inter(lhs.toType_!, rhs.toType_!) + case App(App(Var("->"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Function(lhs.toType_!, rhs.toType_!) case App(App(Var("|"), lhs), rhs) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), lhs), rhs) => Inter(lhs.toType_!, rhs.toType_!) case Lam(lhs, rhs) => Function(lhs.toType_!, rhs.toType_!) diff --git a/shared/src/test/diff/nu/FunSigs.mls b/shared/src/test/diff/nu/FunSigs.mls index 11c76ef790..cc5c35ebc5 100644 --- a/shared/src/test/diff/nu/FunSigs.mls +++ b/shared/src/test/diff/nu/FunSigs.mls @@ -12,18 +12,8 @@ let f = //│ = //│ log is not implemented -// FIXME fun log: string -> unit -//│ ╔══[PARSE ERROR] Unexpected '->' in expression position -//│ ║ l.16: fun log: string -> unit -//│ ╙── ^^ -//│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.16: fun log: string -> unit -//│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 -//│ ║ l.16: fun log: string -> unit -//│ ╙── ^^^^^^^^^^^^^^ -//│ log: string +//│ log: string -> unit //│ = fun log: string => unit From 293128e7bdca3e25d7bbf723ca5a683e5405b7b9 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 27 Feb 2023 14:49:41 +0800 Subject: [PATCH 106/498] Fix class symbol --- .../src/main/scala/mlscript/JSBackend.scala | 13 +- .../main/scala/mlscript/codegen/Scope.scala | 12 + .../main/scala/mlscript/codegen/Symbol.scala | 24 +- shared/src/test/diff/nu/ECOOP23_codegen.mls | 234 +++++++++++++++++- 4 files changed, 267 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 3a9a17252a..2648cbd25c 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -101,6 +101,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSIdent(sym.runtimeName) case S(sym: ModuleSymbol) => JSIdent(sym.runtimeName) + case S(sym: NewClassSymbol) => + JSIdent(sym.runtimeName) case S(sym: ClassSymbol) => if (isCallee) JSNew(JSIdent(sym.runtimeName)) @@ -288,6 +290,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSBinary("===", scrut.member("constructor"), JSLit("String")) case Var(name) => topLevelScope.getType(name) match { case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(runtimeName)) + case S(NewClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(runtimeName), JSIdent(JSLit.makeStringLiteral("class")))) case S(TraitSymbol(_, runtimeName, _, _, _)) => JSIdent(runtimeName)("is")(scrut) case S(_: TypeAliasSymbol) => throw new CodeGenError(s"cannot match type alias $name") case N => throw new CodeGenError(s"unknown match case: $name") @@ -539,7 +542,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def translateNewClassDeclaration( - classSymbol: ClassSymbol, + classSymbol: NewClassSymbol, superFields: Ls[Term] = Nil, rest: Opt[Str] = N )(implicit scope: Scope): JSClassGetter = { @@ -564,7 +567,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def translateNewClassExpression( - classSymbol: ClassSymbol, + classSymbol: NewClassSymbol, superFields: Ls[Term] = Nil, rest: Opt[Str] = N )(implicit scope: Scope): JSClassNewDecl = { @@ -731,9 +734,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def declareNewTypeDefs(typeDefs: Ls[NuTypeDef]): - (Ls[TraitSymbol], Ls[ClassSymbol], Ls[MixinSymbol], Ls[ModuleSymbol], HashMap[String, Ls[Term]]) = { + (Ls[TraitSymbol], Ls[NewClassSymbol], Ls[MixinSymbol], Ls[ModuleSymbol], HashMap[String, Ls[Term]]) = { val traits = new ListBuffer[TraitSymbol]() - val classes = new ListBuffer[ClassSymbol]() + val classes = new ListBuffer[NewClassSymbol]() val mixins = new ListBuffer[MixinSymbol]() val modules = new ListBuffer[ModuleSymbol]() val superParameters = HashMap[String, Ls[Term]]() @@ -778,7 +781,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { val (body, members) = prepare(nme, fs, pars, unit) - val sym = topLevelScope.declareClass(nme, tps map { _._2.name }, body, members) + val sym = topLevelScope.declareNewClass(nme, tps map { _._2.name }, body, members) classes += sym superParameters.put(sym.lexicalName, pars) } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 4d876841b2..63e3972665 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -220,6 +220,18 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } + def declareNewClass( + lexicalName: Str, + params: Ls[Str], + base: Type, + methods: Ls[MethodDef[Left[Term, Type]]] + ): NewClassSymbol = { + val runtimeName = allocateRuntimeName(lexicalName) + val symbol = NewClassSymbol(lexicalName, runtimeName, params.sorted, base, methods) + register(symbol) + symbol + } + def declareMixin( lexicalName: Str, params: Ls[Str], diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index 6bd700e25d..b9f757e24a 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -85,6 +85,22 @@ final case class ClassSymbol( override def toString: Str = s"class $lexicalName ($runtimeName)" } +final case class NewClassSymbol( + lexicalName: Str, + runtimeName: Str, + params: Ls[Str], + body: Type, + methods: Ls[MethodDef[Left[Term, Type]]], +) extends TypeSymbol + with RuntimeSymbol with Ordered[NewClassSymbol] { + + import scala.math.Ordered.orderingToOrdered + + override def compare(that: NewClassSymbol): Int = lexicalName.compare(that.lexicalName) + + override def toString: Str = s"new class $lexicalName ($runtimeName)" +} + final case class MixinSymbol( lexicalName: Str, runtimeName: Str, @@ -92,11 +108,11 @@ final case class MixinSymbol( body: Type, methods: Ls[MethodDef[Left[Term, Type]]], ) extends TypeSymbol - with RuntimeSymbol with Ordered[ClassSymbol] { + with RuntimeSymbol with Ordered[MixinSymbol] { import scala.math.Ordered.orderingToOrdered - override def compare(that: ClassSymbol): Int = lexicalName.compare(that.lexicalName) + override def compare(that: MixinSymbol): Int = lexicalName.compare(that.lexicalName) override def toString: Str = s"mixin $lexicalName ($runtimeName)" } @@ -108,11 +124,11 @@ final case class ModuleSymbol( body: Type, methods: Ls[MethodDef[Left[Term, Type]]], ) extends TypeSymbol - with RuntimeSymbol with Ordered[ClassSymbol] { + with RuntimeSymbol with Ordered[ModuleSymbol] { import scala.math.Ordered.orderingToOrdered - override def compare(that: ClassSymbol): Int = lexicalName.compare(that.lexicalName) + override def compare(that: ModuleSymbol): Int = lexicalName.compare(that.lexicalName) override def toString: Str = s"module $lexicalName ($runtimeName)" } diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 5afdb528c8..979cd8a6d5 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -2,6 +2,7 @@ :NewDefs :js +:ShowRepl class Add(lhs: E, rhs: E) class Lit(n: int) //│ class Add[E](lhs: E, rhs: E) @@ -39,8 +40,46 @@ class Lit(n: int) //│ globalThis.Add = typing_unit.Add; //│ globalThis.Lit = typing_unit.Lit; //│ // End of generated code +//│ ┌ Block at ECOOP23_codegen.mls:6 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let res; +//│ │ │ let typing_unit = { +//│ │ │ cache: {}, +//│ │ │ get Add() { +//│ │ │ if (this.cache.Add === undefined) { +//│ │ │ class Add { +//│ │ │ constructor(lhs, rhs) { +//│ │ │ this.lhs = lhs; +//│ │ │ this.rhs = rhs; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ │ │ this.cache.Add["class"] = Add; +//│ │ │ } +//│ │ │ return this.cache.Add; +//│ │ │ }, +//│ │ │ get Lit() { +//│ │ │ if (this.cache.Lit === undefined) { +//│ │ │ class Lit { +//│ │ │ constructor(n) { +//│ │ │ this.n = n; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Lit = ((n) => new Lit(n)); +//│ │ │ this.cache.Lit["class"] = Lit; +//│ │ │ } +//│ │ │ return this.cache.Lit; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Add = typing_unit.Add; +//│ │ │ globalThis.Lit = typing_unit.Lit; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [class Lit] } +//│ └── No queries :js +:ShowRepl mixin EvalBase { fun eval(e) = if e is @@ -63,7 +102,7 @@ mixin EvalBase { //│ const self = this; //│ return ((() => { //│ let a; -//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { //│ throw new Error("non-exhaustive case expression"); //│ })()); //│ })()); @@ -78,7 +117,7 @@ mixin EvalBase { //│ const self = this; //│ return ((() => { //│ let a; -//│ return (a = e, a instanceof Lit ? ((n) => n)(e.n) : a instanceof Add ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { //│ throw new Error("non-exhaustive case expression"); //│ })()); //│ })()); @@ -89,8 +128,51 @@ mixin EvalBase { //│ }; //│ globalThis.EvalBase = typing_unit1.EvalBase; //│ // End of generated code +//│ ┌ Block at ECOOP23_codegen.mls:83 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit1 = { +//│ │ │ cache: {}, +//│ │ │ EvalBase(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class EvalBase { +//│ │ │ constructor() { +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ let a; +//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ │ │ throw new Error("non-exhaustive case expression"); +//│ │ │ })()); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class EvalBase extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ let a; +//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ │ │ throw new Error("non-exhaustive case expression"); +//│ │ │ })()); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.EvalBase = typing_unit1.EvalBase; +//│ │ └── Reply +//│ │ [Function: EvalBase] +//│ └── No queries :js +:ShowRepl class Neg(expr: A) //│ class Neg[A](expr: A) //│ // Prelude @@ -111,8 +193,31 @@ class Neg(expr: A) //│ }; //│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code +//│ ┌ Block at ECOOP23_codegen.mls:176 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit2 = { +//│ │ │ cache: {}, +//│ │ │ get Neg() { +//│ │ │ if (this.cache.Neg === undefined) { +//│ │ │ class Neg { +//│ │ │ constructor(expr) { +//│ │ │ this.expr = expr; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Neg = ((expr) => new Neg(expr)); +//│ │ │ this.cache.Neg["class"] = Neg; +//│ │ │ } +//│ │ │ return this.cache.Neg; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Neg = typing_unit2.Neg; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [class Neg] } +//│ └── No queries :js +:ShowRepl mixin EvalNeg { fun eval(e) = if e is Neg(d) then 0 - this.eval(d) @@ -134,7 +239,7 @@ mixin EvalNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); @@ -146,7 +251,7 @@ mixin EvalNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); @@ -155,8 +260,45 @@ mixin EvalNeg { //│ }; //│ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ // End of generated code +//│ ┌ Block at ECOOP23_codegen.mls:221 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit3 = { +//│ │ │ cache: {}, +//│ │ │ EvalNeg(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class EvalNeg { +//│ │ │ constructor() { +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class EvalNeg extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.EvalNeg = typing_unit3.EvalNeg; +//│ │ └── Reply +//│ │ [Function: EvalNeg] +//│ └── No queries :js +:ShowRepl mixin EvalNegNeg { fun eval(e) = if e is Neg(Neg(d)) then this.eval(d) @@ -178,7 +320,7 @@ mixin EvalNegNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); @@ -190,7 +332,7 @@ mixin EvalNegNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg ? ((tmp0) => tmp0 instanceof Neg ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); @@ -199,8 +341,45 @@ mixin EvalNegNeg { //│ }; //│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ // End of generated code +//│ ┌ Block at ECOOP23_codegen.mls:302 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit4 = { +//│ │ │ cache: {}, +//│ │ │ EvalNegNeg(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class EvalNegNeg { +//│ │ │ constructor() { +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class EvalNegNeg extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; +//│ │ └── Reply +//│ │ [Function: EvalNegNeg] +//│ └── No queries :js +:ShowRepl module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { //│ fun eval: 'a -> int @@ -224,8 +403,29 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ }; //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code +//│ ┌ Block at ECOOP23_codegen.mls:383 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit5 = { +//│ │ │ cache: {}, +//│ │ │ get TestLang() { +//│ │ │ if (this.cache.TestLang === undefined) { +//│ │ │ this.cache.TestLang = new class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ }; +//│ │ │ } +//│ │ │ return this.cache.TestLang; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.TestLang = typing_unit5.TestLang; +//│ │ └── Reply +//│ │ TestLang {} +//│ └── No queries :js +:ShowRepl fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) @@ -239,8 +439,28 @@ TestLang.eval(mk(0)) //│ let typing_unit6 = { cache: {} }; //│ // Query 1 //│ globalThis.mk = function mk(n) { -//│ return n == 0 === true ? new Lit(0) : n == 1 === true ? new Neg(mk(n)) : new Add(mk(n), mk(n)); +//│ return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); //│ }; //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code +//│ ┌ Block at ECOOP23_codegen.mls:429 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit6 = { cache: {} }; +//│ │ └── Reply +//│ │ undefined +//│ ├─┬ Query 1/2 +//│ │ ├── Prelude: +//│ │ ├── Code: +//│ │ ├── globalThis.mk = function mk(n) { +//│ │ ├── return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); +//│ │ ├── }; +//│ │ ├── Intermediate: [Function: mk] +//│ │ └── Reply: [success] [Function: mk] +//│ └─┬ Query 2/2 +//│ ├── Prelude: +//│ ├── Code: +//│ ├── res = TestLang.eval(mk(0)); +//│ ├── Intermediate: 0 +//│ └── Reply: [success] 0 From 37c5609a3fa53c19ccdd32f3b548cd35069d0e3f Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 27 Feb 2023 15:11:42 +0800 Subject: [PATCH 107/498] Fix class parents --- .../src/main/scala/mlscript/JSBackend.scala | 137 +++++------------- shared/src/test/diff/nu/Super.mls | 2 +- 2 files changed, 40 insertions(+), 99 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 2648cbd25c..6a20fdcef0 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -414,7 +414,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { classSymbol: ClassSymbol, baseClassSymbol: Opt[ClassSymbol] )(implicit scope: Scope): JSClassDecl = { - // Translate class methods and getters. + // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") val members = classSymbol.methods.map { translateClassMember(_)(classScope) @@ -470,60 +470,67 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { ))) } - protected def translateModuleDeclaration( - moduleSymbol: ModuleSymbol, - superFields: Ls[Term] = Nil - )(implicit scope: Scope): JSClassGetter = { - val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") - val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") - val constructorScope = moduleScope.derive(s"${moduleSymbol.lexicalName} constructor") - val members = moduleSymbol.methods.map { - translateClassMember(_)(moduleScope) - } - // Collect class fields. - val fields = moduleSymbol.body.collectFields ++ - moduleSymbol.body.collectTypeNames.flatMap(resolveTraitFields) - val traits = moduleSymbol.body.collectTypeNames.flatMap { - name => scope.getType(name) match { - case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) - case S(_: ClassSymbol) => N - case S(_: TypeSymbol) => N - case N => N - } - } - val rest = constructorScope.declareValue("rest", Some(false), false) - + private def translateParents(superFields: Ls[Term], constructorScope: Scope)(implicit scope: Scope): Opt[JSExpr] = { val bases = superFields.map { sym => sym match { case App(lhs, _) => S(translateTerm(App(lhs, Tup(Ls())))(constructorScope)) case _ => S(translateTerm(sym)(constructorScope)) } } - val base: Opt[JSExpr] = - if (bases.length === 0) N + + if (bases.length === 0) N else if (bases.length === 1) bases.head match { case Some(JSIdent(nme)) => scope.resolveValue(nme) match { case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) - case Some(_) => Some(JSIdent(nme)) + case Some(_) => Some(JSMember(JSIdent(nme), JSLit(JSLit.makeStringLiteral("class")))) + case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") + } + case Some(JSInvoke(JSIdent(nme), _)) => scope.resolveValue(nme) match { + case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) + case Some(_) => Some(JSMember(JSIdent(nme), JSLit(JSLit.makeStringLiteral("class")))) case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") } - case Some(inv: JSInvoke) => Some(inv) case _ => throw CodeGenError("unresolved parents.") } else bases.reduceLeft((res, call) => (res, call) match { case (S(JSIdent(res)), S(JSIdent(call))) => scope.resolveValue(res) match { case Some(sym: MixinSymbol) => S(JSInvoke(JSIdent(call), Ls(JSInvoke(JSIdent(res), Ls())))) - case Some(_) => S(JSInvoke(JSIdent(call), Ls(JSIdent(res)))) + case Some(_) => S(JSInvoke(JSIdent(call), Ls(JSMember(JSIdent(res), JSLit(JSLit.makeStringLiteral("class")))))) case _ => throw CodeGenError(s"unresolved symbol in parents: $res") } case (S(res), S(JSIdent(call))) => S(JSInvoke(JSIdent(call), Ls(res))) case (S(JSIdent(res)), S(JSInvoke(call, _))) => scope.resolveValue(res) match { case Some(sym: MixinSymbol) => S(JSInvoke(call, Ls(JSInvoke(JSIdent(res), Ls())))) - case Some(_) => S(JSInvoke(call, Ls(JSIdent(res)))) + case Some(_) => S(JSInvoke(call, Ls(JSMember(JSIdent(res), JSLit(JSLit.makeStringLiteral("class")))))) case _ => throw CodeGenError(s"unresolved symbol in parents: $res") } case (S(res), S(JSInvoke(call, _))) => S(JSInvoke(call, Ls(res))) case _ => throw CodeGenError("unresolved parents.") }) + } + protected def translateModuleDeclaration( + moduleSymbol: ModuleSymbol, + superFields: Ls[Term] = Nil + )(implicit scope: Scope): JSClassGetter = { + val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") + val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") + val constructorScope = moduleScope.derive(s"${moduleSymbol.lexicalName} constructor") + val members = moduleSymbol.methods.map { + translateClassMember(_)(moduleScope) + } + // Collect class fields. + val fields = moduleSymbol.body.collectFields ++ + moduleSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + val traits = moduleSymbol.body.collectTypeNames.flatMap { + name => scope.getType(name) match { + case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) + case S(_: ClassSymbol) => N + case S(_: TypeSymbol) => N + case N => N + } + } + val rest = constructorScope.declareValue("rest", Some(false), false) + val base: Opt[JSExpr] = + translateParents(superFields, constructorScope) val decl = JSClassNewDecl(moduleSymbol.runtimeName, fields, base, @@ -574,7 +581,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") val members = classSymbol.methods.map { - translateNewClassMember(_)(classScope) + translateClassMember(_)(classScope) } // Collect class fields. val fields = classSymbol.body.collectFields ++ @@ -583,37 +590,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") fields.foreach(constructorScope.declareValue(_, Some(false), false)) val restRuntime = rest.flatMap(name => S(constructorScope.declareValue(name, Some(false), false).runtimeName)) - - val bases = superFields.map { sym => sym match { - case App(lhs, _) => S(translateTerm(App(lhs, Tup(Ls())))(constructorScope)) - case _ => S(translateTerm(sym)(constructorScope)) - } } val base: Opt[JSExpr] = - if (bases.length === 0) N - else if (bases.length === 1) bases.head match { - case Some(JSIdent(nme)) => scope.resolveValue(nme) match { - case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) - case Some(_) => Some(JSIdent(nme)) - case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") - } - case Some(inv: JSInvoke) => Some(inv) - case _ => throw CodeGenError("unresolved parents.") - } - else bases.reduceLeft((res, call) => (res, call) match { - case (S(JSIdent(res)), S(JSIdent(call))) => scope.resolveValue(res) match { - case Some(sym: MixinSymbol) => S(JSInvoke(JSIdent(call), Ls(JSInvoke(JSIdent(res), Ls())))) - case Some(_) => S(JSInvoke(JSIdent(call), Ls(JSIdent(res)))) - case _ => throw CodeGenError(s"unresolved symbol in parents: $res") - } - case (S(res), S(JSIdent(call))) => S(JSInvoke(JSIdent(call), Ls(res))) - case (S(JSIdent(res)), S(JSInvoke(call, _))) => scope.resolveValue(res) match { - case Some(sym: MixinSymbol) => S(JSInvoke(call, Ls(JSInvoke(JSIdent(res), Ls())))) - case Some(_) => S(JSInvoke(call, Ls(JSIdent(res)))) - case _ => throw CodeGenError(s"unresolved symbol in parents: $res") - } - case (S(res), S(JSInvoke(call, _))) => S(JSInvoke(call, Ls(res))) - case _ => throw CodeGenError("unresolved parents.") - }) + translateParents(superFields, constructorScope) val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) @@ -675,43 +653,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } } - private def translateNewClassMember( - method: MethodDef[Left[Term, Type]], - )(implicit scope: Scope): JSClassMemberDecl = { - val name = method.nme.name - // Create the method/getter scope. - val memberScope = method.rhs.value match { - case _: Lam => scope.derive(s"method $name") - case _ => scope.derive(s"getter $name") - } - // Declare the alias for `this` before declaring parameters. - val selfSymbol = memberScope.declareThisAlias() - val superSymbol = memberScope.declareSuper() - // Declare parameters. - val (memberParams, body) = method.rhs.value match { - case Lam(params, body) => - val methodParams = translateParams(params)(memberScope) - (S(methodParams), body) - case term => - (N, term) - } - // Translate class member body. - val bodyResult = translateTerm(body)(memberScope).`return` - // If `this` is accessed, add `const self = this`. - val bodyStmts = if (visitedSymbols(selfSymbol)) { - val thisDecl = JSConstDecl(selfSymbol.runtimeName, JSIdent("this")) - visitedSymbols -= selfSymbol - R(thisDecl :: bodyResult :: Nil) - } else { - R(bodyResult :: Nil) - } - // Returns members depending on what it is. - memberParams match { - case S(memberParams) => JSClassMethod(name, memberParams, bodyStmts) - case N => JSClassGetter(name, bodyStmts) - } - } - /** * Declare symbols for types, traits and classes. * Call this before the code generation. diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index 7877af5090..95f5195229 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -36,7 +36,7 @@ class Bar(x: int, y: int): Foo(x + y) //│ cache: {}, //│ get Bar() { //│ if (this.cache.Bar === undefined) { -//│ class Bar extends new Foo() { +//│ class Bar extends Foo["class"] { //│ constructor(x, y) { //│ super(x + y); //│ this.x = x; From 220e89b610f1b2418fb4ed6981ee7c46d63ceaff Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 27 Feb 2023 15:13:44 +0800 Subject: [PATCH 108/498] Add show repl --- shared/src/test/diff/nu/Super.mls | 175 +++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 3 deletions(-) diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index 95f5195229..ab3a2d93a1 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -2,6 +2,7 @@ :NewDefs :js +:ShowRepl class Foo(x: int) //│ class Foo(x: int) //│ // Prelude @@ -23,12 +24,36 @@ class Foo(x: int) //│ }; //│ globalThis.Foo = typing_unit.Foo; //│ // End of generated code +//│ ┌ Block at Super.mls:6 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let res; +//│ │ │ let typing_unit = { +//│ │ │ cache: {}, +//│ │ │ get Foo() { +//│ │ │ if (this.cache.Foo === undefined) { +//│ │ │ class Foo { +//│ │ │ constructor(x) { +//│ │ │ this.x = x; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Foo = ((x) => new Foo(x)); +//│ │ │ this.cache.Foo["class"] = Foo; +//│ │ │ } +//│ │ │ return this.cache.Foo; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Foo = typing_unit.Foo; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [class Foo] } +//│ └── No queries :js :e +:ShowRepl class Bar(x: int, y: int): Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.29: class Bar(x: int, y: int): Foo(x + y) +//│ ║ l.31: class Bar(x: int, y: int): Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) //│ // Prelude @@ -51,9 +76,34 @@ class Bar(x: int, y: int): Foo(x + y) //│ }; //│ globalThis.Bar = typing_unit1.Bar; //│ // End of generated code +//│ ┌ Block at Super.mls:31 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit1 = { +//│ │ │ cache: {}, +//│ │ │ get Bar() { +//│ │ │ if (this.cache.Bar === undefined) { +//│ │ │ class Bar extends Foo["class"] { +//│ │ │ constructor(x, y) { +//│ │ │ super(x + y); +//│ │ │ this.x = x; +//│ │ │ this.y = y; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Bar = ((x, y) => new Bar(x, y)); +//│ │ │ this.cache.Bar["class"] = Bar; +//│ │ │ } +//│ │ │ return this.cache.Bar; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Bar = typing_unit1.Bar; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [class Bar extends Foo] } +//│ └── No queries :js +:ShowRepl mixin AA(a: int) { } //│ mixin AA() @@ -78,8 +128,34 @@ mixin AA(a: int) { //│ }; //│ globalThis.AA = typing_unit2.AA; //│ // End of generated code +//│ ┌ Block at Super.mls:60 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit2 = { +//│ │ │ cache: {}, +//│ │ │ AA(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class AA { +//│ │ │ constructor(a) { +//│ │ │ this.a = a; +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class AA extends base { +//│ │ │ constructor(a, ...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.AA = typing_unit2.AA; +//│ │ └── Reply +//│ │ [Function: AA] +//│ └── No queries :js +:ShowRepl mixin BB {} //│ mixin BB() //│ // Prelude @@ -99,8 +175,30 @@ mixin BB {} //│ }; //│ globalThis.BB = typing_unit3.BB; //│ // End of generated code +//│ ┌ Block at Super.mls:87 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit3 = { +//│ │ │ cache: {}, +//│ │ │ BB(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return class BB {}; +//│ │ │ } else { +//│ │ │ return (class BB extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.BB = typing_unit3.BB; +//│ │ └── Reply +//│ │ [Function: BB] +//│ └── No queries :js +:ShowRepl class C(x: int): BB //│ class C(x: int) //│ // Prelude @@ -122,12 +220,36 @@ class C(x: int): BB //│ }; //│ globalThis.C = typing_unit4.C; //│ // End of generated code +//│ ┌ Block at Super.mls:109 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit4 = { +//│ │ │ cache: {}, +//│ │ │ get C() { +//│ │ │ if (this.cache.C === undefined) { +//│ │ │ class C extends BB() { +//│ │ │ constructor(x) { +//│ │ │ super(); +//│ │ │ this.x = x; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.C = ((x) => new C(x)); +//│ │ │ this.cache.C["class"] = C; +//│ │ │ } +//│ │ │ return this.cache.C; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.C = typing_unit4.C; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [Function: C] } +//│ └── No queries :js :e +:ShowRepl class D(x: int): AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.128: class D(x: int): AA(x) +//│ ║ l.134: class D(x: int): AA(x) //│ ╙── ^^^^^ //│ class D(x: int) //│ // Prelude @@ -149,12 +271,36 @@ class D(x: int): AA(x) //│ }; //│ globalThis.D = typing_unit5.D; //│ // End of generated code +//│ ┌ Block at Super.mls:134 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit5 = { +//│ │ │ cache: {}, +//│ │ │ get D() { +//│ │ │ if (this.cache.D === undefined) { +//│ │ │ class D extends AA() { +//│ │ │ constructor(x) { +//│ │ │ super(x); +//│ │ │ this.x = x; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.D = ((x) => new D(x)); +//│ │ │ this.cache.D["class"] = D; +//│ │ │ } +//│ │ │ return this.cache.D; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.D = typing_unit5.D; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [Function: D] } +//│ └── No queries :js :e +:ShowRepl class E(x: int): BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.155: class E(x: int): BB, AA(x) +//│ ║ l.162: class E(x: int): BB, AA(x) //│ ╙── ^^^^^ //│ class E(x: int) //│ // Prelude @@ -176,3 +322,26 @@ class E(x: int): BB, AA(x) //│ }; //│ globalThis.E = typing_unit6.E; //│ // End of generated code +//│ ┌ Block at Super.mls:162 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit6 = { +//│ │ │ cache: {}, +//│ │ │ get E() { +//│ │ │ if (this.cache.E === undefined) { +//│ │ │ class E extends AA(BB()) { +//│ │ │ constructor(x) { +//│ │ │ super(x); +//│ │ │ this.x = x; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.E = ((x) => new E(x)); +//│ │ │ this.cache.E["class"] = E; +//│ │ │ } +//│ │ │ return this.cache.E; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.E = typing_unit6.E; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [Function: E] } +//│ └── No queries From fe2cb71b4df94a4c77ddf02c0ca9d3e1f9a1c647 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Feb 2023 15:58:46 +0800 Subject: [PATCH 109/498] WIP Add Node result value printing to newDefs --- shared/src/test/diff/nu/ECOOP23_codegen.mls | 2 ++ shared/src/test/diff/nu/NuScratch.mls | 1 - shared/src/test/diff/nu/Super.mls | 18 +++++++++--------- shared/src/test/scala/mlscript/DiffTests.scala | 16 +++++++++++----- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 979cd8a6d5..16e993f98a 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -464,3 +464,5 @@ TestLang.eval(mk(0)) //│ ├── res = TestLang.eval(mk(0)); //│ ├── Intermediate: 0 //│ └── Reply: [success] 0 +//│ res +//│ = [Function: mk] diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index 391f11a1d5..b95a5f855e 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,4 +1,3 @@ :NewParser :NewDefs -:NoJS diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index ab3a2d93a1..f3668e8470 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -53,7 +53,7 @@ class Foo(x: int) :ShowRepl class Bar(x: int, y: int): Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.31: class Bar(x: int, y: int): Foo(x + y) +//│ ║ l.54: class Bar(x: int, y: int): Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) //│ // Prelude @@ -76,7 +76,7 @@ class Bar(x: int, y: int): Foo(x + y) //│ }; //│ globalThis.Bar = typing_unit1.Bar; //│ // End of generated code -//│ ┌ Block at Super.mls:31 +//│ ┌ Block at Super.mls:54 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit1 = { @@ -128,7 +128,7 @@ mixin AA(a: int) { //│ }; //│ globalThis.AA = typing_unit2.AA; //│ // End of generated code -//│ ┌ Block at Super.mls:60 +//│ ┌ Block at Super.mls:107 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit2 = { @@ -175,7 +175,7 @@ mixin BB {} //│ }; //│ globalThis.BB = typing_unit3.BB; //│ // End of generated code -//│ ┌ Block at Super.mls:87 +//│ ┌ Block at Super.mls:159 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit3 = { @@ -220,7 +220,7 @@ class C(x: int): BB //│ }; //│ globalThis.C = typing_unit4.C; //│ // End of generated code -//│ ┌ Block at Super.mls:109 +//│ ┌ Block at Super.mls:202 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit4 = { @@ -249,7 +249,7 @@ class C(x: int): BB :ShowRepl class D(x: int): AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.134: class D(x: int): AA(x) +//│ ║ l.250: class D(x: int): AA(x) //│ ╙── ^^^^^ //│ class D(x: int) //│ // Prelude @@ -271,7 +271,7 @@ class D(x: int): AA(x) //│ }; //│ globalThis.D = typing_unit5.D; //│ // End of generated code -//│ ┌ Block at Super.mls:134 +//│ ┌ Block at Super.mls:250 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit5 = { @@ -300,7 +300,7 @@ class D(x: int): AA(x) :ShowRepl class E(x: int): BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.162: class E(x: int): BB, AA(x) +//│ ║ l.301: class E(x: int): BB, AA(x) //│ ╙── ^^^^^ //│ class E(x: int) //│ // Prelude @@ -322,7 +322,7 @@ class E(x: int): BB, AA(x) //│ }; //│ globalThis.E = typing_unit6.E; //│ // End of generated code -//│ ┌ Block at Super.mls:162 +//│ ┌ Block at Super.mls:301 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit6 = { diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 92523840c7..47ba7dbdbc 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -493,7 +493,7 @@ class DiffTests } } - val (typeDefs, stmts) = if (newDefs) { + val (typeDefs, stmts, newDefsResults) = if (newDefs) { // /* val vars: Map[Str, typer.SimpleType] = Map.empty @@ -602,7 +602,13 @@ class DiffTests // FirstClassDefn() - (Nil, Nil) + // (Nil, Nil, N) + (Nil, Nil, S(p.tops.collect { + // case LetS(isRec, pat, bod) => ("res", Nil, Nil, false) + case NuFunDef(isLet @ S(_), nme, tparams, bod) => + (nme.name + " ", nme.name :: Nil, Nil, false) + case t: Term => ("res ", "res" :: Nil, Nil, false) + })) } else { @@ -622,7 +628,7 @@ class DiffTests // else typer.processTypeDefs(typeDefs)(ctx, raise) - (typeDefs, stmts) + (typeDefs, stmts, N) } // initialize ts typegen code builder and @@ -727,7 +733,7 @@ class DiffTests // generate typescript types if generateTsDeclarations flag is // set in the mode // The tuple type means: (, , , ) - val typerResults: Ls[(Str, Ls[Str], Ls[Str], Bool)] = stmts.map { stmt => + val typerResults: Ls[(Str, Ls[Str], Ls[Str], Bool)] = newDefsResults getOrElse stmts.map { stmt => // Because diagnostic lines are after the typing results, // we need to cache the diagnostic blocks and add them to the // `typerResults` buffer after the statement has been processed. @@ -910,7 +916,7 @@ class DiffTests } case L(other) => // Print type checking results first. - typerResults.foreach { case (_, typingLines, diagnosticLines, typeBeforeDiags) => + if (!newDefs) typerResults.foreach { case (_, typingLines, diagnosticLines, typeBeforeDiags) => if (typeBeforeDiags) { typingLines.foreach(output) diagnosticLines.foreach(output) From ef471480cbc4c8172250ce7cf9d39dc4e4482b37 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Feb 2023 16:12:12 +0800 Subject: [PATCH 110/498] WIPIP Try more codegen, uncovering problem with nested let --- .../src/main/scala/mlscript/NuTypeDefs.scala | 6 +- shared/src/test/diff/nu/LetRec.mls | 71 ++++++++- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 78 ++++++++-- shared/src/test/diff/nu/SimpleRegionDSL.mls | 136 +++++++++++++++--- 4 files changed, 250 insertions(+), 41 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index dbccbb990a..46c5b99af3 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -350,7 +350,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => named.updateWith(decl.name) { case sv @ S(v) => // * TODO allow defining a previously given signature - err(msg"Refininition of ${decl.name}", decl.toLoc) + decl match { + case NuFunDef(S(_), _, _, _) => () + case _ => + err(msg"Refininition of ${decl.name}", decl.toLoc) + } S(lti) case N => S(lti) diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index e086659b48..f25171200b 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -1,49 +1,112 @@ :NewParser :NewDefs -:NoJS // TODO rm +// :NoJS // TODO rm :js fun f(x) = x > 0 && f(x - 1) //│ fun f: int -> bool +//│ // Prelude +//│ let res; +//│ let typing_unit = { cache: {} }; +//│ // Query 1 +//│ globalThis.f = function f(x) { +//│ return x > 0 && f(x - 1); +//│ }; +//│ // End of generated code f(12) //│ bool +//│ res +//│ = false :js let rec f(x) = x > 0 && f(x - 1) //│ let rec f: int -> bool +//│ // Prelude +//│ let typing_unit2 = { cache: {} }; +//│ // Query 1 +//│ globalThis.f1 = function f1(x) { +//│ return x > 0 && f1(x - 1); +//│ }; +//│ // End of generated code +//│ f +//│ = [Function: f1] f(12) //│ bool +//│ res +//│ = false :js let rec f() = f() //│ let rec f: () -> nothing +//│ // Prelude +//│ let typing_unit4 = { cache: {} }; +//│ // Query 1 +//│ globalThis.f2 = function f2() { +//│ return ((() => { +//│ return f2(); +//│ })()); +//│ }; +//│ // End of generated code +//│ f +//│ = [Function: f2] -// :re +:re f() //│ nothing +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded // TODO (for later) this should be rejected by the type checker -// :ge +:ge :js let rec f = f //│ let rec f: nothing +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding f -// :re +:re :js f //│ nothing +//│ // Prelude +//│ let typing_unit7 = { cache: {} }; +//│ // Query 1 +//│ res = f3; +//│ // End of generated code +//│ res +//│ Runtime error: +//│ ReferenceError: f3 is not defined :p let rec f = 1 //│ |#let| |#rec| |f| |#=| |1| //│ Parsed: let rec f = 1; //│ let rec f: 1 +//│ f +//│ = 1 let rec f = 1 //│ let rec f: 1 +//│ f +//│ = 1 + + +// FIXME should work +// No recursion: +let foo = 1 +let foo = foo + 1 +//│ let foo: 1 +//│ let foo: int +//│ foo +//│ = 1 +//│ foo +//│ = 2 + + diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 861e809af9..cd67aa3c94 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -1,6 +1,5 @@ :NewParser :NewDefs -:NoJS // * Adapted example from Code reuse through polymorphic variants (FOSE 2000) @@ -16,14 +15,23 @@ let l = Cons(1, Nil) //│ let l: Cons['A] //│ where //│ 'A :> 1 +//│ l +//│ = Cons { head: 1, tail: Nil {} } class NotFound class Success(result: A) //│ class NotFound() //│ class Success[A](result: A) -fun eq(l: string, r: string): bool -//│ fun eq: (l: string, r: string,) -> bool +let e = eq +//│ let e: anything -> anything -> bool +//│ e +//│ = [Function: eq] + +let eq(l: string, r: string): bool = e(l)(r) +//│ let eq: (l: string, r: string,) -> bool +//│ eq +//│ = [Function: eq1] fun list_assoc(s, l) = if l is @@ -34,6 +42,8 @@ fun list_assoc(s, l) = //│ fun list_assoc: (string, Cons['A] | Nil,) -> (NotFound | Success['A0]) //│ where //│ 'A <: {_1: string, _2: 'A0} +//│ Code generation crashed: +//│ scala.MatchError: Some(module Nil (Nil)) (of class scala.Some) // fun list_assoc(s: string, l: Cons<{ _1: string, _2: 'b }> | Nil): NotFound | Success['b] @@ -91,6 +101,8 @@ mixin EvalLambda { //│ where //│ 'A2 :> (string, Var,) | 'A0 //│ <: 'A1 +//│ Code generation encountered an error: +//│ unsupported definitions in blocks module Test1: EvalVar, EvalLambda //│ module Test1() { @@ -103,27 +115,39 @@ module Test1: EvalVar, EvalLambda //│ 'A0 :> (string, 'result,) //│ <: 'A1 & {_1: string, _2: 'result} //│ 'A1 <: 'A & 'A0 -//│ 'result :> Var | Abs['result] | App['result] +//│ 'result :> Var | App['result] | Abs['result] Test1.eval(Nil, Var("a")) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test1 is not defined Test1.eval(Nil, Abs("b", Var("a"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test1 is not defined Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test1 is not defined Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> Abs['a] | Abs[Var] | Var | App['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test1 is not defined class Num(n: int) class Add(l: A, r: A) @@ -155,6 +179,8 @@ mixin EvalExpr { //│ this: {eval: ('a, 'c,) -> anything} //│ fun eval: ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) //│ } +//│ Code generation encountered an error: +//│ unsupported definitions in blocks module Test2: EvalVar, EvalExpr //│ module Test2() { @@ -167,31 +193,46 @@ module Test2: EvalVar, EvalExpr Test2.eval(Nil, Var("a")) //│ Num | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test2 is not defined Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Var("a")) //│ Abs[Var] | Num | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test2 is not defined Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) //│ Num | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test2 is not defined :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.213: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.213: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.136: if v is +//│ ║ l.160: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.146: let vv = map_expr(eta, v) +//│ ║ l.170: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error +//│ res +//│ Runtime error: +//│ ReferenceError: Test2 is not defined Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) //│ Abs[Var] | Add[Num | Var] | Num | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test2 is not defined module Test3: EvalVar, EvalExpr, EvalLambda //│ module Test3() { @@ -212,11 +253,17 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Abs[Var] | Num | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test3 is not defined Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var | App['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var +//│ res +//│ Runtime error: +//│ ReferenceError: Test3 is not defined module Test3: EvalVar, EvalLambda, EvalExpr //│ module Test3() { @@ -237,17 +284,20 @@ module Test3: EvalVar, EvalLambda, EvalExpr :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.238: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.285: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.238: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.285: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.136: if v is +//│ ║ l.160: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.146: let vv = map_expr(eta, v) +//│ ║ l.170: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where //│ 'a :> Abs['a] | App['a] | Var | Abs[Var] | Num +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'eval') diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index f418cc89d0..9c6807b609 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -1,8 +1,10 @@ :NewParser :NewDefs -:NoJS -// Adapted example from Compositional Embeddings of Domain-Specific Languages (OOPSLA 2022) + +// * Adapted example from Compositional Embeddings of Domain-Specific Languages (OOPSLA 2022) + + // ******************* Initial System ******************* class Vector(x: int, y: int) @@ -43,12 +45,17 @@ fun go(x, offset) = //│ fun go: (int, int,) -> 'Region //│ where //│ 'Region :> Circle | Union[Translate['Region]] +//│ Code generation encountered an error: +//│ unsupported definitions in blocks // * Note that first-class polymorphism manages (correctly) to preserve que universal quantification let circles = go(20, 1024) //│ let circles: forall 'Region. 'Region //│ where //│ 'Region :> Circle | Union[Translate['Region]] +//│ circles +//│ Runtime error: +//│ ReferenceError: go is not defined // ******************* Adding More Language Constructs ******************* @@ -82,12 +89,21 @@ module TestSize: SizeBase, SizeExt TestSize.size(Empty()) //│ int +//│ res +//│ Runtime error: +//│ Error: non-exhaustive case expression TestSize.size(circles) //│ int +//│ res +//│ Runtime error: +//│ ReferenceError: circles is not defined TestSize.size(Scale(Vector(1, 1), circles)) //│ int +//│ res +//│ Runtime error: +//│ ReferenceError: circles is not defined // ******************* Adding a New Interpretation ******************* // a stupid power (int ** int) implementation @@ -119,12 +135,21 @@ module TestContains: Contains TestContains.contains(Translate(Vector(0, 0), Circle(1)), Vector(0, 0)) //│ bool +//│ res +//│ Runtime error: +//│ Error: non-exhaustive case expression TestContains.contains(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1)), Vector(0, 0)) //│ bool +//│ res +//│ Runtime error: +//│ Error: non-exhaustive case expression TestContains.contains(circles, Vector(0, 0)) //│ bool +//│ res +//│ Runtime error: +//│ ReferenceError: circles is not defined // ******************* Dependencies, Complex Interpretations, and Domain-Specific Optimizations ******************* @@ -146,48 +171,50 @@ mixin Text { //│ this: {size: (Intersect['Region] | Translate['Region0] | Union['Region1] | 'a) -> int} //│ fun text: (Circle | Intersect['Region] | Outside['a] | Translate['Region0] | Union['Region1]) -> string //│ } +//│ Unable to execute the code: +//│ concat is not implemented :e module SizeText: Text //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module SizeText: Text +//│ ║ l.178: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.143: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.168: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.143: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.168: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module SizeText: Text +//│ ║ l.178: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.142: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.167: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.142: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.167: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module SizeText: Text +//│ ║ l.178: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.141: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.166: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.141: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.166: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module SizeText: Text +//│ ║ l.178: module SizeText: Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.140: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.165: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.140: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.165: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -206,15 +233,27 @@ module SizeText: SizeBase, Text SizeText.text(circles) //│ string +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'text') SizeText.size(circles) //│ int +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'size') SizeText.text(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) //│ string +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'text') SizeText.size(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) //│ int +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'size') mixin IsUniv { fun isUniv(e) = @@ -268,14 +307,23 @@ module IsUnivIsEmpty: IsEmpty, IsUniv IsUnivIsEmpty.isUniv(circles) //│ bool +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'isUniv') IsUnivIsEmpty.isEmpty(circles) //│ bool +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'isEmpty') class Foo IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) //│ class Foo() //│ bool +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'isEmpty') mixin Eliminate { fun eliminate(e) = @@ -305,11 +353,16 @@ TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where //│ 'a :> Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ res +//│ = Univ {} TestElim.eliminate(circles) //│ 'a //│ where //│ 'a :> Union['a] | Intersect['a] | Translate['a] | Scale['a] | Circle | Outside['a] +//│ res +//│ Runtime error: +//│ ReferenceError: circles is not defined fun mk(n) = if n is 1 then Outside(mk(n)) @@ -325,6 +378,9 @@ TestElim.eliminate(mk(100)) //│ 'a //│ where //│ 'a :> Scale['a] | Outside['a] | Union['a] | Intersect['a] | Translate['a] +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded // ************************************************************************* @@ -351,62 +407,98 @@ module Lang: SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate Lang.size(circles) //│ int +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.contains(circles, Vector(0, 0)) //│ bool +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.text(circles) //│ string +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.isUniv(circles) //│ bool +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.isEmpty(circles) //│ bool +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.size(Lang.eliminate(circles)) //│ int +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.size(mk(100)) //│ int +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined :e Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.374: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.451: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.319: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.372: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.374: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.451: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.101: if a is +//│ ║ l.117: if a is //│ ╙── ^ //│ error | bool +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined :e Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.390: Lang.text(mk(100)) +//│ ║ l.470: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.319: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.372: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.390: Lang.text(mk(100)) +//│ ║ l.470: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.138: if e is +//│ ║ l.163: if e is //│ ╙── ^ //│ error | string +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.isUniv(mk(100)) //│ bool +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.isEmpty(mk(100)) //│ bool +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined Lang.size(Lang.eliminate(mk(100))) //│ int +//│ res +//│ Runtime error: +//│ ReferenceError: Lang is not defined From 342b7cb4b2195ced84f8e39f0dc9bd78084d19fb Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Feb 2023 16:30:56 +0800 Subject: [PATCH 111/498] WIPIP Update web demo to new defs typing --- js/src/main/scala/Main.scala | 371 ++++++------------ local_testing.html | 80 ++-- .../src/main/scala/mlscript/JSBackend.scala | 2 +- 3 files changed, 140 insertions(+), 313 deletions(-) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index c836365da4..7ba42b421e 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -27,197 +27,7 @@ object Main { def update(str: String): Unit = { // println(s"Input: $str") val target = document.querySelector("#mlscript-output") - val tryRes = Try[Str] { - import fastparse._ - import fastparse.Parsed.{Success, Failure} - import mlscript.{MLParser, ErrorReport, Origin} - val lines = str.splitSane('\n').toIndexedSeq - val processedBlock = MLParser.addTopLevelSeparators(lines).mkString - val fph = new mlscript.FastParseHelpers(str, lines) - val parser = new MLParser(Origin("", 1, fph)) - parse(processedBlock, parser.pgrm(_), verboseFailures = false) match { - case f: Failure => - val Failure(err, index, extra) = f - val (lineNum, lineStr, _) = fph.getLineColAt(index) - "Parse error: " + extra.trace().msg + - s" at line $lineNum:
$lineStr
" - case Success(pgrm, index) => - println(s"Parsed: $pgrm") - val (diags, (typeDefs, stmts)) = pgrm.desugared - // report(diags) // TODO... currently the MLParser does not report any in desugaring so this is fine - val (typeCheckResult, errorResult) = checkProgramType(pgrm) - errorResult match { - case Some(typeCheckResult) => typeCheckResult - case None => { - val htmlBuilder = new StringBuilder - var results = generateRuntimeCode(pgrm) match { - case R(code) => - executeCode(code) match { - case L(errorHtml) => - htmlBuilder ++= errorHtml - Nil - case R(results) => results - } - case L(errorHtml) => - htmlBuilder ++= errorHtml - Nil - } - htmlBuilder ++= """ - | - | - | - | - | - | - | - |""".stripMargin - // Assemble something like: `val : = `. - // If error occurred, leave ``. - typeCheckResult.zip(pgrm.desugared._2._2) foreach { case ((name, ty), origin) => - val value = origin match { - // Do not extract from results if its a type declaration. - case Def(_, _, R(_), _) => N - // Otherwise, `origin` is either a term or a definition. - case _ => results match { - case head :: next => - results = next - S(head) - case Nil => N - } - } - val valueHtml = value match { - case S(text) => s"" - case N => "" - } - htmlBuilder ++= s""" - | - | - | $valueHtml - | - |""".stripMargin - } - htmlBuilder ++= "
NameTypeValue
$textno value
${name getOrElse "res"}$ty
" - htmlBuilder.toString - } - } - } - } - - target.innerHTML = tryRes.fold[Str]( - err => - s""" - - Unexpected error: ${err}${ - err.printStackTrace - // err.getStackTrace().map(s"$htmlLineBreak$htmlWhiteSpace$htmlWhiteSpace at " + _).mkString - "" - }""", - identity - ) - } - - // Returns `Right[Str]` if successful, `Left[Str]` if not. - private def generateRuntimeCode(pgrm: Pgrm): Either[Str, Str] = { - try { - val backend = new JSWebBackend() - val lines = backend(pgrm) - val code = lines.mkString("\n") - println("Running code: " + code) - R(code) - } catch { - case e: Throwable => - val sb = new StringBuilder() - sb ++= "Code generation crashed:" - sb ++= htmlLineBreak + e.getMessage - // sb ++= htmlLineBreak + ((e.getStackTrace) mkString htmlLineBreak) - sb ++= htmlLineBreak - sb ++= htmlLineBreak - L(sb.toString) - } - } - - // Execute the generated code. - // We extract this function because there is some boilerplate code. - // It returns a tuple of three items: - // 1. results of definitions; - // 2. results of expressions; - // 3. error message (if has). - @SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf")) - private def executeCode(code: Str): Either[Str, Ls[Str]] = { - try { - R(js.eval(code).asInstanceOf[js.Array[Str]].toList) - } catch { - case e: Throwable => - val errorBuilder = new StringBuilder() - errorBuilder ++= "Runtime error occurred:" - errorBuilder ++= htmlLineBreak + e.getMessage - errorBuilder ++= htmlLineBreak - errorBuilder ++= htmlLineBreak - L(errorBuilder.toString) - } - } - - private val htmlLineBreak = "
" - private val htmlWhiteSpace = " " - private val splitLeadingSpaces: Regex = "^( +)(.+)$".r - - def checkProgramType(pgrm: Pgrm): Ls[Option[Str] -> Str] -> Option[Str] = { - val (diags, (typeDefs, stmts)) = pgrm.desugared - val typer = new mlscript.Typer( - dbg = false, - verbose = false, - explainErrors = false - ) - - import typer._ - - val res = new collection.mutable.StringBuilder - val results = new collection.mutable.ArrayBuffer[Option[Str] -> Str] - val stopAtFirstError = true - var errorOccurred = false - - def formatError(culprit: Str, err: ErrorReport): Str = { - s""" - Error in ${culprit}: ${err.mainMsg} - -
""" - } - - implicit val raise: Raise = throw _ - implicit var ctx: Ctx = - try processTypeDefs(typeDefs)(Ctx.init, raise) - catch { - case err: ErrorReport => - res ++= formatError("class definitions", err) - Ctx.init - } - implicit val extrCtx: Opt[typer.ExtrCtx] = N - - val curBlockTypeDefs = typeDefs.flatMap(td => ctx.tyDefs.get(td.nme.name)) - typer.computeVariances(curBlockTypeDefs, ctx) - - def getType(ty: typer.SimpleType): mlscript.TypeLike = { - object SimplifyPipeline extends typer.SimplifyPipeline { - def debugOutput(msg: => Str): Unit = println(msg) - } - val sim = SimplifyPipeline(ty)(ctx) - val exp = typer.expandType(sim) - exp - } - def formatBinding(nme: Str, ty: SimpleType): Str = { - val exp = getType(ty) - s""" - val - ${nme}: - ${exp.show} -
""" - } def underline(fragment: Str): Str = s"$fragment" @@ -290,83 +100,128 @@ object Main { sb.toString } - var declared: Map[Var, ST] = Map.empty + // var declared: Map[Var, ST] = Map.empty def htmlize(str: Str): Str = str.replace("\n", "
").replace(" ", " ") - var decls = stmts - while (decls.nonEmpty) { - val d = decls.head - decls = decls.tail - try d match { - case d @ Def(isrec, nme, L(rhs), _) => - val ty_sch = typeLetRhs(isrec, nme.name, rhs)(ctx, raise, Map.empty, true) - println(s"Typed `$nme` as: $ty_sch") - println(s" where: ${ty_sch.showBounds}") - val exp = getType(ty_sch) - declared.get(nme) match { - case S(sign) => - subsume(ty_sch, sign)(ctx, raise, TypeProvenance(d.toLoc, "def definition")) - // Note: keeping the less precise declared type signature here (no ctx update) - case N => - ctx += nme.name -> VarSymbol(ty_sch, nme) - } - res ++= formatBinding(d.nme.name, ty_sch) - results append S(d.nme.name) -> htmlize(getType(ty_sch).show) - case d @ Def(isrec, nme, R(PolyType(tps, rhs)), _) => - declared.get(nme) match { - case S(sign) => - import Message.MessageContext - typer.err(msg"illegal redeclaration of ${nme.name}" -> d.toLoc - :: msg"already defined here:" -> - declared.keysIterator.find(_.name === nme.name).flatMap(_.toLoc) - :: Nil) - case N => () - } - implicit val tp: TP = NoProv // TODO - val ty_sch = ctx.poly { implicit ctx => - typeType(rhs)(ctx, raise, - vars = tps.map(tp => tp.fold(_.name, _ => ??? // FIXME - ) -> freshVar(noProv/*FIXME*/, N)(1)).toMap) - } - ctx += nme.name -> VarSymbol(ty_sch, nme) - declared += nme -> ty_sch - results append S(d.nme.name) -> htmlize(getType(ty_sch).show) - case s: DesugaredStatement => - implicit val vars: Map[Str, SimpleType] = Map.empty - implicit val gl: typer.GenLambdas = true - typer.typeStatement(s, allowPure = true) match { - case R(binds) => - binds.foreach { case (nme, pty) => - ctx += nme -> VarSymbol(pty, Var(nme)) - res ++= formatBinding(nme, pty) - results append S(nme) -> htmlize(getType(pty).show) - } - case L(pty) => - val exp = getType(pty) - if (exp =/= TypeName("unit")) { - val nme = "res" - ctx += nme -> VarSymbol(pty, Var(nme)) - res ++= formatBinding(nme, pty) - results append N -> htmlize(getType(pty).show) - } + + val tryRes = try { + import fastparse._ + import fastparse.Parsed.{Success, Failure} + import mlscript.{NewParser, ErrorReport, Origin} + val lines = str.splitSane('\n').toIndexedSeq + val processedBlock = lines.mkString + val fph = new mlscript.FastParseHelpers(str, lines) + val origin = Origin("", 1, fph) + val lexer = new NewLexer(origin, throw _, dbg = false) + val tokens = lexer.bracketedTokens + val parser = new NewParser(origin, tokens, throw _, dbg = false, N) { + def doPrintDbg(msg: => Str): Unit = if (dbg) println(msg) + } + parser.parseAll(parser.typingUnit) match { + case tu => + val pgrm = Pgrm(tu.entities) + println(s"Parsed: $pgrm") + + val typer = new mlscript.Typer( + dbg = false, + verbose = false, + explainErrors = false + ) { + newDefs = true } - } catch { - case err: ErrorReport => - if (stopAtFirstError) decls = Nil - val culprit = d match { - case Def(isrec, nme, rhs, isByname) => "def " + nme - case _: DesugaredStatement => "statement" + + import typer._ + + implicit val raise: Raise = throw _ + implicit var ctx: Ctx = Ctx.init + implicit val extrCtx: Opt[typer.ExtrCtx] = N + + + + val res = new collection.mutable.StringBuilder + val results = new collection.mutable.ArrayBuffer[Option[Str] -> Str] + val stopAtFirstError = true + var errorOccurred = false + + + val vars: Map[Str, typer.SimpleType] = Map.empty + + val tpd = typer.typeTypingUnit(tu, allowPure = true)(ctx.nest, raise, vars) + val comp = tpd.force()(raise) + + object SimplifyPipeline extends typer.SimplifyPipeline { + def debugOutput(msg: => Str): Unit = + // if (mode.dbgSimplif) output(msg) + println(msg) } - res ++= report(err) - errorOccurred = true + val sim = SimplifyPipeline(comp, all = false)(ctx) + + val exp = typer.expandType(sim)(ctx) + + val expStr = + exp.showIn(ShowCtx.mk(exp :: Nil) + // .copy(newDefs = true) // TODO later + , 0) + + // TODO format HTML better + val str = expStr.stripSuffix("\n") + .replaceAll(" ", "  ") + .replaceAll("\n", "
") + + + // val curBlockTypeDefs = typeDefs.flatMap(td => ctx.tyDefs.get(td.nme.name)) + // typer.computeVariances(curBlockTypeDefs, ctx) + + // def getType(ty: typer.SimpleType): mlscript.TypeLike = { + // object SimplifyPipeline extends typer.SimplifyPipeline { + // def debugOutput(msg: => Str): Unit = println(msg) + // } + // val sim = SimplifyPipeline(ty)(ctx) + // val exp = typer.expandType(sim) + // exp + // } + // def formatBinding(nme: Str, ty: SimpleType): Str = { + // val exp = getType(ty) + // s""" + // val + // ${nme}: + // ${exp.show} + //
""" + // } + + + // TODO + // val backend = new JSWebBackend() + // val lines = backend(pgrm) + // val code = lines.mkString("\n") + // println("Running code: " + code) + // R(code) + + str } + } catch { + // case err: ErrorReport => + case err: Diagnostic => + report(err) + case err: Throwable => + s""" + + Unexpected error: ${err}${ + err.printStackTrace + // err.getStackTrace().map(s"$htmlLineBreak$htmlWhiteSpace$htmlWhiteSpace at " + _).mkString + "" + }""" } - results.toList -> (if (errorOccurred) S(res.toString) else N) + target.innerHTML = tryRes + } - private def underline(fragment: Str): Str = - s"$fragment" + private val htmlLineBreak = "
" + private val htmlWhiteSpace = " " + private val splitLeadingSpaces: Regex = "^( +)(.+)$".r + } + diff --git a/local_testing.html b/local_testing.html index 82b676a049..24944bf9fc 100644 --- a/local_testing.html +++ b/local_testing.html @@ -9,60 +9,32 @@

MLscript demonstration


-

The code is available on github.

+ diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index 0ac8ad38bc..cd43683010 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -49,8 +49,8 @@ fun go(x, offset) = //│ where //│ 'Region :> Circle | Union[Translate['Region]] -// * Note that first-class polymorphism manages (correctly) to preserve que universal quantification -let circles = go(20, 1024) +// * Note that first-class polymorphism manages (correctly) to preserve the universal quantification +let circles = go(2, 1024) //│ let circles: forall 'Region. 'Region //│ where //│ 'Region :> Circle | Union[Translate['Region]] @@ -312,7 +312,7 @@ SizeText.text(circles) SizeText.size(circles) //│ int //│ res -//│ = 4194301 +//│ = 13 SizeText.text(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) //│ string From 4f1d836b9a5d12b425c5967e33b780695ef02b1d Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 28 Feb 2023 12:10:01 +0800 Subject: [PATCH 122/498] Remove js code --- js/src/main/scala/Main.scala | 11 +- shared/src/main/scala/mlscript/helpers.scala | 72 +-- shared/src/test/diff/codegen/Mixin.mls | 511 +++++++++++++++++++ shared/src/test/diff/nu/ECOOP23_codegen.mls | 415 +-------------- shared/src/test/diff/nu/Super.mls | 324 +----------- 5 files changed, 568 insertions(+), 765 deletions(-) create mode 100644 shared/src/test/diff/codegen/Mixin.mls diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index a21acdf23b..5af70a5787 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -159,10 +159,11 @@ object Main { val (lines, resNames) = backend(pgrm, true) val code = lines.mkString("\n") - val jsStr = ("\n\n=====================JavaScript Code=====================\n" + code) - .stripSuffix("\n") - .replaceAll(" ", "  ") - .replaceAll("\n", "
") + // TODO: add a toggle button to show js code + // val jsStr = ("\n\n=====================JavaScript Code=====================\n" + code) + // .stripSuffix("\n") + // .replaceAll(" ", "  ") + // .replaceAll("\n", "
") val exe = executeCode(code) match { case Left(err) => err @@ -174,7 +175,7 @@ object Main { .replaceAll(" ", "  ") .replaceAll("\n", "
") + exe - typingStr + jsStr + resStr + typingStr + resStr } } catch { // case err: ErrorReport => diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index c29fbf86f2..3fe941ee31 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -617,7 +617,7 @@ trait TermImpl extends StatementImpl { self: Term => case lit: Lit => Literal(lit) case App(App(Var("|"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Inter(lhs.toType_!, rhs.toType_!) - case App(App(Var("->"), lhs), Tup(N -> Fld(false, false, rhs) :: Nil)) => Function(lhs.toType_!, rhs.toType_!) + case App(App(Var("->"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Function(lhs.toType_!, rhs.toType_!) case App(App(Var("|"), lhs), rhs) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), lhs), rhs) => Inter(lhs.toType_!, rhs.toType_!) case Lam(lhs, rhs) => Function(lhs.toType_!, rhs.toType_!) @@ -781,41 +781,41 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - ??? // TODO - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - // TODO properly check: - require(fs.isEmpty, fs) - require(pars.size === 1, pars) - require(ths.isEmpty, ths) - require(unit.entities.isEmpty, unit) - val (diags, rhs) = pars.head.toType match { - case L(ds) => (ds :: Nil) -> Top - case R(ty) => Nil -> ty - } - diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => - val diags = Buffer.empty[Diagnostic] - def tt(trm: Term): Type = trm.toType match { - case L(ds) => diags += ds; Top - case R(ty) => ty - } - val params = fs.map { - case (S(nme), Fld(mut, spec, trm)) => - val ty = tt(trm) - nme -> Field(if (mut) S(ty) else N, ty) - case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) - case _ => die - } - val pos = params.unzip._1 - val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) - val termName = Var(nme.name).withLocOf(nme) - val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(false, false, Rcd(fs.map { - case (S(nme), fld) => nme -> Fld(false, false, nme) - case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld - case _ => die - })) :: Nil)))), true) - diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, Nil, pos) :: ctor :: Nil) + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + ??? // TODO + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + // TODO properly check: + require(fs.isEmpty, fs) + require(pars.size === 1, pars) + require(ths.isEmpty, ths) + require(unit.entities.isEmpty, unit) + val (diags, rhs) = pars.head.toType match { + case L(ds) => (ds :: Nil) -> Top + case R(ty) => Nil -> ty + } + diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + val diags = Buffer.empty[Diagnostic] + def tt(trm: Term): Type = trm.toType match { + case L(ds) => diags += ds; Top + case R(ty) => ty + } + val params = fs.map { + case (S(nme), Fld(mut, spec, trm)) => + val ty = tt(trm) + nme -> Field(if (mut) S(ty) else N, ty) + case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) + case _ => die + } + val pos = params.unzip._1 + val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) + val termName = Var(nme.name).withLocOf(nme) + val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(false, false, Rcd(fs.map { + case (S(nme), fld) => nme -> Fld(false, false, nme) + case (N, fld @ Fld(mut, spec, nme: Var)) => nme -> fld + case _ => die + })) :: Nil)))), true) + diags.toList -> (TypeDef(k, nme, tps.map(_._2), bod, Nil, Nil, pos) :: ctor :: Nil) case d: DesugaredStatement => Nil -> (d :: Nil) } import Message._ diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls new file mode 100644 index 0000000000..299271641a --- /dev/null +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -0,0 +1,511 @@ +:NewParser +:NewDefs + +:js +:ShowRepl +class Add(lhs: E, rhs: E) +class Lit(n: int) +//│ class Add[E](lhs: E, rhs: E) +//│ class Lit(n: int) +//│ // Prelude +//│ let res; +//│ let typing_unit = { +//│ cache: {}, +//│ get Add() { +//│ if (this.cache.Add === undefined) { +//│ class Add { +//│ constructor(lhs, rhs) { +//│ this.lhs = lhs; +//│ this.rhs = rhs; +//│ } +//│ }; +//│ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ this.cache.Add["class"] = Add; +//│ } +//│ return this.cache.Add; +//│ }, +//│ get Lit() { +//│ if (this.cache.Lit === undefined) { +//│ class Lit { +//│ constructor(n) { +//│ this.n = n; +//│ } +//│ }; +//│ this.cache.Lit = ((n) => new Lit(n)); +//│ this.cache.Lit["class"] = Lit; +//│ } +//│ return this.cache.Lit; +//│ } +//│ }; +//│ globalThis.Add = typing_unit.Add; +//│ globalThis.Lit = typing_unit.Lit; +//│ // End of generated code +//│ ┌ Block at Mixin.mls:6 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let res; +//│ │ │ let typing_unit = { +//│ │ │ cache: {}, +//│ │ │ get Add() { +//│ │ │ if (this.cache.Add === undefined) { +//│ │ │ class Add { +//│ │ │ constructor(lhs, rhs) { +//│ │ │ this.lhs = lhs; +//│ │ │ this.rhs = rhs; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ │ │ this.cache.Add["class"] = Add; +//│ │ │ } +//│ │ │ return this.cache.Add; +//│ │ │ }, +//│ │ │ get Lit() { +//│ │ │ if (this.cache.Lit === undefined) { +//│ │ │ class Lit { +//│ │ │ constructor(n) { +//│ │ │ this.n = n; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Lit = ((n) => new Lit(n)); +//│ │ │ this.cache.Lit["class"] = Lit; +//│ │ │ } +//│ │ │ return this.cache.Lit; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Add = typing_unit.Add; +//│ │ │ globalThis.Lit = typing_unit.Lit; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [class Lit] } +//│ └── No queries + +:js +:ShowRepl +mixin EvalBase { + fun eval(e) = + if e is + Lit(n) then n: int + Add(l, r) then this.eval(l) + this.eval(r) +} +//│ mixin EvalBase() { +//│ this: {eval: 'lhs -> int} +//│ fun eval: (Add['lhs] | Lit) -> int +//│ } +//│ // Prelude +//│ let typing_unit1 = { +//│ cache: {}, +//│ EvalBase(base) { +//│ if (base === undefined) { +//│ return (class EvalBase { +//│ constructor() { +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })()); +//│ } +//│ }); +//│ } else { +//│ return (class EvalBase extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })()); +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.EvalBase = typing_unit1.EvalBase; +//│ // End of generated code +//│ ┌ Block at Mixin.mls:83 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit1 = { +//│ │ │ cache: {}, +//│ │ │ EvalBase(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class EvalBase { +//│ │ │ constructor() { +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ let a; +//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ │ │ throw new Error("non-exhaustive case expression"); +//│ │ │ })()); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class EvalBase extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ let a; +//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ │ │ throw new Error("non-exhaustive case expression"); +//│ │ │ })()); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.EvalBase = typing_unit1.EvalBase; +//│ │ └── Reply +//│ │ [Function: EvalBase] +//│ └── No queries + +:js +:ShowRepl +class Neg(expr: A) +//│ class Neg[A](expr: A) +//│ // Prelude +//│ let typing_unit2 = { +//│ cache: {}, +//│ get Neg() { +//│ if (this.cache.Neg === undefined) { +//│ class Neg { +//│ constructor(expr) { +//│ this.expr = expr; +//│ } +//│ }; +//│ this.cache.Neg = ((expr) => new Neg(expr)); +//│ this.cache.Neg["class"] = Neg; +//│ } +//│ return this.cache.Neg; +//│ } +//│ }; +//│ globalThis.Neg = typing_unit2.Neg; +//│ // End of generated code +//│ ┌ Block at Mixin.mls:176 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit2 = { +//│ │ │ cache: {}, +//│ │ │ get Neg() { +//│ │ │ if (this.cache.Neg === undefined) { +//│ │ │ class Neg { +//│ │ │ constructor(expr) { +//│ │ │ this.expr = expr; +//│ │ │ } +//│ │ │ }; +//│ │ │ this.cache.Neg = ((expr) => new Neg(expr)); +//│ │ │ this.cache.Neg["class"] = Neg; +//│ │ │ } +//│ │ │ return this.cache.Neg; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Neg = typing_unit2.Neg; +//│ │ └── Reply +//│ │ [Function (anonymous)] { class: [class Neg] } +//│ └── No queries + +:js +:ShowRepl +mixin EvalNeg { + fun eval(e) = + if e is Neg(d) then 0 - this.eval(d) + else super.eval(e) +} +//│ mixin EvalNeg() { +//│ super: {eval: 'a -> 'b} +//│ this: {eval: 'expr -> int} +//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) +//│ } +//│ // Prelude +//│ let typing_unit3 = { +//│ cache: {}, +//│ EvalNeg(base) { +//│ if (base === undefined) { +//│ return (class EvalNeg { +//│ constructor() { +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } else { +//│ return (class EvalNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.EvalNeg = typing_unit3.EvalNeg; +//│ // End of generated code +//│ ┌ Block at Mixin.mls:221 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit3 = { +//│ │ │ cache: {}, +//│ │ │ EvalNeg(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class EvalNeg { +//│ │ │ constructor() { +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class EvalNeg extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.EvalNeg = typing_unit3.EvalNeg; +//│ │ └── Reply +//│ │ [Function: EvalNeg] +//│ └── No queries + +:js +:ShowRepl +mixin EvalNegNeg { + fun eval(e) = + if e is Neg(Neg(d)) then this.eval(d) + else super.eval(e) +} +//│ mixin EvalNegNeg() { +//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ this: {eval: 'expr -> 'b} +//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b +//│ } +//│ // Prelude +//│ let typing_unit4 = { +//│ cache: {}, +//│ EvalNegNeg(base) { +//│ if (base === undefined) { +//│ return (class EvalNegNeg { +//│ constructor() { +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } else { +//│ return (class EvalNegNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; +//│ // End of generated code +//│ ┌ Block at Mixin.mls:302 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit4 = { +//│ │ │ cache: {}, +//│ │ │ EvalNegNeg(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class EvalNegNeg { +//│ │ │ constructor() { +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class EvalNegNeg extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; +//│ │ └── Reply +//│ │ [Function: EvalNegNeg] +//│ └── No queries + +:js +:ShowRepl +module TestLang: EvalBase, EvalNeg, EvalNegNeg +//│ module TestLang() { +//│ fun eval: 'a -> int +//│ } +//│ where +//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'A <: 'a +//│ // Prelude +//│ let typing_unit5 = { +//│ cache: {}, +//│ get TestLang() { +//│ if (this.cache.TestLang === undefined) { +//│ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ } +//│ this.cache.TestLang = new TestLang(); +//│ this.cache.TestLang["class"] = TestLang; +//│ } +//│ return this.cache.TestLang; +//│ } +//│ }; +//│ globalThis.TestLang = typing_unit5.TestLang; +//│ // End of generated code +//│ ┌ Block at Mixin.mls:383 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit5 = { +//│ │ │ cache: {}, +//│ │ │ get TestLang() { +//│ │ │ if (this.cache.TestLang === undefined) { +//│ │ │ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ } +//│ │ │ this.cache.TestLang = new TestLang(); +//│ │ │ this.cache.TestLang["class"] = TestLang; +//│ │ │ } +//│ │ │ return this.cache.TestLang; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.TestLang = typing_unit5.TestLang; +//│ │ └── Reply +//│ │ TestLang { class: [Function: TestLang] } +//│ └── No queries + +:js +:ShowRepl +fun mk(n) = if n is + 0 then Lit(0) + 1 then Neg(mk(n)) + _ then Add(mk(n), mk(n)) +TestLang.eval(mk(0)) +//│ fun mk: number -> (Lit | 'a) +//│ int +//│ where +//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] +//│ // Prelude +//│ let typing_unit6 = { cache: {} }; +//│ // Query 1 +//│ globalThis.mk = function mk(n) { +//│ return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); +//│ }; +//│ // Query 2 +//│ res = TestLang.eval(mk(0)); +//│ // End of generated code +//│ ┌ Block at Mixin.mls:433 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit6 = { cache: {} }; +//│ │ └── Reply +//│ │ undefined +//│ ├─┬ Query 1/2 +//│ │ ├── Prelude: +//│ │ ├── Code: +//│ │ ├── globalThis.mk = function mk(n) { +//│ │ ├── return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); +//│ │ ├── }; +//│ │ ├── Intermediate: [Function: mk] +//│ │ └── Reply: [success] [Function: mk] +//│ └─┬ Query 2/2 +//│ ├── Prelude: +//│ ├── Code: +//│ ├── res = TestLang.eval(mk(0)); +//│ ├── Intermediate: 0 +//│ └── Reply: [success] 0 +//│ res +//│ = [Function: mk] + + +class Foo(x: int) +//│ class Foo(x: int) + + +:e +class Bar(x: int, y: int): Foo(x + y) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.480: class Bar(x: int, y: int): Foo(x + y) +//│ ╙── ^^^^^^^^^^ +//│ class Bar(x: int, y: int) + + +mixin AA(a: int) { +} +//│ mixin AA() + +mixin BB {} +//│ mixin BB() + + +class C(x: int): BB +//│ class C(x: int) + +:e +class D(x: int): AA(x) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.499: class D(x: int): AA(x) +//│ ╙── ^^^^^ +//│ class D(x: int) + +:e +class E(x: int): BB, AA(x) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.506: class E(x: int): BB, AA(x) +//│ ╙── ^^^^^ +//│ class E(x: int) + diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index dc96994f12..0bb0d21638 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -1,85 +1,12 @@ :NewParser :NewDefs -:js -:ShowRepl class Add(lhs: E, rhs: E) class Lit(n: int) //│ class Add[E](lhs: E, rhs: E) //│ class Lit(n: int) -//│ // Prelude -//│ let res; -//│ let typing_unit = { -//│ cache: {}, -//│ get Add() { -//│ if (this.cache.Add === undefined) { -//│ class Add { -//│ constructor(lhs, rhs) { -//│ this.lhs = lhs; -//│ this.rhs = rhs; -//│ } -//│ }; -//│ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); -//│ this.cache.Add["class"] = Add; -//│ } -//│ return this.cache.Add; -//│ }, -//│ get Lit() { -//│ if (this.cache.Lit === undefined) { -//│ class Lit { -//│ constructor(n) { -//│ this.n = n; -//│ } -//│ }; -//│ this.cache.Lit = ((n) => new Lit(n)); -//│ this.cache.Lit["class"] = Lit; -//│ } -//│ return this.cache.Lit; -//│ } -//│ }; -//│ globalThis.Add = typing_unit.Add; -//│ globalThis.Lit = typing_unit.Lit; -//│ // End of generated code -//│ ┌ Block at ECOOP23_codegen.mls:6 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let res; -//│ │ │ let typing_unit = { -//│ │ │ cache: {}, -//│ │ │ get Add() { -//│ │ │ if (this.cache.Add === undefined) { -//│ │ │ class Add { -//│ │ │ constructor(lhs, rhs) { -//│ │ │ this.lhs = lhs; -//│ │ │ this.rhs = rhs; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); -//│ │ │ this.cache.Add["class"] = Add; -//│ │ │ } -//│ │ │ return this.cache.Add; -//│ │ │ }, -//│ │ │ get Lit() { -//│ │ │ if (this.cache.Lit === undefined) { -//│ │ │ class Lit { -//│ │ │ constructor(n) { -//│ │ │ this.n = n; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.Lit = ((n) => new Lit(n)); -//│ │ │ this.cache.Lit["class"] = Lit; -//│ │ │ } -//│ │ │ return this.cache.Lit; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.Add = typing_unit.Add; -//│ │ │ globalThis.Lit = typing_unit.Lit; -//│ │ └── Reply -//│ │ [Function (anonymous)] { class: [class Lit] } -//│ └── No queries -:js -:ShowRepl + mixin EvalBase { fun eval(e) = if e is @@ -90,134 +17,12 @@ mixin EvalBase { //│ this: {eval: 'lhs -> int} //│ fun eval: (Add['lhs] | Lit) -> int //│ } -//│ // Prelude -//│ let typing_unit1 = { -//│ cache: {}, -//│ EvalBase(base) { -//│ if (base === undefined) { -//│ return (class EvalBase { -//│ constructor() { -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalBase extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })()); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.EvalBase = typing_unit1.EvalBase; -//│ // End of generated code -//│ ┌ Block at ECOOP23_codegen.mls:83 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit1 = { -//│ │ │ cache: {}, -//│ │ │ EvalBase(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class EvalBase { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ let a; -//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ │ │ throw new Error("non-exhaustive case expression"); -//│ │ │ })()); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class EvalBase extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ let a; -//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ │ │ throw new Error("non-exhaustive case expression"); -//│ │ │ })()); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.EvalBase = typing_unit1.EvalBase; -//│ │ └── Reply -//│ │ [Function: EvalBase] -//│ └── No queries -:js -:ShowRepl + class Neg(expr: A) //│ class Neg[A](expr: A) -//│ // Prelude -//│ let typing_unit2 = { -//│ cache: {}, -//│ get Neg() { -//│ if (this.cache.Neg === undefined) { -//│ class Neg { -//│ constructor(expr) { -//│ this.expr = expr; -//│ } -//│ }; -//│ this.cache.Neg = ((expr) => new Neg(expr)); -//│ this.cache.Neg["class"] = Neg; -//│ } -//│ return this.cache.Neg; -//│ } -//│ }; -//│ globalThis.Neg = typing_unit2.Neg; -//│ // End of generated code -//│ ┌ Block at ECOOP23_codegen.mls:176 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit2 = { -//│ │ │ cache: {}, -//│ │ │ get Neg() { -//│ │ │ if (this.cache.Neg === undefined) { -//│ │ │ class Neg { -//│ │ │ constructor(expr) { -//│ │ │ this.expr = expr; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.Neg = ((expr) => new Neg(expr)); -//│ │ │ this.cache.Neg["class"] = Neg; -//│ │ │ } -//│ │ │ return this.cache.Neg; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.Neg = typing_unit2.Neg; -//│ │ └── Reply -//│ │ [Function (anonymous)] { class: [class Neg] } -//│ └── No queries -:js -:ShowRepl + mixin EvalNeg { fun eval(e) = if e is Neg(d) then 0 - this.eval(d) @@ -228,77 +33,8 @@ mixin EvalNeg { //│ this: {eval: 'expr -> int} //│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) //│ } -//│ // Prelude -//│ let typing_unit3 = { -//│ cache: {}, -//│ EvalNeg(base) { -//│ if (base === undefined) { -//│ return (class EvalNeg { -//│ constructor() { -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.EvalNeg = typing_unit3.EvalNeg; -//│ // End of generated code -//│ ┌ Block at ECOOP23_codegen.mls:221 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit3 = { -//│ │ │ cache: {}, -//│ │ │ EvalNeg(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class EvalNeg { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class EvalNeg extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.EvalNeg = typing_unit3.EvalNeg; -//│ │ └── Reply -//│ │ [Function: EvalNeg] -//│ └── No queries -:js -:ShowRepl + mixin EvalNegNeg { fun eval(e) = if e is Neg(Neg(d)) then this.eval(d) @@ -309,77 +45,8 @@ mixin EvalNegNeg { //│ this: {eval: 'expr -> 'b} //│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } -//│ // Prelude -//│ let typing_unit4 = { -//│ cache: {}, -//│ EvalNegNeg(base) { -//│ if (base === undefined) { -//│ return (class EvalNegNeg { -//│ constructor() { -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalNegNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; -//│ // End of generated code -//│ ┌ Block at ECOOP23_codegen.mls:302 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit4 = { -//│ │ │ cache: {}, -//│ │ │ EvalNegNeg(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class EvalNegNeg { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class EvalNegNeg extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; -//│ │ └── Reply -//│ │ [Function: EvalNegNeg] -//│ └── No queries -:js -:ShowRepl + module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { //│ fun eval: 'a -> int @@ -387,49 +54,8 @@ module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ where //│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] //│ 'A <: 'a -//│ // Prelude -//│ let typing_unit5 = { -//│ cache: {}, -//│ get TestLang() { -//│ if (this.cache.TestLang === undefined) { -//│ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ } -//│ this.cache.TestLang = new TestLang(); -//│ this.cache.TestLang["class"] = TestLang; -//│ } -//│ return this.cache.TestLang; -//│ } -//│ }; -//│ globalThis.TestLang = typing_unit5.TestLang; -//│ // End of generated code -//│ ┌ Block at ECOOP23_codegen.mls:383 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit5 = { -//│ │ │ cache: {}, -//│ │ │ get TestLang() { -//│ │ │ if (this.cache.TestLang === undefined) { -//│ │ │ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ } -//│ │ │ this.cache.TestLang = new TestLang(); -//│ │ │ this.cache.TestLang["class"] = TestLang; -//│ │ │ } -//│ │ │ return this.cache.TestLang; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.TestLang = typing_unit5.TestLang; -//│ │ └── Reply -//│ │ TestLang { class: [Function: TestLang] } -//│ └── No queries -:js -:ShowRepl + fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) @@ -439,34 +65,5 @@ TestLang.eval(mk(0)) //│ int //│ where //│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] -//│ // Prelude -//│ let typing_unit6 = { cache: {} }; -//│ // Query 1 -//│ globalThis.mk = function mk(n) { -//│ return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); -//│ }; -//│ // Query 2 -//│ res = TestLang.eval(mk(0)); -//│ // End of generated code -//│ ┌ Block at ECOOP23_codegen.mls:433 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit6 = { cache: {} }; -//│ │ └── Reply -//│ │ undefined -//│ ├─┬ Query 1/2 -//│ │ ├── Prelude: -//│ │ ├── Code: -//│ │ ├── globalThis.mk = function mk(n) { -//│ │ ├── return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); -//│ │ ├── }; -//│ │ ├── Intermediate: [Function: mk] -//│ │ └── Reply: [success] [Function: mk] -//│ └─┬ Query 2/2 -//│ ├── Prelude: -//│ ├── Code: -//│ ├── res = TestLang.eval(mk(0)); -//│ ├── Intermediate: 0 -//│ └── Reply: [success] 0 //│ res //│ = [Function: mk] diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index f3668e8470..21bd669f57 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -1,347 +1,41 @@ :NewParser :NewDefs -:js -:ShowRepl + class Foo(x: int) //│ class Foo(x: int) -//│ // Prelude -//│ let res; -//│ let typing_unit = { -//│ cache: {}, -//│ get Foo() { -//│ if (this.cache.Foo === undefined) { -//│ class Foo { -//│ constructor(x) { -//│ this.x = x; -//│ } -//│ }; -//│ this.cache.Foo = ((x) => new Foo(x)); -//│ this.cache.Foo["class"] = Foo; -//│ } -//│ return this.cache.Foo; -//│ } -//│ }; -//│ globalThis.Foo = typing_unit.Foo; -//│ // End of generated code -//│ ┌ Block at Super.mls:6 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let res; -//│ │ │ let typing_unit = { -//│ │ │ cache: {}, -//│ │ │ get Foo() { -//│ │ │ if (this.cache.Foo === undefined) { -//│ │ │ class Foo { -//│ │ │ constructor(x) { -//│ │ │ this.x = x; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.Foo = ((x) => new Foo(x)); -//│ │ │ this.cache.Foo["class"] = Foo; -//│ │ │ } -//│ │ │ return this.cache.Foo; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.Foo = typing_unit.Foo; -//│ │ └── Reply -//│ │ [Function (anonymous)] { class: [class Foo] } -//│ └── No queries -:js + :e -:ShowRepl class Bar(x: int, y: int): Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.54: class Bar(x: int, y: int): Foo(x + y) +//│ ║ l.10: class Bar(x: int, y: int): Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) -//│ // Prelude -//│ let typing_unit1 = { -//│ cache: {}, -//│ get Bar() { -//│ if (this.cache.Bar === undefined) { -//│ class Bar extends Foo["class"] { -//│ constructor(x, y) { -//│ super(x + y); -//│ this.x = x; -//│ this.y = y; -//│ } -//│ }; -//│ this.cache.Bar = ((x, y) => new Bar(x, y)); -//│ this.cache.Bar["class"] = Bar; -//│ } -//│ return this.cache.Bar; -//│ } -//│ }; -//│ globalThis.Bar = typing_unit1.Bar; -//│ // End of generated code -//│ ┌ Block at Super.mls:54 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit1 = { -//│ │ │ cache: {}, -//│ │ │ get Bar() { -//│ │ │ if (this.cache.Bar === undefined) { -//│ │ │ class Bar extends Foo["class"] { -//│ │ │ constructor(x, y) { -//│ │ │ super(x + y); -//│ │ │ this.x = x; -//│ │ │ this.y = y; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.Bar = ((x, y) => new Bar(x, y)); -//│ │ │ this.cache.Bar["class"] = Bar; -//│ │ │ } -//│ │ │ return this.cache.Bar; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.Bar = typing_unit1.Bar; -//│ │ └── Reply -//│ │ [Function (anonymous)] { class: [class Bar extends Foo] } -//│ └── No queries -:js -:ShowRepl mixin AA(a: int) { } //│ mixin AA() -//│ // Prelude -//│ let typing_unit2 = { -//│ cache: {}, -//│ AA(base) { -//│ if (base === undefined) { -//│ return (class AA { -//│ constructor(a) { -//│ this.a = a; -//│ } -//│ }); -//│ } else { -//│ return (class AA extends base { -//│ constructor(a, ...rest) { -//│ super(...rest); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.AA = typing_unit2.AA; -//│ // End of generated code -//│ ┌ Block at Super.mls:107 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit2 = { -//│ │ │ cache: {}, -//│ │ │ AA(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class AA { -//│ │ │ constructor(a) { -//│ │ │ this.a = a; -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class AA extends base { -//│ │ │ constructor(a, ...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.AA = typing_unit2.AA; -//│ │ └── Reply -//│ │ [Function: AA] -//│ └── No queries -:js -:ShowRepl mixin BB {} //│ mixin BB() -//│ // Prelude -//│ let typing_unit3 = { -//│ cache: {}, -//│ BB(base) { -//│ if (base === undefined) { -//│ return class BB {}; -//│ } else { -//│ return (class BB extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.BB = typing_unit3.BB; -//│ // End of generated code -//│ ┌ Block at Super.mls:159 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit3 = { -//│ │ │ cache: {}, -//│ │ │ BB(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return class BB {}; -//│ │ │ } else { -//│ │ │ return (class BB extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.BB = typing_unit3.BB; -//│ │ └── Reply -//│ │ [Function: BB] -//│ └── No queries -:js -:ShowRepl + class C(x: int): BB //│ class C(x: int) -//│ // Prelude -//│ let typing_unit4 = { -//│ cache: {}, -//│ get C() { -//│ if (this.cache.C === undefined) { -//│ class C extends BB() { -//│ constructor(x) { -//│ super(); -//│ this.x = x; -//│ } -//│ }; -//│ this.cache.C = ((x) => new C(x)); -//│ this.cache.C["class"] = C; -//│ } -//│ return this.cache.C; -//│ } -//│ }; -//│ globalThis.C = typing_unit4.C; -//│ // End of generated code -//│ ┌ Block at Super.mls:202 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit4 = { -//│ │ │ cache: {}, -//│ │ │ get C() { -//│ │ │ if (this.cache.C === undefined) { -//│ │ │ class C extends BB() { -//│ │ │ constructor(x) { -//│ │ │ super(); -//│ │ │ this.x = x; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.C = ((x) => new C(x)); -//│ │ │ this.cache.C["class"] = C; -//│ │ │ } -//│ │ │ return this.cache.C; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.C = typing_unit4.C; -//│ │ └── Reply -//│ │ [Function (anonymous)] { class: [Function: C] } -//│ └── No queries -:js :e -:ShowRepl class D(x: int): AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.250: class D(x: int): AA(x) -//│ ╙── ^^^^^ +//│ ║ l.29: class D(x: int): AA(x) +//│ ╙── ^^^^^ //│ class D(x: int) -//│ // Prelude -//│ let typing_unit5 = { -//│ cache: {}, -//│ get D() { -//│ if (this.cache.D === undefined) { -//│ class D extends AA() { -//│ constructor(x) { -//│ super(x); -//│ this.x = x; -//│ } -//│ }; -//│ this.cache.D = ((x) => new D(x)); -//│ this.cache.D["class"] = D; -//│ } -//│ return this.cache.D; -//│ } -//│ }; -//│ globalThis.D = typing_unit5.D; -//│ // End of generated code -//│ ┌ Block at Super.mls:250 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit5 = { -//│ │ │ cache: {}, -//│ │ │ get D() { -//│ │ │ if (this.cache.D === undefined) { -//│ │ │ class D extends AA() { -//│ │ │ constructor(x) { -//│ │ │ super(x); -//│ │ │ this.x = x; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.D = ((x) => new D(x)); -//│ │ │ this.cache.D["class"] = D; -//│ │ │ } -//│ │ │ return this.cache.D; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.D = typing_unit5.D; -//│ │ └── Reply -//│ │ [Function (anonymous)] { class: [Function: D] } -//│ └── No queries -:js + :e -:ShowRepl class E(x: int): BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.301: class E(x: int): BB, AA(x) -//│ ╙── ^^^^^ +//│ ║ l.37: class E(x: int): BB, AA(x) +//│ ╙── ^^^^^ //│ class E(x: int) -//│ // Prelude -//│ let typing_unit6 = { -//│ cache: {}, -//│ get E() { -//│ if (this.cache.E === undefined) { -//│ class E extends AA(BB()) { -//│ constructor(x) { -//│ super(x); -//│ this.x = x; -//│ } -//│ }; -//│ this.cache.E = ((x) => new E(x)); -//│ this.cache.E["class"] = E; -//│ } -//│ return this.cache.E; -//│ } -//│ }; -//│ globalThis.E = typing_unit6.E; -//│ // End of generated code -//│ ┌ Block at Super.mls:301 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit6 = { -//│ │ │ cache: {}, -//│ │ │ get E() { -//│ │ │ if (this.cache.E === undefined) { -//│ │ │ class E extends AA(BB()) { -//│ │ │ constructor(x) { -//│ │ │ super(x); -//│ │ │ this.x = x; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.cache.E = ((x) => new E(x)); -//│ │ │ this.cache.E["class"] = E; -//│ │ │ } -//│ │ │ return this.cache.E; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.E = typing_unit6.E; -//│ │ └── Reply -//│ │ [Function (anonymous)] { class: [Function: E] } -//│ └── No queries From 044abb636760ecb5746d688422780a2944b1f58d Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 28 Feb 2023 12:13:36 +0800 Subject: [PATCH 123/498] Fix some misop --- shared/src/main/scala/mlscript/helpers.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 3fe941ee31..ce7c8a5869 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -617,7 +617,7 @@ trait TermImpl extends StatementImpl { self: Term => case lit: Lit => Literal(lit) case App(App(Var("|"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Inter(lhs.toType_!, rhs.toType_!) - case App(App(Var("->"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Function(lhs.toType_!, rhs.toType_!) + case App(App(Var("->"), lhs), Tup(N -> Fld(false, false, rhs) :: Nil)) => Function(lhs.toType_!, rhs.toType_!) case App(App(Var("|"), lhs), rhs) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), lhs), rhs) => Inter(lhs.toType_!, rhs.toType_!) case Lam(lhs, rhs) => Function(lhs.toType_!, rhs.toType_!) From 9a18622bd838a265762c5c39b2fa14980222cd23 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 28 Feb 2023 12:16:24 +0800 Subject: [PATCH 124/498] WIP: remove :js and add wip --- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 213 +----------------- shared/src/test/diff/nu/SimpleRegionDSL.mls | 96 ++------ 2 files changed, 31 insertions(+), 278 deletions(-) diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index e8fe115b17..066ccf3bb6 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -5,24 +5,8 @@ // * Adapted example from Code reuse through polymorphic variants (FOSE 2000) -:js module Nil //│ module Nil() -//│ // Prelude -//│ let res; -//│ let typing_unit = { -//│ cache: {}, -//│ get Nil() { -//│ if (this.cache.Nil === undefined) { -//│ class Nil {} -//│ this.cache.Nil = new Nil(); -//│ this.cache.Nil["class"] = Nil; -//│ } -//│ return this.cache.Nil; -//│ } -//│ }; -//│ globalThis.Nil = typing_unit.Nil; -//│ // End of generated code class Cons(head: A, tail: Cons | Nil) //│ class Cons[A](head: A, tail: Cons[A] | Nil) @@ -61,29 +45,9 @@ fun list_assoc(s, l) = // fun list_assoc(s: string, l: Cons<{ _1: string, _2: 'b }> | Nil): NotFound | Success['b] -:js class Var(s: string) //│ class Var(s: string) -//│ // Prelude -//│ let typing_unit7 = { -//│ cache: {}, -//│ get Var() { -//│ if (this.cache.Var === undefined) { -//│ class Var { -//│ constructor(s) { -//│ this.s = s; -//│ } -//│ }; -//│ this.cache.Var = ((s) => new Var(s)); -//│ this.cache.Var["class"] = Var; -//│ } -//│ return this.cache.Var; -//│ } -//│ }; -//│ globalThis.Var = typing_unit7.Var; -//│ // End of generated code - -:js + mixin EvalVar { fun eval(sub, v) = if v is Var(s) then @@ -96,56 +60,6 @@ mixin EvalVar { //│ } //│ where //│ 'A <: {_1: string, _2: 'result} -//│ // Prelude -//│ let typing_unit8 = { -//│ cache: {}, -//│ EvalVar(base) { -//│ if (base === undefined) { -//│ return (class EvalVar { -//│ constructor() { -//│ } -//│ eval(sub, v) { -//│ return ((() => { -//│ let a; -//│ return (a = v, a instanceof Var["class"] ? ((s) => (() => { -//│ return (((tmp0) => { -//│ let a; -//│ return (a = tmp0, a instanceof NotFound["class"] ? v : a instanceof Success["class"] ? ((r) => r)(tmp0.result) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })(list_assoc(s, sub))); -//│ })())(v.s) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalVar extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(sub, v) { -//│ return ((() => { -//│ let a; -//│ return (a = v, a instanceof Var["class"] ? ((s) => (() => { -//│ return (((tmp0) => { -//│ let a; -//│ return (a = tmp0, a instanceof NotFound["class"] ? v : a instanceof Success["class"] ? ((r) => r)(tmp0.result) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })(list_assoc(s, sub))); -//│ })())(v.s) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })()); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.EvalVar = typing_unit8.EvalVar; -//│ // End of generated code class Abs(x: string, t: A) class App(s: A, t: A) @@ -158,7 +72,6 @@ fun gensym(): string = "fun" fun int_to_string(x: int): string = "0" //│ fun int_to_string: (x: int,) -> string -:js mixin EvalLambda { fun eval(sub, v) = if v is @@ -183,76 +96,7 @@ mixin EvalLambda { //│ where //│ 'A2 :> (string, Var,) | 'A0 //│ <: 'A1 -//│ // Prelude -//│ let typing_unit12 = { -//│ cache: {}, -//│ EvalLambda(base) { -//│ if (base === undefined) { -//│ return (class EvalLambda { -//│ constructor() { -//│ } -//│ eval(sub, v) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = v, a instanceof App["class"] ? ((t1) => ((t2) => (() => { -//│ let l1 = self.eval(sub, t1); -//│ let l2 = self.eval(sub, t2); -//│ return (t1 instanceof Abs["class"] ? ((x) => ((t) => self.eval(Cons([ -//│ x, -//│ l2 -//│ ], Nil), t))(t1.t))(t1.x) : (() => { -//│ return App(l1, l2); -//│ })()); -//│ })())(v.t))(v.s) : a instanceof Abs["class"] ? ((x) => ((t) => (() => { -//│ let s = gensym(); -//│ return (Abs(s, self.eval(Cons([ -//│ x, -//│ Var(s) -//│ ], sub), t))); -//│ })())(v.t))(v.x) : (() => { -//│ return super.eval(sub, v); -//│ })()); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalLambda extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(sub, v) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = v, a instanceof App["class"] ? ((t1) => ((t2) => (() => { -//│ let l1 = self.eval(sub, t1); -//│ let l2 = self.eval(sub, t2); -//│ return (t1 instanceof Abs["class"] ? ((x) => ((t) => self.eval(Cons([ -//│ x, -//│ l2 -//│ ], Nil), t))(t1.t))(t1.x) : (() => { -//│ return App(l1, l2); -//│ })()); -//│ })())(v.t))(v.s) : a instanceof Abs["class"] ? ((x) => ((t) => (() => { -//│ let s = gensym(); -//│ return (Abs(s, self.eval(Cons([ -//│ x, -//│ Var(s) -//│ ], sub), t))); -//│ })())(v.t))(v.x) : (() => { -//│ return super.eval(sub, v); -//│ })()); -//│ })()); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.EvalLambda = typing_unit12.EvalLambda; -//│ // End of generated code - -:js + module Test1: EvalVar, EvalLambda //│ module Test1() { //│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> 'result @@ -265,24 +109,6 @@ module Test1: EvalVar, EvalLambda //│ <: 'A1 & {_1: string, _2: 'result} //│ 'A1 <: 'A & 'A0 //│ 'result :> Var | App['result] | Abs['result] -//│ // Prelude -//│ let typing_unit13 = { -//│ cache: {}, -//│ get Test1() { -//│ if (this.cache.Test1 === undefined) { -//│ class Test1 extends EvalLambda(EvalVar()) { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ } -//│ this.cache.Test1 = new Test1(); -//│ this.cache.Test1["class"] = Test1; -//│ } -//│ return this.cache.Test1; -//│ } -//│ }; -//│ globalThis.Test1 = typing_unit13.Test1; -//│ // End of generated code Test1.eval(Nil, Var("a")) //│ 'a @@ -370,16 +196,16 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.371: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.366: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.371: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.366: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.323: if v is +//│ ║ l.318: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.333: let vv = map_expr(eta, v) +//│ ║ l.328: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -420,7 +246,6 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num //│ res //│ = Var { s: 'a' } -:js module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { //│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> ('a | 'result) @@ -434,40 +259,22 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr //│ 'result :> Abs['result] | App['result] | Num | 'a | Var //│ 'a <: Add['b] | Mul['b] | Num | Var //│ 'b <: 'a -//│ // Prelude -//│ let typing_unit30 = { -//│ cache: {}, -//│ get Test31() { -//│ if (this.cache.Test31 === undefined) { -//│ class Test31 extends EvalExpr(EvalLambda(EvalVar())) { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ } -//│ this.cache.Test31 = new Test31(); -//│ this.cache.Test31["class"] = Test31; -//│ } -//│ return this.cache.Test31; -//│ } -//│ }; -//│ globalThis.Test31 = typing_unit30.Test31; -//│ // End of generated code // Because EvalExpr does not dispatch lambdas to super and map_expr only // handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.459: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.453: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.459: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.453: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.323: if v is +//│ ║ l.318: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.333: let vv = map_expr(eta, v) +//│ ║ l.328: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index cd43683010..0dd2aacca6 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -75,7 +75,6 @@ class Scale(v: Vector, a: Region) //│ class Empty() //│ class Scale[Region](v: Vector, a: Region) -:js mixin SizeExt { fun size(a) = if a is @@ -89,66 +88,13 @@ mixin SizeExt { //│ this: {size: 'a -> int} //│ fun size: (Empty | Scale['a] | Univ | 'b & ~Empty & ~Scale & ~Univ) -> (int | 'c) //│ } -//│ // Prelude -//│ let typing_unit7 = { -//│ cache: {}, -//│ SizeExt(base) { -//│ if (base === undefined) { -//│ return (class SizeExt { -//│ constructor() { -//│ } -//│ size(a) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return a = a, a instanceof Univ["class"] ? 1 : a instanceof Empty["class"] ? 1 : a instanceof Scale["class"] ? ((a) => self.size(a) + 1)(a.a) : super.size(a); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class SizeExt extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ size(a) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return a = a, a instanceof Univ["class"] ? 1 : a instanceof Empty["class"] ? 1 : a instanceof Scale["class"] ? ((a) => self.size(a) + 1)(a.a) : super.size(a); -//│ })()); -//│ } -//│ }); -//│ } -//│ } -//│ }; -//│ globalThis.SizeExt = typing_unit7.SizeExt; -//│ // End of generated code - -:js + module TestSize extends SizeBase, SizeExt //│ module TestSize() { //│ fun size: 'a -> int //│ } //│ where //│ 'a <: Circle | Empty | Intersect['a] | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ -//│ // Prelude -//│ let typing_unit8 = { -//│ cache: {}, -//│ get TestSize() { -//│ if (this.cache.TestSize === undefined) { -//│ class TestSize extends SizeExt(SizeBase()) { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ } -//│ this.cache.TestSize = new TestSize(); -//│ this.cache.TestSize["class"] = TestSize; -//│ } -//│ return this.cache.TestSize; -//│ } -//│ }; -//│ globalThis.TestSize = typing_unit8.TestSize; -//│ // End of generated code // TODO: UCS hygiene :re @@ -250,44 +196,44 @@ mixin Text { :e module SizeText extends Text //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.251: module SizeText extends Text +//│ ║ l.249: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.243: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.241: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.243: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.241: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.251: module SizeText extends Text +//│ ║ l.249: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.242: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.240: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.242: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.240: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.251: module SizeText extends Text +//│ ║ l.249: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.241: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.239: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.241: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.239: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.251: module SizeText extends Text +//│ ║ l.249: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.240: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.238: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.240: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.238: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -532,16 +478,16 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.533: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.531: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.446: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.444: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.533: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.531: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.186: if a is +//│ ║ l.184: if a is //│ ╙── ^ //│ error | bool //│ res @@ -552,16 +498,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.553: Lang.text(mk(100)) +//│ ║ l.551: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.446: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.444: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.553: Lang.text(mk(100)) +//│ ║ l.551: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.238: if e is +//│ ║ l.236: if e is //│ ╙── ^ //│ error | string //│ res From f4d047b4812280c6e2632cba86b54ac378b07e7e Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 28 Feb 2023 12:17:51 +0800 Subject: [PATCH 125/498] WIP: rerun tests --- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 16 ++++---- shared/src/test/diff/nu/SimpleRegionDSL.mls | 40 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 066ccf3bb6..1174fcd7a9 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -196,16 +196,16 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.366: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.197: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.366: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.197: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.318: if v is +//│ ║ l.149: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.328: let vv = map_expr(eta, v) +//│ ║ l.159: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -265,16 +265,16 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.453: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.266: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.453: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.266: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.318: if v is +//│ ║ l.149: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.328: let vv = map_expr(eta, v) +//│ ║ l.159: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index 0dd2aacca6..a1a5cb264e 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -196,44 +196,44 @@ mixin Text { :e module SizeText extends Text //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.249: module SizeText extends Text +//│ ║ l.197: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.241: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.189: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.241: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.189: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.249: module SizeText extends Text +//│ ║ l.197: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.240: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.188: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.240: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.188: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.249: module SizeText extends Text +//│ ║ l.197: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.239: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.187: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.239: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.187: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.249: module SizeText extends Text +//│ ║ l.197: module SizeText extends Text //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' //│ ╟── Note: constraint arises from field selection: -//│ ║ l.238: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.186: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ║ ^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.238: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.186: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -478,16 +478,16 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.531: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.479: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.444: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.392: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.531: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.479: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.184: if a is +//│ ║ l.132: if a is //│ ╙── ^ //│ error | bool //│ res @@ -498,16 +498,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.551: Lang.text(mk(100)) +//│ ║ l.499: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.444: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.392: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.551: Lang.text(mk(100)) +//│ ║ l.499: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.236: if e is +//│ ║ l.184: if e is //│ ╙── ^ //│ error | string //│ res From 326fec5dc4f087fe5db9385c0d990fc1e2a16301 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 28 Feb 2023 14:31:58 +0800 Subject: [PATCH 126/498] WIP Minor note --- shared/src/test/diff/nu/ECOOP23.mls | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 63cb22a724..0086943d13 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -145,6 +145,11 @@ mixin EvalNegNeg { fun eval(e) = if e is Neg(Neg(d)) then this.eval(d) else super.eval(e) + // * Note: the above is equivalent to: + // if e is Neg(f) then + // if f is Neg(d) then this.eval(d) + // else super.eval(e) + // else super.eval(e) } //│ mixin EvalNegNeg() { //│ super: {eval: (Neg['A] | 'a) -> 'b} From 68ee8c2adab74347efcaba2e1cd40aa555761834 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 28 Feb 2023 19:30:12 +0800 Subject: [PATCH 127/498] Put everything into tables --- js/src/main/scala/Main.scala | 43 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index 5af70a5787..c6c1e0074e 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -145,16 +145,21 @@ object Main { val exp = typer.expandType(sim)(ctx) - val expStr = "=====================Typing Results=====================\n" + - exp.showIn(ShowCtx.mk(exp :: Nil) - // .copy(newDefs = true) // TODO later - , 0) - - // TODO format HTML better - val typingStr = expStr.stripSuffix("\n") + val expStr = exp.showIn(ShowCtx.mk(exp :: Nil), 0).stripSuffix("\n") .replaceAll(" ", "  ") .replaceAll("\n", "
") + // TODO format HTML better + val typingStr = """
+ | + | + | + |""".stripMargin + + s""" + | ${s""} + | + |""".stripMargin + val backend = new JSWebBackend() val (lines, resNames) = backend(pgrm, true) val code = lines.mkString("\n") @@ -170,10 +175,10 @@ object Main { case Right(lines) => generateResultTable(resNames.zip(lines)) } - val resStr = ("\n\n=====================Results=====================") - .stripSuffix("\n") - .replaceAll(" ", "  ") - .replaceAll("\n", "
") + exe + val resStr = (""" + | + | + |""".stripMargin + exe + "
Typing Results
${expStr}
Results
") typingStr + resStr } @@ -217,24 +222,20 @@ object Main { private def generateResultTable(res: Ls[(Str, Str)]): Str = { val htmlBuilder = new StringBuilder - htmlBuilder ++= """ - | - | - | - | - | - | + htmlBuilder ++= """ + | + | + | |""".stripMargin res.foreach(value => { htmlBuilder ++= s""" - | - | ${s""} + | + | ${s""} | |""".stripMargin }) - htmlBuilder ++= "
NameValue
NameValue
${value._1}${value._2}${value._1.replaceAll(" ", "  ").replaceAll("\n", "
")}
${value._2.replaceAll(" ", "  ").replaceAll("\n", "
")}
" htmlBuilder.toString } From 312d01abf2d421acb2e10d10a8374fcfc82aeb92 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 28 Feb 2023 20:07:37 +0800 Subject: [PATCH 128/498] Change table name --- js/src/main/scala/Main.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index c6c1e0074e..8610e6733f 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -176,7 +176,7 @@ object Main { } val resStr = (""" - | Results + | Execution Results | |""".stripMargin + exe + "") From bc5a4dd1b3c8c30764f308fdd62cf3c87b00ae12 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 1 Mar 2023 18:33:36 +0800 Subject: [PATCH 129/498] Minor web demo improvements --- index.css | 2 +- js/src/main/scala/Main.scala | 4 ++-- local_testing.html | 24 +++++++++++++++++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/index.css b/index.css index 3c53c67fa0..4e99503067 100644 --- a/index.css +++ b/index.css @@ -20,7 +20,7 @@ h1, p{ #content { width: 100%; padding: 0px; - height: 600px; + height: 750px; display: grid; grid-template-columns: 50% 50%; grid-template-rows: 100%; diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index 8610e6733f..b0ce5d2a17 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -152,7 +152,7 @@ object Main { // TODO format HTML better val typingStr = """
| - | + | | |""".stripMargin + s""" @@ -176,7 +176,7 @@ object Main { } val resStr = (""" - | + | | |""".stripMargin + exe + "
Typing Results

Typing Results:

Execution Results

Execution Results:

") diff --git a/local_testing.html b/local_testing.html index 3d25eb561c..b538c94b0a 100644 --- a/local_testing.html +++ b/local_testing.html @@ -9,9 +9,9 @@

MLscript demonstration

@@ -45,19 +39,15 @@

MLscript demonstration

Tip: additional definitions from the paper – copy and paste to try them out:

+class Mul[E](lhs: E, rhs: E)
mixin EvalMul {
-  fun eval(e) =
-    if e is
-      Mul(l, r) then this.eval(l) * this.eval(r)
-    else super.eval(e)
+  fun eval(override Mul(l, r)) = this.eval(l) * this.eval(r)
}
mixin EvalNegNeg {
-  fun eval(e) =
-    if e is Neg(Neg(d)) then this.eval(d)
-    else super.eval(e)
+  fun eval(override Neg(Neg(d))) = this.eval(d)
}

-module TestLang2: EvalNothing, EvalAddLit, EvalNeg, EvalMul, EvalNegNeg
+module TestLang2: EvalAddLit, EvalNeg, EvalMul, EvalNegNeg

let res2 = TestLang2.eval(add2negadd11)
diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 00850c04b3..a32784268f 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -265,6 +265,7 @@ object NewLexer { "mixin", "interface", "extends", + "override", "new", "namespace", "module", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 9a660cae90..f94dbc2de2 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -22,6 +22,20 @@ import NewParser._ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: Diagnostic => Unit, val dbg: Bool, fallbackLoc: Opt[Loc], description: Str = "input") { outer => + private var freshCnt: Int = 0 + final def freshVar: Var = { + val res = Var("_$" + freshCnt) + freshCnt += 1 + res + } + + object Spaces { + def unapply(xs: Ls[Stroken -> Loc]): S[(() => Unit, Ls[Stroken -> Loc])] = xs match { + case (SPACE, _) :: Spaces(cons, rest) => S((() => {cons(); consume}, rest)) + case _ => S(() => (), xs) + } + } + final def rec(tokens: Ls[Stroken -> Loc], fallbackLoc: Opt[Loc], description: Str): NewParser = new NewParser(origin, tokens, raiseFun, dbg, fallbackLoc, description) { def doPrintDbg(msg: => Str): Unit = outer.printDbg("> " + msg) @@ -337,7 +351,24 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D ts case _ => Nil } - val ps = funParams + val (ps, transformBody) = yeetSpaces match { + case (br @ BRACKETS(Round, Spaces(cons, (KEYWORD("override"), ovLoc) :: rest)), loc) :: rest2 => + _cur = BRACKETS(Round, rest)(br.innerLoc) -> loc :: rest2 + funParams match { + case ps @ Tup(N -> Fld(false, false, pat) :: Nil) :: Nil => + val fv = freshVar + (Tup(N -> Fld(false, false, fv) :: Nil) :: Nil, S( + (body: Term) => If(IfOpApp(fv, Var("is"), IfThen(pat, body)), S( + App(Sel(Var("super").withLoc(S(ovLoc)), v), Tup(N -> Fld(false, false, fv) :: Nil)) + )) + )) + case r => + err(msg"Unsupported 'override' parameter list shape" -> S(br.innerLoc) :: Nil) + (r, N) + } + case _ => + (funParams, N) + } val asc = yeetSpaces match { case (KEYWORD(":"), _) :: _ => consume @@ -349,11 +380,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (KEYWORD("="), _) :: _ => consume val body = expr(0) - val annotatedBody = asc.fold(body)(ty => Asc(body, ty)) + val newBody = transformBody.fold(body)(_(body)) + val annotatedBody = asc.fold(newBody)(ty => Asc(newBody, ty)) R(NuFunDef(isLetRec, v, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))))) case c => asc match { case S(ty) => + if (transformBody.nonEmpty) die // TODO R(NuFunDef(isLetRec, v, tparams, R(PolyType(Nil, ps.foldRight(ty)((p, r) => Function(p.toType match { case L(diag) => raise(diag); Top // TODO better case R(tp) => tp diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index ce7c8a5869..1d19a34942 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -680,7 +680,7 @@ trait LitImpl { self: Lit => trait VarImpl { self: Var => def isPatVar: Bool = - name.head.isLetter && name.head.isLower && name =/= "true" && name =/= "false" + (name.head.isLetter && name.head.isLower || name.head === '_' || name.head === '$') && name =/= "true" && name =/= "false" var uid: Opt[Int] = N } diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 0086943d13..1fa7d80c63 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -157,6 +157,16 @@ mixin EvalNegNeg { //│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } +// * Alternative: +mixin EvalNegNeg { + fun eval(override Neg(Neg(d))) = this.eval(d) +} +//│ mixin EvalNegNeg() { +//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ this: {eval: 'expr -> 'b} +//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b +//│ } + module TestLang: EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { //│ fun eval: 'a -> int diff --git a/shared/src/test/diff/nu/FunPatterns.mls b/shared/src/test/diff/nu/FunPatterns.mls new file mode 100644 index 0000000000..badf87a2ad --- /dev/null +++ b/shared/src/test/diff/nu/FunPatterns.mls @@ -0,0 +1,34 @@ +:NewParser +:NewDefs +:NoJS + + +fun f(x, y) = x + y +//│ fun f: (int, int,) -> int + +// FIXME array pattern...?! +fun f1([x, y]) = x + y +fun f2([x, y],) = x + y +fun f3([(x, y,),],) = x + y +//│ fun f1: (int, int,) -> int +//│ fun f2: (int, int,) -> int +//│ fun f3: (int, int,) -> int + + +class Pair(lhs: int, rhs: int) +//│ class Pair(lhs: int, rhs: int) + +// TODO +fun f(Pair(x, y)) = x + y +//│ ╔══[ERROR] Unsupported pattern shape: +//│ ║ l.22: fun f(Pair(x, y)) = x + y +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.22: fun f(Pair(x, y)) = x + y +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.22: fun f(Pair(x, y)) = x + y +//│ ╙── ^ +//│ fun f: error -> int + + diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls new file mode 100644 index 0000000000..5898a705dd --- /dev/null +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -0,0 +1,53 @@ +:NewParser +:NewDefs +:NoJS + + + +class Pair(lhs: int, rhs: int) +//│ class Pair(lhs: int, rhs: int) + + +:p +:e +fun f(override Pair(x, y)) = x + y +//│ |#fun| |f|(|#override| |Pair|(|x|,| |y|)|)| |#=| |x| |+| |y| +//│ Parsed: fun f = (_$0,) => if _$0 is (Pair (x, y,)) then + (x,) (y,) else (super).f (_$0,); +//│ ╔══[ERROR] identifier not found: super +//│ ║ l.13: fun f(override Pair(x, y)) = x + y +//│ ╙── ^^^^^^^^ +//│ fun f: anything -> (error | int) + + +mixin Test { + fun f(override Pair(x, y)) = x + y +} +//│ mixin Test() { +//│ super: {f: 'a -> 'b} +//│ fun f: (Pair | 'a & ~Pair) -> (int | 'b) +//│ } + + +:pe +:e +fun f(override Pair(x, y), z) = x + y +//│ ╔══[PARSE ERROR] Unsupported 'override' parameter section shape +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Unsupported pattern shape: +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ╙── ^ +//│ fun f: (error, anything,) -> int + + +// TODO +// :pe +// fun f(override Pair(x, y)): int + + From fea7af898d10b1b6ee105e50bbc8df6de89ecab7 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 7 Mar 2023 13:28:02 +0800 Subject: [PATCH 134/498] WIP Update ECOOP tests + add new misc. tests --- .../src/main/scala/mlscript/JSBackend.scala | 2 +- shared/src/test/diff/nu/ECOOP23_intro.mls | 108 ++++++++++++----- shared/src/test/diff/nu/FilterMap.mls | 81 +++++++++++++ .../test/diff/nu/NewPolyVariantCodeReuse.mls | 14 +-- shared/src/test/diff/nu/OverrideShorthand.mls | 2 +- shared/src/test/diff/nu/SimpleRegionDSL.mls | 10 +- shared/src/test/diff/ucs/ElseIf.mls | 110 ++++++++++++++++++ shared/src/test/diff/ucs/ErrorMessage.mls | 4 +- shared/src/test/diff/ucs/Humiliation.mls | 6 +- shared/src/test/diff/ucs/MultiwayIf.mls | 53 +++++++++ shared/src/test/diff/ucs/NestedBranches.mls | 2 +- shared/src/test/diff/ucs/SimpleUCS.mls | 10 +- shared/src/test/diff/ucs/SplitAfterOp.mls | 18 +-- shared/src/test/diff/ucs/SplitAnd.mls | 4 +- shared/src/test/diff/ucs/SplitAroundOp.mls | 2 +- shared/src/test/diff/ucs/SplitBeforeOp.mls | 6 +- shared/src/test/diff/ucs/SplitOps.mls | 6 +- shared/src/test/diff/ucs/WeirdIf.mls | 6 +- 18 files changed, 372 insertions(+), 72 deletions(-) create mode 100644 shared/src/test/diff/nu/FilterMap.mls create mode 100644 shared/src/test/diff/ucs/ElseIf.mls create mode 100644 shared/src/test/diff/ucs/MultiwayIf.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 5e1e4ae148..a87ad1a3a4 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -256,7 +256,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } case Inst(bod) => translateTerm(bod) case iff: If => - throw CodeGenError(s"if expression has not been desugared") + throw CodeGenError(s"if expression was not desugared") case New(N, TypingUnit(Nil)) => JSRecord(Nil) case New(S(TypeName(className) -> Tup(args)), TypingUnit(Nil)) => val callee = translateVar(className, true) diff --git a/shared/src/test/diff/nu/ECOOP23_intro.mls b/shared/src/test/diff/nu/ECOOP23_intro.mls index c3fbdff360..d03e337885 100644 --- a/shared/src/test/diff/nu/ECOOP23_intro.mls +++ b/shared/src/test/diff/nu/ECOOP23_intro.mls @@ -1,6 +1,5 @@ :NewParser :NewDefs -:NoJS @@ -20,27 +19,31 @@ mixin ComparePoint { //│ } +eq(1)(2) +//│ bool +//│ res +//│ = false -class Color { fun eq: Color -> bool } -//│ class Color() { -//│ fun eq: Color -> bool -//│ } -let Red = Color() -//│ let Red: Color +let Red = "red" +//│ let Red: "red" +//│ Red +//│ = 'red' mixin CompareColored { fun compare(lhs, rhs) = - super.compare(lhs, rhs) && lhs.color.eq(rhs.color) + super.compare(lhs, rhs) && eq(lhs.color)(rhs.color) } //│ mixin CompareColored() { //│ super: {compare: ('a, 'b,) -> bool} -//│ fun compare: ({color: {eq: 'color -> bool}} & 'a, {color: 'color} & 'b,) -> bool +//│ fun compare: ({color: anything} & 'a, {color: anything} & 'b,) -> bool //│ } +// * Explicit version from paper: + // interface Nested[Base] { parent: Option[Base] } // mixin CompareNested[Base, Final] { @@ -54,6 +57,7 @@ mixin CompareColored { // else rhs.parent is None // } +// * Implicit version: mixin CompareNested { fun compare(lhs, rhs): bool = @@ -68,23 +72,20 @@ mixin CompareNested { //│ fun compare: ({parent: Some['value] | ~Some[anything]} & 'a, {parent: Some['value0] | ~Some[anything]} & 'b,) -> bool //│ } -mixin CompareNested { - fun compare(lhs, rhs): bool = - super.compare(lhs, rhs) && - if lhs.parent is - Some(p) then rhs.parent is Some(q) and this.compare(p, q) - None then rhs.parent is None -} -//│ mixin CompareNested() { -//│ super: {compare: ('a, 'b,) -> bool} -//│ this: {compare: ('value, 'value0,) -> bool} -//│ fun compare: ({parent: None | Some['value]} & 'a, {parent: Some['value0] | ~Some[anything]} & 'b,) -> bool -//│ } +// * Alternatively: + +// mixin CompareNested { +// fun compare(lhs, rhs): bool = +// super.compare(lhs, rhs) && +// if lhs.parent is +// Some(p) then rhs.parent is Some(q) and this.compare(p, q) +// None then rhs.parent is None +// } -class MyPoint(x: int, y: int, color: Color, parent: Some[MyPoint] | None) -//│ class MyPoint(x: int, y: int, color: Color, parent: None | Some[MyPoint]) +class MyPoint(x: int, y: int, color: string, parent: Some[MyPoint] | None) +//│ class MyPoint(x: int, y: int, color: string, parent: None | Some[MyPoint]) module CompareMyPoint extends ComparePoint, CompareColored, CompareNested @@ -92,30 +93,85 @@ module CompareMyPoint extends ComparePoint, CompareColored, CompareNested //│ fun compare: ('a, 'b,) -> bool //│ } //│ where -//│ 'b <: {color: 'color, parent: Some['b] | ~Some[anything], x: number, y: number} -//│ 'a <: {color: {eq: 'color -> bool}, parent: None | Some['a], x: number, y: number} +//│ 'b <: {color: anything, parent: Some['b] | ~Some[anything], x: number, y: number} +//│ 'a <: {color: anything, parent: Some['a] | ~Some[anything], x: number, y: number} +let p0 = MyPoint(0, 0, Red, None) let p1 = MyPoint(0, 1, Red, None) let p2 = MyPoint(0, 1, Red, None) let p3 = MyPoint(0, 1, Red, Some(p1)) let p4 = MyPoint(0, 1, Red, Some(p2)) let p5 = MyPoint(0, 1, Red, Some(p3)) +//│ let p0: MyPoint //│ let p1: MyPoint //│ let p2: MyPoint //│ let p3: MyPoint //│ let p4: MyPoint //│ let p5: MyPoint - +//│ p0 +//│ = MyPoint { +//│ x: 0, +//│ y: 0, +//│ color: 'red', +//│ parent: None { class: [class None] } +//│ } +//│ p1 +//│ = MyPoint { +//│ x: 0, +//│ y: 1, +//│ color: 'red', +//│ parent: None { class: [class None] } +//│ } +//│ p2 +//│ = MyPoint { +//│ x: 0, +//│ y: 1, +//│ color: 'red', +//│ parent: None { class: [class None] } +//│ } +//│ p3 +//│ = MyPoint { +//│ x: 0, +//│ y: 1, +//│ color: 'red', +//│ parent: Some { value: MyPoint { x: 0, y: 1, color: 'red', parent: [None] } } +//│ } +//│ p4 +//│ = MyPoint { +//│ x: 0, +//│ y: 1, +//│ color: 'red', +//│ parent: Some { value: MyPoint { x: 0, y: 1, color: 'red', parent: [None] } } +//│ } +//│ p5 +//│ = MyPoint { +//│ x: 0, +//│ y: 1, +//│ color: 'red', +//│ parent: Some { value: MyPoint { x: 0, y: 1, color: 'red', parent: [Some] } } +//│ } + + +CompareMyPoint.compare(p0, p1) +//│ bool +//│ res +//│ = false CompareMyPoint.compare(p1, p2) //│ bool +//│ res +//│ = true CompareMyPoint.compare(p3, p4) //│ bool +//│ res +//│ = true CompareMyPoint.compare(p3, p5) //│ bool +//│ res +//│ = false diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls new file mode 100644 index 0000000000..325693b37a --- /dev/null +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -0,0 +1,81 @@ +:NewParser +:NewDefs + + +// * From https://arxiv.org/abs/2302.12783 + +// 1 -spec filtermap ( fun (( T ) -> boolean ()) , [ T ]) -> [ T ] +// 2 ; ( fun (( T ) -> { true , U } | false ) , [ T ]) -> [ U ] +// 3 ; ( fun (( T ) -> { true , U } | boolean ()) , [ T ]) -> [ T | U ]. +// 4 filtermap ( _F , []) -> []; +// 5 filtermap (F , [ X | XS ]) -> +// 6 case F ( X ) of +// 7 false -> filtermap (F , XS ); +// 8 true -> [ X | filtermap (F , XS )]; +// 9 { true , Y } -> [ Y | filtermap (F , XS )] +// 10 end. + + +module Nil +class Cons[A](head: A, tail: Cons[A] | Nil) +//│ module Nil() +//│ class Cons[A](head: A, tail: Cons[A] | Nil) + + +// FIXME UCS +fun filtermap(f, xs) = if xs is + Nil then Nil + Cons(y, ys) and f(ys) is + false then filtermap(f, ys) + true then Cons(y, filtermap(f, ys)) + [true, z] then Cons(y, filtermap(f, ys)) +//│ ╔══[ERROR] identifier not found: ys +//│ ║ l.28: Cons(y, ys) and f(ys) is +//│ ╙── ^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.28: Cons(y, ys) and f(ys) is +//│ ║ ^^^^^^^^ +//│ ║ l.29: false then filtermap(f, ys) +//│ ║ ^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `number` +//│ ║ l.29: false then filtermap(f, ys) +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.28: Cons(y, ys) and f(ys) is +//│ ║ ^^^^^^^^ +//│ ║ l.29: false then filtermap(f, ys) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.30: true then Cons(y, filtermap(f, ys)) +//│ ║ ^^^^^^^^ +//│ ╟── reference of type `true` is not an instance of type `number` +//│ ║ l.30: true then Cons(y, filtermap(f, ys)) +//│ ╙── ^^^^ +//│ ╔══[ERROR] type identifier not found: Tuple#2 +//│ ╙── +//│ fun filtermap: ((error | Cons['A] | Nil) -> number & (Cons['A] | Nil) -> error, Cons['A0] | Nil,) -> (Cons['A1] | Nil | error) +//│ where +//│ 'A := 'A0 +//│ 'A0 <: nothing +//│ Code generation encountered an error: +//│ unknown match case: Tuple#2 + + +module True +module False +//│ module True() +//│ module False() + +class Pair[A, B](lhs: A, rhs: B) +//│ class Pair[A, B](lhs: A, rhs: B) + +fun filtermap(f, xs) = if xs is + Nil then Nil + Cons(y, ys) then if f(y) is + True then filtermap(f, ys) + False then Cons(y, filtermap(f, ys)) + Pair(True, z) then Cons(z, filtermap(f, ys)) +//│ fun filtermap: ('head -> (False | Pair[anything, 'A] | True), Cons['head] | Nil,) -> (Cons['A] | Nil) +//│ where +//│ 'head <: 'A + + diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 1174fcd7a9..3edec51a6f 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -8,7 +8,7 @@ module Nil //│ module Nil() -class Cons
(head: A, tail: Cons | Nil) +class Cons[A](head: A, tail: Cons[A] | Nil) //│ class Cons[A](head: A, tail: Cons[A] | Nil) let l = Cons(1, Nil) @@ -19,7 +19,7 @@ let l = Cons(1, Nil) //│ = Cons { head: 1, tail: Nil { class: [class Nil] } } class NotFound -class Success(result: A) +class Success[A](result: A) //│ class NotFound() //│ class Success[A](result: A) @@ -43,7 +43,7 @@ fun list_assoc(s, l) = //│ where //│ 'A <: {_1: string, _2: 'A0} -// fun list_assoc(s: string, l: Cons<{ _1: string, _2: 'b }> | Nil): NotFound | Success['b] +// fun list_assoc(s: string, l: Cons[{ _1: string, _2: 'b }] | Nil): NotFound | Success['b] class Var(s: string) //│ class Var(s: string) @@ -61,8 +61,8 @@ mixin EvalVar { //│ where //│ 'A <: {_1: string, _2: 'result} -class Abs(x: string, t: A) -class App(s: A, t: A) +class Abs[A](x: string, t: A) +class App[A](s: A, t: A) //│ class Abs[A](x: string, t: A) //│ class App[A](s: A, t: A) @@ -139,8 +139,8 @@ Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c" //│ = Var { s: 'b' } class Num(n: int) -class Add(l: A, r: A) -class Mul(l: A, r: A) +class Add[A](l: A, r: A) +class Mul[A](l: A, r: A) //│ class Num(n: int) //│ class Add[A](l: A, r: A) //│ class Mul[A](l: A, r: A) diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls index 5898a705dd..f05f438bbd 100644 --- a/shared/src/test/diff/nu/OverrideShorthand.mls +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -31,7 +31,7 @@ mixin Test { :pe :e fun f(override Pair(x, y), z) = x + y -//│ ╔══[PARSE ERROR] Unsupported 'override' parameter section shape +//│ ╔══[PARSE ERROR] Unsupported 'override' parameter list shape //│ ║ l.33: fun f(override Pair(x, y), z) = x + y //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unsupported pattern shape: diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index 11f47c6faa..edbcc3e430 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -11,10 +11,10 @@ class Vector(x: int, y: int) //│ class Vector(x: int, y: int) class Circle(radius: int) -class Outside(a: Region) -class Union(a: Region, b: Region) -class Intersect(a: Region, b: Region) -class Translate(v: Vector, a: Region) +class Outside[Region](a: Region) +class Union[Region](a: Region, b: Region) +class Intersect[Region](a: Region, b: Region) +class Translate[Region](v: Vector, a: Region) //│ class Circle(radius: int) //│ class Outside[Region](a: Region) //│ class Union[Region](a: Region, b: Region) @@ -70,7 +70,7 @@ let circles = go(2, 1024) class Univ class Empty -class Scale(v: Vector, a: Region) +class Scale[Region](v: Vector, a: Region) //│ class Univ() //│ class Empty() //│ class Scale[Region](v: Vector, a: Region) diff --git a/shared/src/test/diff/ucs/ElseIf.mls b/shared/src/test/diff/ucs/ElseIf.mls new file mode 100644 index 0000000000..2628d58c7a --- /dev/null +++ b/shared/src/test/diff/ucs/ElseIf.mls @@ -0,0 +1,110 @@ +:NewParser +:NewDefs + + + +fun f(x, y) = if x == + 0 then true + 1 then false + else if y == + 0 then true + 1 then false + else false +//│ fun f: (number, number,) -> bool + +fun f(x, y) = if x == + 0 then true + 1 then false + else if y == + 0 then true + _ then false +//│ fun f: (number, number,) -> bool + + + +// TODO use real booleans +module True +module False +//│ module True() +//│ module False() + + +:e +:ge +fun f(x, y) = if x is + True and y is True then true + False and y is False then false +//│ ╔══[ERROR] The match is not exhaustive. +//│ ║ l.35: True and y is True then true +//│ ║ ^^^^^^^^^ +//│ ╟── The scrutinee at this position misses 1 case. +//│ ║ l.35: True and y is True then true +//│ ║ ^ +//│ ╙── [Missing Case 1/1] `False` +//│ fun f: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + +fun f(x, y) = if x is + True and y is True then true + False and y is False then false + True and y is False then true + False and y is True then true +//│ fun f: (False | True, False | True,) -> bool + +// FIXME +fun f(x, y) = if x is + True and y is True then true + False and y is False then false + _ and y is + True then true + False then false +//│ ╔══[ERROR] The match is not exhaustive. +//│ ║ l.57: True and y is True then true +//│ ║ ^^^^^^^^^ +//│ ╟── The scrutinee at this position misses 1 case. +//│ ║ l.57: True and y is True then true +//│ ║ ^ +//│ ╙── [Missing Case 1/1] `False` +//│ fun f: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + +// TODO support `else if` +fun f(x, y) = if x is + True and y is True then true + False and y is False then false + else if y is + True then true + False then false +//│ ╔══[ERROR] The match is not exhaustive. +//│ ║ l.75: True and y is True then true +//│ ║ ^^^^^^^^^ +//│ ╟── The scrutinee at this position misses 1 case. +//│ ║ l.75: True and y is True then true +//│ ║ ^ +//│ ╙── [Missing Case 1/1] `False` +//│ fun f: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + +// TODO support `else if` +fun f(x, y) = if x is + True and y is True then true + False and y is False then false + else if y is + True and x is False then true + False and x is True then false +//│ ╔══[ERROR] The match is not exhaustive. +//│ ║ l.93: True and y is True then true +//│ ║ ^^^^^^^^^ +//│ ╟── The scrutinee at this position misses 1 case. +//│ ║ l.93: True and y is True then true +//│ ║ ^ +//│ ╙── [Missing Case 1/1] `False` +//│ fun f: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + + diff --git a/shared/src/test/diff/ucs/ErrorMessage.mls b/shared/src/test/diff/ucs/ErrorMessage.mls index ae72c51784..aa40b49387 100644 --- a/shared/src/test/diff/ucs/ErrorMessage.mls +++ b/shared/src/test/diff/ucs/ErrorMessage.mls @@ -15,7 +15,7 @@ fun f(p) = //│ ╙── ^^^^^^^^^^^^^^ //│ f: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -27,4 +27,4 @@ fun g(xs) = //│ ╙── ^^ //│ g: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/Humiliation.mls b/shared/src/test/diff/ucs/Humiliation.mls index 0ffb9e5e1c..bb55ab0a1c 100644 --- a/shared/src/test/diff/ucs/Humiliation.mls +++ b/shared/src/test/diff/ucs/Humiliation.mls @@ -77,7 +77,7 @@ fun foo(x) = if x is //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared // Change `Pair` to a real pair. :e @@ -97,7 +97,7 @@ fun foo(x) = if x is //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun foo(x) = if x is Pair(a, b) then if a is @@ -170,7 +170,7 @@ fun foo(x) = if x is //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun foo(x, y) = if x is Z() and y is O() then 0 else 1 //│ foo: (anything, anything,) -> (0 | 1) diff --git a/shared/src/test/diff/ucs/MultiwayIf.mls b/shared/src/test/diff/ucs/MultiwayIf.mls new file mode 100644 index 0000000000..41e93b4ada --- /dev/null +++ b/shared/src/test/diff/ucs/MultiwayIf.mls @@ -0,0 +1,53 @@ +:NewParser + + +fun f(x) = + if + x > 0 then 0 + x == 0 then 1 + _ then 2 +//│ f: number -> (0 | 1 | 2) +//│ = [Function: f] + + +// FIXME +fun f(x) = + if + x > 0 and + x % 2 === 0 then true + _ then false + x == 0 then true + _ then false +//│ ╔══[WARNING] Found a duplicated else branch +//│ ║ l.20: _ then false +//│ ║ ^^^^^ +//│ ╟── The first else branch was declared here. +//│ ║ l.18: _ then false +//│ ╙── ^^^^^ +//│ ╔══[ERROR] identifier not found: === +//│ ║ l.17: x % 2 === 0 then true +//│ ╙── ^^^ +//│ f: int -> bool +//│ = [Function: f1] + +// FIXME +fun f(x) = + if + x > 0 and + x % 2 === 0 then true + else false + x == 0 then true + else false +//│ ╔══[WARNING] Found a duplicated else branch +//│ ║ l.40: else false +//│ ║ ^^^^^ +//│ ╟── The first else branch was declared here. +//│ ║ l.38: else false +//│ ╙── ^^^^^ +//│ ╔══[ERROR] identifier not found: === +//│ ║ l.37: x % 2 === 0 then true +//│ ╙── ^^^ +//│ f: int -> bool +//│ = [Function: f2] + + diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index 332947089f..af2293b332 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -110,7 +110,7 @@ fun mapPartition(f, xs) = if xs is //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ mapPartition: (anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/SimpleUCS.mls b/shared/src/test/diff/ucs/SimpleUCS.mls index 192b31c312..ab573e45e0 100644 --- a/shared/src/test/diff/ucs/SimpleUCS.mls +++ b/shared/src/test/diff/ucs/SimpleUCS.mls @@ -49,7 +49,7 @@ fun f(x, y) = //│ ╙── ^^^^^^^^^ //│ f: (anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun f(x, y) = if x is @@ -130,7 +130,7 @@ fun f(x, y) = //│ ╙── ^^^^^^ //│ f: (anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -153,7 +153,7 @@ fun f(x, y) = //│ ╙── ^^^^^^ //│ f: (anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun f(x, y) = if x is @@ -190,7 +190,7 @@ fun f(x, y) = //│ ╙── ^^^^^^^^^^ //│ f: (anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun isValid(x) = if x then false else true //│ isValid: anything -> bool @@ -359,7 +359,7 @@ fun f(x) = //│ ╙── ^^ //│ f: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun f(x) = if x == 0 and x is diff --git a/shared/src/test/diff/ucs/SplitAfterOp.mls b/shared/src/test/diff/ucs/SplitAfterOp.mls index 37baeee25a..b8d8df041e 100644 --- a/shared/src/test/diff/ucs/SplitAfterOp.mls +++ b/shared/src/test/diff/ucs/SplitAfterOp.mls @@ -10,7 +10,7 @@ fun f(x, b) = //│ ╙── ^ //│ f: (anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -26,7 +26,7 @@ if x == y + //│ ╙── ^^^^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -42,7 +42,7 @@ if x == y * //│ ╙── ^^^^^^^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -61,7 +61,7 @@ if x == //│ ╙── ^^^^^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -72,7 +72,7 @@ if x == //│ ╙── ^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e @@ -90,7 +90,7 @@ fun toEnglish(x) = //│ ╙── ^^^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -107,7 +107,7 @@ fun toEnglish(x) = //│ ╙── ^^^^^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -124,7 +124,7 @@ fun toEnglish(x) = //│ ╙── ^^^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun toEnglish(x) = if x == @@ -160,5 +160,5 @@ fun toEnglish(x) = //│ ╙── ^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/SplitAnd.mls b/shared/src/test/diff/ucs/SplitAnd.mls index 5f0dd20e6c..484a7e120f 100644 --- a/shared/src/test/diff/ucs/SplitAnd.mls +++ b/shared/src/test/diff/ucs/SplitAnd.mls @@ -31,7 +31,7 @@ fun f(x) = //│ ╙── ^^^^^^ //│ f: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -45,4 +45,4 @@ fun f(x, y) = //│ ╙── ^^^^^^ //│ f: (anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/SplitAroundOp.mls b/shared/src/test/diff/ucs/SplitAroundOp.mls index dc2d1be5b0..1ff84e7f36 100644 --- a/shared/src/test/diff/ucs/SplitAroundOp.mls +++ b/shared/src/test/diff/ucs/SplitAroundOp.mls @@ -116,4 +116,4 @@ if x is //│ ╙── ^^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/SplitBeforeOp.mls b/shared/src/test/diff/ucs/SplitBeforeOp.mls index c8a7ae203e..f6b14129b8 100644 --- a/shared/src/test/diff/ucs/SplitBeforeOp.mls +++ b/shared/src/test/diff/ucs/SplitBeforeOp.mls @@ -11,7 +11,7 @@ if x //│ ╙── ^^^^^^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -23,7 +23,7 @@ if x //│ ╙── ^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -37,4 +37,4 @@ if x //│ ╙── ^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/SplitOps.mls b/shared/src/test/diff/ucs/SplitOps.mls index 7db2e834ca..37943bd5ae 100644 --- a/shared/src/test/diff/ucs/SplitOps.mls +++ b/shared/src/test/diff/ucs/SplitOps.mls @@ -44,7 +44,7 @@ fun f(x) = //│ ╙── ^^^^^^^^^^^^^^^^ //│ f: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared :e :ge @@ -64,7 +64,7 @@ fun f(x) = //│ ╙── ^^^^^^ //│ f: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared class A() class B() @@ -102,7 +102,7 @@ fun f(a, b, c) = //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ f: (anything, anything, anything,) -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared fun f(x) = if x diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index 46e7bd48df..708280aa36 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -40,7 +40,7 @@ if true //│ ╙── ^^^^ //│ res: error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared // This cannot be parsed. But the next one works. :pe @@ -70,7 +70,7 @@ fun f(x) = //│ ╙── ^^^^ //│ f: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared // But this works. fun f(x) = @@ -95,4 +95,4 @@ fun boolToStr(x) = //│ ╙── ^^^^^^^^^ //│ boolToStr: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared From 707d268709e00356a6a6c8af39ee4c5470ceb7d2 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 7 Mar 2023 15:18:17 +0800 Subject: [PATCH 135/498] WIP Support type aliases and `with` construct --- .../src/main/scala/mlscript/JSBackend.scala | 19 +++--- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 27 +++++++-- .../src/main/scala/mlscript/NuTypeDefs.scala | 53 ++++++++++------- .../main/scala/mlscript/TypeSimplifier.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 10 +++- .../main/scala/mlscript/TyperDatatypes.scala | 40 +++++++++++-- .../main/scala/mlscript/TyperHelpers.scala | 8 ++- .../main/scala/mlscript/codegen/Helpers.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 58 ++++++++++--------- shared/src/main/scala/mlscript/syntax.scala | 1 + shared/src/test/diff/codegen/Mixin.mls | 22 +++---- .../test/diff/nu/BasicClassInheritance.mls | 12 ++-- shared/src/test/diff/nu/BasicMixins.mls | 43 +++++++++----- shared/src/test/diff/nu/ClassSignatures.mls | 23 ++++++++ shared/src/test/diff/nu/ClassesInMixins.mls | 2 +- shared/src/test/diff/nu/ECOOP23.mls | 8 +-- shared/src/test/diff/nu/ECOOP23_codegen.mls | 2 +- shared/src/test/diff/nu/ECOOP23_intro.mls | 53 +++++++++-------- shared/src/test/diff/nu/ECOOP23_repro.mls | 6 +- shared/src/test/diff/nu/GenericClasses.mls | 17 +++--- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 2 +- .../test/diff/nu/NewPolyVariantCodeReuse2.mls | 8 +-- shared/src/test/diff/nu/NuTypeAliases.mls | 10 ---- shared/src/test/diff/nu/ParamOverriding.mls | 2 +- shared/src/test/diff/nu/Super.mls | 20 +++---- shared/src/test/diff/nu/TypeAliases.mls | 53 +++++++++-------- shared/src/test/diff/nu/With.mls | 29 ++++++++++ shared/src/test/diff/parser/Classes.mls | 39 +++++++++---- .../src/test/scala/mlscript/DiffTests.scala | 12 ++-- 30 files changed, 374 insertions(+), 210 deletions(-) create mode 100644 shared/src/test/diff/nu/ClassSignatures.mls delete mode 100644 shared/src/test/diff/nu/NuTypeAliases.mls create mode 100644 shared/src/test/diff/nu/With.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index a87ad1a3a4..008e09ee75 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -712,29 +712,28 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } typeDefs.foreach { - case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members) = prepare(mxName, fs, pars, unit) val sym = topLevelScope.declareMixin(mxName, tps map { _._2.name }, body, members) mixins += sym superParameters.put(sym.runtimeName, pars) } - case NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + case NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members) modules += sym superParameters.put(sym.runtimeName, pars) } - case NuTypeDef(Als, TypeName(nme), tps, _, pars, _, _, _) => { - val body = tt(pars.head) - topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, body) + case NuTypeDef(Als, TypeName(nme), tps, _, sig, pars, _, _, _) => { + topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(die)) } - case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareNewClass(nme, tps map { _._2.name }, body, members) classes += sym superParameters.put(sym.runtimeName, pars) } - case NuTypeDef(k @ Trt, TypeName(nme), tps, tup @ Tup(fs), pars, sup, ths, unit) => { + case NuTypeDef(k @ Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareTrait(nme, tps map { _._2.name }, body, members) traits += sym @@ -954,13 +953,13 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { try generate(pgrm)(topLevelScope, allowEscape) catch { case e: CodeGenError => JSTestBackend.IllFormedCode(e.getMessage()) case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage()) - case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) + // case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) } else try generateNewDef(pgrm)(topLevelScope, allowEscape) catch { case e: CodeGenError => JSTestBackend.IllFormedCode(e.getMessage()) case e: UnimplementedError => JSTestBackend.Unimplemented(e.getMessage()) - case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) + // case e: Throwable => JSTestBackend.UnexpectedCrash(e.getClass().getName, e.getMessage()) } // generate(pgrm)(topLevelScope, allowEscape) @@ -1233,7 +1232,7 @@ object JSTestBackend { /** * Code generation crashed. */ - final case class UnexpectedCrash(val name: Str, override val content: Str) extends ErrorMessage(content) + // final case class UnexpectedCrash(val name: Str, override val content: Str) extends ErrorMessage(content) /** * The result is not executed for some reasons. E.g. `:NoJS` flag. diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index a32784268f..be96e4f926 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -44,6 +44,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { ) private val isAlphaOp = Set( + "with", "and", "or", "is", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index f94dbc2de2..a26faa5bdf 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -304,17 +304,26 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D expr(0) :: otherParents case _ => Nil } - val ps = yeetSpaces match { + val sig = yeetSpaces match { case (KEYWORD("="), _) :: _ if kind is Als => consume - expr(0) :: otherParents - case (KEYWORD(":" | "extends"), _) :: _ => + S(typ(0)) + case (KEYWORD(":"), _) :: _ => + consume + S(typ(0)) + case _ => N + } + val ps = yeetSpaces match { + // case (KEYWORD("="), _) :: _ if kind is Als => + // consume + // expr(0) :: otherParents + case (KEYWORD("extends"), _) :: _ => consume expr(0) :: otherParents case _ => Nil } val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams.map(N -> _), params, ps, N, N, body) + val res = NuTypeDef(kind, tn, tparams.map(N -> _), params, sig, ps, N, N, body) R(res.withLoc(S(l0 ++ res.getLoc))) // TODO make `fun` by-name and `let` by-value @@ -625,6 +634,16 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D L(IfOpApp(acc, v, rhs)) case R(rhs) => exprCont(opStr match { + case "with" => + rhs match { + case rhs: Rcd => + With(acc, rhs)//.withLocOf(term) + case Bra(true, rhs: Rcd) => + With(acc, rhs)//.withLocOf(term) + case _ => + err(msg"record literal expected here; found ${rhs.describe}" -> rhs.toLoc :: Nil) + acc + } case "=>" => Lam(toParams(acc), rhs) case _ => diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 46c5b99af3..18e7dd01ab 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -65,6 +65,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // sealed abstract class TypedNuDecl extends NuMember { sealed trait TypedNuDecl extends NuMember { def name: Str + def level: Level // def freshen(implicit ctx: Ctx): TypedNuDecl = this match { // case m @ TypedNuMxn(td, thisTV, superTV, ttu) => // implicit val freshened: MutMap[TV, ST] = MutMap.empty @@ -72,13 +73,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify = false)) // case _ => ??? // } - } - - sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { - // override def toString: String = this match { - // case _ => ??? - // } - def level: Level def freshen(implicit ctx: Ctx): TypedNuDecl = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty @@ -87,12 +81,21 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => freshenAbove(level, rigidify = false).asInstanceOf[TypedNuDecl] } } - def map(f: ST => ST)(implicit ctx: Ctx): TypedNuTermDef = - mapPol(N, false)((_, ty) => f(ty)).asInstanceOf[TypedNuTermDef]//TODO + def map(f: ST => ST)(implicit ctx: Ctx): TypedNuDecl = + mapPol(N, false)((_, ty) => f(ty)) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef + (implicit ctx: Ctx): TypedNuDecl def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef + (implicit ctx: Ctx): TypedNuDecl + def force()(implicit raise: Raise): Unit = this match { + case x: TypedNuMxn => x.ttu.force() + case x: TypedNuCls => x.ttu.force() + case _: TypedNuFun => () + case _: TypedNuAls => () + } + } + + sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { // def childrenTypes: Ls[ST] /* def freshenAbove(lim: Int, rigidify: Bool) @@ -127,11 +130,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } */ - def force()(implicit raise: Raise): Unit = this match { - case x: TypedNuMxn => x.ttu.force() - case x: TypedNuCls => x.ttu.force() - case _: TypedNuFun => () - } } sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuTypeDefBase with TypedNuDecl { @@ -179,17 +177,30 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // ) // case class TypedNuAls(level: Level, nme: TypeName)(val prov: TP) extends TypedNuTypeDef(Als) { - case class TypedNuAls(level: Level, td: NuTypeDef) extends TypedNuTypeDef(Als) { + case class TypedNuAls(level: Level, td: NuTypeDef, + tparams: Ls[(TN, TV, Opt[VarianceInfo])], + body: ST, + ) extends TypedNuTypeDef(Als) { def name: Str = nme.name - def nme: mlscript.TypeName = ??? + def nme: mlscript.TypeName = td.nme // def freshenAbove(lim: Int, rigidify: Bool) // (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) // : TypedNuTypeDef = ??? def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): NuMember = ??? + (implicit ctx: Ctx): TypedNuDecl = + TypedNuAls( + level, td, + tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), + f(pol, body) + ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): NuMember = ??? + (implicit ctx: Ctx): TypedNuDecl = + TypedNuAls( + level, td, + tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), + f(pol, body) + ) } // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { @@ -302,7 +313,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuFun(level, fd, f(pol, ty)) } - case class CompletedTypingUnit(entities: Ls[TypedNuTermDef], result: Opt[ST]) extends OtherTypeLike { + case class CompletedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) extends OtherTypeLike { def map(f: ST => ST)(implicit ctx: Ctx): CompletedTypingUnit = CompletedTypingUnit(entities.map(_.map(f)), result.map(f)) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 248926a763..cfa4cd2dc3 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -962,7 +962,7 @@ trait TypeSimplifier { self: Typer => trace(s"Setting bounds of $res...") { tv.assignedTo match { case S(ty) => - res.assignedTo = S(transform(ty, PolMap.neu, semp, canDistribForall)) + res.assignedTo = S(transform(ty, pol.invar, semp, canDistribForall)) case N => res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 396028e9cd..3140dbb4ae 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -336,9 +336,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case ti: LazyTypeInfo => // ti.complete() ti.decl match { - case NuTypeDef(k @ (Cls | Nms), _, tps, _, _, _, _, _) => + case NuTypeDef(k @ (Cls | Nms | Als), _, tps, _, _, _, _, _, _) => + S(k, tps.size) + case NuTypeDef(k @ Mxn, _, tps, _, _, _, _, _, _) => + err(msg"mixins cannot be used as types", loc) S(k, tps.size) - case _ => ??? } case _ => N }) @@ -1266,9 +1268,12 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) }) } def goDecl(d: TypedNuDecl): NuDecl = d match { + case TypedNuAls(level, td, tparams, body) => + NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil)) case TypedNuMxn(td, thisTy, superTy, members, ttu) => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), + N, Nil,//TODO // S(go(superTy)), // S(go(thisTy)), @@ -1283,6 +1288,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) NuTypeDef(td.kind, td.nme, td.tparams, // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + N,//TODO Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index d39894ec18..267254f206 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -48,7 +48,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val tparams: Ls[(TN, TV)] = Nil // TODO // val tparams: Ls[(TN, TV, VarianceInfo)] = Nil // TODO var isComputing: Bool = false // TODO replace by a Ctx entry - var result: Opt[TypedNuTermDef] = N + var result: Opt[TypedNuDecl] = N // var result: Opt[A] = N val tv: TV = freshVar( @@ -56,7 +56,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => N, S(decl.name))(level + 1) - def map(f: TypedNuTermDef => TypedNuTermDef): LazyTypeInfo = { + def map(f: TypedNuDecl => TypedNuDecl): LazyTypeInfo = { val res = new LazyTypeInfo(level, decl) // if (result.nonEmpty) res.result = res res.result = result.map(f) @@ -68,7 +68,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // freshVar(noProv/*FIXME*/, N, S("this_"+decl.name))(lvl + 1) freshVar(noProv/*FIXME*/, N, S(decl.name.decapitalize))(lvl + 1) - def complete()(implicit raise: Raise): TypedNuTermDef = result.getOrElse { + def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { if (isComputing) { // lastWords(s"TODO cyclic defition ${decl.name}") err(msg"Unhandled cyclic definition", decl.toLoc) // TODO better loc/explanation @@ -156,6 +156,26 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => td.kind match { + case Als => + + // TODO assert td.params, td.parents are empty + + val tparams = td.tparams.map(tp => + (tp._2, freshVar(TypeProvenance( + tp._2.toLoc, + "type parameter", + S(tp._2.name), + true), N, S(tp._2.name)), tp._1)) + + implicit val vars: Map[Str, SimpleType] = + outerVars ++ tparams.iterator.map { + case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) + } + + val body_ty = typeType(td.sig.getOrElse(die)) + + TypedNuAls(outerCtx.lvl, td, tparams, body_ty) + case Cls | Nms => implicit val prov: TP = noProv // TODO @@ -204,6 +224,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) ctx += "this" -> VarSymbol(thisTV, Var("this")) + val sig_ty = typeType(td.sig.getOrElse(Top)) + td.sig match { + case S(sig) => + err(msg"type signatures not yet supported for classes", sig.toLoc) + case N => () + } + // // TODO check against `tv` // println(td.tparams) // println(td.params) @@ -412,7 +439,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ??? ty } - def force()(implicit raise: Raise): TypedNuTermDef = { + def force()(implicit raise: Raise): TypedNuDecl = { val res = complete() res.force() // decl match { @@ -817,6 +844,11 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => ctx.tyDefs2.get(defn.name).map { info => implicit val raise: Raise = throw _ // FIXME info.complete() match { + case td: TypedNuAls => + assert(td.tparams.size === targs.size) + substSyntax(td.body)(td.tparams.lazyZip(targs).map { + case (tp, ta) => SkolemTag(tp._2.level, tp._2)(noProv) -> ta + }.toMap) case td: TypedNuCls => assert(td.tparams.size === targs.size) ClassTag(Var(td.nme.name).withLocOf(td.nme), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 3c8d85227e..6011a89d18 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -772,6 +772,9 @@ abstract class TyperHelpers { Typer: Typer => case OtherTypeLike(tu) => // tu.entities.flatMap(_.childrenPol) ::: tu.result.toList val ents = tu.entities.flatMap { + case ta: TypedNuAls => + // Q: PolMap.neu or pol.invar?! + ta.tparams.map(pol.invar -> _._2) ::: pol -> ta.body :: Nil case tf: TypedNuFun => PolMap.pos -> tf.ty :: Nil case mxn: TypedNuMxn => @@ -779,7 +782,7 @@ abstract class TyperHelpers { Typer: Typer => S(pol.contravar -> mxn.superTV) ++ S(pol.contravar -> mxn.thisTV) case cls: TypedNuCls => - cls.tparams.iterator.map(PolMap.neu -> _._2) ++ + cls.tparams.iterator.map(pol.invar -> _._2) ++ // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ @@ -956,6 +959,9 @@ abstract class TyperHelpers { Typer: Typer => tu.result.foreach(apply(pol)) } def applyMem(pol: PolMap)(m: NuMember): Unit = m match { + case TypedNuAls(level, td, tparams, body) => + tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) + apply(pol)(body) case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 5248eacfa6..a8634332d3 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -85,7 +85,7 @@ object Helpers { s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, ${inspect(term)})" case NuFunDef(lt, nme, targs, R(ty)) => s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, $ty)" - case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, sig, parents, sup, ths, body) => s"NuTypeDef(${kind.str}, ${nme.name}, ${tparams.mkString("(", ", ", ")")}, ${ inspect(params)}, ${parents.map(inspect).mkString("(", ", ", ")")}, $sup, $ths, ${inspect(body)})" case others => others.toString() diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 1d19a34942..43c2ad3e53 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -133,7 +133,10 @@ trait TypeLikeImpl extends Located { self: TypeLike => // })).mkString("\n") // })).mkString("", "\n", "\n") })).mkString - case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => + case NuTypeDef(kind @ Als, nme, tparams, params, sig, parents, sup, ths, body) => + s"type ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")} = ${ + sig.getOrElse(die).showIn(ctx, 0)}" + case NuTypeDef(kind, nme, tparams, params, sig, parents, sup, ths, body) => val bodyCtx = ctx.indent s"${kind.str} ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}(${ params.fields.map { @@ -170,7 +173,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList - case NuTypeDef(kind, nme, tparams, params, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, sig, parents, sup, ths, body) => // TODO improve this mess tparams.map(_._2) ::: params.fields.collect { case (_, Fld(_, _, Asc(_, ty))) => ty @@ -367,35 +370,36 @@ trait PgrmImpl { self: Pgrm => override def toString = tops.map("" + _ + ";").mkString(" ") private def tryDesugaredNewDec(nd: NuTypeDef): Ls[Diagnostic] = nd match { - case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), pars, sup, ths, unit) => + case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => val bases = pars.foldLeft(Var("base"): Term)((res, p) => p match { case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) case _ => ??? }) - tryDesugaredNewDec(NuTypeDef(Cls, TypeName(mxName), tps, tup, Ls(bases), sup, ths, unit)) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + tryDesugaredNewDec(NuTypeDef(Cls, TypeName(mxName), tps, tup, sig, Ls(bases), sup, ths, unit)) + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => if (pars.length > 0) { val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) case _ => ??? }) - tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, Ls(bases), sup, ths, unit)) + tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, sig, Ls(bases), sup, ths, unit)) } else { - tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, Ls(), sup, ths, unit)) + tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, sig, Ls(), sup, ths, unit)) } - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) - require(pars.size === 1, pars) + require(sig.isDefined) + require(pars.size === 0, pars) require(ths.isEmpty, ths) require(unit.entities.isEmpty, unit) - val (diags, rhs) = pars.head.toType match { - case L(ds) => (ds :: Nil) -> Top - case R(ty) => Nil -> ty - } - diags - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + // val (diags, rhs) = sig.get match { + // case L(ds) => (ds :: Nil) -> Top + // case R(ty) => Nil -> ty + // } + Nil + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { case L(ds) => diags += ds; Top @@ -473,16 +477,17 @@ trait NuDeclImpl extends Located { self: NuDecl => def showDbg: Str = showHead + (this match { case NuFunDef(_, _, _, L(_)) => " = " case NuFunDef(_, _, _, R(_)) => ": " - case NuTypeDef(_, _, _, _, _, _, _, _) => " " + case _: NuTypeDef => " " }) + showBody def showHead: Str = this match { case NuFunDef(N, n, _, b) => s"fun $n" case NuFunDef(S(false), n, _, b) => s"let $n" case NuFunDef(S(true), n, _, b) => s"let rec $n" - case NuTypeDef(k, n, tps, sps, parents, sup, ths, bod) => + case NuTypeDef(k, n, tps, sps, sig, parents, sup, ths, bod) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}(${ // sps.mkString("(",",",")") - sps})${if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" + sps})${sig.fold("")(": " + _.show)}${ + if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" } } trait TypingUnitImpl extends Located { self: TypingUnit => @@ -781,20 +786,17 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => ??? // TODO - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) - require(pars.size === 1, pars) + require(pars.size === 0, pars) + require(sig.isDefined) require(ths.isEmpty, ths) require(unit.entities.isEmpty, unit) - val (diags, rhs) = pars.head.toType match { - case L(ds) => (ds :: Nil) -> Top - case R(ty) => Nil -> ty - } - diags -> (TypeDef(k, nme, tps.map(_._2), rhs, Nil, Nil, Nil) :: Nil) - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), pars, sup, ths, unit) => + Nil -> (TypeDef(k, nme, tps.map(_._2), sig.get, Nil, Nil, Nil) :: Nil) + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { case L(ds) => diags += ds; Top @@ -927,7 +929,7 @@ trait StatementImpl extends Located { self: Statement => case Where(bod, wh) => bod :: wh case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil - case NuTypeDef(k, nme, tps, ps, pars, sup, ths, bod) => + case NuTypeDef(k, nme, tps, ps, sig, pars, sup, ths, bod) => nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index a4ea490580..5813a3c530 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -177,6 +177,7 @@ final case class NuTypeDef( nme: TypeName, tparams: Ls[(Opt[VarianceInfo], TypeName)], params: Tup, // the specialized parameters for that type + sig: Opt[Type], parents: Ls[Term], superAnnot: Opt[Type], thisAnnot: Opt[Type], diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 299271641a..5070daa4ad 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -380,7 +380,7 @@ mixin EvalNegNeg { :js :ShowRepl -module TestLang: EvalBase, EvalNeg, EvalNegNeg +module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { //│ fun eval: 'a -> int //│ } @@ -477,10 +477,10 @@ class Foo(x: int) :e -class Bar(x: int, y: int): Foo(x + y) +class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.480: class Bar(x: int, y: int): Foo(x + y) -//│ ╙── ^^^^^^^^^^ +//│ ║ l.480: class Bar(x: int, y: int) extends Foo(x + y) +//│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -492,20 +492,20 @@ mixin BB {} //│ mixin BB() -class C(x: int): BB +class C(x: int) extends BB //│ class C(x: int) :e -class D(x: int): AA(x) +class D(x: int) extends AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.499: class D(x: int): AA(x) -//│ ╙── ^^^^^ +//│ ║ l.499: class D(x: int) extends AA(x) +//│ ╙── ^^^^^ //│ class D(x: int) :e -class E(x: int): BB, AA(x) +class E(x: int) extends BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.506: class E(x: int): BB, AA(x) -//│ ╙── ^^^^^ +//│ ║ l.506: class E(x: int) extends BB, AA(x) +//│ ╙── ^^^^^ //│ class E(x: int) diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 2cb76e135c..77d9189c48 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -7,10 +7,10 @@ class A //│ class A() // TODO -class B(m: int): A +class B(m: int) extends A //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.10: class B(m: int): A -//│ ╙── ^ +//│ ║ l.10: class B(m: int) extends A +//│ ╙── ^ //│ class B(m: int) @@ -18,10 +18,10 @@ class A(n: int) //│ class A(n: int) // TODO -class B(m: int): A(n + 1) +class B(m: int) extends A(n + 1) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.21: class B(m: int): A(n + 1) -//│ ╙── ^^^^^^^^ +//│ ║ l.21: class B(m: int) extends A(n + 1) +//│ ╙── ^^^^^^^^ //│ class B(m: int) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 3d41937b1f..9980788a61 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -24,7 +24,7 @@ mixin BaseInc { //│ } // :d -class Base1(base: int): BaseTest, BaseInc { +class Base1(base: int) extends BaseTest, BaseInc { fun test3 = [base, this.base] } //│ class Base1(base: int) { @@ -44,9 +44,9 @@ Base1(1).test3 // TODO -class Base1(base): BaseTest +class Base1(base) extends BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.47: class Base1(base): BaseTest +//│ ║ l.47: class Base1(base) extends BaseTest //│ ╙── ^^^^ //│ class Base1(base: error) { //│ fun test: error @@ -61,15 +61,15 @@ Base1(1).test :e -class Base1(x): BaseTest +class Base1(x) extends BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.64: class Base1(x): BaseTest +//│ ║ l.64: class Base1(x) extends BaseTest //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.64: class Base1(x): BaseTest -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.64: class Base1(x) extends BaseTest +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: error}` does not have field 'base' -//│ ║ l.64: class Base1(x): BaseTest +//│ ║ l.64: class Base1(x) extends BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.8: fun test = super.base @@ -81,6 +81,19 @@ class Base1(x): BaseTest //│ fun test: nothing //│ } +:e +class Base1(x): BaseTest +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.85: class Base1(x): BaseTest +//│ ╙── ^ +//│ ╔══[ERROR] mixins cannot be used as types +//│ ║ l.85: class Base1(x): BaseTest +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] type signatures not yet supported for classes +//│ ║ l.85: class Base1(x): BaseTest +//│ ╙── ^^^^^^^^ +//│ class Base1(x: error) + Base1 //│ (x: error,) -> Base1 @@ -94,7 +107,7 @@ mixin Foo { //│ fun test: (int & 'a) -> (int, 'a, 'misc,) //│ } -module Base1(base: int, misc: string): Foo +module Base1(base: int, misc: string) extends Foo //│ module Base1(base: int, misc: string) { //│ fun test: (int & 'a) -> (int, 'a, string,) //│ } @@ -128,7 +141,7 @@ mixin Wrap { // :d -module WrapBase1: WrapBase, Wrap +module WrapBase1 extends WrapBase, Wrap //│ module WrapBase1() { //│ fun wrap: 'a -> ('a,) //│ fun wrapA: int -> (int,) @@ -162,22 +175,22 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.163: WrapBase1.wrapA("ok") +//│ ║ l.176: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.163: WrapBase1.wrapA("ok") +//│ ║ l.176: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.109: fun wrapA(x: int) = x : int +//│ ║ l.122: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.119: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.132: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error -module WrapBase2: WrapBase, Wrap, Wrap, Wrap +module WrapBase2 extends WrapBase, Wrap, Wrap, Wrap //│ module WrapBase2() { //│ fun wrap: 'a -> ((('a,),),) //│ fun wrapA: int -> (((int,),),) diff --git a/shared/src/test/diff/nu/ClassSignatures.mls b/shared/src/test/diff/nu/ClassSignatures.mls new file mode 100644 index 0000000000..7d7c97e1ac --- /dev/null +++ b/shared/src/test/diff/nu/ClassSignatures.mls @@ -0,0 +1,23 @@ +:NewParser +:NewDefs + + +// TODO +class Foo(): {} +//│ ╔══[ERROR] type signatures not yet supported for classes +//│ ║ l.6: class Foo(): {} +//│ ╙── ^^ +//│ class Foo() + +// TODO +class Foo(): {} { + fun x = 0 +} +//│ ╔══[ERROR] type signatures not yet supported for classes +//│ ║ l.13: class Foo(): {} { +//│ ╙── ^^ +//│ class Foo() { +//│ fun x: 0 +//│ } + + diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 69646e179b..0c10478ffe 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -13,7 +13,7 @@ mixin Test { //│ let f: Foo //│ } -module M: Test +module M extends Test //│ module M() { //│ class Foo(n: int) //│ let f: Foo diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index 1fa7d80c63..da6c6ed339 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -37,7 +37,7 @@ mixin EvalBase { //│ } -module TestLang: EvalBase +module TestLang extends EvalBase //│ module TestLang() { //│ fun eval: 'a -> int //│ } @@ -63,7 +63,7 @@ mixin EvalAddLit { Add(l, r) then this.eval(l) + this.eval(r) else super.eval(e) } -module TestLang: EvalNothing, EvalAddLit +module TestLang extends EvalNothing, EvalAddLit //│ mixin EvalNothing() { //│ fun eval: nothing -> nothing //│ } @@ -106,7 +106,7 @@ mixin EvalNeg { //│ } -module TestLang: EvalBase, EvalNeg +module TestLang extends EvalBase, EvalNeg //│ module TestLang() { //│ fun eval: 'a -> int //│ } @@ -167,7 +167,7 @@ mixin EvalNegNeg { //│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b //│ } -module TestLang: EvalBase, EvalNeg, EvalNegNeg +module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { //│ fun eval: 'a -> int //│ } diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 0bb0d21638..385dabf866 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -47,7 +47,7 @@ mixin EvalNegNeg { //│ } -module TestLang: EvalBase, EvalNeg, EvalNegNeg +module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { //│ fun eval: 'a -> int //│ } diff --git a/shared/src/test/diff/nu/ECOOP23_intro.mls b/shared/src/test/diff/nu/ECOOP23_intro.mls index d03e337885..ccef8e314a 100644 --- a/shared/src/test/diff/nu/ECOOP23_intro.mls +++ b/shared/src/test/diff/nu/ECOOP23_intro.mls @@ -19,25 +19,26 @@ mixin ComparePoint { //│ } -eq(1)(2) -//│ bool -//│ res -//│ = false - +class Color(str: string) { + fun equals(that) = eq(this.str)(that.str) +} +//│ class Color(str: string) { +//│ fun equals: {str: anything} -> bool +//│ } -let Red = "red" -//│ let Red: "red" +let Red = Color("red") +//│ let Red: Color //│ Red -//│ = 'red' +//│ = Color { str: 'red' } mixin CompareColored { fun compare(lhs, rhs) = - super.compare(lhs, rhs) && eq(lhs.color)(rhs.color) + super.compare(lhs, rhs) && lhs.color.equals(rhs.color) } //│ mixin CompareColored() { //│ super: {compare: ('a, 'b,) -> bool} -//│ fun compare: ({color: anything} & 'a, {color: anything} & 'b,) -> bool +//│ fun compare: ({color: {equals: 'color -> bool}} & 'a, {color: 'color} & 'b,) -> bool //│ } @@ -84,8 +85,8 @@ mixin CompareNested { -class MyPoint(x: int, y: int, color: string, parent: Some[MyPoint] | None) -//│ class MyPoint(x: int, y: int, color: string, parent: None | Some[MyPoint]) +class MyPoint(x: int, y: int, color: Color, parent: Some[MyPoint] | None) +//│ class MyPoint(x: int, y: int, color: Color, parent: None | Some[MyPoint]) module CompareMyPoint extends ComparePoint, CompareColored, CompareNested @@ -93,8 +94,8 @@ module CompareMyPoint extends ComparePoint, CompareColored, CompareNested //│ fun compare: ('a, 'b,) -> bool //│ } //│ where -//│ 'b <: {color: anything, parent: Some['b] | ~Some[anything], x: number, y: number} -//│ 'a <: {color: anything, parent: Some['a] | ~Some[anything], x: number, y: number} +//│ 'b <: {color: 'color, parent: Some['b] | ~Some[anything], x: number, y: number} +//│ 'a <: {color: {equals: 'color -> bool}, parent: Some['a] | ~Some[anything], x: number, y: number} let p0 = MyPoint(0, 0, Red, None) @@ -113,43 +114,49 @@ let p5 = MyPoint(0, 1, Red, Some(p3)) //│ = MyPoint { //│ x: 0, //│ y: 0, -//│ color: 'red', +//│ color: Color { str: 'red' }, //│ parent: None { class: [class None] } //│ } //│ p1 //│ = MyPoint { //│ x: 0, //│ y: 1, -//│ color: 'red', +//│ color: Color { str: 'red' }, //│ parent: None { class: [class None] } //│ } //│ p2 //│ = MyPoint { //│ x: 0, //│ y: 1, -//│ color: 'red', +//│ color: Color { str: 'red' }, //│ parent: None { class: [class None] } //│ } //│ p3 //│ = MyPoint { //│ x: 0, //│ y: 1, -//│ color: 'red', -//│ parent: Some { value: MyPoint { x: 0, y: 1, color: 'red', parent: [None] } } +//│ color: Color { str: 'red' }, +//│ parent: Some { +//│ value: MyPoint { x: 0, y: 1, color: [Color], parent: [None] } +//│ } //│ } //│ p4 //│ = MyPoint { //│ x: 0, //│ y: 1, -//│ color: 'red', -//│ parent: Some { value: MyPoint { x: 0, y: 1, color: 'red', parent: [None] } } +//│ color: Color { str: 'red' }, +//│ parent: Some { +//│ value: MyPoint { x: 0, y: 1, color: [Color], parent: [None] } +//│ } //│ } //│ p5 //│ = MyPoint { //│ x: 0, //│ y: 1, -//│ color: 'red', -//│ parent: Some { value: MyPoint { x: 0, y: 1, color: 'red', parent: [Some] } } +//│ color: Color { str: 'red' }, +//│ parent: Some { +//│ value: MyPoint { x: 0, y: 1, color: [Color], parent: [Some] } +//│ } //│ } diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index 68626f554d..cf87ecf48e 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -49,7 +49,7 @@ mixin EvalAdd { // FIXME type vars are wrongly refreshed when tying the knot -module TestLang: EvalAdd +module TestLang extends EvalAdd //│ module TestLang() { //│ fun eval: 'a -> nothing //│ } @@ -75,7 +75,7 @@ mixin EvalBase { //│ } -module TestLang: EvalBase +module TestLang extends EvalBase //│ module TestLang() { //│ fun eval: 'a -> int //│ } @@ -125,7 +125,7 @@ mixin EvalNeg { //│ } -module TestLang: EvalBase, EvalNeg +module TestLang extends EvalBase, EvalNeg //│ module TestLang() { //│ fun eval: 'a -> int //│ } diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 3706e2e6a9..5951a48f45 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -81,9 +81,8 @@ None.toArray //│ () -// TODO type Option = Some | None -//│ /!!!\ Uncaught error: scala.MatchError: Als (of class mlscript.Als$) +//│ type Option[A] = None | Some[A] @@ -128,7 +127,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.126: class Test(n) { +//│ ║ l.125: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -148,13 +147,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.148: fun foo = n + 1 +//│ ║ l.147: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.148: fun foo = n + 1 +//│ ║ l.147: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.147: class Test(n: A) { +//│ ║ l.146: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int @@ -211,13 +210,13 @@ class TestBad { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.211: fun foo2(x: A) = x + 1 +//│ ║ l.210: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.211: fun foo2(x: A) = x + 1 +//│ ║ l.210: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.209: class TestBad { +//│ ║ l.208: class TestBad { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 3edec51a6f..32eced5c84 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -97,7 +97,7 @@ mixin EvalLambda { //│ 'A2 :> (string, Var,) | 'A0 //│ <: 'A1 -module Test1: EvalVar, EvalLambda +module Test1 extends EvalVar, EvalLambda //│ module Test1() { //│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> 'result //│ } diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls index 80615b0761..4387604528 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls @@ -103,7 +103,7 @@ mixin EvalLambda { //│ 'a1 :> 'a | (string, Var,) //│ <: 'a0 -module Test1: EvalVar, EvalLambda +module Test1 extends EvalVar, EvalLambda //│ module Test1() { //│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> 'result //│ } @@ -162,7 +162,7 @@ mixin EvalExpr { //│ fun eval: ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) //│ } -module Test2: EvalVar, EvalExpr +module Test2 extends EvalVar, EvalExpr //│ module Test2() { //│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> ('b | Num | Var | 'a) //│ } @@ -182,7 +182,7 @@ Test2.eval(Cons(("a", Num(1)), Nil()), Var("a")) Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) //│ Abs[Var] | Add[Num | Var] | Num | Var -module Test3: EvalVar, EvalExpr, EvalLambda +module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { //│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> anything //│ } @@ -202,7 +202,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(N //│ where //│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var -module Test3: EvalVar, EvalLambda, EvalExpr +module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { //│ fun eval: (List[{_1: string, _2: 'result}], nothing,) -> anything //│ } diff --git a/shared/src/test/diff/nu/NuTypeAliases.mls b/shared/src/test/diff/nu/NuTypeAliases.mls deleted file mode 100644 index bd3d07934f..0000000000 --- a/shared/src/test/diff/nu/NuTypeAliases.mls +++ /dev/null @@ -1,10 +0,0 @@ -:NewParser -:NewDefs -:NoJS - - -// TODO -type A = int -//│ /!!!\ Uncaught error: scala.MatchError: Als (of class mlscript.Als$) - - diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 65545672a4..4cd0931305 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -11,7 +11,7 @@ mixin Over { //│ } -class Base1(p: int): Over { +class Base1(p: int) extends Over { fun test = [p, this.p] // fun test2 = super.p // TODO } diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/Super.mls index 21bd669f57..36a40d07c9 100644 --- a/shared/src/test/diff/nu/Super.mls +++ b/shared/src/test/diff/nu/Super.mls @@ -7,10 +7,10 @@ class Foo(x: int) :e -class Bar(x: int, y: int): Foo(x + y) +class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.10: class Bar(x: int, y: int): Foo(x + y) -//│ ╙── ^^^^^^^^^^ +//│ ║ l.10: class Bar(x: int, y: int) extends Foo(x + y) +//│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -22,20 +22,20 @@ mixin BB {} //│ mixin BB() -class C(x: int): BB +class C(x: int) extends BB //│ class C(x: int) :e -class D(x: int): AA(x) +class D(x: int) extends AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.29: class D(x: int): AA(x) -//│ ╙── ^^^^^ +//│ ║ l.29: class D(x: int) extends AA(x) +//│ ╙── ^^^^^ //│ class D(x: int) :e -class E(x: int): BB, AA(x) +class E(x: int) extends BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.37: class E(x: int): BB, AA(x) -//│ ╙── ^^^^^ +//│ ║ l.37: class E(x: int) extends BB, AA(x) +//│ ╙── ^^^^^ //│ class E(x: int) diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index fc560405b1..dfe8adae6f 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -1,59 +1,66 @@ :NewParser +:NewDefs + type I = int -//│ Defined type alias I +//│ type I = int class CI1 -//│ Defined class CI1 -//│ CI1: () -> CI1 -//│ = [Function: CI11] +//│ class CI1() // :e type AI1 = Array[int] -//│ Defined type alias AI1 +//│ type AI1 = Array[int] type AI2 = Array -//│ Defined type alias AI2 +//│ type AI2 = Array[int] // TODO fail gracefully // :e type AI3(n) = Array[int] +//│ type AI3 = Array[int] //│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: List((None,Fld(false,false,n))) // TODO fail gracefully // :e type AI3[A] = Array -//│ Defined type alias AI3[+A] +//│ type AI3[A] = Array[A] type AI4 = Array -//│ Defined type alias AI4[+A] +//│ type AI4[A] = Array[A] let r = 123 -//│ r: 123 -//│ = 123 +//│ let r: 123 +//│ r +//│ = 123 r: I -//│ res: I -//│ = 123 +//│ I +//│ res +//│ = 123 let a = [r, r, r] -//│ a: (123, 123, 123,) -//│ = [ 123, 123, 123 ] +//│ let a: (123, 123, 123,) +//│ a +//│ = [ 123, 123, 123 ] a : AI1 -//│ res: AI1 -//│ = [ 123, 123, 123 ] +//│ AI1 +//│ res +//│ = [ 123, 123, 123 ] a : AI2 -//│ res: AI2 -//│ = [ 123, 123, 123 ] +//│ AI2 +//│ res +//│ = [ 123, 123, 123 ] -// :e a : AI3[int] -//│ res: AI3[int] -//│ = [ 123, 123, 123 ] +//│ AI3[int] +//│ res +//│ = [ 123, 123, 123 ] a : AI4 -//│ res: AI4[int] -//│ = [ 123, 123, 123 ] +//│ AI4[int] +//│ res +//│ = [ 123, 123, 123 ] diff --git a/shared/src/test/diff/nu/With.mls b/shared/src/test/diff/nu/With.mls new file mode 100644 index 0000000000..75b92ecba0 --- /dev/null +++ b/shared/src/test/diff/nu/With.mls @@ -0,0 +1,29 @@ +:NewParser +:NewDefs + + +{} with {} +//│ anything +//│ res +//│ = {} + +{x: 1} with {y: 2} +//│ {x: 1, y: 2} +//│ res +//│ = { x: 1, y: 2 } + +{x: 1} with {x: 2} +//│ {x: 2} +//│ res +//│ = { x: 2 } + + +:pe +{x: 1} with 123 +//│ ╔══[PARSE ERROR] record literal expected here; found integer literal +//│ ║ l.22: {x: 1} with 123 +//│ ╙── ^^^ +//│ {x: 1} +//│ res +//│ = { x: 1 } + diff --git a/shared/src/test/diff/parser/Classes.mls b/shared/src/test/diff/parser/Classes.mls index eb9cba0e21..62bcbbf162 100644 --- a/shared/src/test/diff/parser/Classes.mls +++ b/shared/src/test/diff/parser/Classes.mls @@ -1,4 +1,3 @@ -:AllowParseErrors class Foo @@ -27,33 +26,51 @@ class Foo: Bar //│ |#class| |Foo|#:| |Bar| //│ Parsed: {class Foo(): Bar {}} +class Foo extends Bar, Baz +//│ |#class| |Foo| |#extends| |Bar|,| |Baz| +//│ Parsed: {class Foo(): Bar, Baz {}} + +:pe class Foo: Bar, Baz //│ |#class| |Foo|#:| |Bar|,| |Baz| -//│ Parsed: {class Foo(): Bar, Baz {}} +//│ ╔══[PARSE ERROR] Expected end of input; found comma instead +//│ ║ l.34: class Foo: Bar, Baz +//│ ╙── ^ +//│ Parsed: {class Foo(): Bar {}} class Foo: Bar { fun f = 0 } //│ |#class| |Foo|#:| |Bar| |{| |#fun| |f| |#=| |0| |}| //│ Parsed: {class Foo(): Bar {fun f = 0}} +class Foo extends Bar, Baz { fun f = 0 } +//│ |#class| |Foo| |#extends| |Bar|,| |Baz| |{| |#fun| |f| |#=| |0| |}| +//│ Parsed: {class Foo(): Bar, Baz {fun f = 0}} + +:pe class Foo: Bar, Baz { fun f = 0 } //│ |#class| |Foo|#:| |Bar|,| |Baz| |{| |#fun| |f| |#=| |0| |}| -//│ Parsed: {class Foo(): Bar, Baz {fun f = 0}} +//│ ╔══[PARSE ERROR] Expected end of input; found comma instead +//│ ║ l.50: class Foo: Bar, Baz { fun f = 0 } +//│ ╙── ^ +//│ Parsed: {class Foo(): Bar {}} // * Pretty confusing... better reject this: +:pe +:w class Foo: Bar { fun f = 0 fun bar = 1 } //│ |#class| |Foo|#:| |Bar| |{| |#fun| |f| |#=| |0|→|#fun| |bar| |#=| |1|←|↵|}| //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position -//│ ║ l.44: fun bar = 1 +//│ ║ l.61: fun bar = 1 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' here -//│ ║ l.44: fun bar = 1 +//│ ║ l.61: fun bar = 1 //│ ╙── ^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.43: class Foo: Bar { fun f = 0 +//│ ║ l.60: class Foo: Bar { fun f = 0 //│ ║ ^ -//│ ║ l.44: fun bar = 1 +//│ ║ l.61: fun bar = 1 //│ ╙── ^^^^^^^^^ //│ Parsed: {class Foo(): Bar {fun f = 0 (bar,)}} @@ -107,16 +124,16 @@ class Foo(x, y, z) class Foo(x, y, z): Bar(z, x) //│ |#class| |Foo|(|x|,| |y|,| |z|)|#:| |Bar|(|z|,| |x|)| -//│ Parsed: {class Foo(x, y, z,): Bar (z, x,) {}} +//│ Parsed: {class Foo(x, y, z,): Bar[(z, x,)] {}} class Foo(x, y, z): Bar(z, x) { fun blah(x) = x + y } //│ |#class| |Foo|(|x|,| |y|,| |z|)|#:| |Bar|(|z|,| |x|)| |{|→|#fun| |blah|(|x|)| |#=| |x| |+| |y|←|↵|}| -//│ Parsed: {class Foo(x, y, z,): Bar (z, x,) {fun blah = (x,) => + (x,) (y,)}} +//│ Parsed: {class Foo(x, y, z,): Bar[(z, x,)] {fun blah = (x,) => + (x,) (y,)}} -class Foo(x, y): Bar(y, x), Baz(x + y) -//│ |#class| |Foo|(|x|,| |y|)|#:| |Bar|(|y|,| |x|)|,| |Baz|(|x| |+| |y|)| +class Foo(x, y) extends Bar(y, x), Baz(x + y) +//│ |#class| |Foo|(|x|,| |y|)| |#extends| |Bar|(|y|,| |x|)|,| |Baz|(|x| |+| |y|)| //│ Parsed: {class Foo(x, y,): Bar (y, x,), Baz (+ (x,) (y,),) {}} diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 47ba7dbdbc..09ee6cc7a5 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -522,6 +522,8 @@ class DiffTests def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind ttu.entities.map(_.complete()(raise)).foreach { + case tc: typer.TypedNuAls => + output(s"${indStr}type ${tc.name} = ${tc.body}") case tc: typer.TypedNuCls => output(s"${indStr}class ${tc.name}") output(s"${indStr} this: ${tc.thisTy} ${tc.thisTy.showBounds @@ -936,11 +938,11 @@ class DiffTests case Unimplemented(message) => output("Unable to execute the code:") output(s" ${message}") - case UnexpectedCrash(name, message) => - if (!mode.fixme) - failures += blockLineNum - output("Code generation crashed:") - output(s" $name: $message") + // case UnexpectedCrash(name, message) => + // if (!mode.fixme) + // failures += blockLineNum + // output("Code generation crashed:") + // output(s" $name: $message") case ResultNotExecuted => () } } From 9559c730d501a75dc72936b3561ee299eda067b4 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 12:38:51 +0800 Subject: [PATCH 136/498] WIP Add many tests and some missing implementations --- .../src/main/scala/mlscript/Diagnostic.scala | 4 + .../src/main/scala/mlscript/JSBackend.scala | 5 +- .../src/main/scala/mlscript/NewParser.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 14 ++- shared/src/main/scala/mlscript/helpers.scala | 11 ++- shared/src/test/diff/nu/BadAliases.mls | 97 +++++++++++++++++++ shared/src/test/diff/nu/GADTMono.mls | 19 ++++ shared/src/test/diff/nu/GenericClasses.mls | 4 +- shared/src/test/diff/nu/GenericModules.mls | 67 +++++++++++-- shared/src/test/diff/nu/ParamOverride.mls | 84 ++++++++++++++++ shared/src/test/diff/nu/TypeAliases.mls | 4 +- 11 files changed, 292 insertions(+), 21 deletions(-) create mode 100644 shared/src/test/diff/nu/BadAliases.mls create mode 100644 shared/src/test/diff/nu/GADTMono.mls create mode 100644 shared/src/test/diff/nu/ParamOverride.mls diff --git a/shared/src/main/scala/mlscript/Diagnostic.scala b/shared/src/main/scala/mlscript/Diagnostic.scala index 1a046f3e06..d99c1b26ed 100644 --- a/shared/src/main/scala/mlscript/Diagnostic.scala +++ b/shared/src/main/scala/mlscript/Diagnostic.scala @@ -60,6 +60,10 @@ final case class Loc(spanStart: Int, spanEnd: Int, origin: Origin) { def right: Loc = copy(spanStart = spanEnd) def left: Loc = copy(spanEnd = spanStart) } +object Loc { + def apply(xs: IterableOnce[Located]): Opt[Loc] = + xs.iterator.foldLeft(none[Loc])((acc, l) => acc.fold(l.toLoc)(_ ++ l.toLoc |> some)) +} final case class Origin(fileName: Str, startLineNum: Int, fph: FastParseHelpers) { override def toString = s"$fileName:+$startLineNum" diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 008e09ee75..cccdce8e6c 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -264,7 +264,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case New(_, TypingUnit(_)) => throw CodeGenError("custom class body is not supported yet") case Forall(_, bod) => translateTerm(bod) - case _: Bind | _: Test | If(_, _) | TyApp(_, _) | _: Splc | _: Where => + case TyApp(base, _) => translateTerm(base) + case _: Bind | _: Test | If(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") } @@ -725,7 +726,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { superParameters.put(sym.runtimeName, pars) } case NuTypeDef(Als, TypeName(nme), tps, _, sig, pars, _, _, _) => { - topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(die)) + topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) } case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members) = prepare(nme, fs, pars, unit) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index a26faa5bdf..0560e17f13 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -308,7 +308,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (KEYWORD("="), _) :: _ if kind is Als => consume S(typ(0)) - case (KEYWORD(":"), _) :: _ => + case (KEYWORD(":"), _) :: _ if !(kind is Als) => consume S(typ(0)) case _ => N @@ -771,7 +771,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D exprCont(res, prec, allowNewlines) case c @ (h :: _) if (h._1 match { - case KEYWORD(";" | "of" | "where") | BRACKETS(Round | Square, _) + case KEYWORD(";" | "of" | "where" | "extends") | BRACKETS(Round | Square, _) | BRACKETS(Indent, ( KEYWORD(";" | "of") | BRACKETS(Round | Square, _) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 267254f206..9305f368f0 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -158,7 +158,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case Als => - // TODO assert td.params, td.parents are empty + if (td.params.fields.nonEmpty) + err(msg"type alias definitions cannot have value parameters" -> td.params.toLoc :: Nil) + if (td.parents.nonEmpty) + err(msg"type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) val tparams = td.tparams.map(tp => (tp._2, freshVar(TypeProvenance( @@ -172,7 +175,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) } - val body_ty = typeType(td.sig.getOrElse(die)) + val body_ty = td.sig match { + case S(sig) => + typeType(sig) + case N => + err(msg"type alias definition requires a right-hand side", td.toLoc) + } TypedNuAls(outerCtx.lvl, td, tparams, body_ty) @@ -381,6 +389,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => )(thisType) } case Mxn => + if (td.parents.nonEmpty) + err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) implicit val prov: TP = noProv // TODO ctx.nest.nextLevel { implicit ctx => implicit val vars: Map[Str, SimpleType] = diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 43c2ad3e53..9a06acfcad 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -369,18 +369,19 @@ trait PgrmImpl { self: Pgrm => } override def toString = tops.map("" + _ + ";").mkString(" ") + // TODO remove this senseless method private def tryDesugaredNewDec(nd: NuTypeDef): Ls[Diagnostic] = nd match { case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => val bases = pars.foldLeft(Var("base"): Term)((res, p) => p match { case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) - case _ => ??? + case _ => Var("anything") // ?? FIXME }) tryDesugaredNewDec(NuTypeDef(Cls, TypeName(mxName), tps, tup, sig, Ls(bases), sup, ths, unit)) case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => if (pars.length > 0) { val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) - case _ => ??? + case _ => Var("anything") // ?? FIXME }) tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, sig, Ls(bases), sup, ths, unit)) } @@ -389,9 +390,9 @@ trait PgrmImpl { self: Pgrm => } case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => // TODO properly check: - require(fs.isEmpty, fs) - require(sig.isDefined) - require(pars.size === 0, pars) + // require(fs.isEmpty, fs) + // require(sig.isDefined) + // require(pars.size === 0, pars) require(ths.isEmpty, ths) require(unit.entities.isEmpty, unit) // val (diags, rhs) = sig.get match { diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls new file mode 100644 index 0000000000..b2801ee4b0 --- /dev/null +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -0,0 +1,97 @@ +:NewParser +:NewDefs + + +// TODO check cyclicity +// :e +type A = A +//│ type A = A + +// TODO check cyclicity +// :e +type A = A | int +//│ type A = int | A + +// TODO check regularity +// :e +type Foo[A] = { x: A, y: Foo[(A, A)] } +//│ type Foo[A] = {x: A, y: Foo[(A, A,)]} + + +// TODO support abstract types +:e +type Test +//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ║ l.23: type Test +//│ ╙── ^^^^^^^^^ +//│ type Test = error + +:e +type Test(n: int) = n +//│ ╔══[ERROR] type alias definitions cannot have value parameters +//│ ║ l.30: type Test(n: int) = n +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] type identifier not found: n +//│ ║ l.30: type Test(n: int) = n +//│ ╙── ^ +//│ type Test = error + +class Base +//│ class Base() + +:pe +:e +type Test: Base +//│ ╔══[PARSE ERROR] Expected end of input; found ':' instead +//│ ║ l.44: type Test: Base +//│ ╙── ^ +//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ║ l.44: type Test: Base +//│ ╙── ^^^^^^^^^ +//│ type Test = error + +:pe +:e +type Test: Base = int +//│ ╔══[PARSE ERROR] Expected end of input; found ':' instead +//│ ║ l.55: type Test: Base = int +//│ ╙── ^ +//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ║ l.55: type Test: Base = int +//│ ╙── ^^^^^^^^^ +//│ type Test = error + +:e +type Test extends Base +//│ ╔══[ERROR] type alias definitions cannot extend parents +//│ ║ l.65: type Test extends Base +//│ ╙── ^^^^ +//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ║ l.65: type Test extends Base +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ +//│ type Test = error + +:pe +:e +type Test extends Base = int +//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead +//│ ║ l.76: type Test extends Base = int +//│ ╙── ^ +//│ ╔══[ERROR] type alias definitions cannot extend parents +//│ ║ l.76: type Test extends Base = int +//│ ╙── ^^^^ +//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ║ l.76: type Test extends Base = int +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ +//│ type Test = error + +:e +type Test = int extends Base +//│ ╔══[ERROR] type alias definitions cannot extend parents +//│ ║ l.89: type Test = int extends Base +//│ ╙── ^^^^ +//│ type Test = int + + + + diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls new file mode 100644 index 0000000000..9eebe1f01c --- /dev/null +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -0,0 +1,19 @@ +:NewParser +:NewDefs + + +// TODO +class Exp[type A] +//│ ╔══[PARSE ERROR] Unexpected 'type' keyword in expression position +//│ ║ l.6: class Exp[type A] +//│ ╙── ^^^^ +//│ class Exp[A]() + +// TODO +class Lit(n: int) extends Exp[int] +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.13: class Lit(n: int) extends Exp[int] +//│ ╙── ^^^^^^^^ +//│ class Lit(n: int) + + diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 5951a48f45..0d31fca36a 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -30,8 +30,8 @@ f(c) class Some(value: A) { fun get = value fun toArray = [value] - // fun mapBad(f) = Some(f(value)) // TODO - // fun map(f : A => 'b) = Some(f(value)) // TODO + // fun mapBad(f) = Some(f(value)) // TODO cyclic + // fun map(f : A => 'b) = Some(f(value)) // TODO cyclic } //│ class Some[A](value: A) { //│ fun get: A diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 6d5ac347b9..65aa52e449 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -1,8 +1,8 @@ :NewParser :NewDefs -:NoJS +// TODO complain abstract module Test { fun foo: A => A } @@ -12,40 +12,93 @@ module Test { Test.foo //│ (??A & 'A) -> ('A | ??A0) +//│ res +//│ = undefined :e Test.foo(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.17: Test.foo(1) +//│ ║ l.19: Test.foo(1) //│ ║ ^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.17: Test.foo(1) +//│ ║ l.19: Test.foo(1) //│ ╙── ^ //│ error | ??A +//│ res +//│ Runtime error: +//│ TypeError: Test.foo is not a function :e Test.foo(error) + 1 //│ ╔══[ERROR] Type error in operator application -//│ ║ l.27: Test.foo(error) + 1 +//│ ║ l.32: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.27: Test.foo(error) + 1 +//│ ║ l.32: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╙── into type `int` //│ error | int +//│ res +//│ Runtime error: +//│ Error: unexpected runtime error :e Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.38: Test .foo +//│ ║ l.46: Test .foo //│ ╙── ^^^^^^^^^ //│ error +//│ res +//│ = undefined :e (Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.45: (Test).foo +//│ ║ l.55: (Test).foo //│ ╙── ^^^^^^^^^ //│ error +//│ res +//│ = undefined + + +Test +//│ Test[?] +//│ res +//│ = Test { class: [class Test] } + +:e +Test: Test<'a> +//│ ╔══[ERROR] Type error in type ascription +//│ ║ l.70: Test: Test<'a> +//│ ║ ^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.70: Test: Test<'a> +//│ ║ ^^ +//│ ╟── back into type variable `A` +//│ ║ l.6: module Test { +//│ ╙── ^ +//│ Test['a] +//│ where +//│ 'a :> error | ??A +//│ <: ??A0 +//│ res +//│ = Test { class: [class Test] } + + +fun test(x) = if x is Test then x.foo +//│ fun test: Test['A] -> 'A -> 'A + +:e +test(Test) +//│ ╔══[ERROR] Type error in application +//│ ║ l.92: test(Test) +//│ ║ ^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.6: module Test { +//│ ╙── ^ +//│ (??A & 'A) -> ('A | ??A0) | error +//│ res +//│ = undefined + diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls new file mode 100644 index 0000000000..d438307451 --- /dev/null +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -0,0 +1,84 @@ +:NewParser +:NewDefs + + +class Base0(n: number) +//│ class Base0(n: number) + +// TODO +class Derived0(n: int) extends Base +//│ ╔══[ERROR] Could not find definition `Base` +//│ ║ l.9: class Derived0(n: int) extends Base +//│ ╙── ^^^^ +//│ class Derived0(n: int) +//│ Code generation encountered an error: +//│ unresolved symbol Base + + +mixin Base1(n: number) +//│ mixin Base1() + +:e +mixin DerivedBad(n: int) extends Base +//│ ╔══[ERROR] mixin definitions cannot yet extend parents +//│ ║ l.22: mixin DerivedBad(n: int) extends Base +//│ ╙── ^^^^ +//│ mixin DerivedBad() + +mixin Derived1(n: int) { + // fun foo = [n, this.n, super.n] // TODO + fun foo = [this.n, super.n] +} +//│ mixin Derived1() { +//│ super: {n: 'n} +//│ this: {n: 'n0} +//│ fun foo: ('n0, 'n,) +//│ } + + +// TODO type check +class Test0 extends Base1(0), Derived1(1) // TODO +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.40: class Test0 extends Base1(0), Derived1(1) // TODO +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.40: class Test0 extends Base1(0), Derived1(1) // TODO +//│ ╙── ^^^^^^^^^^^ +//│ class Test0() + +let t = Test0() +//│ let t: Test0 +//│ t +//│ = Test0 { n: 1 } + +// TODO type check +t.n +//│ ╔══[ERROR] class `Test0` does not contain member `n` +//│ ║ l.55: t.n +//│ ╙── ^^ +//│ error +//│ res +//│ = 1 + +// TODO type check +// FIXME super access to field? +t.foo +//│ ╔══[ERROR] class `Test0` does not contain member `foo` +//│ ║ l.65: t.foo +//│ ╙── ^^^^ +//│ error +//│ res +//│ = [ 1, undefined ] + + +// TODO correct module code-gen +module Test1 extends Base1(0), Derived1(1) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.75: module Test1 extends Base1(0), Derived1(1) +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.75: module Test1 extends Base1(0), Derived1(1) +//│ ╙── ^^^^^^^^^^^ +//│ module Test1() + + diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index dfe8adae6f..725b5d7f5b 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -18,8 +18,10 @@ type AI2 = Array // TODO fail gracefully // :e type AI3(n) = Array[int] +//│ ╔══[ERROR] type alias definitions cannot have value parameters +//│ ║ l.20: type AI3(n) = Array[int] +//│ ╙── ^^^ //│ type AI3 = Array[int] -//│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: List((None,Fld(false,false,n))) // TODO fail gracefully // :e From c4fedb29e360e7d7517aa47340d4b1e992b7d9b4 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 13:00:38 +0800 Subject: [PATCH 137/498] WIP Implement cleaner member access method --- .../scala/mlscript/ConstraintSolver.scala | 81 ++++++++++++++++++- shared/src/main/scala/mlscript/Typer.scala | 4 +- shared/src/test/diff/nu/ClassesInMixins.mls | 4 +- shared/src/test/diff/nu/NestedClasses.mls | 59 ++++++++++++++ .../test/diff/nu/NewPolyVariantCodeReuse.mls | 2 +- .../test/diff/nu/NewPolyVariantCodeReuse2.mls | 4 +- 6 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 shared/src/test/diff/nu/NestedClasses.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 6c72ac1acb..f99911e733 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -23,6 +23,81 @@ class ConstraintSolver extends NormalForms { self: Typer => protected var currentConstrainingRun = 0 + def lookupMember(clsNme: Str, rfnt: Var => Opt[FieldType], fld: Var) + (implicit ctx: Ctx, raise: Raise) + : FieldType + = { + val info = ctx.tyDefs2(clsNme) + + info.complete() match { + case cls: TypedNuCls => + val raw = cls.members.get(fld.name) match { + case S(d: TypedNuFun) => + d.ty.toUpper(provTODO) + case S(p: NuParam) => + p.ty + case S(_) => + err(msg"access to ${cls.td.kind.str} member not yet supported", + fld.toLoc).toUpper(noProv) + case N => + err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", + fld.toLoc).toUpper(noProv) + } + println(s"Lookup ${cls.td.nme.name}.${fld.name} : $raw where ${raw.ub.showBounds}") + + + // TODO dedup with below + + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + + cls.tparams.foreach { case (tn, _tv, vi) => + val targ = rfnt(Var(cls.nme.name + "#" + tn.name)) match { + case S(fty) => + TypeBounds( + fty.lb.getOrElse(BotType), + fty.ub, + )(_tv.prov) + case N => + // FIXME type bounds are kind of wrong for this + TypeBounds( + // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), + _tv.lowerBounds.foldLeft( + Extruded(false, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ | _), + _tv.upperBounds.foldLeft( + Extruded(true, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ & _), + )(_tv.prov) + } + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) // TODO safe not to set original?! + println(s"Set ${_tv} ~> $tv") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + freshened += _tv -> tv + } + + + val res = + raw.freshenAbove(cls.level, rigidify = false)//.asInstanceOf[TypedNuCls] + + println(s"Fresh ${cls.td.nme.name}.${fld.name} : $res where ${res.ub.showBounds}") + + res + + case _ => ??? + } + + } + + // def lookupNuTypeDef(clsNme: Str, rfnt: Map[Var, FieldType]) def lookupNuTypeDef(clsNme: Str, rfnt: Var => Opt[FieldType]) // (implicit raise: Raise, cctx: ConCtx, ctx: Ctx, shadows: Shadows) @@ -453,7 +528,8 @@ class ConstraintSolver extends NormalForms { self: Typer => if (lti.isComputing) annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? else { - val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) + // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) + val fty = lookupMember(nme, r.fields.toMap.get, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) } @@ -680,7 +756,8 @@ class ConstraintSolver extends NormalForms { self: Typer => val lti = ctx.tyDefs2(nme) if (lti.isComputing) reportError() else rt.fields.foreach { case (fldNme, fldTy) => - val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, _ => N), fldNme) + // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, _ => N), fldNme) + val fty = lookupMember(nme, _ => N, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3140dbb4ae..a224d38fcf 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -921,7 +921,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) con(obj_ty, rcd_ty, res) } def mthCallOrSel(obj: Term, fieldName: Var) = - (fieldName.name match { + ( if (newDefs) N else fieldName.name match { case s"$parent.$nme" => ctx.getMth(S(parent), nme) // explicit calls case nme => ctx.getMth(N, nme) // implicit calls }) match { @@ -939,7 +939,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val res = freshVar(prov, N) con(mth_ty.toPT.instantiate, FunctionType(singleTup(o_ty), res)(prov), res) case N => - if (fieldName.name.isCapitalized) err(msg"Method ${fieldName.name} not found", term.toLoc) + if (!newDefs && fieldName.name.isCapitalized) err(msg"Method ${fieldName.name} not found", term.toLoc) else rcdSel(obj, fieldName) // TODO: no else? } obj match { diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 0c10478ffe..693d316a8e 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -27,9 +27,9 @@ M.f.n :e M.Foo -//│ ╔══[ERROR] Method Foo not found +//│ ╔══[ERROR] access to module member not yet supported //│ ║ l.29: M.Foo -//│ ╙── ^^^^^ +//│ ╙── ^^^^ //│ error :e diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls new file mode 100644 index 0000000000..27d98f9914 --- /dev/null +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -0,0 +1,59 @@ +:NewParser +:NewDefs + + +class C0 { + class NC0 +} +//│ class C0() { +//│ class NC0() +//│ } + +let c = C0() +//│ let c: C0 +//│ c +//│ = C0 {} + +:e +c.NC0 +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.18: c.NC0 +//│ ╙── ^^^^ +//│ error +//│ res +//│ = undefined + + +module M0 { + class NC0 +} +//│ module M0() { +//│ class NC0() +//│ } + +:e +M0.NC0 +//│ ╔══[ERROR] access to module member not yet supported +//│ ║ l.35: M0.NC0 +//│ ╙── ^^^^ +//│ error +//│ res +//│ = undefined + + +module M1 { + module NM1 +} +//│ module M1() { +//│ module NM1() +//│ } + +:e +M1.NM1 +//│ ╔══[ERROR] access to module member not yet supported +//│ ║ l.52: M1.NM1 +//│ ╙── ^^^^ +//│ error +//│ res +//│ = undefined + diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 32eced5c84..c6af039774 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -242,7 +242,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var +//│ 'a :> Abs[Var] | Add[Num | Var] | Num | Var | App['a] | Abs['a] //│ res //│ = Var { s: 'a' } diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls index 4387604528..83d926a1aa 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls @@ -114,7 +114,7 @@ module Test1 extends EvalVar, EvalLambda Test1.eval(Nil(), Var("a")) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'a :> Var | App['a] | Abs['a] Test1.eval(Nil(), Abs("b", Var("a"))) //│ 'a @@ -129,7 +129,7 @@ Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var class Num(n: int) class Add(l: A, r: A) From d4b5756ab56e6580ed688f52237efbba37d3ba5d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 13:46:08 +0800 Subject: [PATCH 138/498] WIP minor --- shared/src/main/scala/mlscript/NewLexer.scala | 2 + .../src/main/scala/mlscript/NewParser.scala | 5 +- shared/src/main/scala/mlscript/helpers.scala | 7 ++ shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/nu/BadAliases.mls | 13 ++++ .../test/diff/nu/NewPolyVariantCodeReuse.mls | 78 +++++++++---------- 6 files changed, 64 insertions(+), 43 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index be96e4f926..2ac85e295f 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -274,6 +274,8 @@ object NewLexer { "where", "forall", "exists", + "in", + "out", ) def printToken(tl: TokLoc): Str = tl match { diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 0560e17f13..5c47bfb2a4 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -286,7 +286,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D val ts = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()).map { case (N, Fld(false, false, v @ Var(nme))) => TypeName(nme).withLocOf(v) - case _ => ??? + case nmeo -> param => + err(msg"unsupported type parameter shape (${param.describe})" -> + param.value.toLoc :: Nil) + TypeName(nmeo.fold("")(_.name)).withLocOf(param.value) } ts case _ => Nil diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 9a06acfcad..8ae262f779 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -506,6 +506,13 @@ trait TypeNameImpl extends Ordered[TypeName] { self: TypeName => lazy val toVar: Var = Var(name).withLocOf(this) } +trait FldImpl { self: Fld => + def describe: Str = + (if (self.spec) "specialized " else "") + + (if (self.mut) "mutable " else "") + + self.value.describe +} + trait TermImpl extends StatementImpl { self: Term => val original: this.type = this diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 5813a3c530..f7a5373700 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -89,7 +89,7 @@ final case class IfOpsApp(lhs: Term, opsRhss: Ls[Var -> IfBody]) extends IfBody final case class IfBlock(lines: Ls[IfBody \/ Statement]) extends IfBody // final case class IfApp(fun: Term, opsRhss: Ls[Var -> IfBody]) extends IfBody -final case class Fld(mut: Bool, spec: Bool, value: Term) +final case class Fld(mut: Bool, spec: Bool, value: Term) extends FldImpl sealed abstract class CaseBranches extends CaseBranchesImpl final case class Case(pat: SimpleTerm, body: Term, rest: CaseBranches) extends CaseBranches diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index b2801ee4b0..13b5853a2e 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -93,5 +93,18 @@ type Test = int extends Base //│ type Test = int +:pe +type Poly[mut A] = A +//│ ╔══[PARSE ERROR] unsupported type parameter shape (mutable reference) +//│ ║ l.97: type Poly[mut A] = A +//│ ╙── ^ +//│ type Poly[] = A + +:pe +type Poly[#A] = A +//│ ╔══[PARSE ERROR] unsupported type parameter shape (specialized reference) +//│ ║ l.104: type Poly[#A] = A +//│ ╙── ^ +//│ type Poly[] = A diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index c6af039774..b143c97c1d 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -5,12 +5,13 @@ // * Adapted example from Code reuse through polymorphic variants (FOSE 2000) +type List[A] = Cons[A] | Nil +class Cons[A](head: A, tail: List[A]) module Nil +//│ type List[A] = Cons[A] | Nil +//│ class Cons[A](head: A, tail: List[A]) //│ module Nil() -class Cons[A](head: A, tail: Cons[A] | Nil) -//│ class Cons[A](head: A, tail: Cons[A] | Nil) - let l = Cons(1, Nil) //│ let l: Cons['A] //│ where @@ -23,20 +24,15 @@ class Success[A](result: A) //│ class NotFound() //│ class Success[A](result: A) -let e = eq -//│ let e: anything -> anything -> bool -//│ e -//│ = [Function: eq] - -let eq(l: string, r: string): bool = e(l)(r) -//│ let eq: (l: string, r: string,) -> bool -//│ eq -//│ = [Function: eq1] +let eqStr(l: string, r: string): bool = eq(l)(r) +//│ let eqStr: (l: string, r: string,) -> bool +//│ eqStr +//│ = [Function: eqStr] fun list_assoc(s, l) = if l is Cons(h, t) then - if eq(s, h._1) then Success(h._2) + if eqStr(s, h._1) then Success(h._2) else list_assoc(s, t) Nil then NotFound() //│ fun list_assoc: (string, Cons['A] | Nil,) -> (NotFound | Success['A0]) @@ -91,7 +87,7 @@ mixin EvalLambda { //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b,) -> 'c} //│ this: {eval: (Cons[in 'A out (string, 'd,) | 'A], 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[in 'A0 out (string, Var,) | 'A0 | 'A1], 't1,) -> 'f} -//│ fun eval: ('a & (Cons['A2] | Nil), Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) +//│ fun eval: (List['A2] & 'a, Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) //│ } //│ where //│ 'A2 :> (string, Var,) | 'A0 @@ -99,15 +95,15 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1() { -//│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> 'result +//│ fun eval: (Cons['A] & List['A0] | Nil & List['A0], 'a,) -> 'result //│ } //│ where //│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | Var -//│ 'A :> 'A0 -//│ <: 'A0 & 'A1 -//│ 'A0 :> (string, 'result,) -//│ <: 'A1 & {_1: string, _2: 'result} -//│ 'A1 <: 'A & 'A0 +//│ 'A :> (string, 'result,) +//│ <: 'A1 & {_1: string, _2: 'result} +//│ 'A1 <: 'A0 & 'A +//│ 'A0 :> 'A +//│ <: 'A & 'A1 //│ 'result :> Var | App['result] | Abs['result] Test1.eval(Nil, Var("a")) @@ -196,16 +192,16 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.197: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.193: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.197: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.193: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.149: if v is +//│ ║ l.145: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.159: let vv = map_expr(eta, v) +//│ ║ l.155: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -219,14 +215,14 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> 'result +//│ fun eval: (Cons['A] & List['A0] | Nil & List['A0], 'a,) -> 'result //│ } //│ where -//│ 'A :> 'A0 -//│ <: 'A0 & 'A1 -//│ 'A0 :> (string, 'result,) -//│ <: 'A1 & {_1: string, _2: 'result} -//│ 'A1 <: 'A & 'A0 +//│ 'A :> (string, 'result,) +//│ <: 'A1 & {_1: string, _2: 'result} +//│ 'A1 <: 'A0 & 'A +//│ 'A0 :> 'A +//│ <: 'A & 'A1 //│ 'result :> App['result] | Abs['result] | Num | 'b | Var //│ 'b <: Add['c] | Mul['c] | Num | Var //│ 'c <: 'a @@ -242,20 +238,20 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> Abs[Var] | Add[Num | Var] | Num | Var | App['a] | Abs['a] +//│ 'a :> Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var | App['a] //│ res //│ = Var { s: 'a' } module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: (Cons['A | 'A0] | Nil, 'a,) -> ('a | 'result) +//│ fun eval: (Cons['A] & List['A0] | Nil & List['A0], 'a,) -> ('a | 'result) //│ } //│ where -//│ 'A :> 'A0 -//│ <: 'A0 & 'A1 -//│ 'A0 :> (string, 'result,) -//│ <: 'A1 & {_1: string, _2: 'result} -//│ 'A1 <: 'A & 'A0 +//│ 'A :> (string, 'result,) +//│ <: 'A1 & {_1: string, _2: 'result} +//│ 'A1 <: 'A0 & 'A +//│ 'A0 :> 'A +//│ <: 'A & 'A1 //│ 'result :> Abs['result] | App['result] | Num | 'a | Var //│ 'a <: Add['b] | Mul['b] | Num | Var //│ 'b <: 'a @@ -265,16 +261,16 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.266: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.262: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.266: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.262: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.149: if v is +//│ ║ l.145: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.159: let vv = map_expr(eta, v) +//│ ║ l.155: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where From 168cff80624c7eeccfe2f7480203ecdde1af58f3 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 14:05:16 +0800 Subject: [PATCH 139/498] WIP Support parsing explicit variance --- .../src/main/scala/mlscript/NewParser.scala | 60 +++++++++++++++++-- shared/src/test/diff/nu/BadAliases.mls | 12 ++-- shared/src/test/diff/nu/ExplicitVariance.mls | 54 +++++++++++++++++ shared/src/test/diff/nu/GADTMono.mls | 4 +- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 2 +- 5 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 shared/src/test/diff/nu/ExplicitVariance.mls diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 5c47bfb2a4..7dd34e4cd0 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -283,6 +283,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D val tparams = yeetSpaces match { case (br @ BRACKETS(Angle | Square, toks), loc) :: _ => consume + /* val ts = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()).map { case (N, Fld(false, false, v @ Var(nme))) => TypeName(nme).withLocOf(v) @@ -292,6 +293,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D TypeName(nmeo.fold("")(_.name)).withLocOf(param.value) } ts + */ + rec(toks, S(br.innerLoc), br.describe).concludeWith(_.maybeIndented(_.typeParams)) case _ => Nil } val params = yeetSpaces match { @@ -326,7 +329,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => Nil } val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams.map(N -> _), params, sig, ps, N, N, body) + val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body) R(res.withLoc(S(l0 ++ res.getLoc))) // TODO make `fun` by-name and `let` by-value @@ -850,17 +853,66 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => ??? } - final def argsMaybeIndented()(implicit fe: FoundErr, et: ExpectThen): Ls[Opt[Var] -> Fld] = + // TODO support line-broken param lists; share logic with args/argsOrIf + def typeParams(implicit fe: FoundErr, et: ExpectThen): Ls[(Opt[VarianceInfo], TypeName)] = { + val vinfo = yeetSpaces match { + case (KEYWORD("in"), l0) :: (KEYWORD("out"), l1) :: _ => + consume + S(VarianceInfo.in, l0 ++ l1) + case (KEYWORD("in"), l0) :: _ => + consume + S(VarianceInfo.contra, l0) + case (KEYWORD("out"), l0) :: _ => + consume + S(VarianceInfo.co, l0) + case _ => N + } + yeetSpaces match { + case (IDENT(nme, false), l0) :: _ => + consume + val tyNme = TypeName(nme).withLoc(S(l0)) + yeetSpaces match { + case (COMMA, l0) :: _ => + consume + vinfo.map(_._1) -> tyNme :: typeParams + case _ => + vinfo.map(_._1) -> tyNme :: Nil + } + case _ => + vinfo match { + case S((_, loc)) => + err(msg"dangling variance information" -> S(loc) :: Nil) + case N => + } + Nil + } + } + + + final def maybeIndented[R](f: NewParser => R)(implicit fe: FoundErr, et: ExpectThen): R = cur match { case (br @ BRACKETS(Indent, toks), _) :: _ if (toks.headOption match { case S((KEYWORD("then" | "else"), _)) => false case _ => true }) => consume - rec(toks, S(br.innerLoc), br.describe).concludeWith(_.args(true)) - case _ => args(false) + rec(toks, S(br.innerLoc), br.describe).concludeWith(f) + case _ => f(this) } + final def argsMaybeIndented()(implicit fe: FoundErr, et: ExpectThen): Ls[Opt[Var] -> Fld] = + maybeIndented(_.args(true)) + // final def argsMaybeIndented()(implicit fe: FoundErr, et: ExpectThen): Ls[Opt[Var] -> Fld] = + // cur match { + // case (br @ BRACKETS(Indent, toks), _) :: _ if (toks.headOption match { + // case S((KEYWORD("then" | "else"), _)) => false + // case _ => true + // }) => + // consume + // rec(toks, S(br.innerLoc), br.describe).concludeWith(_.args(true)) + // case _ => args(false) + // } + // TODO support comma-less arg blocks...? final def args(allowNewlines: Bool, prec: Int = NoElsePrec)(implicit fe: FoundErr, et: ExpectThen): Ls[Opt[Var] -> Fld] = // argsOrIf(Nil).map{case (_, L(x))=> ???; case (n, R(x))=>n->x} // TODO diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index 13b5853a2e..0528d822d2 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -95,16 +95,16 @@ type Test = int extends Base :pe type Poly[mut A] = A -//│ ╔══[PARSE ERROR] unsupported type parameter shape (mutable reference) +//│ ╔══[PARSE ERROR] Unexpected 'mut' keyword here //│ ║ l.97: type Poly[mut A] = A -//│ ╙── ^ -//│ type Poly[] = A +//│ ╙── ^^^ +//│ type Poly = A :pe type Poly[#A] = A -//│ ╔══[PARSE ERROR] unsupported type parameter shape (specialized reference) +//│ ╔══[PARSE ERROR] Unexpected '#' here //│ ║ l.104: type Poly[#A] = A -//│ ╙── ^ -//│ type Poly[] = A +//│ ╙── ^ +//│ type Poly = A diff --git a/shared/src/test/diff/nu/ExplicitVariance.mls b/shared/src/test/diff/nu/ExplicitVariance.mls new file mode 100644 index 0000000000..620cc3f2e0 --- /dev/null +++ b/shared/src/test/diff/nu/ExplicitVariance.mls @@ -0,0 +1,54 @@ +:NewParser +:NewDefs + + + +class Foo[out A](x: A) +//│ class Foo[A](x: A) + +fun foo(x: Foo[int]): Foo[number] = x +//│ fun foo: (x: Foo[int],) -> Foo[number] + +:e +fun foo(x: Foo[number]): Foo[int] = x +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.13: fun foo(x: Foo[number]): Foo[int] = x +//│ ║ ^ +//│ ╟── type `number` is not an instance of `int` +//│ ║ l.13: fun foo(x: Foo[number]): Foo[int] = x +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.13: fun foo(x: Foo[number]): Foo[int] = x +//│ ╙── ^^^ +//│ fun foo: (x: Foo[number],) -> Foo[int] + + +class Foo[in A](x: A -> int) +//│ class Foo[A](x: A -> int) + +fun foo(x: Foo[number]): Foo[int] = x +//│ fun foo: (x: Foo[number],) -> Foo[int] + +:e +fun foo(x: Foo[int]): Foo[number] = x +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.33: fun foo(x: Foo[int]): Foo[number] = x +//│ ║ ^ +//│ ╟── type `number` is not an instance of `int` +//│ ║ l.33: fun foo(x: Foo[int]): Foo[number] = x +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.33: fun foo(x: Foo[int]): Foo[number] = x +//│ ╙── ^^^ +//│ fun foo: (x: Foo[int],) -> Foo[number] + + +// :e // TODO check variance annotations! +class Oops0[in A](x: A) +//│ class Oops0[A](x: A) + +// :e // TODO check variance annotations! +class Oops0[out A](x: A -> int) +//│ class Oops0[A](x: A -> int) + + diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 9eebe1f01c..ad66ea7962 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -4,10 +4,10 @@ // TODO class Exp[type A] -//│ ╔══[PARSE ERROR] Unexpected 'type' keyword in expression position +//│ ╔══[PARSE ERROR] Unexpected 'type' keyword here //│ ║ l.6: class Exp[type A] //│ ╙── ^^^^ -//│ class Exp[A]() +//│ class Exp() // TODO class Lit(n: int) extends Exp[int] diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index b143c97c1d..5451418110 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -6,7 +6,7 @@ type List[A] = Cons[A] | Nil -class Cons[A](head: A, tail: List[A]) +class Cons[out A](head: A, tail: List[A]) module Nil //│ type List[A] = Cons[A] | Nil //│ class Cons[A](head: A, tail: List[A]) From d56f5c8f51bed6afb680318eac68fbab142330a2 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 14:25:15 +0800 Subject: [PATCH 140/498] WIP: Fix mixin and module constructor parameters --- .../src/main/scala/mlscript/JSBackend.scala | 8 +- .../main/scala/mlscript/codegen/Codegen.scala | 6 +- shared/src/main/scala/mlscript/helpers.scala | 1 + shared/src/test/diff/codegen/Mixin.mls | 98 +++++++++++++++++++ 4 files changed, 108 insertions(+), 5 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 008e09ee75..bc23bf0518 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -537,6 +537,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val rest = constructorScope.declareValue("rest", Some(false), false) val base: Opt[JSExpr] = translateParents(superFields, constructorScope) + val superParameters = (superFields map { + case App(lhs, Tup(rhs)) => rhs map { + case (_, Fld(mut, spec, trm)) => translateTerm(trm)(getterScope) + } + case _ => Nil + }).flatten val decl = JSClassNewDecl(moduleSymbol.runtimeName, fields, base, @@ -549,7 +555,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), JSIdent("undefined")), Ls( decl, JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), - JSNew(JSInvoke(JSIdent(moduleSymbol.runtimeName), Ls())))), + JSNew(JSInvoke(JSIdent(moduleSymbol.runtimeName), superParameters.reverse)))), JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(moduleSymbol.runtimeName))), )), JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName))) diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 7c8029877c..64f212e8b3 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -857,10 +857,8 @@ final case class JSClassNewDecl( buffer += s" $name.implement(this);" } fields.iterator.zipWithIndex.foreach { pair => - if (rest.isEmpty || pair._2 < fields.length - 1) { - val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" - buffer += s" this${innerName} = ${pair._1};" // TODO: invalid name? - } + val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" + buffer += s" this${innerName} = ${pair._1};" // TODO: invalid name? } buffer += " }" SourceCode(buffer.toList) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 43c2ad3e53..af25f11473 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -380,6 +380,7 @@ trait PgrmImpl { self: Pgrm => if (pars.length > 0) { val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) + case App(pname, _) => App(pname, Tup(Ls(None -> Fld(false, false, res)))) case _ => ??? }) tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, sig, Ls(bases), sup, ths, unit)) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 5070daa4ad..71f34ad882 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -509,3 +509,101 @@ class E(x: int) extends BB, AA(x) //│ ╙── ^^^^^ //│ class E(x: int) +:js +mixin Fooo(x: int) +//│ mixin Fooo() +//│ // Prelude +//│ let typing_unit14 = { +//│ cache: {}, +//│ Fooo(base) { +//│ if (base === undefined) { +//│ return (class Fooo { +//│ constructor(x) { +//│ this.x = x; +//│ } +//│ }); +//│ } else { +//│ return (class Fooo extends base { +//│ constructor(x, ...rest) { +//│ super(...rest); +//│ this.x = x; +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.Fooo = typing_unit14.Fooo; +//│ // End of generated code + +:js +mixin Bazz(y: int) +//│ mixin Bazz() +//│ // Prelude +//│ let typing_unit15 = { +//│ cache: {}, +//│ Bazz(base) { +//│ if (base === undefined) { +//│ return (class Bazz { +//│ constructor(y) { +//│ this.y = y; +//│ } +//│ }); +//│ } else { +//│ return (class Bazz extends base { +//│ constructor(y, ...rest) { +//│ super(...rest); +//│ this.y = y; +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.Bazz = typing_unit15.Bazz; +//│ // End of generated code + +:js +:e // TODO: type check +module Barr extends Fooo(0), Bazz(1) +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.566: module Barr extends Fooo(0), Bazz(1) +//│ ╙── ^^^^^^^ +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.566: module Barr extends Fooo(0), Bazz(1) +//│ ╙── ^^^^^^^ +//│ module Barr() +//│ // Prelude +//│ let typing_unit16 = { +//│ cache: {}, +//│ get Barr() { +//│ if (this.cache.Barr === undefined) { +//│ class Barr extends Bazz(Fooo()) { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ } +//│ this.cache.Barr = new Barr(1, 0); +//│ this.cache.Barr["class"] = Barr; +//│ } +//│ return this.cache.Barr; +//│ } +//│ }; +//│ globalThis.Barr = typing_unit16.Barr; +//│ // End of generated code + +:e +Barr.x +//│ ╔══[ERROR] module `Barr` does not contain member `x` +//│ ║ l.594: Barr.x +//│ ╙── ^^ +//│ error +//│ res +//│ = 0 + +:e +Barr.y +//│ ╔══[ERROR] module `Barr` does not contain member `y` +//│ ║ l.603: Barr.y +//│ ╙── ^^ +//│ error +//│ res +//│ = 1 From 4a34274d5c4051220825b381e754184ff9415ef9 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 14:29:40 +0800 Subject: [PATCH 141/498] WIP: Move parameters into constructor --- shared/src/main/scala/mlscript/JSBackend.scala | 6 +++--- shared/src/test/diff/codegen/Mixin.mls | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index bc23bf0518..c456f39077 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -546,8 +546,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val decl = JSClassNewDecl(moduleSymbol.runtimeName, fields, base, - Ls(JSIdent(s"...${rest.runtimeName}")), - S(rest.runtimeName), + superParameters.reverse, + N, members, traits) @@ -555,7 +555,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), JSIdent("undefined")), Ls( decl, JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), - JSNew(JSInvoke(JSIdent(moduleSymbol.runtimeName), superParameters.reverse)))), + JSNew(JSInvoke(JSIdent(moduleSymbol.runtimeName), Nil)))), JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(moduleSymbol.runtimeName))), )), JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName))) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 71f34ad882..6b2778a8fe 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -393,8 +393,8 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ get TestLang() { //│ if (this.cache.TestLang === undefined) { //│ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { -//│ constructor(...rest) { -//│ super(...rest); +//│ constructor() { +//│ super(); //│ } //│ } //│ this.cache.TestLang = new TestLang(); @@ -413,8 +413,8 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ │ │ get TestLang() { //│ │ │ if (this.cache.TestLang === undefined) { //│ │ │ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); +//│ │ │ constructor() { +//│ │ │ super(); //│ │ │ } //│ │ │ } //│ │ │ this.cache.TestLang = new TestLang(); @@ -577,11 +577,11 @@ module Barr extends Fooo(0), Bazz(1) //│ get Barr() { //│ if (this.cache.Barr === undefined) { //│ class Barr extends Bazz(Fooo()) { -//│ constructor(...rest) { -//│ super(...rest); +//│ constructor() { +//│ super(1, 0); //│ } //│ } -//│ this.cache.Barr = new Barr(1, 0); +//│ this.cache.Barr = new Barr(); //│ this.cache.Barr["class"] = Barr; //│ } //│ return this.cache.Barr; From 0b2b0912ce5caceb231a7347c22dff17e293c2c7 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 14:34:23 +0800 Subject: [PATCH 142/498] WIP Type check type definition parameters early (before completion) --- .../scala/mlscript/ConstraintSolver.scala | 28 ++-- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 122 +++++++++++++++--- shared/src/test/diff/nu/BasicClasses.mls | 27 ++-- shared/src/test/diff/nu/ECOOP23_min.mls | 18 +-- shared/src/test/diff/nu/GenericMixins.mls | 5 +- shared/src/test/diff/nu/MixinParameters.mls | 12 +- shared/src/test/diff/nu/MutualRec.mls | 53 ++------ .../test/diff/nu/NewPolyVariantCodeReuse.mls | 2 +- .../test/diff/nu/NewPolyVariantCodeReuse2.mls | 2 +- shared/src/test/diff/nu/SimpleRegionDSL.mls | 60 +++------ .../src/test/diff/nu/ThisRefinedClasses.mls | 54 +++----- 12 files changed, 199 insertions(+), 186 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index f99911e733..1932e6c8e6 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -28,8 +28,19 @@ class ConstraintSolver extends NormalForms { self: Typer => : FieldType = { val info = ctx.tyDefs2(clsNme) + // require(!info.isComputing) - info.complete() match { + if (info.isComputing) { + + rfnt(fld) match { + case S(fty) => + fty + case N => + // TODO allow when annotated + err(msg"unsupported indirectly recursive member access", fld.toLoc).toUpper(noProv) + } + + } else info.complete() match { case cls: TypedNuCls => val raw = cls.members.get(fld.name) match { case S(d: TypedNuFun) => @@ -524,15 +535,15 @@ class ConstraintSolver extends NormalForms { self: Typer => annoying(Nil, LhsRefined(N, ts, r, trs), Nil, done_rs) case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, trs0), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if nme.isCapitalized => - val lti = ctx.tyDefs2(nme) - if (lti.isComputing) - annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? - else { + // val lti = ctx.tyDefs2(nme) + // if (lti.isComputing) + // annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? + // else { // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) val fty = lookupMember(nme, r.fields.toMap.get, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) - } + // } case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => if (pts.contains(pt) || pts.exists(p => pt.parentsST.contains(p.id))) println(s"OK $pt <: ${pts.mkString(" | ")}") @@ -754,8 +765,9 @@ class ConstraintSolver extends NormalForms { self: Typer => case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => val lti = ctx.tyDefs2(nme) - if (lti.isComputing) reportError() - else rt.fields.foreach { case (fldNme, fldTy) => + // if (lti.isComputing) reportError() + // else + rt.fields.foreach { case (fldNme, fldTy) => // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, _ => N), fldNme) val fty = lookupMember(nme, _ => N, fldNme) rec(fty.ub, fldTy.ub, false) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 18e7dd01ab..d60b542e03 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -351,7 +351,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } val infos = tu.entities.collect { case decl: NuDecl => - val lti = new LazyTypeInfo(lvl, decl) + val lti = new LazyTypeInfo(lvl, decl, implicitly) decl match { case td: NuTypeDef => ctx.tyDefs2 += td.nme.name -> lti diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 9305f368f0..56aae57e17 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -41,11 +41,62 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // protected abstract class TypedNuTypeDefBase extends SimpleType // TODO rm level? already in ctx - class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx, vars: Map[Str, SimpleType]) extends TypeInfo { + // class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]) extends TypeInfo { + class LazyTypeInfo(val level: Int, val decl: NuDecl, outerVars: Map[Str, SimpleType]) + (implicit ctx: Ctx, raise: Raise) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { private def outerCtx = ctx - private def outerVars = vars - val tparams: Ls[(TN, TV)] = Nil // TODO + // private def outerVars = vars + + private implicit val prov: TP = + TypeProvenance(decl.toLoc, decl.describe) + + + lazy val tparams: Ls[(TN, TV, Opt[VarianceInfo])] = ctx.nest.nextLevel { implicit ctx => + decl match { + case td: NuTypeDef => + td.tparams.map(tp => + (tp._2, freshVar(TypeProvenance( + tp._2.toLoc, + "type parameter", + S(tp._2.name), + true), N, S(tp._2.name)), tp._1)) + case fd: NuFunDef => Nil // TODO + } + } + + // println(s"Type params ${tparams.mkString(" ")}") + + lazy private implicit val vars: Map[Str, SimpleType] = + // outerVars ++ tparams.iterator.mapKeys(_.name).toMap + outerVars ++ tparams.iterator.map { + case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) + } + + lazy val typedParams: Ls[Var -> FieldType] = ctx.nest.nextLevel { implicit ctx => + decl match { + case td: NuTypeDef => + td.params.fields.map { + case (S(nme), Fld(mut, spec, value)) => + assert(!mut && !spec, "TODO") // TODO + value.toType match { + case R(tpe) => + implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? + val ty = typeType(tpe) + nme -> FieldType(N, ty)(provTODO) + case _ => ??? + } + case (N, Fld(mut, spec, nme: Var)) => + // assert(!mut && !spec, "TODO") // TODO + // nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) + nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) + case _ => ??? + } + case fd: NuFunDef => Nil // TODO + } + } + + // val tparams: Ls[(TN, TV, VarianceInfo)] = Nil // TODO var isComputing: Bool = false // TODO replace by a Ctx entry var result: Opt[TypedNuDecl] = N @@ -57,7 +108,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => S(decl.name))(level + 1) def map(f: TypedNuDecl => TypedNuDecl): LazyTypeInfo = { - val res = new LazyTypeInfo(level, decl) + val res = new LazyTypeInfo(level, decl, implicitly) // if (result.nonEmpty) res.result = res res.result = result.map(f) res @@ -82,7 +133,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => decl match { case fd: NuFunDef => // assert(fd.isLetRec.isEmpty, fd.isLetRec) - implicit val prov: TP = noProv // TODO + // implicit val prov: TP = noProv // TODO def checkNoTyParams() = if (fd.tparams.nonEmpty) err(msg"Type parameters here are not yet supported in this position", @@ -156,6 +207,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => td.kind match { + case Trt => + err(msg"traits are not yet supported" -> td.toLoc :: Nil) + ??? + case Als => if (td.params.fields.nonEmpty) @@ -163,12 +218,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => if (td.parents.nonEmpty) err(msg"type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) - val tparams = td.tparams.map(tp => - (tp._2, freshVar(TypeProvenance( - tp._2.toLoc, - "type parameter", - S(tp._2.name), - true), N, S(tp._2.name)), tp._1)) + // val tparams = td.tparams.map(tp => + // (tp._2, freshVar(TypeProvenance( + // tp._2.toLoc, + // "type parameter", + // S(tp._2.name), + // true), N, S(tp._2.name)), tp._1)) implicit val vars: Map[Str, SimpleType] = outerVars ++ tparams.iterator.map { @@ -186,9 +241,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case Cls | Nms => - implicit val prov: TP = noProv // TODO + // implicit val prov: TP = noProv // TODO ctx.nest.nextLevel { implicit ctx => + /* val tparams = td.tparams.map(tp => (tp._2, freshVar(TypeProvenance( tp._2.toLoc, @@ -220,6 +276,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) case _ => ??? } + */ + // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) @@ -391,7 +449,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case Mxn => if (td.parents.nonEmpty) err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) - implicit val prov: TP = noProv // TODO + // implicit val prov: TP = noProv // TODO + ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + // TODO include typedParams in members! + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) ctx.nest.nextLevel { implicit ctx => implicit val vars: Map[Str, SimpleType] = outerVars ++ Map.empty // TODO type params @@ -401,7 +462,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => ctx += "super" -> VarSymbol(superTV, Var("super")) // ctx |> { implicit ctx => val ttu = typeTypingUnit(td.body, allowPure = false) - val mems = ttu.entities.map(_.complete()) + val mems = paramMems ++ttu.entities.map(_.complete()) TypedNuMxn(td, thisTV, superTV, mems.map(m => m.name -> m).toMap, ttu) // } } @@ -419,6 +480,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => }() } def typeSignature(implicit raise: Raise): ST = + /* if (isComputing) decl match { case _: NuFunDef => @@ -449,6 +511,33 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ??? ty } + */ + decl match { + case _: NuFunDef => + if (isComputing) { + println(s"Already computing! Using TV: $tv") + tv // TODO FIXME wrong in general (when accessed from difft scope/level) + } else complete() match { + case TypedNuFun(_, fd, ty) => + ty + case _ => die + } + case td: NuTypeDef if td.kind is Nms => + ClassTag(Var(td.nme.name), Set.empty)(provTODO) + case td: NuTypeDef if td.kind is Cls => + PolymorphicType.mk(level, + FunctionType( + TupleType(typedParams.mapKeys(some))(provTODO), + ClassTag(Var(td.nme.name), Set.empty)(provTODO) & RecordType.mk( + tparams.map { case (tn, tv, vi) => // TODO use vi + Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + )(provTODO) + )(provTODO) + ) + // case td: NuTypeDef => + // ??? // TODO + } + def force()(implicit raise: Raise): TypedNuDecl = { val res = complete() res.force() @@ -909,7 +998,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => (td.tvarVariances, td.tparamsargs) case N => val td = ctx.tyDefs2(defn.name) - (N, td.tparams) + (N, td.tparams.map(tp => (tp._1, tp._2))) } tvarVariances.fold(targs.map(f(N, _))) { tvv => assert(tparamsargs.sizeCompare(targs) === 0) @@ -933,7 +1022,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => (td.tvarVariances, td.tparamsargs) case N => val td = ctx.tyDefs2(defn.name) - (N, td.tparams) + // (N, td.tparams) + (N, td.tparams.map(tp => (tp._1, tp._2))) } tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => assert(tparamsargs.sizeCompare(targs) === 0) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 0c230bfa97..fcf9d3d230 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -63,12 +63,9 @@ class Base0(n) { //│ ╔══[ERROR] Class parameters currently need type annotations //│ ║ l.57: class Base0(n) { //│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in field selection: +//│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.61: fun oops = this.my -//│ ║ ^^^^^^^ -//│ ╟── reference of type `Base0 & {n: error}` does not have field 'my' -//│ ║ l.61: fun oops = this.my -//│ ╙── ^^^^ +//│ ╙── ^^^ //│ class Base0(n: error) { //│ fun me: Base0 & {n: error} //│ fun mine: error @@ -140,7 +137,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.141: b.getBaseTypo +//│ ║ l.138: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error @@ -149,21 +146,21 @@ b : Base1 //│ Base1 -:e // TODO class Rec(n: int) { fun go = Rec(n + 1) } -//│ ╔══[ERROR] Cyclic definition -//│ ║ l.153: class Rec(n: int) { -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.154: fun go = Rec(n + 1) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.155: } -//│ ╙── ^ //│ class Rec(n: int) { -//│ fun go: error +//│ fun go: Rec //│ } +let r = Rec(0) +r.n +//│ let r: Rec +//│ int + +r.go.n +//│ int + diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index ba1fddfc6f..47dcd2bca8 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -14,11 +14,11 @@ let e = Add(1, 1) e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α30 +//│ | 0. : α29 //│ ======== TYPED ======== -//│ res: Some(α30) where -//│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) -//│ E23_31 :> 1 +//│ res: Some(α29) where +//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) +//│ E23_30 :> 1 //│ Add[1] e.lhs @@ -28,12 +28,12 @@ e.lhs e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α30 +//│ | 0. : α29 //│ ======== TYPED ======== -//│ res: Some(α30) where -//│ α30 :> (Add<> & {Add#E: mut E23_31..E23_31}) <: {lhs: lhs36} -//│ E23_31 :> 1 <: lhs36 -//│ lhs36 :> 1 +//│ res: Some(α29) where +//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) <: {lhs: lhs35} +//│ E23_30 :> 1 <: lhs35 +//│ lhs35 :> 1 //│ Add[1] diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index b11f844036..99979c4dc5 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -18,10 +18,7 @@ mixin BaseTest { mixin BaseTest(x: A) { fun test = x } -//│ ╔══[ERROR] identifier not found: x -//│ ║ l.19: fun test = x -//│ ╙── ^ //│ mixin BaseTest[A]() { -//│ fun test: error +//│ fun test: A //│ } diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index d2a3e32d67..e920e507de 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -3,24 +3,20 @@ :NoJS -// TODO mixin BaseTest(x: int) { fun test = x } -//│ ╔══[ERROR] identifier not found: x -//│ ║ l.8: fun test = x -//│ ╙── ^ //│ mixin BaseTest() { -//│ fun test: error +//│ fun test: int //│ } // TODO mixin BaseTest(x) { fun test = x } -//│ ╔══[ERROR] identifier not found: x -//│ ║ l.19: fun test = x -//│ ╙── ^ +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.14: mixin BaseTest(x) { +//│ ╙── ^ //│ mixin BaseTest() { //│ fun test: error //│ } diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 2890121cb4..de4e508930 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -134,13 +134,9 @@ module Test1_1 { module Test1_2 { fun b = Test1_1.a } -//│ ╔══[ERROR] Cyclic definition -//│ ║ l.131: module Test1_1 { -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.132: fun a = Test1_2.b -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.133: } -//│ ╙── ^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.135: fun b = Test1_1.a +//│ ╙── ^^ //│ module Test1_1() { //│ fun a: error //│ } @@ -159,13 +155,9 @@ class Test1_1 { class Test1_2 { fun b = Test1_1().a } -//│ ╔══[ERROR] Cyclic definition -//│ ║ l.156: class Test1_1 { -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.157: fun a = Test1_2().b -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.158: } -//│ ╙── ^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.156: fun b = Test1_1().a +//│ ╙── ^^ //│ class Test1_1() { //│ fun a: error //│ } @@ -186,34 +178,11 @@ module Test2_2 { fun c = Test2_1.a fun e = Test2_1.n } -//│ ╔══[ERROR] Cyclic definition -//│ ║ l.178: module Test2_1 { -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.179: fun t2 = Test2_2 -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.180: fun a = Test2_2.b -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.181: fun d = Test2_2.e -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.182: fun n = 456 -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.183: } -//│ ╙── ^ -//│ ╔══[ERROR] Cyclic definition -//│ ║ l.178: module Test2_1 { -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.179: fun t2 = Test2_2 -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.180: fun a = Test2_2.b -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.181: fun d = Test2_2.e -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.182: fun n = 456 -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.183: } -//│ ╙── ^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.178: fun c = Test2_1.a +//│ ╙── ^^ //│ module Test2_1() { -//│ fun a: 123 +//│ fun a: 123 | error //│ fun d: error //│ fun n: 456 //│ fun t2: Test2_2 @@ -228,7 +197,7 @@ Test2_1.t2.b //│ 123 Test2_1.a -//│ 123 +//│ 123 | error // FIXME Test2_1.d diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index 5451418110..b81bbe7318 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -104,7 +104,7 @@ module Test1 extends EvalVar, EvalLambda //│ 'A1 <: 'A0 & 'A //│ 'A0 :> 'A //│ <: 'A & 'A1 -//│ 'result :> Var | App['result] | Abs['result] +//│ 'result :> Var | Abs['result] | App['result] Test1.eval(Nil, Var("a")) //│ 'a diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls index 83d926a1aa..f7704aee40 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls @@ -114,7 +114,7 @@ module Test1 extends EvalVar, EvalLambda Test1.eval(Nil(), Var("a")) //│ 'a //│ where -//│ 'a :> Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Var Test1.eval(Nil(), Abs("b", Var("a"))) //│ 'a diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index edbcc3e430..bf59a18eb4 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -195,46 +195,18 @@ mixin Text { :e module SizeText extends Text -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.197: module SizeText extends Text -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' -//│ ╟── Note: constraint arises from field selection: +//│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.189: Translate then concat("a translated region of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^ -//│ ╟── from reference: -//│ ║ l.189: Translate then concat("a translated region of size ", toString(this.size(e))) -//│ ╙── ^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.197: module SizeText extends Text -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' -//│ ╟── Note: constraint arises from field selection: -//│ ║ l.188: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^ -//│ ╟── from reference: +//│ ╙── ^^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.188: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) -//│ ╙── ^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.197: module SizeText extends Text -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' -//│ ╟── Note: constraint arises from field selection: +//│ ╙── ^^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.187: Union then concat("the union of two regions of size ", toString(this.size(e))) -//│ ║ ^^^^^^^^^ -//│ ╟── from reference: -//│ ║ l.187: Union then concat("the union of two regions of size ", toString(this.size(e))) -//│ ╙── ^^^^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.197: module SizeText extends Text -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not have field 'size' -//│ ╟── Note: constraint arises from field selection: -//│ ║ l.186: Outside(a) then concat("outside a region of size ", toString(this.size(a))) -//│ ║ ^^^^^^^^^ -//│ ╟── from reference: +//│ ╙── ^^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.186: Outside(a) then concat("outside a region of size ", toString(this.size(a))) -//│ ╙── ^^^^ +//│ ╙── ^^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string //│ } @@ -398,7 +370,7 @@ fun mk(n) = if n is TestElim.eliminate(mk(100)) //│ 'a //│ where -//│ 'a :> Scale['a] | Outside['a] | Union['a] | Intersect['a] | Translate['a] +//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -422,7 +394,7 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union -//│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] +//│ 'c :> Union['c] | Intersect['c] | Translate['c] | Scale['c] | Outside['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] // TODO investigate @@ -478,13 +450,13 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.479: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.451: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.392: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.364: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.479: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.451: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.132: if a is @@ -498,13 +470,13 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.499: Lang.text(mk(100)) +//│ ║ l.471: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.392: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.364: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.499: Lang.text(mk(100)) +//│ ║ l.471: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.184: if e is diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index f464abb805..81271c6558 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -11,12 +11,9 @@ :e class Foo { fun test = this.x } -//│ ╔══[ERROR] Type mismatch in field selection: +//│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.13: class Foo { fun test = this.x } -//│ ║ ^^^^^^ -//│ ╟── reference of type `Foo` does not have field 'x' -//│ ║ l.13: class Foo { fun test = this.x } -//│ ╙── ^^^^ +//│ ╙── ^^ //│ class Foo() { //│ fun test: error //│ } @@ -24,12 +21,9 @@ class Foo { fun test = this.x } :e class Foo(n: int) { fun test = this.x } -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.26: class Foo(n: int) { fun test = this.x } -//│ ║ ^^^^^^ -//│ ╟── reference of type `Foo & {n: int}` does not have field 'x' -//│ ║ l.26: class Foo(n: int) { fun test = this.x } -//│ ╙── ^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.23: class Foo(n: int) { fun test = this.x } +//│ ╙── ^^ //│ class Foo(n: int) { //│ fun test: error //│ } @@ -37,12 +31,9 @@ class Foo(n: int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.39: class Foo(n: A) { fun test = this.x } -//│ ║ ^^^^^^ -//│ ╟── reference of type `Foo & {Foo#A = ?A, n: A}` does not have field 'x' -//│ ║ l.39: class Foo(n: A) { fun test = this.x } -//│ ╙── ^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.33: class Foo(n: A) { fun test = this.x } +//│ ╙── ^^ //│ class Foo[A](n: A) { //│ fun test: error //│ } @@ -54,32 +45,21 @@ class Foo { this: { x: 'a } // fun test = this.x } -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.54: this: { x: 'a } -//│ ║ ^^^^ -//│ ╟── reference of type `Foo` does not have field 'x' -//│ ╟── Note: constraint arises from record type: -//│ ║ l.54: this: { x: 'a } -//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.45: this: { x: 'a } +//│ ╙── ^ //│ class Foo() // TODO // * All on one line: class Test { this: { x: int}; fun test = this.x } -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } -//│ ║ ^^^^ -//│ ╟── reference of type `Test` does not have field 'x' -//│ ╟── Note: constraint arises from record type: -//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } -//│ ║ ^^^^^^ -//│ ╟── reference of type `Test` does not have field 'x' -//│ ║ l.69: class Test { this: { x: int}; fun test = this.x } -//│ ╙── ^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.56: class Test { this: { x: int}; fun test = this.x } +//│ ╙── ^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.56: class Test { this: { x: int}; fun test = this.x } +//│ ╙── ^^ //│ class Test() { //│ fun test: error //│ } From 2640e5c8f4364aa2ec13f84db81d3667bb77c932 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 15:06:13 +0800 Subject: [PATCH 143/498] WIP: try to fix members without this --- .../src/main/scala/mlscript/JSBackend.scala | 60 ++++++++++++++++--- shared/src/test/diff/nu/ECOOP23_intro.mls | 2 +- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index c456f39077..0a13d7880c 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -445,12 +445,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val getterScope = scope.derive(s"getter ${mixinSymbol.lexicalName}") val mixinScope = getterScope.derive(s"mixin ${mixinSymbol.lexicalName}") mixinScope.declareSuper() - val members = mixinSymbol.methods.map { - translateClassMember(_)(mixinScope) - } // Collect class fields. val fields = mixinSymbol.body.collectFields ++ mixinSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + + val members = mixinSymbol.methods.map { + translateNewClassMember(_, fields)(mixinScope) + } val constructorScope = mixinScope.derive(s"${mixinSymbol.lexicalName} constructor") fields.foreach(constructorScope.declareValue(_, Some(false), false)) val rest = constructorScope.declareValue("rest", Some(false), false) @@ -520,12 +521,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") val constructorScope = moduleScope.derive(s"${moduleSymbol.lexicalName} constructor") - val members = moduleSymbol.methods.map { - translateClassMember(_)(moduleScope) - } // Collect class fields. val fields = moduleSymbol.body.collectFields ++ moduleSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + val members = moduleSymbol.methods.map { + translateNewClassMember(_, fields)(moduleScope) + } val traits = moduleSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) @@ -594,12 +595,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { )(implicit scope: Scope): JSClassNewDecl = { // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") - val members = classSymbol.methods.map { - translateClassMember(_)(classScope) - } // Collect class fields. val fields = classSymbol.body.collectFields ++ classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + val members = classSymbol.methods.map { + translateNewClassMember(_, fields)(classScope) + } val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") fields.foreach(constructorScope.declareValue(_, Some(false), false)) @@ -667,6 +668,47 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } } + private def translateNewClassMember( + method: MethodDef[Left[Term, Type]], + props: Ls[Str] = Nil + )(implicit scope: Scope): JSClassMemberDecl = { + val name = method.nme.name + // Create the method/getter scope. + val memberScope = method.rhs.value match { + case _: Lam => scope.derive(s"method $name") + case _ => scope.derive(s"getter $name") + } + // Declare the alias for `this` before declaring parameters. + val selfSymbol = memberScope.declareThisAlias() + val preDecs = props.map(p => { + val runtime = memberScope.declareValue(p, Some(false), false) + JSConstDecl(runtime.runtimeName, JSField(JSIdent("this"), p)) + }) + // Declare parameters. + val (memberParams, body) = method.rhs.value match { + case Lam(params, body) => + val methodParams = translateParams(params)(memberScope) + (S(methodParams), body) + case term => + (N, term) + } + // Translate class member body. + val bodyResult = translateTerm(body)(memberScope).`return` + // If `this` is accessed, add `const self = this`. + val bodyStmts = if (visitedSymbols(selfSymbol)) { + val thisDecl = JSConstDecl(selfSymbol.runtimeName, JSIdent("this")) + visitedSymbols -= selfSymbol + R(preDecs ::: (thisDecl :: bodyResult :: Nil)) + } else { + R(preDecs ::: (bodyResult :: Nil)) + } + // Returns members depending on what it is. + memberParams match { + case S(memberParams) => JSClassMethod(name, memberParams, bodyStmts) + case N => JSClassGetter(name, bodyStmts) + } + } + /** * Declare symbols for types, traits and classes. * Call this before the code generation. diff --git a/shared/src/test/diff/nu/ECOOP23_intro.mls b/shared/src/test/diff/nu/ECOOP23_intro.mls index ccef8e314a..f6d68f563c 100644 --- a/shared/src/test/diff/nu/ECOOP23_intro.mls +++ b/shared/src/test/diff/nu/ECOOP23_intro.mls @@ -20,7 +20,7 @@ mixin ComparePoint { class Color(str: string) { - fun equals(that) = eq(this.str)(that.str) + fun equals(that) = eq(str)(that.str) } //│ class Color(str: string) { //│ fun equals: {str: anything} -> bool From 48c9b2a69f678892a879c7d4db9395901843b27b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 15:48:40 +0800 Subject: [PATCH 144/498] WIP Use explicitly-specified variances in type checking and simplification --- .../scala/mlscript/ConstraintSolver.scala | 15 +++- .../src/main/scala/mlscript/NuTypeDefs.scala | 11 +++ .../main/scala/mlscript/TyperDatatypes.scala | 14 +++- shared/src/test/diff/nu/ListConsNil.mls | 42 +++++++++++ .../test/diff/nu/NewPolyVariantCodeReuse.mls | 75 ++++++------------- 5 files changed, 104 insertions(+), 53 deletions(-) create mode 100644 shared/src/test/diff/nu/ListConsNil.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 1932e6c8e6..9425c5f192 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -900,6 +900,7 @@ class ConstraintSolver extends NormalForms { self: Typer => if (!v.isCovariant) rec(targ2, targ1, false) } case N => + /* ctx.tyDefs2(tr1.defn.name).complete() match { case cls: TypedNuCls => cls.tparams.map(_._2).lazyZip(tr1.targs).lazyZip(tr2.targs).foreach { @@ -908,7 +909,19 @@ class ConstraintSolver extends NormalForms { self: Typer => if (!v.isContravariant) rec(targ1, targ2, false) if (!v.isCovariant) rec(targ2, targ1, false) } - case _ => ??? + // case _ => ??? + } + */ + ctx.tyDefs2.get(tr1.defn.name) match { + case S(lti) => + lti.tparams.map(_._2).lazyZip(tr1.targs).lazyZip(tr2.targs).foreach { + (tv, targ1, targ2) => + val v = lti.varianceOf(tv) + if (!v.isContravariant) rec(targ1, targ2, false) + if (!v.isCovariant) rec(targ2, targ1, false) + } + case N => + ??? // TODO } } } else { diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index d60b542e03..4a6a456d8b 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -216,6 +216,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name + + // TODO + // def checkVariances + + // lazy val explicitVariances: VarianceStore = + // MutMap.from(tparams.iterator.map(tp => tp._2 -> tp._3.getOrElse(VarianceInfo.in))) + + // TODO should we really recompute them on freshened instances, or can we avoid that? private var _variances: Opt[VarianceStore] = N def variances(implicit ctx: Ctx): VarianceStore = { _variances match { @@ -254,6 +262,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // println(store) store + // TODO check consistency with explicitVariances + store ++ tparams.iterator.collect { case (_, tv, S(vi)) => tv -> vi } + } } def varianceOf(tv: TV)(implicit ctx: Ctx): VarianceInfo = diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 56aae57e17..669028ba4a 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -65,6 +65,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } } + lazy val explicitVariances: VarianceStore = + MutMap.from(tparams.iterator.map(tp => tp._2 -> tp._3.getOrElse(VarianceInfo.in))) + + def varianceOf(tv: TV)(implicit ctx: Ctx): VarianceInfo = + // TODO make use of inferred vce if result is completed + explicitVariances.get(tv).getOrElse(VarianceInfo.in) + // println(s"Type params ${tparams.mkString(" ")}") lazy private implicit val vars: Map[Str, SimpleType] = @@ -1023,7 +1030,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case N => val td = ctx.tyDefs2(defn.name) // (N, td.tparams) - (N, td.tparams.map(tp => (tp._1, tp._2))) + // (td.explicitVariances, td.tparams) + // TODO computed varces + // (some[VarianceStore]( + // MutMap.from(td.tparams.iterator.map(tp => tp._2 -> tp._3.getOrElse(VarianceInfo.in))) + // ), td.tparams.map(tp => (tp._1, tp._2))) + (some(td.explicitVariances), td.tparams.map(tp => (tp._1, tp._2))) } tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => assert(tparamsargs.sizeCompare(targs) === 0) diff --git a/shared/src/test/diff/nu/ListConsNil.mls b/shared/src/test/diff/nu/ListConsNil.mls new file mode 100644 index 0000000000..459e525fb7 --- /dev/null +++ b/shared/src/test/diff/nu/ListConsNil.mls @@ -0,0 +1,42 @@ +:NewParser +:NewDefs + + + +type List[out A] = Cons[A] | Nil +class Cons[out A](head: A, tail: List[A]) +module Nil +//│ type List[A] = Cons[A] | Nil +//│ class Cons[A](head: A, tail: List[A]) +//│ module Nil() + + + +// TODO should better simplify these types (reduce the List refinement) + +:ng +let test0: Cons[int] & List[number] +let test1: Nil & List[int] +//│ let test0: Cons[int] & List[number] +//│ let test1: List[int] & Nil + + + +fun list_assoc(s, l) = + if l is + Cons(h, t) then + if eq(s)(h._1) then Cons(h._2, Nil) + else list_assoc(s, t) + Nil then Nil +//│ fun list_assoc: (anything, Cons[{_1: anything, _2: 'A}] | Nil,) -> (Cons['A] | Nil) + +fun test(x, l) = list_assoc(42, Cons(x, l)) +//│ fun test: ({_1: anything, _2: 'A}, List[{_1: anything, _2: 'A}],) -> (Cons['A] | Nil) + +fun test(x, l) = if l is + Nil then list_assoc(42, Cons(x, l)) + Cons(h, t) then list_assoc(42, Cons(h, t)) +//│ fun test: ({_1: anything, _2: 'A}, Cons[{_1: anything, _2: 'A}] | Nil,) -> (Cons['A] | Nil) + + + diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index b81bbe7318..cc7364bd78 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -5,17 +5,13 @@ // * Adapted example from Code reuse through polymorphic variants (FOSE 2000) -type List[A] = Cons[A] | Nil -class Cons[out A](head: A, tail: List[A]) +class Cons[out A](head: A, tail: Cons[A] | Nil) module Nil -//│ type List[A] = Cons[A] | Nil -//│ class Cons[A](head: A, tail: List[A]) +//│ class Cons[A](head: A, tail: Cons[A] | Nil) //│ module Nil() let l = Cons(1, Nil) -//│ let l: Cons['A] -//│ where -//│ 'A :> 1 +//│ let l: Cons[1] //│ l //│ = Cons { head: 1, tail: Nil { class: [class Nil] } } @@ -35,9 +31,7 @@ fun list_assoc(s, l) = if eqStr(s, h._1) then Success(h._2) else list_assoc(s, t) Nil then NotFound() -//│ fun list_assoc: (string, Cons['A] | Nil,) -> (NotFound | Success['A0]) -//│ where -//│ 'A <: {_1: string, _2: 'A0} +//│ fun list_assoc: (string, Cons[{_1: string, _2: 'A}] | Nil,) -> (NotFound | Success['A]) // fun list_assoc(s: string, l: Cons[{ _1: string, _2: 'b }] | Nil): NotFound | Success['b] @@ -52,10 +46,8 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (Cons['A] | Nil, Var,) -> (Var | 'result) +//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, Var,) -> (Var | 'result) //│ } -//│ where -//│ 'A <: {_1: string, _2: 'result} class Abs[A](x: string, t: A) class App[A](s: A, t: A) @@ -86,25 +78,17 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b,) -> 'c} -//│ this: {eval: (Cons[in 'A out (string, 'd,) | 'A], 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[in 'A0 out (string, Var,) | 'A0 | 'A1], 't1,) -> 'f} -//│ fun eval: (List['A2] & 'a, Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) +//│ this: {eval: (Cons[(string, 'd,)], 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[(string, Var,) | 'A], 't1,) -> 'f} +//│ fun eval: ('a & (Cons['A] | Nil), Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) //│ } -//│ where -//│ 'A2 :> (string, Var,) | 'A0 -//│ <: 'A1 module Test1 extends EvalVar, EvalLambda //│ module Test1() { -//│ fun eval: (Cons['A] & List['A0] | Nil & List['A0], 'a,) -> 'result +//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> 'result //│ } //│ where //│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | Var -//│ 'A :> (string, 'result,) -//│ <: 'A1 & {_1: string, _2: 'result} -//│ 'A1 <: 'A0 & 'A -//│ 'A0 :> 'A -//│ <: 'A & 'A1 -//│ 'result :> Var | Abs['result] | App['result] +//│ 'result :> Var | App['result] | Abs['result] Test1.eval(Nil, Var("a")) //│ 'a @@ -130,7 +114,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var +//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] //│ res //│ = Var { s: 'b' } @@ -167,12 +151,11 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2() { -//│ fun eval: (Cons['A] | Nil, 'a,) -> (Num | Var | 'result | 'a) +//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> (Num | Var | 'result | 'a) //│ } //│ where //│ 'a <: Add['b] | Mul['b] | Num | Var //│ 'b <: 'a -//│ 'A <: {_1: string, _2: 'result} Test2.eval(Nil, Var("a")) //│ Num | Var @@ -192,16 +175,16 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.193: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.193: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.145: if v is +//│ ║ l.129: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.155: let vv = map_expr(eta, v) +//│ ║ l.139: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -215,15 +198,10 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: (Cons['A] & List['A0] | Nil & List['A0], 'a,) -> 'result +//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> 'result //│ } //│ where -//│ 'A :> (string, 'result,) -//│ <: 'A1 & {_1: string, _2: 'result} -//│ 'A1 <: 'A0 & 'A -//│ 'A0 :> 'A -//│ <: 'A & 'A1 -//│ 'result :> App['result] | Abs['result] | Num | 'b | Var +//│ 'result :> App['result] | Abs['result] | Num | Var | 'b //│ 'b <: Add['c] | Mul['c] | Num | Var //│ 'c <: 'a //│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | 'b & ~Abs & ~App @@ -238,21 +216,16 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var | App['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var //│ res //│ = Var { s: 'a' } module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: (Cons['A] & List['A0] | Nil & List['A0], 'a,) -> ('a | 'result) +//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> ('a | 'result) //│ } //│ where -//│ 'A :> (string, 'result,) -//│ <: 'A1 & {_1: string, _2: 'result} -//│ 'A1 <: 'A0 & 'A -//│ 'A0 :> 'A -//│ <: 'A & 'A1 -//│ 'result :> Abs['result] | App['result] | Num | 'a | Var +//│ 'result :> Abs['result] | App['result] | Var | Num | 'a //│ 'a <: Add['b] | Mul['b] | Num | Var //│ 'b <: 'a @@ -261,16 +234,16 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.262: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.262: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.145: if v is +//│ ║ l.129: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.155: let vv = map_expr(eta, v) +//│ ║ l.139: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where From d17d07ead3a54c05b7918764d1ef6e1388dccdc1 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 15:55:25 +0800 Subject: [PATCH 145/498] WIP Small cleanups, tests, & improvements --- js/src/main/scala/Main.scala | 4 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 15 +- shared/src/main/scala/mlscript/syntax.scala | 9 +- shared/src/test/diff/codegen/Super.mls | 226 ++++++++++++++++++ shared/src/test/diff/nu/BasicMixins.mls | 12 +- shared/src/test/diff/nu/ModuleParameters.mls | 30 +++ .../test/diff/nu/NewPolyVariantCodeReuse.mls | 9 +- .../diff/nu/{Super.mls => ParamPassing.mls} | 0 10 files changed, 286 insertions(+), 25 deletions(-) create mode 100644 shared/src/test/diff/codegen/Super.mls create mode 100644 shared/src/test/diff/nu/ModuleParameters.mls rename shared/src/test/diff/nu/{Super.mls => ParamPassing.mls} (100%) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index b0ce5d2a17..64803239ba 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -135,14 +135,14 @@ object Main { val vars: Map[Str, typer.SimpleType] = Map.empty val tpd = typer.typeTypingUnit(tu, allowPure = true)(ctx.nest, raise, vars) val comp = tpd.force()(raise) - + object SimplifyPipeline extends typer.SimplifyPipeline { def debugOutput(msg: => Str): Unit = // if (mode.dbgSimplif) output(msg) println(msg) } val sim = SimplifyPipeline(comp, all = false)(ctx) - + val exp = typer.expandType(sim)(ctx) val expStr = exp.showIn(ShowCtx.mk(exp :: Nil), 0).stripSuffix("\n") diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 4a6a456d8b..86a9962ed9 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -362,7 +362,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } val infos = tu.entities.collect { case decl: NuDecl => - val lti = new LazyTypeInfo(lvl, decl, implicitly) + val lti = new LazyTypeInfo(decl, implicitly) decl match { case td: NuTypeDef => ctx.tyDefs2 += td.nme.name -> lti diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index a224d38fcf..78b081d740 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -67,8 +67,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) tyDefs: Map[Str, TypeDef], // tyDefs2: MutMap[Str, NuTypeDef], tyDefs2: MutMap[Str, LazyTypeInfo], - inRecursiveDef: Opt[Var], - nuTyDefs: Map[Str, TypedNuTypeDef], + inRecursiveDef: Opt[Var], // TODO rm extrCtx: ExtrCtx, ) { def +=(b: Str -> TypeInfo): Unit = env += b @@ -154,7 +153,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) tyDefs = Map.from(builtinTypes.map(t => t.nme.name -> t)), tyDefs2 = MutMap.empty, inRecursiveDef = N, - nuTyDefs = Map.empty, MutMap.empty, ) val empty: Ctx = init diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 669028ba4a..db8a2a1aaf 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -42,12 +42,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // TODO rm level? already in ctx // class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]) extends TypeInfo { - class LazyTypeInfo(val level: Int, val decl: NuDecl, outerVars: Map[Str, SimpleType]) + class LazyTypeInfo(val decl: NuDecl, outerVars: Map[Str, SimpleType]) (implicit ctx: Ctx, raise: Raise) extends TypeInfo { // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { private def outerCtx = ctx // private def outerVars = vars + val level: Level = ctx.lvl + private implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) @@ -115,7 +117,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => S(decl.name))(level + 1) def map(f: TypedNuDecl => TypedNuDecl): LazyTypeInfo = { - val res = new LazyTypeInfo(level, decl, implicitly) + val res = new LazyTypeInfo(decl, implicitly) // if (result.nonEmpty) res.result = res res.result = result.map(f) res @@ -285,6 +287,11 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } */ + if ((td.kind is Nms) && typedParams.nonEmpty) + // * Can we do better? (Memoization semantics?) + err(msg"${td.kind.str} parameters are not supported", + Loc(typedParams.iterator.map(_._1))) + // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) @@ -360,7 +367,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case fun @ TypedNuFun(_, fd, ty) => fun case m: NuMember => m - case _ => ??? + // case _ => ??? } case cls: TypedNuCls => err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO @@ -456,9 +463,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case Mxn => if (td.parents.nonEmpty) err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) - // implicit val prov: TP = noProv // TODO ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) - // TODO include typedParams in members! val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) ctx.nest.nextLevel { implicit ctx => implicit val vars: Map[Str, SimpleType] = diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index f7a5373700..ee7097d989 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -5,7 +5,7 @@ import mlscript.utils._, shorthands._ // Terms -final case class Pgrm(tops: Ls[Statement]) extends PgrmOrTypingUnit with PgrmImpl +final case class Pgrm(tops: Ls[Statement]) extends PgrmImpl sealed abstract class Decl extends DesugaredStatement with DeclImpl final case class Def(rec: Bool, nme: Var, rhs: Term \/ Type, isByname: Bool) extends Decl with Terms { @@ -76,7 +76,7 @@ final case class New(head: Opt[(NamedType, Term)], body: TypingUnit) extends Ter final case class If(body: IfBody, els: Opt[Term]) extends Term final case class TyApp(lhs: Term, targs: Ls[Type]) extends Term final case class Where(body: Term, where: Ls[Statement]) extends Term -final case class Forall(params: Ls[TypeVar], body: Term) extends Term +final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term sealed abstract class IfBody extends IfBodyImpl @@ -165,7 +165,7 @@ final case class PolyType(targs: Ls[TypeName \/ TypeVar], body: Type) extends Ty // New Definitions AST -final case class TypingUnit(entities: Ls[Statement]) extends PgrmOrTypingUnit with TypingUnitImpl +final case class TypingUnit(entities: Ls[Statement]) extends TypingUnitImpl // final case class TypingUnit(entities: Ls[Statement]) extends TypeLike with PgrmOrTypingUnit with TypingUnitImpl final case class Signature(members: Ls[NuDecl], result: Opt[Type]) extends TypeLike with SignatureImpl @@ -195,9 +195,6 @@ final case class NuFunDef( } -sealed trait PgrmOrTypingUnit // TODO rm - - final case class VarianceInfo(isCovariant: Bool, isContravariant: Bool) { diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls new file mode 100644 index 0000000000..4c59762680 --- /dev/null +++ b/shared/src/test/diff/codegen/Super.mls @@ -0,0 +1,226 @@ +:NewParser +:NewDefs + + + +// FIXME `let` fields should not be getters +:js +mixin Foo0 { + let foo0 = 0 +} +//│ mixin Foo0() { +//│ let foo0: 0 +//│ } +//│ // Prelude +//│ let res; +//│ let typing_unit = { +//│ cache: {}, +//│ Foo0(base) { +//│ if (base === undefined) { +//│ return (class Foo0 { +//│ constructor() { +//│ } +//│ get foo0() { +//│ return 0; +//│ } +//│ }); +//│ } else { +//│ return (class Foo0 extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ get foo0() { +//│ return 0; +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.Foo0 = typing_unit.Foo0; +//│ // End of generated code + +:js +mixin Foo1 { + let foo0 = 1 + let foo1 = super.foo0 +} +//│ mixin Foo1() { +//│ super: {foo0: 'foo0} +//│ let foo0: 1 +//│ let foo1: 'foo0 +//│ } +//│ // Prelude +//│ let typing_unit1 = { +//│ cache: {}, +//│ Foo1(base) { +//│ if (base === undefined) { +//│ return (class Foo1 { +//│ constructor() { +//│ } +//│ get foo0() { +//│ return 1; +//│ } +//│ get foo1() { +//│ return super.foo0; +//│ } +//│ }); +//│ } else { +//│ return (class Foo1 extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ get foo0() { +//│ return 1; +//│ } +//│ get foo1() { +//│ return super.foo0; +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.Foo1 = typing_unit1.Foo1; +//│ // End of generated code + +module Test0 extends Foo0, Foo1 +//│ module Test0() { +//│ let foo0: 1 +//│ let foo1: 0 +//│ } + +[Test0.foo0, Test0.foo1] +//│ (1, 0,) +//│ res +//│ = [ 1, 0 ] + + +// FIXME some errors are currently swallowed! + +:ShowRepl +:js +mixin Foo2 { + fun foo2 = super +} +//│ mixin Foo2() { +//│ super: 'super +//│ fun foo2: 'super +//│ } +//│ // Prelude +//│ let typing_unit4 = { +//│ cache: {}, +//│ Foo2(base) { +//│ if (base === undefined) { +//│ return (class Foo2 { +//│ constructor() { +//│ } +//│ get foo2() { +//│ return super; +//│ } +//│ }); +//│ } else { +//│ return (class Foo2 extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ get foo2() { +//│ return super; +//│ } +//│ }); +//│ } +//│ } +//│ }; +//│ globalThis.Foo2 = typing_unit4.Foo2; +//│ // End of generated code +//│ ┌ Block at Super.mls:101 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit4 = { +//│ │ │ cache: {}, +//│ │ │ Foo2(base) { +//│ │ │ if (base === undefined) { +//│ │ │ return (class Foo2 { +//│ │ │ constructor() { +//│ │ │ } +//│ │ │ get foo2() { +//│ │ │ return super; +//│ │ │ } +//│ │ │ }); +//│ │ │ } else { +//│ │ │ return (class Foo2 extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ get foo2() { +//│ │ │ return super; +//│ │ │ } +//│ │ │ }); +//│ │ │ } +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Foo2 = typing_unit4.Foo2; +//│ │ └── Reply [syntax error] 'super' keyword unexpected here +//│ └── No queries + +:ShowRepl +:js +module Test0 extends Foo2 +//│ module Test0() { +//│ fun foo2: anything +//│ } +//│ // Prelude +//│ let typing_unit5 = { +//│ cache: {}, +//│ get Test01() { +//│ if (this.cache.Test01 === undefined) { +//│ class Test01 extends Foo2() { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ } +//│ this.cache.Test01 = new Test01(); +//│ this.cache.Test01["class"] = Test01; +//│ } +//│ return this.cache.Test01; +//│ } +//│ }; +//│ globalThis.Test01 = typing_unit5.Test01; +//│ // End of generated code +//│ ┌ Block at Super.mls:166 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit5 = { +//│ │ │ cache: {}, +//│ │ │ get Test01() { +//│ │ │ if (this.cache.Test01 === undefined) { +//│ │ │ class Test01 extends Foo2() { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ } +//│ │ │ this.cache.Test01 = new Test01(); +//│ │ │ this.cache.Test01["class"] = Test01; +//│ │ │ } +//│ │ │ return this.cache.Test01; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Test01 = typing_unit5.Test01; +//│ │ └── Reply +//│ │ Uncaught ReferenceError: Foo2 is not defined +//│ │ at get Test01 [as Test01] (REPL9:1:78) +//│ └── No queries + +:re +Test0 +//│ Test0 +//│ res +//│ Runtime error: +//│ ReferenceError: Test01 is not defined + +:re +Test0.foo2 +//│ anything +//│ res +//│ Runtime error: +//│ ReferenceError: Test01 is not defined + + diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 9980788a61..9710b846d3 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -107,7 +107,11 @@ mixin Foo { //│ fun test: (int & 'a) -> (int, 'a, 'misc,) //│ } +:e module Base1(base: int, misc: string) extends Foo +//│ ╔══[ERROR] module parameters are not supported +//│ ║ l.111: module Base1(base: int, misc: string) extends Foo +//│ ╙── ^^^^^^^^^^^^^^^ //│ module Base1(base: int, misc: string) { //│ fun test: (int & 'a) -> (int, 'a, string,) //│ } @@ -175,16 +179,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.176: WrapBase1.wrapA("ok") +//│ ║ l.180: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.176: WrapBase1.wrapA("ok") +//│ ║ l.180: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.122: fun wrapA(x: int) = x : int +//│ ║ l.126: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.132: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.136: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error diff --git a/shared/src/test/diff/nu/ModuleParameters.mls b/shared/src/test/diff/nu/ModuleParameters.mls new file mode 100644 index 0000000000..90caa3bb8b --- /dev/null +++ b/shared/src/test/diff/nu/ModuleParameters.mls @@ -0,0 +1,30 @@ +:NewParser +:NewDefs + + +// FIXME +module A(x: int) { fun y = x } +//│ ╔══[ERROR] module parameters are not supported +//│ ║ l.6: module A(x: int) { fun y = x } +//│ ╙── ^ +//│ module A(x: int) { +//│ fun y: int +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol x + +:re +A.x +//│ int +//│ res +//│ Runtime error: +//│ ReferenceError: A is not defined + +:re +A.y +//│ int +//│ res +//│ Runtime error: +//│ ReferenceError: A is not defined + + diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index cc7364bd78..e595113d21 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -220,6 +220,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num //│ res //│ = Var { s: 'a' } +// * Incorrect version, for regression testing module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { //│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> ('a | 'result) @@ -229,15 +230,15 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr //│ 'a <: Add['b] | Mul['b] | Num | Var //│ 'b <: 'a -// Because EvalExpr does not dispatch lambdas to super and map_expr only -// handles exprs +// * Because EvalExpr does not dispatch lambdas to super and map_expr only +// * handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.236: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.235: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.236: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.129: if v is diff --git a/shared/src/test/diff/nu/Super.mls b/shared/src/test/diff/nu/ParamPassing.mls similarity index 100% rename from shared/src/test/diff/nu/Super.mls rename to shared/src/test/diff/nu/ParamPassing.mls From aadd62f724b50afb43f4fdebb57ab6d35d73a7e6 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 17:56:56 +0800 Subject: [PATCH 146/498] Fix parser regression that changed other tests' outputs --- shared/src/main/scala/mlscript/NewParser.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 7dd34e4cd0..4e31f3b4d6 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -294,7 +294,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } ts */ - rec(toks, S(br.innerLoc), br.describe).concludeWith(_.maybeIndented(_.typeParams)) + rec(toks, S(br.innerLoc), br.describe).concludeWith(_.maybeIndented((p, _) => p.typeParams)) case _ => Nil } val params = yeetSpaces match { @@ -889,19 +889,19 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } - final def maybeIndented[R](f: NewParser => R)(implicit fe: FoundErr, et: ExpectThen): R = + final def maybeIndented[R](f: (NewParser, Bool) => R)(implicit fe: FoundErr, et: ExpectThen): R = cur match { case (br @ BRACKETS(Indent, toks), _) :: _ if (toks.headOption match { case S((KEYWORD("then" | "else"), _)) => false case _ => true }) => consume - rec(toks, S(br.innerLoc), br.describe).concludeWith(f) - case _ => f(this) + rec(toks, S(br.innerLoc), br.describe).concludeWith(f(_, true)) + case _ => f(this, false) } final def argsMaybeIndented()(implicit fe: FoundErr, et: ExpectThen): Ls[Opt[Var] -> Fld] = - maybeIndented(_.args(true)) + maybeIndented(_.args(_)) // final def argsMaybeIndented()(implicit fe: FoundErr, et: ExpectThen): Ls[Opt[Var] -> Fld] = // cur match { // case (br @ BRACKETS(Indent, toks), _) :: _ if (toks.headOption match { From 368199d8943930562691fd169c81f7f23bb6f319 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 20:23:07 +0800 Subject: [PATCH 147/498] WIP: Fix syntax error swallowed --- shared/src/test/diff/codegen/Super.mls | 46 ++----- .../src/test/scala/mlscript/DiffTests.scala | 115 ++++++++++-------- 2 files changed, 73 insertions(+), 88 deletions(-) diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 4c59762680..e5dcedb93e 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -94,10 +94,9 @@ module Test0 extends Foo0, Foo1 //│ = [ 1, 0 ] -// FIXME some errors are currently swallowed! - :ShowRepl :js +:ge mixin Foo2 { fun foo2 = super } @@ -131,35 +130,8 @@ mixin Foo2 { //│ }; //│ globalThis.Foo2 = typing_unit4.Foo2; //│ // End of generated code -//│ ┌ Block at Super.mls:101 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit4 = { -//│ │ │ cache: {}, -//│ │ │ Foo2(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class Foo2 { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ get foo2() { -//│ │ │ return super; -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class Foo2 extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ get foo2() { -//│ │ │ return super; -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.Foo2 = typing_unit4.Foo2; -//│ │ └── Reply [syntax error] 'super' keyword unexpected here -//│ └── No queries +//│ Syntax error: +//│ 'super' keyword unexpected here :ShowRepl :js @@ -173,8 +145,8 @@ module Test0 extends Foo2 //│ get Test01() { //│ if (this.cache.Test01 === undefined) { //│ class Test01 extends Foo2() { -//│ constructor(...rest) { -//│ super(...rest); +//│ constructor() { +//│ super(); //│ } //│ } //│ this.cache.Test01 = new Test01(); @@ -185,7 +157,7 @@ module Test0 extends Foo2 //│ }; //│ globalThis.Test01 = typing_unit5.Test01; //│ // End of generated code -//│ ┌ Block at Super.mls:166 +//│ ┌ Block at Super.mls:138 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit5 = { @@ -193,8 +165,8 @@ module Test0 extends Foo2 //│ │ │ get Test01() { //│ │ │ if (this.cache.Test01 === undefined) { //│ │ │ class Test01 extends Foo2() { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); +//│ │ │ constructor() { +//│ │ │ super(); //│ │ │ } //│ │ │ } //│ │ │ this.cache.Test01 = new Test01(); @@ -206,7 +178,7 @@ module Test0 extends Foo2 //│ │ │ globalThis.Test01 = typing_unit5.Test01; //│ │ └── Reply //│ │ Uncaught ReferenceError: Foo2 is not defined -//│ │ at get Test01 [as Test01] (REPL9:1:78) +//│ │ at Object.get Test01 [as Test01] (REPL9:1:78) //│ └── No queries :re diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 09ee6cc7a5..f28d25919e 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -839,15 +839,21 @@ class DiffTests // Execute code. if (!mode.noExecution) { val preludeReply = if (prelude.isEmpty) N else S(host.execute(prelude.mkString(" "))) - if (mode.showRepl) showReplPrelude(prelude, preludeReply, blockLineNum) - val replies = queries.map { - case CodeQuery(preludeLines, codeLines, resultName) => - host.query(preludeLines.mkString, codeLines.mkString, resultName) - case AbortedQuery(reason) => (ReplHost.Unexecuted(reason), "") - case EmptyQuery => (ReplHost.Empty, "") + preludeReply match { + case S(ue: ReplHost.Unexecuted) => R((ue, "") :: Nil) + case S(err: ReplHost.Error) => R((err, "") :: Nil) + case _ => { + if (mode.showRepl) showReplPrelude(prelude, preludeReply, blockLineNum) + val replies = queries.map { + case CodeQuery(preludeLines, codeLines, resultName) => + host.query(preludeLines.mkString, codeLines.mkString, resultName) + case AbortedQuery(reason) => (ReplHost.Unexecuted(reason), "") + case EmptyQuery => (ReplHost.Empty, "") + } + if (mode.showRepl) showReplContent(queries, replies) + R(replies) + } } - if (mode.showRepl) showReplContent(queries, replies) - R(replies) } else { L(ResultNotExecuted) } @@ -865,55 +871,62 @@ class DiffTests loglines.foreach(output) } } + + def checkReply(replyQueue: mutable.Queue[(ReplHost.Reply, Str)], prefixLength: Int): Unit = + replyQueue.headOption.foreach { case (head, log) => + head match { + case ReplHost.Error(isSyntaxError, content) => + // We don't expect type errors nor FIXME. + if (!mode.expectTypeErrors && !mode.fixme) { + // We don't expect code generation errors and it is. + if (!mode.expectCodeGenErrors && isSyntaxError) + failures += blockLineNum + // We don't expect runtime errors and it's a runtime error. + if (!mode.expectRuntimeErrors && !allowRuntimeErrors && !isSyntaxError) + failures += blockLineNum + } + if (isSyntaxError) { + // If there is syntax error in the generated code, + // it should be a code generation error. + output("Syntax error:") + totalCodeGenErrors += 1 + } else { // Otherwise, it is a runtime error. + output("Runtime error:") + totalRuntimeErrors += 1 + } + content.linesIterator.foreach { s => output(" " + s) } + case ReplHost.Unexecuted(reason) => + output(" " * prefixLength + "= ") + output(" " * (prefixLength + 2) + reason) + case ReplHost.Result(result, _) => + result.linesIterator.zipWithIndex.foreach { case (line, i) => + if (i =:= 0) output(" " * prefixLength + "= " + line) + else output(" " * (prefixLength + 2) + line) + } + case ReplHost.Empty => + output(" " * prefixLength + "= ") + } + outputLog(log) + replyQueue.dequeue() + } // If code generation fails, show the error message. executionResults match { case R(replies) => val replyQueue = mutable.Queue.from(replies) - typerResults.foreach { case (name, typingLines, diagnosticLines, typeBeforeDiags) => - if (typeBeforeDiags) { - typingLines.foreach(output) - diagnosticLines.foreach(output) - } else { - diagnosticLines.foreach(output) - typingLines.foreach(output) - } - val prefixLength = name.length - replyQueue.headOption.foreach { case (head, log) => - head match { - case ReplHost.Error(isSyntaxError, content) => - // We don't expect type errors nor FIXME. - if (!mode.expectTypeErrors && !mode.fixme) { - // We don't expect code generation errors and it is. - if (!mode.expectCodeGenErrors && isSyntaxError) - failures += blockLineNum - // We don't expect runtime errors and it's a runtime error. - if (!mode.expectRuntimeErrors && !allowRuntimeErrors && !isSyntaxError) - failures += blockLineNum - } - if (isSyntaxError) { - // If there is syntax error in the generated code, - // it should be a code generation error. - output("Syntax error:") - totalCodeGenErrors += 1 - } else { // Otherwise, it is a runtime error. - output("Runtime error:") - totalRuntimeErrors += 1 - } - content.linesIterator.foreach { s => output(" " + s) } - case ReplHost.Unexecuted(reason) => - output(" " * prefixLength + "= ") - output(" " * (prefixLength + 2) + reason) - case ReplHost.Result(result, _) => - result.linesIterator.zipWithIndex.foreach { case (line, i) => - if (i =:= 0) output(" " * prefixLength + "= " + line) - else output(" " * (prefixLength + 2) + line) - } - case ReplHost.Empty => - output(" " * prefixLength + "= ") + if (typerResults.isEmpty) + checkReply(replyQueue, 0) + else { + typerResults.foreach { case (name, typingLines, diagnosticLines, typeBeforeDiags) => + if (typeBeforeDiags) { + typingLines.foreach(output) + diagnosticLines.foreach(output) + } else { + diagnosticLines.foreach(output) + typingLines.foreach(output) } - outputLog(log) - replyQueue.dequeue() + val prefixLength = name.length + checkReply(replyQueue, prefixLength) } } case L(other) => From dbee9bb99348b000ceb128abc9e4da92cd772246 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 20:27:46 +0800 Subject: [PATCH 148/498] WIP: Ignore trival output --- shared/src/test/scala/mlscript/DiffTests.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index f28d25919e..0c825266a0 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -872,7 +872,7 @@ class DiffTests } } - def checkReply(replyQueue: mutable.Queue[(ReplHost.Reply, Str)], prefixLength: Int): Unit = + def checkReply(replyQueue: mutable.Queue[(ReplHost.Reply, Str)], prefixLength: Int, errorOnly: Boolean = false): Unit = replyQueue.headOption.foreach { case (head, log) => head match { case ReplHost.Error(isSyntaxError, content) => @@ -898,13 +898,14 @@ class DiffTests case ReplHost.Unexecuted(reason) => output(" " * prefixLength + "= ") output(" " * (prefixLength + 2) + reason) - case ReplHost.Result(result, _) => + case ReplHost.Result(result, _) if (!errorOnly) => result.linesIterator.zipWithIndex.foreach { case (line, i) => if (i =:= 0) output(" " * prefixLength + "= " + line) else output(" " * (prefixLength + 2) + line) } - case ReplHost.Empty => + case ReplHost.Empty if (!errorOnly) => output(" " * prefixLength + "= ") + case _ => () } outputLog(log) replyQueue.dequeue() @@ -915,7 +916,7 @@ class DiffTests case R(replies) => val replyQueue = mutable.Queue.from(replies) if (typerResults.isEmpty) - checkReply(replyQueue, 0) + checkReply(replyQueue, 0, true) else { typerResults.foreach { case (name, typingLines, diagnosticLines, typeBeforeDiags) => if (typeBeforeDiags) { From 99f722b54ec30b97648b34e05dba7db80e9e28b5 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 20:37:58 +0800 Subject: [PATCH 149/498] WIP: Fix some test files --- shared/src/test/diff/nu/ModuleParameters.mls | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/shared/src/test/diff/nu/ModuleParameters.mls b/shared/src/test/diff/nu/ModuleParameters.mls index 90caa3bb8b..960f3be435 100644 --- a/shared/src/test/diff/nu/ModuleParameters.mls +++ b/shared/src/test/diff/nu/ModuleParameters.mls @@ -10,21 +10,15 @@ module A(x: int) { fun y = x } //│ module A(x: int) { //│ fun y: int //│ } -//│ Code generation encountered an error: -//│ unresolved symbol x -:re A.x //│ int //│ res -//│ Runtime error: -//│ ReferenceError: A is not defined +//│ = undefined -:re A.y //│ int //│ res -//│ Runtime error: -//│ ReferenceError: A is not defined +//│ = undefined From fb2db16baafc9c47ac8845763f1e5339f3d2d0e5 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 20:42:06 +0800 Subject: [PATCH 150/498] WIP: Add private fields --- .../main/scala/mlscript/codegen/Codegen.scala | 9 +++- shared/src/test/diff/codegen/Mixin.mls | 52 ++++++++++++++----- shared/src/test/diff/nu/ParamOverride.mls | 6 +-- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 64f212e8b3..9dbbc5395d 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -845,6 +845,11 @@ final case class JSClassNewDecl( })((p, s) => if (s.isEmpty) s"${p._1}" else s"${p._1}, $s") + if (!fields.isEmpty) + buffer += fields.iterator.zipWithIndex.foldLeft("")((res, f) => + if (f._2 === fields.length - 1) s"$res #${f._1};" + else s"$res #${f._1};\n" + ) buffer += s" constructor($params) {" if (`extends`.isDefined) { val sf = superFields.iterator.zipWithIndex.foldLeft("")((res, p) => @@ -858,7 +863,9 @@ final case class JSClassNewDecl( } fields.iterator.zipWithIndex.foreach { pair => val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" - buffer += s" this${innerName} = ${pair._1};" // TODO: invalid name? + val privateName = if (JSField.isValidIdentifier(pair._1)) s".#${pair._1}" else s"[#${JSLit.makeStringLiteral(pair._1)}]" + buffer += s" this${innerName} = ${pair._1};" + buffer += s" this${privateName} = ${pair._1};" // TODO: invalid name? } buffer += " }" SourceCode(buffer.toList) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 6b2778a8fe..0d02b9a8e2 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -14,9 +14,13 @@ class Lit(n: int) //│ get Add() { //│ if (this.cache.Add === undefined) { //│ class Add { +//│ #lhs; +//│ #rhs; //│ constructor(lhs, rhs) { //│ this.lhs = lhs; +//│ this.#lhs = lhs; //│ this.rhs = rhs; +//│ this.#rhs = rhs; //│ } //│ }; //│ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); @@ -27,8 +31,10 @@ class Lit(n: int) //│ get Lit() { //│ if (this.cache.Lit === undefined) { //│ class Lit { +//│ #n; //│ constructor(n) { //│ this.n = n; +//│ this.#n = n; //│ } //│ }; //│ this.cache.Lit = ((n) => new Lit(n)); @@ -49,9 +55,13 @@ class Lit(n: int) //│ │ │ get Add() { //│ │ │ if (this.cache.Add === undefined) { //│ │ │ class Add { +//│ │ │ #lhs; +//│ #rhs; //│ │ │ constructor(lhs, rhs) { //│ │ │ this.lhs = lhs; +//│ │ │ this.#lhs = lhs; //│ │ │ this.rhs = rhs; +//│ │ │ this.#rhs = rhs; //│ │ │ } //│ │ │ }; //│ │ │ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); @@ -62,8 +72,10 @@ class Lit(n: int) //│ │ │ get Lit() { //│ │ │ if (this.cache.Lit === undefined) { //│ │ │ class Lit { +//│ │ │ #n; //│ │ │ constructor(n) { //│ │ │ this.n = n; +//│ │ │ this.#n = n; //│ │ │ } //│ │ │ }; //│ │ │ this.cache.Lit = ((n) => new Lit(n)); @@ -75,7 +87,7 @@ class Lit(n: int) //│ │ │ globalThis.Add = typing_unit.Add; //│ │ │ globalThis.Lit = typing_unit.Lit; //│ │ └── Reply -//│ │ [Function (anonymous)] { class: [class Lit] } +//│ │ ... [Function (anonymous)] { class: [class Lit] } //│ └── No queries :js @@ -128,7 +140,7 @@ mixin EvalBase { //│ }; //│ globalThis.EvalBase = typing_unit1.EvalBase; //│ // End of generated code -//│ ┌ Block at Mixin.mls:83 +//│ ┌ Block at Mixin.mls:99 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit1 = { @@ -181,8 +193,10 @@ class Neg(expr: A) //│ get Neg() { //│ if (this.cache.Neg === undefined) { //│ class Neg { +//│ #expr; //│ constructor(expr) { //│ this.expr = expr; +//│ this.#expr = expr; //│ } //│ }; //│ this.cache.Neg = ((expr) => new Neg(expr)); @@ -193,7 +207,7 @@ class Neg(expr: A) //│ }; //│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:176 +//│ ┌ Block at Mixin.mls:192 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit2 = { @@ -201,8 +215,10 @@ class Neg(expr: A) //│ │ │ get Neg() { //│ │ │ if (this.cache.Neg === undefined) { //│ │ │ class Neg { +//│ │ │ #expr; //│ │ │ constructor(expr) { //│ │ │ this.expr = expr; +//│ │ │ this.#expr = expr; //│ │ │ } //│ │ │ }; //│ │ │ this.cache.Neg = ((expr) => new Neg(expr)); @@ -260,7 +276,7 @@ mixin EvalNeg { //│ }; //│ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:221 +//│ ┌ Block at Mixin.mls:243 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit3 = { @@ -341,7 +357,7 @@ mixin EvalNegNeg { //│ }; //│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:302 +//│ ┌ Block at Mixin.mls:324 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit4 = { @@ -405,7 +421,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ }; //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code -//│ ┌ Block at Mixin.mls:383 +//│ ┌ Block at Mixin.mls:405 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit5 = { @@ -448,7 +464,7 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:433 +//│ ┌ Block at Mixin.mls:455 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit6 = { cache: {} }; @@ -479,7 +495,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.480: class Bar(x: int, y: int) extends Foo(x + y) +//│ ║ l.502: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -498,14 +514,14 @@ class C(x: int) extends BB :e class D(x: int) extends AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.499: class D(x: int) extends AA(x) +//│ ║ l.521: class D(x: int) extends AA(x) //│ ╙── ^^^^^ //│ class D(x: int) :e class E(x: int) extends BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.506: class E(x: int) extends BB, AA(x) +//│ ║ l.528: class E(x: int) extends BB, AA(x) //│ ╙── ^^^^^ //│ class E(x: int) @@ -518,15 +534,19 @@ mixin Fooo(x: int) //│ Fooo(base) { //│ if (base === undefined) { //│ return (class Fooo { +//│ #x; //│ constructor(x) { //│ this.x = x; +//│ this.#x = x; //│ } //│ }); //│ } else { //│ return (class Fooo extends base { +//│ #x; //│ constructor(x, ...rest) { //│ super(...rest); //│ this.x = x; +//│ this.#x = x; //│ } //│ }); //│ } @@ -544,15 +564,19 @@ mixin Bazz(y: int) //│ Bazz(base) { //│ if (base === undefined) { //│ return (class Bazz { +//│ #y; //│ constructor(y) { //│ this.y = y; +//│ this.#y = y; //│ } //│ }); //│ } else { //│ return (class Bazz extends base { +//│ #y; //│ constructor(y, ...rest) { //│ super(...rest); //│ this.y = y; +//│ this.#y = y; //│ } //│ }); //│ } @@ -565,10 +589,10 @@ mixin Bazz(y: int) :e // TODO: type check module Barr extends Fooo(0), Bazz(1) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.566: module Barr extends Fooo(0), Bazz(1) +//│ ║ l.600: module Barr extends Fooo(0), Bazz(1) //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.566: module Barr extends Fooo(0), Bazz(1) +//│ ║ l.600: module Barr extends Fooo(0), Bazz(1) //│ ╙── ^^^^^^^ //│ module Barr() //│ // Prelude @@ -593,7 +617,7 @@ module Barr extends Fooo(0), Bazz(1) :e Barr.x //│ ╔══[ERROR] module `Barr` does not contain member `x` -//│ ║ l.594: Barr.x +//│ ║ l.628: Barr.x //│ ╙── ^^ //│ error //│ res @@ -602,7 +626,7 @@ Barr.x :e Barr.y //│ ╔══[ERROR] module `Barr` does not contain member `y` -//│ ║ l.603: Barr.y +//│ ║ l.637: Barr.y //│ ╙── ^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index d438307451..00301a2b3b 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -49,7 +49,7 @@ class Test0 extends Base1(0), Derived1(1) // TODO let t = Test0() //│ let t: Test0 //│ t -//│ = Test0 { n: 1 } +//│ = Test0 { n: 0 } // TODO type check t.n @@ -58,7 +58,7 @@ t.n //│ ╙── ^^ //│ error //│ res -//│ = 1 +//│ = 0 // TODO type check // FIXME super access to field? @@ -68,7 +68,7 @@ t.foo //│ ╙── ^^^^ //│ error //│ res -//│ = [ 1, undefined ] +//│ = [ 0, undefined ] // TODO correct module code-gen From 008b06b2e175f6a3fa8b4697480ee4dec057dab3 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 20:42:43 +0800 Subject: [PATCH 151/498] WIP: rerun tests --- shared/src/test/diff/codegen/Mixin.mls | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 0d02b9a8e2..fdb3ca2b88 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -140,7 +140,7 @@ mixin EvalBase { //│ }; //│ globalThis.EvalBase = typing_unit1.EvalBase; //│ // End of generated code -//│ ┌ Block at Mixin.mls:99 +//│ ┌ Block at Mixin.mls:95 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit1 = { @@ -207,7 +207,7 @@ class Neg(expr: A) //│ }; //│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:192 +//│ ┌ Block at Mixin.mls:188 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit2 = { @@ -276,7 +276,7 @@ mixin EvalNeg { //│ }; //│ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:243 +//│ ┌ Block at Mixin.mls:237 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit3 = { @@ -357,7 +357,7 @@ mixin EvalNegNeg { //│ }; //│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:324 +//│ ┌ Block at Mixin.mls:318 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit4 = { @@ -421,7 +421,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ }; //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code -//│ ┌ Block at Mixin.mls:405 +//│ ┌ Block at Mixin.mls:399 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit5 = { @@ -464,7 +464,7 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:455 +//│ ┌ Block at Mixin.mls:449 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit6 = { cache: {} }; @@ -495,7 +495,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.502: class Bar(x: int, y: int) extends Foo(x + y) +//│ ║ l.496: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -514,14 +514,14 @@ class C(x: int) extends BB :e class D(x: int) extends AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.521: class D(x: int) extends AA(x) +//│ ║ l.515: class D(x: int) extends AA(x) //│ ╙── ^^^^^ //│ class D(x: int) :e class E(x: int) extends BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.528: class E(x: int) extends BB, AA(x) +//│ ║ l.522: class E(x: int) extends BB, AA(x) //│ ╙── ^^^^^ //│ class E(x: int) @@ -589,10 +589,10 @@ mixin Bazz(y: int) :e // TODO: type check module Barr extends Fooo(0), Bazz(1) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.600: module Barr extends Fooo(0), Bazz(1) +//│ ║ l.590: module Barr extends Fooo(0), Bazz(1) //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.600: module Barr extends Fooo(0), Bazz(1) +//│ ║ l.590: module Barr extends Fooo(0), Bazz(1) //│ ╙── ^^^^^^^ //│ module Barr() //│ // Prelude @@ -617,7 +617,7 @@ module Barr extends Fooo(0), Bazz(1) :e Barr.x //│ ╔══[ERROR] module `Barr` does not contain member `x` -//│ ║ l.628: Barr.x +//│ ║ l.618: Barr.x //│ ╙── ^^ //│ error //│ res @@ -626,7 +626,7 @@ Barr.x :e Barr.y //│ ╔══[ERROR] module `Barr` does not contain member `y` -//│ ║ l.637: Barr.y +//│ ║ l.627: Barr.y //│ ╙── ^^ //│ error //│ res From 40822523fe07565de46724cfba079032b33f259a Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Wed, 8 Mar 2023 22:29:12 +0800 Subject: [PATCH 152/498] Update shared/src/test/diff/codegen/Super.mls Co-authored-by: Lionel Parreaux --- shared/src/test/diff/codegen/Super.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index e5dcedb93e..da49eb91d5 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -96,7 +96,7 @@ module Test0 extends Foo0, Foo1 :ShowRepl :js -:ge +// FIXME prevent misuse of `super` using the type system mixin Foo2 { fun foo2 = super } From f843520686256cb74163ba76913e1a16819b5214 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 23:00:10 +0800 Subject: [PATCH 153/498] WIP: Use default Object base class instead --- .../src/main/scala/mlscript/JSBackend.scala | 9 +- shared/src/test/diff/codegen/Mixin.mls | 306 ++++++------------ shared/src/test/diff/codegen/Super.mls | 93 ++---- 3 files changed, 134 insertions(+), 274 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 0ef51c1171..1d5243d515 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -469,11 +469,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val classBody = JSClassNewDecl(mixinSymbol.runtimeName, fields, S(JSIdent(base.runtimeName)), Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, traits) - val baseClassBody = JSClassNewDecl(mixinSymbol.runtimeName, fields, N, - Ls(), N, members, traits) JSClassMethod(mixinSymbol.lexicalName, Ls(JSNamePattern(base.runtimeName)), R(Ls( - JSIfStmt(JSBinary("===", JSIdent(base.runtimeName), JSIdent("undefined")), - Ls(JSReturnStmt(S(JSClassExpr(baseClassBody)))), Ls(JSReturnStmt(S(JSClassExpr(classBody))))) + JSReturnStmt(S(JSClassExpr(classBody))) ))) } @@ -487,12 +484,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case head :: tail => tail.foldLeft( head match { case Some(JSIdent(nme)) => scope.resolveValue(nme) match { - case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) + case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls(JSIdent("Object")))) case Some(_) => Some(JSMember(JSIdent(nme), JSLit(JSLit.makeStringLiteral("class")))) case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") } case Some(JSInvoke(JSIdent(nme), _)) => scope.resolveValue(nme) match { - case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls())) + case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls(JSIdent("Object")))) case Some(_) => Some(JSMember(JSIdent(nme), JSLit(JSLit.makeStringLiteral("class")))) case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") } diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index fdb3ca2b88..422a8eddbe 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -106,36 +106,20 @@ mixin EvalBase { //│ let typing_unit1 = { //│ cache: {}, //│ EvalBase(base) { -//│ if (base === undefined) { -//│ return (class EvalBase { -//│ constructor() { -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalBase extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ let a; -//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); +//│ return (class EvalBase extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ throw new Error("non-exhaustive case expression"); //│ })()); -//│ } -//│ }); -//│ } +//│ })()); +//│ } +//│ }); //│ } //│ }; //│ globalThis.EvalBase = typing_unit1.EvalBase; @@ -146,36 +130,20 @@ mixin EvalBase { //│ │ │ let typing_unit1 = { //│ │ │ cache: {}, //│ │ │ EvalBase(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class EvalBase { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ let a; -//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ │ │ throw new Error("non-exhaustive case expression"); -//│ │ │ })()); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class EvalBase extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ let a; -//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { -//│ │ │ throw new Error("non-exhaustive case expression"); -//│ │ │ })()); +//│ │ │ return (class EvalBase extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ let a; +//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ │ │ throw new Error("non-exhaustive case expression"); //│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); //│ │ │ } //│ │ │ }; //│ │ │ globalThis.EvalBase = typing_unit1.EvalBase; @@ -207,7 +175,7 @@ class Neg(expr: A) //│ }; //│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:188 +//│ ┌ Block at Mixin.mls:156 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit2 = { @@ -248,64 +216,38 @@ mixin EvalNeg { //│ let typing_unit3 = { //│ cache: {}, //│ EvalNeg(base) { -//│ if (base === undefined) { -//│ return (class EvalNeg { -//│ constructor() { -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } +//│ return (class EvalNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); //│ } //│ }; //│ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:237 +//│ ┌ Block at Mixin.mls:205 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit3 = { //│ │ │ cache: {}, //│ │ │ EvalNeg(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class EvalNeg { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class EvalNeg extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } +//│ │ │ return (class EvalNeg extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); //│ │ │ } //│ │ │ }; //│ │ │ globalThis.EvalNeg = typing_unit3.EvalNeg; @@ -329,64 +271,38 @@ mixin EvalNegNeg { //│ let typing_unit4 = { //│ cache: {}, //│ EvalNegNeg(base) { -//│ if (base === undefined) { -//│ return (class EvalNegNeg { -//│ constructor() { -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } else { -//│ return (class EvalNegNeg extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ eval(e) { -//│ const self = this; -//│ return ((() => { -//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ })()); -//│ } -//│ }); -//│ } +//│ return (class EvalNegNeg extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ const self = this; +//│ return ((() => { +//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ })()); +//│ } +//│ }); //│ } //│ }; //│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:318 +//│ ┌ Block at Mixin.mls:260 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit4 = { //│ │ │ cache: {}, //│ │ │ EvalNegNeg(base) { -//│ │ │ if (base === undefined) { -//│ │ │ return (class EvalNegNeg { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } else { -//│ │ │ return (class EvalNegNeg extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const self = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } +//│ │ │ return (class EvalNegNeg extends base { +//│ │ │ constructor(...rest) { +//│ │ │ super(...rest); +//│ │ │ } +//│ │ │ eval(e) { +//│ │ │ const self = this; +//│ │ │ return ((() => { +//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ │ │ })()); +//│ │ │ } +//│ │ │ }); //│ │ │ } //│ │ │ }; //│ │ │ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; @@ -408,7 +324,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ cache: {}, //│ get TestLang() { //│ if (this.cache.TestLang === undefined) { -//│ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { +//│ class TestLang extends EvalNegNeg(EvalNeg(EvalBase(Object))) { //│ constructor() { //│ super(); //│ } @@ -421,14 +337,14 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ }; //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code -//│ ┌ Block at Mixin.mls:399 +//│ ┌ Block at Mixin.mls:315 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit5 = { //│ │ │ cache: {}, //│ │ │ get TestLang() { //│ │ │ if (this.cache.TestLang === undefined) { -//│ │ │ class TestLang extends EvalNegNeg(EvalNeg(EvalBase())) { +//│ │ │ class TestLang extends EvalNegNeg(EvalNeg(EvalBase(Object))) { //│ │ │ constructor() { //│ │ │ super(); //│ │ │ } @@ -464,7 +380,7 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:449 +//│ ┌ Block at Mixin.mls:365 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit6 = { cache: {} }; @@ -495,7 +411,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.496: class Bar(x: int, y: int) extends Foo(x + y) +//│ ║ l.412: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -514,14 +430,14 @@ class C(x: int) extends BB :e class D(x: int) extends AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.515: class D(x: int) extends AA(x) +//│ ║ l.431: class D(x: int) extends AA(x) //│ ╙── ^^^^^ //│ class D(x: int) :e class E(x: int) extends BB, AA(x) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.522: class E(x: int) extends BB, AA(x) +//│ ║ l.438: class E(x: int) extends BB, AA(x) //│ ╙── ^^^^^ //│ class E(x: int) @@ -532,24 +448,14 @@ mixin Fooo(x: int) //│ let typing_unit14 = { //│ cache: {}, //│ Fooo(base) { -//│ if (base === undefined) { -//│ return (class Fooo { -//│ #x; -//│ constructor(x) { -//│ this.x = x; -//│ this.#x = x; -//│ } -//│ }); -//│ } else { -//│ return (class Fooo extends base { -//│ #x; -//│ constructor(x, ...rest) { -//│ super(...rest); -//│ this.x = x; -//│ this.#x = x; -//│ } -//│ }); -//│ } +//│ return (class Fooo extends base { +//│ #x; +//│ constructor(x, ...rest) { +//│ super(...rest); +//│ this.x = x; +//│ this.#x = x; +//│ } +//│ }); //│ } //│ }; //│ globalThis.Fooo = typing_unit14.Fooo; @@ -562,24 +468,14 @@ mixin Bazz(y: int) //│ let typing_unit15 = { //│ cache: {}, //│ Bazz(base) { -//│ if (base === undefined) { -//│ return (class Bazz { -//│ #y; -//│ constructor(y) { -//│ this.y = y; -//│ this.#y = y; -//│ } -//│ }); -//│ } else { -//│ return (class Bazz extends base { -//│ #y; -//│ constructor(y, ...rest) { -//│ super(...rest); -//│ this.y = y; -//│ this.#y = y; -//│ } -//│ }); -//│ } +//│ return (class Bazz extends base { +//│ #y; +//│ constructor(y, ...rest) { +//│ super(...rest); +//│ this.y = y; +//│ this.#y = y; +//│ } +//│ }); //│ } //│ }; //│ globalThis.Bazz = typing_unit15.Bazz; @@ -589,10 +485,10 @@ mixin Bazz(y: int) :e // TODO: type check module Barr extends Fooo(0), Bazz(1) //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.590: module Barr extends Fooo(0), Bazz(1) +//│ ║ l.486: module Barr extends Fooo(0), Bazz(1) //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.590: module Barr extends Fooo(0), Bazz(1) +//│ ║ l.486: module Barr extends Fooo(0), Bazz(1) //│ ╙── ^^^^^^^ //│ module Barr() //│ // Prelude @@ -600,7 +496,7 @@ module Barr extends Fooo(0), Bazz(1) //│ cache: {}, //│ get Barr() { //│ if (this.cache.Barr === undefined) { -//│ class Barr extends Bazz(Fooo()) { +//│ class Barr extends Bazz(Fooo(Object)) { //│ constructor() { //│ super(1, 0); //│ } @@ -617,7 +513,7 @@ module Barr extends Fooo(0), Bazz(1) :e Barr.x //│ ╔══[ERROR] module `Barr` does not contain member `x` -//│ ║ l.618: Barr.x +//│ ║ l.514: Barr.x //│ ╙── ^^ //│ error //│ res @@ -626,7 +522,7 @@ Barr.x :e Barr.y //│ ╔══[ERROR] module `Barr` does not contain member `y` -//│ ║ l.627: Barr.y +//│ ║ l.523: Barr.y //│ ╙── ^^ //│ error //│ res diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index da49eb91d5..52e8863c24 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -16,24 +16,14 @@ mixin Foo0 { //│ let typing_unit = { //│ cache: {}, //│ Foo0(base) { -//│ if (base === undefined) { -//│ return (class Foo0 { -//│ constructor() { -//│ } -//│ get foo0() { -//│ return 0; -//│ } -//│ }); -//│ } else { -//│ return (class Foo0 extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ get foo0() { -//│ return 0; -//│ } -//│ }); -//│ } +//│ return (class Foo0 extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ get foo0() { +//│ return 0; +//│ } +//│ }); //│ } //│ }; //│ globalThis.Foo0 = typing_unit.Foo0; @@ -53,30 +43,17 @@ mixin Foo1 { //│ let typing_unit1 = { //│ cache: {}, //│ Foo1(base) { -//│ if (base === undefined) { -//│ return (class Foo1 { -//│ constructor() { -//│ } -//│ get foo0() { -//│ return 1; -//│ } -//│ get foo1() { -//│ return super.foo0; -//│ } -//│ }); -//│ } else { -//│ return (class Foo1 extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ get foo0() { -//│ return 1; -//│ } -//│ get foo1() { -//│ return super.foo0; -//│ } -//│ }); -//│ } +//│ return (class Foo1 extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ get foo0() { +//│ return 1; +//│ } +//│ get foo1() { +//│ return super.foo0; +//│ } +//│ }); //│ } //│ }; //│ globalThis.Foo1 = typing_unit1.Foo1; @@ -108,24 +85,14 @@ mixin Foo2 { //│ let typing_unit4 = { //│ cache: {}, //│ Foo2(base) { -//│ if (base === undefined) { -//│ return (class Foo2 { -//│ constructor() { -//│ } -//│ get foo2() { -//│ return super; -//│ } -//│ }); -//│ } else { -//│ return (class Foo2 extends base { -//│ constructor(...rest) { -//│ super(...rest); -//│ } -//│ get foo2() { -//│ return super; -//│ } -//│ }); -//│ } +//│ return (class Foo2 extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ get foo2() { +//│ return super; +//│ } +//│ }); //│ } //│ }; //│ globalThis.Foo2 = typing_unit4.Foo2; @@ -144,7 +111,7 @@ module Test0 extends Foo2 //│ cache: {}, //│ get Test01() { //│ if (this.cache.Test01 === undefined) { -//│ class Test01 extends Foo2() { +//│ class Test01 extends Foo2(Object) { //│ constructor() { //│ super(); //│ } @@ -157,14 +124,14 @@ module Test0 extends Foo2 //│ }; //│ globalThis.Test01 = typing_unit5.Test01; //│ // End of generated code -//│ ┌ Block at Super.mls:138 +//│ ┌ Block at Super.mls:105 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit5 = { //│ │ │ cache: {}, //│ │ │ get Test01() { //│ │ │ if (this.cache.Test01 === undefined) { -//│ │ │ class Test01 extends Foo2() { +//│ │ │ class Test01 extends Foo2(Object) { //│ │ │ constructor() { //│ │ │ super(); //│ │ │ } From 561c425b12a284b1c4751fe44ed6bf5fcfcddb9c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 23:00:20 +0800 Subject: [PATCH 154/498] WIP Implement mixin parameter type checking --- .../src/main/scala/mlscript/NuTypeDefs.scala | 25 ++- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 175 +++++++----------- .../main/scala/mlscript/TyperHelpers.scala | 4 +- shared/src/main/scala/mlscript/helpers.scala | 3 +- shared/src/test/diff/codegen/Mixin.mls | 36 +--- shared/src/test/diff/codegen/Super.mls | 2 +- shared/src/test/diff/nu/BadClasses.mls | 36 ++++ .../test/diff/nu/BasicClassInheritance.mls | 2 +- shared/src/test/diff/nu/GenericMixins.mls | 8 +- shared/src/test/diff/nu/MixinParameters.mls | 4 +- shared/src/test/diff/nu/ModuleParameters.mls | 2 +- shared/src/test/diff/nu/ParamOverride.mls | 115 ++++++++---- shared/src/test/diff/nu/ParamPassing.mls | 15 +- 14 files changed, 219 insertions(+), 212 deletions(-) create mode 100644 shared/src/test/diff/nu/BadClasses.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 86a9962ed9..843189d2e7 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -137,23 +137,25 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // val tparams: Ls[TN -> TV] = Nil // TODO override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = this match { - case m @ TypedNuMxn(td, thisTV, superTV, members, ttu) => + case m @ TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => // println(">>",m.level) // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) TypedNuMxn(td, thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).asInstanceOf[TV], tp._3)), + params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) - case cls @ TypedNuCls(level, td, ttu, tps, params, members, thisTy) => + case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => println(">>",level,ctx.lvl) // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), // params.mapValues(_.freshenAbove(level, rigidify)), // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), - // tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), - tps.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).asInstanceOf[TV], tp._3)), + // tparams.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).asInstanceOf[TV], tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify))( @@ -290,7 +292,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )(f(pol, instanceType)) } - case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, members: Map[Str, NuMember], ttu: TypedTypingUnit) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { + case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, + tparams: Ls[(TN, TV, Opt[VarianceInfo])], params: Ls[Var -> FieldType], + members: Map[Str, NuMember], ttu: TypedTypingUnit, + ) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { val level: Level = thisTV.level - 1 // TODO cleaner def nme: TypeName = td.nme def name: Str = nme.name @@ -298,10 +303,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuMxn(td, f(pol.map(!_), thisTV), f(pol.map(!_), superTV), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) + TypedNuMxn(td, f(pol.map(!_), thisTV), f(pol.map(!_), superTV), + tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), + params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), + members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuMxn(td, f(pol.contravar, thisTV), f(pol.contravar, superTV), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) + TypedNuMxn(td, f(pol.contravar, thisTV), f(pol.contravar, superTV), + tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), + params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), + members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) } /** Note: the type `ty` is stoed *without* its polymorphic wrapper! */ diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 78b081d740..613fdc8519 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1268,9 +1268,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: TypedNuDecl): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil)) - case TypedNuMxn(td, thisTy, superTy, members, ttu) => + case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => NuTypeDef(td.kind, td.nme, td.tparams, - Tup(Nil), + Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), N, Nil,//TODO // S(go(superTy)), diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index db8a2a1aaf..0cd44d081a 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -135,14 +135,14 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } // else // TODO avert infinite completion recursion here? trace(s"Completing ${decl.showDbg}") { - // var res: ST = errType + println(s"Type params ${tparams.mkString(" ")}") + println(s"Params ${typedParams.mkString(" ")}") + val res = try { isComputing = true - // res = decl match { case fd: NuFunDef => // assert(fd.isLetRec.isEmpty, fd.isLetRec) - // implicit val prov: TP = noProv // TODO def checkNoTyParams() = if (fd.tparams.nonEmpty) err(msg"Type parameters here are not yet supported in this position", @@ -227,18 +227,6 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => if (td.parents.nonEmpty) err(msg"type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) - // val tparams = td.tparams.map(tp => - // (tp._2, freshVar(TypeProvenance( - // tp._2.toLoc, - // "type parameter", - // S(tp._2.name), - // true), N, S(tp._2.name)), tp._1)) - - implicit val vars: Map[Str, SimpleType] = - outerVars ++ tparams.iterator.map { - case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) - } - val body_ty = td.sig match { case S(sig) => typeType(sig) @@ -253,55 +241,13 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // implicit val prov: TP = noProv // TODO ctx.nest.nextLevel { implicit ctx => - /* - val tparams = td.tparams.map(tp => - (tp._2, freshVar(TypeProvenance( - tp._2.toLoc, - "type parameter", - S(tp._2.name), - true), N, S(tp._2.name)), tp._1)) - - println(s"Type params ${tparams.mkString(" ")}") - - implicit val vars: Map[Str, SimpleType] = - // outerVars ++ tparams.iterator.mapKeys(_.name).toMap - outerVars ++ tparams.iterator.map { - case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) - } - - val typedParams = td.params.fields.map { - case (S(nme), Fld(mut, spec, value)) => - assert(!mut && !spec, "TODO") // TODO - value.toType match { - case R(tpe) => - implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? - val ty = typeType(tpe) - nme -> FieldType(N, ty)(provTODO) - case _ => ??? - } - case (N, Fld(mut, spec, nme: Var)) => - // assert(!mut && !spec, "TODO") // TODO - // nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) - nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) - case _ => ??? - } - */ - if ((td.kind is Nms) && typedParams.nonEmpty) // * Can we do better? (Memoization semantics?) err(msg"${td.kind.str} parameters are not supported", Loc(typedParams.iterator.map(_._1))) - // ctx ++= typedParams.mapKeysIter(_.name).mapValues(_.ub |> VarSymbol(_)) ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) - // ctx += "this" -> VarSymbol( - // ClassTag(Var(td.name), - // Set.empty//TODO - // )(provTODO), - // Var("this")) - - // val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) ctx += "this" -> VarSymbol(thisTV, Var("this")) val sig_ty = typeType(td.sig.getOrElse(Top)) @@ -311,11 +257,6 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case N => () } - // // TODO check against `tv` - // println(td.tparams) - // println(td.params) - // println(td.parents) - implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) @@ -331,10 +272,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) - // def inherit(parents: Ls[Term], superType: ST, members: Ls[TypedNuDecl -> ST]): Unit = parents match { - def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]) - // : Ls[NuMember] = : (ST, Ls[NuMember]) = parents match { // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { @@ -342,53 +280,67 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // case L(p) :: ps => case p :: ps => val newMembs = trace(s"${lvl}. Inheriting from $p") { - p match { - case Var(nme) => - ctx.get(nme) match { - case S(lti: LazyTypeInfo) => - lti.complete().freshen match { - case mxn: TypedNuMxn => - // mxn.thisTV - // mxn.ttu.entities - // ??? - // val fresh = mxn.freshen - // println(fresh) - - println(s"Fresh $mxn") - - assert(finalType.level === lvl) - assert(mxn.superTV.level === lvl) - assert(mxn.thisTV.level === lvl) - constrain(superType, mxn.superTV) - constrain(finalType, mxn.thisTV) - - // TODO check overriding - mxn.ttu.entities.map(_.complete()).map { - case fun @ TypedNuFun(_, fd, ty) => - fun - case m: NuMember => m - // case _ => ??? - } - case cls: TypedNuCls => - err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO - Nil - case als: TypedNuAls => - // TODO dealias first? - err(msg"Cannot inherit from a type alias", p.toLoc) - Nil - case cls: TypedNuFun => - err(msg"Cannot inherit from this", p.toLoc) - Nil + val (v @ Var(mxnNme), mxnArgs) = p match { + case v @ Var(nme) => + v -> Nil + case App(v @ Var(nme), Tup(args)) => + v -> args + case _ => + err(msg"Unsupported parent specification", p.toLoc) // TODO + return inherit(ps, superType, members) + } + ctx.get(mxnNme) match { + case S(lti: LazyTypeInfo) => + lti.complete().freshen match { + case mxn: TypedNuMxn => + + println(s"Fresh $mxn") + + assert(finalType.level === lvl) + assert(mxn.superTV.level === lvl) + assert(mxn.thisTV.level === lvl) + + constrain(superType, mxn.superTV) + constrain(finalType, mxn.thisTV) + + if (mxnArgs.sizeCompare(mxn.params) =/= 0) + err(msg"mixin $mxnNme expects ${ + mxn.params.size.toString} parameters; got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) + + val paramMems = mxn.params.lazyZip(mxnArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false) } - case S(_) => - err(msg"Cannot inherit from this", p.toLoc) + + // TODO check overriding + val bodyMems = mxn.ttu.entities.map(_.complete()).map { + case fun @ TypedNuFun(_, fd, ty) => + fun + case m: NuMember => m + // case _ => ??? + } + + paramMems ++ bodyMems + + case cls: TypedNuCls => + err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO + Nil + case als: TypedNuAls => + // TODO dealias first? + err(msg"Cannot inherit from a type alias", p.toLoc) Nil - case N => - err(msg"Could not find definition `${nme}`", p.toLoc) + case cls: TypedNuFun => + err(msg"Cannot inherit from this", p.toLoc) Nil } - case _ => - err(msg"Unsupported parent specification", p.toLoc) // TODO + case S(_) => + err(msg"Cannot inherit from this", p.toLoc) + Nil + case N => + err(msg"Could not find definition `${mxnNme}`", p.toLoc) Nil } }() @@ -399,7 +351,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => RecordType( // newMembs.foldLeft(TopType.toUpper(provTODO))(_ && _.ty.toUpper(provTODO)) // newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) - newMembs.collect{case m: TypedNuFun => m.fd.nme -> m.ty.toUpper(provTODO)} + newMembs.collect{ + case m: NuParam => m.nme -> m.ty + case m: TypedNuFun => m.fd.nme -> m.ty.toUpper(provTODO) + } )(provTODO) )(provTODO) inherit(ps, newSuperType, members ++ newMembs) @@ -475,7 +430,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // ctx |> { implicit ctx => val ttu = typeTypingUnit(td.body, allowPure = false) val mems = paramMems ++ttu.entities.map(_.complete()) - TypedNuMxn(td, thisTV, superTV, mems.map(m => m.name -> m).toMap, ttu) + TypedNuMxn(td, thisTV, superTV, tparams, typedParams, mems.map(m => m.name -> m).toMap, ttu) // } } // case Als => ??? diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 6011a89d18..83ce1f6994 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -968,7 +968,9 @@ abstract class TyperHelpers { Typer: Typer => members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuMxn(td, thisTV, superTV, members, ttu) => + case TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => + tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) + params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTV) apply(pol.contravar)(superTV) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 88e259e6df..1d05f8ebcc 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -507,7 +507,8 @@ trait TypeNameImpl extends Ordered[TypeName] { self: TypeName => lazy val toVar: Var = Var(name).withLocOf(this) } -trait FldImpl { self: Fld => +trait FldImpl extends Located { self: Fld => + def children: Ls[Located] = self.value :: Nil def describe: Str = (if (self.spec) "specialized " else "") + (if (self.mut) "mutable " else "") + diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 422a8eddbe..eec1ef0aa1 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -410,7 +410,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) -//│ ╔══[ERROR] Unsupported parent specification +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) //│ ║ l.412: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -418,7 +418,7 @@ class Bar(x: int, y: int) extends Foo(x + y) mixin AA(a: int) { } -//│ mixin AA() +//│ mixin AA(a: int) mixin BB {} //│ mixin BB() @@ -427,23 +427,15 @@ mixin BB {} class C(x: int) extends BB //│ class C(x: int) -:e class D(x: int) extends AA(x) -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.431: class D(x: int) extends AA(x) -//│ ╙── ^^^^^ //│ class D(x: int) -:e class E(x: int) extends BB, AA(x) -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.438: class E(x: int) extends BB, AA(x) -//│ ╙── ^^^^^ //│ class E(x: int) :js mixin Fooo(x: int) -//│ mixin Fooo() +//│ mixin Fooo(x: int) //│ // Prelude //│ let typing_unit14 = { //│ cache: {}, @@ -463,7 +455,7 @@ mixin Fooo(x: int) :js mixin Bazz(y: int) -//│ mixin Bazz() +//│ mixin Bazz(y: int) //│ // Prelude //│ let typing_unit15 = { //│ cache: {}, @@ -482,14 +474,7 @@ mixin Bazz(y: int) //│ // End of generated code :js -:e // TODO: type check module Barr extends Fooo(0), Bazz(1) -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.486: module Barr extends Fooo(0), Bazz(1) -//│ ╙── ^^^^^^^ -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.486: module Barr extends Fooo(0), Bazz(1) -//│ ╙── ^^^^^^^ //│ module Barr() //│ // Prelude //│ let typing_unit16 = { @@ -510,20 +495,13 @@ module Barr extends Fooo(0), Bazz(1) //│ globalThis.Barr = typing_unit16.Barr; //│ // End of generated code -:e Barr.x -//│ ╔══[ERROR] module `Barr` does not contain member `x` -//│ ║ l.514: Barr.x -//│ ╙── ^^ -//│ error +//│ 0 //│ res //│ = 0 -:e Barr.y -//│ ╔══[ERROR] module `Barr` does not contain member `y` -//│ ║ l.523: Barr.y -//│ ╙── ^^ -//│ error +//│ 1 //│ res //│ = 1 + diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 52e8863c24..cd905eba48 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -145,7 +145,7 @@ module Test0 extends Foo2 //│ │ │ globalThis.Test01 = typing_unit5.Test01; //│ │ └── Reply //│ │ Uncaught ReferenceError: Foo2 is not defined -//│ │ at Object.get Test01 [as Test01] (REPL9:1:78) +//│ │ at get Test01 [as Test01] (REPL9:1:78) //│ └── No queries :re diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls new file mode 100644 index 0000000000..d4cbd2dd6d --- /dev/null +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -0,0 +1,36 @@ +:NewParser +:NewDefs + + + +mixin M0(x: int) +//│ mixin M0(x: int) + +:e +class C0 extends M0 +//│ ╔══[ERROR] mixin M0 expects 1 parameters; got 0 +//│ ║ l.10: class C0 extends M0 +//│ ╙── ^^ +//│ class C0() + +:e +class C0 extends M0(1, 2) +//│ ╔══[ERROR] mixin M0 expects 1 parameters; got 2 +//│ ║ l.17: class C0 extends M0(1, 2) +//│ ╙── ^^^^^^^ +//│ class C0() + +:e +class C0 extends M0(true) +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.24: class C0 extends M0(true) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── reference of type `true` is not an instance of type `int` +//│ ║ l.24: class C0 extends M0(true) +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.6: mixin M0(x: int) +//│ ╙── ^^^ +//│ class C0() + + diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 77d9189c48..b55bb4dce8 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -19,7 +19,7 @@ class A(n: int) // TODO class B(m: int) extends A(n + 1) -//│ ╔══[ERROR] Unsupported parent specification +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) //│ ║ l.21: class B(m: int) extends A(n + 1) //│ ╙── ^^^^^^^^ //│ class B(m: int) diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 99979c4dc5..56f28e9b80 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -10,15 +10,11 @@ mixin BaseTest { //│ ╔══[ERROR] type identifier not found: A //│ ║ l.8: fun test(x: A) = x //│ ╙── ^ -//│ mixin BaseTest[A]() { -//│ fun test: (x: error,) -> error -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A26' // TODO support mixin BaseTest(x: A) { fun test = x } -//│ mixin BaseTest[A]() { -//│ fun test: A -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A31_38' diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index e920e507de..63a3597467 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -6,7 +6,7 @@ mixin BaseTest(x: int) { fun test = x } -//│ mixin BaseTest() { +//│ mixin BaseTest(x: int) { //│ fun test: int //│ } @@ -17,7 +17,7 @@ mixin BaseTest(x) { //│ ╔══[ERROR] Class parameters currently need type annotations //│ ║ l.14: mixin BaseTest(x) { //│ ╙── ^ -//│ mixin BaseTest() { +//│ mixin BaseTest(x: error) { //│ fun test: error //│ } diff --git a/shared/src/test/diff/nu/ModuleParameters.mls b/shared/src/test/diff/nu/ModuleParameters.mls index 960f3be435..de92e5f536 100644 --- a/shared/src/test/diff/nu/ModuleParameters.mls +++ b/shared/src/test/diff/nu/ModuleParameters.mls @@ -2,7 +2,7 @@ :NewDefs -// FIXME +:e module A(x: int) { fun y = x } //│ ╔══[ERROR] module parameters are not supported //│ ║ l.6: module A(x: int) { fun y = x } diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index 00301a2b3b..bbfcc0ff8d 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -15,70 +15,105 @@ class Derived0(n: int) extends Base //│ unresolved symbol Base -mixin Base1(n: number) -//│ mixin Base1() +mixin Base1(n: number) { + fun original = n +} +//│ mixin Base1(n: number) { +//│ fun original: number +//│ } :e mixin DerivedBad(n: int) extends Base //│ ╔══[ERROR] mixin definitions cannot yet extend parents -//│ ║ l.22: mixin DerivedBad(n: int) extends Base +//│ ║ l.26: mixin DerivedBad(n: int) extends Base //│ ╙── ^^^^ -//│ mixin DerivedBad() +//│ mixin DerivedBad(n: int) mixin Derived1(n: int) { - // fun foo = [n, this.n, super.n] // TODO - fun foo = [this.n, super.n] + fun foo = [n, this.n, super.n] } -//│ mixin Derived1() { +//│ mixin Derived1(n: int) { //│ super: {n: 'n} //│ this: {n: 'n0} -//│ fun foo: ('n0, 'n,) +//│ fun foo: (int, 'n0, 'n,) //│ } -// TODO type check -class Test0 extends Base1(0), Derived1(1) // TODO -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.40: class Test0 extends Base1(0), Derived1(1) // TODO -//│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.40: class Test0 extends Base1(0), Derived1(1) // TODO -//│ ╙── ^^^^^^^^^^^ -//│ class Test0() +class Test0 extends Base1(0), Derived1(1) +//│ class Test0() { +//│ fun foo: (int, 1, 0,) +//│ fun original: number +//│ } let t = Test0() //│ let t: Test0 //│ t //│ = Test0 { n: 0 } -// TODO type check +// FIXME field value t.n -//│ ╔══[ERROR] class `Test0` does not contain member `n` -//│ ║ l.55: t.n -//│ ╙── ^^ -//│ error +//│ 1 +//│ res +//│ = 0 + +t.original +//│ number //│ res //│ = 0 -// TODO type check -// FIXME super access to field? +// FIXME super access to field t.foo -//│ ╔══[ERROR] class `Test0` does not contain member `foo` -//│ ║ l.65: t.foo -//│ ╙── ^^^^ -//│ error +//│ (int, 1, 0,) +//│ res +//│ = [ 0, 0, undefined ] + + +// FIXME error swallowed! +:ShowRepl +module Test1 extends Base1(0), Derived1(1) { + fun n = this.n +} +//│ module Test1() { +//│ fun foo: (int, 1, 0,) +//│ fun n: 1 +//│ fun original: number +//│ } +//│ ┌ Block at ParamOverride.mls:73 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ let typing_unit10 = { +//│ │ │ cache: {}, +//│ │ │ get Test1() { +//│ │ │ if (this.cache.Test1 === undefined) { +//│ │ │ class Test1 extends Derived1(Base1(Object)) { +//│ │ │ constructor() { +//│ │ │ super(1, 0); +//│ │ │ } +//│ │ │ get n() { +//│ │ │ const self = this; +//│ │ │ return self.n; +//│ │ │ } +//│ │ │ } +//│ │ │ this.cache.Test1 = new Test1(); +//│ │ │ this.cache.Test1["class"] = Test1; +//│ │ │ } +//│ │ │ return this.cache.Test1; +//│ │ │ } +//│ │ │ }; +//│ │ │ globalThis.Test1 = typing_unit10.Test1; +//│ │ └── Reply +//│ │ Uncaught TypeError: Cannot set property n of # which has only a getter +//│ │ at new Base1 (REPL3:1:171) +//│ │ at new Derived1 (REPL5:1:146) +//│ │ at new Test1 (REPL19:1:180) +//│ │ at get Test1 [as Test1] (REPL19:1:318) +//│ └── No queries + +// FIXME +Test1.n +//│ 1 //│ res -//│ = [ 0, undefined ] - - -// TODO correct module code-gen -module Test1 extends Base1(0), Derived1(1) -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.75: module Test1 extends Base1(0), Derived1(1) -//│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.75: module Test1 extends Base1(0), Derived1(1) -//│ ╙── ^^^^^^^^^^^ -//│ module Test1() +//│ Runtime error: +//│ ReferenceError: Test1 is not defined diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 36a40d07c9..3c6f4971aa 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -8,7 +8,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) -//│ ╔══[ERROR] Unsupported parent specification +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) //│ ║ l.10: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -16,7 +16,7 @@ class Bar(x: int, y: int) extends Foo(x + y) mixin AA(a: int) { } -//│ mixin AA() +//│ mixin AA(a: int) mixin BB {} //│ mixin BB() @@ -25,17 +25,10 @@ mixin BB {} class C(x: int) extends BB //│ class C(x: int) -:e class D(x: int) extends AA(x) -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.29: class D(x: int) extends AA(x) -//│ ╙── ^^^^^ //│ class D(x: int) - -:e class E(x: int) extends BB, AA(x) -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.37: class E(x: int) extends BB, AA(x) -//│ ╙── ^^^^^ //│ class E(x: int) + + From d60c8ccc4e514e50f148184ab0337a1265b333b5 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 23:35:44 +0800 Subject: [PATCH 155/498] WIP: Update mixin codegen and private fields --- .../src/main/scala/mlscript/JSBackend.scala | 6 +-- .../main/scala/mlscript/codegen/Codegen.scala | 14 ++---- shared/src/test/diff/codegen/Mixin.mls | 26 +++++----- shared/src/test/diff/nu/ECOOP23_intro.mls | 50 +++---------------- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 22 ++++---- shared/src/test/diff/nu/ParamOverride.mls | 6 +-- shared/src/test/diff/nu/SimpleRegionDSL.mls | 22 +------- 7 files changed, 44 insertions(+), 102 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 1d5243d515..d40692e9b9 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -622,8 +622,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { }).flatten JSClassNewDecl(classSymbol.runtimeName, fields, base, restRuntime match { - case Some(restRuntime) => superParameters :+ JSIdent(s"...$restRuntime") - case _ => superParameters + case Some(restRuntime) => superParameters.reverse :+ JSIdent(s"...$restRuntime") + case _ => superParameters.reverse }, restRuntime, members, traits) } @@ -680,7 +680,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val selfSymbol = memberScope.declareThisAlias() val preDecs = props.map(p => { val runtime = memberScope.declareValue(p, Some(false), false) - JSConstDecl(runtime.runtimeName, JSField(JSIdent("this"), p)) + JSConstDecl(runtime.runtimeName, JSIdent(s"this.#$p")) }) // Declare parameters. val (memberParams, body) = method.rhs.value match { diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 9dbbc5395d..37e216454d 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -845,11 +845,10 @@ final case class JSClassNewDecl( })((p, s) => if (s.isEmpty) s"${p._1}" else s"${p._1}, $s") - if (!fields.isEmpty) - buffer += fields.iterator.zipWithIndex.foldLeft("")((res, f) => - if (f._2 === fields.length - 1) s"$res #${f._1};" - else s"$res #${f._1};\n" - ) + if (!fields.isEmpty) { + fields.foreach(f => buffer += s" #${f};") + fields.foreach(f => buffer += s" get ${f}() { return this.#${f}; }") + } buffer += s" constructor($params) {" if (`extends`.isDefined) { val sf = superFields.iterator.zipWithIndex.foldLeft("")((res, p) => @@ -862,10 +861,7 @@ final case class JSClassNewDecl( buffer += s" $name.implement(this);" } fields.iterator.zipWithIndex.foreach { pair => - val innerName = if (JSField.isValidIdentifier(pair._1)) s".${pair._1}" else s"[${JSLit.makeStringLiteral(pair._1)}]" - val privateName = if (JSField.isValidIdentifier(pair._1)) s".#${pair._1}" else s"[#${JSLit.makeStringLiteral(pair._1)}]" - buffer += s" this${innerName} = ${pair._1};" - buffer += s" this${privateName} = ${pair._1};" // TODO: invalid name? + buffer += s" this.#${pair._1} = ${pair._1};" // TODO: invalid name? } buffer += " }" SourceCode(buffer.toList) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 422a8eddbe..42aa959585 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -15,11 +15,11 @@ class Lit(n: int) //│ if (this.cache.Add === undefined) { //│ class Add { //│ #lhs; -//│ #rhs; +//│ #rhs; +//│ get lhs() { return this.#lhs; } +//│ get rhs() { return this.#rhs; } //│ constructor(lhs, rhs) { -//│ this.lhs = lhs; //│ this.#lhs = lhs; -//│ this.rhs = rhs; //│ this.#rhs = rhs; //│ } //│ }; @@ -32,8 +32,8 @@ class Lit(n: int) //│ if (this.cache.Lit === undefined) { //│ class Lit { //│ #n; +//│ get n() { return this.#n; } //│ constructor(n) { -//│ this.n = n; //│ this.#n = n; //│ } //│ }; @@ -56,11 +56,11 @@ class Lit(n: int) //│ │ │ if (this.cache.Add === undefined) { //│ │ │ class Add { //│ │ │ #lhs; -//│ #rhs; +//│ │ │ #rhs; +//│ │ │ get lhs() { return this.#lhs; } +//│ │ │ get rhs() { return this.#rhs; } //│ │ │ constructor(lhs, rhs) { -//│ │ │ this.lhs = lhs; //│ │ │ this.#lhs = lhs; -//│ │ │ this.rhs = rhs; //│ │ │ this.#rhs = rhs; //│ │ │ } //│ │ │ }; @@ -73,8 +73,8 @@ class Lit(n: int) //│ │ │ if (this.cache.Lit === undefined) { //│ │ │ class Lit { //│ │ │ #n; +//│ │ │ get n() { return this.#n; } //│ │ │ constructor(n) { -//│ │ │ this.n = n; //│ │ │ this.#n = n; //│ │ │ } //│ │ │ }; @@ -87,7 +87,7 @@ class Lit(n: int) //│ │ │ globalThis.Add = typing_unit.Add; //│ │ │ globalThis.Lit = typing_unit.Lit; //│ │ └── Reply -//│ │ ... [Function (anonymous)] { class: [class Lit] } +//│ │ [Function (anonymous)] { class: [class Lit] } //│ └── No queries :js @@ -162,8 +162,8 @@ class Neg(expr: A) //│ if (this.cache.Neg === undefined) { //│ class Neg { //│ #expr; +//│ get expr() { return this.#expr; } //│ constructor(expr) { -//│ this.expr = expr; //│ this.#expr = expr; //│ } //│ }; @@ -184,8 +184,8 @@ class Neg(expr: A) //│ │ │ if (this.cache.Neg === undefined) { //│ │ │ class Neg { //│ │ │ #expr; +//│ │ │ get expr() { return this.#expr; } //│ │ │ constructor(expr) { -//│ │ │ this.expr = expr; //│ │ │ this.#expr = expr; //│ │ │ } //│ │ │ }; @@ -450,9 +450,9 @@ mixin Fooo(x: int) //│ Fooo(base) { //│ return (class Fooo extends base { //│ #x; +//│ get x() { return this.#x; } //│ constructor(x, ...rest) { //│ super(...rest); -//│ this.x = x; //│ this.#x = x; //│ } //│ }); @@ -470,9 +470,9 @@ mixin Bazz(y: int) //│ Bazz(base) { //│ return (class Bazz extends base { //│ #y; +//│ get y() { return this.#y; } //│ constructor(y, ...rest) { //│ super(...rest); -//│ this.y = y; //│ this.#y = y; //│ } //│ }); diff --git a/shared/src/test/diff/nu/ECOOP23_intro.mls b/shared/src/test/diff/nu/ECOOP23_intro.mls index f6d68f563c..7e017b589c 100644 --- a/shared/src/test/diff/nu/ECOOP23_intro.mls +++ b/shared/src/test/diff/nu/ECOOP23_intro.mls @@ -29,7 +29,7 @@ class Color(str: string) { let Red = Color("red") //│ let Red: Color //│ Red -//│ = Color { str: 'red' } +//│ = Color {} mixin CompareColored { @@ -111,53 +111,17 @@ let p5 = MyPoint(0, 1, Red, Some(p3)) //│ let p4: MyPoint //│ let p5: MyPoint //│ p0 -//│ = MyPoint { -//│ x: 0, -//│ y: 0, -//│ color: Color { str: 'red' }, -//│ parent: None { class: [class None] } -//│ } +//│ = MyPoint {} //│ p1 -//│ = MyPoint { -//│ x: 0, -//│ y: 1, -//│ color: Color { str: 'red' }, -//│ parent: None { class: [class None] } -//│ } +//│ = MyPoint {} //│ p2 -//│ = MyPoint { -//│ x: 0, -//│ y: 1, -//│ color: Color { str: 'red' }, -//│ parent: None { class: [class None] } -//│ } +//│ = MyPoint {} //│ p3 -//│ = MyPoint { -//│ x: 0, -//│ y: 1, -//│ color: Color { str: 'red' }, -//│ parent: Some { -//│ value: MyPoint { x: 0, y: 1, color: [Color], parent: [None] } -//│ } -//│ } +//│ = MyPoint {} //│ p4 -//│ = MyPoint { -//│ x: 0, -//│ y: 1, -//│ color: Color { str: 'red' }, -//│ parent: Some { -//│ value: MyPoint { x: 0, y: 1, color: [Color], parent: [None] } -//│ } -//│ } +//│ = MyPoint {} //│ p5 -//│ = MyPoint { -//│ x: 0, -//│ y: 1, -//│ color: Color { str: 'red' }, -//│ parent: Some { -//│ value: MyPoint { x: 0, y: 1, color: [Color], parent: [Some] } -//│ } -//│ } +//│ = MyPoint {} CompareMyPoint.compare(p0, p1) diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index e595113d21..d1d1d4c178 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -13,7 +13,7 @@ module Nil let l = Cons(1, Nil) //│ let l: Cons[1] //│ l -//│ = Cons { head: 1, tail: Nil { class: [class Nil] } } +//│ = Cons {} class NotFound class Success[A](result: A) @@ -95,28 +95,28 @@ Test1.eval(Nil, Var("a")) //│ where //│ 'a :> App['a] | Abs['a] | Var //│ res -//│ = Var { s: 'a' } +//│ = Var {} Test1.eval(Nil, Abs("b", Var("a"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var //│ res -//│ = Abs { x: 'fun', t: Var { s: 'a' } } +//│ = Abs {} Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Var //│ res -//│ = Var { s: 'b' } +//│ = Var {} Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where //│ 'a :> Abs[Var] | Var | App['a] | Abs['a] //│ res -//│ = Var { s: 'b' } +//│ = Var {} class Num(n: int) class Add[A](l: A, r: A) @@ -160,17 +160,17 @@ module Test2 extends EvalVar, EvalExpr Test2.eval(Nil, Var("a")) //│ Num | Var //│ res -//│ = Var { s: 'a' } +//│ = Var {} Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Var("a")) //│ Abs[Var] | Num | Var //│ res -//│ = Var { s: 'a' } +//│ = Var {} Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) //│ Num | Var //│ res -//│ = Var { s: 'a' } +//│ = Var {} :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) @@ -194,7 +194,7 @@ Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) //│ Abs[Var] | Add[Num | Var] | Num | Var //│ res -//│ = Add { l: Num { n: 1 }, r: Var { s: 'a' } } +//│ = Add {} module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { @@ -211,14 +211,14 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ where //│ 'a :> App['a] | Abs['a] | Abs[Var] | Num | Var //│ res -//│ = Abs { x: 'fun', t: Var { s: 'a' } } +//│ = Abs {} Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where //│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var //│ res -//│ = Var { s: 'a' } +//│ = Var {} // * Incorrect version, for regression testing module Test3 extends EvalVar, EvalLambda, EvalExpr diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index 00301a2b3b..e88ba66ede 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -49,7 +49,7 @@ class Test0 extends Base1(0), Derived1(1) // TODO let t = Test0() //│ let t: Test0 //│ t -//│ = Test0 { n: 0 } +//│ = Test0 {} // TODO type check t.n @@ -58,7 +58,7 @@ t.n //│ ╙── ^^ //│ error //│ res -//│ = 0 +//│ = 1 // TODO type check // FIXME super access to field? @@ -68,7 +68,7 @@ t.foo //│ ╙── ^^^^ //│ error //│ res -//│ = [ 0, undefined ] +//│ = [ 1, 0 ] // TODO correct module code-gen diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index bf59a18eb4..fc631a9921 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -55,16 +55,7 @@ let circles = go(2, 1024) //│ where //│ 'Region :> Circle | Union[Translate['Region]] //│ circles -//│ = Union { -//│ a: Translate { -//│ v: Vector { x: -1024, y: 0 }, -//│ a: Union { a: [Translate], b: [Translate] } -//│ }, -//│ b: Translate { -//│ v: Vector { x: 1024, y: 0 }, -//│ a: Union { a: [Translate], b: [Translate] } -//│ } -//│ } +//│ = Union {} // ******************* Adding More Language Constructs ******************* @@ -345,16 +336,7 @@ TestElim.eliminate(circles) //│ where //│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Circle //│ res -//│ = Union { -//│ a: Translate { -//│ v: Vector { x: -1024, y: 0 }, -//│ a: Union { a: [Translate], b: [Translate] } -//│ }, -//│ b: Translate { -//│ v: Vector { x: 1024, y: 0 }, -//│ a: Union { a: [Translate], b: [Translate] } -//│ } -//│ } +//│ = Union {} fun mk(n) = if n is 1 then Outside(mk(n)) From 98ae45e127ee0ae60e87330c996bd2d2345f523a Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 23:36:32 +0800 Subject: [PATCH 156/498] WIP: rerun tests --- shared/src/test/diff/nu/SimpleRegionDSL.mls | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index fc631a9921..11fe51a855 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -187,16 +187,16 @@ mixin Text { :e module SizeText extends Text //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.189: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.180: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.188: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.179: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.187: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.178: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.186: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.177: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -432,16 +432,16 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.451: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.433: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.364: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.346: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.451: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.433: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.132: if a is +//│ ║ l.123: if a is //│ ╙── ^ //│ error | bool //│ res @@ -452,16 +452,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.471: Lang.text(mk(100)) +//│ ║ l.453: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.364: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.346: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.471: Lang.text(mk(100)) +//│ ║ l.453: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.184: if e is +//│ ║ l.175: if e is //│ ╙── ^ //│ error | string //│ res From b70fac6ab9b7735b3e92bc0c3c1b420f4550ba61 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 8 Mar 2023 23:46:18 +0800 Subject: [PATCH 157/498] Remove FIXME --- shared/src/test/diff/nu/ParamOverride.mls | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index ce6d765faa..906dd19fc4 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -50,7 +50,6 @@ let t = Test0() //│ t //│ = Test0 {} -// FIXME field value t.n //│ 1 //│ res @@ -61,14 +60,12 @@ t.original //│ res //│ = 0 -// FIXME super access to field t.foo //│ (int, 1, 0,) //│ res //│ = [ 1, 1, 0 ] -// FIXME error swallowed! :ShowRepl module Test1 extends Base1(0), Derived1(1) { fun n = this.n @@ -78,7 +75,7 @@ module Test1 extends Base1(0), Derived1(1) { //│ fun n: 1 //│ fun original: number //│ } -//│ ┌ Block at ParamOverride.mls:73 +//│ ┌ Block at ParamOverride.mls:70 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit10 = { From e3cafa5b03df2ad9596b8131c310182d89ab09f2 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 8 Mar 2023 23:46:40 +0800 Subject: [PATCH 158/498] WIP Implement `super` for classes (codegen not working yet) --- .../src/main/scala/mlscript/JSBackend.scala | 1 + shared/src/main/scala/mlscript/Typer.scala | 1 + .../main/scala/mlscript/TyperDatatypes.scala | 1 + .../scala/mlscript/codegen/Polyfill.scala | 3 + .../main/scala/mlscript/codegen/Scope.scala | 1 + shared/src/test/diff/codegen/Super.mls | 2 +- shared/src/test/diff/fcp-lit/FreezeML.mls | 2 +- shared/src/test/diff/fcp-lit/HMF.mls | 2 +- shared/src/test/diff/fcp-lit/HML.mls | 2 +- shared/src/test/diff/fcp-lit/Leijen.mls | 2 +- shared/src/test/diff/fcp/PaperTable.mls | 2 +- shared/src/test/diff/nu/ParamOverride.mls | 76 ++++++++++--------- 12 files changed, 54 insertions(+), 41 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index d40692e9b9..7db613887c 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -422,6 +422,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { )(implicit scope: Scope): JSClassDecl = { // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") + classScope.declareSuper() val members = classSymbol.methods.map { translateClassMember(_)(classScope) } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 613fdc8519..16e35e2925 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -261,6 +261,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) "le" -> numberBinPred, "gt" -> numberBinPred, "ge" -> numberBinPred, + "length" -> fun(singleTup(StrType), IntType)(noProv), "concat" -> fun(singleTup(StrType), fun(singleTup(StrType), StrType)(noProv))(noProv), "eq" -> { val v = freshVar(noProv, N)(1) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 0cd44d081a..772fc76d9e 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -385,6 +385,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // TODO // ctx += "super" -> VarSymbol(superTV, Var("super")) + ctx += "super" -> VarSymbol(thisType, Var("super")) val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use diff --git a/shared/src/main/scala/mlscript/codegen/Polyfill.scala b/shared/src/main/scala/mlscript/codegen/Polyfill.scala index 08e162e550..24b9580dd3 100644 --- a/shared/src/main/scala/mlscript/codegen/Polyfill.scala +++ b/shared/src/main/scala/mlscript/codegen/Polyfill.scala @@ -154,6 +154,9 @@ object Polyfill { `throw`(JSNew(JSIdent("Error"))(JSExpr("unexpected runtime error"))) } ) + buffer += BuiltinFunc( + "length", fn(_, param("x")) { `return` { id("x").member("length") } } + ) buffer += BuiltinFunc("concat", makeBinaryFunc("+")) buffer += BuiltinFunc("add", makeBinaryFunc("+")) buffer += BuiltinFunc("sub", makeBinaryFunc("-")) diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 63e3972665..0871ec9b73 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -31,6 +31,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { "emptyArray", "succ", "error", + "length", "concat", "add", "sub", diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 52e8863c24..cd905eba48 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -145,7 +145,7 @@ module Test0 extends Foo2 //│ │ │ globalThis.Test01 = typing_unit5.Test01; //│ │ └── Reply //│ │ Uncaught ReferenceError: Foo2 is not defined -//│ │ at Object.get Test01 [as Test01] (REPL9:1:78) +//│ │ at get Test01 [as Test01] (REPL9:1:78) //│ └── No queries :re diff --git a/shared/src/test/diff/fcp-lit/FreezeML.mls b/shared/src/test/diff/fcp-lit/FreezeML.mls index 79836852db..03c8f8d5a8 100644 --- a/shared/src/test/diff/fcp-lit/FreezeML.mls +++ b/shared/src/test/diff/fcp-lit/FreezeML.mls @@ -113,7 +113,7 @@ rec def length l = //│ List[?] -> int //│ <: length: //│ List[?] -> int -//│ = [Function: length] +//│ = [Function: length1] def id: 'a -> 'a def id x = x diff --git a/shared/src/test/diff/fcp-lit/HMF.mls b/shared/src/test/diff/fcp-lit/HMF.mls index 4a7b48287c..cc017dcd58 100644 --- a/shared/src/test/diff/fcp-lit/HMF.mls +++ b/shared/src/test/diff/fcp-lit/HMF.mls @@ -93,7 +93,7 @@ rec def length l = //│ List[?] -> int //│ <: length: //│ List[?] -> int -//│ = [Function: length] +//│ = [Function: length1] def choose: forall 'a. 'a -> 'a -> 'a def choose x y = if true then x else y diff --git a/shared/src/test/diff/fcp-lit/HML.mls b/shared/src/test/diff/fcp-lit/HML.mls index 3d4860b061..ce4e9e11f0 100644 --- a/shared/src/test/diff/fcp-lit/HML.mls +++ b/shared/src/test/diff/fcp-lit/HML.mls @@ -97,7 +97,7 @@ rec def length l = //│ List[?] -> int //│ <: length: //│ List[?] -> int -//│ = [Function: length] +//│ = [Function: length1] def id: forall 'a. 'a -> 'a def id x = x diff --git a/shared/src/test/diff/fcp-lit/Leijen.mls b/shared/src/test/diff/fcp-lit/Leijen.mls index 29584abcee..43b1d25ad0 100644 --- a/shared/src/test/diff/fcp-lit/Leijen.mls +++ b/shared/src/test/diff/fcp-lit/Leijen.mls @@ -124,7 +124,7 @@ rec def length l = //│ List[?] -> int //│ <: length: //│ List[?] -> int -//│ = [Function: length] +//│ = [Function: length1] def id: 'a -> 'a def id x = x diff --git a/shared/src/test/diff/fcp/PaperTable.mls b/shared/src/test/diff/fcp/PaperTable.mls index 187d822c5f..d5f4de259a 100644 --- a/shared/src/test/diff/fcp/PaperTable.mls +++ b/shared/src/test/diff/fcp/PaperTable.mls @@ -113,7 +113,7 @@ rec def length l = //│ List[?] -> int //│ <: length: //│ List[?] -> int -//│ = [Function: length] +//│ = [Function: length1] def id: 'a -> 'a def id x = x diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index 906dd19fc4..b7634c4ab2 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -39,9 +39,9 @@ mixin Derived1(n: int) { //│ } -class Test0 extends Base1(0), Derived1(1) +class Test0 extends Base1(1/2), Derived1(1) //│ class Test0() { -//│ fun foo: (int, 1, 0,) +//│ fun foo: (int, 1, number,) //│ fun original: number //│ } @@ -58,51 +58,24 @@ t.n t.original //│ number //│ res -//│ = 0 +//│ = 0.5 t.foo -//│ (int, 1, 0,) +//│ (int, 1, number,) //│ res -//│ = [ 1, 1, 0 ] +//│ = [ 1, 1, 0.5 ] -:ShowRepl -module Test1 extends Base1(0), Derived1(1) { +module Test1 extends Base1(1/2), Derived1(1) { fun n = this.n } //│ module Test1() { -//│ fun foo: (int, 1, 0,) +//│ fun foo: (int, 1, number,) //│ fun n: 1 //│ fun original: number //│ } -//│ ┌ Block at ParamOverride.mls:70 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit10 = { -//│ │ │ cache: {}, -//│ │ │ get Test1() { -//│ │ │ if (this.cache.Test1 === undefined) { -//│ │ │ class Test1 extends Derived1(Base1(Object)) { -//│ │ │ constructor() { -//│ │ │ super(1, 0); -//│ │ │ } -//│ │ │ get n() { -//│ │ │ const self = this; -//│ │ │ return self.n; -//│ │ │ } -//│ │ │ } -//│ │ │ this.cache.Test1 = new Test1(); -//│ │ │ this.cache.Test1["class"] = Test1; -//│ │ │ } -//│ │ │ return this.cache.Test1; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.Test1 = typing_unit10.Test1; -//│ │ └── Reply -//│ │ Test1 { class: [Function: Test1] } -//│ └── No queries -// FIXME +:re Test1.n //│ 1 //│ res @@ -110,3 +83,36 @@ Test1.n //│ RangeError: Maximum call stack size exceeded +class Test2(n: string) extends Base1(1/2), Derived1(1) { + fun bar = [this.foo, n, this.original] +} +//│ class Test2(n: string) { +//│ fun bar: ((int, 1, number,), string, number,) +//│ fun foo: (int, 1, number,) +//│ fun original: number +//│ } + +Test2("test").bar +//│ ((int, 1, number,), string, number,) +//│ res +//│ = [ [ 1, 'test', 0.5 ], 'test', 0.5 ] + +// FIXME +class Test3(n: string) extends Base1(1/2), Derived1(length(n)) { + fun foo = [super.foo, n, this.original] +} +//│ class Test3(n: string) { +//│ fun foo: ((int, int, number,), string, number,) +//│ fun original: number +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol super + +// FIXME +Test3("test").foo +//│ ((int, int, number,), string, number,) +//│ res +//│ Runtime error: +//│ ReferenceError: Test3 is not defined + + From 4d2db8f41524d4b450089cbebd54067a8f8fa1ac Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 9 Mar 2023 12:53:33 +0800 Subject: [PATCH 159/498] WIP Add neat test --- shared/src/test/diff/nu/FilterMap.mls | 11 +- shared/src/test/diff/nu/MetaWrap.mls | 141 ++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 shared/src/test/diff/nu/MetaWrap.mls diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 325693b37a..96d2c6aa43 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -17,7 +17,7 @@ module Nil -class Cons[A](head: A, tail: Cons[A] | Nil) +class Cons[out A](head: A, tail: Cons[A] | Nil) //│ module Nil() //│ class Cons[A](head: A, tail: Cons[A] | Nil) @@ -52,10 +52,7 @@ fun filtermap(f, xs) = if xs is //│ ╙── ^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── -//│ fun filtermap: ((error | Cons['A] | Nil) -> number & (Cons['A] | Nil) -> error, Cons['A0] | Nil,) -> (Cons['A1] | Nil | error) -//│ where -//│ 'A := 'A0 -//│ 'A0 <: nothing +//│ fun filtermap: ((error | Cons[nothing] | Nil) -> number & (Cons[nothing] | Nil) -> error, Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 @@ -74,8 +71,6 @@ fun filtermap(f, xs) = if xs is True then filtermap(f, ys) False then Cons(y, filtermap(f, ys)) Pair(True, z) then Cons(z, filtermap(f, ys)) -//│ fun filtermap: ('head -> (False | Pair[anything, 'A] | True), Cons['head] | Nil,) -> (Cons['A] | Nil) -//│ where -//│ 'head <: 'A +//│ fun filtermap: ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls new file mode 100644 index 0000000000..a07d2d4794 --- /dev/null +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -0,0 +1,141 @@ +:NewParser +:NewDefs + + +// * A test to show how to add meta data to underlying values by wrapping them. + + +mixin Base { + fun unwrap(x) = x + fun rewrap(x, f) = f(x) +} +//│ mixin Base() { +//│ fun rewrap: ('a, 'a -> 'b,) -> 'b +//│ fun unwrap: 'c -> 'c +//│ } + + +mixin WithUid { + fun unwrap(x) = super.unwrap(x).underlying + fun rewrap(x, f) = super.rewrap(x, y => { underlying: f(y.underlying), uid: y.uid }) + fun getUid(x) = super.unwrap(x).uid + fun setUid(x, uid: int) = super.rewrap(x, y => { + underlying: y.underlying, + uid + }) +} +//│ mixin WithUid() { +//│ super: {rewrap: ('a, forall 'uid. {uid: 'uid, underlying: 'underlying} -> {uid: 'uid, underlying: 'b},) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {uid: int, underlying: 'underlying0},) -> 'e, unwrap: 'f -> {underlying: 'underlying1} & 'g -> {uid: 'uid0}} +//│ fun getUid: 'g -> 'uid0 +//│ fun rewrap: ('a, 'underlying -> 'b,) -> 'c +//│ fun setUid: ('d, uid: int,) -> 'e +//│ fun unwrap: 'f -> 'underlying1 +//│ } + + +class Type(name: string) +//│ class Type(name: string) + +mixin WithType { + fun unwrap(x) = super.unwrap(x).underlying + fun rewrap(x, f) = super.rewrap(x, y => { underlying: f(y.underlying), ty: y.ty }) + fun getType(x) = super.unwrap(x).ty + fun setType(x, ty: Type) = super.rewrap(x, y => { + underlying: y.underlying, + ty + }) +} +//│ mixin WithType() { +//│ super: {rewrap: ('a, forall 'ty. {ty: 'ty, underlying: 'underlying} -> {ty: 'ty, underlying: 'b},) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {ty: Type, underlying: 'underlying0},) -> 'e, unwrap: 'f -> {underlying: 'underlying1} & 'g -> {ty: 'ty0}} +//│ fun getType: 'g -> 'ty0 +//│ fun rewrap: ('a, 'underlying -> 'b,) -> 'c +//│ fun setType: ('d, ty: Type,) -> 'e +//│ fun unwrap: 'f -> 'underlying1 +//│ } + + +module Test0 extends Base, WithUid +//│ module Test0() { +//│ fun getUid: {uid: 'uid, underlying: 'underlying} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying0} +//│ fun setUid: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying0} +//│ fun unwrap: {uid: 'uid, underlying: 'underlying} -> 'underlying +//│ } + +module Test0 extends Base, WithUid, WithUid +//│ module Test0() { +//│ fun getUid: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {uid: int | 'uid1, underlying: 'underlying0}} +//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying2 | {uid: int | 'uid1, underlying: 'underlying0}} +//│ fun unwrap: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'underlying +//│ } + + +module Test1 extends Base, WithUid, WithType +//│ module Test1() { +//│ fun getType: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty +//│ fun getUid: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: 'ty0 | Type, underlying: 'underlying0}} +//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, ty: Type,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: 'ty0 | Type, underlying: 'underlying0}} +//│ fun setUid: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: 'ty0 | Type, underlying: 'underlying0}} +//│ fun unwrap: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying +//│ } + +let uid = 0 +let ty = Type("A") +let underlying = 42 +let a = { uid, underlying: { ty, underlying } } +//│ let uid: 0 +//│ let ty: Type +//│ let underlying: 42 +//│ let a: {uid: 0, underlying: {ty: Type, underlying: 42}} +//│ uid +//│ = 0 +//│ ty +//│ = Type {} +//│ underlying +//│ = 42 +//│ a +//│ = { uid: 0, underlying: { ty: Type {}, underlying: 42 } } + +Test1.unwrap(a) +//│ 42 +//│ res +//│ = 42 + +Test1.getUid(a) +//│ 0 +//│ res +//│ = 0 + +Test1.setUid(a, 1) +//│ {uid: int, underlying: {ty: Type, underlying: 42}} +//│ res +//│ = { underlying: { ty: Type {}, underlying: 42 }, uid: 1 } + +Test1.getType(a).name +//│ string +//│ res +//│ = 'A' + +a.underlying.ty.name +//│ string +//│ res +//│ = 'A' + +let b = Test1.setType(a, Type("B")) +//│ let b: {uid: int, underlying: {ty: Type, underlying: 42}} +//│ b +//│ = { underlying: { underlying: 42, ty: Type {} }, uid: 0 } + +Test1.getType(b).name +//│ string +//│ res +//│ = 'B' + +b.underlying.ty.name +//│ string +//│ res +//│ = 'B' + + From eda16a57adf249c71052c361498b482bce43dc2c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 9 Mar 2023 13:19:48 +0800 Subject: [PATCH 160/498] WIP Add missing force() when typing typing unit terms --- shared/src/main/scala/mlscript/Typer.scala | 1 + shared/src/test/diff/nu/BadClasses.mls | 26 +++++++++++++++++++++ shared/src/test/diff/nu/TypingUnitTerms.mls | 17 ++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 shared/src/test/diff/nu/TypingUnitTerms.mls diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 16e35e2925..a759e9d957 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -970,6 +970,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case Blk(stmts) => if (newDefs) { val ttu = typeTypingUnit(TypingUnit(stmts), allowPure = false) + ttu.force() // TODO check unused defs // ttu.res ttu.result.getOrElse(UnitType) diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index d4cbd2dd6d..dd732ef8ea 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -34,3 +34,29 @@ class C0 extends M0(true) //│ class C0() +// TODO catch this at typing +class Foo { + fun foo = 0 + fun bar = foo +} +//│ class Foo() { +//│ fun bar: 0 +//│ fun foo: 0 +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol foo + +// FIXME +class Foo { + let foo = 0 + fun bar = foo +} +//│ class Foo() { +//│ fun bar: 0 +//│ let foo: 0 +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol foo + + + diff --git a/shared/src/test/diff/nu/TypingUnitTerms.mls b/shared/src/test/diff/nu/TypingUnitTerms.mls new file mode 100644 index 0000000000..77887269a7 --- /dev/null +++ b/shared/src/test/diff/nu/TypingUnitTerms.mls @@ -0,0 +1,17 @@ +:NewParser +:NewDefs + + +:e +fun test = + let x = 0(0) + 1 +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.7: let x = 0(0) +//│ ║ ^^^^ +//│ ╟── integer literal of type `0` is not a function +//│ ║ l.7: let x = 0(0) +//│ ╙── ^ +//│ fun test: 1 + + From cc04b0d1a338f86fbcfd694b11a9487852df42f5 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 9 Mar 2023 15:06:09 +0800 Subject: [PATCH 161/498] Fix uncaught errors swallowed --- shared/src/test/diff/codegen/Mixin.mls | 22 +++++++++++++++++++ shared/src/test/scala/mlscript/ReplHost.scala | 9 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index fd6ed813c1..6ca81e4f2c 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -505,3 +505,25 @@ Barr.y //│ res //│ = 1 +:e +:ge +mixin Base { + fun x = y +} +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.511: fun x = y +//│ ╙── ^ +//│ mixin Base() { +//│ fun x: error +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol y + + +:re +module Test extends Base +//│ module Test() { +//│ fun x: error +//│ } +//│ Runtime error: +//│ ReferenceError: Base is not defined diff --git a/shared/src/test/scala/mlscript/ReplHost.scala b/shared/src/test/scala/mlscript/ReplHost.scala index 0968058db6..c13b421f61 100644 --- a/shared/src/test/scala/mlscript/ReplHost.scala +++ b/shared/src/test/scala/mlscript/ReplHost.scala @@ -37,7 +37,13 @@ final case class ReplHost() { buffer.delete(buffer.length - 3, buffer.length) val reply = buffer.toString() reply.linesIterator.find(_.startsWith(ReplHost.syntaxErrorHead)) match { - case None => ReplHost.Result(reply, None) + case None => reply.linesIterator.find(_.startsWith(ReplHost.uncaughtErrorHead)) match { + case None => ReplHost.Result(reply, None) + case Some(uncaughtErrorLine) => { + val message = uncaughtErrorLine.substring(ReplHost.uncaughtErrorHead.length) + ReplHost.Error(false, message) + } + } case Some(syntaxErrorLine) => val message = syntaxErrorLine.substring(ReplHost.syntaxErrorHead.length) ReplHost.Error(true, message) @@ -141,6 +147,7 @@ object ReplHost { * The syntax error beginning text from Node.js. */ private val syntaxErrorHead = "Uncaught SyntaxError: " + private val uncaughtErrorHead = "Uncaught " /** * The base class of all kinds of REPL replies. From a9b9f25990a1c6dee4de976a74097dffae579d1a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 9 Mar 2023 17:41:29 +0800 Subject: [PATCH 162/498] WIP Misc --- shared/src/main/scala/mlscript/Typer.scala | 1 + .../main/scala/mlscript/codegen/Scope.scala | 1 + shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/test/diff/nu/BasicMixins.mls | 68 ++++++++++++---- shared/src/test/diff/nu/ClassField.mls | 78 +++++++++++++++++++ shared/src/test/diff/nu/ParamOverride.mls | 8 +- 6 files changed, 136 insertions(+), 22 deletions(-) create mode 100644 shared/src/test/diff/nu/ClassField.mls diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index a759e9d957..787f114067 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -245,6 +245,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) "false" -> FalseType, "document" -> BotType, "window" -> BotType, + "typeof" -> fun(singleTup(TopType), StrType)(noProv), "toString" -> fun(singleTup(TopType), StrType)(noProv), "not" -> fun(singleTup(BoolType), BoolType)(noProv), "succ" -> fun(singleTup(IntType), IntType)(noProv), diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 0871ec9b73..4177149a69 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -39,6 +39,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { "div", "gt", "not", + "typeof", "toString", "negate", "eq", diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 1d05f8ebcc..8380cd21aa 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -581,7 +581,7 @@ trait TermImpl extends StatementImpl { self: Term => case DecLit(value) => value.toString case StrLit(value) => '"'.toString + value + '"' case UnitLit(value) => if (value) "undefined" else "null" - case Var(name) => name + case v @ Var(name) => name + v.uid.fold("")("::"+_.toString) case Asc(trm, ty) => s"$trm : ${ty.show}" |> bra case Lam(pat, rhs) => s"($pat) => $rhs" |> bra case App(lhs, rhs) => s"${lhs.print(!lhs.isInstanceOf[App])} ${rhs.print(true)}" |> bra diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 9710b846d3..3cf5168e18 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -1,9 +1,7 @@ :NewParser :NewDefs -:NoJS -// :d mixin BaseTest { fun test = super.base } @@ -23,7 +21,7 @@ mixin BaseInc { //│ fun test2: 'base //│ } -// :d +// TODO reject by typing class Base1(base: int) extends BaseTest, BaseInc { fun test3 = [base, this.base] } @@ -35,18 +33,24 @@ class Base1(base: int) extends BaseTest, BaseInc { Base1(1).test //│ int +//│ res +//│ = NaN Base1(1).test2 //│ int +//│ res +//│ = 1 Base1(1).test3 //│ (int, int,) +//│ res +//│ = [ 1, 1 ] // TODO class Base1(base) extends BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.47: class Base1(base) extends BaseTest +//│ ║ l.51: class Base1(base) extends BaseTest //│ ╙── ^^^^ //│ class Base1(base: error) { //│ fun test: error @@ -54,28 +58,32 @@ class Base1(base) extends BaseTest Base1 //│ (base: error,) -> Base1 +//│ res +//│ = [Function (anonymous)] { class: [Function: Base11] } // TODO Base1(1).test //│ error +//│ res +//│ = undefined :e class Base1(x) extends BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.64: class Base1(x) extends BaseTest +//│ ║ l.72: class Base1(x) extends BaseTest //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.64: class Base1(x) extends BaseTest +//│ ║ l.72: class Base1(x) extends BaseTest //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: error}` does not have field 'base' -//│ ║ l.64: class Base1(x) extends BaseTest +//│ ║ l.72: class Base1(x) extends BaseTest //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.8: fun test = super.base +//│ ║ l.6: fun test = super.base //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.8: fun test = super.base +//│ ║ l.6: fun test = super.base //│ ╙── ^^^^^ //│ class Base1(x: error) { //│ fun test: nothing @@ -84,18 +92,20 @@ class Base1(x) extends BaseTest :e class Base1(x): BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.85: class Base1(x): BaseTest +//│ ║ l.93: class Base1(x): BaseTest //│ ╙── ^ //│ ╔══[ERROR] mixins cannot be used as types -//│ ║ l.85: class Base1(x): BaseTest +//│ ║ l.93: class Base1(x): BaseTest //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.85: class Base1(x): BaseTest +//│ ║ l.93: class Base1(x): BaseTest //│ ╙── ^^^^^^^^ //│ class Base1(x: error) Base1 //│ (x: error,) -> Base1 +//│ res +//│ = [Function (anonymous)] { class: [class Base13] } // :ns @@ -110,7 +120,7 @@ mixin Foo { :e module Base1(base: int, misc: string) extends Foo //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.111: module Base1(base: int, misc: string) extends Foo +//│ ║ l.121: module Base1(base: int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ module Base1(base: int, misc: string) { //│ fun test: (int & 'a) -> (int, 'a, string,) @@ -118,6 +128,8 @@ module Base1(base: int, misc: string) extends Foo Base1.test //│ (int & 'a) -> (int, 'a, string,) +//│ res +//│ = [Function: test] mixin WrapBase { @@ -154,13 +166,19 @@ module WrapBase1 extends WrapBase, Wrap WrapBase1 //│ WrapBase1 +//│ res +//│ = WrapBase1 { class: [Function: WrapBase1] } // :d WrapBase1.wrapA //│ int -> (int,) +//│ res +//│ = [Function: wrapA] WrapBase1.wrap //│ 'a -> ('a,) +//│ res +//│ = [Function: wrap] // :d // WrapBase1.wrap @@ -168,29 +186,37 @@ WrapBase1.wrap WrapBase1.wrap(1) //│ (1,) +//│ res +//│ = [ 1 ] WrapBase1.wrap("ok") //│ ("ok",) +//│ res +//│ = [ 'ok' ] WrapBase1.wrapA(1) //│ (int,) +//│ res +//│ = [ 1 ] :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.180: WrapBase1.wrapA("ok") +//│ ║ l.204: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.180: WrapBase1.wrapA("ok") +//│ ║ l.204: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.126: fun wrapA(x: int) = x : int +//│ ║ l.138: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.136: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.148: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error +//│ res +//│ = [ 'ok' ] @@ -202,11 +228,19 @@ module WrapBase2 extends WrapBase, Wrap, Wrap, Wrap let w = WrapBase2.wrap //│ let w: 'a -> ((('a,),),) +//│ w +//│ = [Function: wrap] let wd = w(1) //│ let wd: (((1,),),) +//│ wd +//│ = [ [ [ 1 ] ] ] +// TODO implement _1 wd._1._1._1 + 1 //│ int +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading '_1') diff --git a/shared/src/test/diff/nu/ClassField.mls b/shared/src/test/diff/nu/ClassField.mls new file mode 100644 index 0000000000..283eb544f3 --- /dev/null +++ b/shared/src/test/diff/nu/ClassField.mls @@ -0,0 +1,78 @@ +:NewParser +:NewDefs + + + +class Foo(x: int) +//│ class Foo(x: int) + +Foo +//│ (x: int,) -> Foo +//│ res +//│ = [Function (anonymous)] { class: [class Foo] } + +typeof(Foo) +//│ string +//│ res +//│ = 'function' + +let f = Foo(123) +//│ let f: Foo +//│ f +//│ = Foo {} + +typeof(f) +//│ string +//│ res +//│ = 'object' + +:e +let cls = Foo.class +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.30: let cls = Foo.class +//│ ║ ^^^^^^^^^ +//│ ╟── reference of type `(x: int,) -> Foo` does not have field 'class' +//│ ║ l.30: let cls = Foo.class +//│ ╙── ^^^ +//│ let cls: error +//│ cls +//│ = [class Foo] + +typeof(cls) +//│ string +//│ res +//│ = 'function' + + + +mixin Base +//│ mixin Base() + +class Derived extends Base +//│ class Derived() + +// * Strangely, we now get `{ class: [Function: Derived] }` +Derived +//│ () -> Derived +//│ res +//│ = [Function (anonymous)] { class: [Function: Derived] } + +:e +let cls = Derived.class +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.61: let cls = Derived.class +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── reference of type `() -> Derived` does not have field 'class' +//│ ║ l.61: let cls = Derived.class +//│ ╙── ^^^^^^^ +//│ let cls: error +//│ cls +//│ = [Function: Derived] + +typeof(cls) +//│ string +//│ res +//│ = 'function' + + + diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index b7634c4ab2..6c3b232edc 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -84,18 +84,18 @@ Test1.n class Test2(n: string) extends Base1(1/2), Derived1(1) { - fun bar = [this.foo, n, this.original] + fun bar = [this.foo, n, this.n, this.original] } //│ class Test2(n: string) { -//│ fun bar: ((int, 1, number,), string, number,) +//│ fun bar: ((int, 1, number,), string, 1, number,) //│ fun foo: (int, 1, number,) //│ fun original: number //│ } Test2("test").bar -//│ ((int, 1, number,), string, number,) +//│ ((int, 1, number,), string, 1, number,) //│ res -//│ = [ [ 1, 'test', 0.5 ], 'test', 0.5 ] +//│ = [ [ 1, 'test', 0.5 ], 'test', 'test', 0.5 ] // FIXME class Test3(n: string) extends Base1(1/2), Derived1(length(n)) { From c574512b9dc6dbeeea67bda9aac6755c9b777e2c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 9 Mar 2023 18:02:07 +0800 Subject: [PATCH 163/498] WIP Forbid misuse of `super` and make it work in classes --- .../src/main/scala/mlscript/JSBackend.scala | 3 +- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 3 ++ shared/src/main/scala/mlscript/Typer.scala | 11 +++- .../main/scala/mlscript/codegen/Scope.scala | 5 -- shared/src/main/scala/mlscript/helpers.scala | 3 ++ shared/src/main/scala/mlscript/syntax.scala | 1 + shared/src/test/diff/codegen/Super.mls | 42 ++++++--------- shared/src/test/diff/nu/BadSuper.mls | 52 +++++++++++++++++++ shared/src/test/diff/nu/ParamOverride.mls | 8 +-- 10 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 shared/src/test/diff/nu/BadSuper.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 7db613887c..86168b33f6 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -151,6 +151,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateTerm(term: Term)(implicit scope: Scope): JSExpr = term match { case _ if term.desugaredTerm.isDefined => translateTerm(term.desugaredTerm.getOrElse(die)) case Var(name) => translateVar(name, false) + case Super() => JSIdent("super") case Lam(params, body) => val lamScope = scope.derive("Lam") val patterns = translateParams(params)(lamScope) @@ -422,7 +423,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { )(implicit scope: Scope): JSClassDecl = { // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") - classScope.declareSuper() val members = classSymbol.methods.map { translateClassMember(_)(classScope) } @@ -446,7 +446,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { )(implicit scope: Scope): JSClassMethod = { val getterScope = scope.derive(s"getter ${mixinSymbol.lexicalName}") val mixinScope = getterScope.derive(s"mixin ${mixinSymbol.lexicalName}") - mixinScope.declareSuper() // Collect class fields. val fields = mixinSymbol.body.collectFields ++ mixinSymbol.body.collectTypeNames.flatMap(resolveTraitFields) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 2ac85e295f..57c2f88b4a 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -267,6 +267,7 @@ object NewLexer { "interface", "extends", "override", + "super", "new", "namespace", "module", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 4e31f3b4d6..32bbf17998 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -481,6 +481,9 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (IDENT(nme, false), l0) :: _ => consume exprCont(Var(nme).withLoc(S(l0)), prec, allowNewlines = false) + case (KEYWORD("super"), l0) :: _ => + consume + exprCont(Super().withLoc(S(l0)), prec, allowNewlines = false) case (br @ BRACKETS(bk @ (Round | Square | Curly), toks), loc) :: _ => consume val res = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 787f114067..2b2c4ebd1c 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -741,6 +741,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // currently we get things like "flows into variable reference" // but we used to get the better "flows into object receiver" or "flows into applied expression"... case lit: Lit => ClassTag(lit, lit.baseClasses)(prov) + case Super() => + err(s"Illegal use of `super`", term.toLoc)(raise) + typeTerm(Var("super").withLocOf(term)) case App(Var("neg" | "~"), trm) => typeTerm(trm).neg(prov) case App(App(Var("|"), lhs), rhs) => typeTerm(lhs) | (typeTerm(rhs), prov) @@ -940,7 +943,13 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) con(mth_ty.toPT.instantiate, FunctionType(singleTup(o_ty), res)(prov), res) case N => if (!newDefs && fieldName.name.isCapitalized) err(msg"Method ${fieldName.name} not found", term.toLoc) - else rcdSel(obj, fieldName) // TODO: no else? + else { + val realPrefix = obj match { + case Super() => Var("super").withLocOf(obj) + case _ => obj + } + rcdSel(realPrefix, fieldName) + } } obj match { case Var(name) if name.isCapitalized && ctx.tyDefs.isDefinedAt(name) => // explicit retrieval diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 4177149a69..efedf902c6 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -283,11 +283,6 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } - def declareSuper(): Unit = { - val symbol = ValueSymbol("super", "super", Some(false), false) - register(symbol) - } - def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean): ValueSymbol = { val runtimeName = lexicalValueSymbols.get(lexicalName) match { // If we are implementing a stub symbol and the stub symbol did not shadow any other diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 8380cd21aa..3741cb0b57 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -566,6 +566,7 @@ trait TermImpl extends StatementImpl { self: Term => case Where(_, _) => s"constraint clause" case Forall(_, _) => s"forall clause" case Inst(bod) => "explicit instantiation" + case Super() => "super" } } @@ -614,6 +615,7 @@ trait TermImpl extends StatementImpl { self: Term => case Where(bod, wh) => s"${bod} where {${wh.mkString("; ")}}" case Forall(ps, bod) => s"forall ${ps.mkString(", ")}. ${bod}" case Inst(bod) => s"${bod.print(true)}!" + case Super() => "super" }} def toTypeRaise(implicit raise: Raise): Type = toType match { @@ -939,6 +941,7 @@ trait StatementImpl extends Located { self: Statement => case Where(bod, wh) => bod :: wh case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil + case Super() => Nil case NuTypeDef(k, nme, tps, ps, sig, pars, sup, ths, bod) => nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index ee7097d989..6c757eefba 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -78,6 +78,7 @@ final case class TyApp(lhs: Term, targs: Ls[Type]) extends Ter final case class Where(body: Term, where: Ls[Statement]) extends Term final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term +final case class Super() extends Term sealed abstract class IfBody extends IfBodyImpl // final case class IfTerm(expr: Term) extends IfBody // rm? diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index cd905eba48..1f51042189 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -3,7 +3,7 @@ -// FIXME `let` fields should not be getters +// * FIXME `let` fields should not be getters :js mixin Foo0 { let foo0 = 0 @@ -73,10 +73,13 @@ module Test0 extends Foo0, Foo1 :ShowRepl :js -// FIXME prevent misuse of `super` using the type system +:e mixin Foo2 { fun foo2 = super } +//│ ╔══[ERROR] Illegal use of `super` +//│ ║ l.78: fun foo2 = super +//│ ╙── ^^^^^ //│ mixin Foo2() { //│ super: 'super //│ fun foo2: 'super @@ -100,7 +103,7 @@ mixin Foo2 { //│ Syntax error: //│ 'super' keyword unexpected here -:ShowRepl +:re :js module Test0 extends Foo2 //│ module Test0() { @@ -124,29 +127,8 @@ module Test0 extends Foo2 //│ }; //│ globalThis.Test01 = typing_unit5.Test01; //│ // End of generated code -//│ ┌ Block at Super.mls:105 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let typing_unit5 = { -//│ │ │ cache: {}, -//│ │ │ get Test01() { -//│ │ │ if (this.cache.Test01 === undefined) { -//│ │ │ class Test01 extends Foo2(Object) { -//│ │ │ constructor() { -//│ │ │ super(); -//│ │ │ } -//│ │ │ } -//│ │ │ this.cache.Test01 = new Test01(); -//│ │ │ this.cache.Test01["class"] = Test01; -//│ │ │ } -//│ │ │ return this.cache.Test01; -//│ │ │ } -//│ │ │ }; -//│ │ │ globalThis.Test01 = typing_unit5.Test01; -//│ │ └── Reply -//│ │ Uncaught ReferenceError: Foo2 is not defined -//│ │ at get Test01 [as Test01] (REPL9:1:78) -//│ └── No queries +//│ Runtime error: +//│ ReferenceError: Foo2 is not defined :re Test0 @@ -163,3 +145,11 @@ Test0.foo2 //│ ReferenceError: Test01 is not defined +class Foo extends Foo0 { + fun foo0(n) = [super.foo0, super.foo0 + n] +} +//│ class Foo() { +//│ fun foo0: int -> (0, int,) +//│ } + + diff --git a/shared/src/test/diff/nu/BadSuper.mls b/shared/src/test/diff/nu/BadSuper.mls new file mode 100644 index 0000000000..655da0163f --- /dev/null +++ b/shared/src/test/diff/nu/BadSuper.mls @@ -0,0 +1,52 @@ +:NewParser +:NewDefs + + +mixin M0 { + fun f = 42 +} +//│ mixin M0() { +//│ fun f: 42 +//│ } + +:e +mixin M1 { + fun g = super +} +//│ ╔══[ERROR] Illegal use of `super` +//│ ║ l.14: fun g = super +//│ ╙── ^^^^^ +//│ mixin M1() { +//│ super: 'super +//│ fun g: 'super +//│ } +//│ Syntax error: +//│ 'super' keyword unexpected here + +:re +module C0 extends M0, M1 +C0.g +//│ module C0() { +//│ fun f: 42 +//│ fun g: {f: 42} +//│ } +//│ {f: 42} +//│ res +//│ Runtime error: +//│ ReferenceError: M1 is not defined + + +:e +class Foo { + fun f = super +} +//│ ╔══[ERROR] Illegal use of `super` +//│ ║ l.41: fun f = super +//│ ╙── ^^^^^ +//│ class Foo() { +//│ fun f: Foo +//│ } +//│ Syntax error: +//│ 'super' keyword unexpected here + + diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index 6c3b232edc..fd84468b84 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -97,7 +97,7 @@ Test2("test").bar //│ res //│ = [ [ 1, 'test', 0.5 ], 'test', 'test', 0.5 ] -// FIXME + class Test3(n: string) extends Base1(1/2), Derived1(length(n)) { fun foo = [super.foo, n, this.original] } @@ -105,14 +105,10 @@ class Test3(n: string) extends Base1(1/2), Derived1(length(n)) { //│ fun foo: ((int, int, number,), string, number,) //│ fun original: number //│ } -//│ Code generation encountered an error: -//│ unresolved symbol super -// FIXME Test3("test").foo //│ ((int, int, number,), string, number,) //│ res -//│ Runtime error: -//│ ReferenceError: Test3 is not defined +//│ = [ [ 4, 'test', 0.5 ], 'test', 0.5 ] From 438c960911feae6b6f7431e4273c71c97a7c4053 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 9 Mar 2023 18:26:13 +0800 Subject: [PATCH 164/498] WIP Fix class type param static semantics wrt super --- .../main/scala/mlscript/TyperDatatypes.scala | 10 +- shared/src/test/diff/nu/BasicMixins.mls | 196 ++++++++++++------ shared/src/test/diff/nu/ParamOverride.mls | 10 +- shared/src/test/diff/nu/ParamOverriding.mls | 11 +- 4 files changed, 143 insertions(+), 84 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 772fc76d9e..84003627b7 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -359,9 +359,9 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => - val thisType = superType & + val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & - RecordType(tparamFields)(ttp(td.params, isType = true)) + RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { assert(finalType.level === lvl) constrain(thisType, finalType) @@ -371,10 +371,10 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => (thisType, members) } + // * We start from an empty super type. val baseType = - // clsNameToNomTag(td)(provTODO, ctx) & - // RecordType(tparamFields ::: typedParams)(ttp(td.params, isType = true)) - RecordType(typedParams)(ttp(td.params, isType = true)) + RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) // val baseMems = inherit(td.parents, baseType, Nil) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 3cf5168e18..f29c967b0e 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -2,6 +2,13 @@ :NewDefs +mixin Base { + let base = 42 +} +//│ mixin Base() { +//│ let base: 42 +//│ } + mixin BaseTest { fun test = super.base } @@ -10,102 +17,129 @@ mixin BaseTest { //│ fun test: 'base //│ } + +module Base0 extends Base, BaseTest +//│ module Base0() { +//│ let base: 42 +//│ fun test: 42 +//│ } + +Base0 +//│ Base0 +//│ res +//│ = Base0 { class: [Function: Base0] } + +Base0.test +//│ 42 +//│ res +//│ = 42 + + +:e +class Base1(base: int) extends BaseTest { + fun test2 = [base, this.base] +} +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.39: class Base1(base: int) extends BaseTest { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.40: fun test2 = [base, this.base] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.41: } +//│ ║ ^ +//│ ╟── Object of type `anything` does not have field 'base' +//│ ║ l.39: class Base1(base: int) extends BaseTest { +//│ ║ ^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.13: fun test = super.base +//│ ║ ^^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.13: fun test = super.base +//│ ╙── ^^^^^ +//│ class Base1(base: int) { +//│ fun test: nothing +//│ fun test2: (int, int,) +//│ } + + +mixin BaseOf(base: int) { + fun original = base +} +//│ mixin BaseOf(base: int) { +//│ fun original: int +//│ } + mixin BaseInc { - fun test = super.base + 1 - fun test2 = this.base + fun base = super.base + 1 + fun test2 = [this.original, this.base] } //│ mixin BaseInc() { //│ super: {base: int} -//│ this: {base: 'base} -//│ fun test: int -//│ fun test2: 'base +//│ this: {base: 'base, original: 'original} +//│ fun base: int +//│ fun test2: ('original, 'base,) //│ } -// TODO reject by typing -class Base1(base: int) extends BaseTest, BaseInc { - fun test3 = [base, this.base] + +class Base2(x: int) extends BaseOf(x + 1), BaseTest, BaseInc { + fun base = x + fun overridden = super.base } -//│ class Base1(base: int) { +//│ class Base2(x: int) { +//│ fun base: int +//│ fun original: int +//│ fun overridden: int //│ fun test: int -//│ fun test2: int -//│ fun test3: (int, int,) +//│ fun test2: (int, int,) //│ } -Base1(1).test +Base2(11).base //│ int //│ res -//│ = NaN +//│ = 11 -Base1(1).test2 +Base2(11).overridden //│ int //│ res -//│ = 1 - -Base1(1).test3 -//│ (int, int,) -//│ res -//│ = [ 1, 1 ] - - -// TODO -class Base1(base) extends BaseTest -//│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.51: class Base1(base) extends BaseTest -//│ ╙── ^^^^ -//│ class Base1(base: error) { -//│ fun test: error -//│ } +//│ = 13 -Base1 -//│ (base: error,) -> Base1 +Base2(11).test +//│ int //│ res -//│ = [Function (anonymous)] { class: [Function: Base11] } +//│ = 12 -// TODO -Base1(1).test -//│ error +Base2(11).test2 +//│ (int, int,) //│ res -//│ = undefined +//│ = [ 12, 11 ] -:e -class Base1(x) extends BaseTest +// TODO +class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.72: class Base1(x) extends BaseTest -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.72: class Base1(x) extends BaseTest -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `{x: error}` does not have field 'base' -//│ ║ l.72: class Base1(x) extends BaseTest -//│ ║ ^^^ -//│ ╟── Note: constraint arises from field selection: -//│ ║ l.6: fun test = super.base -//│ ║ ^^^^^^^^^^ -//│ ╟── from reference: -//│ ║ l.6: fun test = super.base -//│ ╙── ^^^^^ -//│ class Base1(x: error) { -//│ fun test: nothing +//│ ║ l.117: class Base2(x) extends BaseOf(x + 1), BaseTest +//│ ╙── ^ +//│ class Base2(x: error) { +//│ fun original: int +//│ fun test: int //│ } :e class Base1(x): BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.93: class Base1(x): BaseTest -//│ ╙── ^ +//│ ║ l.127: class Base1(x): BaseTest +//│ ╙── ^ //│ ╔══[ERROR] mixins cannot be used as types -//│ ║ l.93: class Base1(x): BaseTest -//│ ╙── ^^^^^^^^ +//│ ║ l.127: class Base1(x): BaseTest +//│ ╙── ^^^^^^^^ //│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.93: class Base1(x): BaseTest -//│ ╙── ^^^^^^^^ +//│ ║ l.127: class Base1(x): BaseTest +//│ ╙── ^^^^^^^^ //│ class Base1(x: error) Base1 //│ (x: error,) -> Base1 //│ res -//│ = [Function (anonymous)] { class: [class Base13] } +//│ = [Function (anonymous)] { class: [class Base11] } // :ns @@ -120,14 +154,38 @@ mixin Foo { :e module Base1(base: int, misc: string) extends Foo //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.121: module Base1(base: int, misc: string) extends Foo +//│ ║ l.155: module Base1(base: int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Object of type `anything` does not have field 'misc' +//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ ^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ║ ^^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Object of type `anything` does not have field 'base' +//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ ^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ║ ^^^^^^^^^^ +//│ ╟── from reference: +//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ╙── ^^^^^ //│ module Base1(base: int, misc: string) { -//│ fun test: (int & 'a) -> (int, 'a, string,) +//│ fun test: (int & 'a) -> (int, 'a, nothing,) //│ } Base1.test -//│ (int & 'a) -> (int, 'a, string,) +//│ (int & 'a) -> (int, 'a, nothing,) //│ res //│ = [Function: test] @@ -203,16 +261,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.204: WrapBase1.wrapA("ok") +//│ ║ l.262: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.204: WrapBase1.wrapA("ok") +//│ ║ l.262: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.138: fun wrapA(x: int) = x : int +//│ ║ l.196: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.148: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.206: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error //│ res diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index fd84468b84..aadf53e5ac 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -87,13 +87,13 @@ class Test2(n: string) extends Base1(1/2), Derived1(1) { fun bar = [this.foo, n, this.n, this.original] } //│ class Test2(n: string) { -//│ fun bar: ((int, 1, number,), string, 1, number,) -//│ fun foo: (int, 1, number,) +//│ fun bar: ((int, string, number,), string, string, number,) +//│ fun foo: (int, string, number,) //│ fun original: number //│ } Test2("test").bar -//│ ((int, 1, number,), string, 1, number,) +//│ ((int, string, number,), string, string, number,) //│ res //│ = [ [ 1, 'test', 0.5 ], 'test', 'test', 0.5 ] @@ -102,12 +102,12 @@ class Test3(n: string) extends Base1(1/2), Derived1(length(n)) { fun foo = [super.foo, n, this.original] } //│ class Test3(n: string) { -//│ fun foo: ((int, int, number,), string, number,) +//│ fun foo: ((int, string, number,), string, number,) //│ fun original: number //│ } Test3("test").foo -//│ ((int, int, number,), string, number,) +//│ ((int, string, number,), string, number,) //│ res //│ = [ [ 4, 'test', 0.5 ], 'test', 0.5 ] diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 4cd0931305..4f11877290 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -13,18 +13,19 @@ mixin Over { class Base1(p: int) extends Over { fun test = [p, this.p] - // fun test2 = super.p // TODO + fun test2 = super.p } //│ class Base1(p: int) { //│ fun p: "hi" -//│ fun test: (int, "hi",) +//│ fun test: (int, int,) +//│ fun test2: int //│ } Base1(123).test -//│ (int, "hi",) +//│ (int, int,) -// TODO -// Base1(123).test2 +Base1(123).test2 +//│ int From 3b9dc5d18bc87032017a3c2b0cd5aafcc6802785 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Fri, 10 Mar 2023 23:23:33 +0800 Subject: [PATCH 165/498] Fix super parameters order (#4) --- .../src/main/scala/mlscript/JSBackend.scala | 4 +- shared/src/test/diff/codegen/Mixin.mls | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 86168b33f6..c820a1f3ff 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -541,7 +541,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case (_, Fld(mut, spec, trm)) => translateTerm(trm)(getterScope) } case _ => Nil - }).flatten + }).map(_.reverse).flatten val decl = JSClassNewDecl(moduleSymbol.runtimeName, fields, base, @@ -619,7 +619,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case (_, Fld(mut, spec, trm)) => translateTerm(trm)(constructorScope) } case _ => Nil - }).flatten + }).map(_.reverse).flatten JSClassNewDecl(classSymbol.runtimeName, fields, base, restRuntime match { case Some(restRuntime) => superParameters.reverse :+ JSIdent(s"...$restRuntime") diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 6ca81e4f2c..e3d3b4f5d5 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -527,3 +527,46 @@ module Test extends Base //│ } //│ Runtime error: //│ ReferenceError: Base is not defined + +mixin MA(a: int) +mixin MB(b1: int, b2: int) +mixin MC(c: int) +//│ mixin MA(a: int) +//│ mixin MB(b1: int, b2: int) +//│ mixin MC(c: int) + +:js +module MM extends MA(1), MB(2, 3), MC(4) +//│ module MM() +//│ // Prelude +//│ let typing_unit22 = { +//│ cache: {}, +//│ get MM() { +//│ if (this.cache.MM === undefined) { +//│ class MM extends MC(MB(MA(Object))) { +//│ constructor() { +//│ super(4, 2, 3, 1); +//│ } +//│ } +//│ this.cache.MM = new MM(); +//│ this.cache.MM["class"] = MM; +//│ } +//│ return this.cache.MM; +//│ } +//│ }; +//│ globalThis.MM = typing_unit22.MM; +//│ // End of generated code + +MM.a +MM.b1 +MM.b2 +MM.c +//│ 4 +//│ res +//│ = 1 +//│ res +//│ = 2 +//│ res +//│ = 3 +//│ res +//│ = 4 From d525f5d0f1eb636b2d1c634c2293addbe390b5b4 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Sat, 11 Mar 2023 13:11:30 +0800 Subject: [PATCH 166/498] Fix Cache Access (#5) --- .../src/main/scala/mlscript/JSBackend.scala | 22 ++++-- shared/src/test/diff/codegen/Mixin.mls | 72 ++++++++++++++++--- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index c820a1f3ff..6d94b865ec 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -567,7 +567,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { rest: Opt[Str] = N )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"${classSymbol.lexicalName} getter") - val classBody = translateNewClassExpression(classSymbol, superFields, rest)(getterScope) + val cacheSymbol = getterScope.declareValue("cache", Some(false), false) + val classBody = translateNewClassExpression(classSymbol, superFields, rest, cacheSymbol.runtimeName)(getterScope) val constructor = classBody match { case JSClassNewDecl(_, fields, _, _, _, _, _) => fields.map(JSNamePattern(_)) } @@ -576,6 +577,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } JSClassGetter(classSymbol.runtimeName, R(Ls( + JSConstDecl(cacheSymbol.runtimeName, JSField(JSIdent("this"), "cache")), JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), classSymbol.runtimeName), JSIdent("undefined")), Ls( JSExprStmt(JSClassExpr(classBody)), JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), classSymbol.runtimeName), @@ -589,7 +591,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateNewClassExpression( classSymbol: NewClassSymbol, superFields: Ls[Term] = Nil, - rest: Opt[Str] = N + rest: Opt[Str] = N, + cacheName: Str )(implicit scope: Scope): JSClassNewDecl = { // Translate class methods and getters. val classScope = scope.derive(s"class ${classSymbol.lexicalName}") @@ -597,7 +600,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val fields = classSymbol.body.collectFields ++ classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) val members = classSymbol.methods.map { - translateNewClassMember(_, fields)(classScope) + translateNewClassMember(_, fields, S(JSConstDecl(classSymbol.runtimeName, JSField(JSIdent(cacheName), classSymbol.runtimeName))))(classScope) } val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") @@ -668,7 +671,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { private def translateNewClassMember( method: MethodDef[Left[Term, Type]], - props: Ls[Str] = Nil + props: Ls[Str] = Nil, + selfClass: Opt[JSConstDecl] = N )(implicit scope: Scope): JSClassMemberDecl = { val name = method.nme.name // Create the method/getter scope. @@ -696,9 +700,15 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val bodyStmts = if (visitedSymbols(selfSymbol)) { val thisDecl = JSConstDecl(selfSymbol.runtimeName, JSIdent("this")) visitedSymbols -= selfSymbol - R(preDecs ::: (thisDecl :: bodyResult :: Nil)) + selfClass match { + case Some(selfClass) => R((selfClass :: preDecs) ::: (thisDecl :: bodyResult :: Nil)) + case _ => R(preDecs ::: (thisDecl :: bodyResult :: Nil)) + } } else { - R(preDecs ::: (bodyResult :: Nil)) + selfClass match { + case Some(selfClass) => R((selfClass :: preDecs) ::: (bodyResult :: Nil)) + case _ => R(preDecs ::: (bodyResult :: Nil)) + } } // Returns members depending on what it is. memberParams match { diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index e3d3b4f5d5..a769d17b95 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -12,6 +12,7 @@ class Lit(n: int) //│ let typing_unit = { //│ cache: {}, //│ get Add() { +//│ const cache = this.cache; //│ if (this.cache.Add === undefined) { //│ class Add { //│ #lhs; @@ -29,6 +30,7 @@ class Lit(n: int) //│ return this.cache.Add; //│ }, //│ get Lit() { +//│ const cache = this.cache; //│ if (this.cache.Lit === undefined) { //│ class Lit { //│ #n; @@ -53,6 +55,7 @@ class Lit(n: int) //│ │ │ let typing_unit = { //│ │ │ cache: {}, //│ │ │ get Add() { +//│ │ │ const cache = this.cache; //│ │ │ if (this.cache.Add === undefined) { //│ │ │ class Add { //│ │ │ #lhs; @@ -70,6 +73,7 @@ class Lit(n: int) //│ │ │ return this.cache.Add; //│ │ │ }, //│ │ │ get Lit() { +//│ │ │ const cache = this.cache; //│ │ │ if (this.cache.Lit === undefined) { //│ │ │ class Lit { //│ │ │ #n; @@ -124,7 +128,7 @@ mixin EvalBase { //│ }; //│ globalThis.EvalBase = typing_unit1.EvalBase; //│ // End of generated code -//│ ┌ Block at Mixin.mls:95 +//│ ┌ Block at Mixin.mls:99 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit1 = { @@ -159,6 +163,7 @@ class Neg(expr: A) //│ let typing_unit2 = { //│ cache: {}, //│ get Neg() { +//│ const cache = this.cache; //│ if (this.cache.Neg === undefined) { //│ class Neg { //│ #expr; @@ -175,12 +180,13 @@ class Neg(expr: A) //│ }; //│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:156 +//│ ┌ Block at Mixin.mls:160 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit2 = { //│ │ │ cache: {}, //│ │ │ get Neg() { +//│ │ │ const cache = this.cache; //│ │ │ if (this.cache.Neg === undefined) { //│ │ │ class Neg { //│ │ │ #expr; @@ -231,7 +237,7 @@ mixin EvalNeg { //│ }; //│ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:205 +//│ ┌ Block at Mixin.mls:211 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit3 = { @@ -286,7 +292,7 @@ mixin EvalNegNeg { //│ }; //│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:260 +//│ ┌ Block at Mixin.mls:266 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit4 = { @@ -337,7 +343,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ }; //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code -//│ ┌ Block at Mixin.mls:315 +//│ ┌ Block at Mixin.mls:321 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit5 = { @@ -380,7 +386,7 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:365 +//│ ┌ Block at Mixin.mls:371 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit6 = { cache: {} }; @@ -411,7 +417,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.412: class Bar(x: int, y: int) extends Foo(x + y) +//│ ║ l.418: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -511,7 +517,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.511: fun x = y +//│ ║ l.517: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error @@ -528,6 +534,51 @@ module Test extends Base //│ Runtime error: //│ ReferenceError: Base is not defined +:js +class Test(n: int) { + fun inc = Test(n + 1) +} +//│ class Test(n: int) { +//│ fun inc: Test +//│ } +//│ // Prelude +//│ let typing_unit21 = { +//│ cache: {}, +//│ get Test1() { +//│ const cache = this.cache; +//│ if (this.cache.Test1 === undefined) { +//│ class Test1 { +//│ #n; +//│ get n() { return this.#n; } +//│ constructor(n) { +//│ this.#n = n; +//│ } +//│ get inc() { +//│ const Test1 = cache.Test1; +//│ const n = this.#n; +//│ return Test1(n + 1); +//│ } +//│ }; +//│ this.cache.Test1 = ((n) => new Test1(n)); +//│ this.cache.Test1["class"] = Test1; +//│ } +//│ return this.cache.Test1; +//│ } +//│ }; +//│ globalThis.Test1 = typing_unit21.Test1; +//│ // End of generated code + +:js +Test(0).inc.n +//│ int +//│ // Prelude +//│ let typing_unit22 = { cache: {} }; +//│ // Query 1 +//│ res = Test1(0).inc.n; +//│ // End of generated code +//│ res +//│ = 1 + mixin MA(a: int) mixin MB(b1: int, b2: int) mixin MC(c: int) @@ -539,7 +590,7 @@ mixin MC(c: int) module MM extends MA(1), MB(2, 3), MC(4) //│ module MM() //│ // Prelude -//│ let typing_unit22 = { +//│ let typing_unit24 = { //│ cache: {}, //│ get MM() { //│ if (this.cache.MM === undefined) { @@ -554,7 +605,7 @@ module MM extends MA(1), MB(2, 3), MC(4) //│ return this.cache.MM; //│ } //│ }; -//│ globalThis.MM = typing_unit22.MM; +//│ globalThis.MM = typing_unit24.MM; //│ // End of generated code MM.a @@ -570,3 +621,4 @@ MM.c //│ = 3 //│ res //│ = 4 + From 4717e01e65880ec022039556cd4a4be0ebf98c2a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 11 Mar 2023 12:45:03 +0800 Subject: [PATCH 167/498] WIP Implement Eql and remove some needless type tag decapitalization --- local_testing.html | 47 ++++ .../scala/mlscript/ConstraintSolver.scala | 59 ++++- .../src/main/scala/mlscript/NuTypeDefs.scala | 4 +- shared/src/main/scala/mlscript/TypeDefs.scala | 19 +- .../main/scala/mlscript/TypeSimplifier.scala | 4 +- shared/src/main/scala/mlscript/Typer.scala | 78 +++--- .../main/scala/mlscript/TyperDatatypes.scala | 22 +- .../codegen/typescript/TsTypegen.scala | 20 +- shared/src/main/scala/mlscript/helpers.scala | 6 +- shared/src/test/diff/basics/Errors.fun | 4 +- shared/src/test/diff/basics/Negations.fun | 4 +- shared/src/test/diff/basics/Simplesub1.fun | 6 +- .../test/diff/codegen/IndirectRecursion.mls | 2 +- shared/src/test/diff/codegen/Mixin.mls | 75 ++---- shared/src/test/diff/codegen/NuClasses.mls | 61 +++++ .../src/test/diff/contys/AbstractBounds.mls | 2 +- shared/src/test/diff/fcp-lit/CPS_LB.mls | 4 +- shared/src/test/diff/fcp-lit/Leijen.mls | 56 ++--- shared/src/test/diff/fcp-lit/MLF.mls | 2 +- shared/src/test/diff/fcp-lit/QML.mls | 6 +- shared/src/test/diff/fcp/Church_CT.mls | 176 +++++++------- shared/src/test/diff/fcp/Church_ST.mls | 20 +- .../src/test/diff/fcp/ConstrainedTypes1.mls | 2 +- .../src/test/diff/fcp/ConstrainedTypes2.mls | 12 +- shared/src/test/diff/fcp/FCPTony.mls | 16 +- shared/src/test/diff/fcp/FunnyId.mls | 12 +- shared/src/test/diff/fcp/MoreChurch.mls | 10 +- shared/src/test/diff/fcp/NestedDataTypes.mls | 8 +- shared/src/test/diff/fcp/PaperTable.mls | 4 +- shared/src/test/diff/fcp/Proofs.mls | 6 +- .../test/diff/fcp/QML_exist_Classes_CT.mls | 104 ++++---- .../test/diff/fcp/QML_exist_Classes_ST.mls | 38 +-- .../diff/fcp/QML_exist_Classes_ST_Repro.mls | 12 +- .../src/test/diff/fcp/QML_exist_Records.mls | 8 +- shared/src/test/diff/fcp/SystemF.mls | 4 +- shared/src/test/diff/fcp/SystemF_2.mls | 118 ++++----- .../src/test/diff/fcp/ToChurchSimplif_CT.mls | 22 +- .../src/test/diff/fcp/ToChurchSimplif_ST.mls | 10 +- shared/src/test/diff/fcp/Vec.mls | 8 +- .../diff/mlf-examples/ex_casparticuliers.mls | 20 +- shared/src/test/diff/mlf-examples/ex_demo.mls | 56 ++--- .../src/test/diff/mlf-examples/ex_hashtbl.mls | 28 +-- .../test/diff/mlf-examples/ex_predicative.mls | 44 ++-- .../src/test/diff/mlf-examples/ex_selfapp.mls | 6 +- .../src/test/diff/mlf-examples/ex_shallow.mls | 14 +- shared/src/test/diff/mlscript/Addable.mls | 2 +- shared/src/test/diff/mlscript/Arrays.mls | 22 +- shared/src/test/diff/mlscript/Baber.mls | 8 +- shared/src/test/diff/mlscript/BadInherit.mls | 25 +- shared/src/test/diff/mlscript/BadMethods.mls | 24 +- shared/src/test/diff/mlscript/David2.mls | 2 +- shared/src/test/diff/mlscript/ExprProb.mls | 36 +-- .../src/test/diff/mlscript/ExprProb_Inv.mls | 30 +-- .../src/test/diff/mlscript/GenericClasses.mls | 6 +- shared/src/test/diff/mlscript/HeadOption.mls | 42 ++-- shared/src/test/diff/mlscript/JetBrains.mls | 2 +- shared/src/test/diff/mlscript/Luyu.mls | 2 +- shared/src/test/diff/mlscript/Match3.mls | 2 +- shared/src/test/diff/mlscript/Methods2.mls | 10 +- shared/src/test/diff/mlscript/Misc.mls | 24 +- shared/src/test/diff/mlscript/Mut.mls | 137 +++++------ .../test/diff/mlscript/NestedClassArgs.mls | 36 ++- shared/src/test/diff/mlscript/Paper.mls | 2 +- .../diff/mlscript/PolyVariantCodeReuse.mls | 28 +-- .../src/test/diff/mlscript/RecursiveTypes.mls | 16 +- .../test/diff/mlscript/RecursiveTypes2.mls | 8 +- shared/src/test/diff/mlscript/SafeDiv.mls | 2 +- shared/src/test/diff/mlscript/SelfNeg.mls | 8 +- shared/src/test/diff/mlscript/SelfNegs.mls | 2 +- shared/src/test/diff/mlscript/Seqs.mls | 2 +- .../src/test/diff/mlscript/SimpleMethods.mls | 2 +- shared/src/test/diff/mlscript/StressDNF.mls | 4 +- .../src/test/diff/mlscript/StressTraits.mls | 20 +- shared/src/test/diff/mlscript/StressUgly.mls | 6 +- shared/src/test/diff/mlscript/Tony.mls | 4 +- .../test/diff/mlscript/TrickyExtrusion.mls | 12 +- shared/src/test/diff/mlscript/TypeClasses.mls | 38 ++- shared/src/test/diff/mlscript/TypeDefs.mls | 2 +- shared/src/test/diff/mlscript/TypeRanges.mls | 8 +- shared/src/test/diff/mlscript/TypeTags.mls | 6 + shared/src/test/diff/mlscript/Undef.mls | 4 +- shared/src/test/diff/mlscript/Undefined.mls | 2 +- shared/src/test/diff/mlscript/Variant-sub.mls | 2 +- shared/src/test/diff/mlscript/Wildcards.mls | 2 +- shared/src/test/diff/nu/Ascription.mls | 35 +-- shared/src/test/diff/nu/BadClasses.mls | 13 +- shared/src/test/diff/nu/ECOOP23.mls | 12 +- shared/src/test/diff/nu/ECOOP23_codegen.mls | 6 +- shared/src/test/diff/nu/ECOOP23_min.mls | 18 +- shared/src/test/diff/nu/ECOOP23_repro.mls | 2 +- shared/src/test/diff/nu/ECOOP23_small.mls | 4 +- shared/src/test/diff/nu/Eql.mls | 224 ++++++++++++++++++ shared/src/test/diff/nu/EqlClasses.mls | 161 +++++++++++++ shared/src/test/diff/nu/FunSigs.mls | 32 ++- shared/src/test/diff/nu/GenericClasses.mls | 50 ++-- shared/src/test/diff/nu/GenericMixins.mls | 4 +- shared/src/test/diff/nu/Misc.mls | 106 +++++---- shared/src/test/diff/nu/Mut.mls | 103 ++++---- shared/src/test/diff/nu/MutualRec.mls | 11 + shared/src/test/diff/nu/NamedArgs.mls | 51 ++-- .../test/diff/nu/NewPolyVariantCodeReuse.mls | 10 +- .../test/diff/nu/NewPolyVariantCodeReuse2.mls | 10 +- shared/src/test/diff/nu/OverrideShorthand.mls | 2 +- shared/src/test/diff/nu/SelfRec.mls | 59 +++++ shared/src/test/diff/nu/SimpleRegionDSL.mls | 12 +- shared/src/test/diff/typegen/TypegenTerms.mls | 4 +- .../src/test/diff/typegen/TypegenTypedefs.mls | 10 +- shared/src/test/diff/ucs/MultiwayIf.mls | 10 +- shared/src/test/diff/ucs/SimpleUCS.mls | 2 +- .../src/test/scala/mlscript/DiffTests.scala | 2 +- 110 files changed, 1720 insertions(+), 1062 deletions(-) create mode 100644 shared/src/test/diff/codegen/NuClasses.mls create mode 100644 shared/src/test/diff/nu/Eql.mls create mode 100644 shared/src/test/diff/nu/EqlClasses.mls create mode 100644 shared/src/test/diff/nu/SelfRec.mls diff --git a/local_testing.html b/local_testing.html index d481874a30..b922c72e2f 100644 --- a/local_testing.html +++ b/local_testing.html @@ -51,6 +51,53 @@

Tip: additional definitions from the paper – copy and paste to try them ou
let res2 = TestLang2.eval(add2negadd11)

+
+
+class Some[A](value: A)
+
+mixin Foo { fun foo: int = 1 }
+mixin Bar { fun foo = Some(super.foo) }
+module ClsFoo extends Foo, Bar, Bar
+
+ClsFoo.foo
+
+
+
+class Some[A](value: A)
+module None
+
+mixin ComparePoint {
+  fun compare(lhs, rhs) = (lhs.x == rhs.x) && (lhs.y == rhs.y)
+}
+mixin CompareColored {
+  fun compare(lhs, rhs) =
+    super.compare(lhs, rhs) && eq(lhs.color)(rhs.color)
+}
+mixin CompareNested {
+  fun compare(lhs, rhs) =
+    super.compare(lhs, rhs) &&
+      if lhs.parent is Some(p)
+        then rhs.parent is Some(q) and this.compare(p, q)
+        else rhs.parent is None
+}
+
+class MyPoint(x: int, y: int, color: string, parent: Some[MyPoint] | None)
+
+module CompareMyPoint extends ComparePoint, CompareColored, CompareNested
+
+let Red = "red"
+let p0 = MyPoint(0, 0, Red, None)
+let p1 = MyPoint(0, 1, Red, None)
+let p2 = MyPoint(0, 1, Red, None)
+let p3 = MyPoint(0, 1, Red, Some(p1))
+let p4 = MyPoint(0, 1, Red, Some(p2))
+let p5 = MyPoint(0, 1, Red, Some(p3))
+
+CompareMyPoint.compare(p0, p1)
+CompareMyPoint.compare(p1, p2)
+CompareMyPoint.compare(p3, p4)
+CompareMyPoint.compare(p3, p5)
+
diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 9425c5f192..558ea4d7be 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -533,8 +533,41 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(f0, f1, true) case (LhsRefined(S(f: FunctionType), ts, r, trs), RhsBases(pts, _, _)) => annoying(Nil, LhsRefined(N, ts, r, trs), Nil, done_rs) - case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, trs0), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) - if nme.isCapitalized => + + // * These deal with the implicit Eql type member in primitive types. + // * (Originally I added this to all such types, + // * but it requires not expanding primitive type refs + // * which causes regressions in simplification + // * because we don't yet simplify unexpanded type refs...) + case (LhsRefined(S(ct @ ClassTag(Var(nme @ ("int" | "number" | "string" | "bool")), _)), ts, r, trs0), + RhsBases(ots, S(R(RhsField(Var("Eql#A"), fldTy))), trs)) => + nme match { + case "int" | "number" => rec(fldTy.lb.getOrElse(TopType), DecType, false) + case "string" => rec(fldTy.lb.getOrElse(TopType), StrType, false) + case "bool" => rec(fldTy.lb.getOrElse(TopType), BoolType, false) + case _ => die + } + case (LhsRefined(S(ct @ ClassTag(lit: Lit, _)), ts, r, trs0), + RhsBases(ots, S(R(RhsField(Var("Eql#A"), fldTy))), trs)) => + lit match { + case _: IntLit | _: DecLit => rec(fldTy.lb.getOrElse(TopType), DecType, false) + case _: StrLit => rec(fldTy.lb.getOrElse(TopType), StrType, false) + case _: UnitLit => reportError() + } + + // * This deals with the implicit Eql type member for user-defined classes. + case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, trs0), + RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) + if ctx.tyDefs2.contains(nme) => if (newDefs && fldNme.name === "Eql#A") { + val info = ctx.tyDefs2(nme) + info.typedParams.foreach { p => + val fty = lookupMember(nme, r.fields.toMap.get, p._1) + rec(fldTy.lb.get, RecordType(p._1 -> TypeRef(TypeName("Eql"), + fty.ub // FIXME check mutable? + :: Nil + )(provTODO).toUpper(provTODO) :: Nil)(provTODO), false) + } + } else { // val lti = ctx.tyDefs2(nme) // if (lti.isComputing) // annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? @@ -544,6 +577,7 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) // } + } case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => if (pts.contains(pt) || pts.exists(p => pt.parentsST.contains(p.id))) println(s"OK $pt <: ${pts.mkString(" | ")}") @@ -763,15 +797,15 @@ class ConstraintSolver extends NormalForms { self: Typer => case (_: TypeTag, _: TypeTag) if lhs === rhs => () case (NegType(lhs), NegType(rhs)) => rec(rhs, lhs, true) - case (ClassTag(Var(nme), _), rt: RecordType) if nme.isCapitalized => + case (ClassTag(Var(nme), _), rt: RecordType) if newDefs && nme.isCapitalized => val lti = ctx.tyDefs2(nme) - // if (lti.isComputing) reportError() - // else - rt.fields.foreach { case (fldNme, fldTy) => - // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, _ => N), fldNme) - val fty = lookupMember(nme, _ => N, fldNme) - rec(fty.ub, fldTy.ub, false) - recLb(fldTy, fty) + rt.fields.foreach { + case (fldNme @ Var("Eql#A"), fldTy) => + goToWork(lhs, RecordType(fldNme -> fldTy :: Nil)(noProv)) + case (fldNme, fldTy) => + val fty = lookupMember(nme, _ => N, fldNme) + rec(fty.ub, fldTy.ub, false) + recLb(fldTy, fty) } // * Note: at this point, it could be that a polymorphic type could be distribbed @@ -885,10 +919,13 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(tup.toRecord, rhs, true) // Q: really support this? means we'd put names into tuple reprs at runtime case (err @ ClassTag(ErrTypeId, _), RecordType(fs1)) => fs1.foreach(f => rec(err, f._2.ub, false)) + case (_, RecordType(fs1)) => + goToWork(lhs, rhs) case (RecordType(fs1), err @ ClassTag(ErrTypeId, _)) => fs1.foreach(f => rec(f._2.ub, err, false)) - case (tr1: TypeRef, tr2: TypeRef) if tr1.defn.name =/= "Array" => + case (tr1: TypeRef, tr2: TypeRef) + if tr1.defn.name =/= "Array" && tr2.defn.name =/= "Eql" => if (tr1.defn === tr2.defn) { assert(tr1.targs.sizeCompare(tr2.targs) === 0) ctx.tyDefs.get(tr1.defn.name) match { diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 843189d2e7..7421a141ae 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -149,7 +149,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => - println(">>",level,ctx.lvl) + // println(">>",level,ctx.lvl) // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), // params.mapValues(_.freshenAbove(level, rigidify)), // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) @@ -427,7 +427,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // go(dss ::: stmts) S(typeTerms(dss, false, Nil)(ctx, raise, TypeProvenance(s.toLoc, s match { case trm: Term => trm.describe - case s => ??? + case s => "statement" }), Map.empty, genLambdas = false)) } stmts match { diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 94f40e4a65..66d0975a2e 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -44,7 +44,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => positionals: Ls[Str], ) { def allBaseClasses(ctx: Ctx)(implicit traversed: Set[TypeName]): Set[TypeName] = - baseClasses.map(v => TypeName(v.name.decapitalize)) ++ + baseClasses.map(v => TypeName(v.name)) ++ baseClasses.iterator.filterNot(traversed).flatMap(v => ctx.tyDefs.get(v.name).fold(Set.empty[TypeName])(_.allBaseClasses(ctx)(traversed + v))) val (tparams: List[TypeName], targs: List[TypeVariable]) = tparamsargs.unzip @@ -112,15 +112,22 @@ class TypeDefs extends NuTypeDefs { self: Typer => def clsNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { require((td.kind is Cls) || (td.kind is Nms), td.kind) - ClassTag(Var(td.nme.name), ctx.allBaseClassesOf(td.nme.name))(prov) + ClassTag(Var(td.nme.name), + // ctx.allBaseClassesOf(td.nme.name) + Set.single(TypeName("Eql")) // TODO superclasses + )(prov) } def clsNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { require(td.kind is Cls) - ClassTag(Var(td.nme.name.decapitalize), ctx.allBaseClassesOf(td.nme.name))(prov) + if (newDefs && td.kind.str.isCapitalized) ClassTag(Var(td.nme.name), + // ctx.allBaseClassesOf(td.nme.name))(prov) + Set.single(TypeName("Eql")) // TODO superclasses + )(prov) + else ClassTag(Var(td.nme.name), ctx.allBaseClassesOf(td.nme.name))(prov) } def trtNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): TraitTag = { require(td.kind is Trt) - TraitTag(Var(td.nme.name.decapitalize))(prov) + TraitTag(Var(td.nme.name))(prov) } def baseClassesOf(tyd: mlscript.TypeDef): Set[TypeName] = @@ -414,7 +421,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => // This is because implicit method calls always default to the parent methods. case S(MethodType(_, _, parents, _)) if { val bcs = ctx.allBaseClassesOf(tn.name) - parents.forall(prt => bcs(TypeName(prt.name.decapitalize))) + parents.forall(prt => bcs(TypeName(prt.name))) } => // If this class is one of the base classes of the parent(s) of the currently registered method, // then we need to register the new method. Only happens when the class definitions are "out-of-order", @@ -427,7 +434,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => // class A // method F: int case S(MethodType(_, _, parents, _)) if { - val v = TypeName(tn.name.decapitalize) + val v = TypeName(tn.name) parents.forall(prt => ctx.allBaseClassesOf(prt.name).contains(v)) } => ctx.addMth(N, mn, mthTy) // If this class is unrelated to the parent(s) of the currently registered method, diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index cfa4cd2dc3..c63a5ebf71 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -22,7 +22,7 @@ trait TypeSimplifier { self: Typer => val _ctx = ctx val allVarPols = ty.getVarsPol(PolMap(pol)) - println("!!"+ty.childrenPol(PolMap(pol))) + // println("!!"+ty.childrenPol(PolMap(pol))) println(s"allVarPols: ${printPols(allVarPols)}") val renewed = MutMap.empty[TypeVariable, TypeVariable] @@ -211,7 +211,7 @@ trait TypeSimplifier { self: Typer => case S(cls @ ClassTag(Var(tagNme), ps)) if !primitiveTypes.contains(tagNme) && ctx.tyDefs.contains(tagNme.capitalize) - && !tagNme.isCapitalized // currently capitalization characterizes nudefs + && !newDefs => val clsNme = tagNme.capitalize // TODO rm capitalize val clsTyNme = TypeName(clsNme) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 2b2c4ebd1c..ff38d7b458 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -3,6 +3,7 @@ package mlscript import scala.collection.mutable import scala.collection.mutable.{Map => MutMap, Set => MutSet} import scala.collection.immutable.{SortedSet, SortedMap} +import Set.{empty => semp} import scala.util.chaining._ import scala.annotation.tailrec import mlscript.utils._, shorthands._ @@ -179,15 +180,23 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def provTODO: TypeProvenance = noProv def noTyProv: TypeProvenance = TypeProvenance(N, "type", isType = true) + private def sing[A](x: A): Set[A] = Set.single(x) + val TopType: ExtrType = ExtrType(false)(noTyProv) val BotType: ExtrType = ExtrType(true)(noTyProv) - val UnitType: ClassTag = ClassTag(Var("unit"), Set.empty)(noTyProv) - val BoolType: ClassTag = ClassTag(Var("bool"), Set.empty)(noTyProv) - val TrueType: ClassTag = ClassTag(Var("true"), Set.single(TypeName("bool")))(noTyProv) - val FalseType: ClassTag = ClassTag(Var("false"), Set.single(TypeName("bool")))(noTyProv) - val IntType: ClassTag = ClassTag(Var("int"), Set.single(TypeName("number")))(noTyProv) - val DecType: ClassTag = ClassTag(Var("number"), Set.empty)(noTyProv) - val StrType: ClassTag = ClassTag(Var("string"), Set.empty)(noTyProv) + + val UnitType: ClassTag = ClassTag(Var("unit"), semp)(noTyProv) + + val BoolType: ClassTag = ClassTag(Var("bool"), sing(TN("Eql")))(noTyProv) + val TrueType: ClassTag = ClassTag(Var("true"), sing(TN("bool")) + TN("Eql"))(noTyProv) + val FalseType: ClassTag = ClassTag(Var("false"), sing(TN("bool")) + TN("Eql"))(noTyProv) + + val IntType: ClassTag = ClassTag(Var("int"), sing(TN("number")) + TN("Eql"))(noTyProv) + val DecType: ClassTag = ClassTag(Var("number"), sing(TN("Eql")))(noTyProv) + val StrType: ClassTag = ClassTag(Var("string"), sing(TN("Eql")))(noTyProv) + // val IntType: ST = TypeRef(TN("int"), Nil)(noTyProv) + // val DecType: ST = TypeRef(TN("number"), Nil)(noTyProv) + // val StrType: ST = TypeRef(TN("string"), Nil)(noTyProv) val ErrTypeId: SimpleTerm = Var("error") @@ -197,22 +206,22 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) "anything" -> TopType, "nothing" -> BotType) val builtinTypes: Ls[TypeDef] = - TypeDef(Cls, TypeName("int"), Nil, TopType, Nil, Nil, Set.single(TypeName("number")), N, Nil) :: - TypeDef(Cls, TypeName("number"), Nil, TopType, Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Cls, TypeName("bool"), Nil, TopType, Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Cls, TypeName("true"), Nil, TopType, Nil, Nil, Set.single(TypeName("bool")), N, Nil) :: - TypeDef(Cls, TypeName("false"), Nil, TopType, Nil, Nil, Set.single(TypeName("bool")), N, Nil) :: - TypeDef(Cls, TypeName("string"), Nil, TopType, Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Als, TypeName("undefined"), Nil, ClassTag(UnitLit(true), Set.empty)(noProv), Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Als, TypeName("null"), Nil, ClassTag(UnitLit(false), Set.empty)(noProv), Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Als, TypeName("anything"), Nil, TopType, Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Als, TypeName("nothing"), Nil, BotType, Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Cls, TypeName("error"), Nil, TopType, Nil, Nil, Set.empty, N, Nil) :: - TypeDef(Cls, TypeName("unit"), Nil, TopType, Nil, Nil, Set.empty, N, Nil) :: + TypeDef(Cls, TN("int"), Nil, TopType, Nil, Nil, sing(TN("number")) + TN("Eql"), N, Nil) :: + TypeDef(Cls, TN("number"), Nil, TopType, Nil, Nil, sing(TN("Eql")), N, Nil) :: + TypeDef(Cls, TN("bool"), Nil, TopType, Nil, Nil, sing(TN("Eql")), N, Nil) :: + TypeDef(Cls, TN("true"), Nil, TopType, Nil, Nil, sing(TN("bool")) + TN("Eql"), N, Nil) :: + TypeDef(Cls, TN("false"), Nil, TopType, Nil, Nil, sing(TN("bool")) + TN("Eql"), N, Nil) :: + TypeDef(Cls, TN("string"), Nil, TopType, Nil, Nil, sing(TN("Eql")), N, Nil) :: + TypeDef(Als, TN("undefined"), Nil, ClassTag(UnitLit(true), semp)(noProv), Nil, Nil, semp, N, Nil) :: + TypeDef(Als, TN("null"), Nil, ClassTag(UnitLit(false), semp)(noProv), Nil, Nil, semp, N, Nil) :: + TypeDef(Als, TN("anything"), Nil, TopType, Nil, Nil, semp, N, Nil) :: + TypeDef(Als, TN("nothing"), Nil, BotType, Nil, Nil, semp, N, Nil) :: + TypeDef(Cls, TN("error"), Nil, TopType, Nil, Nil, semp, N, Nil) :: + TypeDef(Cls, TN("unit"), Nil, TopType, Nil, Nil, semp, N, Nil) :: { val tv = freshVar(noTyProv, N)(1) - val tyDef = TypeDef(Als, TypeName("Array"), List(TypeName("A") -> tv), - ArrayType(FieldType(None, tv)(noTyProv))(noTyProv), Nil, Nil, Set.empty, N, Nil) + val tyDef = TypeDef(Als, TN("Array"), List(TN("A") -> tv), + ArrayType(FieldType(None, tv)(noTyProv))(noTyProv), Nil, Nil, semp, N, Nil) // * ^ Note that the `noTyProv` here is kind of a problem // * since we currently expand primitive types eagerly in DNFs. // * For instance, see `inn2 v1` in test `Yicong.mls`. @@ -224,14 +233,21 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) } :: { val tv = freshVar(noTyProv, N)(1) - val tyDef = TypeDef(Als, TypeName("MutArray"), List(TypeName("A") -> tv), - ArrayType(FieldType(Some(tv), tv)(noTyProv))(noTyProv), Nil, Nil, Set.empty, N, Nil) + val tyDef = TypeDef(Als, TN("MutArray"), List(TN("A") -> tv), + ArrayType(FieldType(Some(tv), tv)(noTyProv))(noTyProv), Nil, Nil, semp, N, Nil) tyDef.tvarVariances = S(MutMap(tv -> VarianceInfo.in)) tyDef } :: + { + val tv = freshVar(noTyProv, N)(1) + val tyDef = TypeDef(Cls, TN("Eql"), List(TN("A") -> tv), + TopType, Nil, Nil, semp, N, Nil) + tyDef.tvarVariances = S(MutMap(tv -> VarianceInfo.contra)) + tyDef + } :: Nil val primitiveTypes: Set[Str] = - builtinTypes.iterator.map(_.nme.name).flatMap(n => n.decapitalize :: n.capitalize :: Nil).toSet + builtinTypes.iterator.map(_.nme.name).flatMap(n => n.decapitalize :: n.capitalize :: Nil).toSet - "Eql" def singleTup(ty: ST): ST = if (funkyTuples) ty else TupleType((N, ty.toUpper(ty.prov) ) :: Nil)(noProv) val builtinBindings: Bindings = { @@ -283,6 +299,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) "<=" -> numberBinPred, ">=" -> numberBinPred, "==" -> numberBinPred, + "===" -> { + val v = freshVar(noProv, N)(1) + val eq = TypeRef(TypeName("Eql"), v :: Nil)(noProv) + PolymorphicType(MinLevel, fun(singleTup(eq), fun(singleTup(v), BoolType)(noProv))(noProv)) + }, "&&" -> fun(singleTup(BoolType), fun(singleTup(BoolType), BoolType)(noProv))(noProv), "||" -> fun(singleTup(BoolType), fun(singleTup(BoolType), BoolType)(noProv))(noProv), "id" -> { @@ -403,13 +424,15 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) r.fields.map { case (n, f) => n -> FieldType(f.in.map(rec), rec(f.out))( tyTp(App(n, Var("").withLocOf(f)).toCoveringLoc, "extension field")) } )(tyTp(r.toLoc, "extension record")))(tyTp(ty.toLoc, "extension type")) - case Literal(lit) => ClassTag(lit, lit.baseClasses)(tyTp(ty.toLoc, "literal type")) + case Literal(lit) => + ClassTag(lit, lit.baseClasses)(tyTp(ty.toLoc, "literal type")) case TypeName("this") => ctx.env.getOrElse("this", err(msg"undeclared this" -> ty.toLoc :: Nil)) match { case AbstractConstructor(_, _) => die case VarSymbol(t: SimpleType, _) => t } - case tn @ TypeTag(name) => rec(TypeName(name.decapitalize)) + case tn @ TypeTag(name) => rec(TypeName(name.decapitalize)) // TODO rm this hack + // case tn @ TypeTag(name) => rec(TypeName(name)) case tn @ TypeName(name) => val tyLoc = ty.toLoc val tpr = tyTp(tyLoc, "type reference") @@ -1250,8 +1273,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def expandType(st: TypeLike, stopAtTyVars: Bool = false)(implicit ctx: Ctx): mlscript.TypeLike = { val expandType = () - import Set.{empty => semp} - var bounds: Ls[TypeVar -> Bounds] = Nil val seenVars = mutable.Set.empty[TV] @@ -1374,7 +1395,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case obj: ObjectTag => obj.id match { case Var(n) => if (primitiveTypes.contains(n) // primitives like `int` are internally maintained as class tags - || n.isCapitalized // rigid type params like A in class Foo[A] || n === "this" // `this` type ) TypeName(n) else TypeTag(n.capitalize) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 84003627b7..2febc66aba 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -11,6 +11,7 @@ import mlscript.Message._ abstract class TyperDatatypes extends TyperHelpers { self: Typer => type TN = TypeName + val TN: TypeName.type = TypeName // The data types used for type inference: @@ -491,19 +492,25 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case _ => die } case td: NuTypeDef if td.kind is Nms => - ClassTag(Var(td.nme.name), Set.empty)(provTODO) + ClassTag(Var(td.nme.name), + // TODO base classes + // Set.empty + Set.single(TN("Eql")) + )(provTODO) case td: NuTypeDef if td.kind is Cls => PolymorphicType.mk(level, FunctionType( TupleType(typedParams.mapKeys(some))(provTODO), - ClassTag(Var(td.nme.name), Set.empty)(provTODO) & RecordType.mk( + ClassTag(Var(td.nme.name), + // TODO base classes + // Set.empty + Set.single(TypeName("Eql")) + )(provTODO) & RecordType.mk( tparams.map { case (tn, tv, vi) => // TODO use vi Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } )(provTODO) )(provTODO) ) - // case td: NuTypeDef => - // ??? // TODO } def force()(implicit raise: Raise): TypedNuDecl = { @@ -600,7 +607,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => object PolymorphicType { def mk(polymLevel: Level, body: SimpleType): SimpleType = { require(polymLevel <= MaxLevel) - println(polymLevel, body.level) + // println(polymLevel, body.level) if (polymLevel === MaxLevel || body.level <= polymLevel) body else body.unwrapProvs match { // Q: unwrap other proxies? case PolymorphicType(lvl, bod) => PolymorphicType(polymLevel min lvl, bod) @@ -918,9 +925,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => }.toMap) case td: TypedNuCls => assert(td.tparams.size === targs.size) - ClassTag(Var(td.nme.name).withLocOf(td.nme), - Set.empty//TODO - )(provTODO) & RecordType(td.tparams.lazyZip(targs).map { + clsNameToNomTag(td.td)(provTODO, ctx) & + RecordType(td.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.td.nme.name + "#" + tn.name Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) diff --git a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala index 5e269fe0ec..1873077fa3 100644 --- a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala +++ b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala @@ -404,11 +404,11 @@ final class TsTypegenCodeBuilder { ) case Record(fields) => // ts can only handle fields that have only out type or the same in out types - if (fields.iterator - .map(field => field._2.in.map(in => in === field._2.out).getOrElse(true)) - .exists(!_)) - throw CodeGenError("Cannot convert mutable record field with different in out types to typescript") - + fields.iterator.foreach { field => + if (field._2.in.exists(in => in =/= field._2.out)) throw CodeGenError( + s"Cannot convert mutable record field with different in out types to typescript (${ + field})") + } SourceCode.recordWithEntries( fields.map(entry => if (entry._2.in.isDefined) @@ -418,11 +418,11 @@ final class TsTypegenCodeBuilder { )) case Tuple(fields) => // ts can only handle fields that have only out type or the same in out types - if (fields.iterator - .map(field => field._2.in.map(in => in === field._2.out).getOrElse(true)) - .exists(!_)) - throw CodeGenError("Cannot convert mutable tuple field with different in out types to typescript") - + fields.iterator.foreach { field => + if (field._2.in.exists(in => in =/= field._2.out)) throw CodeGenError( + s"Cannot convert mutable tuple field with different in out types to typescript (${ + field})") + } // tuple that is a function argument becomes // multi-parameter argument list // ! Note: No equivalent to readonly fields for tuples diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 3741cb0b57..447ef8b324 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -688,9 +688,9 @@ private class NotAType(val trm: Statement) extends Throwable trait LitImpl { self: Lit => def baseClasses: Set[TypeName] = this match { - case _: IntLit => Set.single(TypeName("int")) + TypeName("number") - case _: StrLit => Set.single(TypeName("string")) - case _: DecLit => Set.single(TypeName("number")) + case _: IntLit => Set.single(TypeName("int")) + TypeName("number") + TypeName("Eql") + case _: StrLit => Set.single(TypeName("string")) + TypeName("Eql") + case _: DecLit => Set.single(TypeName("number")) + TypeName("Eql") case _: UnitLit => Set.empty } } diff --git a/shared/src/test/diff/basics/Errors.fun b/shared/src/test/diff/basics/Errors.fun index b7773b8d51..b55a2c9f7f 100644 --- a/shared/src/test/diff/basics/Errors.fun +++ b/shared/src/test/diff/basics/Errors.fun @@ -477,7 +477,7 @@ f arg2 //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+3: f arg1 //│ ║ ^^^^^^ -//│ ╟── record of type `{fld: ?a}` does not have field 'prop' +//│ ╟── record of type `forall ?a. {fld: ?a}` does not have field 'prop' //│ ║ l.+1: let arg1 = {fld: not true} //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{prop: ?prop}` @@ -612,7 +612,7 @@ i arg //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+2: i arg //│ ║ ^^^^^ -//│ ╟── record of type `{prop: ?a}` does not have field 'fld' +//│ ╟── record of type `forall ?a. {prop: ?a}` does not have field 'fld' //│ ║ l.402: let arg = {prop: not true} //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{fld: ?fld}` diff --git a/shared/src/test/diff/basics/Negations.fun b/shared/src/test/diff/basics/Negations.fun index be1448aa30..ffdbfd39d8 100644 --- a/shared/src/test/diff/basics/Negations.fun +++ b/shared/src/test/diff/basics/Negations.fun @@ -35,7 +35,7 @@ jesus(water: w) //│ ╟── from binding: //│ ║ l.14: let jesus = (water: neg Wine) => Wine //│ ╙── ^^^^^^^^^^^^^^^ -//│ res: error | Wine +//│ res: Wine | error //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.22: jesus(water: w) //│ ║ ^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ jesus(water: w) //│ ╟── Note: constraint arises from application: //│ ║ l.14: let jesus = (water: neg Wine) => Wine //│ ╙── ^^^^^^^^ -//│ res: error | Wine +//│ res: Wine | error (0 | 1) & neg 0 diff --git a/shared/src/test/diff/basics/Simplesub1.fun b/shared/src/test/diff/basics/Simplesub1.fun index 6f9af685a4..d39f003a50 100644 --- a/shared/src/test/diff/basics/Simplesub1.fun +++ b/shared/src/test/diff/basics/Simplesub1.fun @@ -437,15 +437,15 @@ let rec x = (let y = (x x); (z => z)) (f => (x => f (v => (x x) v)) (x => f (v => (x x) v))) //│ res: ((forall 'a 'b. 'a -> 'b //│ where -//│ forall 'c 'd. 'c -> 'd +//│ forall 'c 'd. 'd -> 'c //│ where //│ 'e <: (forall 'f 'g. 'f -> 'g //│ where -//│ 'c <: 'c -> 'f -> 'g) -> 'd <: (forall 'c 'd. 'c -> 'd +//│ 'd <: 'd -> 'f -> 'g) -> 'c <: (forall 'c 'd. 'd -> 'c //│ where //│ 'e <: (forall 'f 'g. 'f -> 'g //│ where -//│ 'c <: 'c -> 'f -> 'g) -> 'd) -> 'a -> 'b) -> 'h & 'e) -> 'h +//│ 'd <: 'd -> 'f -> 'g) -> 'c) -> 'a -> 'b) -> 'h & 'e) -> 'h // * Function that takes arbitrarily many arguments: // :e // Works thanks to inconsistent constrained types... diff --git a/shared/src/test/diff/codegen/IndirectRecursion.mls b/shared/src/test/diff/codegen/IndirectRecursion.mls index 4363b1f7fc..4438a67a11 100644 --- a/shared/src/test/diff/codegen/IndirectRecursion.mls +++ b/shared/src/test/diff/codegen/IndirectRecursion.mls @@ -149,7 +149,7 @@ def z = //│ ((anything -> nothing) -> anything) -> error //│ <: z: //│ (('a -> 'b) -> ('a -> 'b & 'c)) -> 'c -//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d ?e ?f ?g. ?c -> ?d) -> ?h` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d ?e ?f ?g. ?f -> ?c) -> ?h` exceeded recursion depth limit (250) //│ ║ l.148: (fun f -> (fun x -> f (fun v -> (x x) v)) (fun x -> f (fun v -> (x x) v))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index a769d17b95..987a4fc70a 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -216,7 +216,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) //│ } //│ // Prelude //│ let typing_unit3 = { @@ -271,7 +271,7 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: {eval: (Neg['A] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b +//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b //│ } //│ // Prelude //│ let typing_unit4 = { @@ -323,7 +323,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] //│ 'A <: 'a //│ // Prelude //│ let typing_unit5 = { @@ -440,8 +440,11 @@ class E(x: int) extends BB, AA(x) //│ class E(x: int) :js -mixin Fooo(x: int) -//│ mixin Fooo(x: int) +mixin Fooo(x: int) { fun f = [x, this.x] } +//│ mixin Fooo(x: int) { +//│ this: {x: 'x} +//│ fun f: (int, 'x,) +//│ } //│ // Prelude //│ let typing_unit14 = { //│ cache: {}, @@ -453,6 +456,14 @@ mixin Fooo(x: int) //│ super(...rest); //│ this.#x = x; //│ } +//│ get f() { +//│ const x = this.#x; +//│ const self = this; +//│ return ([ +//│ x, +//│ self.x +//│ ]); +//│ } //│ }); //│ } //│ }; @@ -481,7 +492,9 @@ mixin Bazz(y: int) :js module Barr extends Fooo(0), Bazz(1) -//│ module Barr() +//│ module Barr() { +//│ fun f: (int, 0,) +//│ } //│ // Prelude //│ let typing_unit16 = { //│ cache: {}, @@ -517,7 +530,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.517: fun x = y +//│ ║ l.530: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error @@ -534,50 +547,6 @@ module Test extends Base //│ Runtime error: //│ ReferenceError: Base is not defined -:js -class Test(n: int) { - fun inc = Test(n + 1) -} -//│ class Test(n: int) { -//│ fun inc: Test -//│ } -//│ // Prelude -//│ let typing_unit21 = { -//│ cache: {}, -//│ get Test1() { -//│ const cache = this.cache; -//│ if (this.cache.Test1 === undefined) { -//│ class Test1 { -//│ #n; -//│ get n() { return this.#n; } -//│ constructor(n) { -//│ this.#n = n; -//│ } -//│ get inc() { -//│ const Test1 = cache.Test1; -//│ const n = this.#n; -//│ return Test1(n + 1); -//│ } -//│ }; -//│ this.cache.Test1 = ((n) => new Test1(n)); -//│ this.cache.Test1["class"] = Test1; -//│ } -//│ return this.cache.Test1; -//│ } -//│ }; -//│ globalThis.Test1 = typing_unit21.Test1; -//│ // End of generated code - -:js -Test(0).inc.n -//│ int -//│ // Prelude -//│ let typing_unit22 = { cache: {} }; -//│ // Query 1 -//│ res = Test1(0).inc.n; -//│ // End of generated code -//│ res -//│ = 1 mixin MA(a: int) mixin MB(b1: int, b2: int) @@ -590,7 +559,7 @@ mixin MC(c: int) module MM extends MA(1), MB(2, 3), MC(4) //│ module MM() //│ // Prelude -//│ let typing_unit24 = { +//│ let typing_unit22 = { //│ cache: {}, //│ get MM() { //│ if (this.cache.MM === undefined) { @@ -605,7 +574,7 @@ module MM extends MA(1), MB(2, 3), MC(4) //│ return this.cache.MM; //│ } //│ }; -//│ globalThis.MM = typing_unit24.MM; +//│ globalThis.MM = typing_unit22.MM; //│ // End of generated code MM.a diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls new file mode 100644 index 0000000000..4333dcd844 --- /dev/null +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -0,0 +1,61 @@ +:NewDefs + +:js +class Test(n: int) { + fun inc = Test(n + 1) +} +//│ class Test(n: int) { +//│ fun inc: Test +//│ } +//│ // Prelude +//│ let res; +//│ let typing_unit = { +//│ cache: {}, +//│ get Test() { +//│ const cache = this.cache; +//│ if (this.cache.Test === undefined) { +//│ class Test { +//│ #n; +//│ get n() { return this.#n; } +//│ constructor(n) { +//│ this.#n = n; +//│ } +//│ get inc() { +//│ const Test = cache.Test; +//│ const n = this.#n; +//│ return Test(n + 1); +//│ } +//│ }; +//│ this.cache.Test = ((n) => new Test(n)); +//│ this.cache.Test["class"] = Test; +//│ } +//│ return this.cache.Test; +//│ } +//│ }; +//│ globalThis.Test = typing_unit.Test; +//│ // End of generated code + +Test(0).inc.n +//│ int +//│ res +//│ = 1 + +class Test2(n: int) { + fun inc = Test3.inc(n) +} +module Test3 { + fun inc(n) = Test2(n + 1) +} +//│ class Test2(n: int) { +//│ fun inc: Test2 +//│ } +//│ module Test3() { +//│ fun inc: int -> Test2 +//│ } + +Test2(0).inc.n +//│ int +//│ res +//│ = 1 + + diff --git a/shared/src/test/diff/contys/AbstractBounds.mls b/shared/src/test/diff/contys/AbstractBounds.mls index 3bd7069d74..b63a15ce62 100644 --- a/shared/src/test/diff/contys/AbstractBounds.mls +++ b/shared/src/test/diff/contys/AbstractBounds.mls @@ -83,7 +83,7 @@ class Test3[A, B] //│ Defined Test3.Bar3: Test3['A, 'B] -> 'A -> 'B fun x -> fun y -> x.Foo3 y -//│ res: 'a -> (forall 'b 'A. 'A -> 'b +//│ res: 'a -> (forall 'A 'b. 'A -> 'b //│ where //│ 'a <: Test3['A, 'b]) //│ = [Function: res] diff --git a/shared/src/test/diff/fcp-lit/CPS_LB.mls b/shared/src/test/diff/fcp-lit/CPS_LB.mls index dc2a0d4410..a140270b59 100644 --- a/shared/src/test/diff/fcp-lit/CPS_LB.mls +++ b/shared/src/test/diff/fcp-lit/CPS_LB.mls @@ -76,11 +76,11 @@ def test18 = (s x x x x x x x x x x x x x x x x x x e) // (* A function that receives a token *) def f t = (s x x t x x e) -//│ f: (() -> List["x"] -> (forall 'b 'a. () -> List['a] -> (() -> List["x" | 'a] -> 'b) -> 'b) -> (forall 'c 'a. () -> List['a] -> (() -> List["x" | 'a] -> 'c) -> 'c) -> (forall 'a0 'd. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'd) -> 'd) -> 'e) -> 'e +//│ f: (() -> List["x"] -> (forall 'a 'b. () -> List['a] -> (() -> List["x" | 'a] -> 'b) -> 'b) -> (forall 'a 'c. () -> List['a] -> (() -> List["x" | 'a] -> 'c) -> 'c) -> (forall 'a0 'd. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'd) -> 'd) -> 'e) -> 'e // (* If the token is used twice, we must reveive two arguments *) def g t1 t2 = (s x x t1 x (s x t2 x e) e) -//│ g: (() -> List["x"] -> (forall 'a 'b. () -> List['a] -> (() -> List["x" | 'a] -> 'b) -> 'b) -> 'c -> (forall 'a0 'd. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'd) -> 'd) -> 'e) -> (() -> List["x"] -> (forall 'a 'f. () -> List['a] -> (() -> List["x" | 'a] -> 'f) -> 'f) -> (forall 'a0 'g. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'g) -> 'g) -> 'c) -> 'e +//│ g: (() -> List["x"] -> (forall 'a 'b. () -> List['a] -> (() -> List["x" | 'a] -> 'b) -> 'b) -> 'c -> (forall 'a0 'd. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'd) -> 'd) -> 'e) -> (() -> List["x"] -> (forall 'f 'a. () -> List['a] -> (() -> List["x" | 'a] -> 'f) -> 'f) -> (forall 'g 'a0. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'g) -> 'g) -> 'c) -> 'e // (* This does not type. It requires first-class polymorphism. *) def h t = g t t diff --git a/shared/src/test/diff/fcp-lit/Leijen.mls b/shared/src/test/diff/fcp-lit/Leijen.mls index 43b1d25ad0..1b416bb8e0 100644 --- a/shared/src/test/diff/fcp-lit/Leijen.mls +++ b/shared/src/test/diff/fcp-lit/Leijen.mls @@ -388,12 +388,8 @@ map xauto (map xauto ids) //│ ║ ^^ //│ ╟── back into type variable `'b` //│ ║ l.174: def xauto : forall 'a. (forall 'b. 'b -> 'b) -> 'a -> 'a -//│ ║ ^^ -//│ ╟── adding a type annotation to any of the following terms may help resolve the problem -//│ ╟── • this application: -//│ ║ l.382: map xauto (map xauto ids) -//│ ╙── ^^^^^^^^^^^^^ -//│ res: error | List['a -> 'a] +//│ ╙── ^^ +//│ res: List['a -> 'a] | error //│ = Cons { head: [Function: id1], tail: Nil {} } // ,("map auto ids", ok "[forall a. a -> a]") @@ -443,16 +439,16 @@ app (map head) (single ids) :ng (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.444: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) +//│ ║ l.440: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'d` is not an instance of type `int` -//│ ║ l.444: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) +//│ ║ l.440: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) //│ ║ ^^ //│ ╟── but it flows into quantified type variable with expected type `int` -//│ ║ l.444: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) +//│ ║ l.440: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) //│ ║ ^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.444: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) +//│ ║ l.440: (error : List['a -> 'a] -> int) (error : List[(forall 'd. 'd -> 'd) -> (int -> int)]) //│ ╙── ^^^ //│ res: error | int @@ -526,16 +522,16 @@ fun x -> let polys (xs: List[forall 'a. 'a -> 'a]) = 1 in let f y = x in polys ( :e ids : forall 'b. List[forall 'a. 'a -> 'b] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.527: ids : forall 'b. List[forall 'a. 'a -> 'b] +//│ ║ l.523: ids : forall 'b. List[forall 'a. 'a -> 'b] //│ ║ ^^^ //│ ╟── type `'a` does not match type `'b` -//│ ║ l.527: ids : forall 'b. List[forall 'a. 'a -> 'b] +//│ ║ l.523: ids : forall 'b. List[forall 'a. 'a -> 'b] //│ ║ ^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.527: ids : forall 'b. List[forall 'a. 'a -> 'b] +//│ ║ l.523: ids : forall 'b. List[forall 'a. 'a -> 'b] //│ ║ ^^ //│ ╟── Note: quantified type variable 'a is defined at: -//│ ║ l.527: ids : forall 'b. List[forall 'a. 'a -> 'b] +//│ ║ l.523: ids : forall 'b. List[forall 'a. 'a -> 'b] //│ ╙── ^^ //│ res: List[anything -> nothing] //│ = Cons { head: [Function: id1], tail: Nil {} } @@ -825,10 +821,10 @@ single id : List[forall 'a. 'a -> 'a] :ng returnST 1 : forall 's. ST['s, int] //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.826: returnST 1 : forall 's. ST['s, int] +//│ ║ l.822: returnST 1 : forall 's. ST['s, int] //│ ║ ^^^^^^^^^^ //│ ╟── type variable `'s` leaks out of its scope -//│ ║ l.826: returnST 1 : forall 's. ST['s, int] +//│ ║ l.822: returnST 1 : forall 's. ST['s, int] //│ ╙── ^^ //│ res: ST['s, int] @@ -957,17 +953,17 @@ runST4 (newRef4 1) :e (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.958: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.954: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'a` leaks out of its scope -//│ ║ l.958: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.954: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ║ ^^ //│ ╟── back into type variable `'a` -//│ ║ l.958: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.954: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ║ ^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this application: -//│ ║ l.958: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.954: (fun x -> xauto x) : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ╙── ^^^^^^^ //│ res: (forall 'a. 'a -> 'a) -> (forall 'a0. 'a0 -> 'a0) //│ = [Function: res] @@ -980,17 +976,17 @@ runST4 (newRef4 1) :e xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.981: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.977: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ║ ^^^^^ //│ ╟── type variable `'a` leaks out of its scope -//│ ║ l.981: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.977: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ║ ^^ //│ ╟── back into type variable `'a` -//│ ║ l.981: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.977: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ║ ^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.981: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) +//│ ║ l.977: xauto : (forall 'a. 'a -> 'a) -> (forall 'a. 'a -> 'a) //│ ╙── ^^^^^ //│ res: (forall 'a. 'a -> 'a) -> (forall 'a0. 'a0 -> 'a0) //│ = [Function: xauto] @@ -1036,18 +1032,14 @@ test2 = test1 //│ <: test2: //│ List[forall 'a. 'a -> 'a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.1034: test2 = test1 +//│ ║ l.1030: test2 = test1 //│ ║ ^^^^^^^^^^^^^ //│ ╟── type variable `'a` leaks out of its scope -//│ ║ l.1020: def test2: List[forall 'a. 'a -> 'a] +//│ ║ l.1016: def test2: List[forall 'a. 'a -> 'a] //│ ║ ^^ //│ ╟── back into type variable `'a` -//│ ║ l.1020: def test2: List[forall 'a. 'a -> 'a] -//│ ║ ^^ -//│ ╟── adding a type annotation to any of the following terms may help resolve the problem -//│ ╟── • this reference: -//│ ║ l.1034: test2 = test1 -//│ ╙── ^^^^^ +//│ ║ l.1016: def test2: List[forall 'a. 'a -> 'a] +//│ ╙── ^^ //│ = //│ test1 and test2 are not implemented diff --git a/shared/src/test/diff/fcp-lit/MLF.mls b/shared/src/test/diff/fcp-lit/MLF.mls index b600370263..238eb9fcb1 100644 --- a/shared/src/test/diff/fcp-lit/MLF.mls +++ b/shared/src/test/diff/fcp-lit/MLF.mls @@ -144,7 +144,7 @@ let f = choose id in (f auto, f succ) //│ res: (forall 'b 'a. (forall 'a0. 'a0 -> 'a0 & 'b) -> ('a -> 'a | 'b), forall 'b. (int & 'b) -> (int | 'b),) let f = choose id in (f auto2, f succ) -//│ res: (forall 'a 'b 'c. ('b -> 'c & 'b & 'a) -> ('c | 'a), forall 'a. (int & 'a) -> (int | 'a),) +//│ res: (forall 'a 'b 'c. ('a -> 'b & 'a & 'c) -> ('b | 'c), forall 'c. (int & 'c) -> (int | 'c),) // ------------ Sec 6 ------------ diff --git a/shared/src/test/diff/fcp-lit/QML.mls b/shared/src/test/diff/fcp-lit/QML.mls index 4073fc887e..be62497912 100644 --- a/shared/src/test/diff/fcp-lit/QML.mls +++ b/shared/src/test/diff/fcp-lit/QML.mls @@ -202,7 +202,7 @@ def sstep = fun xx -> xx (fun (xinit, xsub) -> then xsub r1 (div i 2) else xsub r2 (div i 2) in fun f -> f (init, sub)) -//│ ((forall 'a 'b 'c 'd 'e. ('e -> 'a, 'b -> int -> 'c,) -> (('e -> ('a, 'a,), ('b, 'b,) -> (int & number) -> 'c,) -> 'd) -> 'd) -> 'f) -> 'f +//│ ((forall 'a 'b 'c 'd 'e. ('c -> 'e, 'b -> int -> 'a,) -> (('c -> ('e, 'e,), ('b, 'b,) -> (int & number) -> 'a,) -> 'd) -> 'd) -> 'f) -> 'f //│ <: sstep: //│ ExSmall -> ExSmall //│ ╔══[ERROR] Type error in def definition @@ -415,7 +415,7 @@ def base : ExSig def base f = f ((((fun a -> a, fun r -> fun (i : int) -> r), fun r -> fun (i : int) -> fun a -> a), fun f -> fun b -> fun r -> f r b),) //│ base: ExSig //│ = -//│ ((((forall 'a. 'a -> 'a, forall 'b. 'b -> int -> 'b,), forall 'c. anything -> int -> 'c -> 'c,), forall 'd 'e 'f. ('f -> 'd -> 'e) -> 'd -> 'f -> 'e,) -> 'g) -> 'g +//│ ((((forall 'a. 'a -> 'a, forall 'b. 'b -> int -> 'b,), forall 'c. anything -> int -> 'c -> 'c,), forall 'd 'e 'f. ('d -> 'e -> 'f) -> 'e -> 'd -> 'f,) -> 'g) -> 'g //│ <: base: //│ ExSig //│ = [Function: base] @@ -440,7 +440,7 @@ def step = fun xx -> xx (fun ((((xinit, xsub), xupdate), xfold),) -> else (fst r, xupdate (snd r) (div i 2) a) in let fold f b r = xfold f (xfold f b (fst r)) (snd r) in fun f -> f ((((init, sub), update), fold),) ) -//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm 'n 'o 'p. ((('o -> 'j, 'g -> int -> 'c,), 'm -> int -> 'p -> 'b & 'h -> int -> 'p -> 'k,), 'l -> ('a -> 'e -> 'i & 'd -> 'n -> 'a),) -> (((('o -> ('j, 'j,), ('g, 'g,) -> (int & number) -> 'c,), forall 'q 'r. ('m & 'q, 'h & 'r,) -> (int & number) -> 'p -> ('b | 'q, 'r | 'k,),), 'l -> 'd -> ('n, 'e,) -> 'i,) -> 'f) -> 'f) -> 's) -> 's +//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm 'n 'o 'p. ((('c -> 'o, 'm -> int -> 'b,), 'g -> int -> 'k -> 'l & 'a -> int -> 'k -> 'e,), 'h -> ('d -> 'p -> 'n & 'i -> 'f -> 'd),) -> (((('c -> ('o, 'o,), ('m, 'm,) -> (int & number) -> 'b,), forall 'q 'r. ('g & 'q, 'a & 'r,) -> (int & number) -> 'k -> ('l | 'q, 'r | 'e,),), 'h -> 'i -> ('f, 'p,) -> 'n,) -> 'j) -> 'j) -> 's) -> 's //│ <: step: //│ ExSig -> ExSig //│ ╔══[ERROR] Type error in def definition diff --git a/shared/src/test/diff/fcp/Church_CT.mls b/shared/src/test/diff/fcp/Church_CT.mls index b60309ccde..1b3544e992 100644 --- a/shared/src/test/diff/fcp/Church_CT.mls +++ b/shared/src/test/diff/fcp/Church_CT.mls @@ -37,10 +37,10 @@ def succ: (forall 'N. ('N -> 'N) -> ('N -> 'N)) -> (forall 'M. ('M -> 'M) -> ('M :e // * Since "sound extrusion" def succ n f x = f (n f x) -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'b <: 'c -> 'd +//│ 'a <: 'b -> 'e -> 'c)) //│ <: succ: //│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -93,10 +93,10 @@ def succD: forall 'M. ChurchInt -> ('M -> 'M) -> ('M -> 'M) def succD n f x = f (n f x) //│ succD: ChurchInt -> ('M -> 'M) -> 'M -> 'M //│ = -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'a <: 'b -> 'e -> 'c +//│ 'b <: 'c -> 'd)) //│ <: succD: //│ ChurchInt -> ('M -> 'M) -> 'M -> 'M //│ = [Function: succD] @@ -284,8 +284,8 @@ def z f x = x def s n f x = f (n f x) //│ s: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'b <: 'd -> 'e +//│ 'a <: 'b -> 'c -> 'd)) //│ = [Function: s] zero = z @@ -298,8 +298,8 @@ zero = z succ = s //│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'b <: 'd -> 'e +//│ 'a <: 'b -> 'c -> 'd)) //│ <: succ: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -359,32 +359,32 @@ s: ChurchInt -> ChurchInt n1 = s z -//│ n1: 'a -> (forall 'b 'c 'd. 'c -> 'b +//│ n1: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ anything -> (forall 'e. 'e -> 'e) <: 'a -> 'c -> 'd -//│ 'a <: 'd -> 'b) +//│ 'a <: 'c -> 'd +//│ anything -> (forall 'e. 'e -> 'e) <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] n2 = s (s z) //│ n2: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ 'a <: 'c -> 'd //│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h //│ where -//│ 'e <: 'g -> 'h -//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g) <: 'a -> 'b -> 'c) +//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g +//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c +//│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] n3 = s (s (s z)) //│ n3: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. 'g -> 'f +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h //│ where -//│ 'e <: 'h -> 'f -//│ forall 'i. 'i -> (forall 'j 'k 'l. 'j -> 'l +//│ forall 'i. 'i -> (forall 'j 'k 'l. 'k -> 'j //│ where -//│ 'i <: 'k -> 'l -//│ anything -> (forall 'm. 'm -> 'm) <: 'i -> 'j -> 'k) <: 'e -> 'g -> 'h) <: 'a -> 'b -> 'c +//│ 'i <: 'l -> 'j +//│ anything -> (forall 'm. 'm -> 'm) <: 'i -> 'k -> 'l) <: 'e -> 'f -> 'g +//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c //│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] @@ -396,8 +396,8 @@ wrap x = { x } n1w = n1 wrap //│ n1w: 'a -> 'b //│ where -//│ anything -> (forall 'c. 'c -> 'c) <: (forall 'd. 'd -> {x: 'd}) -> 'a -> 'e -//│ forall 'd. 'd -> {x: 'd} <: 'e -> 'b +//│ forall 'c. 'c -> {x: 'c} <: 'd -> 'b +//│ anything -> (forall 'e. 'e -> 'e) <: (forall 'c. 'c -> {x: 'c}) -> 'a -> 'd //│ = [Function (anonymous)] n1w 0 @@ -442,8 +442,8 @@ wrap_ty = wrap n1w = n1 wrap_ty //│ n1w: 'b -> 'c //│ where -//│ anything -> (forall 'd. 'd -> 'd) <: (forall 'a. 'a -> {x: 'a}) -> 'b -> 'e -//│ forall 'a. 'a -> {x: 'a} <: 'e -> 'c +//│ forall 'a. 'a -> {x: 'a} <: 'd -> 'c +//│ anything -> (forall 'e. 'e -> 'e) <: (forall 'a. 'a -> {x: 'a}) -> 'b -> 'd //│ = [Function (anonymous)] n1w 0 @@ -478,20 +478,20 @@ res.x.x.x + 1 sz = s zero //│ sz: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ 'a <: 'c -> 'd -//│ ChurchInt <: 'a -> 'b -> 'c) +//│ ChurchInt <: 'a -> 'b -> 'c +//│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] :ns sz -//│ res: forall 'a 'b. 'b +//│ res: forall 'a 'b. 'a //│ where -//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'e -> 'g +//│ 'a :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'e -> 'g //│ where -//│ 'a <: 'c -> 'd +//│ 'b <: 'c -> 'd //│ 'c <: 'f -> 'g) //│ 'd <: 'e -> 'f -//│ 'a :> ChurchInt +//│ 'b :> ChurchInt //│ = [Function (anonymous)] sz: ChurchInt @@ -523,15 +523,15 @@ sz1 = sz 1 :ns sz1 -//│ res: forall 'a 'b 'c. 'c +//│ res: forall 'a 'b 'c. 'a //│ where -//│ 'c :> forall 'd 'e 'f 'g. 'e -> 'g +//│ 'a :> forall 'd 'e 'f 'g. 'e -> 'g //│ where -//│ 'a <: 'b -> 'd -//│ 'b <: 'f -> 'g +//│ 'c <: 'f -> 'g +//│ 'b <: 'c -> 'd //│ 'd <: 'e -> 'f -//│ 'b :> 1 -//│ 'a :> ChurchInt +//│ 'b :> ChurchInt +//│ 'c :> 1 //│ = [Function (anonymous)] :e // * Since inconsistent constrained types (delayed error from above) @@ -588,10 +588,10 @@ rec def to_ch_s n = else s (to_ch_s (n - 1)) //│ to_ch_s: int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'b 'e 'f. ('e & 'c) -> ('e | 'd) +//│ 'a :> forall 'b. 'b -> (forall 'c 'b 'd 'e 'f. ('d & 'f) -> ('d | 'e) //│ where -//│ 'a <: 'b -> 'c -> 'f -//│ 'b <: 'f -> 'd) +//│ 'b <: 'c -> 'e +//│ 'a <: 'b -> 'f -> 'c) //│ = [Function: to_ch_s] rec def to_ch n = @@ -599,23 +599,23 @@ rec def to_ch n = else s (to_ch (n - 1)) //│ to_ch: int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'b 'c 'd 'e 'f. ('d & 'c) -> ('d | 'e) +//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'e 'b 'f. ('e & 'd) -> ('e | 'f) //│ where -//│ 'b <: 'f -> 'e -//│ 'a <: 'b -> 'c -> 'f) +//│ 'a <: 'b -> 'd -> 'c +//│ 'b <: 'c -> 'f) //│ = [Function: to_ch] :e // * Needs distrib (see below) to_church_ty = to_ch //│ int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'b 'e 'f. ('e & 'c) -> ('e | 'd) +//│ 'a :> forall 'b. 'b -> (forall 'b 'c 'd 'e 'f. ('f & 'd) -> ('f | 'e) //│ where -//│ 'b <: 'f -> 'd -//│ 'a <: 'b -> 'c -> 'f) +//│ 'b <: 'c -> 'e +//│ 'a <: 'b -> 'd -> 'c) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?to_ch. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch ?c ?d. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.609: to_church_ty = to_ch //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -640,7 +640,7 @@ to_church_ty = to_ch_simplif //│ 'b <: 'd -> 'e) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch_simplif ?c ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.634: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -710,10 +710,10 @@ rec def to_ch_A1 n = //│ ╟── Note: constraint arises from application: //│ ║ l.284: def s n f x = f (n f x) //│ ╙── ^^^^^ -//│ to_ch_A1: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. ('e & 'b) -> ('b | 'c) +//│ to_ch_A1: int -> (forall 'a. 'a -> (forall 'b 'c 'a 'd 'e. ('b & 'c) -> ('c | 'd) //│ where -//│ 'a <: 'd -> 'c -//│ ChurchInt <: 'a -> 'e -> 'd)) +//│ 'a <: 'e -> 'd +//│ ChurchInt <: 'a -> 'b -> 'e)) //│ = [Function: to_ch_A1] :precise-rec-typing @@ -722,10 +722,10 @@ rec def to_ch_A1 n = else s (to_ch_A1 (n - 1) : ChurchInt) //│ to_ch_A1: 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'd 'e 'a. ('d & 'b) -> ('b | 'e) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'a 'd 'e. ('b & 'd) -> ('d | 'e) //│ where //│ 'a <: 'c -> 'e -//│ ChurchInt <: 'a -> 'd -> 'c)) +//│ ChurchInt <: 'a -> 'b -> 'c)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ = [Function: to_ch_A11] @@ -735,10 +735,10 @@ rec def to_ch_A1 n = to_church_ty = to_ch_A1 //│ 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('b & 'd) -> ('d | 'e) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('d & 'e) -> ('e | 'b) //│ where -//│ ChurchInt <: 'a -> 'b -> 'c -//│ 'a <: 'c -> 'e)) +//│ 'a <: 'c -> 'b +//│ ChurchInt <: 'a -> 'd -> 'c)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ <: to_church_ty: @@ -856,18 +856,18 @@ to_church_ty = to_ch_A2 def to_church_mix n = if n == 0 then z else s (to_church (n - 1)) -//│ to_church_mix: int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. ('e & 'b) -> ('b | 'c) +//│ to_church_mix: int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('c & 'e) -> ('e | 'd) //│ where -//│ ChurchInt <: 'a -> 'e -> 'd -//│ 'a <: 'd -> 'c)) +//│ ChurchInt <: 'a -> 'c -> 'b +//│ 'a <: 'b -> 'd)) //│ = [Function: to_church_mix] :e to_church_ty = to_church_mix -//│ int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. ('d & 'e) -> ('e | 'b) +//│ int -> (forall 'a. 'a -> (forall 'b 'a 'c 'd 'e. ('e & 'b) -> ('b | 'c) //│ where -//│ ChurchInt <: 'a -> 'd -> 'c -//│ 'a <: 'c -> 'b)) +//│ ChurchInt <: 'a -> 'e -> 'd +//│ 'a <: 'd -> 'c)) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -918,8 +918,8 @@ rec def to_chD n = succ = s //│ 'a -> 'b -> ('c -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'e -//│ 'b <: 'e -> 'd) +//│ 'b <: 'e -> 'd +//│ 'a <: 'b -> 'c -> 'e) //│ <: succ: //│ ChurchInt -> ChurchInt //│ = [Function: s] @@ -941,16 +941,16 @@ rec def to_chD n = to_church_ty = to_ch //│ int -> 'a -> ('b -> ('b | 'c) //│ where -//│ 'a <: 'd -> 'c -//│ 'e <: 'a -> 'b -> 'd) +//│ 'd <: 'a -> 'b -> 'e +//│ 'a <: 'e -> 'c) //│ where -//│ 'e :> forall 'f 'g 'h 'i 'j. 'h -> (('j & 'g) -> ('j | 'f) +//│ 'd :> forall 'f 'g 'h 'i 'j. 'f -> (('g & 'j) -> ('g | 'h) //│ where -//│ 'h <: 'i -> 'f -//│ 'e <: 'h -> 'g -> 'i) +//│ 'f <: 'i -> 'h +//│ 'd <: 'f -> 'j -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?to_ch ?b ?c ?d. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch ?d. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.941: to_church_ty = to_ch //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -960,16 +960,16 @@ to_church_ty = to_ch to_church_ty = to_ch_simplif //│ anything -> 'a -> ('b -> 'c //│ where -//│ 'a <: 'd -> 'c -//│ 'e <: 'a -> 'b -> 'd) +//│ 'd <: 'a -> 'b -> 'e +//│ 'a <: 'e -> 'c) //│ where -//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ 'd :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i //│ where -//│ 'e <: 'f -> 'g -> 'h -//│ 'f <: 'h -> 'i) +//│ 'f <: 'h -> 'i +//│ 'd <: 'f -> 'g -> 'h) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch_simplif ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif ?a ?b ?c ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.960: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -979,13 +979,13 @@ to_church_ty = to_ch_simplif rec def to_ch_simplif n = s (to_ch_simplif n) //│ to_ch_simplif: anything -> 'a -> ('b -> 'c //│ where -//│ 'a <: 'd -> 'c -//│ 'e <: 'a -> 'b -> 'd) +//│ 'd <: 'a -> 'b -> 'e +//│ 'a <: 'e -> 'c) //│ where -//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ 'd :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i //│ where -//│ 'e <: 'f -> 'g -> 'h -//│ 'f <: 'h -> 'i) +//│ 'f <: 'h -> 'i +//│ 'd <: 'f -> 'g -> 'h) //│ = [Function: to_ch_simplif1] :e // * Since the removal of "recursive definition hacks" @@ -995,13 +995,13 @@ to_church_ty = to_ch_simplif //│ 'a <: 'd -> 'c //│ 'e <: 'a -> 'b -> 'd) //│ where -//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ 'e :> forall 'f 'g 'h 'i. 'g -> ('h -> 'f //│ where -//│ 'e <: 'f -> 'g -> 'h -//│ 'f <: 'h -> 'i) +//│ 'g <: 'i -> 'f +//│ 'e <: 'g -> 'h -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch_simplif ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif ?a ?b ?c ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.992: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -1012,10 +1012,10 @@ to_church_ty = to_ch_simplif to_church_ty = to_ch_A1 //│ 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. 'c -> (('e & 'b) -> ('b | 'd) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. 'd -> (('c & 'e) -> ('e | 'a) //│ where -//│ 'c <: 'a -> 'd -//│ ChurchInt <: 'c -> 'e -> 'a)) +//│ 'd <: 'b -> 'a +//│ ChurchInt <: 'd -> 'c -> 'b)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ <: to_church_ty: diff --git a/shared/src/test/diff/fcp/Church_ST.mls b/shared/src/test/diff/fcp/Church_ST.mls index 62f8dc3da5..eeada66a6a 100644 --- a/shared/src/test/diff/fcp/Church_ST.mls +++ b/shared/src/test/diff/fcp/Church_ST.mls @@ -62,13 +62,13 @@ def succ n f x = f (n f x) // * This explicit annotation makes it type check; like in MLF: def succ (n: (forall 'N. ('N -> 'N) -> ('N -> 'N))) = fun f -> fun x -> f (n f x) -//│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'N0 'N1 'a. ('N0 -> ('N0 & 'N1) & 'N1 -> 'a) -> ('N0 & 'N1) -> 'a) +//│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'a 'N0 'N1. ('N0 -> ('N0 & 'N1) & 'N1 -> 'a) -> ('N0 & 'N1) -> 'a) //│ <: succ: //│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ = [Function: succ2] def succ (n: ChurchInt) f x = f (n f x) -//│ ChurchInt -> (forall 'N 'N0 'a. ('N -> ('N & 'N0) & 'N0 -> 'a) -> ('N & 'N0) -> 'a) +//│ ChurchInt -> (forall 'a 'N 'N0. ('N -> ('N & 'N0) & 'N0 -> 'a) -> ('N & 'N0) -> 'a) //│ <: succ: //│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ = [Function: succ3] @@ -493,16 +493,16 @@ sz = s zero :ns sz -//│ res: forall 'a 'b 'c 'N 'd. 'a +//│ res: forall 'a 'b 'c 'd 'N. 'c //│ where -//│ 'a :> forall 'e 'f 'g. 'e -> (forall 'h 'i. 'h -> 'i) +//│ 'c :> forall 'e 'f 'g. 'e -> (forall 'h 'i. 'h -> 'i) //│ 'i :> 'g -//│ 'h <: 'c -//│ 'c <: 'N -//│ 'e <: 'f -> 'g & 'b -//│ 'b <: 'N -> 'N -//│ 'N <: 'd -//│ 'f :> 'd +//│ 'h <: 'a +//│ 'a <: 'N +//│ 'e <: 'f -> 'g & 'd +//│ 'd <: 'N -> 'N +//│ 'N <: 'b +//│ 'f :> 'b //│ = [Function (anonymous)] sz: ChurchInt diff --git a/shared/src/test/diff/fcp/ConstrainedTypes1.mls b/shared/src/test/diff/fcp/ConstrainedTypes1.mls index 21956fa1af..1d3d61ba61 100644 --- a/shared/src/test/diff/fcp/ConstrainedTypes1.mls +++ b/shared/src/test/diff/fcp/ConstrainedTypes1.mls @@ -11,7 +11,7 @@ foo x = foo x = let _ = log (succ x.prop) in x -//│ foo: forall 'prop 'a. 'a -> 'a +//│ foo: forall 'a 'prop. 'a -> 'a //│ where //│ 'a <: {prop: 'prop} //│ 'prop <: int diff --git a/shared/src/test/diff/fcp/ConstrainedTypes2.mls b/shared/src/test/diff/fcp/ConstrainedTypes2.mls index dd9abeffe9..6c1e88ca44 100644 --- a/shared/src/test/diff/fcp/ConstrainedTypes2.mls +++ b/shared/src/test/diff/fcp/ConstrainedTypes2.mls @@ -77,9 +77,9 @@ def test extr = let f n m = n 0 in let _ = extr f in f 0 -//│ test: ((forall 'a 'b. 'b -> (anything -> 'a +//│ test: ((forall 'a 'b. 'a -> (anything -> 'b //│ where -//│ 'b <: 0 -> 'a)) -> anything) -> (anything -> 'c +//│ 'a <: 0 -> 'b)) -> anything) -> (anything -> 'c //│ where //│ 0 <: 0 -> 'c) //│ = [Function: test] @@ -108,8 +108,8 @@ def test extr x = in f 0 //│ test: ((forall 'a 'b 'c. 'a -> (anything -> 'c //│ where -//│ 'd <: 'b -> 'c -//│ 'a <: 0 -> 'b)) -> anything) -> 'd -> (anything -> 'e +//│ 'a <: 0 -> 'b +//│ 'd <: 'b -> 'c)) -> anything) -> 'd -> (anything -> 'e //│ where //│ 'd <: 'f -> 'e //│ 0 <: 0 -> 'f) @@ -128,8 +128,8 @@ test 0 //│ ╙── ^^^^^^ //│ res: 'a -> (anything -> 'b //│ where -//│ 'a <: 'c -> 'b -//│ 0 <: 0 -> 'c) | error +//│ 0 <: 0 -> 'c +//│ 'a <: 'c -> 'b) | error //│ = [Function (anonymous)] def test extr x = diff --git a/shared/src/test/diff/fcp/FCPTony.mls b/shared/src/test/diff/fcp/FCPTony.mls index b4659058da..0c50732ff2 100644 --- a/shared/src/test/diff/fcp/FCPTony.mls +++ b/shared/src/test/diff/fcp/FCPTony.mls @@ -127,11 +127,11 @@ def succ n f x = f (n f x) :ns def add n m = n succ m -//│ add: forall 'a. 'a -> (forall 'b 'c 'd. 'd -> 'c +//│ add: forall 'a. 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ 'a <: (ChurchInt -> ChurchInt) -> 'b) +//│ 'a <: (ChurchInt -> ChurchInt) -> 'c) //│ where -//│ 'b <: 'd -> 'c +//│ 'c <: 'b -> 'd //│ = [Function: add] add @@ -142,13 +142,13 @@ add :ns def f x y = add x y -//│ f: forall 'a. 'a -> (forall 'b 'c 'd 'e 'f. 'b -> 'c +//│ f: forall 'a. 'a -> (forall 'b 'c 'd 'e 'f. 'e -> 'f //│ where -//│ 'a <: (ChurchInt -> ChurchInt) -> 'd) +//│ 'a <: (ChurchInt -> ChurchInt) -> 'b) //│ where -//│ 'b <: 'e -//│ 'd <: 'e -> 'f -//│ 'f <: 'c +//│ 'e <: 'c +//│ 'b <: 'c -> 'd +//│ 'd <: 'f //│ = [Function: f] // :ds diff --git a/shared/src/test/diff/fcp/FunnyId.mls b/shared/src/test/diff/fcp/FunnyId.mls index 9f524947cd..e0f434b95a 100644 --- a/shared/src/test/diff/fcp/FunnyId.mls +++ b/shared/src/test/diff/fcp/FunnyId.mls @@ -188,14 +188,14 @@ rec def id1 x = if true then x else id1 id1 x id1 id //│ res: 'a -> 'b | 'id //│ where -//│ 'a :> forall 'id 'c 'd. 'a -> 'b | 'id +//│ 'a :> forall 'c 'id 'd. 'a -> 'b | 'id //│ <: 'b -//│ 'b :> forall 'id 'c 'd. 'id +//│ 'b :> forall 'c 'id 'd. 'id //│ <: 'a -> 'b -//│ 'id :> 'c -> 'd -//│ 'c :> 'id -//│ <: 'd +//│ 'id :> 'd -> 'c //│ 'd :> 'id -//│ <: 'c -> 'd +//│ <: 'c +//│ 'c :> 'id +//│ <: 'd -> 'c diff --git a/shared/src/test/diff/fcp/MoreChurch.mls b/shared/src/test/diff/fcp/MoreChurch.mls index 1bfc9329c2..2317d48416 100644 --- a/shared/src/test/diff/fcp/MoreChurch.mls +++ b/shared/src/test/diff/fcp/MoreChurch.mls @@ -68,7 +68,7 @@ def add n m = n succ m // * Note: cycle check fails when generalizing curried lambdas add_ty = add -//│ ((forall 'a 'b 'c 'd. ('a -> 'b -> 'c) -> ('c -> 'd & 'a) -> 'b -> 'd) -> 'e -> 'f) -> 'e -> 'f +//│ ((forall 'a 'b 'c 'd. ('b -> 'c -> 'd) -> ('d -> 'a & 'b) -> 'c -> 'a) -> 'e -> 'f) -> 'e -> 'f //│ <: add_ty: //│ ChurchInt -> ChurchInt -> ChurchInt //│ = [Function: add] @@ -90,12 +90,12 @@ def mul_ty: ChurchInt -> ChurchInt -> ChurchInt //│ = def mul n m = n (add m) zero -//│ mul: ((forall 'a 'b 'c 'd 'e. ('d -> 'b -> 'a & 'c) -> (('a -> ('a & 'e) & 'd) -> 'b -> 'e | 'c)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g +//│ mul: ((forall 'a 'b 'c 'd 'e. ('c -> 'd -> 'e & 'a) -> (('e -> ('e & 'b) & 'c) -> 'd -> 'b | 'a)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g //│ = [Function: mul] // * Note: cycle check fails when generalizing curried lambdas mul_ty = mul -//│ ((forall 'a 'b 'c 'd 'e. ('a -> 'e -> 'd & 'c) -> (('d -> ('d & 'b) & 'a) -> 'e -> 'b | 'c)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g +//│ ((forall 'a 'b 'c 'd 'e. ('c -> 'b -> 'd & 'e) -> (('d -> ('d & 'a) & 'c) -> 'b -> 'a | 'e)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g //│ <: mul_ty: //│ ChurchInt -> ChurchInt -> ChurchInt //│ = [Function: mul] @@ -230,11 +230,11 @@ def pred n = let s p = pair (snd p) (succ (snd p)) in let z = pair zero zero in fst (n s z) -//│ pred: ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('d -> 'a -> 'f & 'e)) -> ('e -> (('f -> 'c & 'd) -> 'a -> 'c) -> 'b) -> 'b) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k +//│ pred: ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('e -> 'd -> 'a & 'b)) -> ('b -> (('a -> 'c & 'e) -> 'd -> 'c) -> 'f) -> 'f) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k //│ = [Function: pred1] // * Note: cycle check fails when generalizing curried lambdas pred_ty = pred -//│ ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('d -> 'c -> 'a & 'f)) -> ('f -> (('a -> 'e & 'd) -> 'c -> 'e) -> 'b) -> 'b) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k +//│ ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('f -> 'e -> 'c & 'a)) -> ('a -> (('c -> 'b & 'f) -> 'e -> 'b) -> 'd) -> 'd) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k //│ <: pred_ty: //│ ChurchInt -> ChurchInt //│ = [Function: pred1] diff --git a/shared/src/test/diff/fcp/NestedDataTypes.mls b/shared/src/test/diff/fcp/NestedDataTypes.mls index b02ecae949..9bb0546d38 100644 --- a/shared/src/test/diff/fcp/NestedDataTypes.mls +++ b/shared/src/test/diff/fcp/NestedDataTypes.mls @@ -230,17 +230,17 @@ rec def map f tree = case tree of { } //│ map: 'map //│ where -//│ 'map :> forall 'subTree 'A 'a 'subTree0 'value 'value0. 'a -> ((Leaf[?] & {value: 'value} | (Node[?] with {subTree: 'subTree})) -> (Leaf['value0] | (Node['A] with {subTree: 'subTree0})) +//│ 'map :> forall 'value 'value0 'subTree 'A 'a 'subTree0. 'a -> ((Leaf[?] & {value: 'value0} | (Node[?] with {subTree: 'subTree0})) -> (Leaf['value] | (Node['A] with {subTree: 'subTree})) //│ where -//│ 'a <: 'value -> 'value0 //│ 'map <: (forall 'b 'c 'd 'e. ('b, 'd,) -> ('c, 'e,) //│ where -//│ 'a <: 'b -> 'c & 'd -> 'e) -> 'subTree -> (PerfectTree[Two['A]] & 'subTree0)) +//│ 'a <: 'b -> 'c & 'd -> 'e) -> 'subTree0 -> (PerfectTree[Two['A]] & 'subTree) +//│ 'a <: 'value0 -> 'value) //│ = [Function: map1] :e map succ n4 -//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?subTree ?A ?value ?b ?A0 ?subTree0 ?A1. ?b) -> ?c` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?A ?value ?b ?A0 ?subTree ?A1 ?subTree0. ?b) -> ?c` exceeded recursion depth limit (250) //│ ║ l.242: map succ n4 //│ ║ ^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/PaperTable.mls b/shared/src/test/diff/fcp/PaperTable.mls index d5f4de259a..ab15ffbc13 100644 --- a/shared/src/test/diff/fcp/PaperTable.mls +++ b/shared/src/test/diff/fcp/PaperTable.mls @@ -618,7 +618,7 @@ rec def id1 x = if true then x else id1 id1 x :e // G9 id1 id1 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?id1 ?c ?d ?e. ?id1 <: (forall ?f ?g ?h ?i ?id10 ?j. ?id10) -> ?k` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?id1 ?e. ?id1 <: (forall ?f ?id10 ?g ?h ?i ?j. ?id10) -> ?k` exceeded recursion depth limit (250) //│ ║ l.620: id1 id1 //│ ║ ^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -968,7 +968,7 @@ rec def id1 x = if true then x else id1 id1 x :e // G9 id1 id1 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?id1 ?d ?e. ?id1 <: (forall ?f ?g ?id10 ?h ?i ?j. ?id10) -> ?k` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?id1 ?c ?d ?e. ?id1 <: (forall ?id10 ?f ?g ?h ?i ?j. ?id10) -> ?k` exceeded recursion depth limit (250) //│ ║ l.970: id1 id1 //│ ║ ^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/Proofs.mls b/shared/src/test/diff/fcp/Proofs.mls index a8fbf38e52..2ee3205792 100644 --- a/shared/src/test/diff/fcp/Proofs.mls +++ b/shared/src/test/diff/fcp/Proofs.mls @@ -142,7 +142,7 @@ DNE_to_EM: DNE -> EM def DNE_to_EM_let dne = let poly = dne (fun not_em -> not_em (Right { v = fun a -> not_em (Left { v = a }) })) in poly -//│ DNE_to_EM_let: ((forall 'a 'b 'v. ((Left with {v: 'v}) -> 'a & (Right & {v: 'v -> 'a}) -> 'b) -> 'b) -> 'c) -> 'c +//│ DNE_to_EM_let: ((forall 'v 'a 'b. ((Left with {v: 'v}) -> 'a & (Right & {v: 'v -> 'a}) -> 'b) -> 'b) -> 'c) -> 'c //│ = [Function: DNE_to_EM_let] // * This one used to work because we used let polymorphism @@ -454,9 +454,9 @@ EM_to_DNE: EM -> DNE def DNE_to_EM dne = dne (fun not_em -> not_em (Right { v = fun a -> not_em (Left { v = a }) })) -//│ DNE_to_EM: ((forall 'a 'b. ((Right & {v: forall 'c 'v. 'v -> 'c +//│ DNE_to_EM: ((forall 'a 'b. ((Right & {v: forall 'v 'c. 'v -> 'c //│ where -//│ 'b <: (Left with {v: 'v}) -> 'c}) -> 'a & 'b) -> 'a) -> 'd) -> 'd +//│ 'a <: (Left with {v: 'v}) -> 'c}) -> 'b & 'a) -> 'b) -> 'd) -> 'd :e // * Still needs distrib! (after "sound extrusion") DNE_to_EM: DNE -> EM diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls b/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls index 2aca942c40..b90da69a6c 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls @@ -48,9 +48,9 @@ baseImpl = ArraysImpl { update = fun r -> fun (i : int) -> fun a -> a; fold = fun f -> fun b -> fun r -> f r b } -//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c 'd. 'b -> 'c -> ('d -> 'a +//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c 'd. 'a -> 'b -> ('c -> 'd //│ where -//│ 'b <: 'd -> 'c -> 'a), init: forall 'e. 'e -> 'e, sub: forall 'f. 'f -> int -> 'f, update: forall 'g. anything -> int -> 'g -> 'g} +//│ 'a <: 'c -> 'b -> 'd), init: forall 'e. 'e -> 'e, sub: forall 'f. 'f -> int -> 'f, update: forall 'g. anything -> int -> 'g -> 'g} //│ = ArraysImpl { //│ init: [Function: init], //│ sub: [Function: sub], @@ -84,7 +84,7 @@ def simpleStepImpl arrImpl = ArraysImpl { //│ where //│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 //│ where -//│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) +//│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'A7 'Rep6. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where //│ 'c <: ArraysRep['A7, 'Rep6])}) //│ where @@ -107,37 +107,37 @@ def simpleStepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> Arrays def simpleStepImpl2 arr = arr simpleStepImpl -//│ simpleStepImpl2: ((forall 'Rep 'a 'A 'Rep0 'A0 'Rep1 'A1 'c 'A2 'A3 'Rep2. (ArraysRep[in 'A | 'A0 & 'A1 | 'A3 | 'A1 & 'A2 out 'A & 'A0 & 'A3 & 'A2, in 'c & 'Rep1 & 'Rep | 'Rep1 | 'Rep0 out 'Rep & 'c & 'Rep1 & ('c | 'Rep0)] & 'a) -> (ArraysImpl['A1, 'Rep2] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b +//│ simpleStepImpl2: ((forall 'A 'a 'c 'Rep 'Rep0 'Rep1 'A0 'A1 'A2 'A3 'Rep2. (ArraysRep[in 'A3 | 'A2 & 'A | 'A1 | 'A & 'A0 out 'A3 & 'A2 & 'A1 & 'A0, in 'a & 'Rep2 & 'Rep | 'Rep2 | 'Rep1 out 'Rep & 'a & 'Rep2 & ('a | 'Rep1)] & 'c) -> (ArraysImpl['A, 'Rep0] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b //│ where -//│ 'd <: 'A4 -> 'b -> 'b -//│ 'a <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) +//│ 'c <: ArraysRep['A4, 'Rep3] +//│ 'd <: 'A4 -> 'b -> 'b), init: forall 'Rep4 'A5. 'A5 -> ('Rep4, "initialized",) //│ where -//│ 'a <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 +//│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 //│ where -//│ 'a <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) +//│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where -//│ 'a <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e +//│ 'c <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e //│ where -//│ 'Rep2 :> ('c, "initialized" | "updated",) +//│ 'Rep0 :> ('a, "initialized" | "updated",) //│ <: (nothing, anything,) -//│ 'A1 <: nothing +//│ 'A <: nothing //│ = [Function: simpleStepImpl2] simpleStepImpl2_ty = simpleStepImpl2 -//│ ((forall 'a 'A 'Rep 'c 'A0 'A1 'Rep0 'Rep1 'A2 'A3 'Rep2. (ArraysRep[in 'A0 | 'A3 & 'A2 | 'A | 'A2 & 'A1 out 'A0 & 'A3 & 'A & 'A1, in 'c & 'Rep0 & 'Rep2 | 'Rep0 | 'Rep1 out 'Rep2 & 'c & 'Rep0 & ('c | 'Rep1)] & 'a) -> (ArraysImpl['A2, 'Rep] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b +//│ ((forall 'a 'A 'Rep 'A0 'A1 'A2 'c 'Rep0 'Rep1 'Rep2 'A3. (ArraysRep[in 'A3 | 'A1 & 'A | 'A0 | 'A & 'A2 out 'A3 & 'A1 & 'A0 & 'A2, in 'a & 'Rep & 'Rep0 | 'Rep | 'Rep1 out 'Rep0 & 'a & 'Rep & ('a | 'Rep1)] & 'c) -> (ArraysImpl['A, 'Rep2] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b //│ where -//│ 'a <: ArraysRep['A4, 'Rep3] -//│ 'd <: 'A4 -> 'b -> 'b), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) +//│ 'd <: 'A4 -> 'b -> 'b +//│ 'c <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) //│ where -//│ 'a <: ArraysRep['A5, 'Rep4], sub: forall 'A6 'Rep5. ('Rep5, anything,) -> (int -> 'A6 +//│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 //│ where -//│ 'a <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) +//│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where -//│ 'a <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e +//│ 'c <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e //│ where -//│ 'Rep :> ('c, "initialized" | "updated",) -//│ <: (nothing, anything,) -//│ 'A2 <: nothing +//│ 'Rep2 :> ('a, "initialized" | "updated",) +//│ <: (nothing, anything,) +//│ 'A <: nothing //│ <: simpleStepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, string,)] //│ = [Function: simpleStepImpl2] @@ -183,20 +183,20 @@ def simpleStep: Arrays['a] -> Arrays['a] def simpleStep arr f = f (simpleStepImpl2 arr) //│ 'a -> (('c -> 'd) -> 'd //│ where -//│ 'a <: (forall 'A 'A0 'Rep 'e 'f. (ArraysRep[in anything out nothing, in 'A out nothing] & 'e) -> (ArraysImpl['A0, 'Rep] with {fold: forall 'g 'b 'A1 'Rep0. 'g -> 'b -> (('Rep0, 'A,) -> 'b +//│ 'a <: (forall 'e 'f 'A 'A0 'Rep. (ArraysRep[in anything out nothing, in 'A0 out nothing] & 'e) -> (ArraysImpl['A, 'Rep] with {fold: forall 'b 'A1 'Rep0 'g. 'g -> 'b -> (('Rep0, 'A0,) -> 'b //│ where //│ 'e <: ArraysRep['A1, 'Rep0] //│ 'g <: 'A1 -> 'b -> 'b), init: forall 'A2 'Rep1. 'A2 -> ('Rep1, "initialized",) //│ where -//│ 'e <: ArraysRep['A2, 'Rep1], sub: forall 'Rep2 'A3. ('Rep2, 'A,) -> (int -> 'A3 +//│ 'e <: ArraysRep['A2, 'Rep1], sub: forall 'Rep2 'A3. ('Rep2, 'A0,) -> (int -> 'A3 //│ where -//│ 'e <: ArraysRep['A3, 'Rep2]), update: forall 'Rep3 'A4. ('Rep3, 'A,) -> int -> ('A4 -> ('Rep3, "updated",) +//│ 'e <: ArraysRep['A3, 'Rep2]), update: forall 'Rep3 'A4. ('Rep3, 'A0,) -> int -> ('A4 -> ('Rep3, "updated",) //│ where //│ 'e <: ArraysRep['A4, 'Rep3])})) -> 'c) //│ where //│ 'Rep :> ('f, "initialized" | "updated",) -//│ <: (nothing, 'A,) -//│ 'A0 <: nothing +//│ <: (nothing, 'A0,) +//│ 'A <: nothing //│ <: simpleStep: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -355,16 +355,16 @@ def stepImpl arrImpl = ArraysImpl { else (r0, arrImpl.Update r1 (div i 2) a); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f (arrImpl.Fold f b r0) r1 } -//│ stepImpl: (ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 & 'A4 | 'A3 & 'A5 | 'A3 & ('A6 | 'A7) out 'A & 'A0 & 'A6 & 'A7 & 'A1 & 'A2 & 'A4 & 'A5, in 'a & 'Rep & 'Rep0 | 'Rep | 'c & 'Rep1 & 'Rep2 | 'Rep1 | 'Rep3 | 'Rep4 out 'Rep0 & 'a & 'Rep & 'Rep2 & 'c & 'Rep1 & ('a | 'Rep3) & ('c | 'Rep4)] & 'd) -> (ArraysImpl['A3, 'Rep5] with {fold: forall 'Rep6 'e 'b 'f 'Rep7 'A8 'b0 'A9. 'f -> 'e -> (('Rep7, 'Rep6,) -> ('e | 'b) +//│ stepImpl: (ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 & 'A4 | 'A3 & 'A5 | 'A3 & ('A6 | 'A7) out 'A & 'A0 & 'A6 & 'A7 & 'A1 & 'A2 & 'A4 & 'A5, in 'Rep | 'Rep0 | 'Rep1 | 'Rep2 out 'Rep3 & 'a & 'Rep4 & 'c & ('a | 'Rep1) & ('c | 'Rep2)] & 'd) -> (ArraysImpl['A3, 'Rep5] with {fold: forall 'Rep6 'A8 'e 'b 'A9 'b0 'Rep7 'f. 'f -> 'e -> (('Rep7, 'Rep6,) -> ('e | 'b) //│ where -//│ 'd <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7] -//│ 'f <: 'A9 -> ('e | 'b) -> 'b & 'A8 -> ('b0 | 'e) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) +//│ 'f <: 'A9 -> ('e | 'b) -> 'b & 'A8 -> ('b0 | 'e) -> ('b & 'b0) +//│ 'd <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7]), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) //│ where -//│ 'd <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'A12 'Rep10 'g 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g +//│ 'd <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'Rep10 'Rep11 'A12 'g 'A13. ('Rep11, 'Rep10,) -> (int -> 'g //│ where -//│ 'd <: ArraysRep['A13, 'Rep10] & ArraysRep['A12, 'Rep11]), update: forall 'Rep12 'A14 'A15 'Rep13. ('Rep13, 'Rep12,) -> int -> (('A14 & 'A15) -> ('Rep13, 'Rep12,) +//│ 'd <: ArraysRep['A13, 'Rep11] & ArraysRep['A12, 'Rep10]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where -//│ 'd <: ArraysRep['A14, 'Rep13] & ArraysRep['A15, 'Rep12])}) +//│ 'd <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])}) //│ where //│ 'A12 <: 'g //│ 'A13 <: 'g @@ -378,39 +378,39 @@ def stepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl[' //│ = def stepImpl2 arr = arr stepImpl -//│ stepImpl2: ((forall 'A 'a 'Rep 'A0 'Rep0 'c 'A1 'A2 'Rep1 'Rep2 'A3 'Rep3 'Rep4 'A4 'A5 'd 'Rep5 'A6 'A7. (ArraysRep[in 'A5 | 'A7 | 'A | 'A6 | 'A4 & 'A2 | 'A4 & 'A0 | 'A4 & ('A1 | 'A3) out 'A5 & 'A7 & 'A1 & 'A3 & 'A & 'A6 & 'A2 & 'A0, in 'c & 'Rep2 & 'Rep | 'Rep2 | 'd & 'Rep4 & 'Rep3 | 'Rep4 | 'Rep1 | 'Rep0 out 'Rep & 'c & 'Rep2 & 'Rep3 & 'd & 'Rep4 & ('c | 'Rep1) & ('d | 'Rep0)] & 'a) -> (ArraysImpl['A4, 'Rep5] with {fold: forall 'b 'Rep6 'e 'b0 'Rep7 'A8 'A9 'f. 'e -> 'f -> (('Rep7, 'Rep6,) -> ('f | 'b0) +//│ stepImpl2: ((forall 'Rep 'A 'A0 'A1 'Rep0 'A2 'A3 'Rep1 'A4 'A5 'A6 'Rep2 'Rep3 'Rep4 'a 'A7 'c 'Rep5 'd. (ArraysRep[in 'A6 | 'A7 | 'A | 'A1 | 'A5 & 'A3 | 'A5 & 'A0 | 'A5 & ('A2 | 'A4) out 'A6 & 'A7 & 'A2 & 'A4 & 'A & 'A1 & 'A3 & 'A0, in 'Rep3 | 'Rep1 | 'Rep0 | 'Rep out 'Rep2 & 'd & 'Rep5 & 'c & ('d | 'Rep0) & ('c | 'Rep)] & 'a) -> (ArraysImpl['A5, 'Rep4] with {fold: forall 'A8 'b 'Rep6 'e 'A9 'f 'Rep7 'b0. 'e -> 'f -> (('Rep7, 'Rep6,) -> ('f | 'b) //│ where -//│ 'a <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7] -//│ 'e <: 'A9 -> ('f | 'b0) -> 'b0 & 'A8 -> ('b | 'f) -> ('b0 & 'b)), init: forall 'Rep8 'A10 'Rep9 'A11. ('A11 & 'A10) -> ('Rep8, 'Rep9,) +//│ 'a <: ArraysRep['A8, 'Rep6] & ArraysRep['A9, 'Rep7] +//│ 'e <: 'A8 -> ('f | 'b) -> 'b & 'A9 -> ('b0 | 'f) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) //│ where -//│ 'a <: ArraysRep['A11, 'Rep8] & ArraysRep['A10, 'Rep9], sub: forall 'g 'Rep10 'Rep11 'A12 'A13. ('Rep11, 'Rep10,) -> (int -> 'g +//│ 'a <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'g 'Rep10 'A12 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g //│ where -//│ 'a <: ArraysRep['A12, 'Rep11] & ArraysRep['A13, 'Rep10]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) +//│ 'a <: ArraysRep['A13, 'Rep10] & ArraysRep['A12, 'Rep11]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where //│ 'a <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h //│ where -//│ 'A13 <: 'g //│ 'A12 <: 'g -//│ 'Rep5 :> ('c, 'd,) +//│ 'A13 <: 'g +//│ 'Rep4 :> ('d, 'c,) //│ <: (nothing, nothing,) -//│ 'A4 <: nothing +//│ 'A5 <: nothing //│ = [Function: stepImpl2] stepImpl2_ty = stepImpl2 -//│ ((forall 'A 'Rep 'a 'Rep0 'A0 'Rep1 'A1 'A2 'A3 'c 'A4 'd 'A5 'A6 'Rep2 'A7 'Rep3 'Rep4 'Rep5. (ArraysRep[in 'A | 'A3 | 'A7 | 'A0 | 'A2 & 'A5 | 'A2 & 'A6 | 'A2 & ('A1 | 'A4) out 'A & 'A3 & 'A1 & 'A4 & 'A7 & 'A0 & 'A5 & 'A6, in 'c & 'Rep3 & 'Rep5 | 'Rep3 | 'd & 'Rep4 & 'Rep0 | 'Rep4 | 'Rep2 | 'Rep out 'Rep5 & 'c & 'Rep3 & 'Rep0 & 'd & 'Rep4 & ('c | 'Rep2) & ('d | 'Rep)] & 'a) -> (ArraysImpl['A2, 'Rep1] with {fold: forall 'Rep6 'A8 'Rep7 'b 'e 'A9 'f 'b0. 'e -> 'f -> (('Rep6, 'Rep7,) -> ('f | 'b) +//│ ((forall 'Rep 'Rep0 'Rep1 'a 'A 'A0 'A1 'A2 'c 'Rep2 'A3 'A4 'Rep3 'A5 'Rep4 'Rep5 'A6 'A7 'd. (ArraysRep[in 'A4 | 'A3 | 'A7 | 'A5 | 'A2 & 'A0 | 'A2 & 'A6 | 'A2 & ('A1 | 'A) out 'A4 & 'A3 & 'A1 & 'A & 'A7 & 'A5 & 'A0 & 'A6, in 'Rep5 | 'Rep4 | 'Rep | 'Rep0 out 'Rep1 & 'a & 'Rep2 & 'd & ('a | 'Rep) & ('d | 'Rep0)] & 'c) -> (ArraysImpl['A2, 'Rep3] with {fold: forall 'A8 'Rep6 'Rep7 'e 'b 'f 'b0 'A9. 'e -> 'f -> (('Rep6, 'Rep7,) -> ('f | 'b0) //│ where -//│ 'a <: ArraysRep['A8, 'Rep7] & ArraysRep['A9, 'Rep6] -//│ 'e <: 'A8 -> ('f | 'b) -> 'b & 'A9 -> ('b0 | 'f) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) +//│ 'c <: ArraysRep['A9, 'Rep7] & ArraysRep['A8, 'Rep6] +//│ 'e <: 'A9 -> ('f | 'b0) -> 'b0 & 'A8 -> ('b | 'f) -> ('b0 & 'b)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A11 & 'A10) -> ('Rep9, 'Rep8,) //│ where -//│ 'a <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'Rep10 'A12 'g 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g +//│ 'c <: ArraysRep['A11, 'Rep9] & ArraysRep['A10, 'Rep8], sub: forall 'A12 'g 'Rep10 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g //│ where -//│ 'a <: ArraysRep['A12, 'Rep10] & ArraysRep['A13, 'Rep11]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) +//│ 'c <: ArraysRep['A12, 'Rep10] & ArraysRep['A13, 'Rep11]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where -//│ 'a <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h +//│ 'c <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h //│ where //│ 'A13 <: 'g //│ 'A12 <: 'g -//│ 'Rep1 :> ('c, 'd,) +//│ 'Rep3 :> ('a, 'd,) //│ <: (nothing, nothing,) //│ 'A2 <: nothing //│ <: stepImpl2_ty: @@ -426,16 +426,16 @@ def step: Arrays['a] -> Arrays['a] def step arr f = f (stepImpl2 arr) //│ 'a -> (('c -> 'd) -> 'd //│ where -//│ 'a <: (forall 'A 'e 'f 'g. (ArraysRep[in anything out nothing, in anything out 'e & 'f] & 'g) -> (ArraysImpl['A, ('e, 'f,)] with {fold: forall 'A0 'Rep 'h 'b 'b0 'A1 'i 'Rep0. 'h -> 'i -> (('Rep, 'Rep0,) -> ('i | 'b) +//│ 'a <: (forall 'A 'e 'f 'g. (ArraysRep[in anything out nothing, in anything out 'e & 'f] & 'g) -> (ArraysImpl['A, ('e, 'f,)] with {fold: forall 'Rep 'b 'h 'A0 'i 'Rep0 'A1 'b0. 'i -> 'h -> (('Rep0, 'Rep,) -> ('h | 'b0) //│ where -//│ 'g <: ArraysRep['A1, 'Rep0] & ArraysRep['A0, 'Rep] -//│ 'h <: 'A1 -> ('i | 'b) -> 'b & 'A0 -> ('b0 | 'i) -> ('b & 'b0)), init: forall 'A2 'Rep1 'A3 'Rep2. ('A2 & 'A3) -> ('Rep1, 'Rep2,) +//│ 'g <: ArraysRep['A1, 'Rep] & ArraysRep['A0, 'Rep0] +//│ 'i <: 'A1 -> ('h | 'b0) -> 'b0 & 'A0 -> ('b | 'h) -> ('b0 & 'b)), init: forall 'A2 'Rep1 'A3 'Rep2. ('A2 & 'A3) -> ('Rep1, 'Rep2,) //│ where -//│ 'g <: ArraysRep['A2, 'Rep1] & ArraysRep['A3, 'Rep2], sub: forall 'A4 'j 'A5 'Rep3 'Rep4. ('Rep3, 'Rep4,) -> (int -> 'j +//│ 'g <: ArraysRep['A2, 'Rep1] & ArraysRep['A3, 'Rep2], sub: forall 'Rep3 'A4 'Rep4 'j 'A5. ('Rep4, 'Rep3,) -> (int -> 'j //│ where -//│ 'g <: ArraysRep['A5, 'Rep3] & ArraysRep['A4, 'Rep4]), update: forall 'A6 'Rep5 'Rep6 'A7. ('Rep5, 'Rep6,) -> int -> (('A7 & 'A6) -> ('Rep5, 'Rep6,) +//│ 'g <: ArraysRep['A5, 'Rep4] & ArraysRep['A4, 'Rep3]), update: forall 'Rep5 'Rep6 'A6 'A7. ('Rep5, 'Rep6,) -> int -> (('A6 & 'A7) -> ('Rep5, 'Rep6,) //│ where -//│ 'g <: ArraysRep['A7, 'Rep5] & ArraysRep['A6, 'Rep6])})) -> 'c) +//│ 'g <: ArraysRep['A6, 'Rep5] & ArraysRep['A7, 'Rep6])})) -> 'c) //│ where //│ 'A4 <: 'j //│ 'A5 <: 'j diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls b/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls index 098495439a..7fe726a3f9 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls @@ -48,7 +48,7 @@ baseImpl = ArraysImpl { update = fun r -> fun (i : int) -> fun a -> a; fold = fun f -> fun b -> fun r -> f r b } -//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c. ('b -> 'c -> 'a) -> 'c -> 'b -> 'a, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> int -> 'e, update: forall 'f. anything -> int -> 'f -> 'f} +//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> int -> 'e, update: forall 'f. anything -> int -> 'f -> 'f} //│ = ArraysImpl { //│ init: [Function: init], //│ sub: [Function: sub], @@ -88,20 +88,20 @@ def simpleStepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> Arrays def simpleStepImpl2 arr = arr simpleStepImpl -//│ simpleStepImpl2: ((forall 'A 'Rep 'A0 'A1 'Rep0 'A2 'A3 'Rep1 'Rep2. ArraysRep[in 'A2 | 'A1 | 'A0 | 'A & 'A3 out 'A1 & 'A, in 'Rep0 | 'Rep1 out nothing] -> (ArraysImpl['A3, 'Rep2] with {fold: forall 'b. ('A -> 'b -> 'b) -> 'b -> ('Rep1, anything,) -> 'b, init: 'A2 -> (nothing, "initialized",), sub: ('Rep0, anything,) -> int -> 'A1, update: forall 'a. ('Rep & 'a, anything,) -> int -> 'A0 -> ('a, "updated",)})) -> 'c) -> 'c +//│ simpleStepImpl2: ((forall 'Rep 'A 'A0 'Rep0 'A1 'Rep1 'A2 'A3 'Rep2. ArraysRep[in 'A | 'A2 | 'A1 | 'A3 & 'A0 out 'A2 & 'A3, in 'Rep2 | 'Rep0 out nothing] -> (ArraysImpl['A0, 'Rep] with {fold: forall 'b. ('A3 -> 'b -> 'b) -> 'b -> ('Rep0, anything,) -> 'b, init: 'A -> (nothing, "initialized",), sub: ('Rep2, anything,) -> int -> 'A2, update: forall 'a. ('Rep1 & 'a, anything,) -> int -> 'A1 -> ('a, "updated",)})) -> 'c) -> 'c //│ where -//│ 'Rep2 :> (nothing, "initialized" | "updated",) -//│ <: (nothing, anything,) -//│ 'A3 :> 'A1 +//│ 'Rep :> (nothing, "initialized" | "updated",) +//│ <: (nothing, anything,) +//│ 'A0 :> 'A2 //│ <: nothing //│ = [Function: simpleStepImpl2] simpleStepImpl2_ty = simpleStepImpl2 -//│ ((forall 'A 'Rep 'A0 'Rep0 'Rep1 'A1 'Rep2 'A2 'A3. ArraysRep[in 'A3 | 'A0 | 'A | 'A2 & 'A1 out 'A0 & 'A2, in 'Rep0 | 'Rep out nothing] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b. ('A2 -> 'b -> 'b) -> 'b -> ('Rep, anything,) -> 'b, init: 'A3 -> (nothing, "initialized",), sub: ('Rep0, anything,) -> int -> 'A0, update: forall 'a. ('Rep2 & 'a, anything,) -> int -> 'A -> ('a, "updated",)})) -> 'c) -> 'c +//│ ((forall 'A 'A0 'Rep 'Rep0 'A1 'Rep1 'Rep2 'A2 'A3. ArraysRep[in 'A3 | 'A1 | 'A0 | 'A & 'A2 out 'A1 & 'A, in 'Rep0 | 'Rep2 out nothing] -> (ArraysImpl['A2, 'Rep1] with {fold: forall 'b. ('A -> 'b -> 'b) -> 'b -> ('Rep2, anything,) -> 'b, init: 'A3 -> (nothing, "initialized",), sub: ('Rep0, anything,) -> int -> 'A1, update: forall 'a. ('Rep & 'a, anything,) -> int -> 'A0 -> ('a, "updated",)})) -> 'c) -> 'c //│ where //│ 'Rep1 :> (nothing, "initialized" | "updated",) //│ <: (nothing, anything,) -//│ 'A1 :> 'A0 +//│ 'A2 :> 'A1 //│ <: nothing //│ <: simpleStepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, string,)] @@ -149,11 +149,11 @@ def simpleStep: Arrays['a] -> Arrays['a] :e // * Since "sound extrusion" def simpleStep arr f = f (simpleStepImpl2 arr) -//│ ((forall 'A 'Rep 'Rep0 'Rep1 'A0 'A1 'A2 'A3 'Rep2. ArraysRep[in 'A3 | 'A2 | 'A | 'A0 & 'A1 out 'A2 & 'A0, in 'Rep2 | 'Rep out nothing] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b. ('A0 -> 'b -> 'b) -> 'b -> ('Rep, anything,) -> 'b, init: 'A3 -> (nothing, "initialized",), sub: ('Rep2, anything,) -> int -> 'A2, update: forall 'a. ('Rep0 & 'a, anything,) -> int -> 'A -> ('a, "updated",)})) -> 'c) -> ('c -> 'd) -> 'd +//│ ((forall 'Rep 'Rep0 'A 'A0 'Rep1 'A1 'A2 'Rep2 'A3. ArraysRep[in 'A3 | 'A | 'A1 | 'A0 & 'A2 out 'A & 'A0, in 'Rep2 | 'Rep out nothing] -> (ArraysImpl['A2, 'Rep1] with {fold: forall 'b. ('A0 -> 'b -> 'b) -> 'b -> ('Rep, anything,) -> 'b, init: 'A3 -> (nothing, "initialized",), sub: ('Rep2, anything,) -> int -> 'A, update: forall 'a. ('Rep0 & 'a, anything,) -> int -> 'A1 -> ('a, "updated",)})) -> 'c) -> ('c -> 'd) -> 'd //│ where //│ 'Rep1 :> (nothing, "initialized" | "updated",) //│ <: (nothing, anything,) -//│ 'A1 :> 'A2 +//│ 'A2 :> 'A //│ <: nothing //│ <: simpleStep: //│ Arrays['a] -> Arrays['a] @@ -319,7 +319,7 @@ def stepImpl arrImpl = ArraysImpl { else (r0, arrImpl.Update r1 (div i 2) a); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f (arrImpl.Fold f b r0) r1 } -//│ stepImpl: ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 | 'A4 | 'A5 & ('A6 | 'A7) out 'A1 & 'A2 & 'A6 & 'A7, in 'Rep | 'Rep0 | 'Rep1 | 'Rep2 out nothing] -> (ArraysImpl['A5, 'Rep3] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A7 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep2, 'Rep1,) -> 'b, init: ('A & 'A0) -> (nothing, nothing,), sub: ('Rep, 'Rep0,) -> int -> ('A1 | 'A2), update: forall 'a 'c. ('Rep4 & 'a, 'Rep5 & 'c,) -> int -> ('A3 & 'A4) -> ('a, 'c,)}) +//│ stepImpl: ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 | 'A4 | 'A5 & ('A6 | 'A7) out 'A1 & 'A2 & 'A6 & 'A7, in 'Rep | 'Rep0 | 'Rep1 | 'Rep2 out nothing] -> (ArraysImpl['A5, 'Rep3] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A7 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep2, 'Rep1,) -> 'b, init: ('A & 'A0) -> (nothing, nothing,), sub: ('Rep, 'Rep0,) -> int -> ('A1 | 'A2), update: forall 'a 'c. ('Rep4 & 'c, 'Rep5 & 'a,) -> int -> ('A3 & 'A4) -> ('c, 'a,)}) //│ where //│ 'Rep3 :> ('d, 'e,) //│ <: (nothing, nothing,) @@ -332,20 +332,20 @@ def stepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl[' //│ = def stepImpl2 arr = arr stepImpl -//│ stepImpl2: ((forall 'Rep 'Rep0 'A 'Rep1 'A0 'A1 'A2 'Rep2 'a 'A3 'Rep3 'Rep4 'A4 'A5 'Rep5 'A6 'A7 'c. ArraysRep[in 'A5 | 'A7 | 'A6 | 'A1 | 'A3 | 'A0 | 'A4 & ('A | 'A2) out 'A6 & 'A1 & 'A & 'A2, in 'Rep5 | 'Rep4 | 'Rep0 | 'Rep1 out nothing] -> (ArraysImpl['A4, 'Rep3] with {fold: forall 'b 'b0. ('A -> 'b0 -> 'b0 & 'A2 -> 'b -> ('b0 & 'b)) -> ('b0 & 'b) -> ('Rep1, 'Rep0,) -> 'b0, init: ('A5 & 'A7) -> (nothing, nothing,), sub: ('Rep5, 'Rep4,) -> int -> ('A6 | 'A1), update: forall 'd 'e. ('Rep2 & 'd, 'Rep & 'e,) -> int -> ('A3 & 'A0) -> ('d, 'e,)})) -> 'f) -> 'f +//│ stepImpl2: ((forall 'A 'A0 'A1 'Rep 'Rep0 'A2 'A3 'Rep1 'Rep2 'A4 'a 'Rep3 'A5 'Rep4 'Rep5 'A6 'c 'A7. ArraysRep[in 'A2 | 'A4 | 'A7 | 'A0 | 'A5 | 'A3 | 'A1 & ('A6 | 'A) out 'A7 & 'A0 & 'A6 & 'A, in 'Rep | 'Rep1 | 'Rep3 | 'Rep5 out nothing] -> (ArraysImpl['A1, 'Rep4] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep5, 'Rep3,) -> 'b, init: ('A2 & 'A4) -> (nothing, nothing,), sub: ('Rep, 'Rep1,) -> int -> ('A7 | 'A0), update: forall 'd 'e. ('Rep2 & 'd, 'Rep0 & 'e,) -> int -> ('A5 & 'A3) -> ('d, 'e,)})) -> 'f) -> 'f //│ where -//│ 'Rep3 :> ('c, 'a,) +//│ 'Rep4 :> ('a, 'c,) //│ <: (nothing, nothing,) -//│ 'A4 :> anything +//│ 'A1 :> anything //│ <: nothing //│ = [Function: stepImpl2] stepImpl2_ty = stepImpl2 -//│ ((forall 'Rep 'A 'A0 'Rep0 'A1 'A2 'A3 'Rep1 'A4 'Rep2 'Rep3 'A5 'a 'Rep4 'A6 'A7 'c 'Rep5. ArraysRep[in 'A0 | 'A7 | 'A5 | 'A3 | 'A1 | 'A4 | 'A6 & ('A | 'A2) out 'A5 & 'A3 & 'A & 'A2, in 'Rep2 | 'Rep4 | 'Rep | 'Rep3 out nothing] -> (ArraysImpl['A6, 'Rep5] with {fold: forall 'b 'b0. ('A -> 'b -> 'b & 'A2 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep3, 'Rep,) -> 'b, init: ('A0 & 'A7) -> (nothing, nothing,), sub: ('Rep2, 'Rep4,) -> int -> ('A5 | 'A3), update: forall 'd 'e. ('Rep1 & 'd, 'Rep0 & 'e,) -> int -> ('A1 & 'A4) -> ('d, 'e,)})) -> 'f) -> 'f +//│ ((forall 'A 'A0 'a 'Rep 'A1 'A2 'A3 'c 'A4 'A5 'Rep0 'Rep1 'A6 'A7 'Rep2 'Rep3 'Rep4 'Rep5. ArraysRep[in 'A3 | 'A1 | 'A4 | 'A7 | 'A0 | 'A2 | 'A5 & ('A6 | 'A) out 'A4 & 'A7 & 'A6 & 'A, in 'Rep0 | 'Rep3 | 'Rep | 'Rep5 out nothing] -> (ArraysImpl['A5, 'Rep2] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep5, 'Rep,) -> 'b, init: ('A3 & 'A1) -> (nothing, nothing,), sub: ('Rep0, 'Rep3,) -> int -> ('A4 | 'A7), update: forall 'd 'e. ('Rep4 & 'd, 'Rep1 & 'e,) -> int -> ('A0 & 'A2) -> ('d, 'e,)})) -> 'f) -> 'f //│ where -//│ 'Rep5 :> ('c, 'a,) +//│ 'Rep2 :> ('a, 'c,) //│ <: (nothing, nothing,) -//│ 'A6 :> anything +//│ 'A5 :> anything //│ <: nothing //│ <: stepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, 'Rep,)] @@ -358,11 +358,11 @@ def step: Arrays['a] -> Arrays['a] :e // * Since "sound extrusion" def step arr f = f (stepImpl2 arr) -//│ ((forall 'Rep 'A 'Rep0 'Rep1 'A0 'Rep2 'a 'A1 'Rep3 'Rep4 'A2 'c 'A3 'A4 'Rep5 'A5 'A6 'A7. ArraysRep[in 'A5 | 'A0 | 'A4 | 'A6 | 'A7 | 'A | 'A2 & ('A1 | 'A3) out 'A4 & 'A6 & 'A1 & 'A3, in 'Rep0 | 'Rep5 | 'Rep4 | 'Rep out nothing] -> (ArraysImpl['A2, 'Rep3] with {fold: forall 'b 'b0. ('A1 -> 'b -> 'b & 'A3 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep, 'Rep4,) -> 'b, init: ('A5 & 'A0) -> (nothing, nothing,), sub: ('Rep0, 'Rep5,) -> int -> ('A4 | 'A6), update: forall 'd 'e. ('Rep2 & 'd, 'Rep1 & 'e,) -> int -> ('A7 & 'A) -> ('d, 'e,)})) -> 'f) -> ('f -> 'g) -> 'g +//│ ((forall 'A 'Rep 'A0 'A1 'Rep0 'Rep1 'Rep2 'A2 'Rep3 'A3 'Rep4 'A4 'A5 'Rep5 'a 'c 'A6 'A7. ArraysRep[in 'A6 | 'A7 | 'A0 | 'A5 | 'A3 | 'A | 'A1 & ('A2 | 'A4) out 'A0 & 'A5 & 'A2 & 'A4, in 'Rep | 'Rep0 | 'Rep2 | 'Rep4 out nothing] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b 'b0. ('A2 -> 'b -> 'b & 'A4 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep4, 'Rep2,) -> 'b, init: ('A6 & 'A7) -> (nothing, nothing,), sub: ('Rep, 'Rep0,) -> int -> ('A0 | 'A5), update: forall 'd 'e. ('Rep5 & 'd, 'Rep3 & 'e,) -> int -> ('A3 & 'A) -> ('d, 'e,)})) -> 'f) -> ('f -> 'g) -> 'g //│ where -//│ 'Rep3 :> ('c, 'a,) +//│ 'Rep1 :> ('a, 'c,) //│ <: (nothing, nothing,) -//│ 'A2 :> anything +//│ 'A1 :> anything //│ <: nothing //│ <: step: //│ Arrays['a] -> Arrays['a] diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls b/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls index ec53871583..f32ab899a0 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls @@ -55,7 +55,7 @@ def simpleStepImpl arrImpl = ArraysImpl { // * Something off is going on here (see stats) :stats simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?A ?a ?Rep ?A0 ?A1 ?fold ?Rep0 ?b ?A2 ?c ?d ?Rep1 ?init ?Rep2 ?Rep3 ?A3 ?e ?f ?update ?A4 ?Rep4 ?g ?A5 ?Rep5 ?Rep6 ?Rep7 ?A6 ?A7 ?h ?sub ?Rep8 ?Rep9 ?Rep10 ?A8 ?i ?j ?k ?A9. ?k -> ?c <: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)]` took too many steps and ran out of fuel (5000) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?Rep ?Rep0 ?A ?a ?b ?Rep1 ?Rep2 ?c ?Rep3 ?A0 ?A1 ?A2 ?Rep4 ?Rep5 ?A3 ?Rep6 ?d ?e ?f ?fold ?g ?A4 ?A5 ?Rep7 ?A6 ?Rep8 ?Rep9 ?h ?init ?A7 ?Rep10 ?A8 ?i ?update ?j ?k ?sub ?A9. ?h -> ?g <: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)]` took too many steps and ran out of fuel (5000) //│ ║ l.57: simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -63,9 +63,9 @@ simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ where //│ 'a :> error //│ = [Function: simpleStepImpl] -//│ constrain calls : 5231 -//│ annoying calls : 61 -//│ subtyping calls : 32257 +//│ constrain calls : 5230 +//│ annoying calls : 62 +//│ subtyping calls : 32236 // :ResetFuel // * Note that the above incidentally can be checked using recursive types @@ -75,8 +75,8 @@ simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ res: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)] //│ = [Function: simpleStepImpl] //│ constrain calls : 579 -//│ annoying calls : 101 -//│ subtyping calls : 5641 +//│ annoying calls : 104 +//│ subtyping calls : 5637 :NoRecursiveTypes diff --git a/shared/src/test/diff/fcp/QML_exist_Records.mls b/shared/src/test/diff/fcp/QML_exist_Records.mls index 4df757dc78..16693ec681 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records.mls @@ -207,7 +207,7 @@ stepImpl_ty = stepImpl_Ann_4 // def stepImpl2 (arr: Arrays['a]) = arr stepImpl def stepImpl2 arr = arr stepImpl -//│ stepImpl2: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'j -> 'g -> 'c -> 'b, init: 'f -> 'k, sub: 'm -> 'a -> 'e, update: 'i -> 'l -> 'h -> 'd} -> {fold: 'j -> 'g -> ('c, anything,) -> 'b, init: 'f -> ('k, "hi",), sub: ('m, anything,) -> 'a -> 'e, update: ('i, anything,) -> 'l -> 'h -> ('d, "hey",)}) -> 'n) -> 'n +//│ stepImpl2: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'j -> 'm -> 'a -> 'e, init: 'h -> 'k, sub: 'g -> 'd -> 'b, update: 'l -> 'i -> 'f -> 'c} -> {fold: 'j -> 'm -> ('a, anything,) -> 'e, init: 'h -> ('k, "hi",), sub: ('g, anything,) -> 'd -> 'b, update: ('l, anything,) -> 'i -> 'f -> ('c, "hey",)}) -> 'n) -> 'n //│ = [Function: stepImpl2] def stepImpl2_ arr = arr stepImpl_ty @@ -222,7 +222,7 @@ def stepImpl2_Ann_2 arr = arr stepImpl_Ann_2 //│ = [Function: stepImpl2_Ann_2] def stepImpl2_Ann_3 arr = arr stepImpl_Ann_3 -//│ stepImpl2_Ann_3: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'a -> 'd, sub: 'h -> 'f -> 'g, update: 'b -> 'e -> 'i -> 'c} -> {fold: Fold[nothing, (anything, string,)], init: 'a -> ('d, "hi",), sub: ('h, anything,) -> 'f -> 'g, update: ('b, anything,) -> 'e -> 'i -> ('c, "hey",)}) -> 'j) -> 'j +//│ stepImpl2_Ann_3: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'a -> 'd, sub: 'g -> 'c -> 'i, update: 'b -> 'h -> 'f -> 'e} -> {fold: Fold[nothing, (anything, string,)], init: 'a -> ('d, "hi",), sub: ('g, anything,) -> 'c -> 'i, update: ('b, anything,) -> 'h -> 'f -> ('e, "hey",)}) -> 'j) -> 'j //│ = [Function: stepImpl2_Ann_3] def stepImpl2_Ann_4 arr = arr stepImpl_Ann_4 @@ -249,7 +249,7 @@ def step: Arrays['a] -> Arrays['a] // * But this problem actually disappeared after fixing a subtle bug in type freshening...! :e // * Since "sound extrusion" def step arr f = f (stepImpl2 arr) -//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'g -> 'f -> 'b -> 'i, init: 'h -> 'e, sub: 'k -> 'a -> 'c, update: 'm -> 'j -> 'd -> 'l} -> {fold: 'g -> 'f -> ('b, anything,) -> 'i, init: 'h -> ('e, "hi",), sub: ('k, anything,) -> 'a -> 'c, update: ('m, anything,) -> 'j -> 'd -> ('l, "hey",)}) -> 'n) -> ('n -> 'o) -> 'o +//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'f -> 'k -> 'a -> 'd, init: 'm -> 'j, sub: 'e -> 'l -> 'h, update: 'b -> 'c -> 'i -> 'g} -> {fold: 'f -> 'k -> ('a, anything,) -> 'd, init: 'm -> ('j, "hi",), sub: ('e, anything,) -> 'l -> 'h, update: ('b, anything,) -> 'c -> 'i -> ('g, "hey",)}) -> 'n) -> ('n -> 'o) -> 'o //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -330,7 +330,7 @@ def step arr f = f (stepImpl2_Ann_2 arr) :e def step arr f = f (stepImpl2_Ann_3 arr) -//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'a -> 'g, sub: 'e -> 'b -> 'h, update: 'f -> 'd -> 'c -> 'i} -> {fold: Fold[nothing, (anything, string,)], init: 'a -> ('g, "hi",), sub: ('e, anything,) -> 'b -> 'h, update: ('f, anything,) -> 'd -> 'c -> ('i, "hey",)}) -> 'j) -> ('j -> 'k) -> 'k +//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'f -> 'd, sub: 'b -> 'i -> 'g, update: 'a -> 'c -> 'e -> 'h} -> {fold: Fold[nothing, (anything, string,)], init: 'f -> ('d, "hi",), sub: ('b, anything,) -> 'i -> 'g, update: ('a, anything,) -> 'c -> 'e -> ('h, "hey",)}) -> 'j) -> ('j -> 'k) -> 'k //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition diff --git a/shared/src/test/diff/fcp/SystemF.mls b/shared/src/test/diff/fcp/SystemF.mls index 228b11da0e..72e3f9c073 100644 --- a/shared/src/test/diff/fcp/SystemF.mls +++ b/shared/src/test/diff/fcp/SystemF.mls @@ -145,7 +145,7 @@ iter256() = iter4() (iter4()) def iter256_ty: () -> (forall 'X. ('X -> 'X) -> 'X -> 'X) iter256_ty() = iter4_ty() (iter4_ty()) iter256_ty = iter256 -//│ iter256: () -> ('a -> ('a & 'b) & ('c | 'b) -> ('a & 'c)) -> 'a -> 'c +//│ iter256: () -> ('a -> ('a & 'b) & ('b | 'c) -> ('a & 'c)) -> 'a -> 'c //│ where //│ 'a :> 'c //│ = [Function: iter256] @@ -155,7 +155,7 @@ iter256_ty = iter256 //│ <: iter256_ty: //│ () -> (forall 'X. ('X -> 'X) -> 'X -> 'X) //│ = [Function: iter256_ty] -//│ () -> ('a -> ('a & 'b) & ('c | 'b) -> ('a & 'c)) -> 'a -> 'c +//│ () -> ('a -> ('a & 'b) & ('b | 'c) -> ('a & 'c)) -> 'a -> 'c //│ where //│ 'a :> 'c //│ <: iter256_ty: diff --git a/shared/src/test/diff/fcp/SystemF_2.mls b/shared/src/test/diff/fcp/SystemF_2.mls index 332c15e0c5..18c18c73a3 100644 --- a/shared/src/test/diff/fcp/SystemF_2.mls +++ b/shared/src/test/diff/fcp/SystemF_2.mls @@ -145,17 +145,17 @@ iter2 f x = f(f x) iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'e -> 'd +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where -//│ 'c <: 'e -> 'f & 'f -> 'd) <: 'a -> 'g & 'g -> 'b +//│ 'c <: 'd -> 'e & 'e -> 'f) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] id iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'f -> 'e //│ where -//│ 'c <: 'd -> 'e & 'e -> 'f) <: 'a -> 'g & 'g -> 'b +//│ 'c <: 'f -> 'd & 'd -> 'e) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] @@ -207,8 +207,8 @@ def succ: (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X. ('X -> 'X) -> 'X -> succ = succ_ //│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'd -> 'e)) //│ <: succ: //│ (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X0. ('X0 -> 'X0) -> 'X0 -> 'X0) //│ ╔══[ERROR] Type error in def definition @@ -243,13 +243,13 @@ c2 c2 K //│ = [Function (anonymous)] c2_ = succ_ (succ_ n0) -//│ c2_: 'a -> (forall 'b 'c 'd. 'c -> 'b +//│ c2_: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'g -> 'f //│ where -//│ 'e <: 'g -> 'h -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'f -> 'g) <: 'a -> 'c -> 'd -//│ 'a <: 'd -> 'b) +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'g -> 'h +//│ 'e <: 'h -> 'f) <: 'a -> 'b -> 'c +//│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] c2_ c2_ @@ -257,21 +257,21 @@ c2_ c2_ //│ where //│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f) <: 'k -> 'b -//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'c -> 'd -> 'e +//│ 'c <: 'e -> 'f) <: (forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n -//│ 'l <: 'n -> 'o) <: (forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ 'g <: 'i -> 'j +//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n +//│ where +//│ 'k <: 'm -> 'n +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm) <: 'g -> 'h -> 'i)) -> 'a -> 'o +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ 'g <: 'i -> 'j +//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n //│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f)) -> 'a -> 'k +//│ 'k <: 'm -> 'n +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm) <: 'g -> 'h -> 'i) <: 'o -> 'b //│ = [Function (anonymous)] c2_ c2_ K @@ -279,39 +279,39 @@ c2_ c2_ K //│ where //│ forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'f <: 'd -> 'e -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ forall 'f. 'f -> (forall 'g 'h 'i. 'g -> 'i //│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'f -> 'c -> 'd <: 'k -> 'b +//│ 'f <: 'h -> 'i +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'g -> 'h) <: 'j -> 'c -> 'd +//│ 'j <: 'd -> 'e <: 'k -> 'b //│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n -//│ 'l <: 'n -> 'o) <: (forall 'c 'd 'e. 'c -> 'e +//│ 'l <: 'n -> 'o +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n) <: (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'f <: 'd -> 'e -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ forall 'f. 'f -> (forall 'g 'h 'i. 'g -> 'i //│ where -//│ 'g <: 'i -> 'j -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'g -> 'h -> 'i) <: 'f -> 'c -> 'd) -> 'a -> 'k +//│ 'f <: 'h -> 'i +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'g -> 'h) <: 'j -> 'c -> 'd +//│ 'j <: 'd -> 'e) -> 'a -> 'k //│ where -//│ 'f :> forall 'p 'q 'r 's. ('p & 's) -> (anything -> 's | 'r) +//│ 'j :> forall 'p 'q 'r 's. ('p & 's) -> (anything -> 's | 'r) //│ where -//│ 'f <: 'q -> 'r +//│ 'j <: 'q -> 'r //│ forall 't. 't -> (forall 'u 'v 'w. 'u -> 'w //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'u -> 'v -//│ 't <: 'v -> 'w) <: 'f -> 'p -> 'q +//│ 't <: 'v -> 'w +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'u -> 'v) <: 'j -> 'p -> 'q //│ = [Function (anonymous)] c2__ = succ_ (succ_ n0_) -//│ c2__: 'a -> (forall 'b 'c 'd. 'b -> 'd +//│ c2__: 'a -> (forall 'b 'c 'd. 'c -> 'b //│ where -//│ 'a <: 'c -> 'd //│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h //│ where -//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g -//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c) +//│ 'e <: 'g -> 'h +//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g) <: 'a -> 'c -> 'd +//│ 'a <: 'd -> 'b) //│ = [Function (anonymous)] c2__ c2__ @@ -319,43 +319,43 @@ c2__ c2__ //│ where //│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j -//│ where -//│ 'g <: 'i -> 'j -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f) <: 'l -> 'b -//│ forall 'm. 'm -> (forall 'n 'o 'p. 'p -> 'o +//│ 'c <: 'e -> 'f +//│ anything -> (forall 'g. 'g -> 'g) <: 'c -> 'd -> 'e) <: (forall 'h. 'h -> (forall 'i 'j 'k. 'i -> 'k //│ where -//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'p -> 'n -//│ 'm <: 'n -> 'o) <: (forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ 'h <: 'j -> 'k +//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o +//│ where +//│ 'l <: 'n -> 'o +//│ anything -> (forall 'g. 'g -> 'g) <: 'l -> 'm -> 'n) <: 'h -> 'i -> 'j)) -> 'a -> 'p +//│ forall 'h. 'h -> (forall 'i 'j 'k. 'i -> 'k //│ where -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ 'h <: 'j -> 'k +//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o //│ where -//│ 'g <: 'i -> 'j -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f)) -> 'a -> 'l +//│ 'l <: 'n -> 'o +//│ anything -> (forall 'g. 'g -> 'g) <: 'l -> 'm -> 'n) <: 'h -> 'i -> 'j) <: 'p -> 'b //│ = [Function (anonymous)] c2__ c2__ K //│ res: 'a -> 'b //│ where -//│ forall 'c 'd 'e. 'c -> 'e +//│ forall 'c 'd 'e. 'd -> 'c //│ where -//│ forall 'f. 'f -> anything -> 'f <: 'd -> 'e +//│ forall 'f. 'f -> anything -> 'f <: 'e -> 'c //│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where //│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i -//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'c -> 'd <: 'l -> 'b +//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'd -> 'e <: 'l -> 'b //│ forall 'm. 'm -> (forall 'n 'o 'p. 'n -> 'p //│ where //│ 'm <: 'o -> 'p -//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'n -> 'o) <: (forall 'c 'd 'e. 'c -> 'e +//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'n -> 'o) <: (forall 'c 'd 'e. 'd -> 'c //│ where -//│ forall 'f. 'f -> anything -> 'f <: 'd -> 'e +//│ forall 'f. 'f -> anything -> 'f <: 'e -> 'c //│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where //│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i -//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'c -> 'd) -> 'a -> 'l +//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'd -> 'e) -> 'a -> 'l //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls index 112f78e7fc..f2c1ff1bcc 100644 --- a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls +++ b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls @@ -48,9 +48,9 @@ s :e // * Since "sound extrusion" succ = s -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd. 'd -> 'c +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd. 'c -> 'd //│ where -//│ 'a <: 'b -> 'd -> 'c)) +//│ 'a <: 'b -> 'c -> 'd)) //│ <: succ: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -105,9 +105,9 @@ def succ_min : (forall 'N. ('N -> 'N)) -> (forall 'M. ('M -> 'M)) :e // * Since "sound extrusion" succ_min n f = n f -//│ 'a -> (forall 'b 'c. 'c -> 'b +//│ 'a -> (forall 'b 'c. 'b -> 'c //│ where -//│ 'a <: 'c -> 'b) +//│ 'a <: 'b -> 'c) //│ <: succ_min: //│ (forall 'N. 'N -> 'N) -> (forall 'M. 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -150,7 +150,7 @@ to_church = to_ch //│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?to_ch. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) //│ ║ l.145: to_church = to_ch //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -178,7 +178,7 @@ to_church = to_ch //│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch ?a ?b ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?to_ch ?b ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) //│ ║ l.173: to_church = to_ch //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -236,9 +236,9 @@ def to_ch n = :e // * Since "sound extrusion" to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd. ('b & 'd) -> ('d | 'c) +//│ int -> (forall 'a. 'a -> (forall 'b 'a 'c 'd. ('c & 'b) -> ('b | 'd) //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'c -> 'd)) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -541,9 +541,9 @@ to_church = to_ch //│ where //│ 'd <: 'a -> 'b -> 'c) //│ where -//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) +//│ 'd :> forall 'e 'f 'g 'h. 'g -> (('f & 'h) -> ('f | 'e) //│ where -//│ 'd <: 'e -> 'f -> 'g) +//│ 'd <: 'g -> 'h -> 'e) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) @@ -575,7 +575,7 @@ to_church = to_ch //│ 'd <: 'e -> 'f -> 'g) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch ?a ?b ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) //│ ║ l.568: to_church = to_ch //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls b/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls index 5aaf5cf478..5ab48ba9f4 100644 --- a/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls +++ b/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls @@ -37,13 +37,13 @@ def s n f x = (n f x) :ns s -//│ res: forall 'a 'b 'c 'd 'e. 'd -> (forall 'f. 'f -> (forall 'g 'h. 'g -> 'h)) +//│ res: forall 'a 'b 'c 'd 'e. 'e -> (forall 'f. 'f -> (forall 'g 'h. 'g -> 'h)) //│ where -//│ 'h :> 'a +//│ 'h :> 'b //│ 'g <: 'c -//│ 'f <: 'b -//│ 'd <: 'b -> 'e -//│ 'e <: 'c -> 'a +//│ 'f <: 'a +//│ 'e <: 'a -> 'd +//│ 'd <: 'c -> 'b //│ = [Function: s] :e // * Works with CT diff --git a/shared/src/test/diff/fcp/Vec.mls b/shared/src/test/diff/fcp/Vec.mls index 3af0b8adae..f88aeb0b40 100644 --- a/shared/src/test/diff/fcp/Vec.mls +++ b/shared/src/test/diff/fcp/Vec.mls @@ -353,7 +353,7 @@ sum_ty = sum //│ 'a <: (((Cons[?, ?]\size with {head: int, tail: 'a}) | Nil) -> int) -> (int & 'b) //│ <: sum_ty: //│ Vec[int, 'n] -> int -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?tail ?c ?sum. ?sum <: forall 'n. Vec[int, 'n] -> int` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?tail ?a ?b ?c ?sum. ?sum <: forall 'n. Vec[int, 'n] -> int` exceeded recursion depth limit (250) //│ ║ l.350: sum_ty = sum //│ ║ ^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -364,7 +364,7 @@ sum nil // * Note: also worked woth top/bot extrusion sum v1_0 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?tail ?sum ?c. ?sum <: (forall ?P ?A ?head 'n 'a ?N ?d. ?d) -> ?e` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?sum ?tail ?b ?c. ?sum <: (forall 'a ?P ?d 'n ?N ?A ?head. ?d) -> ?e` exceeded recursion depth limit (250) //│ ║ l.366: sum v1_0 //│ ║ ^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -372,7 +372,7 @@ sum v1_0 // * Note: also worked woth top/bot extrusion sum v2 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?sum ?c ?tail. ?sum <: (forall 'p ?N ?head 'p0 'p1 'p2 ?A 'p3 ?d 'n 'p4 'p5 'a 'p6 ?P. ?d) -> ?e` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?tail ?c ?sum. ?sum <: (forall ?A 'p 'p0 'p1 ?N 'p2 'p3 ?d 'a ?P 'p4 'p5 ?head 'p6 'n. ?d) -> ?e` exceeded recursion depth limit (250) //│ ║ l.374: sum v2 //│ ║ ^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -419,7 +419,7 @@ sum v1_ty //│ ╟── type `Cons[int, Z]` is not a function //│ ║ l.198: v1_ty = v1_ : Cons[int, Z] //│ ║ ^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `(forall ?head ?a ?b ?tail ?c ?d. ?b -> ?a) -> ?e` +//│ ╟── but it flows into reference with expected type `(forall ?a ?tail ?b ?c ?d ?head. ?d -> ?a) -> ?e` //│ ║ l.+1: sum v1_ty //│ ║ ^^^^^ //│ ╟── Note: constraint arises from application: diff --git a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls index abe6093d35..2f1ca425c9 100644 --- a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls +++ b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls @@ -523,14 +523,14 @@ def succ (n: ChurchInt) = fun f -> fun x -> f (n f x) def succ' n = fun f -> fun x -> f (n f x) //│ succ_ty: ChurchInt -> ChurchInt //│ = -//│ succ: ChurchInt -> (forall 'b. 'b -> (forall 'a 'c. 'a -> 'c +//│ succ: ChurchInt -> (forall 'b. 'b -> (forall 'c 'a. 'a -> 'c //│ where //│ 'b <: 'a -> 'a & 'a -> 'c)) //│ = [Function: succ1] //│ succ': 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'd -> 'e)) //│ = [Function: succ$1] // * Note: without constrained types we wouldn't get the principal type of succ' @@ -573,8 +573,8 @@ succ_ty = succ' succ_ty = succ' //│ 'a -> 'b -> ('c -> 'd //│ where -//│ 'b <: 'e -> 'd -//│ 'a <: 'b -> 'c -> 'e) +//│ 'a <: 'b -> 'c -> 'e +//│ 'b <: 'e -> 'd) //│ <: succ_ty: //│ ChurchInt -> ChurchInt //│ = [Function: succ$1] @@ -583,16 +583,16 @@ succ_ty = succ' succ' //│ res: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'd -> 'e)) //│ = [Function: succ$1] // :e // * Error delayed by inconsistent constrained types succ' {} -//│ res: 'a -> (forall 'b 'c 'd. 'b -> 'd +//│ res: 'a -> (forall 'b 'c 'd. 'c -> 'b //│ where -//│ 'a <: 'c -> 'd -//│ anything <: 'a -> 'b -> 'c) +//│ anything <: 'a -> 'c -> 'd +//│ 'a <: 'd -> 'b) //│ = [Function (anonymous)] // :e // * Error delayed by inconsistent constrained types diff --git a/shared/src/test/diff/mlf-examples/ex_demo.mls b/shared/src/test/diff/mlf-examples/ex_demo.mls index 773a09261f..9966a8c063 100644 --- a/shared/src/test/diff/mlf-examples/ex_demo.mls +++ b/shared/src/test/diff/mlf-examples/ex_demo.mls @@ -365,17 +365,17 @@ id1 id1 id1 //│ res: forall 'a 'b 'c 'id1 'd 'e. 'id1 //│ where -//│ 'id1 := 'e -> 'b -//│ 'e :> 'e -> 'b +//│ 'id1 := 'e -> 'c +//│ 'e :> 'e -> 'c +//│ <: 'a +//│ 'c :> 'e -> 'c +//│ <: 'b & 'd +//│ 'd :> 'e -> 'c +//│ <: 'e -> 'b +//│ 'b :> 'e -> 'c +//│ <: 'a +//│ 'a :> 'e -> 'c //│ <: 'c -//│ 'b :> 'e -> 'b -//│ <: 'a & 'd -//│ 'd :> 'e -> 'b -//│ <: 'e -> 'a -//│ 'a :> 'e -> 'b -//│ <: 'c -//│ 'c :> 'e -> 'b -//│ <: 'b //│ = [Function: id13] :e @@ -476,7 +476,7 @@ ex_list1 = cons (make_ex1 (("A String", print_string))) ex_list2 = cons (make_ex2 (("String", "String", eqstring))) (cons (make_ex2 ((1250, 4890, eqint))) (cons (make_ex2 ((true, false, eqbool))) nil)) -//│ ex_list2: List[forall 'b. (forall 'a 'a0 'a1. ('a0, 'a0, 'a0 -> 'a0 -> bool,) -> 'b & ('a1, 'a1, 'a1 -> 'a1 -> (bool | false),) -> 'b & ('a, 'a, 'a -> 'a -> bool,) -> 'b) -> 'b] +//│ ex_list2: List[forall 'b. (forall 'a 'a0 'a1. ('a, 'a, 'a -> 'a -> bool,) -> 'b & ('a0, 'a0, 'a0 -> 'a0 -> (bool | false),) -> 'b & ('a1, 'a1, 'a1 -> 'a1 -> bool,) -> 'b) -> 'b] //│ = Cons { //│ head: [Function (anonymous)], //│ tail: Cons { @@ -487,7 +487,7 @@ ex_list2 = cons (make_ex2 (("String", "String", eqstring))) h = head ex_list1 -//│ h: (forall 'a 'a0 'a1. ('a, 'a -> unit,) -> 'b & ('a0, 'a0 -> unit,) -> 'b & ('a1, 'a1 -> unit,) -> 'b) -> 'b +//│ h: (forall 'a 'a0 'a1. ('a1, 'a1 -> unit,) -> 'b & ('a, 'a -> unit,) -> 'b & ('a0, 'a0 -> unit,) -> 'b) -> 'b //│ = [Function (anonymous)] h (fun ((x, f)) -> f x) @@ -876,7 +876,7 @@ def c_add n (m: Fint) = m c_succ n //│ = [Function: c_add] def c_add_ n m = m c_succ_ n -//│ c_add_: 'a -> (forall 'b. ((forall 'c 'd 'e. ('c -> 'd -> 'e) -> (forall 'f. ('f -> 'd & 'c) -> 'f -> 'e)) -> 'a -> 'b) -> 'b) +//│ c_add_: 'a -> (forall 'b. ((forall 'c 'd 'e. ('e -> 'c -> 'd) -> (forall 'f. ('f -> 'c & 'e) -> 'f -> 'd)) -> 'a -> 'b) -> 'b) //│ = [Function: c_add_] // let c_mul n (m:Int) = m (c_add n) c_i0 @@ -894,7 +894,7 @@ def c_mul_ m n = m (c_add_ n) c_i0 // :e // due to tapping def c_pow m (n: Fint) = m (c_mul n) c_i1 -//│ c_pow: ((Fint -> (forall 'a 'a0. ('a0 -> ('a0 & 'a)) -> (forall 'b. ('a0 & 'b) -> ('a | 'b)) | Fint)) -> (forall 'c 'd. ('c -> 'd) -> 'c -> 'd) -> 'e) -> Fint -> 'e +//│ c_pow: ((Fint -> (forall 'a 'a0. ('a -> ('a & 'a0)) -> (forall 'b. ('a & 'b) -> ('a0 | 'b)) | Fint)) -> (forall 'c 'd. ('c -> 'd) -> 'c -> 'd) -> 'e) -> Fint -> 'e //│ = [Function: c_pow] def c_pow_ m n = m (c_mul_ n) c_i1 @@ -918,7 +918,7 @@ def c_pred_ n = let s = fun p -> c_pair (c_2_2_ p) (c_succ_ (c_2_2_ p)) in let z = c_pair c_i0 c_i0 in c_1_2_ (n s z) -//│ c_pred_: ((forall 'a 'b 'c 'd. ((anything -> (forall 'e. 'e -> 'e)) -> ('a -> 'b -> 'c & 'd)) -> (forall 'f. ('d -> (forall 'g. ('g -> 'b & 'a) -> 'g -> 'c) -> 'f) -> 'f)) -> (forall 'h. ((anything -> (forall 'i. 'i -> 'i)) -> (anything -> (forall 'i. 'i -> 'i)) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k +//│ c_pred_: ((forall 'a 'b 'c 'd. ((anything -> (forall 'e. 'e -> 'e)) -> ('d -> 'a -> 'b & 'c)) -> (forall 'f. ('c -> (forall 'g. ('g -> 'a & 'd) -> 'g -> 'b) -> 'f) -> 'f)) -> (forall 'h. ((anything -> (forall 'i. 'i -> 'i)) -> (anything -> (forall 'i. 'i -> 'i)) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k //│ = [Function: c_pred_] @@ -1036,7 +1036,7 @@ rec def c_fact_ n = (fun _ -> c_mul_ n (c_fact_ (c_pred_ n))) //│ c_fact_: 'a -> 'b //│ where -//│ 'a <: (anything -> anything -> (forall 'c. ((forall 'd. 'd -> 'd) -> 'c) -> 'c)) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (anything -> (forall 'f 'g. ('f -> 'g) -> 'f -> 'g)) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l. ('j -> 'k -> 'l) -> (forall 'm. ('m -> 'k & 'j) -> 'm -> 'l)) -> 'b -> 'i) -> 'i) -> (anything -> (forall 'n. 'n -> 'n)) -> 'h & (forall 'o 'p 'q 'r. ((anything -> (forall 's. 's -> 's)) -> ('o -> 'p -> 'q & 'r)) -> (forall 't. ('r -> (forall 'u. ('u -> 'p & 'o) -> 'u -> 'q) -> 't) -> 't)) -> (forall 'v. ((anything -> (forall 'n. 'n -> 'n)) -> (anything -> (forall 'n. 'n -> 'n)) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a +//│ 'a <: (anything -> anything -> (forall 'c. ((forall 'd. 'd -> 'd) -> 'c) -> 'c)) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (anything -> (forall 'f 'g. ('f -> 'g) -> 'f -> 'g)) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l. ('l -> 'j -> 'k) -> (forall 'm. ('m -> 'j & 'l) -> 'm -> 'k)) -> 'b -> 'i) -> 'i) -> (anything -> (forall 'n. 'n -> 'n)) -> 'h & (forall 'o 'p 'q 'r. ((anything -> (forall 's. 's -> 's)) -> ('o -> 'p -> 'q & 'r)) -> (forall 't. ('r -> (forall 'u. ('u -> 'p & 'o) -> 'u -> 'q) -> 't) -> 't)) -> (forall 'v. ((anything -> (forall 'n. 'n -> 'n)) -> (anything -> (forall 'n. 'n -> 'n)) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a //│ = [Function: c_fact_] @@ -1146,7 +1146,7 @@ this_should_be_98_ = //│ ║ l.1140: let c_i10_ = c_mul_ c_i5_ c_i2_ in //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?e ?f. ?c -> ?e <: (forall ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?a1 ?b1 ?c1 ?d1 ?e1 ?f1 ?g1 ?h1 ?i1 ?j1 ?k1 ?l1 ?m1 ?n1 ?o1 ?p1 ?q1 ?r1 ?s1 ?t1 ?u1 ?v1 ?w1 ?x1 ?y1 ?z1 ?a2 ?b2 ?c2 ?d2 ?e2 ?f2 ?g2 'a ?h2 ?i2 ?j2 ?k2 ?l2 ?m2 ?n2 ?o2 ?p2 ?q2 ?r2 ?s2 ?t2 ?u2 ?v2 ?w2 ?x2 ?y2 ?z2 ?a3 ?b3 ?c3 ?d3 ?e3 ?f3 ?g3 ?h3 ?i3 ?j3 ?k3 ?l3 ?m3 ?n3 ?o3 ?p3 ?q3 ?r3 ?s3 ?t3 ?u3 ?v3 ?w3 ?x3 ?y3 ?z3 ?a4 ?b4 ?c4 ?d4 ?e4 ?f4 ?g4 ?h4 ?i4 ?j4 ?k4 ?l4 ?m4 ?n4 ?o4 ?p4 ?q4 ?r4 ?s4 ?t4 ?u4 ?v4 ?w4 ?x4 ?y4 ?z4 ?a5 ?b5 ?c5 ?d5 ?e5 ?f5 ?g5 ?h5 ?i5 ?j5 ?k5 ?l5 ?m5 ?n5 ?o5 ?p5 ?q5 ?r5 ?s5 ?t5 ?u5 ?v5 ?w5 ?x5 ?y5 ?z5 ?a6 ?b6 ?c6 ?d6 ?e6 ?f6 ?g6 ?h6 ?i6 ?j6 ?k6 ?l6 ?m6 ?n6 ?o6 ?p6 ?q6 ?r6 ?s6 ?t6 ?u6 ?v6 ?w6 ?x6 ?y6 ?z6 ?a7 ?b7 ?c7 ?d7 ?e7 ?f7 ?g7 ?h7 ?i7 ?j7 ?k7 ?l7 ?m7 ?n7 ?o7 ?p7 ?q7 ?r7 ?s7 ?t7 ?u7 ?v7 ?w7 ?x7 ?y7 ?z7 ?a8 ?b8 ?c8 ?d8 ?e8 ?f8 ?g8 ?h8 ?i8 ?j8 ?k8 ?l8 ?m8 ?n8 ?o8 ?p8 ?q8 ?r8 ?s8 ?t8 ?u8 ?v8 ?w8 ?x8 ?y8 ?z8 ?a9 ?b9 ?c9 ?d9 ?e9 ?f9 ?g9 ?h9 ?i9 ?j9 ?k9 ?l9 ?m9 ?n9 ?o9 ?p9 ?q9 ?r9 ?s9 ?t9 ?u9 ?v9 ?w9 ?x9 ?y9 ?z9 'a0 ?a10 ?b10 ?c10 ?d10 ?e10 ?f10 ?g10 ?h10 ?i10 ?j10 ?k10 ?l10 ?m10. ?p7) -> ?n10` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?e ?f. ?d -> ?f <: (forall ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?a1 ?b1 ?c1 ?d1 ?e1 ?f1 ?g1 ?h1 ?i1 ?j1 ?k1 ?l1 ?m1 ?n1 ?o1 ?p1 ?q1 ?r1 ?s1 ?t1 ?u1 ?v1 ?w1 ?x1 ?y1 ?z1 ?a2 ?b2 ?c2 ?d2 ?e2 ?f2 ?g2 ?h2 ?i2 ?j2 ?k2 ?l2 ?m2 ?n2 ?o2 ?p2 ?q2 ?r2 ?s2 ?t2 ?u2 ?v2 ?w2 ?x2 ?y2 ?z2 ?a3 ?b3 ?c3 ?d3 ?e3 ?f3 ?g3 ?h3 ?i3 ?j3 ?k3 ?l3 ?m3 ?n3 ?o3 ?p3 ?q3 ?r3 ?s3 ?t3 ?u3 ?v3 ?w3 ?x3 ?y3 ?z3 ?a4 ?b4 ?c4 ?d4 ?e4 ?f4 ?g4 ?h4 ?i4 ?j4 ?k4 ?l4 ?m4 ?n4 ?o4 ?p4 ?q4 ?r4 ?s4 ?t4 ?u4 ?v4 ?w4 ?x4 ?y4 ?z4 ?a5 ?b5 ?c5 ?d5 ?e5 ?f5 ?g5 ?h5 ?i5 ?j5 ?k5 ?l5 ?m5 ?n5 ?o5 ?p5 ?q5 ?r5 ?s5 ?t5 ?u5 ?v5 ?w5 ?x5 ?y5 ?z5 ?a6 ?b6 ?c6 ?d6 ?e6 ?f6 ?g6 ?h6 ?i6 ?j6 ?k6 ?l6 ?m6 ?n6 ?o6 ?p6 ?q6 ?r6 ?s6 ?t6 ?u6 ?v6 ?w6 ?x6 ?y6 ?z6 ?a7 ?b7 ?c7 ?d7 ?e7 ?f7 ?g7 ?h7 ?i7 ?j7 ?k7 ?l7 ?m7 ?n7 ?o7 ?p7 ?q7 ?r7 ?s7 ?t7 ?u7 ?v7 ?w7 ?x7 ?y7 ?z7 ?a8 ?b8 ?c8 ?d8 ?e8 ?f8 ?g8 ?h8 ?i8 'a ?j8 ?k8 ?l8 ?m8 ?n8 ?o8 ?p8 ?q8 ?r8 ?s8 ?t8 ?u8 ?v8 ?w8 ?x8 ?y8 ?z8 ?a9 ?b9 ?c9 ?d9 ?e9 ?f9 ?g9 ?h9 ?i9 ?j9 ?k9 ?l9 'a0 ?m9 ?n9 ?o9 ?p9 ?q9 ?r9 ?s9 ?t9 ?u9 ?v9 ?w9 ?x9 ?y9 ?z9 ?a10 ?b10 ?c10 ?d10 ?e10 ?f10 ?g10 ?h10 ?i10 ?j10 ?k10 ?l10 ?m10. ?b10) -> ?n10` exceeded recursion depth limit (250) //│ ║ l.1141: let c_i9_ = c_pred_ c_i10_ in //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -1175,7 +1175,7 @@ c_i10_ = c_mul_ c_i5_ c_i2_ //│ ╙── Note: use flag `:ex` to see internal error info. //│ c_i10_: ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'p -> 'o & 'q -> 'p & 'r -> 'q & (forall 's. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'p -> 'o & 's -> 'p & 't & 'u & 'v & 'w & 'x & 'y) -> 's -> 'h | 'z) -> ('a1 & 'b1) & (forall 'c1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'c1 -> 'o & 'u & 'v & 'w & 'x & 'y) -> 'c1 -> 'g | 'd1) -> ('e1 -> 'q -> 'i & 'z) & (forall 'f1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'f1 -> 'n & 'v & 'w & 'x & 'y) -> 'f1 -> 'f | 'g1) -> ('t -> 'p -> ('h & 'i) & 'd1) & (forall 'h1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'h1 -> 'm & 'w & 'x & 'y) -> 'h1 -> 'e | 'i1) -> ('u -> 'o -> ('g & 'h & 'i) & 'g1) & (forall 'j1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'j1 -> 'l & 'x & 'y) -> 'j1 -> 'd | 'k1) -> ('v -> 'n -> ('f & 'g & 'h & 'i) & 'i1) & (forall 'l1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l1 -> 'k & 'y) -> 'l1 -> 'c | 'm1) -> ('w -> 'm -> ('e & 'f & 'g & 'h & 'i) & 'k1) & (forall 'n1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'n1 -> 'j) -> 'n1 -> 'b | 'o1) -> ('x -> 'l -> ('d & 'e & 'f & 'g & 'h & 'i) & 'm1) & 'p1 -> ('y -> 'k -> ('c & 'd & 'e & 'f & 'g & 'h & 'i) & 'o1) & 'e1 & 't & 'u & 'v & 'w & 'x & 'y) -> ('r & 'p1) -> (forall 'r. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'p -> 'o & 'q -> 'p & 'r -> 'q & 'e1 & 't & 'u & 'v & 'w & 'x & 'y) -> 'r -> 'i | 'i | 'a1) | error //│ where -//│ 'b1 <: (forall 'q1 'r1 's1. ('q1 -> 'r1 -> 's1) -> (forall 't1. ('t1 -> 'r1 & 'q1) -> 't1 -> 's1)) -> (forall 'u1 'v1 'w1. ('u1 -> 'v1 & 'w1 -> 'u1) -> 'w1 -> 'v1) -> 'b1 +//│ 'b1 <: (forall 'q1 'r1 's1. ('q1 -> 'r1 -> 's1) -> (forall 't1. ('t1 -> 'r1 & 'q1) -> 't1 -> 's1)) -> (forall 'u1 'v1 'w1. ('w1 -> 'u1 & 'v1 -> 'w1) -> 'v1 -> 'u1) -> 'b1 //│ = [Function (anonymous)] //│ constrain calls : 1756 //│ annoying calls : 0 @@ -1301,8 +1301,8 @@ def c_succ_ n = fun f -> fun x -> n f (f x) //│ = [Function: c_succ1] //│ c_succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'e -> 'c)) +//│ 'b <: 'e -> 'c +//│ 'a <: 'b -> 'c -> 'd)) //│ = [Function: c_succ_1] def c_add_ n m = m c_succ_ n @@ -1328,10 +1328,10 @@ def c_i2_ = c_succ_ c_i1 //│ = [Function: c_i22] //│ c_i2_: 'a -> (forall 'b 'c 'd. 'd -> 'c //│ where +//│ 'a <: 'd -> 'b //│ forall 'e. 'e -> (forall 'f 'g. 'f -> 'g //│ where -//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c -//│ 'a <: 'd -> 'b) +//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c) //│ = [Function: c_i2_1] // let c_i3 = c_succ c_i2 @@ -1344,7 +1344,7 @@ def c_i3_ = c_succ_ c_i2 //│ c_i3_: 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where //│ 'b <: 'e -> 'c -//│ forall 'f. 'f -> (forall 'g 'a. 'g -> 'a +//│ forall 'f. 'f -> (forall 'a 'g. 'g -> 'a //│ where //│ 'f <: 'a -> 'a & 'g -> 'a) <: 'b -> 'c -> 'd) //│ = [Function: c_i3_1] @@ -1354,16 +1354,16 @@ def c_i3_ = c_succ_ c_i2 c_i5_ = c_add_ c_i3_ c_i2 //│ c_i5_: 'b //│ where -//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'e -> 'd +//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'f -> 'e //│ where -//│ 'c <: 'e -> 'g & 'e -> 'f -//│ 'b <: 'c -> 'g -> 'd +//│ 'c <: 'f -> 'd & 'f -> 'g //│ forall 'h. 'h -> (forall 'i 'j 'k. 'k -> 'j //│ where +//│ 'h <: 'k -> 'i //│ forall 'l. 'l -> (forall 'a 'm. 'm -> 'a //│ where -//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j -//│ 'h <: 'k -> 'i) <: 'c -> 'f -> 'd) +//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j) <: 'c -> 'g -> 'e +//│ 'b <: 'c -> 'd -> 'e) //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/mlf-examples/ex_hashtbl.mls b/shared/src/test/diff/mlf-examples/ex_hashtbl.mls index 2c0f8def91..7a471c52cf 100644 --- a/shared/src/test/diff/mlf-examples/ex_hashtbl.mls +++ b/shared/src/test/diff/mlf-examples/ex_hashtbl.mls @@ -119,29 +119,29 @@ rec def find table key = :ns find -//│ res: forall 'b 'c 'd 'a 'e 'f 'g 'val 'a0 'h 'a1 'i 'j 'a2 'find 'k 'l. 'find +//│ res: forall 'a 'a0 'b 'c 'val 'd 'e 'a1 'f 'find 'g 'h 'i 'j 'k 'l 'a2. 'find //│ where -//│ 'find := 'l -> 'h -> 'g +//│ 'find := 'b -> 'h -> 'g //│ 'g :> (forall 'm. 'm) | (forall 'n. 'n) +//│ <: 'd +//│ 'd :> (forall 'm. 'm) | (forall 'n. 'n) +//│ <: 'k +//│ 'k :> (forall 'm. 'm) | (forall 'n. 'n) //│ <: 'e //│ 'e :> (forall 'm. 'm) | (forall 'n. 'n) //│ <: 'i //│ 'i :> (forall 'm. 'm) | (forall 'n. 'n) -//│ <: 'c -//│ 'c :> (forall 'm. 'm) | (forall 'n. 'n) -//│ <: 'b -//│ 'b :> (forall 'm. 'm) | (forall 'n. 'n) //│ <: 'g //│ 'n :> #None //│ 'm :> #Some & {val: 'val, Some#a = 'a0} -//│ 'h <: 'k -//│ 'l :> List['a1] -//│ <: List['a1] & List['a2] & List['a] -//│ 'a1 <: 'a & 'a2 +//│ 'h <: 'c +//│ 'b :> List['a] +//│ <: List['a] & List['a2] & List['a1] +//│ 'a <: 'a1 & 'a2 //│ 'a2 <: {_2: 'f} & {_1: 'j} -//│ 'j <: 'k -//│ 'f <: 'd -//│ 'd <: 'val +//│ 'j <: 'c +//│ 'f <: 'l +//│ 'l <: 'val //│ 'val <: 'a0 //│ = [Function: find1] @@ -216,7 +216,7 @@ table = hashtbl_add table "one" (fun f -> fun x -> f x) table = hashtbl_add table "two" (fun f -> fun x -> f (f x)) //│ table: List[nothing] //│ = Nil {} -//│ table: List[("one", forall 'a 'b. ('b -> 'a) -> 'b -> 'a,)] +//│ table: List[("one", forall 'a 'b. ('a -> 'b) -> 'a -> 'b,)] //│ = Cons { head: [ 'one', [Function (anonymous)] ], tail: Nil {} } //│ table: List[("one" | "two", forall 'a 'b 'c. ('a -> 'b & 'b -> 'c & 'a -> 'c) -> 'a -> 'c,)] //│ = Cons { diff --git a/shared/src/test/diff/mlf-examples/ex_predicative.mls b/shared/src/test/diff/mlf-examples/ex_predicative.mls index 9cae3ca6c4..46e13d53a7 100644 --- a/shared/src/test/diff/mlf-examples/ex_predicative.mls +++ b/shared/src/test/diff/mlf-examples/ex_predicative.mls @@ -221,7 +221,7 @@ t id succ 0 :e def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) two -//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b ?c ?d ?e. ?e -> ?b -> ?d) -> ?f` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b ?c ?d ?e. ?b -> ?c -> ?e) -> ?f` exceeded recursion depth limit (250) //│ ║ l.223: def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) two //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -237,29 +237,29 @@ t2 id succ 0 def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) two //│ t2: 'a -> 'b -> ('c -> 'd //│ where -//│ forall 'e 'f 'g. ('e -> 'f & 'f -> 'g) -> 'e -> 'g <: (forall 'h 'i 'j. 'j -> (('h -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm +//│ forall 'e 'f 'g. ('e -> 'f & 'f -> 'g) -> 'e -> 'g <: (forall 'h 'i 'j. 'j -> (('h -> (forall 'k 'l 'm 'n. 'k -> ('l -> 'n //│ where -//│ 'n <: 'l -> 'm -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'i) -> 'i +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'k -> 'l -> 'm +//│ 'k <: 'm -> 'n)) -> 'i) -> 'i //│ where //│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'h)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'r & 's -> 'c -> 'd -//│ forall 't 'u. ((forall 'v. anything -> anything -> 'v -> 'v) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'y 'z 'a1 'b1 'c1. 'b1 -> ('z -> 'c1 +//│ forall 't 'u. ((forall 'v. anything -> anything -> 'v -> 'v) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'y 'z 'a1 'b1 'c1. 'c1 -> ('z -> 'b1 //│ where -//│ 't <: (forall 'd1 'j 'e1. 'j -> (('d1 -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm +//│ 'u <: (forall 'd1 'j 'e1. 'j -> (('d1 -> (forall 'k 'l 'm 'n. 'k -> ('l -> 'n //│ where -//│ 'n <: 'l -> 'm -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'e1) -> 'e1 +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'k -> 'l -> 'm +//│ 'k <: 'm -> 'n)) -> 'e1) -> 'e1 //│ where -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'd1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'y & 'a1 -> 'z -> 'c1 -//│ forall 'f1 'g1. ((forall 'h1. anything -> anything -> 'h1 -> 'h1) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'i1 'j1 'k1 'l1 'm1. 'i1 -> ('l1 -> 'j1 +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'd1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'a1 & 'y -> 'z -> 'b1 +//│ forall 'f1 'g1. ((forall 'h1. anything -> anything -> 'h1 -> 'h1) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'i1 'j1 'k1 'l1 'm1. 'l1 -> ('i1 -> 'k1 //│ where -//│ 'g1 <: (forall 'n1 'j 'o1. 'j -> (('o1 -> (forall 'k 'l 'm 'n. 'n -> ('k -> 'm +//│ 'g1 <: (forall 'n1 'o1 'j. 'j -> (('n1 -> (forall 'k 'l 'm 'n. 'k -> ('l -> 'n //│ where -//│ 'n <: 'l -> 'm -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n -> 'k -> 'l)) -> 'n1) -> 'n1 +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'k -> 'l -> 'm +//│ 'k <: 'm -> 'n)) -> 'o1) -> 'o1 //│ where -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'o1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'm1 & 'k1 -> 'l1 -> 'j1 -//│ anything -> 'a <: 'm1 -> 'i1 -> 'k1)) -> 'f1 & 'g1) -> 'f1 <: 'y -> 'b1 -> 'a1)) -> 'u & 't) -> 'u <: 'r -> 'b -> 's) +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'j1 & 'm1 -> 'i1 -> 'k1 +//│ anything -> 'a <: 'j1 -> 'l1 -> 'm1)) -> 'f1 & 'g1) -> 'f1 <: 'a1 -> 'c1 -> 'y)) -> 't & 'u) -> 't <: 'r -> 'b -> 's) //│ = [Function: t22] :NoConstrainedTypes @@ -311,16 +311,16 @@ def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) //│ ║ l.276: def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) three //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ t2: ('a -> ('b -> 'c & 'd & 'e & 'f)) -> (('a & 'g) -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('k -> 'j -> 'i & 'l)) -> ('l -> (forall 'o. ('i -> 'o & 'k) -> 'j -> 'o) -> 'n) -> ('m -> 'm | 'n) | 'e) -> (forall 'p 'q 'r 's. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'p & 'q & 'r) -> ('r -> 'r | 's | 'p) | 't | 'c | 'u) -> 'b & 'v) & 'b & 't & 'w & 'x) -> ('c | 'u) | error) +//│ t2: ('a -> ('b -> 'c & 'd & 'e & 'f)) -> (('a & 'g) -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> ('k -> 'k | 'j) | 'e) -> (forall 'p 'q 'r 's. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 's) -> ('s -> 's | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v) & 'b & 't & 'w & 'x) -> ('c | 'u) | error) //│ where -//│ 'b :> forall 'y 'q 's 'p 'z. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'p & 'q & 'z) -> ('y -> ('z | 'y) | 's | 'p | 'z) | 'c | 'u +//│ 'b :> forall 'r 'y 'p 'q 'z. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'y) -> ('z -> ('y | 'z) | 'p | 'q | 'y) | 'c | 'u //│ <: (forall 'h. anything -> 'h -> 'h) -> nothing -> nothing -> anything -//│ 'c <: (forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('k -> 'j -> 'i & 'l)) -> ('l -> (forall 'o. ('i -> 'o & 'k) -> 'j -> 'o) -> 'n) -> ('m -> 'm | 'n) | 'e) -> (forall 'p 'q 'a1 's. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'p & 'q & 'a1) -> ('a1 -> 'a1 | 's | 'p) | 't | 'c | 'u) -> 'b & 'v & 'b1) -//│ 'b1 <: (forall 'c1. anything -> anything -> 'c1 -> 'c1) -> (forall 'd1. 'd1 -> anything -> 'd1) -> (forall 'e1 'f1. ('f1 -> 'e1) -> 'f1 -> 'e1) -> ('a -> ('b & 't & 'w) -> 'c) -> 'g -> ((forall 'g1 'h1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'g1 & 'h1) -> (anything -> 'h1 | 'g1) | 'x | 'c | 'u) -> 'i1 & 'i1 -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('k -> 'j -> 'i & 'l)) -> ('l -> (forall 'o. ('i -> 'o & 'k) -> 'j -> 'o) -> 'n) -> ('m -> 'm | 'n) | 'e) -> (forall 'p 'q 'j1 's. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'p & 'q & 'j1) -> ('j1 -> 'j1 | 's | 'p) | 't | 'c | 'u) -> 'b & 'v) & 'u)) & (forall 'i 'j 'k 'l 'n. ((forall 'h. anything -> 'h -> 'h) -> ('k -> 'j -> 'i & 'l)) -> ('l -> (forall 'o. ('i -> 'o & 'k) -> 'j -> 'o) -> 'n) -> 'n) -> (forall 'p. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'p) -> 'p) -> (forall 'd1. 'd1 -> anything -> 'd1) -> anything & 'd -> 'f -//│ 'f <: (forall 'p 'q 'k1 's. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'p & 'q & 'k1) -> ('k1 -> 'k1 | 's | 'p) | 'w | 'c | 'u) -> 'c -//│ 'i1 :> forall 'l1 'q 's. 'q -> ('l1 -> 'l1 | 's) | 'c +//│ 'c <: (forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> ('k -> 'k | 'j) | 'e) -> (forall 'p 'q 'r 'a1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'a1) -> ('a1 -> 'a1 | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v & 'b1) +//│ 'b1 <: (forall 'c1. anything -> anything -> 'c1 -> 'c1) -> (forall 'd1. 'd1 -> anything -> 'd1) -> (forall 'e1 'f1. ('e1 -> 'f1) -> 'e1 -> 'f1) -> ('a -> ('b & 't & 'w) -> 'c) -> 'g -> ((forall 'g1 'h1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'g1 & 'h1) -> (anything -> 'h1 | 'g1) | 'x | 'c | 'u) -> 'i1 & 'i1 -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> ('k -> 'k | 'j) | 'e) -> (forall 'p 'q 'r 'j1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'j1) -> ('j1 -> 'j1 | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v) & 'u)) & (forall 'i 'j 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> 'j) -> (forall 'q. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q) -> 'q) -> (forall 'd1. 'd1 -> anything -> 'd1) -> anything & 'd -> 'f +//│ 'f <: (forall 'p 'q 'r 'k1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'k1) -> ('k1 -> 'k1 | 'p | 'q) | 'w | 'c | 'u) -> 'c +//│ 'i1 :> forall 'p 'l1 'r. 'r -> ('l1 -> 'l1 | 'p) | 'c //│ <: (forall 'h. anything -> 'h -> 'h) -> (nothing -> nothing -> anything & 'b1) & 'b & 't & 'w -//│ 'q <: (forall 'm1 'n1. anything -> 'm1 -> ('n1 -> 'n1 | 'm1) | 'v) -> (forall 'o1. ('b -> 'o1 & 'e) -> ('b & 't) -> 'o1) -> 's +//│ 'r <: (forall 'm1 'n1. anything -> 'm1 -> ('n1 -> 'n1 | 'm1) | 'v) -> (forall 'o1. ('b -> 'o1 & 'e) -> ('b & 't) -> 'o1) -> 'p //│ = [Function: t23] // (* This comment is from the ORIGINAL PAGE: *) diff --git a/shared/src/test/diff/mlf-examples/ex_selfapp.mls b/shared/src/test/diff/mlf-examples/ex_selfapp.mls index cc19e9534b..cf87cc3dcf 100644 --- a/shared/src/test/diff/mlf-examples/ex_selfapp.mls +++ b/shared/src/test/diff/mlf-examples/ex_selfapp.mls @@ -129,7 +129,7 @@ b = error: Baa def build_ = fun g -> g (fun x -> fun xs -> Cons (x, xs)) Nil -//│ build_: ((forall 'b. 'b -> (forall 'a 'tail. (List['a] & 'tail) -> (Cons['a | 'b] with {head: 'b, tail: 'tail}))) -> Nil -> 'c) -> 'c +//│ build_: ((forall 'b. 'b -> (forall 'tail 'a. (List['a] & 'tail) -> (Cons['a | 'b] with {head: 'b, tail: 'tail}))) -> Nil -> 'c) -> 'c //│ = [Function: build_] :e // * Expected: List is a structural equirecursive types and recursive types are disabled @@ -148,7 +148,7 @@ def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun //│ ║ l.146: def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> Cons (x, xs)) Nil //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ build: (forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> ((Cons['a] with {tail: 'tail}) | error | Nil) +//│ build: (forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> ('tail | error) //│ where //│ 'tail :> (Cons['a] with {tail: 'tail}) | Nil //│ = [Function: build] @@ -423,7 +423,7 @@ def k: int -> Baa -> Baa :e def k = fun x -> fun (xs: Baa) -> fun c -> fun n -> c (x + 1) (xs k z c n) -//│ int -> Baa -> (forall 'a 'b. (int -> 'a -> 'b) -> 'a -> 'b) +//│ int -> Baa -> (forall 'a 'b. (int -> 'b -> 'a) -> 'b -> 'a) //│ <: k: //│ int -> Baa -> Baa //│ ╔══[ERROR] Type mismatch in def definition: diff --git a/shared/src/test/diff/mlf-examples/ex_shallow.mls b/shared/src/test/diff/mlf-examples/ex_shallow.mls index 10069fa7fd..765ec7078d 100644 --- a/shared/src/test/diff/mlf-examples/ex_shallow.mls +++ b/shared/src/test/diff/mlf-examples/ex_shallow.mls @@ -324,11 +324,11 @@ def a2_ (x: A1) = //│ = [Function: a31] //│ a2: A1 -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) +//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a21] //│ a2_: A1 -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) +//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a2_1] def a0 = a2 a1 @@ -340,7 +340,7 @@ def a0 = a2 a1 def a0_ = a2_ a1 //│ a0_: anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a +//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a //│ = [Function: a0_1] def a1' = fun f -> fun x -> f (f (either id x)) @@ -357,7 +357,7 @@ def a2' (x: A1') = ) a3 //│ a2': A1' -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('c -> 'd -> 'e) -> ('e -> 'b & 'c) -> 'd -> 'b <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) +//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a2$1] def a2'_ x = @@ -368,9 +368,9 @@ def a2'_ x = ) a3 //│ a2'_: ((forall 'a 'b. ('a -> 'b & 'a) -> 'b) -> (forall 'c. 'c -> 'c) -> anything & (forall 'd. 'd -> (forall 'e. anything -> 'e //│ where -//│ 'd <: (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> 'e)) -> (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> anything) -> (forall 'i. anything -> 'i +//│ 'd <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'e)) -> (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> anything) -> (forall 'i. anything -> 'i //│ where -//│ forall 'j 'k 'l 'm. ('j -> 'k -> 'l) -> ('l -> 'm & 'j) -> 'k -> 'm <: (forall 'f 'g 'h. ('h -> 'f & 'f -> 'g) -> 'h -> 'g) -> 'i) +//│ forall 'j 'k 'l 'm. ('j -> 'k -> 'l) -> ('l -> 'm & 'j) -> 'k -> 'm <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'i) //│ = [Function: a2$_1] :e // * [FCP-LIM] since polymorphic RHS DNF fix @@ -423,7 +423,7 @@ def a0'_ = a2'_ a1' //│ ╙── Note: use flag `:ex` to see internal error info. //│ a0'_: anything -> 'a | error //│ where -//│ forall 'b 'c 'd 'e. ('d -> 'e -> 'b) -> ('b -> 'c & 'd) -> 'e -> 'c <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a +//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a //│ = [Function: a0$_2] // * ^ Strangely, this one works with recursive types: diff --git a/shared/src/test/diff/mlscript/Addable.mls b/shared/src/test/diff/mlscript/Addable.mls index 8ca68b7f49..5f3aac69cc 100644 --- a/shared/src/test/diff/mlscript/Addable.mls +++ b/shared/src/test/diff/mlscript/Addable.mls @@ -183,5 +183,5 @@ class Str_bad_0: Addable[Str_bad_0] & { val: string } //│ ║ l.+2: method Add that = Str_bad_0 { val = this.val + that.val } //│ ╙── ^^^^^^^^ //│ Defined class Str_bad_0 -//│ Defined Str_bad_0.Add: Str_bad_0 -> {val: int} -> (error | (Str_bad_0 with {val: error | int})) +//│ Defined Str_bad_0.Add: Str_bad_0 -> {val: int} -> ((Str_bad_0 with {val: error | int}) | error) diff --git a/shared/src/test/diff/mlscript/Arrays.mls b/shared/src/test/diff/mlscript/Arrays.mls index 75e5c547bf..d1db957f75 100644 --- a/shared/src/test/diff/mlscript/Arrays.mls +++ b/shared/src/test/diff/mlscript/Arrays.mls @@ -40,9 +40,9 @@ ty2B = ty2A //│ MyArray['a] //│ <: ty2B: //│ MyArray[MyArray['a]] -//│ constrain calls : 30 +//│ constrain calls : 26 //│ annoying calls : 23 -//│ subtyping calls : 99 +//│ subtyping calls : 75 @@ -78,9 +78,9 @@ ty3B = ty3A //│ 'a //│ where //│ 'a := MyArray[MyArray['a]] -//│ constrain calls : 84 -//│ annoying calls : 23 -//│ subtyping calls : 253 +//│ constrain calls : 82 +//│ annoying calls : 25 +//│ subtyping calls : 215 :stats ty3A = ty3B @@ -91,9 +91,9 @@ ty3A = ty3B //│ 'a //│ where //│ 'a := MyArray['a] -//│ constrain calls : 84 -//│ annoying calls : 23 -//│ subtyping calls : 253 +//│ constrain calls : 82 +//│ annoying calls : 25 +//│ subtyping calls : 215 def ty4B: MyArray[MyArray[MyArray['a]]] as 'a //│ ty4B: 'a @@ -172,8 +172,8 @@ ty2A = ty2B //│ ╟── Note: constraint arises from applied type reference: //│ ║ l.35: def ty2B: MyArray[MyArray['a]] //│ ╙── ^^^^^^^^^^^ -//│ constrain calls : 27 -//│ annoying calls : 22 -//│ subtyping calls : 140 +//│ constrain calls : 18 +//│ annoying calls : 29 +//│ subtyping calls : 57 diff --git a/shared/src/test/diff/mlscript/Baber.mls b/shared/src/test/diff/mlscript/Baber.mls index 72e740adf8..3058bff92e 100644 --- a/shared/src/test/diff/mlscript/Baber.mls +++ b/shared/src/test/diff/mlscript/Baber.mls @@ -13,11 +13,11 @@ def f e = case e of :ns f -//│ res: forall 'a 'z 'b 'y 'c 'd. 'c -> ('y | 'z | 'd) +//│ res: forall 'y 'z 'a 'b 'c 'd. 'a -> ('y | 'z | 'b) //│ where -//│ 'c <: #Foo & 'a | (#Foo & 'b | 'd & ~#Foo) & ~#Foo -//│ 'b <: {z: 'z} -//│ 'a <: {y: 'y} +//│ 'a <: #Foo & 'c | (#Foo & 'd | 'b & ~#Foo) & ~#Foo +//│ 'd <: {z: 'z} +//│ 'c <: {y: 'y} //│ = [Function: f] class Foo2: Foo[int] & { y: int } diff --git a/shared/src/test/diff/mlscript/BadInherit.mls b/shared/src/test/diff/mlscript/BadInherit.mls index 9b472cb8fa..6e001de84b 100644 --- a/shared/src/test/diff/mlscript/BadInherit.mls +++ b/shared/src/test/diff/mlscript/BadInherit.mls @@ -272,18 +272,33 @@ class Bool //│ Defined class String //│ Defined class Bool +:e "1" : String true : Bool -//│ res: string +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.276: "1" : String +//│ ║ ^^^ +//│ ╟── string literal of type `"1"` is not an instance of type `String` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.276: "1" : String +//│ ╙── ^^^^^^ +//│ res: String //│ = '1' -//│ res: bool +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.277: true : Bool +//│ ║ ^^^^ +//│ ╟── reference of type `true` is not an instance of type `Bool` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.277: true : Bool +//│ ╙── ^^^^ +//│ res: Bool //│ = true :e class Weird: {} | {} //│ ╔══[ERROR] cannot inherit from a type union -//│ ║ l.284: class Weird: {} | {} +//│ ║ l.299: class Weird: {} | {} //│ ╙── ^^^^^^^^^^^^^^ @@ -293,7 +308,7 @@ class A type Id[T] = T class B: Id[A] //│ ╔══[ERROR] cannot inherit from a type alias -//│ ║ l.294: class B: Id[A] +//│ ║ l.309: class B: Id[A] //│ ╙── ^^^^^^^^ //│ Defined class A //│ Defined type alias Id[+T] @@ -305,7 +320,7 @@ class B: Id[A] class Class3A class Class3B: Class3A & 'a //│ ╔══[ERROR] cannot inherit from a polymorphic type -//│ ║ l.306: class Class3B: Class3A & 'a +//│ ║ l.321: class Class3B: Class3A & 'a //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ Defined class Class3A diff --git a/shared/src/test/diff/mlscript/BadMethods.mls b/shared/src/test/diff/mlscript/BadMethods.mls index 9b4bb961da..25dc7eb755 100644 --- a/shared/src/test/diff/mlscript/BadMethods.mls +++ b/shared/src/test/diff/mlscript/BadMethods.mls @@ -550,9 +550,9 @@ t = Dup { x = 42 } :stats t : Dup[bool, int] //│ res: Dup[?, int] -//│ constrain calls : 27 -//│ annoying calls : 19 -//│ subtyping calls : 81 +//│ constrain calls : 25 +//│ annoying calls : 21 +//│ subtyping calls : 70 :stats t : Dup[int, bool] @@ -566,23 +566,23 @@ t : Dup[int, bool] //│ ║ l.558: t : Dup[int, bool] //│ ╙── ^^^^ //│ res: Dup[?, bool] -//│ constrain calls : 41 -//│ annoying calls : 22 -//│ subtyping calls : 120 +//│ constrain calls : 39 +//│ annoying calls : 24 +//│ subtyping calls : 109 :stats t.MthDup (fun x -> mul 2 x) //│ res: int -//│ constrain calls : 74 -//│ annoying calls : 19 -//│ subtyping calls : 227 +//│ constrain calls : 72 +//│ annoying calls : 21 +//│ subtyping calls : 216 :stats t.MthDup id //│ res: 42 -//│ constrain calls : 71 -//│ annoying calls : 18 -//│ subtyping calls : 231 +//│ constrain calls : 69 +//│ annoying calls : 20 +//│ subtyping calls : 220 // We don't currently analyze forward method declarations diff --git a/shared/src/test/diff/mlscript/David2.mls b/shared/src/test/diff/mlscript/David2.mls index 313e3b5e1c..9b25bc4025 100644 --- a/shared/src/test/diff/mlscript/David2.mls +++ b/shared/src/test/diff/mlscript/David2.mls @@ -148,7 +148,7 @@ rec def mkInteger_oops value = Integer { value; addOne = fun n -> mkInteger_oops // * We may still want to retain the precise typing of the `value` part: def mkIntegerPrecise value = Integer { value; addOne = addOne1 } -//│ mkIntegerPrecise: (int & 'value) -> (Integer with {addOne: forall 'a 'b. ((Integer\value with {addOne: 'b -> 'a}) & 'b) -> 'a, value: 'value}) +//│ mkIntegerPrecise: (int & 'value) -> (Integer with {addOne: forall 'a 'b. ((Integer\value with {addOne: 'a -> 'b}) & 'a) -> 'b, value: 'value}) //│ = [Function: mkIntegerPrecise] def mkIntegerPrecise value = Integer { value; addOne = fun n -> mkInteger (n.value + 1) } diff --git a/shared/src/test/diff/mlscript/ExprProb.mls b/shared/src/test/diff/mlscript/ExprProb.mls index d8324473fb..77994518ce 100644 --- a/shared/src/test/diff/mlscript/ExprProb.mls +++ b/shared/src/test/diff/mlscript/ExprProb.mls @@ -50,13 +50,13 @@ rec def eval1_stub e = case e of { | Add -> eval1_stub e.lhs | _ -> 0 } -//│ eval1_stub: forall 'a 'b 'c 'd 'lhs 'eval1_stub 'e. 'eval1_stub +//│ eval1_stub: forall 'a 'b 'c 'eval1_stub 'd 'e 'lhs. 'eval1_stub //│ where -//│ 'eval1_stub := 'b -> (1 | 'e | 0) -//│ 'e :> 1 | 'e | 0 -//│ 'b <: #Lit & 'c | (#Add & 'd | 'a & ~#Add) & ~#Lit -//│ 'd <: {lhs: 'lhs} -//│ 'lhs <: 'b +//│ 'eval1_stub := 'e -> (1 | 'd | 0) +//│ 'd :> 1 | 'd | 0 +//│ 'e <: #Lit & 'a | (#Add & 'b | 'c & ~#Add) & ~#Lit +//│ 'b <: {lhs: 'lhs} +//│ 'lhs <: 'e //│ = [Function: eval1_stub2] eval1_stub @@ -82,18 +82,18 @@ rec def eval1 k e = case e of { :ns eval1 -//│ res: forall 'lhs 'rhs 'a 'b 'val 'c 'd 'e 'eval1 'f 'g. 'eval1 -//│ where -//│ 'eval1 := 'f -> 'g -> ('val | 'b | 'd) -//│ 'b := int -//│ 'g <: #Lit & 'a | (#Add & 'e | 'c & ~#Add) & ~#Lit -//│ 'e <: {rhs: 'rhs} & {lhs: 'lhs} -//│ 'lhs <: 'g -//│ 'rhs <: 'g -//│ 'a <: {val: 'val} +//│ res: forall 'val 'a 'b 'lhs 'eval1 'c 'rhs 'd 'e 'f 'g. 'eval1 +//│ where +//│ 'eval1 := 'c -> 'e -> ('val | 'a | 'g) +//│ 'a := int +//│ 'e <: #Lit & 'b | (#Add & 'd | 'f & ~#Add) & ~#Lit +//│ 'd <: {rhs: 'rhs} & {lhs: 'lhs} +//│ 'lhs <: 'e +//│ 'rhs <: 'e +//│ 'b <: {val: 'val} //│ 'val <: int -//│ 'f <: 'c -> 'd -//│ 'd <: int +//│ 'c <: 'f -> 'g +//│ 'g <: int //│ = [Function: eval1] :re @@ -158,7 +158,7 @@ def eval1_ty_ugly = eval1 :ns def eval1_ty: ('a -> int) -> (Lit | Add['b] | 'a & ~lit & ~add as 'b) -> int -//│ eval1_ty: forall 'b 'a. ('a -> int) -> 'b -> int +//│ eval1_ty: forall 'a 'b. ('a -> int) -> 'b -> int //│ where //│ 'b := Lit | Add['b] | 'a & ~#Lit & ~#Add //│ = diff --git a/shared/src/test/diff/mlscript/ExprProb_Inv.mls b/shared/src/test/diff/mlscript/ExprProb_Inv.mls index e56ae16cc8..0e79410d89 100644 --- a/shared/src/test/diff/mlscript/ExprProb_Inv.mls +++ b/shared/src/test/diff/mlscript/ExprProb_Inv.mls @@ -52,13 +52,13 @@ rec def eval1_stub e = case e of { | Add -> eval1_stub e.lhs | _ -> 0 } -//│ eval1_stub: forall 'a 'b 'c 'd 'lhs 'eval1_stub 'e. 'eval1_stub +//│ eval1_stub: forall 'a 'b 'c 'd 'e 'lhs 'eval1_stub. 'eval1_stub //│ where -//│ 'eval1_stub := 'a -> (1 | 'd | 0) -//│ 'd :> 1 | 'd | 0 -//│ 'a <: #Lit & 'c | (#Add & 'e | 'b & ~#Add) & ~#Lit -//│ 'e <: {lhs: 'lhs} -//│ 'lhs <: 'a +//│ 'eval1_stub := 'd -> (1 | 'e | 0) +//│ 'e :> 1 | 'e | 0 +//│ 'd <: #Lit & 'b | (#Add & 'a | 'c & ~#Add) & ~#Lit +//│ 'a <: {lhs: 'lhs} +//│ 'lhs <: 'd //│ = [Function: eval1_stub2] eval1_stub @@ -84,18 +84,18 @@ rec def eval1 k e = case e of { :ns eval1 -//│ res: forall 'a 'lhs 'b 'c 'eval1 'd 'val 'rhs 'e 'f 'g. 'eval1 +//│ res: forall 'eval1 'a 'b 'rhs 'c 'lhs 'd 'e 'f 'val 'g. 'eval1 //│ where -//│ 'eval1 := 'e -> 'b -> ('val | 'f | 'd) +//│ 'eval1 := 'e -> 'c -> ('val | 'f | 'g) //│ 'f := int -//│ 'b <: #Lit & 'a | (#Add & 'c | 'g & ~#Add) & ~#Lit -//│ 'c <: {rhs: 'rhs} & {lhs: 'lhs} -//│ 'lhs <: 'b -//│ 'rhs <: 'b -//│ 'a <: {val: 'val} +//│ 'c <: #Lit & 'b | (#Add & 'd | 'a & ~#Add) & ~#Lit +//│ 'd <: {rhs: 'rhs} & {lhs: 'lhs} +//│ 'lhs <: 'c +//│ 'rhs <: 'c +//│ 'b <: {val: 'val} //│ 'val <: int -//│ 'e <: 'g -> 'd -//│ 'd <: int +//│ 'e <: 'a -> 'g +//│ 'g <: int //│ = [Function: eval1] :re diff --git a/shared/src/test/diff/mlscript/GenericClasses.mls b/shared/src/test/diff/mlscript/GenericClasses.mls index 3ffc3a588c..dd7613bbd2 100644 --- a/shared/src/test/diff/mlscript/GenericClasses.mls +++ b/shared/src/test/diff/mlscript/GenericClasses.mls @@ -33,9 +33,9 @@ res.value //│ ╔══[ERROR] Type mismatch in field selection: //│ ║ l.32: res.value //│ ║ ^^^^^^^^^ -//│ ╟── type `None` does not have field 'value' -//│ ║ l.21: type Option[A] = Some[A] | None -//│ ║ ^^^^ +//│ ╟── type `Option[int]` does not have field 'value' +//│ ║ l.25: Some 42 : Option[int] +//│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{value: ?value}` //│ ║ l.32: res.value //│ ╙── ^^^ diff --git a/shared/src/test/diff/mlscript/HeadOption.mls b/shared/src/test/diff/mlscript/HeadOption.mls index e4cc007d18..52a56e055d 100644 --- a/shared/src/test/diff/mlscript/HeadOption.mls +++ b/shared/src/test/diff/mlscript/HeadOption.mls @@ -58,58 +58,58 @@ class Cons[A]: List[A] & { head: A; tail: List[A] } :stats l0 = Cons { head = 1; tail = Nil {} } //│ l0: Cons[1] with {tail: Nil[?]} -//│ constrain calls : 25 -//│ annoying calls : 0 -//│ subtyping calls : 89 +//│ constrain calls : 24 +//│ annoying calls : 1 +//│ subtyping calls : 90 :stats Cons.HeadOption l0 //│ res: Some[1] -//│ constrain calls : 49 -//│ annoying calls : 18 -//│ subtyping calls : 151 +//│ constrain calls : 48 +//│ annoying calls : 22 +//│ subtyping calls : 157 :stats l1 = Cons { head = 1; tail = Cons { head = 2; tail = Cons { head = 3; tail = Nil {} } } } //│ l1: Cons[1] with {tail: Cons[2] with {tail: Cons[3] with {tail: Nil[?]}}} -//│ constrain calls : 55 -//│ annoying calls : 0 -//│ subtyping calls : 257 +//│ constrain calls : 54 +//│ annoying calls : 1 +//│ subtyping calls : 258 :stats Cons.HeadOption l1 //│ res: Some[1] //│ constrain calls : 45 -//│ annoying calls : 18 -//│ subtyping calls : 154 +//│ annoying calls : 21 +//│ subtyping calls : 159 :stats l2 = Cons { head = 0; tail = l1 } //│ l2: Cons[0] with {tail: Cons[1] with {tail: Cons[2] with {tail: Cons[3] with {tail: Nil[?]}}}} //│ constrain calls : 20 -//│ annoying calls : 0 +//│ annoying calls : 1 //│ subtyping calls : 181 :stats Cons.HeadOption l2 //│ res: Some[0] //│ constrain calls : 51 -//│ annoying calls : 18 -//│ subtyping calls : 155 +//│ annoying calls : 22 +//│ subtyping calls : 160 :stats l3 = Cons { head = 0-1; tail = l2 } //│ l3: Cons[int] with {tail: Cons[0] with {tail: Cons[1] with {tail: Cons[2] with {tail: Cons[3] with {tail: Nil[?]}}}}} //│ constrain calls : 34 -//│ annoying calls : 0 +//│ annoying calls : 1 //│ subtyping calls : 268 :stats Cons.HeadOption l3 //│ res: Some[int] //│ constrain calls : 57 -//│ annoying calls : 18 -//│ subtyping calls : 182 +//│ annoying calls : 22 +//│ subtyping calls : 187 :stats @@ -125,8 +125,8 @@ rec def lr1 = Cons { head = 0; tail = lr1 } Cons.HeadOption lr1 //│ res: Some[0] //│ constrain calls : 51 -//│ annoying calls : 18 -//│ subtyping calls : 165 +//│ annoying calls : 21 +//│ subtyping calls : 170 :stats rec def lr2 = Cons { head = 0; tail = Cons { head = 1; tail = Cons { head = 3; tail = lr2 } } } @@ -141,8 +141,8 @@ rec def lr2 = Cons { head = 0; tail = Cons { head = 1; tail = Cons { head = 3; t Cons.HeadOption lr2 //│ res: Some[0] //│ constrain calls : 50 -//│ annoying calls : 18 -//│ subtyping calls : 159 +//│ annoying calls : 21 +//│ subtyping calls : 164 :e diff --git a/shared/src/test/diff/mlscript/JetBrains.mls b/shared/src/test/diff/mlscript/JetBrains.mls index 3fffcce208..62704a1a0a 100644 --- a/shared/src/test/diff/mlscript/JetBrains.mls +++ b/shared/src/test/diff/mlscript/JetBrains.mls @@ -101,7 +101,7 @@ def evalN3 evalN3 x = case x of { //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.+2: Neg -> 0 - (evalN2 x.underlying) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b ?c. ?c | ?b)` is not an instance of type `int` +//│ ╟── function of type `?a -> (forall ?b ?c. ?b | ?c)` is not an instance of type `int` //│ ║ l.73: def evalN2 evalN2 x = case x of { //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.74: Neg -> 0 - (evalN2 evalN2 x.underlying) diff --git a/shared/src/test/diff/mlscript/Luyu.mls b/shared/src/test/diff/mlscript/Luyu.mls index aef1473d4a..7c899cb8c2 100644 --- a/shared/src/test/diff/mlscript/Luyu.mls +++ b/shared/src/test/diff/mlscript/Luyu.mls @@ -55,7 +55,7 @@ mib0.Map (fun _ -> "str") //│ ╟── from application: //│ ║ l.23: method Map f = MappableIntBox { value = f this.value } //│ ╙── ^^^^^^^^^^^^ -//│ res: error | (MappableIntBox with {value: "str"}) +//│ res: (MappableIntBox with {value: "str"}) | error //│ = MappableIntBox { value: 'str' } class BetterIntBox: { value: int } diff --git a/shared/src/test/diff/mlscript/Match3.mls b/shared/src/test/diff/mlscript/Match3.mls index a3334509d9..edbd388f60 100644 --- a/shared/src/test/diff/mlscript/Match3.mls +++ b/shared/src/test/diff/mlscript/Match3.mls @@ -33,7 +33,7 @@ eval_expr (M {}) //│ ╟── Note: class M is defined at: //│ ║ l.3: class M //│ ╙── ^ -//│ res: error | M +//│ res: M | error //│ = M {} def eval_expr v = diff --git a/shared/src/test/diff/mlscript/Methods2.mls b/shared/src/test/diff/mlscript/Methods2.mls index 19381eca28..d72f629530 100644 --- a/shared/src/test/diff/mlscript/Methods2.mls +++ b/shared/src/test/diff/mlscript/Methods2.mls @@ -100,7 +100,7 @@ l.Map (fun x -> mul x 2) //│ res: List[int] //│ = Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } } //│ constrain calls : 72 -//│ annoying calls : 5 +//│ annoying calls : 6 //│ subtyping calls : 245 l0 = Cons { head = 0; tail = Nil {} } @@ -114,7 +114,7 @@ Cons.HeadOption l0 //│ Runtime error: //│ TypeError: (intermediate value).HeadOption is not a function //│ constrain calls : 55 -//│ annoying calls : 28 +//│ annoying calls : 31 //│ subtyping calls : 194 @@ -129,7 +129,7 @@ Cons.HeadOption l1 //│ Runtime error: //│ TypeError: (intermediate value).HeadOption is not a function //│ constrain calls : 55 -//│ annoying calls : 28 +//│ annoying calls : 31 //│ subtyping calls : 194 :re @@ -139,7 +139,7 @@ Cons.HeadOption l //│ Runtime error: //│ TypeError: (intermediate value).HeadOption is not a function //│ constrain calls : 70 -//│ annoying calls : 28 +//│ annoying calls : 31 //│ subtyping calls : 258 :stats @@ -147,7 +147,7 @@ o = l.(Cons.HeadOption) //│ o: Some[0 | 1] //│ = undefined //│ constrain calls : 68 -//│ annoying calls : 28 +//│ annoying calls : 31 //│ subtyping calls : 245 o = l.(Cons.HeadOption) diff --git a/shared/src/test/diff/mlscript/Misc.mls b/shared/src/test/diff/mlscript/Misc.mls index 022f43f507..a41c1fc475 100644 --- a/shared/src/test/diff/mlscript/Misc.mls +++ b/shared/src/test/diff/mlscript/Misc.mls @@ -46,26 +46,26 @@ def arg = if true then c else 0 :ns def arg = if true then C{x = 42} else C{x = 1} -//│ arg: forall 'a 'A 'A0 'x 'x0. 'a +//│ arg: forall 'x 'x0 'A 'A0 'a. 'a //│ where -//│ 'a :> #C & {x: 'x0, C#A = 'A0} | #C & {x: 'x, C#A = 'A} -//│ 'x :> 1 -//│ <: 'A +//│ 'a :> #C & {x: 'x, C#A = 'A0} | #C & {x: 'x0, C#A = 'A} +//│ 'x0 :> 1 +//│ <: 'A //│ 'A :> 1 -//│ 'x0 :> 42 -//│ <: 'A0 +//│ 'x :> 42 +//│ <: 'A0 //│ 'A0 :> 42 :ns arg -//│ res: forall 'a 'A 'A0 'x 'x0. 'a +//│ res: forall 'x 'x0 'A 'A0 'a. 'a //│ where -//│ 'a :> #C & {x: 'x0, C#A = 'A0} | #C & {x: 'x, C#A = 'A} -//│ 'x :> 1 -//│ <: 'A +//│ 'a :> #C & {x: 'x, C#A = 'A0} | #C & {x: 'x0, C#A = 'A} +//│ 'x0 :> 1 +//│ <: 'A //│ 'A :> 1 -//│ 'x0 :> 42 -//│ <: 'A0 +//│ 'x :> 42 +//│ <: 'A0 //│ 'A0 :> 42 arg diff --git a/shared/src/test/diff/mlscript/Mut.mls b/shared/src/test/diff/mlscript/Mut.mls index 86517480ec..ff60eeab4b 100644 --- a/shared/src/test/diff/mlscript/Mut.mls +++ b/shared/src/test/diff/mlscript/Mut.mls @@ -425,12 +425,15 @@ k1._2 <- 233 //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.424: k1._2 <- 233 //│ ║ ^^^^^^^^^^^^ -//│ ╟── tuple field of type `"hello"` is not mutable +//│ ╟── tuple literal of type `forall ?a ?b. (mut ?a, "hello", mut ?b,)` does not have field '_2' //│ ║ l.414: k1 = (mut 233, "hello", mut true) -//│ ║ ^^^^^^^ -//│ ╟── but it flows into assigned field with expected type `?a` +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `{mut _2: in ?c}` +//│ ║ l.424: k1._2 <- 233 +//│ ║ ^^ +//│ ╟── Note: constraint arises from assigned selection: //│ ║ l.424: k1._2 <- 233 -//│ ╙── ^^ +//│ ╙── ^^^^^ //│ = [] mt1 = (mut 3, mut false) @@ -454,16 +457,16 @@ amf mt3 :e amf mt4 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.455: amf mt4 +//│ ║ l.458: amf mt4 //│ ║ ^^^^^^^ //│ ╟── type `(mut bool, bool, bool,)` does not match type `MutArray['a]` //│ ║ l.384: def mt4: (mut bool, bool, bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `MutArray['a]` -//│ ║ l.455: amf mt4 +//│ ║ l.458: amf mt4 //│ ║ ^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.445: def amf : MutArray['a] -> 'a +//│ ║ l.448: def amf : MutArray['a] -> 'a //│ ╙── ^^^^^^^^^^^^ //│ res: bool | error //│ = @@ -474,18 +477,18 @@ a1[0] <- 1 mt1[0] <- mt2._1 mt4[3] <- true //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.473: a1[0] <- 1 +//│ ║ l.476: a1[0] <- 1 //│ ║ ^^^^^^^^^^ //│ ╟── type `Array[int]` does not match type `MutArray[?a]` //│ ║ l.30: def a1: Array[int] //│ ║ ^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `MutArray[?a]` -//│ ║ l.473: a1[0] <- 1 +//│ ║ l.476: a1[0] <- 1 //│ ╙── ^^ //│ = //│ a1 is not implemented //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.474: mt1[0] <- mt2._1 +//│ ║ l.477: mt1[0] <- mt2._1 //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── type `int` is not an instance of `bool` //│ ║ l.381: def mt1: (mut int, mut bool) @@ -494,33 +497,33 @@ mt4[3] <- true //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── from assigned array element: -//│ ║ l.474: mt1[0] <- mt2._1 +//│ ║ l.477: mt1[0] <- mt2._1 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.474: mt1[0] <- mt2._1 +//│ ║ l.477: mt1[0] <- mt2._1 //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── type `int` is not an instance of `bool` //│ ║ l.382: def mt2: (int, int) //│ ║ ^^^ //│ ╟── but it flows into field selection with expected type `bool` -//│ ║ l.474: mt1[0] <- mt2._1 +//│ ║ l.477: mt1[0] <- mt2._1 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── from assigned array element: -//│ ║ l.474: mt1[0] <- mt2._1 +//│ ║ l.477: mt1[0] <- mt2._1 //│ ╙── ^^^^^^ //│ = //│ mt2 is not implemented //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.475: mt4[3] <- true +//│ ║ l.478: mt4[3] <- true //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `(mut bool, bool, bool,)` does not match type `MutArray[?a]` //│ ║ l.384: def mt4: (mut bool, bool, bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `MutArray[?a]` -//│ ║ l.475: mt4[3] <- true +//│ ║ l.478: mt4[3] <- true //│ ╙── ^^^ //│ = [] @@ -546,68 +549,68 @@ mt1._1 <- (b1.t <- 4) (mt1._1 <- b1.t) <- 4 b1.x <- 1 + 2 <- 4 //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.543: mt1._1 <- mt1._2 +//│ ║ l.546: mt1._1 <- mt1._2 //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── but it flows into field selection with expected type `int` -//│ ║ l.543: mt1._1 <- mt1._2 +//│ ║ l.546: mt1._1 <- mt1._2 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^ //│ ╟── from assigned selection: -//│ ║ l.543: mt1._1 <- mt1._2 +//│ ║ l.546: mt1._1 <- mt1._2 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.544: mt1._2 <- 1 +//│ ║ l.547: mt1._2 <- 1 //│ ║ ^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.544: mt1._2 <- 1 +//│ ║ l.547: mt1._2 <- 1 //│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── from assigned selection: -//│ ║ l.544: mt1._2 <- 1 +//│ ║ l.547: mt1._2 <- 1 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.545: mt1._1 <- (b1.t <- 4) +//│ ║ l.548: mt1._1 <- (b1.t <- 4) //│ ║ ^^^^^^^^^ //│ ╟── type `B` does not have field 't' //│ ║ l.265: def b1 : B //│ ║ ^ //│ ╟── but it flows into reference with expected type `{mut t: in ?t}` -//│ ║ l.545: mt1._1 <- (b1.t <- 4) +//│ ║ l.548: mt1._1 <- (b1.t <- 4) //│ ║ ^^ //│ ╟── Note: constraint arises from assigned selection: -//│ ║ l.545: mt1._1 <- (b1.t <- 4) +//│ ║ l.548: mt1._1 <- (b1.t <- 4) //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.545: mt1._1 <- (b1.t <- 4) +//│ ║ l.548: mt1._1 <- (b1.t <- 4) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── assignment of type `unit` is not an instance of type `int` -//│ ║ l.545: mt1._1 <- (b1.t <- 4) +//│ ║ l.548: mt1._1 <- (b1.t <- 4) //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^ //│ ╟── from assigned selection: -//│ ║ l.545: mt1._1 <- (b1.t <- 4) +//│ ║ l.548: mt1._1 <- (b1.t <- 4) //│ ╙── ^^^^^^ //│ ╔══[ERROR] Illegal assignment -//│ ║ l.546: (mt1._1 <- b1.t) <- 4 +//│ ║ l.549: (mt1._1 <- b1.t) <- 4 //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── cannot assign to assignment -//│ ║ l.546: (mt1._1 <- b1.t) <- 4 +//│ ║ l.549: (mt1._1 <- b1.t) <- 4 //│ ╙── ^^^^^^^^^^^^^^^^ //│ res: error //│ ╔══[ERROR] Illegal assignment -//│ ║ l.547: b1.x <- 1 + 2 <- 4 +//│ ║ l.550: b1.x <- 1 + 2 <- 4 //│ ║ ^^^^^^ //│ ╟── cannot assign to integer literal -//│ ║ l.547: b1.x <- 1 + 2 <- 4 +//│ ║ l.550: b1.x <- 1 + 2 <- 4 //│ ╙── ^ //│ Code generation encountered an error: //│ illegal assignemnt left-hand side: Bra(rcd = false, Assign(Sel(Var(mt1), _1), Sel(Var(b1), t))) @@ -631,7 +634,7 @@ f mt1 1 :e f mt2 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.632: f mt2 +//│ ║ l.635: f mt2 //│ ║ ^^^^^ //│ ╟── tuple field of type `int` is not mutable //│ ║ l.382: def mt2: (int, int) @@ -643,10 +646,10 @@ f mt2 :e g (1, true) 2 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.644: g (1, true) 2 +//│ ║ l.647: g (1, true) 2 //│ ║ ^^^^^^^^^^^ //│ ╟── argument of type `1` is not mutable -//│ ║ l.644: g (1, true) 2 +//│ ║ l.647: g (1, true) 2 //│ ╙── ^ //│ res: error | unit //│ = @@ -655,10 +658,10 @@ g (1, true) 2 // TODO forbid `mut` here g (mut 1, true) 2 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.656: g (mut 1, true) 2 +//│ ║ l.659: g (mut 1, true) 2 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument of type `1` is not mutable -//│ ║ l.656: g (mut 1, true) 2 +//│ ║ l.659: g (mut 1, true) 2 //│ ╙── ^ //│ res: error | unit //│ = @@ -702,13 +705,13 @@ st2._1 <- 8 :e st1._1 <- 9 //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.703: st1._1 <- 9 +//│ ║ l.706: st1._1 <- 9 //│ ║ ^^^^^^^^^^^ //│ ╟── tuple field of type `int` is not mutable -//│ ║ l.679: def st1 : (int, ) +//│ ║ l.682: def st1 : (int, ) //│ ║ ^^^ //│ ╟── but it flows into assigned field with expected type `?a` -//│ ║ l.703: st1._1 <- 9 +//│ ║ l.706: st1._1 <- 9 //│ ╙── ^^ //│ = [] @@ -733,20 +736,20 @@ foreach am1 (fun y -> y._1 <- 2) (1,2,3)[0] <- true (1,2,3)._1 <- "hello" //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.733: (1,2,3)[0] <- true +//│ ║ l.736: (1,2,3)[0] <- true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `(1, 2, 3,)` does not match type `MutArray[?a]` -//│ ║ l.733: (1,2,3)[0] <- true +//│ ║ l.736: (1,2,3)[0] <- true //│ ╙── ^^^^^^^ //│ = [] //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.734: (1,2,3)._1 <- "hello" +//│ ║ l.737: (1,2,3)._1 <- "hello" //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple field of type `1` is not mutable -//│ ║ l.734: (1,2,3)._1 <- "hello" +//│ ║ l.737: (1,2,3)._1 <- "hello" //│ ║ ^ //│ ╟── but it flows into assigned field with expected type `?a` -//│ ║ l.734: (1,2,3)._1 <- "hello" +//│ ║ l.737: (1,2,3)._1 <- "hello" //│ ╙── ^^ //│ = [] @@ -754,18 +757,18 @@ foreach am1 (fun y -> y._1 <- 2) (0,)["oops"] (mut 0,)["oops"] <- 1 //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.754: (0,)["oops"] +//│ ║ l.757: (0,)["oops"] //│ ║ ^^^^^^^^^^^^ //│ ╟── string literal of type `"oops"` is not an instance of type `int` -//│ ║ l.754: (0,)["oops"] +//│ ║ l.757: (0,)["oops"] //│ ╙── ^^^^^^ //│ res: 0 | undefined //│ = undefined //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.755: (mut 0,)["oops"] <- 1 +//│ ║ l.758: (mut 0,)["oops"] <- 1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"oops"` is not an instance of type `int` -//│ ║ l.755: (mut 0,)["oops"] <- 1 +//│ ║ l.758: (mut 0,)["oops"] <- 1 //│ ╙── ^^^^^^ //│ = [] @@ -782,24 +785,24 @@ arr = (mut 0,) arr[oops] arr[oops] <- 1 //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.782: arr[oops] +//│ ║ l.785: arr[oops] //│ ║ ^^^^^^^^^ //│ ╟── string literal of type `"oops"` is not an instance of type `int` -//│ ║ l.772: oops = "oops" +//│ ║ l.775: oops = "oops" //│ ║ ^^^^^^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.782: arr[oops] +//│ ║ l.785: arr[oops] //│ ╙── ^^^^ //│ res: 0 | undefined //│ = undefined //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.783: arr[oops] <- 1 +//│ ║ l.786: arr[oops] <- 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── string literal of type `"oops"` is not an instance of type `int` -//│ ║ l.772: oops = "oops" +//│ ║ l.775: oops = "oops" //│ ║ ^^^^^^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.783: arr[oops] <- 1 +//│ ║ l.786: arr[oops] <- 1 //│ ╙── ^^^^ //│ = [] @@ -813,10 +816,10 @@ x = 1 :e x <- 2 //│ ╔══[ERROR] Illegal assignment -//│ ║ l.814: x <- 2 +//│ ║ l.817: x <- 2 //│ ║ ^^^^^^ //│ ╟── cannot assign to reference -//│ ║ l.814: x <- 2 +//│ ║ l.817: x <- 2 //│ ╙── ^ //│ res: error //│ = [] @@ -846,16 +849,16 @@ foo { mut a = 1 } 2 add :e foo { mut a = 1 } 2 3 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.847: foo { mut a = 1 } 2 3 +//│ ║ l.850: foo { mut a = 1 } 2 3 //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `3` is not a function -//│ ║ l.847: foo { mut a = 1 } 2 3 +//│ ║ l.850: foo { mut a = 1 } 2 3 //│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.838: def foo x y z = (x.a <- 0, x.a + 1, x.a, x.a <- y, z x.a) +//│ ║ l.841: def foo x y z = (x.a <- 0, x.a + 1, x.a, x.a <- y, z x.a) //│ ║ ^^^^^ //│ ╟── from reference: -//│ ║ l.838: def foo x y z = (x.a <- 0, x.a + 1, x.a, x.a <- y, z x.a) +//│ ║ l.841: def foo x y z = (x.a <- 0, x.a + 1, x.a, x.a <- y, z x.a) //│ ╙── ^ //│ res: (unit, int, 0 | 1 | 2, unit, nothing,) | error //│ Runtime error: @@ -865,24 +868,24 @@ foo { mut a = 1 } 2 3 foo { mut a = "oops" } 2 foo { a = 1 } 2 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.865: foo { mut a = "oops" } 2 +//│ ║ l.868: foo { mut a = "oops" } 2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"oops"` is not an instance of type `int` -//│ ║ l.865: foo { mut a = "oops" } 2 +//│ ║ l.868: foo { mut a = "oops" } 2 //│ ║ ^^^^^^ //│ ╟── but it flows into mutable record field with expected type `int` -//│ ║ l.865: foo { mut a = "oops" } 2 +//│ ║ l.868: foo { mut a = "oops" } 2 //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.838: def foo x y z = (x.a <- 0, x.a + 1, x.a, x.a <- y, z x.a) +//│ ║ l.841: def foo x y z = (x.a <- 0, x.a + 1, x.a, x.a <- y, z x.a) //│ ╙── ^^^ //│ res: (("oops" | 0 | 2) -> 'a) -> (unit, int, "oops" | 0 | 2, unit, 'a,) | error //│ = [Function (anonymous)] //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.866: foo { a = 1 } 2 +//│ ║ l.869: foo { a = 1 } 2 //│ ║ ^^^^^^^^^^^^^ //│ ╟── record field of type `1` is not mutable -//│ ║ l.866: foo { a = 1 } 2 +//│ ║ l.869: foo { a = 1 } 2 //│ ╙── ^^^^^ //│ res: (1 -> 'a) -> (unit, int, 1, unit, 'a,) | error //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/mlscript/NestedClassArgs.mls b/shared/src/test/diff/mlscript/NestedClassArgs.mls index b581d3ebbd..bc607c757c 100644 --- a/shared/src/test/diff/mlscript/NestedClassArgs.mls +++ b/shared/src/test/diff/mlscript/NestedClassArgs.mls @@ -139,14 +139,14 @@ rec def c5 a = C5{ a = C2 { a = c5 a } } //│ c5: anything -> 'a //│ where //│ 'a :> C5['A] with {a: C2['A0] with {a: 'a}} -//│ 'A0 :> 'a | C5['A] +//│ 'A0 :> C5['A] | 'a //│ <: C5['A] c = c5 //│ anything -> 'a //│ where //│ 'a :> C5['A] with {a: C2['A0] with {a: 'a}} -//│ 'A0 :> 'a | C5['A] +//│ 'A0 :> C5['A] | 'a //│ <: C5['A] //│ <: c: //│ 'a -> C5['a] @@ -163,23 +163,23 @@ def c: 'a -> C6['a] //│ c: 'a -> C6['a] rec def c6 a = C6{ a = c5 (c6 a) } -//│ c6: anything -> (C6['A] with {a: forall 'A0 'a 'A1. 'a}) +//│ c6: anything -> (C6['A] with {a: forall 'a 'A0 'A1. 'a}) //│ where -//│ 'a :> C5['A1] with {a: C2['A0] with {a: 'a}} -//│ 'A0 :> 'a | C5['A1] -//│ <: C5['A1] +//│ 'a :> C5['A0] with {a: C2['A1] with {a: 'a}} +//│ 'A1 :> C5['A0] | 'a +//│ <: C5['A0] :stats c = c6 //│ anything -> (C6['A] with {a: forall 'a 'A0 'A1. 'a}) //│ where //│ 'a :> C5['A0] with {a: C2['A1] with {a: 'a}} -//│ 'A1 :> 'a | C5['A0] +//│ 'A1 :> C5['A0] | 'a //│ <: C5['A0] //│ <: c: //│ 'a -> C6['a] //│ constrain calls : 70 -//│ annoying calls : 30 +//│ annoying calls : 34 //│ subtyping calls : 417 @@ -259,9 +259,7 @@ L{h=error;t=s2} //│ ╟── Note: constraint arises from applied type reference: //│ ║ l.229: class L[T]: { h: T; t: O[L[T]] } //│ ╙── ^^^^ -//│ res: error | (L['T] with {h: nothing, t: forall '_. O['_]}) -//│ where -//│ '_ :> 1 +//│ res: error //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.252: L{h=error;t=s2} //│ ║ ^^^^^^^^^^^^^^^ @@ -288,12 +286,12 @@ def append ls elem = L { h = elem; t = S { v = ls } } :ns append -//│ res: forall 'a 'T 'h 'v 'T0 'b 'c 't. 'a -> 'b -> 'c +//│ res: forall 'a 'h 'b 'c 'T 't 'v 'T0. 'a -> 'c -> 'b //│ where -//│ 'c :> #L & {h: 'h, t: 't, L#T = 'T0} +//│ 'b :> #L & {h: 'h, t: 't, L#T = 'T0} //│ 't :> #S & {v: 'v, S#T = 'T} //│ <: O[L['T0]] -//│ 'b <: 'h +//│ 'c <: 'h //│ 'h <: 'T0 //│ 'a <: 'v //│ 'v <: L['T0] & 'T @@ -329,10 +327,10 @@ append_ty_2 = append //│ <: append_ty_2: //│ (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] with {h: 'h, t: S['T0] with {v: 'v}}) //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.327: append_ty_2 = append +//│ ║ l.325: append_ty_2 = append //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'T0` is not an instance of type `L` -//│ ║ l.320: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) +//│ ║ l.318: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) //│ ║ ^^^ //│ ╟── Note: constraint arises from applied type reference: //│ ║ l.229: class L[T]: { h: T; t: O[L[T]] } @@ -352,13 +350,13 @@ append_ty_2 = append_ty //│ <: append_ty_2: //│ (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] with {h: 'h, t: S['T0] with {v: 'v}}) //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.350: append_ty_2 = append_ty +//│ ║ l.348: append_ty_2 = append_ty //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'T0` is not an instance of type `L` -//│ ║ l.320: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) +//│ ║ l.318: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) //│ ║ ^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.306: def append_ty: (L['T] & 'v) -> ('T & 'h) -> (L['T] & {h: 'h; t: S[L['T]] & {v: 'v}}) +//│ ║ l.304: def append_ty: (L['T] & 'v) -> ('T & 'h) -> (L['T] & {h: 'h; t: S[L['T]] & {v: 'v}}) //│ ╙── ^^^^^ diff --git a/shared/src/test/diff/mlscript/Paper.mls b/shared/src/test/diff/mlscript/Paper.mls index b8c6cf60fd..84f5176b76 100644 --- a/shared/src/test/diff/mlscript/Paper.mls +++ b/shared/src/test/diff/mlscript/Paper.mls @@ -53,7 +53,7 @@ class SomeAnd[A, P]: Some[A] & { payload: P } let arg = if true then SomeAnd{value = 42; payload = 23} else None{} in mapSome (fun x -> x.value + x.payload) arg -//│ res: int | None +//│ res: None | int //│ = 65 diff --git a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls index c8675b59aa..df0b443a77 100644 --- a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls +++ b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls @@ -129,7 +129,7 @@ def eval_lambda eval_rec subst v = case v of { Abs { name = new_name; body = eval_rec (Cons (Tuple v.name (Var { name = new_name })) subst) v.body } } -//│ eval_lambda: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('result & 'body & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | App[?] & {lhs: 'lhs, rhs: 'lhs} | Var & 'result) -> (Abs['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | 'result) +//│ eval_lambda: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('body & 'result & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | App[?] & {lhs: 'lhs, rhs: 'lhs} | Var & 'result) -> (Abs['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | 'result) //│ where //│ 'b <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'b}) | Nil //│ = @@ -139,14 +139,14 @@ rec def eval1 subst = eval_lambda eval1 subst //│ eval1: (List[?] & 'tail) -> 'b -> 'rhs //│ where //│ 'tail <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'tail}) | Nil -//│ 'result :> 'rhs | Var +//│ 'result :> 'rhs //│ <: 'b & (Abs[?] & 'c | 'lhs & ~#Abs) //│ 'rhs :> 'result | 'd | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Abs['rhs] //│ 'd :> Var //│ <: 'b & (Abs[?] & 'c | {name: string} & 'lhs & ~#Abs) //│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Var //│ <: 'a & 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'rhs}) | 'rhs | Var +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'rhs}) | 'rhs //│ 'c <: {body: 'b, name: string} //│ 'b <: Abs[?] & {body: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Var & 'd //│ = @@ -254,7 +254,7 @@ def eval_lexpr eval_rec subst v = case v of { | Lambda -> eval_lambda eval_rec subst v | Expr -> eval_expr eval_rec subst v } -//│ eval_lexpr: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('body & 'result & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | Add[?] & {lhs: 'lhs, rhs: 'lhs} | App[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | Num & 'result | Var & 'result) -> (Abs['body] | Add['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | Mul['body] | Num | 'result) +//│ eval_lexpr: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('result & 'body & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | Add[?] & {lhs: 'lhs, rhs: 'lhs} | App[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | Num & 'result | Var & 'result) -> (Abs['body] | Add['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | Mul['body] | Num | 'result) //│ where //│ 'b <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'b}) | Nil //│ = @@ -264,10 +264,10 @@ rec def eval3 subst = eval_lexpr eval3 subst //│ eval3: (List[?] & 'tail) -> 'b -> 'rhs //│ where //│ 'tail <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'tail}) | Nil -//│ 'result :> 'rhs | Var | Num +//│ 'result :> Var | 'rhs | Num //│ <: 'b & (Abs[?] & 'c | 'lhs & (Num | ~#Abs & ~#Num)) //│ 'rhs :> Abs['rhs] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | 'result | 'd | 'e -//│ 'a :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | 'rhs | Var +//│ 'a :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | 'rhs //│ 'lhs :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Num | Var //│ <: 'b & 'a //│ 'b <: Abs[?] & {body: 'b} | Add[?] & {lhs: 'b, rhs: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Num & (Add[?] & 'e | Mul[?] & 'e | Num & 'result | Var & 'd) | Var & 'd @@ -315,7 +315,7 @@ eval3 Nil (Var { name = "s" }) //│ res: 'result //│ where //│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'result | Var | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b //│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = @@ -334,7 +334,7 @@ eval3 Nil (Abs { name = "s"; body = Var { name = "s" } }) //│ res: 'result //│ where //│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'result | Var | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b //│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = @@ -351,7 +351,7 @@ eval3 Nil (Num { num = 1 }) //│ res: 'result //│ where //│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'result | Var | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b //│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = @@ -361,7 +361,7 @@ eval3 Nil (App { lhs = Num {num = 0}; rhs = Num {num = 0}}) //│ res: 'result //│ where //│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'result | Var | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b //│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = @@ -371,7 +371,7 @@ eval3 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Num { //│ res: 'result //│ where //│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'result | Var | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b //│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = @@ -418,10 +418,10 @@ rec def eval4 subst = eval_lexpr' eval4 subst //│ eval4: (List[?] & 'tail) -> 'b -> 'rhs //│ where //│ 'tail <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'tail}) | Nil -//│ 'result :> 'rhs | Var | Num +//│ 'result :> Var | 'rhs | Num //│ <: 'b & (Abs[?] & 'c | 'lhs & (Abs[?] & 'c & ~#Abs | 'lhs0 & (Num | ~#Abs & ~#Num))) //│ 'rhs :> Abs['rhs] | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | 'result | 'd | 'e | (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) -//│ 'a :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | 'rhs | Var +//│ 'a :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | 'rhs //│ 'lhs :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Num | Var //│ <: 'b & 'a //│ 'lhs0 :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Num | Var @@ -441,7 +441,7 @@ eval4 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Num { //│ res: 'result //│ where //│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'result | Var | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b //│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = diff --git a/shared/src/test/diff/mlscript/RecursiveTypes.mls b/shared/src/test/diff/mlscript/RecursiveTypes.mls index 6fdfea7e3a..d2d94e7716 100644 --- a/shared/src/test/diff/mlscript/RecursiveTypes.mls +++ b/shared/src/test/diff/mlscript/RecursiveTypes.mls @@ -206,7 +206,7 @@ class C[A]: { a: A } :ns rec def foo (c: C['a]) = foo (c.a) -//│ foo: forall 'foo 'a 'a0 'b. 'foo +//│ foo: forall 'a 'a0 'b 'foo. 'foo //│ where //│ 'foo := C['a] -> 'b //│ 'a <: 'a0 @@ -411,17 +411,17 @@ f 1 :ns rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x -//│ f: forall 'b 'c 'd 'a 'e 'f 'g. 'f +//│ f: forall 'b 'c 'd 'f 'e 'g 'a. 'f //│ where -//│ 'f := 'b -> 'g -//│ 'b :> 'b\a & {a: 'c} +//│ 'f := 'e -> 'g +//│ 'e :> 'e\a & {a: 'c} //│ <: ({a: 'a} | ~{a: 'c} | ~{})\a & ({a: 'a} | ~{a: 'c})\a & (number | ~{a: 'c} | ~{})\a & (number | ~{a: 'c})\a & (int | ~{a: 'c} | ~{})\a & (int | ~{a: 'c})\a & 'd & int & number //│ 'a <: 'd -//│ 'd :> 'b\a & {a: 'c} +//│ 'd :> 'e\a & {a: 'c} //│ <: 'g -//│ 'g :> 'b\a & {a: 'c} -//│ <: 'e -//│ 'e :> 'b\a & {a: 'c} +//│ 'g :> 'e\a & {a: 'c} +//│ <: 'b +//│ 'b :> 'e\a & {a: 'c} //│ <: {a: 'a} //│ 'c :> int diff --git a/shared/src/test/diff/mlscript/RecursiveTypes2.mls b/shared/src/test/diff/mlscript/RecursiveTypes2.mls index 39ee3b2ea0..35d144d86f 100644 --- a/shared/src/test/diff/mlscript/RecursiveTypes2.mls +++ b/shared/src/test/diff/mlscript/RecursiveTypes2.mls @@ -41,7 +41,7 @@ f.x //│ where //│ 'a :> T3 & {x: T1 & 'a} //│ constrain calls : 6 -//│ annoying calls : 4 +//│ annoying calls : 5 //│ subtyping calls : 148 g = error : T1 & { x: T2 | 'a } as 'a @@ -55,7 +55,7 @@ g.x //│ where //│ 'a :> T1 & {x: 'a | T2} //│ constrain calls : 6 -//│ annoying calls : 4 +//│ annoying calls : 5 //│ subtyping calls : 85 :stats @@ -68,7 +68,7 @@ f = g //│ where //│ 'a :> T3 & {x: T1 & 'a} //│ constrain calls : 69 -//│ annoying calls : 95 -//│ subtyping calls : 3476 +//│ annoying calls : 97 +//│ subtyping calls : 3493 diff --git a/shared/src/test/diff/mlscript/SafeDiv.mls b/shared/src/test/diff/mlscript/SafeDiv.mls index a462b57251..7392c71862 100644 --- a/shared/src/test/diff/mlscript/SafeDiv.mls +++ b/shared/src/test/diff/mlscript/SafeDiv.mls @@ -48,7 +48,7 @@ type Option[A] = Some[A] | None fun x -> case x of { int -> safeDiv 1 x | _ -> None{} } -//│ res: (int & ~0 | ~int) -> (int | None) +//│ res: (int & ~0 | ~int) -> (None | int) //│ = [Function: res] :e // we no longer refine x's type here, as that was rather unexpected diff --git a/shared/src/test/diff/mlscript/SelfNeg.mls b/shared/src/test/diff/mlscript/SelfNeg.mls index bdd07ee710..410c38b874 100644 --- a/shared/src/test/diff/mlscript/SelfNeg.mls +++ b/shared/src/test/diff/mlscript/SelfNeg.mls @@ -56,11 +56,11 @@ def foo: ('a -> (~'a -> anything) -> anything) -> MutArray['a] :ns r = foo (fun a -> fun f -> f a) -//│ r: forall 'b 'c 'a. 'c +//│ r: forall 'b 'a 'c. 'b //│ where -//│ 'c :> MutArray['a] -//│ 'a <: 'b -//│ 'b <: ~'a +//│ 'b :> MutArray['a] +//│ 'a <: 'c +//│ 'c <: ~'a //│ = //│ foo is not implemented diff --git a/shared/src/test/diff/mlscript/SelfNegs.mls b/shared/src/test/diff/mlscript/SelfNegs.mls index 3cae854b7d..2313cff065 100644 --- a/shared/src/test/diff/mlscript/SelfNegs.mls +++ b/shared/src/test/diff/mlscript/SelfNegs.mls @@ -12,7 +12,7 @@ def foo(fa: ((~'a) -> 'a, 'a)) = :ns foo -//│ res: forall 'b 'c 'a. (~'a -> 'a, 'a,) -> 'c +//│ res: forall 'a 'b 'c. (~'a -> 'a, 'a,) -> 'c //│ where //│ 'a <: 'c & 'b //│ 'b <: ~'a diff --git a/shared/src/test/diff/mlscript/Seqs.mls b/shared/src/test/diff/mlscript/Seqs.mls index 8b172e2ed7..1e9912d6d3 100644 --- a/shared/src/test/diff/mlscript/Seqs.mls +++ b/shared/src/test/diff/mlscript/Seqs.mls @@ -33,7 +33,7 @@ Nil{} //│ ╟── record literal of type `anything` does not have field 'size' //│ ║ l.29: Nil{} //│ ╙── ^^ -//│ res: error | Nil & {size: nothing} +//│ res: Nil & {size: nothing} | error //│ = Nil { size: undefined } def Nil = Nil { size = 0 } diff --git a/shared/src/test/diff/mlscript/SimpleMethods.mls b/shared/src/test/diff/mlscript/SimpleMethods.mls index 1d881c7bc9..32b2dd048a 100644 --- a/shared/src/test/diff/mlscript/SimpleMethods.mls +++ b/shared/src/test/diff/mlscript/SimpleMethods.mls @@ -6,7 +6,7 @@ class C0 //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.4: method Foo0[A](a: A) = a + 1 //│ ║ ^^^ -//│ ╟── reference of type `A` is not an instance of type `int` +//│ ╟── reference of type `#A` is not an instance of type `int` //│ ║ l.4: method Foo0[A](a: A) = a + 1 //│ ║ ^ //│ ╟── Note: method type parameter A is defined at: diff --git a/shared/src/test/diff/mlscript/StressDNF.mls b/shared/src/test/diff/mlscript/StressDNF.mls index c534504c2c..122156bd08 100644 --- a/shared/src/test/diff/mlscript/StressDNF.mls +++ b/shared/src/test/diff/mlscript/StressDNF.mls @@ -16,9 +16,9 @@ def ty0: ('a & 'b & A | 'b & 'c & B | 'c & 'd & C | 'd & 'e & D | 'e & 'f & E) - :stats ty0 = ty0 -//│ (E & 'e & 'f | 'd & (C & 'c | D & 'e) | 'b & (A & 'a | B & 'c)) -> ('a, 'b, 'c, 'd, 'e, 'f,) +//│ (C & 'c & 'd | 'b & (A & 'a | B & 'c) | 'e & (D & 'd | E & 'f)) -> ('a, 'b, 'c, 'd, 'e, 'f,) //│ <: ty0: -//│ (E & 'e & 'f | 'd & (C & 'c | D & 'e) | 'b & (A & 'a | B & 'c)) -> ('a, 'b, 'c, 'd, 'e, 'f,) +//│ (A & 'a & 'b | 'e & (D & 'd | E & 'f) | 'c & (B & 'b | C & 'd)) -> ('a, 'b, 'c, 'd, 'e, 'f,) //│ constrain calls : 1 //│ annoying calls : 0 //│ subtyping calls : 181 diff --git a/shared/src/test/diff/mlscript/StressTraits.mls b/shared/src/test/diff/mlscript/StressTraits.mls index c752de1117..db60a314f4 100644 --- a/shared/src/test/diff/mlscript/StressTraits.mls +++ b/shared/src/test/diff/mlscript/StressTraits.mls @@ -83,7 +83,7 @@ foo arg //│ res: error | int //│ constrain calls : 71 //│ annoying calls : 90 -//│ subtyping calls : 4291 +//│ subtyping calls : 4279 :stats :e @@ -103,7 +103,7 @@ foo arg //│ res: error //│ constrain calls : 94 //│ annoying calls : 216 -//│ subtyping calls : 17284 +//│ subtyping calls : 17114 // ====== 2 ====== // @@ -160,7 +160,7 @@ foo arg //│ res: error | int //│ constrain calls : 82 //│ annoying calls : 90 -//│ subtyping calls : 2915 +//│ subtyping calls : 2903 // ====== 4 ====== // @@ -190,7 +190,7 @@ foo arg //│ res: error //│ constrain calls : 102 //│ annoying calls : 131 -//│ subtyping calls : 3957 +//│ subtyping calls : 3945 :stats :e @@ -208,7 +208,7 @@ foo (arg with { x = 1} with { y = 2 }) //│ res: error //│ constrain calls : 77 //│ annoying calls : 128 -//│ subtyping calls : 3370 +//│ subtyping calls : 3358 :stats :e @@ -226,7 +226,7 @@ foo (arg with { x = 1; y = 2; z = 3 }) //│ res: error //│ constrain calls : 77 //│ annoying calls : 128 -//│ subtyping calls : 3358 +//│ subtyping calls : 3346 // ====== 5 ====== // @@ -257,7 +257,7 @@ foo arg //│ res: error //│ constrain calls : 106 //│ annoying calls : 131 -//│ subtyping calls : 4388 +//│ subtyping calls : 4376 // ====== 6 ====== // @@ -289,7 +289,7 @@ foo arg //│ res: error //│ constrain calls : 110 //│ annoying calls : 131 -//│ subtyping calls : 4953 +//│ subtyping calls : 4941 // ====== 7 ====== // @@ -322,7 +322,7 @@ foo arg //│ res: error //│ constrain calls : 114 //│ annoying calls : 131 -//│ subtyping calls : 5673 +//│ subtyping calls : 5661 def foo_manual: ({fA: 'a} & a | {fB: 'a} & b & ~a | {fC: 'a} & c & ~a & ~b | {fD: 'a} & d & ~a & ~b & ~c | {fE: 'a} & e & ~a & ~b & ~c & ~d | {fF: 'a} & f & ~a & ~b & ~c & ~d & ~e | {fG: 'a} & g & ~a & ~b & ~c & ~d & ~e & ~f) -> 'a //│ foo_manual: ({fA: 'a} & #A | ~#A & ({fB: 'a} & #B | ~#B & ({fC: 'a} & #C | ~#C & ({fD: 'a} & #D | ~#D & ({fE: 'a} & #E | ~#E & ({fF: 'a} & #F | {fG: 'a} & #G & ~#F)))))) -> 'a @@ -388,6 +388,6 @@ foo arg //│ res: error //│ constrain calls : 118 //│ annoying calls : 131 -//│ subtyping calls : 6569 +//│ subtyping calls : 6557 diff --git a/shared/src/test/diff/mlscript/StressUgly.mls b/shared/src/test/diff/mlscript/StressUgly.mls index 3093921636..95e1115d8f 100644 --- a/shared/src/test/diff/mlscript/StressUgly.mls +++ b/shared/src/test/diff/mlscript/StressUgly.mls @@ -44,7 +44,7 @@ eval1_ty = eval1_ty_ugly //│ ╙── ^^^ //│ = //│ eval1_ty_ugly is not implemented -//│ constrain calls : 62 -//│ annoying calls : 44 -//│ subtyping calls : 542 +//│ constrain calls : 60 +//│ annoying calls : 46 +//│ subtyping calls : 517 diff --git a/shared/src/test/diff/mlscript/Tony.mls b/shared/src/test/diff/mlscript/Tony.mls index 3e95c33c2a..99c0b3962a 100644 --- a/shared/src/test/diff/mlscript/Tony.mls +++ b/shared/src/test/diff/mlscript/Tony.mls @@ -17,11 +17,11 @@ arg = if true then Some{value = 42} with {payload = 23} else None {} // > TODO don't distribute neg inters + handle better at constraint top level :stats flatMap3 (fun x -> add x.value x.payload) arg -//│ res: int | None +//│ res: None | int //│ = 65 //│ constrain calls : 94 //│ annoying calls : 23 -//│ subtyping calls : 538 +//│ subtyping calls : 539 arg = if true then Some{value = 42} else None {} diff --git a/shared/src/test/diff/mlscript/TrickyExtrusion.mls b/shared/src/test/diff/mlscript/TrickyExtrusion.mls index 0570525bf0..4de41a0a19 100644 --- a/shared/src/test/diff/mlscript/TrickyExtrusion.mls +++ b/shared/src/test/diff/mlscript/TrickyExtrusion.mls @@ -110,13 +110,13 @@ not (test id)._1 test f = let r x = f x in (r 0, r True) -//│ test: forall 'a 'b 'c 'd 'e 'f 'g. 'b -> ('d, 'g,) +//│ test: forall 'a 'b 'c 'd 'e 'f 'g. 'c -> ('f, 'g,) //│ where -//│ 'b <: 'e -> 'f & 'c -> 'a -//│ 'a <: 'd -//│ 'c :> 0 -//│ 'f <: 'g -//│ 'e :> true +//│ 'c <: 'a -> 'b & 'd -> 'e +//│ 'e <: 'f +//│ 'd :> 0 +//│ 'b <: 'g +//│ 'a :> true //│ = [Function: test3] // * Q: why does this type *appear* approximated after simplification? diff --git a/shared/src/test/diff/mlscript/TypeClasses.mls b/shared/src/test/diff/mlscript/TypeClasses.mls index 3af6f10cf3..47e03bb156 100644 --- a/shared/src/test/diff/mlscript/TypeClasses.mls +++ b/shared/src/test/diff/mlscript/TypeClasses.mls @@ -128,7 +128,7 @@ class ComplexMonoid_bad_0[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b. ?b)` is not a record (expected a record with fields: real, imaginary) +//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` is not a record (expected a record with fields: real, imaginary) //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` @@ -143,7 +143,22 @@ class ComplexMonoid_bad_0[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b. ?b)` does not have field 'Complex#A' +//│ ╟── function of type `forall ?imaginary ?a ?b. ?b -> ?a` is not a record (expected a record with fields: real, imaginary) +//│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` +//│ ║ l.+2: method Empty = Complex { real = this.base } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from record type: +//│ ║ l.29: class Complex[A]: { real: A; imaginary: A } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from inherited method declaration: +//│ ║ l.3: method Empty: A +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in method definition: +//│ ║ l.+2: method Empty = Complex { real = this.base } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` does not have field 'Complex#A' //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{Complex#A <: A}` @@ -187,7 +202,22 @@ class ComplexMonoid_bad_1[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b. ?b)` is not a record (expected a record with fields: real, imaginary) +//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` is not a record (expected a record with fields: real, imaginary) +//│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` +//│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from record type: +//│ ║ l.29: class Complex[A]: { real: A; imaginary: A } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from inherited method declaration: +//│ ║ l.3: method Empty: A +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in method definition: +//│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── function of type `forall ?a ?b ?imaginary. ?b -> ?a` is not a record (expected a record with fields: real, imaginary) //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` @@ -202,7 +232,7 @@ class ComplexMonoid_bad_1[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b. ?b)` does not have field 'Complex#A' +//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` does not have field 'Complex#A' //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{Complex#A <: A}` diff --git a/shared/src/test/diff/mlscript/TypeDefs.mls b/shared/src/test/diff/mlscript/TypeDefs.mls index 2518005fb7..4616809d4c 100644 --- a/shared/src/test/diff/mlscript/TypeDefs.mls +++ b/shared/src/test/diff/mlscript/TypeDefs.mls @@ -21,7 +21,7 @@ Test1 { x = "oops" } //│ ╟── Note: constraint arises from type reference: //│ ║ l.2: class Test1: { x: int } //│ ╙── ^^^ -//│ res: error | (Test1 with {x: "oops"}) +//│ res: (Test1 with {x: "oops"}) | error //│ = Test1 { x: 'oops' } def Test1 = fun x -> Test1 { x = x } diff --git a/shared/src/test/diff/mlscript/TypeRanges.mls b/shared/src/test/diff/mlscript/TypeRanges.mls index c91a61d4aa..1a8a514fc8 100644 --- a/shared/src/test/diff/mlscript/TypeRanges.mls +++ b/shared/src/test/diff/mlscript/TypeRanges.mls @@ -489,7 +489,7 @@ foo: { get: int } //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.488: foo: { get: int } //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.388: def foo: R[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -503,7 +503,7 @@ foo: { set: number -> () } //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.502: foo: { set: number -> () } //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.502: foo: { set: number -> () } //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -524,7 +524,7 @@ foo2: S['a] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.523: foo2: S['a] //│ ║ ^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.388: def foo: R[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -544,7 +544,7 @@ foo2: S['a..'b] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.543: foo2: S['a..'b] //│ ║ ^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.388: def foo: R[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/mlscript/TypeTags.mls b/shared/src/test/diff/mlscript/TypeTags.mls index 5ac9e7110f..d9624307dc 100644 --- a/shared/src/test/diff/mlscript/TypeTags.mls +++ b/shared/src/test/diff/mlscript/TypeTags.mls @@ -70,3 +70,9 @@ foo = Foo //│ = [Function: foo1] + +1 : #Eql +//│ res: Eql[?] +//│ = 1 + + diff --git a/shared/src/test/diff/mlscript/Undef.mls b/shared/src/test/diff/mlscript/Undef.mls index d1fa8a74c2..598b7e6556 100644 --- a/shared/src/test/diff/mlscript/Undef.mls +++ b/shared/src/test/diff/mlscript/Undef.mls @@ -8,13 +8,13 @@ undef = Undef{} def example: int | Undef -//│ example: int | Undef +//│ example: Undef | int //│ = example = if true then undef else 42 //│ 42 | Undef //│ <: example: -//│ int | Undef +//│ Undef | int //│ = Undef {} def qmrk_qmrk lhs rhs = case lhs of { Undef -> rhs | _ -> lhs } diff --git a/shared/src/test/diff/mlscript/Undefined.mls b/shared/src/test/diff/mlscript/Undefined.mls index eb03cf67d9..24c81f3cad 100644 --- a/shared/src/test/diff/mlscript/Undefined.mls +++ b/shared/src/test/diff/mlscript/Undefined.mls @@ -20,7 +20,7 @@ Undefined2 { x = "I am here to make a type mismatch." } //│ ╟── Note: constraint arises from literal type: //│ ║ l.1: class Undefined2: { x: undefined } //│ ╙── ^^^^^^^^^ -//│ res: error | (Undefined2 with {x: "I am here to make a type mismatch."}) +//│ res: (Undefined2 with {x: "I am here to make a type mismatch."}) | error //│ = Undefined2 { x: 'I am here to make a type mismatch.' } :e diff --git a/shared/src/test/diff/mlscript/Variant-sub.mls b/shared/src/test/diff/mlscript/Variant-sub.mls index 8372acee8a..6a026dbeb9 100644 --- a/shared/src/test/diff/mlscript/Variant-sub.mls +++ b/shared/src/test/diff/mlscript/Variant-sub.mls @@ -36,7 +36,7 @@ flatMap f "oops" //│ ╟── Note: constraint arises from reference: //│ ║ l.14: case opt of { Some -> f opt.v | None -> opt } //│ ╙── ^^^ -//│ res: error | Some[nothing] +//│ res: Some[nothing] | error //│ Runtime error: //│ Error: non-exhaustive case expression diff --git a/shared/src/test/diff/mlscript/Wildcards.mls b/shared/src/test/diff/mlscript/Wildcards.mls index ac96094c50..5ccbd132d8 100644 --- a/shared/src/test/diff/mlscript/Wildcards.mls +++ b/shared/src/test/diff/mlscript/Wildcards.mls @@ -210,7 +210,7 @@ f e //│ ╟── Note: constraint arises from type wildcard: //│ ║ l.196: def f: Expr[?] -> Expr[?] //│ ╙── ^ -//│ res: error | Expr[?] +//│ res: Expr[?] | error diff --git a/shared/src/test/diff/nu/Ascription.mls b/shared/src/test/diff/nu/Ascription.mls index 49b308b0b6..0b50f382cf 100644 --- a/shared/src/test/diff/nu/Ascription.mls +++ b/shared/src/test/diff/nu/Ascription.mls @@ -1,35 +1,38 @@ -:NewParser +:NewDefs 1: int -//│ res: int -//│ = 1 +//│ int +//│ res +//│ = 1 1 : int -//│ res: int -//│ = 1 +//│ int +//│ res +//│ = 1 // TODO? :e 1 : int : int //│ ╔══[ERROR] not a recognized type: int : int -//│ ║ l.13: 1 : int : int +//│ ║ l.15: 1 : int : int //│ ╙── ^^^ -//│ res: anything -//│ = 1 +//│ anything +//│ res +//│ = 1 fun foo(x: int) = x + 1 -//│ foo: (x: int,) -> int -//│ = [Function: foo] +//│ fun foo: (x: int,) -> int fun foo(x : int) = x + 1 -//│ foo: int -> int -//│ = [Function: foo1] +//│ fun foo: int -> int foo(123 : int) : int -//│ res: int -//│ = 124 +//│ int +//│ res +//│ = 124 foo(123:int):int -//│ res: int -//│ = 124 +//│ int +//│ res +//│ = 124 diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index dd732ef8ea..fa2265bed4 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -9,27 +8,27 @@ mixin M0(x: int) :e class C0 extends M0 //│ ╔══[ERROR] mixin M0 expects 1 parameters; got 0 -//│ ║ l.10: class C0 extends M0 -//│ ╙── ^^ +//│ ║ l.9: class C0 extends M0 +//│ ╙── ^^ //│ class C0() :e class C0 extends M0(1, 2) //│ ╔══[ERROR] mixin M0 expects 1 parameters; got 2 -//│ ║ l.17: class C0 extends M0(1, 2) +//│ ║ l.16: class C0 extends M0(1, 2) //│ ╙── ^^^^^^^ //│ class C0() :e class C0 extends M0(true) //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.24: class C0 extends M0(true) +//│ ║ l.23: class C0 extends M0(true) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.24: class C0 extends M0(true) +//│ ║ l.23: class C0 extends M0(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.6: mixin M0(x: int) +//│ ║ l.5: mixin M0(x: int) //│ ╙── ^^^ //│ class C0() diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/nu/ECOOP23.mls index da6c6ed339..7b1034087c 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/nu/ECOOP23.mls @@ -70,7 +70,7 @@ module TestLang extends EvalNothing, EvalAddLit //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ fun eval: (Add['lhs] | Lit | 'a & ~#Add & ~#Lit) -> (int | 'b) //│ } //│ module TestLang() { //│ fun eval: 'c -> int @@ -102,7 +102,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) //│ } @@ -154,7 +154,7 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: {eval: (Neg['A] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b +//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b //│ } // * Alternative: @@ -164,7 +164,7 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: {eval: (Neg['A] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b +//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b //│ } module TestLang extends EvalBase, EvalNeg, EvalNegNeg @@ -172,7 +172,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] //│ 'A <: 'a fun mk(n) = if n is @@ -186,7 +186,7 @@ fun mk(n) = if n is TestLang.eval //│ 'a -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] //│ 'A <: 'a TestLang.eval(mk(0)) diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/ECOOP23_codegen.mls index 385dabf866..e063431eae 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/ECOOP23_codegen.mls @@ -31,7 +31,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) //│ } @@ -43,7 +43,7 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: {eval: (Neg['A] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~Neg | Neg['expr])] | 'a & ~Neg) -> 'b +//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b //│ } @@ -52,7 +52,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ fun eval: 'a -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~Neg | Neg['a])] +//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] //│ 'A <: 'a diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls index 47dcd2bca8..ac8de9f7ef 100644 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ b/shared/src/test/diff/nu/ECOOP23_min.mls @@ -14,11 +14,11 @@ let e = Add(1, 1) e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α29 +//│ | 0. : α32 //│ ======== TYPED ======== -//│ res: Some(α29) where -//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) -//│ E23_30 :> 1 +//│ res: Some(α32) where +//│ α32 :> (Add & {Add#E: mut E26_33..E26_33}) +//│ E26_33 :> 1 //│ Add[1] e.lhs @@ -28,12 +28,12 @@ e.lhs e //│ 0. Typing TypingUnit(List(e)) //│ | 0. Typing term e -//│ | 0. : α29 +//│ | 0. : α32 //│ ======== TYPED ======== -//│ res: Some(α29) where -//│ α29 :> (Add<> & {Add#E: mut E23_30..E23_30}) <: {lhs: lhs35} -//│ E23_30 :> 1 <: lhs35 -//│ lhs35 :> 1 +//│ res: Some(α32) where +//│ α32 :> (Add & {Add#E: mut E26_33..E26_33}) <: {lhs: lhs38} +//│ E26_33 :> 1 <: lhs38 +//│ lhs38 :> 1 //│ Add[1] diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ECOOP23_repro.mls index cf87ecf48e..79aee81ecf 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ECOOP23_repro.mls @@ -121,7 +121,7 @@ mixin EvalNeg { //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~Neg) -> (int | 'b) +//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) //│ } diff --git a/shared/src/test/diff/nu/ECOOP23_small.mls b/shared/src/test/diff/nu/ECOOP23_small.mls index d78f05b6ed..19574fc37c 100644 --- a/shared/src/test/diff/nu/ECOOP23_small.mls +++ b/shared/src/test/diff/nu/ECOOP23_small.mls @@ -36,12 +36,12 @@ mixin EvalNeg { //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} //│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit | 'a & ~Add & ~Lit) -> (int | 'b) +//│ fun eval: (Add['lhs] | Lit | 'a & ~#Add & ~#Lit) -> (int | 'b) //│ } //│ mixin EvalNeg() { //│ super: {eval: 'c -> 'd} //│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'c & ~Neg) -> (int | 'd) +//│ fun eval: (Neg['expr] | 'c & ~#Neg) -> (int | 'd) //│ } module TestLang extends EvalNothing, EvalAddLit, EvalNeg diff --git a/shared/src/test/diff/nu/Eql.mls b/shared/src/test/diff/nu/Eql.mls new file mode 100644 index 0000000000..101cdff4d7 --- /dev/null +++ b/shared/src/test/diff/nu/Eql.mls @@ -0,0 +1,224 @@ +:NewDefs + + +let x: Eql[int] +//│ let x: Eql[int] +//│ x +//│ = + +x === 1 +//│ bool +//│ res +//│ = +//│ x is not implemented + +:e +1 === x +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.16: 1 === x +//│ ║ ^^^^^^^ +//│ ╟── type `#Eql & {Eql#A :> int}` is not an instance of type `number` +//│ ║ l.4: let x: Eql[int] +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into reference with expected type `number` +//│ ║ l.16: 1 === x +//│ ╙── ^ +//│ bool | error +//│ res +//│ = +//│ x is not implemented + +:e +x === x +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.32: x === x +//│ ║ ^^^^^^^ +//│ ╟── type `#Eql & {Eql#A :> int}` is not an instance of type `int` +//│ ║ l.4: let x: Eql[int] +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into reference with expected type `int` +//│ ║ l.32: x === x +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.4: let x: Eql[int] +//│ ╙── ^^^ +//│ bool | error +//│ res +//│ = +//│ x is not implemented + + +fun test1(x) = + x === x +//│ fun test1: (Eql['a] & 'a) -> bool + +fun test2(x, y) = + x === y +//│ fun test2: (Eql['a], 'a,) -> bool + + +1 : Eql['a] +//│ Eql[number] +//│ res +//│ = 1 + +1 : Eql[int] +//│ Eql[int] +//│ res +//│ = 1 + +1 : Eql[1] +//│ Eql[1] +//│ res +//│ = 1 + +test1(1) +//│ bool +//│ res +//│ = true + + +let n: int = 1 +//│ let n: int +//│ n +//│ = 1 + +n : Eql['a] +//│ Eql[number] +//│ res +//│ = 1 + +test1(n) +//│ bool +//│ res +//│ = true + + +let n: number +//│ let n: number +//│ n +//│ = + +test1(n) +//│ bool +//│ res +//│ = +//│ n is not implemented + +let d = 1/2 +//│ let d: number +//│ d +//│ = 0.5 + +test1(d) +//│ bool +//│ res +//│ = true + +test1("hello") +//│ bool +//│ res +//│ = true + + +test2(0, 1) +//│ bool +//│ res +//│ = false + +test2(0, d) +//│ bool +//│ res +//│ = false + +x => test2(0, x) +//│ number -> bool +//│ res +//│ = [Function: res] + +x => test2(x, 0) +//│ Eql[0] -> bool +//│ res +//│ = [Function: res] + +x => test2(d, x) +//│ number -> bool +//│ res +//│ = [Function: res] + +x => test2(x, d) +//│ Eql[number] -> bool +//│ res +//│ = [Function: res] + + +:e +test2(1, "oops") +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.156: test2(1, "oops") +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── string literal of type `"oops"` is not an instance of type `number` +//│ ║ l.156: test2(1, "oops") +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.56: x === y +//│ ╙── ^ +//│ bool | error +//│ res +//│ = false + +:e +test2("oops", 1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.171: test2("oops", 1) +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── integer literal of type `1` is not an instance of type `string` +//│ ║ l.171: test2("oops", 1) +//│ ║ ^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.56: x === y +//│ ╙── ^ +//│ bool | error +//│ res +//│ = false + +:e +test2(1, {}) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.186: test2(1, {}) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── record literal of type `anything` is not an instance of type `number` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.56: x === y +//│ ╙── ^ +//│ bool | error +//│ res +//│ = false + +:e +test2({}, 1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.199: test2({}, 1) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── record literal of type `anything` is not an instance of type `Eql` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.56: x === y +//│ ╙── ^ +//│ bool | error +//│ res +//│ = false + +:e +test2({}, {}) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.212: test2({}, {}) +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── record literal of type `anything` is not an instance of type `Eql` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.56: x === y +//│ ╙── ^ +//│ bool | error +//│ res +//│ = false + + diff --git a/shared/src/test/diff/nu/EqlClasses.mls b/shared/src/test/diff/nu/EqlClasses.mls new file mode 100644 index 0000000000..041defb51e --- /dev/null +++ b/shared/src/test/diff/nu/EqlClasses.mls @@ -0,0 +1,161 @@ +:NewDefs + + + +module Mod +//│ module Mod() + +Mod === Mod +//│ bool +//│ res +//│ = true + + +class Cls1() +//│ class Cls1() + +Cls1() === Cls1() +//│ bool +//│ res +//│ = false + + +class Cls2(x: int) +//│ class Cls2(x: int) + +Cls2(0) === Cls2(1) +//│ bool +//│ res +//│ = false + + + +class Pair[A](fst: A, snd: A) +// extends (A <: Eql[A]) => Eql[Pair[A]] +//│ class Pair[A](fst: A, snd: A) + +let p = Pair(1, 2) +//│ let p: Pair[1 | 2] +//│ p +//│ = Pair {} + +p === p +//│ bool +//│ res +//│ = true + + +x => p === x +//│ {fst: Eql[1 | 2], snd: Eql[1 | 2]} -> bool +//│ res +//│ = [Function: res] + +x => x === p +//│ Eql[Pair[1 | 2]] -> bool +//│ res +//│ = [Function: res] + +p === { fst: 1, snd: 2 } +//│ bool +//│ res +//│ = false + +:e +{ fst: 1, snd: 2 } === p +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.64: { fst: 1, snd: 2 } === p +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── record literal of type `{fst: 1, snd: 2}` is not an instance of type `Eql` +//│ ║ l.64: { fst: 1, snd: 2 } === p +//│ ╙── ^^^^^^^^^ +//│ bool | error +//│ res +//│ = false + +let r = {x: 42, y: y => y} +//│ let r: {x: 42, y: forall 'a. 'a -> 'a} +//│ r +//│ = { x: 42, y: [Function: y] } + +r : {x: int} +//│ {x: int} +//│ res +//│ = { x: 42, y: [Function: y] } + + +:e +x => { a: 0 } === x +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.87: x => { a: 0 } === x +//│ ║ ^^^^^^^^^^^^ +//│ ╟── record literal of type `{a: 0}` is not an instance of type `Eql` +//│ ║ l.87: x => { a: 0 } === x +//│ ╙── ^ +//│ anything -> (bool | error) +//│ res +//│ Syntax error: +//│ Unexpected token '===' + +x => x === { a: 0 } +//│ Eql[{a: 0}] -> bool +//│ res +//│ = [Function: res] + + + +let q = Pair(1, "oops") +//│ let q: Pair["oops" | 1] +//│ q +//│ = Pair {} + +:e +q === q +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.112: q === q +//│ ║ ^^^^^^^ +//│ ╟── integer literal of type `1` is not an instance of type `string` +//│ ║ l.106: let q = Pair(1, "oops") +//│ ╙── ^ +//│ bool | error +//│ res +//│ = true + + +class Pair2[A, B](fst: A, snd: B) +//│ class Pair2[A, B](fst: A, snd: B) + +let q = Pair2(1, "oops") +//│ let q: Pair2[1, "oops"] +//│ q +//│ = Pair2 {} + +q === q +//│ bool +//│ res +//│ = true + + + + +// *** NOTES *** + +// * Intended type for comparing Cons: +// Eql[Cons & { head: Eql['h], tail: Eql['t] } | ~Cons & List] + + +// * Original code +// x: Int +// y: Int +// x == y + +// * Refactored code (we want an error) +// x: Option[Int] +// y: Int +// x == y +// --> +// x.exists(_ == y) + +// * Should not be equatable: +// Int | Option[Int] + + diff --git a/shared/src/test/diff/nu/FunSigs.mls b/shared/src/test/diff/nu/FunSigs.mls index cc5c35ebc5..c6ade5fc26 100644 --- a/shared/src/test/diff/nu/FunSigs.mls +++ b/shared/src/test/diff/nu/FunSigs.mls @@ -1,38 +1,34 @@ -:NewParser +:NewDefs fun log(msg: string): unit -//│ log: (msg: string,) -> unit -//│ = +//│ fun log: (msg: string,) -> unit let f = log("ok") 123 -//│ f: 123 -//│ = -//│ log is not implemented +//│ let f: 123 +//│ f +//│ = +//│ log is not implemented fun log: string -> unit -//│ log: string -> unit -//│ = +//│ fun log: string -> unit fun log: string => unit -//│ log: string -> unit -//│ = +//│ fun log: string -> unit log("ok") -//│ = -//│ log is not implemented +//│ unit +//│ res +//│ = +//│ log is not implemented fun con: string => string => string -//│ con: string -> string -> string -//│ = +//│ fun con: string -> string -> string fun con = concat -//│ string -> string -> string -//│ <: con: -//│ string -> string -> string -//│ = [Function: con] +//│ fun con: string -> string -> string diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 0d31fca36a..b5a001e02e 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -1,6 +1,6 @@ :NewParser :NewDefs -:NoJS +:NoJS // TODO class C
@@ -30,11 +30,13 @@ f(c) class Some(value: A) { fun get = value fun toArray = [value] - // fun mapBad(f) = Some(f(value)) // TODO cyclic - // fun map(f : A => 'b) = Some(f(value)) // TODO cyclic + fun map(f) = Some(f(value)) + fun map_A(f : A => 'b) = Some(f(value)) } //│ class Some[A](value: A) { //│ fun get: A +//│ fun map: (A -> 'A) -> Some['A] +//│ fun map_A: (A -> 'A0) -> Some['A0] //│ fun toArray: (A,) //│ } @@ -53,26 +55,31 @@ s.toArray //│ (1,) -// TODO - -// s.mapBad +s.map +//│ (1 -> 'A) -> Some['A] -// s.mapBad(succ) +s.map(succ) +//│ Some[int] -// s.map +s.map_A +//│ (1 -> 'A) -> Some['A] -// s.map(succ) +s.map_A(succ) +//│ Some[int] module None { fun get = error fun toArray = [] - // fun mapBad(f) = None // TODO + fun map(f) = None + fun map_A(f: nothing -> anything) = None } //│ module None() { //│ fun get: nothing +//│ fun map: anything -> None +//│ fun map_A: (f: nothing -> anything,) -> None //│ fun toArray: () //│ } @@ -93,11 +100,14 @@ opt.toArray //│ Array[123] -// TODO +opt.map(succ) +//│ None | Some[int] -// opt.mapBad(succ) +opt.map_A(succ) +//│ None | Some[int] -// opt.map(succ) +opt.map(x => x > 0) +//│ None | Some[bool] @@ -127,7 +137,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.125: class Test(n) { +//│ ║ l.135: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -147,13 +157,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.147: fun foo = n + 1 +//│ ║ l.157: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.147: fun foo = n + 1 +//│ ║ l.157: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.146: class Test(n: A) { +//│ ║ l.156: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int @@ -210,13 +220,13 @@ class TestBad { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.210: fun foo2(x: A) = x + 1 +//│ ║ l.220: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.210: fun foo2(x: A) = x + 1 +//│ ║ l.220: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.208: class TestBad { +//│ ║ l.218: class TestBad { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 56f28e9b80..41daeeec7f 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -10,11 +10,11 @@ mixin BaseTest { //│ ╔══[ERROR] type identifier not found: A //│ ║ l.8: fun test(x: A) = x //│ ╙── ^ -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A26' +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A29' // TODO support mixin BaseTest(x: A) { fun test = x } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A31_38' +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A34_41' diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index 92cf1c2559..a1732a5d63 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -1,110 +1,126 @@ -:NewParser +:NewDefs 1 -//│ res: 1 -//│ = 1 +//│ 1 +//│ res +//│ = 1 2 + 2 -//│ res: int -//│ = 4 +//│ int +//│ res +//│ = 4 let r = { x: 1 } -//│ r: {x: 1} -//│ = { x: 1 } +//│ let r: {x: 1} +//│ r +//│ = { x: 1 } r.x + 1 -//│ res: int -//│ = 2 +//│ int +//│ res +//│ = 2 x => x + 1 -//│ res: int -> int -//│ = [Function: res] +//│ int -> int +//│ res +//│ = [Function: res] { y } => y -//│ res: {y: 'a} -> 'a -//│ = [Function: res] +//│ {y: 'a} -> 'a +//│ res +//│ = [Function: res] fun f({ y }) = y -//│ f: {y: 'a} -> 'a -//│ = [Function: f] +//│ fun f: {y: 'a} -> 'a fun f of { y } = y -//│ f: {y: 'a} -> 'a -//│ = [Function: f1] +//│ fun f: {y: 'a} -> 'a f({y: 1}) -//│ res: 1 -//│ = 1 +//│ 1 +//│ res +//│ = 1 let f = (x, y) => x + y -//│ f: (int, int,) -> int -//│ = [Function: f2] +//│ let f: (int, int,) -> int +//│ f +//│ = [Function: f2] f(1, 2) -//│ res: int -//│ = 3 +//│ int +//│ res +//│ = 3 :e f([1, 2]) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.51: f([1, 2]) +//│ ║ l.58: f([1, 2]) //│ ║ ^^^^^^^^^ //│ ╟── argument of type `((1, 2,),)` does not match type `(?a, ?b,)` -//│ ║ l.51: f([1, 2]) +//│ ║ l.58: f([1, 2]) //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.42: let f = (x, y) => x + y +//│ ║ l.47: let f = (x, y) => x + y //│ ╙── ^^^^ -//│ res: error | int -//│ = '1,2undefined' +//│ error | int +//│ res +//│ = '1,2undefined' let f = ((x, y)) => x + y -//│ f: (int, int,) -> int -//│ = [Function: f3] +//│ let f: (int, int,) -> int +//│ f +//│ = [Function: f3] :e f(1, 2) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.71: f(1, 2) +//│ ║ l.80: f(1, 2) //│ ║ ^^^^^^^ //│ ╟── argument list of type `(1, 2,)` does not match type `((?a, ?b,),)` -//│ ║ l.71: f(1, 2) +//│ ║ l.80: f(1, 2) //│ ╙── ^^^^^^ -//│ res: error | int +//│ error | int +//│ res //│ Runtime error: //│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) f((1, 2)) -//│ res: int -//│ = 3 +//│ int +//│ res +//│ = 3 f([1, 2]) -//│ res: int -//│ = 3 +//│ int +//│ res +//│ = 3 let f = (((x, y))) => x + y -//│ f: (int, int,) -> int -//│ = [Function: f4] +//│ let f: (int, int,) -> int +//│ f +//│ = [Function: f4] // TODO parse as tuple arg! let f = [x, y] => x + y -//│ f: (int, int,) -> int -//│ = [Function: f5] +//│ let f: (int, int,) -> int +//│ f +//│ = [Function: f5] f(1, 2) -//│ res: int -//│ = 3 +//│ int +//│ res +//│ = 3 // TODO... let f = [[[x, y]]] => x + y -//│ f: (int, int,) -> int -//│ = [Function: f6] +//│ let f: (int, int,) -> int +//│ f +//│ = [Function: f6] diff --git a/shared/src/test/diff/nu/Mut.mls b/shared/src/test/diff/nu/Mut.mls index 00e6299c5b..0bb919b622 100644 --- a/shared/src/test/diff/nu/Mut.mls +++ b/shared/src/test/diff/nu/Mut.mls @@ -1,4 +1,4 @@ -:NewParser +:NewDefs :pe @@ -6,117 +6,102 @@ let v1: {mut 1} //│ ╔══[PARSE ERROR] Record field should have a name //│ ║ l.5: let v1: {mut 1} //│ ╙── ^ -//│ v1: {mut : 1} -//│ = +//│ let v1: {mut : 1} +//│ v1 +//│ = let v1: {mut int} -//│ v1: {mut int: int} -//│ = +//│ let v1: {mut int: int} +//│ v1 +//│ = let v1 = {mut int: 0} -//│ {mut int: 'int} +//│ let v1: {mut int: 'int} //│ where //│ 'int :> 0 -//│ <: v1: -//│ {mut int: int} -//│ = { int: 0 } +//│ v1 +//│ = { int: 0 } let v1: {mut x: int} -//│ v1: {mut x: int} -//│ = +//│ let v1: {mut x: int} +//│ v1 +//│ = :pe -:e let v1 = {mut 1} //│ ╔══[PARSE ERROR] Record field should have a name -//│ ║ l.31: let v1 = {mut 1} +//│ ║ l.32: let v1 = {mut 1} //│ ╙── ^ -//│ {mut : '} +//│ let v1: {mut : '} //│ where //│ ' :> 1 -//│ <: v1: -//│ {mut x: int} -//│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.31: let v1 = {mut 1} -//│ ║ ^^^^^^^^^^^^ -//│ ╟── record literal of type `{mut : ?}` does not have field 'x' -//│ ║ l.31: let v1 = {mut 1} -//│ ║ ^ -//│ ╟── Note: constraint arises from record type: -//│ ║ l.25: let v1: {mut x: int} -//│ ╙── ^^^^^^^^^^^^ -//│ = { '': 1 } +//│ v1 +//│ = { '': 1 } let v1 = {mut x: 1} -//│ {mut x: 'x} +//│ let v1: {mut x: 'x} //│ where //│ 'x :> 1 -//│ <: v1: -//│ {mut x: int} -//│ = { x: 1 } +//│ v1 +//│ = { x: 1 } // * TODO: support this syntax? :pe v1.x = 1 //│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.61: v1.x = 1 +//│ ║ l.51: v1.x = 1 //│ ╙── ^ -//│ res: int -//│ = 1 +//│ 1 +//│ res +//│ = 1 // * TODO: support this syntax? :e :ng v1.x <- 1 //│ ╔══[ERROR] identifier not found: <- -//│ ║ l.71: v1.x <- 1 +//│ ║ l.62: v1.x <- 1 //│ ╙── ^^ -//│ res: error +//│ error let v2: (mut int) -//│ v2: (mut int,) -//│ = +//│ let v2: (mut int,) +//│ v2 +//│ = let v2 = (mut 1) -//│ (mut 'a,) +//│ let v2: (mut 'a,) //│ where //│ 'a :> 1 -//│ <: v2: -//│ (mut int,) -//│ = [ 1 ] +//│ v2 +//│ = [ 1 ] let v2: (mut x: int) -//│ v2: (mut x: int,) -//│ = +//│ let v2: (mut x: int,) +//│ v2 +//│ = let v2 = (mut 1) -//│ (mut 'a,) +//│ let v2: (mut 'a,) //│ where //│ 'a :> 1 -//│ <: v2: -//│ (mut x: int,) -//│ = [ 1 ] +//│ v2 +//│ = [ 1 ] let v2 = (mut x: 1) -//│ (mut x: 'x,) +//│ let v2: (mut x: 'x,) //│ where //│ 'x :> 1 -//│ <: v2: -//│ (mut x: int,) -//│ = [ 1 ] +//│ v2 +//│ = [ 1 ] -:e let v2 = (mut y: 1) -//│ (mut y: 'y,) +//│ let v2: (mut y: 'y,) //│ where //│ 'y :> 1 -//│ <: v2: -//│ (mut x: int,) -//│ ╔══[ERROR] Wrong tuple field name: found 'y' instead of 'x' -//│ ║ l.111: let v2 = (mut y: 1) -//│ ╙── ^ -//│ = [ 1 ] +//│ v2 +//│ = [ 1 ] diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index de4e508930..6083210641 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -206,3 +206,14 @@ Test2_1.d Test2_1.n //│ 456 + +// FIXME where does the throw come from? +// :s +class Test2(n: int) { + fun inc = Test3.inc(this) +} +module Test3 { + fun inc(t: Test2) = Test2(t.n + 1) +} +//│ /!!!\ Uncaught error: mlscript.ErrorReport: Unhandled cyclic definition + diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index 953ac86b93..2288b313c6 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -1,41 +1,48 @@ -:NewParser +:NewDefs class Foo(x: int) -//│ Defined class Foo -//│ Foo: (x: int,) -> Foo -//│ = [Function: Foo1] +//│ class Foo(x: int) Foo(1) -//│ res: Foo -//│ = Foo { x: 1 } +//│ Foo +//│ res +//│ = Foo {} Foo(x: 1) -//│ res: Foo -//│ = Foo { x: 1 } +//│ Foo +//│ res +//│ = Foo {} -// :e // TODO check parameter name matches Foo(y: 1) -//│ res: Foo -//│ = Foo { x: 1 } +//│ Foo +//│ res +//│ = Foo {} -// TODO: Here `x` is not currently treated as a field name +:e // TODO: Here `x` is not currently treated as a field name class Bar(x) -//│ Defined class Bar -//│ Bar: 'x -> (Bar & {x: 'x}) -//│ = [Function: Bar1] +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.24: class Bar(x) +//│ ╙── ^ +//│ class Bar(x: error) Bar(1) -//│ res: Bar & {x: 1} -//│ = Bar { x: 1 } +//│ Bar +//│ res +//│ = Bar {} Bar(x: 1) -//│ res: Bar & {x: 1} -//│ = Bar { x: 1 } +//│ Bar +//│ res +//│ = Bar {} -// :e +:e Bar(y: 1) -//│ res: Bar & {x: 1} -//│ = Bar { x: 1 } +//│ ╔══[ERROR] Wrong tuple field name: found 'y' instead of 'x' +//│ ║ l.41: Bar(y: 1) +//│ ╙── ^^^^^^ +//│ Bar | error +//│ res +//│ = Bar {} diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls index d1d1d4c178..6f32b10224 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls @@ -79,7 +79,7 @@ mixin EvalLambda { //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b,) -> 'c} //│ this: {eval: (Cons[(string, 'd,)], 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[(string, Var,) | 'A], 't1,) -> 'f} -//│ fun eval: ('a & (Cons['A] | Nil), Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'b & ~Abs & ~App,) -> (Abs['f] | App['d | 'e] | 'c) +//│ fun eval: ('a & (Cons['A] | Nil), Abs['t1] | App['t0 & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['f] | App['d | 'e] | 'c) //│ } module Test1 extends EvalVar, EvalLambda @@ -87,8 +87,8 @@ module Test1 extends EvalVar, EvalLambda //│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> 'result //│ } //│ where -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | Var -//│ 'result :> Var | App['result] | Abs['result] +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | Var +//│ 'result :> Var | Abs['result] | App['result] Test1.eval(Nil, Var("a")) //│ 'a @@ -114,7 +114,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] +//│ 'a :> Abs['a] | Abs[Var] | Var | App['a] //│ res //│ = Var {} @@ -204,7 +204,7 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ 'result :> App['result] | Abs['result] | Num | Var | 'b //│ 'b <: Add['c] | Mul['c] | Num | Var //│ 'c <: 'a -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | 'b & ~Abs & ~App +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | 'b & ~#Abs & ~#App Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ 'a diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls index f7704aee40..0f8292fce5 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls +++ b/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls @@ -97,7 +97,7 @@ mixin EvalLambda { //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c,) -> 'd} //│ this: {eval: (List[out (string, 'e,)], 't,) -> 'd & ('b, 't0,) -> ('e & 'f) & (List[in 'a out 'a | 'a0 | (string, Var,)], 't1,) -> 'g} -//│ fun eval: (List['a1] & 'b, Abs['t1] | App['t0 & (Abs['t] | ~Abs)] | 'c & ~Abs & ~App,) -> (Abs['g] | App['e | 'f] | 'd) +//│ fun eval: (List['a1] & 'b, Abs['t1] | App['t0 & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) //│ } //│ where //│ 'a1 :> 'a | (string, Var,) @@ -108,13 +108,13 @@ module Test1 extends EvalVar, EvalLambda //│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> 'result //│ } //│ where -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | Var +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | Var //│ 'result :> anything Test1.eval(Nil(), Var("a")) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'a :> Var | App['a] | Abs['a] Test1.eval(Nil(), Abs("b", Var("a"))) //│ 'a @@ -187,7 +187,7 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> anything //│ } //│ where -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~Abs)] | (Add['b] | Mul['b] | Num | Var) & ~Abs & ~App +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | (Add['b] | Mul['b] | Num | Var) & ~#Abs & ~#App //│ 'b <: 'a //│ 'result :> anything //│ <: Num @@ -200,7 +200,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var +//│ 'a :> Abs[Var] | Add[Num | Var] | Num | Var | App['a] | Abs['a] module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls index f05f438bbd..44db753336 100644 --- a/shared/src/test/diff/nu/OverrideShorthand.mls +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -24,7 +24,7 @@ mixin Test { } //│ mixin Test() { //│ super: {f: 'a -> 'b} -//│ fun f: (Pair | 'a & ~Pair) -> (int | 'b) +//│ fun f: (Pair | 'a & ~#Pair) -> (int | 'b) //│ } diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls new file mode 100644 index 0000000000..f1d8c0af1e --- /dev/null +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -0,0 +1,59 @@ +:NewDefs + + + +// TODO use available type signatures! +class Foo1(x: int) { + fun test = Foo1(1).x +} +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.7: fun test = Foo1(1).x +//│ ╙── ^^ +//│ class Foo1(x: int) { +//│ fun test: error +//│ } + +// TODO +class Foo2[A](x: A) { + fun test = Foo2(1).x +} +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.18: fun test = Foo2(1).x +//│ ╙── ^^ +//│ class Foo2[A](x: A) { +//│ fun test: error +//│ } + + +// * FIXME 'A 'A0 A +class Foo3[A](x: A) { + fun test = Foo3(1) + fun foo = Foo3 +} +//│ class Foo3[A](x: A) { +//│ fun foo: forall 'A 'A0. (x: A,) -> Foo3['A] +//│ fun test: Foo3[1] +//│ } + +// * FIXME `nothing` +Foo3 +//│ forall 'A. (x: A,) -> Foo3[nothing] +//│ res +//│ = [Function (anonymous)] { class: [class Foo3] } + +Foo3(1) +//│ Foo3[1] +//│ res +//│ = Foo3 {} + +Foo3(1).x +//│ 1 +//│ res +//│ = 1 + +Foo3(1).foo +//│ forall 'A. (x: A,) -> Foo3[nothing] +//│ res +//│ = [Function (anonymous)] { class: [class Foo3] } + + diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/nu/SimpleRegionDSL.mls index 11fe51a855..a5ca500582 100644 --- a/shared/src/test/diff/nu/SimpleRegionDSL.mls +++ b/shared/src/test/diff/nu/SimpleRegionDSL.mls @@ -77,7 +77,7 @@ mixin SizeExt { //│ mixin SizeExt() { //│ super: {size: 'b -> 'c} //│ this: {size: 'a -> int} -//│ fun size: (Empty | Scale['a] | Univ | 'b & ~Empty & ~Scale & ~Univ) -> (int | 'c) +//│ fun size: (Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ) -> (int | 'c) //│ } module TestSize extends SizeBase, SizeExt @@ -313,7 +313,7 @@ mixin Eliminate { } //│ mixin Eliminate() { //│ this: {eliminate: 'a -> 'b & 'a0 -> 'c & 'a1 -> 'd & 'a2 -> 'e & 'a3 -> 'f & 'a4 -> 'g} -//│ fun eliminate: (Intersect['a2] | Outside['a0 & (Outside['a] | ~Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'h & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union) -> (Intersect['e] | Outside['c] | Scale['g] | Translate['f] | Union['d] | 'b | 'h) +//│ fun eliminate: (Intersect['a2] | Outside['a0 & (Outside['a] | ~#Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> (Intersect['e] | Outside['c] | Scale['g] | Translate['f] | Union['d] | 'b | 'h) //│ } module TestElim extends Eliminate @@ -321,13 +321,13 @@ module TestElim extends Eliminate //│ fun eliminate: 'a -> 'b //│ } //│ where -//│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union +//│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~#Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union //│ 'b :> Outside['b] | Union['b] | Intersect['b] | Translate['b] | Scale['b] TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where -//│ 'a :> Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ 'a :> Scale['a] | Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] //│ res //│ = Univ {} @@ -375,8 +375,8 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ 'Region <: 'f //│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~Intersect & ~Outside & ~Scale & ~Translate & ~Union -//│ 'c :> Union['c] | Intersect['c] | Translate['c] | Scale['c] | Outside['c] +//│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~#Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] // TODO investigate diff --git a/shared/src/test/diff/typegen/TypegenTerms.mls b/shared/src/test/diff/typegen/TypegenTerms.mls index 9400551044..cfa6f9b1bd 100644 --- a/shared/src/test/diff/typegen/TypegenTerms.mls +++ b/shared/src/test/diff/typegen/TypegenTerms.mls @@ -66,7 +66,7 @@ rec def l (a: int) = l rec def m (a: int) (b: int) = m def f: ('c -> 'a as 'a) -> 'c -> int // recursion type functions -//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α108,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))))),α108),Top))) List() +//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α111,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))))),α111),Top))) List() :ts :e @@ -152,6 +152,6 @@ def weird: ((int, int) -> 'a) as 'a def weird: ('a -> (int, int)) as 'a def weird: ((int, 'a) as 'a) -> int def weird: ((int, bool) | 'a) -> 'a -//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α231,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))), (None,Field(None,TypeName(int))))),α231),Top))) List() +//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α234,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))), (None,Field(None,TypeName(int))))),α234),Top))) List() diff --git a/shared/src/test/diff/typegen/TypegenTypedefs.mls b/shared/src/test/diff/typegen/TypegenTypedefs.mls index 6b4952c993..5e67baf638 100644 --- a/shared/src/test/diff/typegen/TypegenTypedefs.mls +++ b/shared/src/test/diff/typegen/TypegenTypedefs.mls @@ -29,6 +29,7 @@ class StackedRectangleBoxes[T, N]: RectangleBox[T] & { size: N } //│ // end ts +// FIXME :ts class Lock[T]: { pins: T } method Map: (T -> 'a) -> Lock['a] @@ -71,6 +72,7 @@ let lockA = Lock 20 in let lockB = Lock 30 in (Bank lockA 2000).Better(Bank lock //│ // end ts +// FIXME :ts class None: {} class Some[T]: { value: T } @@ -189,18 +191,18 @@ class Arg[T]: (T, T) class Prog[T] method Run: Arg[T] -> number //│ ╔══[ERROR] cannot inherit from a tuple type -//│ ║ l.188: class Arg[T]: (T, T) +//│ ║ l.190: class Arg[T]: (T, T) //│ ╙── ^^^^^^^^^^^^^^ //│ ╔══[ERROR] type identifier not found: Arg -//│ ║ l.190: method Run: Arg[T] -> number +//│ ║ l.192: method Run: Arg[T] -> number //│ ╙── ^^^^^^ //│ Defined class Prog[±T] //│ Declared Prog.Run: Prog[?] -> error -> number //│ ╔══[WARNING] Type definition Prog has bivariant type parameters: -//│ ║ l.189: class Prog[T] +//│ ║ l.191: class Prog[T] //│ ║ ^^^^ //│ ╟── T is irrelevant and may be removed -//│ ║ l.189: class Prog[T] +//│ ║ l.191: class Prog[T] //│ ╙── ^ //│ // start ts //│ export declare class Prog { diff --git a/shared/src/test/diff/ucs/MultiwayIf.mls b/shared/src/test/diff/ucs/MultiwayIf.mls index 41e93b4ada..6a59d9b55d 100644 --- a/shared/src/test/diff/ucs/MultiwayIf.mls +++ b/shared/src/test/diff/ucs/MultiwayIf.mls @@ -24,9 +24,6 @@ fun f(x) = //│ ╟── The first else branch was declared here. //│ ║ l.18: _ then false //│ ╙── ^^^^^ -//│ ╔══[ERROR] identifier not found: === -//│ ║ l.17: x % 2 === 0 then true -//│ ╙── ^^^ //│ f: int -> bool //│ = [Function: f1] @@ -39,14 +36,11 @@ fun f(x) = x == 0 then true else false //│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.40: else false +//│ ║ l.37: else false //│ ║ ^^^^^ //│ ╟── The first else branch was declared here. -//│ ║ l.38: else false +//│ ║ l.35: else false //│ ╙── ^^^^^ -//│ ╔══[ERROR] identifier not found: === -//│ ║ l.37: x % 2 === 0 then true -//│ ╙── ^^^ //│ f: int -> bool //│ = [Function: f2] diff --git a/shared/src/test/diff/ucs/SimpleUCS.mls b/shared/src/test/diff/ucs/SimpleUCS.mls index ab573e45e0..929d3111e4 100644 --- a/shared/src/test/diff/ucs/SimpleUCS.mls +++ b/shared/src/test/diff/ucs/SimpleUCS.mls @@ -210,7 +210,7 @@ fun f(x) = Some(x) then "roll" _ and x == 0 then 0 _ then "rock" -//│ f: (None | number | Some) -> ("bruh" | "rock" | "roll" | 0) +//│ f: (None | Some | number) -> ("bruh" | "rock" | "roll" | 0) //│ = [Function: f13] fun f(x, a, b) = diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 0c825266a0..3677e04068 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -213,7 +213,7 @@ class DiffTests case "AllowRuntimeErrors" => allowRuntimeErrors = true; mode case "ShowRelativeLineNums" => showRelativeLineNums = true; mode case "NewParser" => newParser = true; mode - case "NewDefs" => newDefs = true; mode + case "NewDefs" => newParser = true; newDefs = true; mode case "NoJS" => noJavaScript = true; mode case "NoProvs" => noProvs = true; mode case "GeneralizeCurriedFunctions" => generalizeCurriedFunctions = true; mode From b33d4bca298e58d28539e97ec2492f5ab0e70ae8 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 11 Mar 2023 13:30:15 +0800 Subject: [PATCH 168/498] WIP Update and reorganize tests --- .../src/main/scala/mlscript/NewParser.scala | 2 +- .../ExpressionProblem.mls} | 42 +++++-- .../ECOOP23_intro.mls => ecoop23/Intro.mls} | 0 .../PolymorphicVariants.mls} | 0 .../diff/{nu => ecoop23}/SimpleRegionDSL.mls | 0 shared/src/test/diff/nu/Andong.mls | 1 - shared/src/test/diff/nu/BadAliases.mls | 31 +++-- shared/src/test/diff/nu/BadSuper.mls | 5 +- .../test/diff/nu/BasicClassInheritance.mls | 10 +- shared/src/test/diff/nu/BasicClasses.mls | 60 ++++++++-- shared/src/test/diff/nu/BasicMixins.mls | 47 ++++---- shared/src/test/diff/nu/ClassField.mls | 9 +- shared/src/test/diff/nu/ClassSignatures.mls | 5 +- shared/src/test/diff/nu/ClassesInMixins.mls | 13 +-- shared/src/test/diff/nu/ECOOP23_min.mls | 43 ------- shared/src/test/diff/nu/EncodedLists.mls | 7 +- .../{ECOOP23_codegen.mls => EvalNegNeg.mls} | 2 +- shared/src/test/diff/nu/ExplicitVariance.mls | 13 +-- ..._repro.mls => ExpressionProblem_repro.mls} | 3 - ..._small.mls => ExpressionProblem_small.mls} | 1 - shared/src/test/diff/nu/FilterMap.mls | 17 ++- shared/src/test/diff/nu/FunPatterns.mls | 7 +- shared/src/test/diff/nu/GADTMono.mls | 5 +- shared/src/test/diff/nu/GenericClasses.mls | 108 ++++++++++++++++-- shared/src/test/diff/nu/GenericMethods.mls | 37 ++++-- shared/src/test/diff/nu/GenericMixins.mls | 4 +- shared/src/test/diff/nu/GenericModules.mls | 23 ++-- shared/src/test/diff/nu/LetRec.mls | 2 - shared/src/test/diff/nu/ListConsNil.mls | 1 - shared/src/test/diff/nu/MetaWrap.mls | 1 - shared/src/test/diff/nu/MixinParameters.mls | 3 +- shared/src/test/diff/nu/ModuleParameters.mls | 3 +- shared/src/test/diff/nu/MutualRec.mls | 13 +-- shared/src/test/diff/nu/NestedClasses.mls | 7 +- shared/src/test/diff/nu/NuScratch.mls | 1 - shared/src/test/diff/nu/OverrideShorthand.mls | 17 +-- shared/src/test/diff/nu/ParamOverride.mls | 5 +- shared/src/test/diff/nu/ParamOverriding.mls | 6 +- shared/src/test/diff/nu/ParamPassing.mls | 5 +- ...Reuse2.mls => PolymorphicVariants_Alt.mls} | 1 - .../src/test/diff/nu/ThisRefinedClasses.mls | 14 +-- shared/src/test/diff/nu/TypeAliases.mls | 3 +- shared/src/test/diff/nu/TypingUnitTerms.mls | 5 +- shared/src/test/diff/nu/With.mls | 3 +- 44 files changed, 343 insertions(+), 242 deletions(-) rename shared/src/test/diff/{nu/ECOOP23.mls => ecoop23/ExpressionProblem.mls} (85%) rename shared/src/test/diff/{nu/ECOOP23_intro.mls => ecoop23/Intro.mls} (100%) rename shared/src/test/diff/{nu/NewPolyVariantCodeReuse.mls => ecoop23/PolymorphicVariants.mls} (100%) rename shared/src/test/diff/{nu => ecoop23}/SimpleRegionDSL.mls (100%) delete mode 100644 shared/src/test/diff/nu/ECOOP23_min.mls rename shared/src/test/diff/nu/{ECOOP23_codegen.mls => EvalNegNeg.mls} (99%) rename shared/src/test/diff/nu/{ECOOP23_repro.mls => ExpressionProblem_repro.mls} (99%) rename shared/src/test/diff/nu/{ECOOP23_small.mls => ExpressionProblem_small.mls} (99%) rename shared/src/test/diff/nu/{NewPolyVariantCodeReuse2.mls => PolymorphicVariants_Alt.mls} (99%) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 32bbf17998..cc1c150aba 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -374,7 +374,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D val fv = freshVar (Tup(N -> Fld(false, false, fv) :: Nil) :: Nil, S( (body: Term) => If(IfOpApp(fv, Var("is"), IfThen(pat, body)), S( - App(Sel(Var("super").withLoc(S(ovLoc)), v), Tup(N -> Fld(false, false, fv) :: Nil)) + App(Sel(Super().withLoc(S(ovLoc)), v), Tup(N -> Fld(false, false, fv) :: Nil)) )) )) case r => diff --git a/shared/src/test/diff/nu/ECOOP23.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls similarity index 85% rename from shared/src/test/diff/nu/ECOOP23.mls rename to shared/src/test/diff/ecoop23/ExpressionProblem.mls index 7b1034087c..a9c9d0bd6c 100644 --- a/shared/src/test/diff/nu/ECOOP23.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -1,6 +1,8 @@ :NewParser :NewDefs -:NoJS + + +// * Motivating paper example, demonstrating the expression problem solution class Add(lhs: E, rhs: E) @@ -11,10 +13,6 @@ class Lit(n: int) fun add11 = Add(Lit(1), Lit(2)) //│ fun add11: Add[Lit] -// add11 + 1 - -// add11 - fun eval(e) = if e is @@ -48,9 +46,13 @@ TestLang.eval //│ 'a -> int //│ where //│ 'a <: Add['a] | Lit +//│ res +//│ = [Function: eval] TestLang.eval(add11) //│ int +//│ res +//│ = 3 mixin EvalNothing { @@ -82,9 +84,13 @@ TestLang.eval //│ 'a -> int //│ where //│ 'a <: Add['a] | Lit +//│ res +//│ = [Function: eval] TestLang.eval(add11) //│ int +//│ res +//│ = 3 class Neg(expr: A) @@ -92,6 +98,8 @@ class Neg(expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) //│ let add2negadd11: Add[Lit | Neg[Add[Lit]]] +//│ add2negadd11 +//│ = Add {} mixin EvalNeg { @@ -117,31 +125,45 @@ TestLang.eval //│ 'a -> int //│ where //│ 'a <: Add['a] | Lit | Neg['a] +//│ res +//│ = [Function: eval] TestLang.eval(add11) //│ int +//│ res +//│ = 3 TestLang.eval(Neg(add11)) //│ int +//│ res +//│ = -3 TestLang.eval(Add(Lit(2), Neg(Lit(1)))) //│ int +//│ res +//│ = 1 TestLang.eval(Neg(Neg(add11))) //│ int +//│ res +//│ = 3 TestLang.eval(add2negadd11) //│ int +//│ res +//│ = -1 // add11 TestLang.eval(Add(Lit(2), Neg(add11))) //│ int +//│ res +//│ = -1 -mixin EvalNegNeg { +mixin EvalNegNeg_0 { fun eval(e) = if e is Neg(Neg(d)) then this.eval(d) else super.eval(e) @@ -151,13 +173,13 @@ mixin EvalNegNeg { // else super.eval(e) // else super.eval(e) } -//│ mixin EvalNegNeg() { +//│ mixin EvalNegNeg_0() { //│ super: {eval: (Neg['A] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} //│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b //│ } -// * Alternative: +// * Concise alternative, usign syntax sugar: mixin EvalNegNeg { fun eval(override Neg(Neg(d))) = this.eval(d) } @@ -188,8 +210,12 @@ TestLang.eval //│ where //│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] //│ 'A <: 'a +//│ res +//│ = [Function: eval] TestLang.eval(mk(0)) //│ int +//│ res +//│ = 0 diff --git a/shared/src/test/diff/nu/ECOOP23_intro.mls b/shared/src/test/diff/ecoop23/Intro.mls similarity index 100% rename from shared/src/test/diff/nu/ECOOP23_intro.mls rename to shared/src/test/diff/ecoop23/Intro.mls diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls similarity index 100% rename from shared/src/test/diff/nu/NewPolyVariantCodeReuse.mls rename to shared/src/test/diff/ecoop23/PolymorphicVariants.mls diff --git a/shared/src/test/diff/nu/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls similarity index 100% rename from shared/src/test/diff/nu/SimpleRegionDSL.mls rename to shared/src/test/diff/ecoop23/SimpleRegionDSL.mls diff --git a/shared/src/test/diff/nu/Andong.mls b/shared/src/test/diff/nu/Andong.mls index 97ed28c23b..e75a3ab5f6 100644 --- a/shared/src/test/diff/nu/Andong.mls +++ b/shared/src/test/diff/nu/Andong.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs :NoJS diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index 0528d822d2..1728931c38 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -22,17 +21,17 @@ type Foo[A] = { x: A, y: Foo[(A, A)] } :e type Test //│ ╔══[ERROR] type alias definition requires a right-hand side -//│ ║ l.23: type Test +//│ ║ l.22: type Test //│ ╙── ^^^^^^^^^ //│ type Test = error :e type Test(n: int) = n //│ ╔══[ERROR] type alias definitions cannot have value parameters -//│ ║ l.30: type Test(n: int) = n +//│ ║ l.29: type Test(n: int) = n //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] type identifier not found: n -//│ ║ l.30: type Test(n: int) = n +//│ ║ l.29: type Test(n: int) = n //│ ╙── ^ //│ type Test = error @@ -43,10 +42,10 @@ class Base :e type Test: Base //│ ╔══[PARSE ERROR] Expected end of input; found ':' instead -//│ ║ l.44: type Test: Base +//│ ║ l.43: type Test: Base //│ ╙── ^ //│ ╔══[ERROR] type alias definition requires a right-hand side -//│ ║ l.44: type Test: Base +//│ ║ l.43: type Test: Base //│ ╙── ^^^^^^^^^ //│ type Test = error @@ -54,20 +53,20 @@ type Test: Base :e type Test: Base = int //│ ╔══[PARSE ERROR] Expected end of input; found ':' instead -//│ ║ l.55: type Test: Base = int +//│ ║ l.54: type Test: Base = int //│ ╙── ^ //│ ╔══[ERROR] type alias definition requires a right-hand side -//│ ║ l.55: type Test: Base = int +//│ ║ l.54: type Test: Base = int //│ ╙── ^^^^^^^^^ //│ type Test = error :e type Test extends Base //│ ╔══[ERROR] type alias definitions cannot extend parents -//│ ║ l.65: type Test extends Base +//│ ║ l.64: type Test extends Base //│ ╙── ^^^^ //│ ╔══[ERROR] type alias definition requires a right-hand side -//│ ║ l.65: type Test extends Base +//│ ║ l.64: type Test extends Base //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ type Test = error @@ -75,20 +74,20 @@ type Test extends Base :e type Test extends Base = int //│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.76: type Test extends Base = int +//│ ║ l.75: type Test extends Base = int //│ ╙── ^ //│ ╔══[ERROR] type alias definitions cannot extend parents -//│ ║ l.76: type Test extends Base = int +//│ ║ l.75: type Test extends Base = int //│ ╙── ^^^^ //│ ╔══[ERROR] type alias definition requires a right-hand side -//│ ║ l.76: type Test extends Base = int +//│ ║ l.75: type Test extends Base = int //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ type Test = error :e type Test = int extends Base //│ ╔══[ERROR] type alias definitions cannot extend parents -//│ ║ l.89: type Test = int extends Base +//│ ║ l.88: type Test = int extends Base //│ ╙── ^^^^ //│ type Test = int @@ -96,14 +95,14 @@ type Test = int extends Base :pe type Poly[mut A] = A //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword here -//│ ║ l.97: type Poly[mut A] = A +//│ ║ l.96: type Poly[mut A] = A //│ ╙── ^^^ //│ type Poly = A :pe type Poly[#A] = A //│ ╔══[PARSE ERROR] Unexpected '#' here -//│ ║ l.104: type Poly[#A] = A +//│ ║ l.103: type Poly[#A] = A //│ ╙── ^ //│ type Poly = A diff --git a/shared/src/test/diff/nu/BadSuper.mls b/shared/src/test/diff/nu/BadSuper.mls index 655da0163f..eafaee489d 100644 --- a/shared/src/test/diff/nu/BadSuper.mls +++ b/shared/src/test/diff/nu/BadSuper.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -14,7 +13,7 @@ mixin M1 { fun g = super } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.14: fun g = super +//│ ║ l.13: fun g = super //│ ╙── ^^^^^ //│ mixin M1() { //│ super: 'super @@ -41,7 +40,7 @@ class Foo { fun f = super } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.41: fun f = super +//│ ║ l.40: fun f = super //│ ╙── ^^^^^ //│ class Foo() { //│ fun f: Foo diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index b55bb4dce8..5789edbd21 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS class A @@ -9,8 +7,8 @@ class A // TODO class B(m: int) extends A //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.10: class B(m: int) extends A -//│ ╙── ^ +//│ ║ l.8: class B(m: int) extends A +//│ ╙── ^ //│ class B(m: int) @@ -20,9 +18,11 @@ class A(n: int) // TODO class B(m: int) extends A(n + 1) //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.21: class B(m: int) extends A(n + 1) +//│ ║ l.19: class B(m: int) extends A(n + 1) //│ ╙── ^^^^^^^^ //│ class B(m: int) +//│ Code generation encountered an error: +//│ unresolved symbol in parents: A1 diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index fcf9d3d230..64e2ab454d 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS class A(n: int) @@ -8,9 +6,13 @@ class A(n: int) A //│ (n: int,) -> A +//│ res +//│ = [Function (anonymous)] { class: [class A] } let a = A(42) //│ let a: A +//│ a +//│ = A {} fun f(x: A) = x.n @@ -28,18 +30,24 @@ fun f(x) = x.n f(a) //│ int +//│ res +//│ = 42 fun f(x) = if x is A then x.n //│ fun f: A -> int f(a) //│ int +//│ res +//│ = 42 fun f(x) = if x is A then x.n else 0 //│ fun f: anything -> int f(a) //│ int +//│ res +//│ = 42 @@ -61,10 +69,10 @@ class Base0(n) { fun oops = this.my } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.57: class Base0(n) { +//│ ║ l.65: class Base0(n) { //│ ╙── ^ //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.61: fun oops = this.my +//│ ║ l.69: fun oops = this.my //│ ╙── ^^^ //│ class Base0(n: error) { //│ fun me: Base0 & {n: error} @@ -72,27 +80,45 @@ class Base0(n) { //│ fun my: error //│ fun oops: error //│ } +//│ Code generation encountered an error: +//│ unresolved symbol my // :d // Base0 -// Base0 +:re let b1 = Base0(42) //│ let b1: Base0 +//│ b1 +//│ Runtime error: +//│ ReferenceError: Base0 is not defined -// :d +:re let n1 = b1.n //│ let n1: error +//│ n1 +//│ Runtime error: +//│ ReferenceError: b1 is not defined // TODO n1 + 1 //│ int +//│ res +//│ Runtime error: +//│ ReferenceError: n1 is not defined +:re let b2 = Base0("hi") let n2 = b2.n //│ let b2: Base0 //│ let n2: error +//│ b2 +//│ Runtime error: +//│ ReferenceError: Base0 is not defined +//│ n2 +//│ Runtime error: +//│ ReferenceError: b2 is not defined @@ -120,30 +146,44 @@ class Base1(base: int) { Base1 //│ (base: int,) -> Base1 +//│ res +//│ = [Function (anonymous)] { class: [class Base11] } let b = Base1(1) //│ let b: Base1 +//│ b +//│ = Base11 {} b.base //│ int +//│ res +//│ = 1 b.getBase1 //│ int +//│ res +//│ = 1 // :d b.me //│ Base1 & {base: int} +//│ res +//│ = Base11 {} :e b.getBaseTypo //│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` -//│ ║ l.138: b.getBaseTypo +//│ ║ l.174: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error +//│ res +//│ = undefined b : Base1 //│ Base1 +//│ res +//│ = Base11 {} class Rec(n: int) { @@ -157,9 +197,15 @@ let r = Rec(0) r.n //│ let r: Rec //│ int +//│ r +//│ = Rec {} +//│ res +//│ = 0 r.go.n //│ int +//│ res +//│ = 1 diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index f29c967b0e..82666f1821 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -40,20 +39,20 @@ class Base1(base: int) extends BaseTest { fun test2 = [base, this.base] } //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.39: class Base1(base: int) extends BaseTest { +//│ ║ l.38: class Base1(base: int) extends BaseTest { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.40: fun test2 = [base, this.base] +//│ ║ l.39: fun test2 = [base, this.base] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.41: } +//│ ║ l.40: } //│ ║ ^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.39: class Base1(base: int) extends BaseTest { +//│ ║ l.38: class Base1(base: int) extends BaseTest { //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.13: fun test = super.base +//│ ║ l.12: fun test = super.base //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.13: fun test = super.base +//│ ║ l.12: fun test = super.base //│ ╙── ^^^^^ //│ class Base1(base: int) { //│ fun test: nothing @@ -116,7 +115,7 @@ Base2(11).test2 // TODO class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.117: class Base2(x) extends BaseOf(x + 1), BaseTest +//│ ║ l.116: class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╙── ^ //│ class Base2(x: error) { //│ fun original: int @@ -126,13 +125,13 @@ class Base2(x) extends BaseOf(x + 1), BaseTest :e class Base1(x): BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.127: class Base1(x): BaseTest +//│ ║ l.126: class Base1(x): BaseTest //│ ╙── ^ //│ ╔══[ERROR] mixins cannot be used as types -//│ ║ l.127: class Base1(x): BaseTest +//│ ║ l.126: class Base1(x): BaseTest //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.127: class Base1(x): BaseTest +//│ ║ l.126: class Base1(x): BaseTest //│ ╙── ^^^^^^^^ //│ class Base1(x: error) @@ -154,31 +153,31 @@ mixin Foo { :e module Base1(base: int, misc: string) extends Foo //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ l.154: module Base1(base: int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ l.154: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'misc' -//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ l.154: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ l.154: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.155: module Base1(base: int, misc: string) extends Foo +//│ ║ l.154: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.147: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ module Base1(base: int, misc: string) { //│ fun test: (int & 'a) -> (int, 'a, nothing,) @@ -261,16 +260,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.262: WrapBase1.wrapA("ok") +//│ ║ l.261: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.262: WrapBase1.wrapA("ok") +//│ ║ l.261: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.196: fun wrapA(x: int) = x : int +//│ ║ l.195: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.206: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.205: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error //│ res diff --git a/shared/src/test/diff/nu/ClassField.mls b/shared/src/test/diff/nu/ClassField.mls index 283eb544f3..2ef4c13b11 100644 --- a/shared/src/test/diff/nu/ClassField.mls +++ b/shared/src/test/diff/nu/ClassField.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -29,10 +28,10 @@ typeof(f) :e let cls = Foo.class //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.30: let cls = Foo.class +//│ ║ l.29: let cls = Foo.class //│ ║ ^^^^^^^^^ //│ ╟── reference of type `(x: int,) -> Foo` does not have field 'class' -//│ ║ l.30: let cls = Foo.class +//│ ║ l.29: let cls = Foo.class //│ ╙── ^^^ //│ let cls: error //│ cls @@ -60,10 +59,10 @@ Derived :e let cls = Derived.class //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.61: let cls = Derived.class +//│ ║ l.60: let cls = Derived.class //│ ║ ^^^^^^^^^^^^^ //│ ╟── reference of type `() -> Derived` does not have field 'class' -//│ ║ l.61: let cls = Derived.class +//│ ║ l.60: let cls = Derived.class //│ ╙── ^^^^^^^ //│ let cls: error //│ cls diff --git a/shared/src/test/diff/nu/ClassSignatures.mls b/shared/src/test/diff/nu/ClassSignatures.mls index 7d7c97e1ac..28fa2581c3 100644 --- a/shared/src/test/diff/nu/ClassSignatures.mls +++ b/shared/src/test/diff/nu/ClassSignatures.mls @@ -1,11 +1,10 @@ -:NewParser :NewDefs // TODO class Foo(): {} //│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.6: class Foo(): {} +//│ ║ l.5: class Foo(): {} //│ ╙── ^^ //│ class Foo() @@ -14,7 +13,7 @@ class Foo(): {} { fun x = 0 } //│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.13: class Foo(): {} { +//│ ║ l.12: class Foo(): {} { //│ ╙── ^^ //│ class Foo() { //│ fun x: 0 diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 693d316a8e..57667bf396 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -1,6 +1,5 @@ -:NewParser :NewDefs -:NoJS +:NoJS // TODO @@ -28,14 +27,14 @@ M.f.n :e M.Foo //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.29: M.Foo +//│ ║ l.28: M.Foo //│ ╙── ^^^^ //│ error :e mixin Test2 { let f = Foo(1) } //│ ╔══[ERROR] identifier not found: Foo -//│ ║ l.36: mixin Test2 { let f = Foo(1) } +//│ ║ l.35: mixin Test2 { let f = Foo(1) } //│ ╙── ^^^ //│ mixin Test2() { //│ let f: error @@ -60,11 +59,11 @@ mixin Test { Add(l, r) then this.size(l) + this.size(r) } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.55: class Add(lhs: A, rhs: A) { +//│ ║ l.54: class Add(lhs: A, rhs: A) { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.56: let cached = size(this) +//│ ║ l.55: let cached = size(this) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.57: } +//│ ║ l.56: } //│ ╙── ^^^ //│ mixin Test() { //│ this: {size: 'lhs -> int} diff --git a/shared/src/test/diff/nu/ECOOP23_min.mls b/shared/src/test/diff/nu/ECOOP23_min.mls deleted file mode 100644 index ac8de9f7ef..0000000000 --- a/shared/src/test/diff/nu/ECOOP23_min.mls +++ /dev/null @@ -1,43 +0,0 @@ -:NewParser -:NewDefs -:NoJS - - -class Add(lhs: E, rhs: E) -// class Lit(n: int) -//│ class Add[E](lhs: E, rhs: E) - -let e = Add(1, 1) -//│ let e: Add[1] - -:d -e -//│ 0. Typing TypingUnit(List(e)) -//│ | 0. Typing term e -//│ | 0. : α32 -//│ ======== TYPED ======== -//│ res: Some(α32) where -//│ α32 :> (Add & {Add#E: mut E26_33..E26_33}) -//│ E26_33 :> 1 -//│ Add[1] - -e.lhs -//│ 1 - -:d -e -//│ 0. Typing TypingUnit(List(e)) -//│ | 0. Typing term e -//│ | 0. : α32 -//│ ======== TYPED ======== -//│ res: Some(α32) where -//│ α32 :> (Add & {Add#E: mut E26_33..E26_33}) <: {lhs: lhs38} -//│ E26_33 :> 1 <: lhs38 -//│ lhs38 :> 1 -//│ Add[1] - - -Add(2, 2) -//│ Add[2] - - diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index b694e0bb9f..174d5e95ad 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs :NoJS @@ -20,14 +19,14 @@ let x: List // FIXME x: List //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.21: x: List +//│ ║ l.20: x: List //│ ║ ^ //│ ╟── expression of type `anything` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.17: let x: List +//│ ║ l.16: let x: List //│ ║ ^^^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.6: class List { +//│ ║ l.5: class List { //│ ╙── ^ //│ List[anything] diff --git a/shared/src/test/diff/nu/ECOOP23_codegen.mls b/shared/src/test/diff/nu/EvalNegNeg.mls similarity index 99% rename from shared/src/test/diff/nu/ECOOP23_codegen.mls rename to shared/src/test/diff/nu/EvalNegNeg.mls index e063431eae..21e66d3733 100644 --- a/shared/src/test/diff/nu/ECOOP23_codegen.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -1,6 +1,6 @@ -:NewParser :NewDefs + class Add(lhs: E, rhs: E) class Lit(n: int) //│ class Add[E](lhs: E, rhs: E) diff --git a/shared/src/test/diff/nu/ExplicitVariance.mls b/shared/src/test/diff/nu/ExplicitVariance.mls index 620cc3f2e0..38a5bc5bf8 100644 --- a/shared/src/test/diff/nu/ExplicitVariance.mls +++ b/shared/src/test/diff/nu/ExplicitVariance.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -12,13 +11,13 @@ fun foo(x: Foo[int]): Foo[number] = x :e fun foo(x: Foo[number]): Foo[int] = x //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.13: fun foo(x: Foo[number]): Foo[int] = x +//│ ║ l.12: fun foo(x: Foo[number]): Foo[int] = x //│ ║ ^ //│ ╟── type `number` is not an instance of `int` -//│ ║ l.13: fun foo(x: Foo[number]): Foo[int] = x +//│ ║ l.12: fun foo(x: Foo[number]): Foo[int] = x //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.13: fun foo(x: Foo[number]): Foo[int] = x +//│ ║ l.12: fun foo(x: Foo[number]): Foo[int] = x //│ ╙── ^^^ //│ fun foo: (x: Foo[number],) -> Foo[int] @@ -32,13 +31,13 @@ fun foo(x: Foo[number]): Foo[int] = x :e fun foo(x: Foo[int]): Foo[number] = x //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.33: fun foo(x: Foo[int]): Foo[number] = x +//│ ║ l.32: fun foo(x: Foo[int]): Foo[number] = x //│ ║ ^ //│ ╟── type `number` is not an instance of `int` -//│ ║ l.33: fun foo(x: Foo[int]): Foo[number] = x +//│ ║ l.32: fun foo(x: Foo[int]): Foo[number] = x //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.33: fun foo(x: Foo[int]): Foo[number] = x +//│ ║ l.32: fun foo(x: Foo[int]): Foo[number] = x //│ ╙── ^^^ //│ fun foo: (x: Foo[int],) -> Foo[number] diff --git a/shared/src/test/diff/nu/ECOOP23_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls similarity index 99% rename from shared/src/test/diff/nu/ECOOP23_repro.mls rename to shared/src/test/diff/nu/ExpressionProblem_repro.mls index 79aee81ecf..2c8e947d12 100644 --- a/shared/src/test/diff/nu/ECOOP23_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs :NoJS @@ -151,11 +150,9 @@ TestLang.eval(Neg(Neg(add11))) //│ int -// :e TestLang.eval(add2negadd11) //│ int -// :e TestLang.eval(Add(Lit(2), Neg(add11))) //│ int diff --git a/shared/src/test/diff/nu/ECOOP23_small.mls b/shared/src/test/diff/nu/ExpressionProblem_small.mls similarity index 99% rename from shared/src/test/diff/nu/ECOOP23_small.mls rename to shared/src/test/diff/nu/ExpressionProblem_small.mls index 19574fc37c..ea0cee1c4b 100644 --- a/shared/src/test/diff/nu/ECOOP23_small.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_small.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs :NoJS diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 96d2c6aa43..7bf201140c 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -30,25 +29,25 @@ fun filtermap(f, xs) = if xs is true then Cons(y, filtermap(f, ys)) [true, z] then Cons(y, filtermap(f, ys)) //│ ╔══[ERROR] identifier not found: ys -//│ ║ l.28: Cons(y, ys) and f(ys) is +//│ ║ l.27: Cons(y, ys) and f(ys) is //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.28: Cons(y, ys) and f(ys) is +//│ ║ l.27: Cons(y, ys) and f(ys) is //│ ║ ^^^^^^^^ -//│ ║ l.29: false then filtermap(f, ys) +//│ ║ l.28: false then filtermap(f, ys) //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `number` -//│ ║ l.29: false then filtermap(f, ys) +//│ ║ l.28: false then filtermap(f, ys) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.28: Cons(y, ys) and f(ys) is +//│ ║ l.27: Cons(y, ys) and f(ys) is //│ ║ ^^^^^^^^ -//│ ║ l.29: false then filtermap(f, ys) +//│ ║ l.28: false then filtermap(f, ys) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.30: true then Cons(y, filtermap(f, ys)) +//│ ║ l.29: true then Cons(y, filtermap(f, ys)) //│ ║ ^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `number` -//│ ║ l.30: true then Cons(y, filtermap(f, ys)) +//│ ║ l.29: true then Cons(y, filtermap(f, ys)) //│ ╙── ^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── diff --git a/shared/src/test/diff/nu/FunPatterns.mls b/shared/src/test/diff/nu/FunPatterns.mls index badf87a2ad..414a848b1e 100644 --- a/shared/src/test/diff/nu/FunPatterns.mls +++ b/shared/src/test/diff/nu/FunPatterns.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs :NoJS @@ -21,13 +20,13 @@ class Pair(lhs: int, rhs: int) // TODO fun f(Pair(x, y)) = x + y //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.22: fun f(Pair(x, y)) = x + y +//│ ║ l.21: fun f(Pair(x, y)) = x + y //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: x -//│ ║ l.22: fun f(Pair(x, y)) = x + y +//│ ║ l.21: fun f(Pair(x, y)) = x + y //│ ╙── ^ //│ ╔══[ERROR] identifier not found: y -//│ ║ l.22: fun f(Pair(x, y)) = x + y +//│ ║ l.21: fun f(Pair(x, y)) = x + y //│ ╙── ^ //│ fun f: error -> int diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index ad66ea7962..ba71213812 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -1,18 +1,17 @@ -:NewParser :NewDefs // TODO class Exp[type A] //│ ╔══[PARSE ERROR] Unexpected 'type' keyword here -//│ ║ l.6: class Exp[type A] +//│ ║ l.5: class Exp[type A] //│ ╙── ^^^^ //│ class Exp() // TODO class Lit(n: int) extends Exp[int] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.13: class Lit(n: int) extends Exp[int] +//│ ║ l.12: class Lit(n: int) extends Exp[int] //│ ╙── ^^^^^^^^ //│ class Lit(n: int) diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index b5a001e02e..ae3ec9c36d 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS // TODO class C @@ -22,9 +20,13 @@ fun f(x) = if x is C(a) then a let c = C(1) //│ let c: C[1] +//│ c +//│ = C1 {} f(c) //│ 1 +//│ res +//│ = 1 class Some(value: A) { @@ -43,30 +45,46 @@ class Some(value: A) { let s = Some(1) //│ let s: Some[1] +//│ s +//│ = Some {} s.value //│ 1 +//│ res +//│ = 1 s.get //│ 1 +//│ res +//│ = 1 s.toArray //│ (1,) +//│ res +//│ = [ 1 ] s.map //│ (1 -> 'A) -> Some['A] +//│ res +//│ = [Function: map] s.map(succ) //│ Some[int] +//│ res +//│ = Some {} s.map_A //│ (1 -> 'A) -> Some['A] +//│ res +//│ = [Function: map_A] s.map_A(succ) //│ Some[int] +//│ res +//│ = Some {} @@ -86,6 +104,8 @@ module None { None.toArray //│ () +//│ res +//│ = [] type Option = Some | None @@ -95,27 +115,41 @@ type Option = Some | None let opt = if true then Some(123) else None //│ let opt: None | Some[123] +//│ opt +//│ = Some {} opt.toArray //│ Array[123] +//│ res +//│ = [ 123 ] opt.map(succ) //│ None | Some[int] +//│ res +//│ = Some {} opt.map_A(succ) //│ None | Some[int] +//│ res +//│ = Some {} opt.map(x => x > 0) //│ None | Some[bool] +//│ res +//│ = Some {} if opt is Some then opt.value else 0 //│ 0 | 123 +//│ res +//│ = 123 if opt is Some(v) then v else 0 //│ 0 | 123 +//│ res +//│ = 123 fun map(x, f) = if x is @@ -125,9 +159,13 @@ fun map(x, f) = if x is let mo = map(opt, succ) //│ let mo: None | Some[int] +//│ mo +//│ = Some {} mo.toArray //│ Array[int] +//│ res +//│ = [ 124 ] @@ -137,7 +175,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.135: class Test(n) { +//│ ║ l.173: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -146,10 +184,14 @@ class Test(n) { Test(1) //│ Test +//│ res +//│ = Test {} // :e Test(true) //│ Test +//│ res +//│ = Test {} :e @@ -157,13 +199,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.157: fun foo = n + 1 +//│ ║ l.199: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.157: fun foo = n + 1 +//│ ║ l.199: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.156: class Test(n: A) { +//│ ║ l.198: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int @@ -171,9 +213,13 @@ class Test(n: A) { Test(1) //│ Test[1] +//│ res +//│ = Test1 {} Test(true) //│ Test[true] +//│ res +//│ = Test1 {} class Test(n: A) { @@ -189,29 +235,45 @@ class Test(n: A) { Test(1) //│ Test[1] +//│ res +//│ = Test2 {} Test(1).foo //│ 1 +//│ res +//│ = 1 Test("ok").foo //│ "ok" +//│ res +//│ = 'ok' let t = Test(1) //│ let t: Test[1] +//│ t +//│ = Test2 {} t.foo1(true) //│ 1 | true +//│ res +//│ = true t : Test<'a> //│ Test['a] //│ where //│ 'a :> 1 | true +//│ res +//│ = Test2 {} t.id //│ 'a -> 'a +//│ res +//│ = [Function: id] [t.id(1), t.id(true)] //│ (1, true,) +//│ res +//│ = [ 1, true ] :e @@ -220,13 +282,13 @@ class TestBad { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.220: fun foo2(x: A) = x + 1 +//│ ║ l.282: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.220: fun foo2(x: A) = x + 1 +//│ ║ l.282: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.218: class TestBad { +//│ ║ l.280: class TestBad { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A @@ -235,28 +297,44 @@ class TestBad { TestBad().foo1 //│ (x: 'A,) -> 'A +//│ res +//│ = [Function: foo1] TestBad().foo1(1) //│ 1 +//│ res +//│ = 1 x => TestBad().foo1(x) //│ 'a -> 'a +//│ res +//│ = [Function: res] // :d let t = TestBad() //│ let t: forall 'A. TestBad['A] +//│ t +//│ = TestBad {} t.foo1 //│ (x: 'A,) -> 'A +//│ res +//│ = [Function: foo1] [t.foo1(0), t.foo1(true)] //│ (0, true,) +//│ res +//│ = [ 0, true ] t.foo1(0) //│ 0 +//│ res +//│ = 0 t //│ forall 'A. TestBad['A] +//│ res +//│ = TestBad {} fun foo(x: TestBad) = x.foo1 @@ -264,13 +342,19 @@ fun foo(x: TestBad) = x.foo1 foo(t) //│ (x: int,) -> int +//│ res +//│ = [Function: foo1] foo(t)(1) //│ int +//│ res +//│ = 1 TestBad().foo2 //│ (x: anything,) -> (error | int) +//│ res +//│ = [Function: foo2] @@ -279,12 +363,18 @@ class Weird(x: C<'a>) let w = Weird(c) //│ let w: Weird +//│ w +//│ = Weird {} w.x //│ C['a] +//│ res +//│ = C1 {} // FIXME not(w.x.a) //│ bool +//│ res +//│ = false diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 3327c6d5ab..5d6d84168a 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS fun foo1 = forall 'A; (x: 'A) => x @@ -8,6 +6,8 @@ fun foo1 = forall 'A; (x: 'A) => x foo1(42) //│ 42 +//│ res +//│ = 42 :e foo1[int](42) @@ -15,6 +15,8 @@ foo1[int](42) //│ ║ l.13: foo1[int](42) //│ ╙── ^^^^^^^^^ //│ error +//│ res +//│ = 42 fun foo2(x: A) = x @@ -22,13 +24,17 @@ fun foo2(x: A) = x foo2(42) //│ 42 +//│ res +//│ = 42 :e foo2(42) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.27: foo2(42) +//│ ║ l.31: foo2(42) //│ ╙── ^^^^^^^^^ //│ error +//│ res +//│ = 42 fun foo3[A](x: A) = x @@ -36,13 +42,17 @@ fun foo3[A](x: A) = x foo3(42) //│ 42 +//│ res +//│ = 42 :e foo3[int](42) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.41: foo3[int](42) +//│ ║ l.49: foo3[int](42) //│ ╙── ^^^^^^^^^ //│ error +//│ res +//│ = 42 fun bar: forall 'A; 'A => 'A @@ -51,37 +61,40 @@ fun bar: forall 'A; 'A => 'A :e fun bar : A => A //│ ╔══[ERROR] Type parameters here are not yet supported in this position -//│ ║ l.52: fun bar : A => A +//│ ║ l.62: fun bar : A => A //│ ╙── ^ //│ ╔══[ERROR] type identifier not found: A -//│ ║ l.52: fun bar : A => A +//│ ║ l.62: fun bar : A => A //│ ╙── ^ //│ ╔══[ERROR] type identifier not found: A -//│ ║ l.52: fun bar : A => A +//│ ║ l.62: fun bar : A => A //│ ╙── ^ //│ fun bar: error -> error :pe :e :w +:ge fun bar: A => A //│ ╔══[PARSE ERROR] Unmatched opening angle bracket -//│ ║ l.67: fun bar: A => A +//│ ║ l.78: fun bar: A => A //│ ║ ^ //│ ╙── Note that `<` without spaces around it is considered as an angle bracket and not as an operator //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position -//│ ║ l.67: fun bar: A => A +//│ ║ l.78: fun bar: A => A //│ ╙── ^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.67: fun bar: A => A +//│ ║ l.78: fun bar: A => A //│ ╙── ^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.67: fun bar: A => A +//│ ║ l.78: fun bar: A => A //│ ╙── ^^^^^ //│ ╔══[ERROR] identifier not found: A -//│ ║ l.67: fun bar: A => A +//│ ║ l.78: fun bar: A => A //│ ╙── ^ //│ error -> error +//│ Code generation encountered an error: +//│ term App(App(Var(>:), Tup(_: Var(A))), Tup(_: Var(A))) is not a valid pattern module Test { diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 41daeeec7f..1f399014cb 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS // TODO support @@ -8,7 +6,7 @@ mixin BaseTest { fun test(x: A) = x } //│ ╔══[ERROR] type identifier not found: A -//│ ║ l.8: fun test(x: A) = x +//│ ║ l.6: fun test(x: A) = x //│ ╙── ^ //│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A29' diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 65aa52e449..f13dcb88a4 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -18,10 +17,10 @@ Test.foo :e Test.foo(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.19: Test.foo(1) +//│ ║ l.18: Test.foo(1) //│ ║ ^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.19: Test.foo(1) +//│ ║ l.18: Test.foo(1) //│ ╙── ^ //│ error | ??A //│ res @@ -31,10 +30,10 @@ Test.foo(1) :e Test.foo(error) + 1 //│ ╔══[ERROR] Type error in operator application -//│ ║ l.32: Test.foo(error) + 1 +//│ ║ l.31: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.32: Test.foo(error) + 1 +//│ ║ l.31: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╙── into type `int` //│ error | int @@ -45,7 +44,7 @@ Test.foo(error) + 1 :e Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.46: Test .foo +//│ ║ l.45: Test .foo //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -54,7 +53,7 @@ Test .foo :e (Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.55: (Test).foo +//│ ║ l.54: (Test).foo //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -69,13 +68,13 @@ Test :e Test: Test<'a> //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.70: Test: Test<'a> +//│ ║ l.69: Test: Test<'a> //│ ║ ^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.70: Test: Test<'a> +//│ ║ l.69: Test: Test<'a> //│ ║ ^^ //│ ╟── back into type variable `A` -//│ ║ l.6: module Test { +//│ ║ l.5: module Test { //│ ╙── ^ //│ Test['a] //│ where @@ -91,10 +90,10 @@ fun test(x) = if x is Test then x.foo :e test(Test) //│ ╔══[ERROR] Type error in application -//│ ║ l.92: test(Test) +//│ ║ l.91: test(Test) //│ ║ ^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.6: module Test { +//│ ║ l.5: module Test { //│ ╙── ^ //│ (??A & 'A) -> ('A | ??A0) | error //│ res diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index f25171200b..4a14085d05 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -// :NoJS // TODO rm :js diff --git a/shared/src/test/diff/nu/ListConsNil.mls b/shared/src/test/diff/nu/ListConsNil.mls index 459e525fb7..d6fdd6d715 100644 --- a/shared/src/test/diff/nu/ListConsNil.mls +++ b/shared/src/test/diff/nu/ListConsNil.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index a07d2d4794..9890d57e01 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index 63a3597467..af9b11d424 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs :NoJS @@ -15,7 +14,7 @@ mixin BaseTest(x) { fun test = x } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.14: mixin BaseTest(x) { +//│ ║ l.13: mixin BaseTest(x) { //│ ╙── ^ //│ mixin BaseTest(x: error) { //│ fun test: error diff --git a/shared/src/test/diff/nu/ModuleParameters.mls b/shared/src/test/diff/nu/ModuleParameters.mls index de92e5f536..afe26a519d 100644 --- a/shared/src/test/diff/nu/ModuleParameters.mls +++ b/shared/src/test/diff/nu/ModuleParameters.mls @@ -1,11 +1,10 @@ -:NewParser :NewDefs :e module A(x: int) { fun y = x } //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.6: module A(x: int) { fun y = x } +//│ ║ l.5: module A(x: int) { fun y = x } //│ ╙── ^ //│ module A(x: int) { //│ fun y: int diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 6083210641..264f95eb99 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -1,6 +1,5 @@ -:NewParser :NewDefs -:NoJS +:NoJS // TODO @@ -17,10 +16,10 @@ fun fooo(x) = class C(y, z) C(0, x) //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.17: class C(y, z) +//│ ║ l.16: class C(y, z) //│ ╙── ^ //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.17: class C(y, z) +//│ ║ l.16: class C(y, z) //│ ╙── ^ //│ fun fooo: error -> C @@ -135,7 +134,7 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.135: fun b = Test1_1.a +//│ ║ l.134: fun b = Test1_1.a //│ ╙── ^^ //│ module Test1_1() { //│ fun a: error @@ -156,7 +155,7 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.156: fun b = Test1_1().a +//│ ║ l.155: fun b = Test1_1().a //│ ╙── ^^ //│ class Test1_1() { //│ fun a: error @@ -179,7 +178,7 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.178: fun c = Test2_1.a +//│ ║ l.177: fun c = Test2_1.a //│ ╙── ^^ //│ module Test2_1() { //│ fun a: 123 | error diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index 27d98f9914..b8663f5687 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -17,7 +16,7 @@ let c = C0() :e c.NC0 //│ ╔══[ERROR] access to class member not yet supported -//│ ║ l.18: c.NC0 +//│ ║ l.17: c.NC0 //│ ╙── ^^^^ //│ error //│ res @@ -34,7 +33,7 @@ module M0 { :e M0.NC0 //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.35: M0.NC0 +//│ ║ l.34: M0.NC0 //│ ╙── ^^^^ //│ error //│ res @@ -51,7 +50,7 @@ module M1 { :e M1.NM1 //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.52: M1.NM1 +//│ ║ l.51: M1.NM1 //│ ╙── ^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index b95a5f855e..db2ada0199 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,3 +1,2 @@ -:NewParser :NewDefs diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls index 44db753336..6f193ced97 100644 --- a/shared/src/test/diff/nu/OverrideShorthand.mls +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS @@ -14,9 +12,11 @@ fun f(override Pair(x, y)) = x + y //│ |#fun| |f|(|#override| |Pair|(|x|,| |y|)|)| |#=| |x| |+| |y| //│ Parsed: fun f = (_$0,) => if _$0 is (Pair (x, y,)) then + (x,) (y,) else (super).f (_$0,); //│ ╔══[ERROR] identifier not found: super -//│ ║ l.13: fun f(override Pair(x, y)) = x + y +//│ ║ l.11: fun f(override Pair(x, y)) = x + y //│ ╙── ^^^^^^^^ //│ fun f: anything -> (error | int) +//│ Syntax error: +//│ 'super' keyword unexpected here mixin Test { @@ -30,20 +30,23 @@ mixin Test { :pe :e +:ge fun f(override Pair(x, y), z) = x + y //│ ╔══[PARSE ERROR] Unsupported 'override' parameter list shape -//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ║ l.34: fun f(override Pair(x, y), z) = x + y //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ║ l.34: fun f(override Pair(x, y), z) = x + y //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: x -//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ║ l.34: fun f(override Pair(x, y), z) = x + y //│ ╙── ^ //│ ╔══[ERROR] identifier not found: y -//│ ║ l.33: fun f(override Pair(x, y), z) = x + y +//│ ║ l.34: fun f(override Pair(x, y), z) = x + y //│ ╙── ^ //│ fun f: (error, anything,) -> int +//│ Code generation encountered an error: +//│ term App(Var(Pair), Tup(_: Var(x), _: Var(y))) is not a valid pattern // TODO diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index aadf53e5ac..48ccfb0a0c 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -8,7 +7,7 @@ class Base0(n: number) // TODO class Derived0(n: int) extends Base //│ ╔══[ERROR] Could not find definition `Base` -//│ ║ l.9: class Derived0(n: int) extends Base +//│ ║ l.8: class Derived0(n: int) extends Base //│ ╙── ^^^^ //│ class Derived0(n: int) //│ Code generation encountered an error: @@ -25,7 +24,7 @@ mixin Base1(n: number) { :e mixin DerivedBad(n: int) extends Base //│ ╔══[ERROR] mixin definitions cannot yet extend parents -//│ ║ l.26: mixin DerivedBad(n: int) extends Base +//│ ║ l.25: mixin DerivedBad(n: int) extends Base //│ ╙── ^^^^ //│ mixin DerivedBad(n: int) diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 4f11877290..07f5129860 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS mixin Over { @@ -24,8 +22,12 @@ class Base1(p: int) extends Over { Base1(123).test //│ (int, int,) +//│ res +//│ = [ 123, 123 ] Base1(123).test2 //│ int +//│ res +//│ = 'hi' diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 3c6f4971aa..4f890426d7 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -9,8 +8,8 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.10: class Bar(x: int, y: int) extends Foo(x + y) -//│ ╙── ^^^^^^^^^^ +//│ ║ l.9: class Bar(x: int, y: int) extends Foo(x + y) +//│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) diff --git a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls similarity index 99% rename from shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls rename to shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 0f8292fce5..4aab3c52fc 100644 --- a/shared/src/test/diff/nu/NewPolyVariantCodeReuse2.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs :NoJS diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 81271c6558..7e7aec7c21 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -1,6 +1,4 @@ -:NewParser :NewDefs -:NoJS @@ -12,7 +10,7 @@ :e class Foo { fun test = this.x } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.13: class Foo { fun test = this.x } +//│ ║ l.11: class Foo { fun test = this.x } //│ ╙── ^^ //│ class Foo() { //│ fun test: error @@ -22,7 +20,7 @@ class Foo { fun test = this.x } :e class Foo(n: int) { fun test = this.x } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.23: class Foo(n: int) { fun test = this.x } +//│ ║ l.21: class Foo(n: int) { fun test = this.x } //│ ╙── ^^ //│ class Foo(n: int) { //│ fun test: error @@ -32,7 +30,7 @@ class Foo(n: int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.33: class Foo(n: A) { fun test = this.x } +//│ ║ l.31: class Foo(n: A) { fun test = this.x } //│ ╙── ^^ //│ class Foo[A](n: A) { //│ fun test: error @@ -46,7 +44,7 @@ class Foo { // fun test = this.x } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.45: this: { x: 'a } +//│ ║ l.43: this: { x: 'a } //│ ╙── ^ //│ class Foo() @@ -55,10 +53,10 @@ class Foo { // * All on one line: class Test { this: { x: int}; fun test = this.x } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.56: class Test { this: { x: int}; fun test = this.x } +//│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^ //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.56: class Test { this: { x: int}; fun test = this.x } +//│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^^ //│ class Test() { //│ fun test: error diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index 725b5d7f5b..8fc1a60689 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -19,7 +18,7 @@ type AI2 = Array // :e type AI3(n) = Array[int] //│ ╔══[ERROR] type alias definitions cannot have value parameters -//│ ║ l.20: type AI3(n) = Array[int] +//│ ║ l.19: type AI3(n) = Array[int] //│ ╙── ^^^ //│ type AI3 = Array[int] diff --git a/shared/src/test/diff/nu/TypingUnitTerms.mls b/shared/src/test/diff/nu/TypingUnitTerms.mls index 77887269a7..a581e7bd3b 100644 --- a/shared/src/test/diff/nu/TypingUnitTerms.mls +++ b/shared/src/test/diff/nu/TypingUnitTerms.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -7,10 +6,10 @@ fun test = let x = 0(0) 1 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.7: let x = 0(0) +//│ ║ l.6: let x = 0(0) //│ ║ ^^^^ //│ ╟── integer literal of type `0` is not a function -//│ ║ l.7: let x = 0(0) +//│ ║ l.6: let x = 0(0) //│ ╙── ^ //│ fun test: 1 diff --git a/shared/src/test/diff/nu/With.mls b/shared/src/test/diff/nu/With.mls index 75b92ecba0..ce040e3d2d 100644 --- a/shared/src/test/diff/nu/With.mls +++ b/shared/src/test/diff/nu/With.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -21,7 +20,7 @@ :pe {x: 1} with 123 //│ ╔══[PARSE ERROR] record literal expected here; found integer literal -//│ ║ l.22: {x: 1} with 123 +//│ ║ l.21: {x: 1} with 123 //│ ╙── ^^^ //│ {x: 1} //│ res From 7bb89a199f1677953d16e89d4602bc17971c48c0 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 11 Mar 2023 17:18:29 +0800 Subject: [PATCH 169/498] WIP Fix printing of type parameter references --- .../main/scala/mlscript/TypeSimplifier.scala | 7 +- shared/src/main/scala/mlscript/Typer.scala | 78 +++++++++++-------- .../main/scala/mlscript/TyperDatatypes.scala | 1 + .../main/scala/mlscript/TyperHelpers.scala | 2 + shared/src/main/scala/mlscript/helpers.scala | 30 +++---- shared/src/test/diff/fcp/ForallTerms.mls | 2 +- shared/src/test/diff/nu/Ascription.mls | 2 +- shared/src/test/diff/nu/GenericMixins.mls | 5 +- shared/src/test/diff/nu/SelfRec.mls | 8 +- .../src/test/scala/mlscript/DiffTests.scala | 7 +- 10 files changed, 79 insertions(+), 63 deletions(-) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index c63a5ebf71..f57c6688b4 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -41,6 +41,8 @@ trait TypeSimplifier { self: Typer => // trace(s"process($ty) $canDistribForall") { ty match { + case SkolemTag(l, tv: TypeVariable) => process(tv, parent) + case tv: TypeVariable => parent.filter(_._2 === tv).foreach(p => return ExtrType(p._1)(noProv)) @@ -60,7 +62,7 @@ trait TypeSimplifier { self: Typer => case S(false) => nv.upperBounds = (process(ty, S(false -> tv)) :: Nil).filterNot(_.isTop) - case N => + case N => nv.assignedTo = S(process(ty, N)) } case N => @@ -918,7 +920,8 @@ trait TypeSimplifier { self: Typer => transform(r, pol, semp, canDistribForall))(st.prov) case ot @ Overload(as) => ot.mapAltsPol(pol)((p, t) => transform(t, p, parents, canDistribForall)) - case _: TypeTag | ExtrType(_) => st + case SkolemTag(lvl, id) => transform(id, pol, parents) + case _: ObjectTag | _: Extruded | ExtrType(_) => st case tv: TypeVariable if parents.exists(_ === tv) => if (pol(tv).getOrElse(lastWords(s"parent in invariant position $tv $parents"))) BotType else TopType case tv: TypeVariable => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ff38d7b458..9b9d7afcdf 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -345,7 +345,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType], newDefsInfo: Map[Str, (TypeDefKind, Int)]): (SimpleType, Iterable[TypeVariable]) = // TODO rm _2 result? // trace(s"$lvl. Typing type $ty") { - trace(s"Typing type ${ty.show}") { + trace(s"Typing type ${ty.showDbg}") { println(s"vars=$vars newDefsInfo=$newDefsInfo") val typeType2 = () // val outerCtxLvl = MinLevel + 1 @@ -369,7 +369,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val localVars = mutable.Map.empty[TypeVar, TypeVariable] def tyTp(loco: Opt[Loc], desc: Str, originName: Opt[Str] = N) = TypeProvenance(loco, desc, originName, isType = true) - def rec(ty: Type)(implicit ctx: Ctx, recVars: Map[TypeVar, TypeVariable]): SimpleType = trace(s"$lvl. type ${ty.show}") { ty match { + def rec(ty: Type)(implicit ctx: Ctx, recVars: Map[TypeVar, TypeVariable]): SimpleType = trace(s"$lvl. type ${ty.showDbg}") { ty match { case Top => ExtrType(false)(tyTp(ty.toLoc, "top type")) case Bot => ExtrType(true)(tyTp(ty.toLoc, "bottom type")) case Bounds(Bot, Top) => @@ -1277,7 +1277,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val seenVars = mutable.Set.empty[TV] - def field(ft: FieldType): Field = ft match { + def field(ft: FieldType)(implicit ectx: ExpCtx): Field = ft match { case FieldType(S(l: TV), u: TV) if l === u => val res = go(u) Field(S(res), res) // TODO improve Field @@ -1285,7 +1285,12 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Field(f.lb.map(go), go(f.ub)) } - def mkTypingUnit(thisTy: ST, members: Map[Str, NuMember]): TypingUnit = { + class ExpCtx(val tps: Map[TV, TN]) { + def apply(tparams: Ls[(TN, TV, Opt[VarianceInfo])]): ExpCtx = + new ExpCtx(tps ++ tparams.iterator.map{case (tn, tv, vi) => tv -> tn}) + } + + def mkTypingUnit(thisTy: ST, members: Map[Str, NuMember])(implicit ectx: ExpCtx): TypingUnit = { val sorted = members.toList.sortBy(_._1) // def mkTypingUnit(members: Ls[Str -> NuMember]): TypingUnit = { TypingUnit( @@ -1298,37 +1303,45 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // case _ => die }) } - def goDecl(d: TypedNuDecl): NuDecl = d match { + def goDecl(d: TypedNuDecl)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => - NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil)) + ectx(tparams) |> { implicit ectx => + NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil)) + } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => - NuTypeDef(td.kind, td.nme, td.tparams, - Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), - N, - Nil,//TODO - // S(go(superTy)), - // S(go(thisTy)), - Option.when(!(TopType <:< superTy))(go(superTy)), - Option.when(!(TopType <:< thisTy))(go(thisTy)), - // mkTypingUnit(thisTy, - // // members - // Map.empty - // ) - mkTypingUnit(thisTy, members)) + ectx(tparams) |> { implicit ectx => + NuTypeDef(td.kind, td.nme, td.tparams, + Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + N, + Nil,//TODO + // S(go(superTy)), + // S(go(thisTy)), + Option.when(!(TopType <:< superTy))(go(superTy)), + Option.when(!(TopType <:< thisTy))(go(thisTy)), + // mkTypingUnit(thisTy, + // // members + // Map.empty + // ) + mkTypingUnit(thisTy, members)) + } case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => - NuTypeDef(td.kind, td.nme, td.tparams, - // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) - Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), - N,//TODO - Nil,//TODO - N,//TODO - Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members)) - // mkTypingUnit(() :: members.toList.sortBy(_._1))) + // new ExpCtx(ectx.tps ++ tparams.iterator.map{case (tn, tv, vi) => tv -> tn}) |> { implicit ectx => + ectx(tparams) |> { implicit ectx => + NuTypeDef(td.kind, td.nme, td.tparams, + // NuTypeDef(td.kind, td.nme, tparams.map{case (tn, tv, vi) => }, + // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) + Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + N,//TODO + Nil,//TODO + N,//TODO + Option.when(!(TopType <:< thisTy))(go(thisTy)), + mkTypingUnit(thisTy, members)) + // mkTypingUnit(() :: members.toList.sortBy(_._1))) + } case TypedNuFun(level, fd, ty) => NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(ty))) } - def goLike(ty: TypeLike): mlscript.TypeLike = ty match { + def goLike(ty: TypeLike)(implicit ectx: ExpCtx): mlscript.TypeLike = ty match { case ty: SimpleType => val res = go(ty) // if (bounds.isEmpty) res @@ -1354,11 +1367,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // Signature(mems, ttu.result.map(go)) } - def go(st: SimpleType): Type = + def go(st: SimpleType)(implicit ectx: ExpCtx): Type = // trace(s"expand $st") { st.unwrapProvs match { case tv: TypeVariable if stopAtTyVars => tv.asTypeVar - case tv: TypeVariable => + case tv: TypeVariable => ectx.tps.getOrElse(tv, { val nv = tv.asTypeVar if (!seenVars(tv)) { seenVars += tv @@ -1374,6 +1387,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) } } nv + }) case FunctionType(l, r) => Function(go(l), go(r)) case ComposedType(true, l, r) => Union(go(l), go(r)) case ComposedType(false, l, r) => Inter(go(l), go(r)) @@ -1433,7 +1447,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) } // }(r => s"~> $r") - val res = goLike(st) + val res = goLike(st)(new ExpCtx(Map.empty)) if (bounds.isEmpty) res else Constrained(res, bounds, Nil) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 2febc66aba..1ec28f5fe9 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -54,6 +54,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => private implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) + println(s"${ctx.lvl}. Created lazy type info $decl") lazy val tparams: Ls[(TN, TV, Opt[VarianceInfo])] = ctx.nest.nextLevel { implicit ctx => decl match { diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 83ce1f6994..0b87f11ef5 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -863,6 +863,8 @@ abstract class TyperHelpers { Typer: Typer => val ents = tu.entities.flatMap { case tf: TypedNuFun => tf.ty :: Nil + case als: TypedNuAls => + als.tparams.iterator.map(_._2) ++ S(als.body) case mxn: TypedNuMxn => mxn.members.valuesIterator.flatMap(childrenMem) ++ S(mxn.superTV) ++ diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 447ef8b324..4fd8ea6131 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -17,6 +17,8 @@ trait SignatureImpl extends Located { self: Signature => trait TypeLikeImpl extends Located { self: TypeLike => + def showDbg2: Str = show // TODO more lightweight debug printing routine + def show: Str = showIn(ShowCtx.mk(this :: Nil), 0) private def parensIf(str: Str, cnd: Boolean): Str = if (cnd) "(" + str + ")" else str @@ -177,7 +179,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => // TODO improve this mess tparams.map(_._2) ::: params.fields.collect { case (_, Fld(_, _, Asc(_, ty))) => ty - } ::: sup.toList ::: ths.toList ::: Signature(body.entities.collect { + } ::: sig.toList ::: sup.toList ::: ths.toList ::: Signature(body.entities.collect { case d: NuDecl => d }, N) :: Nil // TODO parents? } @@ -438,14 +440,14 @@ object OpApp { trait DeclImpl extends Located { self: Decl => val body: Located def showBody: Str = this match { - case Def(_, _, rhs, isByname) => rhs.fold(_.toString, _.show) - case td: TypeDef => td.body.show + case Def(_, _, rhs, isByname) => rhs.fold(_.toString, _.showDbg2) + case td: TypeDef => td.body.showDbg2 } def describe: Str = this match { case _: Def => "definition" case _: TypeDef => "type declaration" } - def show: Str = showHead + (this match { + def showDbg: Str = showHead + (this match { case TypeDef(Als, _, _, _, _, _, _) => " = "; case _ => ": " }) + showBody def showHead: Str = this match { case Def(true, n, b, isByname) => s"rec def $n" @@ -469,8 +471,8 @@ trait NuDeclImpl extends Located { self: NuDecl => } def name: Str = nameVar.name def showBody: Str = this match { - case NuFunDef(_, _, _, rhs) => rhs.fold(_.toString, _.show) - case td: NuTypeDef => td.body.show + case NuFunDef(_, _, _, rhs) => rhs.fold(_.toString, _.showDbg2) + case td: NuTypeDef => td.body.showDbg } def describe: Str = this match { case _: NuFunDef => "definition" @@ -488,12 +490,12 @@ trait NuDeclImpl extends Located { self: NuDecl => case NuTypeDef(k, n, tps, sps, sig, parents, sup, ths, bod) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}(${ // sps.mkString("(",",",")") - sps})${sig.fold("")(": " + _.show)}${ + sps})${sig.fold("")(": " + _.showDbg2)}${ if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" } } trait TypingUnitImpl extends Located { self: TypingUnit => - def show: Str = entities.map { + def showDbg: Str = entities.map { case t: Term => t.toString case d: NuDecl => d.showDbg case _ => die @@ -583,7 +585,7 @@ trait TermImpl extends StatementImpl { self: Term => case StrLit(value) => '"'.toString + value + '"' case UnitLit(value) => if (value) "undefined" else "null" case v @ Var(name) => name + v.uid.fold("")("::"+_.toString) - case Asc(trm, ty) => s"$trm : ${ty.show}" |> bra + case Asc(trm, ty) => s"$trm : ${ty.showDbg2}" |> bra case Lam(pat, rhs) => s"($pat) => $rhs" |> bra case App(lhs, rhs) => s"${lhs.print(!lhs.isInstanceOf[App])} ${rhs.print(true)}" |> bra case Rcd(fields) => @@ -608,10 +610,10 @@ trait TermImpl extends StatementImpl { self: Term => s"case $s of { ${c.print(true)} }" |> bra case Subs(a, i) => s"($a)[$i]" case Assign(lhs, rhs) => s" $lhs <- $rhs" |> bra - case New(S((at, ar)), bod) => s"new ${at.show}($ar) ${bod.show}" |> bra - case New(N, bod) => s"new ${bod.show}" |> bra + case New(S((at, ar)), bod) => s"new ${at.showDbg2}($ar) ${bod.showDbg}" |> bra + case New(N, bod) => s"new ${bod.showDbg}" |> bra case If(body, els) => s"if $body" + els.fold("")(" else " + _) |> bra - case TyApp(lhs, targs) => s"$lhs‹${targs.map(_.show).mkString(", ")}›" + case TyApp(lhs, targs) => s"$lhs‹${targs.map(_.showDbg2).mkString(", ")}›" case Where(bod, wh) => s"${bod} where {${wh.mkString("; ")}}" case Forall(ps, bod) => s"forall ${ps.mkString(", ")}. ${bod}" case Inst(bod) => s"${bod.print(true)}!" @@ -626,7 +628,7 @@ trait TermImpl extends StatementImpl { self: Term => try R(toType_!.withLocOf(this)) catch { case e: NotAType => import Message._ - L(ErrorReport(msg"not a recognized type: ${e.trm.toString}"->e.trm.toLoc::Nil)) } + L(ErrorReport(msg"not a recognized type" -> e.trm.toLoc::Nil)) } protected def toType_! : Type = (this match { case Var(name) if name.startsWith("`") => TypeVar(R(name.tail), N) case Var(name) if name.startsWith("'") => TypeVar(R(name), N) @@ -952,7 +954,7 @@ trait StatementImpl extends Located { self: Statement => case DatatypeDefn(head, body) => s"data type $head of $body" case DataDefn(head) => s"data $head" case _: Term => super.toString - case d: Decl => d.show + case d: Decl => d.showDbg case d: NuDecl => d.showDbg } } diff --git a/shared/src/test/diff/fcp/ForallTerms.mls b/shared/src/test/diff/fcp/ForallTerms.mls index 9045eeb01f..5a0ef5695c 100644 --- a/shared/src/test/diff/fcp/ForallTerms.mls +++ b/shared/src/test/diff/fcp/ForallTerms.mls @@ -73,7 +73,7 @@ f = forall 'A. fun (x: 'A) -> x + 1 //│ ╟── but it flows into reference with expected type `int` //│ ║ l.66: f = forall 'A. fun (x: 'A) -> x + 1 //│ ╙── ^ -//│ f: 'A -> (error | int) +//│ f: anything -> (error | int) //│ = [Function: f1] diff --git a/shared/src/test/diff/nu/Ascription.mls b/shared/src/test/diff/nu/Ascription.mls index 0b50f382cf..9c85bf03ad 100644 --- a/shared/src/test/diff/nu/Ascription.mls +++ b/shared/src/test/diff/nu/Ascription.mls @@ -13,7 +13,7 @@ // TODO? :e 1 : int : int -//│ ╔══[ERROR] not a recognized type: int : int +//│ ╔══[ERROR] not a recognized type //│ ║ l.15: 1 : int : int //│ ╙── ^^^ //│ anything diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 1f399014cb..02b0b726d3 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -10,9 +10,10 @@ mixin BaseTest { //│ ╙── ^ //│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A29' -// TODO support mixin BaseTest(x: A) { fun test = x } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A34_41' +//│ mixin BaseTest[A](x: A) { +//│ fun test: A +//│ } diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index f1d8c0af1e..7d6bfb93df 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -25,19 +25,17 @@ class Foo2[A](x: A) { //│ } -// * FIXME 'A 'A0 A class Foo3[A](x: A) { fun test = Foo3(1) fun foo = Foo3 } //│ class Foo3[A](x: A) { -//│ fun foo: forall 'A 'A0. (x: A,) -> Foo3['A] +//│ fun foo: forall 'A. (x: A,) -> Foo3[A] //│ fun test: Foo3[1] //│ } -// * FIXME `nothing` Foo3 -//│ forall 'A. (x: A,) -> Foo3[nothing] +//│ forall 'A. (x: 'A,) -> Foo3['A] //│ res //│ = [Function (anonymous)] { class: [class Foo3] } @@ -52,7 +50,7 @@ Foo3(1).x //│ = 1 Foo3(1).foo -//│ forall 'A. (x: A,) -> Foo3[nothing] +//│ forall 'A. (x: 'A,) -> Foo3['A] //│ res //│ = [Function (anonymous)] { class: [class Foo3] } diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 3677e04068..83cf6b21db 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -410,7 +410,7 @@ class DiffTests val res = p.parseAll(p.typingUnit) if (parseOnly) - output("Parsed: " + res.show) + output("Parsed: " + res.showDbg) postProcess(mode, basePath, testName, res).foreach(output) @@ -545,11 +545,6 @@ class DiffTests case N => "fun" }} ${tf.name}: ${tf.ty} where ${tf.ty.showBounds .indentNewLines(indStr+"|")}") - output(s"${indStr}[pretty-printed] ${tf.name}: ${ - // exp.show - typer.expandType(tf.ty)(ctx).show - // typer.expandType(tf.ty)(ctx).showIn(sctx) - .indentNewLines(indStr+"|")}") } } if (mode.dbg || mode.explainErrors) { From 8535c5a31961bec3568b7406bdbb02870f778ea8 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 11 Mar 2023 18:34:39 +0800 Subject: [PATCH 170/498] WIP Move LaxyTypeRef implementation + fix expansion hack --- .../scala/mlscript/ConstraintSolver.scala | 15 +- .../src/main/scala/mlscript/NormalForms.scala | 2 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 526 ++++++++++++++++- .../main/scala/mlscript/TyperDatatypes.scala | 547 +----------------- shared/src/main/scala/mlscript/syntax.scala | 3 +- .../main/scala/mlscript/utils/package.scala | 1 + shared/src/test/diff/nu/MutualRec.mls | 20 +- 7 files changed, 548 insertions(+), 566 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 558ea4d7be..4ef48d89e0 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -513,7 +513,13 @@ class ConstraintSolver extends NormalForms { self: Typer => case (LhsRefined(_, ts, _, trs), RhsBases(pts, _, _)) if ts.exists(pts.contains) => () case (LhsRefined(bo, ts, r, trs), _) if trs.nonEmpty => - annoying(trs.valuesIterator.map(_.expand).toList, LhsRefined(bo, ts, r, SortedMap.empty), Nil, done_rs) + annoying(trs.valuesIterator.flatMap { tr => + if (tr.canExpand) S(tr.expand) + else { + println(s"cannot expand type reference ${tr}; falling back") + tr.expansionFallback + } + }.toList, LhsRefined(bo, ts, r, SortedMap.empty), Nil, done_rs) case (_, RhsBases(pts, bf, trs)) if trs.nonEmpty => annoying(Nil, done_ls, trs.valuesIterator.map(_.expand).toList, RhsBases(pts, bf, SortedMap.empty)) @@ -970,7 +976,12 @@ class ConstraintSolver extends NormalForms { self: Typer => } } case (tr: TypeRef, _) => rec(tr.expand, rhs, true) - case (_, tr: TypeRef) => rec(lhs, tr.expand, true) + case (_, tr: TypeRef) => + if (tr.canExpand) rec(lhs, tr.expand, true) + else { + println(s"cannot expand type reference ${tr}; falling back") + rec(lhs, tr.expansionFallback.getOrElse(TopType), true) + } case (ClassTag(ErrTypeId, _), _) => () case (_, ClassTag(ErrTypeId, _)) => () diff --git a/shared/src/main/scala/mlscript/NormalForms.scala b/shared/src/main/scala/mlscript/NormalForms.scala index 11fdd52d83..38db2d725b 100644 --- a/shared/src/main/scala/mlscript/NormalForms.scala +++ b/shared/src/main/scala/mlscript/NormalForms.scala @@ -701,7 +701,7 @@ class NormalForms extends TyperDatatypes { self: Typer => case ProxyType(underlying) => mk(polymLvl, cons, underlying, pol) case tr @ TypeRef(defn, targs) => // * TODO later: when proper TypeRef-based simplif. is implemented, can remove this special case - if (preserveTypeRefs && !primitiveTypes.contains(defn.name)) { + if (preserveTypeRefs && !primitiveTypes.contains(defn.name) || !tr.canExpand) { of(polymLvl, cons, LhsRefined(tr.mkTag, ssEmp, RecordType.empty, SortedMap(defn -> tr))) } else mk(polymLvl, cons, tr.expand, pol) case TypeBounds(lb, ub) => mk(polymLvl, cons, if (pol) ub else lb, pol) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 7421a141ae..544fbe68da 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -132,15 +132,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => */ } - sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuTypeDefBase with TypedNuDecl { + sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { def nme: TypeName - // val tparams: Ls[TN -> TV] = Nil // TODO override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = this match { case m @ TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => - // println(">>",m.level) - // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) - // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) TypedNuMxn(td, thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], @@ -149,36 +145,19 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => - // println(">>",level,ctx.lvl) - // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), - // params.mapValues(_.freshenAbove(level, rigidify)), - // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), - // tparams.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).asInstanceOf[TV], tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify))( cls.instanceType.freshenAbove(lim, rigidify)) - // case _ => ??? - // } } - // val prov: TP val td: NuTypeDef val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) val level: Level def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = ??? } - // case class TypedNuTypeDef( - // kind: TypeDefKind, - // nme: TypeName, - // tparamsargs: List[(TypeName, TypeVariable)], - // bodyTy: SimpleType, - // baseClasses: Set[TypeName], - // toLoc: Opt[Loc], - // ) - // case class TypedNuAls(level: Level, nme: TypeName)(val prov: TP) extends TypedNuTypeDef(Als) { case class TypedNuAls(level: Level, td: NuTypeDef, tparams: Ls[(TN, TV, Opt[VarianceInfo])], body: ST, @@ -446,8 +425,507 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => }() // }(raise, noProv/*TODO*/)}() - // class TypedTypingUnit(tu: TypingUnit)(implicit ctx: Ctx, raise: Raise) { - // } + + trait LazyTypeInfoImpl { this: LazyTypeInfo => + // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { + private def outerCtx = ctx + // private def outerVars = vars + + val level: Level = ctx.lvl + + private implicit val prov: TP = + TypeProvenance(decl.toLoc, decl.describe) + + println(s"${ctx.lvl}. Created lazy type info $decl") + + lazy val tparams: Ls[(TN, TV, Opt[VarianceInfo])] = ctx.nest.nextLevel { implicit ctx => + decl match { + case td: NuTypeDef => + td.tparams.map(tp => + (tp._2, freshVar(TypeProvenance( + tp._2.toLoc, + "type parameter", + S(tp._2.name), + true), N, S(tp._2.name)), tp._1)) + case fd: NuFunDef => Nil // TODO + } + } + + lazy val explicitVariances: VarianceStore = + MutMap.from(tparams.iterator.map(tp => tp._2 -> tp._3.getOrElse(VarianceInfo.in))) + + def varianceOf(tv: TV)(implicit ctx: Ctx): VarianceInfo = + // TODO make use of inferred vce if result is completed + explicitVariances.get(tv).getOrElse(VarianceInfo.in) + + // println(s"Type params ${tparams.mkString(" ")}") + + lazy private implicit val vars: Map[Str, SimpleType] = + // outerVars ++ tparams.iterator.mapKeys(_.name).toMap + outerVars ++ tparams.iterator.map { + case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) + } + + lazy val typedParams: Ls[Var -> FieldType] = ctx.nest.nextLevel { implicit ctx => + decl match { + case td: NuTypeDef => + td.params.fields.map { + case (S(nme), Fld(mut, spec, value)) => + assert(!mut && !spec, "TODO") // TODO + value.toType match { + case R(tpe) => + implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? + val ty = typeType(tpe) + nme -> FieldType(N, ty)(provTODO) + case _ => ??? + } + case (N, Fld(mut, spec, nme: Var)) => + // assert(!mut && !spec, "TODO") // TODO + // nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) + nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) + case _ => ??? + } + case fd: NuFunDef => Nil // TODO + } + } + + + // val tparams: Ls[(TN, TV, VarianceInfo)] = Nil // TODO + var isComputing: Bool = false // TODO replace by a Ctx entry + var result: Opt[TypedNuDecl] = N + // var result: Opt[A] = N + + val tv: TV = freshVar( + TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), + N, + S(decl.name))(level + 1) + + def map(f: TypedNuDecl => TypedNuDecl): LazyTypeInfo = { + val res = new LazyTypeInfo(decl, implicitly) + // if (result.nonEmpty) res.result = res + res.result = result.map(f) + res + } + + // TODO does this also need freshening in freshenAbove? + private lazy val thisTV: TV = + // freshVar(noProv/*FIXME*/, N, S("this_"+decl.name))(lvl + 1) + freshVar(noProv/*FIXME*/, N, S(decl.name.decapitalize))(lvl + 1) + + def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { + if (isComputing) { + // lastWords(s"TODO cyclic defition ${decl.name}") + err(msg"Unhandled cyclic definition", decl.toLoc) // TODO better loc/explanation + } + // else // TODO avert infinite completion recursion here? + trace(s"Completing ${decl.showDbg}") { + println(s"Type params ${tparams.mkString(" ")}") + println(s"Params ${typedParams.mkString(" ")}") + + val res = try { + isComputing = true + decl match { + case fd: NuFunDef => + // assert(fd.isLetRec.isEmpty, fd.isLetRec) + def checkNoTyParams() = + if (fd.tparams.nonEmpty) + err(msg"Type parameters here are not yet supported in this position", + fd.tparams.head.toLoc) + val res_ty = fd.rhs match { + case R(PolyType(tps, ty)) => + checkNoTyParams() + // val body_ty = typeType(ty)(ctx.nextLevel, raise, + // vars = tps.map(tp => tp.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) + val body_ty = + // ctx.nextLevel { implicit ctx: Ctx => + // // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods + // // * in the current typing unit are quantified together. + ctx.poly { implicit ctx: Ctx => + typeType(ty)(ctx, raise, + vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) + } + // TODO check against `tv` + TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) + case L(body) => + // println(fd.isLetRec) + // implicit val vars: Map[Str, SimpleType] = + // outerVars ++ Map.empty // TODO tparams + fd.isLetRec match { + case S(true) => // * Let rec bindings + checkNoTyParams() + implicit val gl: GenLambdas = true + TypedNuFun(ctx.lvl, fd, typeTerm( + Let(true, fd.nme, body, fd.nme) + )) + case S(false) => // * Let bindings + checkNoTyParams() + implicit val gl: GenLambdas = true + TypedNuFun(ctx.lvl, fd, typeTerm(body)) + case N => + /* + implicit val gl: GenLambdas = true + val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) + // implicit val prov: TP = noProv // TODO + // subsume(body_ty, PolymorphicType(level, tv)) // TODO + TypedNuFun(ctx.lvl, fd, body_ty) + */ + + // * We don't type functions polymorphically from the point of view of a typing unit + // * to avoid cyclic-looking constraints due to the polymorphic recursion limitation, + // * as these functions are allowed to be mutually-recursive. + // * In the future, we should type each mutual-recursion-component independently + // * and polymorphically wrt to non-recursive users of them. + implicit val gl: GenLambdas = false + val body_ty = ctx.nextLevel { implicit ctx: Ctx => + // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods + // * in the current typing unit are quantified together. + vars ++ fd.tparams.map { tn => + tn.name -> freshVar(TypeProvenance(tn.toLoc, "method type parameter", + originName = S(tn.name), + isType = true), N) + } |> { implicit vars => + typeTerm(body) + } + } + TypedNuFun(ctx.lvl, fd, body_ty) + } + } + // // subsume(res_ty, tv) + // constrain(res_ty.ty, tv) + ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.ty, tv) } + res_ty + + + case td: NuTypeDef => + + td.kind match { + + case Trt => + err(msg"traits are not yet supported" -> td.toLoc :: Nil) + ??? + + case Als => + + if (td.params.fields.nonEmpty) + err(msg"type alias definitions cannot have value parameters" -> td.params.toLoc :: Nil) + if (td.parents.nonEmpty) + err(msg"type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) + + val body_ty = td.sig match { + case S(sig) => + typeType(sig) + case N => + err(msg"type alias definition requires a right-hand side", td.toLoc) + } + + TypedNuAls(outerCtx.lvl, td, tparams, body_ty) + + case Cls | Nms => + + // implicit val prov: TP = noProv // TODO + ctx.nest.nextLevel { implicit ctx => + + if ((td.kind is Nms) && typedParams.nonEmpty) + // * Can we do better? (Memoization semantics?) + err(msg"${td.kind.str} parameters are not supported", + Loc(typedParams.iterator.map(_._1))) + + ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + + ctx += "this" -> VarSymbol(thisTV, Var("this")) + + val sig_ty = typeType(td.sig.getOrElse(Top)) + td.sig match { + case S(sig) => + err(msg"type signatures not yet supported for classes", sig.toLoc) + case N => () + } + + implicit val prov: TP = + TypeProvenance(decl.toLoc, decl.describe) + + // val finalType = freshVar(noProv/*TODO*/, N, S("this")) + val finalType = thisTV + + val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi + val fldNme = td.nme.name + "#" + tp.name + NuParam(Var(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isType = true) + } + // tparamMems.map(p => p.nme -> p.ty):Int + val tparamFields = tparamMems.map(p => p.nme -> p.ty) + assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) + + + def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]) + : (ST, Ls[NuMember]) = + parents match { + // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { + // case R(p) :: ps => ??? + // case L(p) :: ps => + case p :: ps => + val newMembs = trace(s"${lvl}. Inheriting from $p") { + val (v @ Var(mxnNme), mxnArgs) = p match { + case v @ Var(nme) => + v -> Nil + case App(v @ Var(nme), Tup(args)) => + v -> args + case _ => + err(msg"Unsupported parent specification", p.toLoc) // TODO + return inherit(ps, superType, members) + } + ctx.get(mxnNme) match { + case S(lti: LazyTypeInfo) => + lti.complete().freshen match { + case mxn: TypedNuMxn => + + println(s"Fresh $mxn") + + assert(finalType.level === lvl) + assert(mxn.superTV.level === lvl) + assert(mxn.thisTV.level === lvl) + + constrain(superType, mxn.superTV) + constrain(finalType, mxn.thisTV) + + if (mxnArgs.sizeCompare(mxn.params) =/= 0) + err(msg"mixin $mxnNme expects ${ + mxn.params.size.toString} parameters; got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) + + val paramMems = mxn.params.lazyZip(mxnArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false) + } + + // TODO check overriding + val bodyMems = mxn.ttu.entities.map(_.complete()).map { + case fun @ TypedNuFun(_, fd, ty) => + fun + case m: NuMember => m + // case _ => ??? + } + + paramMems ++ bodyMems + + case cls: TypedNuCls => + err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO + Nil + case als: TypedNuAls => + // TODO dealias first? + err(msg"Cannot inherit from a type alias", p.toLoc) + Nil + case cls: TypedNuFun => + err(msg"Cannot inherit from this", p.toLoc) + Nil + } + case S(_) => + err(msg"Cannot inherit from this", p.toLoc) + Nil + case N => + err(msg"Could not find definition `${mxnNme}`", p.toLoc) + Nil + } + }() + val newSuperType = + // superType & + WithType( + superType, + RecordType( + // newMembs.foldLeft(TopType.toUpper(provTODO))(_ && _.ty.toUpper(provTODO)) + // newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) + newMembs.collect{ + case m: NuParam => m.nme -> m.ty + case m: TypedNuFun => m.fd.nme -> m.ty.toUpper(provTODO) + } + )(provTODO) + )(provTODO) + inherit(ps, newSuperType, members ++ newMembs) + case Nil => + val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & + clsNameToNomTag(td)(provTODO, ctx) & + RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) + trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { + assert(finalType.level === lvl) + constrain(thisType, finalType) + members + }() + // println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") + (thisType, members) + } + + // * We start from an empty super type. + val baseType = + RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) + + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) + // val baseMems = inherit(td.parents, baseType, Nil) + + val (thisType, baseMems) = + inherit(td.parents, baseType, tparamMems ++ paramMems) + + // ctx += thisTV + + // TODO + // ctx += "super" -> VarSymbol(superTV, Var("super")) + ctx += "super" -> VarSymbol(thisType, Var("super")) + + val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use + + // TODO check overriding + val clsMems = ttu.entities.map(_.complete()) + // .map { + // case fun @ TypedNuFun(_, fd, ty) => + // fun + // // case _ => ??? + // case m => m + // } + + // val thisTy = ClassTag(Var(td.name), + // Set.empty//TODO + // )(provTODO) + // constrain(thisTy, thisTV) + + // val thisType = superType & + // clsNameToNomTag(td)(provTODO, ctx) & + // RecordType(tparamFields)(ttp(td.params, isType = true)) + + // val mems = baseMems ++ paramMems ++ clsMems + val mems = baseMems ++ clsMems + + TypedNuCls(outerCtx.lvl, td, ttu, + tparams, typedParams, mems.map(d => d.name -> d).toMap, + // if (td.kind is Nms) TopType else thisTV + TopType + )(thisType) + } + case Mxn => + if (td.parents.nonEmpty) + err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) + ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) + ctx.nest.nextLevel { implicit ctx => + implicit val vars: Map[Str, SimpleType] = + outerVars ++ Map.empty // TODO type params + val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) + val superTV = freshVar(noProv/*FIXME*/, N, S("super")) + ctx += "this" -> VarSymbol(thisTV, Var("this")) + ctx += "super" -> VarSymbol(superTV, Var("super")) + // ctx |> { implicit ctx => + val ttu = typeTypingUnit(td.body, allowPure = false) + val mems = paramMems ++ttu.entities.map(_.complete()) + TypedNuMxn(td, thisTV, superTV, tparams, typedParams, mems.map(m => m.name -> m).toMap, ttu) + // } + } + // case Als => ??? + // case _ => ??? + } + } + + // } finally { result = S(res); isComputing = false } + } finally { /* result = S(res); */ isComputing = false } + + result = S(res) + res + + }() + } + def typeSignature(implicit raise: Raise): ST = + /* + if (isComputing) + decl match { + case _: NuFunDef => + println(s"Already computing! Using TV: $tv") + tv // TODO FIXME wrong in general (when accessed from difft scope/level) + case _ => + err(msg"Cyclic definition", decl.toLoc) + } + else complete() match { + case cls: TypedNuCls if cls.td.kind is Nms => + ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) + case _cls: TypedNuCls => + val cls = _cls.freshen.asInstanceOf[TypedNuCls] + PolymorphicType.mk(cls.level, + FunctionType( + TupleType(cls.params.mapKeys(some))(provTODO), + // cls.tparams.foldLeft( + // ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) + // ) { case (acc, (tn, tv)) => acc & } + ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( + cls.tparams.map { case (tn, tv, vi) => // TODO use vi + Var(cls.td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + )(provTODO) + )(provTODO) + ) + case TypedNuFun(_, fd, ty) => + // println(fd, ty) + // ??? + ty + } + */ + decl match { + case _: NuFunDef => + if (isComputing) { + println(s"Already computing! Using TV: $tv") + tv // TODO FIXME wrong in general (when accessed from difft scope/level) + } else complete() match { + case TypedNuFun(_, fd, ty) => + ty + case _ => die + } + case td: NuTypeDef if td.kind is Nms => + ClassTag(Var(td.nme.name), + // TODO base classes + // Set.empty + Set.single(TN("Eql")) + )(provTODO) + case td: NuTypeDef if td.kind is Cls => + PolymorphicType.mk(level, + FunctionType( + TupleType(typedParams.mapKeys(some))(provTODO), + ClassTag(Var(td.nme.name), + // TODO base classes + // Set.empty + Set.single(TypeName("Eql")) + )(provTODO) & RecordType.mk( + tparams.map { case (tn, tv, vi) => // TODO use vi + Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + )(provTODO) + )(provTODO) + ) + } + + def force()(implicit raise: Raise): TypedNuDecl = { + val res = complete() + res.force() + // decl match { + // case td: NuTypeDef => + // td.kind match { + // case Cls | Nms => + // // implicit val prov: TP = noProv // TODO + // // val thisTy = ClassTag(Var(td.name), + // // Set.empty//TODO + // // )(provTODO) + // // constrain(thisTy, thisTV) + // case _ => + // } + // case _ => + // } + res match { + case cls: TypedNuCls => + // implicit val prov: TP = noProv // TODO + // constrain(cls.instanceType, thisTV) + // println(cls.variances) + case _ => + } + res + } + override def toString: String = + s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" + + } + } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 1ec28f5fe9..86461efed7 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -16,6 +16,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => // The data types used for type inference: + case class TypeProvenance(loco: Opt[Loc], desc: Str, originName: Opt[Str] = N, isType: Bool = false) { val isOrigin: Bool = originName.isDefined def & (that: TypeProvenance): TypeProvenance = this // arbitrary; maybe should do better @@ -23,532 +24,21 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } type TP = TypeProvenance + sealed abstract class TypeInfo + /** A type for abstract classes that is used to check and throw * errors if the abstract class is being instantiated */ case class AbstractConstructor(absMths: Set[Var], isTraitWithMethods: Bool) extends TypeInfo + case class VarSymbol(ty: ST, definingVar: Var) extends TypeInfo - // case class DeclType(level: Level, info: LazyTypeInfo) extends SimpleType { - // // def level: Level = info.complete().level - // def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = ??? - // val prov: TP = TypeProvenance(info.decl.toLoc, info.decl.describe, isType = true) - // } - // case class DeclType() extends SimpleType { - protected abstract class TypedNuTypeDefBase - // protected abstract class TypedNuTypeDefBase extends SimpleType + class LazyTypeInfo(val decl: NuDecl, val outerVars: Map[Str, SimpleType]) + (implicit val ctx: Ctx, val raise: Raise) extends TypeInfo with LazyTypeInfoImpl - // TODO rm level? already in ctx - // class LazyTypeInfo(val level: Int, val decl: NuDecl)(implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]) extends TypeInfo { - class LazyTypeInfo(val decl: NuDecl, outerVars: Map[Str, SimpleType]) - (implicit ctx: Ctx, raise: Raise) extends TypeInfo { - // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { - private def outerCtx = ctx - // private def outerVars = vars - - val level: Level = ctx.lvl - - private implicit val prov: TP = - TypeProvenance(decl.toLoc, decl.describe) - - println(s"${ctx.lvl}. Created lazy type info $decl") - - lazy val tparams: Ls[(TN, TV, Opt[VarianceInfo])] = ctx.nest.nextLevel { implicit ctx => - decl match { - case td: NuTypeDef => - td.tparams.map(tp => - (tp._2, freshVar(TypeProvenance( - tp._2.toLoc, - "type parameter", - S(tp._2.name), - true), N, S(tp._2.name)), tp._1)) - case fd: NuFunDef => Nil // TODO - } - } - - lazy val explicitVariances: VarianceStore = - MutMap.from(tparams.iterator.map(tp => tp._2 -> tp._3.getOrElse(VarianceInfo.in))) - - def varianceOf(tv: TV)(implicit ctx: Ctx): VarianceInfo = - // TODO make use of inferred vce if result is completed - explicitVariances.get(tv).getOrElse(VarianceInfo.in) - - // println(s"Type params ${tparams.mkString(" ")}") - - lazy private implicit val vars: Map[Str, SimpleType] = - // outerVars ++ tparams.iterator.mapKeys(_.name).toMap - outerVars ++ tparams.iterator.map { - case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) - } - - lazy val typedParams: Ls[Var -> FieldType] = ctx.nest.nextLevel { implicit ctx => - decl match { - case td: NuTypeDef => - td.params.fields.map { - case (S(nme), Fld(mut, spec, value)) => - assert(!mut && !spec, "TODO") // TODO - value.toType match { - case R(tpe) => - implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? - val ty = typeType(tpe) - nme -> FieldType(N, ty)(provTODO) - case _ => ??? - } - case (N, Fld(mut, spec, nme: Var)) => - // assert(!mut && !spec, "TODO") // TODO - // nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) - nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) - case _ => ??? - } - case fd: NuFunDef => Nil // TODO - } - } - - - // val tparams: Ls[(TN, TV, VarianceInfo)] = Nil // TODO - var isComputing: Bool = false // TODO replace by a Ctx entry - var result: Opt[TypedNuDecl] = N - // var result: Opt[A] = N - - val tv: TV = freshVar( - TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), - N, - S(decl.name))(level + 1) - - def map(f: TypedNuDecl => TypedNuDecl): LazyTypeInfo = { - val res = new LazyTypeInfo(decl, implicitly) - // if (result.nonEmpty) res.result = res - res.result = result.map(f) - res - } - - // TODO does this also need freshening in freshenAbove? - private lazy val thisTV: TV = - // freshVar(noProv/*FIXME*/, N, S("this_"+decl.name))(lvl + 1) - freshVar(noProv/*FIXME*/, N, S(decl.name.decapitalize))(lvl + 1) - - def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { - if (isComputing) { - // lastWords(s"TODO cyclic defition ${decl.name}") - err(msg"Unhandled cyclic definition", decl.toLoc) // TODO better loc/explanation - } - // else // TODO avert infinite completion recursion here? - trace(s"Completing ${decl.showDbg}") { - println(s"Type params ${tparams.mkString(" ")}") - println(s"Params ${typedParams.mkString(" ")}") - - val res = try { - isComputing = true - decl match { - case fd: NuFunDef => - // assert(fd.isLetRec.isEmpty, fd.isLetRec) - def checkNoTyParams() = - if (fd.tparams.nonEmpty) - err(msg"Type parameters here are not yet supported in this position", - fd.tparams.head.toLoc) - val res_ty = fd.rhs match { - case R(PolyType(tps, ty)) => - checkNoTyParams() - // val body_ty = typeType(ty)(ctx.nextLevel, raise, - // vars = tps.map(tp => tp.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) - val body_ty = - // ctx.nextLevel { implicit ctx: Ctx => - // // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods - // // * in the current typing unit are quantified together. - ctx.poly { implicit ctx: Ctx => - typeType(ty)(ctx, raise, - vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) - } - // TODO check against `tv` - TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) - case L(body) => - // println(fd.isLetRec) - // implicit val vars: Map[Str, SimpleType] = - // outerVars ++ Map.empty // TODO tparams - fd.isLetRec match { - case S(true) => // * Let rec bindings - checkNoTyParams() - implicit val gl: GenLambdas = true - TypedNuFun(ctx.lvl, fd, typeTerm( - Let(true, fd.nme, body, fd.nme) - )) - case S(false) => // * Let bindings - checkNoTyParams() - implicit val gl: GenLambdas = true - TypedNuFun(ctx.lvl, fd, typeTerm(body)) - case N => - /* - implicit val gl: GenLambdas = true - val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) - // implicit val prov: TP = noProv // TODO - // subsume(body_ty, PolymorphicType(level, tv)) // TODO - TypedNuFun(ctx.lvl, fd, body_ty) - */ - - // * We don't type functions polymorphically from the point of view of a typing unit - // * to avoid cyclic-looking constraints due to the polymorphic recursion limitation, - // * as these functions are allowed to be mutually-recursive. - // * In the future, we should type each mutual-recursion-component independently - // * and polymorphically wrt to non-recursive users of them. - implicit val gl: GenLambdas = false - val body_ty = ctx.nextLevel { implicit ctx: Ctx => - // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods - // * in the current typing unit are quantified together. - vars ++ fd.tparams.map { tn => - tn.name -> freshVar(TypeProvenance(tn.toLoc, "method type parameter", - originName = S(tn.name), - isType = true), N) - } |> { implicit vars => - typeTerm(body) - } - } - TypedNuFun(ctx.lvl, fd, body_ty) - } - } - // // subsume(res_ty, tv) - // constrain(res_ty.ty, tv) - ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.ty, tv) } - res_ty - - - case td: NuTypeDef => - - td.kind match { - - case Trt => - err(msg"traits are not yet supported" -> td.toLoc :: Nil) - ??? - - case Als => - - if (td.params.fields.nonEmpty) - err(msg"type alias definitions cannot have value parameters" -> td.params.toLoc :: Nil) - if (td.parents.nonEmpty) - err(msg"type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) - - val body_ty = td.sig match { - case S(sig) => - typeType(sig) - case N => - err(msg"type alias definition requires a right-hand side", td.toLoc) - } - - TypedNuAls(outerCtx.lvl, td, tparams, body_ty) - - case Cls | Nms => - - // implicit val prov: TP = noProv // TODO - ctx.nest.nextLevel { implicit ctx => - - if ((td.kind is Nms) && typedParams.nonEmpty) - // * Can we do better? (Memoization semantics?) - err(msg"${td.kind.str} parameters are not supported", - Loc(typedParams.iterator.map(_._1))) - - ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) - - ctx += "this" -> VarSymbol(thisTV, Var("this")) - - val sig_ty = typeType(td.sig.getOrElse(Top)) - td.sig match { - case S(sig) => - err(msg"type signatures not yet supported for classes", sig.toLoc) - case N => () - } - - implicit val prov: TP = - TypeProvenance(decl.toLoc, decl.describe) - - // val finalType = freshVar(noProv/*TODO*/, N, S("this")) - val finalType = thisTV - - val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi - val fldNme = td.nme.name + "#" + tp.name - NuParam(Var(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isType = true) - } - // tparamMems.map(p => p.nme -> p.ty):Int - val tparamFields = tparamMems.map(p => p.nme -> p.ty) - assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) - - - def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]) - : (ST, Ls[NuMember]) = - parents match { - // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { - // case R(p) :: ps => ??? - // case L(p) :: ps => - case p :: ps => - val newMembs = trace(s"${lvl}. Inheriting from $p") { - val (v @ Var(mxnNme), mxnArgs) = p match { - case v @ Var(nme) => - v -> Nil - case App(v @ Var(nme), Tup(args)) => - v -> args - case _ => - err(msg"Unsupported parent specification", p.toLoc) // TODO - return inherit(ps, superType, members) - } - ctx.get(mxnNme) match { - case S(lti: LazyTypeInfo) => - lti.complete().freshen match { - case mxn: TypedNuMxn => - - println(s"Fresh $mxn") - - assert(finalType.level === lvl) - assert(mxn.superTV.level === lvl) - assert(mxn.thisTV.level === lvl) - - constrain(superType, mxn.superTV) - constrain(finalType, mxn.thisTV) - - if (mxnArgs.sizeCompare(mxn.params) =/= 0) - err(msg"mixin $mxnNme expects ${ - mxn.params.size.toString} parameters; got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) - - val paramMems = mxn.params.lazyZip(mxnArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false) - } - - // TODO check overriding - val bodyMems = mxn.ttu.entities.map(_.complete()).map { - case fun @ TypedNuFun(_, fd, ty) => - fun - case m: NuMember => m - // case _ => ??? - } - - paramMems ++ bodyMems - - case cls: TypedNuCls => - err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO - Nil - case als: TypedNuAls => - // TODO dealias first? - err(msg"Cannot inherit from a type alias", p.toLoc) - Nil - case cls: TypedNuFun => - err(msg"Cannot inherit from this", p.toLoc) - Nil - } - case S(_) => - err(msg"Cannot inherit from this", p.toLoc) - Nil - case N => - err(msg"Could not find definition `${mxnNme}`", p.toLoc) - Nil - } - }() - val newSuperType = - // superType & - WithType( - superType, - RecordType( - // newMembs.foldLeft(TopType.toUpper(provTODO))(_ && _.ty.toUpper(provTODO)) - // newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) - newMembs.collect{ - case m: NuParam => m.nme -> m.ty - case m: TypedNuFun => m.fd.nme -> m.ty.toUpper(provTODO) - } - )(provTODO) - )(provTODO) - inherit(ps, newSuperType, members ++ newMembs) - case Nil => - val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & - clsNameToNomTag(td)(provTODO, ctx) & - RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) - trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { - assert(finalType.level === lvl) - constrain(thisType, finalType) - members - }() - // println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") - (thisType, members) - } - - // * We start from an empty super type. - val baseType = - RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) - - val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) - // val baseMems = inherit(td.parents, baseType, Nil) - - val (thisType, baseMems) = - inherit(td.parents, baseType, tparamMems ++ paramMems) - - // ctx += thisTV - - // TODO - // ctx += "super" -> VarSymbol(superTV, Var("super")) - ctx += "super" -> VarSymbol(thisType, Var("super")) - - val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use - - // TODO check overriding - val clsMems = ttu.entities.map(_.complete()) - // .map { - // case fun @ TypedNuFun(_, fd, ty) => - // fun - // // case _ => ??? - // case m => m - // } - - // val thisTy = ClassTag(Var(td.name), - // Set.empty//TODO - // )(provTODO) - // constrain(thisTy, thisTV) - - // val thisType = superType & - // clsNameToNomTag(td)(provTODO, ctx) & - // RecordType(tparamFields)(ttp(td.params, isType = true)) - - // val mems = baseMems ++ paramMems ++ clsMems - val mems = baseMems ++ clsMems - - TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems.map(d => d.name -> d).toMap, - // if (td.kind is Nms) TopType else thisTV - TopType - )(thisType) - } - case Mxn => - if (td.parents.nonEmpty) - err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) - ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) - val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) - ctx.nest.nextLevel { implicit ctx => - implicit val vars: Map[Str, SimpleType] = - outerVars ++ Map.empty // TODO type params - val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) - val superTV = freshVar(noProv/*FIXME*/, N, S("super")) - ctx += "this" -> VarSymbol(thisTV, Var("this")) - ctx += "super" -> VarSymbol(superTV, Var("super")) - // ctx |> { implicit ctx => - val ttu = typeTypingUnit(td.body, allowPure = false) - val mems = paramMems ++ttu.entities.map(_.complete()) - TypedNuMxn(td, thisTV, superTV, tparams, typedParams, mems.map(m => m.name -> m).toMap, ttu) - // } - } - // case Als => ??? - // case _ => ??? - } - } - - // } finally { result = S(res); isComputing = false } - } finally { /* result = S(res); */ isComputing = false } - - result = S(res) - res - - }() - } - def typeSignature(implicit raise: Raise): ST = - /* - if (isComputing) - decl match { - case _: NuFunDef => - println(s"Already computing! Using TV: $tv") - tv // TODO FIXME wrong in general (when accessed from difft scope/level) - case _ => - err(msg"Cyclic definition", decl.toLoc) - } - else complete() match { - case cls: TypedNuCls if cls.td.kind is Nms => - ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) - case _cls: TypedNuCls => - val cls = _cls.freshen.asInstanceOf[TypedNuCls] - PolymorphicType.mk(cls.level, - FunctionType( - TupleType(cls.params.mapKeys(some))(provTODO), - // cls.tparams.foldLeft( - // ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) - // ) { case (acc, (tn, tv)) => acc & } - ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( - cls.tparams.map { case (tn, tv, vi) => // TODO use vi - Var(cls.td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } - )(provTODO) - )(provTODO) - ) - case TypedNuFun(_, fd, ty) => - // println(fd, ty) - // ??? - ty - } - */ - decl match { - case _: NuFunDef => - if (isComputing) { - println(s"Already computing! Using TV: $tv") - tv // TODO FIXME wrong in general (when accessed from difft scope/level) - } else complete() match { - case TypedNuFun(_, fd, ty) => - ty - case _ => die - } - case td: NuTypeDef if td.kind is Nms => - ClassTag(Var(td.nme.name), - // TODO base classes - // Set.empty - Set.single(TN("Eql")) - )(provTODO) - case td: NuTypeDef if td.kind is Cls => - PolymorphicType.mk(level, - FunctionType( - TupleType(typedParams.mapKeys(some))(provTODO), - ClassTag(Var(td.nme.name), - // TODO base classes - // Set.empty - Set.single(TypeName("Eql")) - )(provTODO) & RecordType.mk( - tparams.map { case (tn, tv, vi) => // TODO use vi - Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } - )(provTODO) - )(provTODO) - ) - } - - def force()(implicit raise: Raise): TypedNuDecl = { - val res = complete() - res.force() - // decl match { - // case td: NuTypeDef => - // td.kind match { - // case Cls | Nms => - // // implicit val prov: TP = noProv // TODO - // // val thisTy = ClassTag(Var(td.name), - // // Set.empty//TODO - // // )(provTODO) - // // constrain(thisTy, thisTV) - // case _ => - // } - // case _ => - // } - res match { - case cls: TypedNuCls => - // implicit val prov: TP = noProv // TODO - // constrain(cls.instanceType, thisTV) - // println(cls.variances) - case _ => - } - res - } - override def toString: String = - s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" - } - - // /** A type that potentially contains universally quantified type variables, - // * and which can be isntantiated to a given level. */ - // sealed abstract class TypeScheme { - // def uninstantiatedBody: SimpleType - // def instantiate(implicit lvl: Int): SimpleType - // } /** A type with universally quantified type variables * (by convention, those variables of level greater than `level` are considered quantified). */ @@ -907,24 +397,17 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = targs.iterator.map(_.levelBelow(ub)).maxOption.getOrElse(MinLevel) override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]): TypeRef = TypeRef(defn, targs.map(_.freshenAbove(lim, rigidify)))(prov) + def canExpand(implicit ctx: Ctx): Bool = ctx.tyDefs2.get(defn.name).forall(_.result.isDefined) def expand(implicit ctx: Ctx): SimpleType = expandWith(paramTags = true) def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = //if (defn.name.isCapitalized) { - // ctx.tyDefs2.get(defn.name).map(_.decl match { - // case td: NuTypeDef if td.kind is Cls => - // ClassTag(Var(td.nme.name).withLocOf(td.nme), - // Set.empty//TODO - // )(provTODO) - // case _ => ??? - // } ctx.tyDefs2.get(defn.name).map { info => - implicit val raise: Raise = throw _ // FIXME - info.complete() match { - case td: TypedNuAls => + info.result match { + case S(td: TypedNuAls) => assert(td.tparams.size === targs.size) substSyntax(td.body)(td.tparams.lazyZip(targs).map { case (tp, ta) => SkolemTag(tp._2.level, tp._2)(noProv) -> ta }.toMap) - case td: TypedNuCls => + case S(td: TypedNuCls) => assert(td.tparams.size === targs.size) clsNameToNomTag(td.td)(provTODO, ctx) & RecordType(td.tparams.lazyZip(targs).map { @@ -932,7 +415,8 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => val fldNme = td.td.nme.name + "#" + tn.name Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) })(provTODO) - case _ => ??? + case S(d) => wat("unexpected declaration in type reference", d) + case N => lastWords("cannot expand unforced type reference") // Definition was not forced yet, which indicates an error (hopefully) } }.getOrElse { val td = ctx.tyDefs(defn.name) @@ -950,9 +434,11 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => case Nms => throw new NotImplementedError("Namespaces are not supported yet.") case Cls => clsNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags case Trt => trtNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags + case Mxn => lastWords("mixins cannot be used as types") }, td.targs.lazyZip(targs).toMap) //.withProv(prov) } //tap { res => println(s"Expand $this => $res") } private var tag: Opt[Opt[ClassTag]] = N + def expansionFallback(implicit ctx: Ctx): Opt[ST] = mkTag def mkTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { val res = ctx.tyDefs.get(defn.name) match { case S(td: TypeDef) if td.kind is Cls => S(clsNameToNomTag(td)(noProv, ctx)) @@ -962,11 +448,6 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => res } def mapTargs[R](pol: Opt[Bool])(f: (Opt[Bool], ST) => R)(implicit ctx: Ctx): Ls[R] = { - // val td = ctx.tyDefs(defn.name) - // td.tvarVariances.fold(targs.map(f(N, _))) { tvv => - // assert(td.tparamsargs.sizeCompare(targs) === 0) - // (td.tparamsargs lazyZip targs).map { case ((_, tv), ta) => - // TODO factor w/ below val (tvarVariances, tparamsargs) = ctx.tyDefs.get(defn.name) match { case S(td) => diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 6c757eefba..879b244a1c 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -139,7 +139,7 @@ final case class Bounds(lb: Type, ub: Type) extends Type final case class WithExtension(base: Type, rcd: Record) extends Type final case class Splice(fields: Ls[Either[Type, Field]]) extends Type final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds]) extends Type -final case class FirstClassDefn(defn: NuTypeDef) extends Type +// final case class FirstClassDefn(defn: NuTypeDef) extends Type // TODO final case class Field(in: Opt[Type], out: Type) extends FieldImpl @@ -189,7 +189,6 @@ final case class NuFunDef( isLetRec: Opt[Bool], // None means it's a `fun`, which is always recursive; Some means it's a `let` nme: Var, tparams: Ls[TypeName], - // rhs: Term \/ PolyType, rhs: Term \/ Type, ) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) diff --git a/shared/src/main/scala/mlscript/utils/package.scala b/shared/src/main/scala/mlscript/utils/package.scala index fcf17596ed..b92819269d 100644 --- a/shared/src/main/scala/mlscript/utils/package.scala +++ b/shared/src/main/scala/mlscript/utils/package.scala @@ -203,6 +203,7 @@ package object utils { def TODO(msg: String): Nothing = throw new NotImplementedError(msg) def die: Nothing = lastWords("Program reached and unexpected state.") def lastWords(msg: String): Nothing = throw new Exception(s"Internal Error: $msg") + def wat(msg: String, wat: Any): Nothing = lastWords(s"$msg ($wat)") /** To make Scala unexhaustivity warnings believed to be spurious go away, * while clearly indicating the intent. */ diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 264f95eb99..11dab73fdc 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -205,14 +205,26 @@ Test2_1.d Test2_1.n //│ 456 - -// FIXME where does the throw come from? -// :s +// TODO leverage type annotation to find type class Test2(n: int) { fun inc = Test3.inc(this) } module Test3 { fun inc(t: Test2) = Test2(t.n + 1) } -//│ /!!!\ Uncaught error: mlscript.ErrorReport: Unhandled cyclic definition +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.213: fun inc(t: Test2) = Test2(t.n + 1) +//│ ║ ^^^ +//│ ╟── type `Test2` does not have field 'n' +//│ ║ l.213: fun inc(t: Test2) = Test2(t.n + 1) +//│ ║ ^^^^^ +//│ ╟── but it flows into reference with expected type `{n: ?n}` +//│ ║ l.213: fun inc(t: Test2) = Test2(t.n + 1) +//│ ╙── ^ +//│ class Test2(n: int) { +//│ fun inc: Test2 | error +//│ } +//│ module Test3() { +//│ fun inc: (t: Test2,) -> Test2 +//│ } From f2b1ef9f7ed168ad33d5b349c39970ab82507d5e Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 11 Mar 2023 20:29:43 +0800 Subject: [PATCH 171/498] WIP Use polymorphic equality in tests (because why not) --- shared/src/test/diff/ecoop23/Intro.mls | 12 +++---- .../test/diff/ecoop23/PolymorphicVariants.mls | 34 ++++++++----------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index 7e017b589c..4fba0e2557 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -12,18 +12,18 @@ module None mixin ComparePoint { fun compare(lhs, rhs) = - (lhs.x == rhs.x) && (lhs.y == rhs.y) + (lhs.x === rhs.x) && (lhs.y === rhs.y) } //│ mixin ComparePoint() { -//│ fun compare: ({x: number, y: number}, {x: number, y: number},) -> bool +//│ fun compare: ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b},) -> bool //│ } class Color(str: string) { - fun equals(that) = eq(str)(that.str) + fun equals(that) = str === that.str } //│ class Color(str: string) { -//│ fun equals: {str: anything} -> bool +//│ fun equals: {str: string} -> bool //│ } let Red = Color("red") @@ -94,8 +94,8 @@ module CompareMyPoint extends ComparePoint, CompareColored, CompareNested //│ fun compare: ('a, 'b,) -> bool //│ } //│ where -//│ 'b <: {color: 'color, parent: Some['b] | ~Some[anything], x: number, y: number} -//│ 'a <: {color: {equals: 'color -> bool}, parent: Some['a] | ~Some[anything], x: number, y: number} +//│ 'b <: {color: 'color, parent: Some['b] | ~Some[anything], x: 'c, y: 'd} +//│ 'a <: {color: {equals: 'color -> bool}, parent: Some['a] | ~Some[anything], x: Eql['c], y: Eql['d]} let p0 = MyPoint(0, 0, Red, None) diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 6f32b10224..f20449ec1f 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -20,18 +20,13 @@ class Success[A](result: A) //│ class NotFound() //│ class Success[A](result: A) -let eqStr(l: string, r: string): bool = eq(l)(r) -//│ let eqStr: (l: string, r: string,) -> bool -//│ eqStr -//│ = [Function: eqStr] - fun list_assoc(s, l) = if l is Cons(h, t) then - if eqStr(s, h._1) then Success(h._2) + if s === h._1 then Success(h._2) else list_assoc(s, t) Nil then NotFound() -//│ fun list_assoc: (string, Cons[{_1: string, _2: 'A}] | Nil,) -> (NotFound | Success['A]) +//│ fun list_assoc: (Eql['a], Cons[{_1: 'a, _2: 'A}] | Nil,) -> (NotFound | Success['A]) // fun list_assoc(s: string, l: Cons[{ _1: string, _2: 'b }] | Nil): NotFound | Success['b] @@ -88,7 +83,7 @@ module Test1 extends EvalVar, EvalLambda //│ } //│ where //│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | Var -//│ 'result :> Var | Abs['result] | App['result] +//│ 'result :> Var | App['result] | Abs['result] Test1.eval(Nil, Var("a")) //│ 'a @@ -100,7 +95,7 @@ Test1.eval(Nil, Var("a")) Test1.eval(Nil, Abs("b", Var("a"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'a :> Abs['a] | Var | App['a] //│ res //│ = Abs {} @@ -114,7 +109,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> Abs['a] | Abs[Var] | Var | App['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var //│ res //│ = Var {} @@ -172,19 +167,20 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) //│ res //│ = Var {} +// * This expected error shows that Test2 does not handle Abs expression inputs :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.172: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.172: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.129: if v is +//│ ║ l.124: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.139: let vv = map_expr(eta, v) +//│ ║ l.134: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -220,7 +216,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num //│ res //│ = Var {} -// * Incorrect version, for regression testing +// * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { //│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> ('a | 'result) @@ -235,16 +231,16 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.236: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.232: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.236: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.232: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.129: if v is +//│ ║ l.124: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.139: let vv = map_expr(eta, v) +//│ ║ l.134: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where From d27830c91eedf174c1521a6dc9f84405f724548b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 11 Mar 2023 20:42:55 +0800 Subject: [PATCH 172/498] WIP Refactor: move PolymorphicType and TypeRef methods into TyperHelpers --- .../main/scala/mlscript/TyperDatatypes.scala | 157 +----------------- .../main/scala/mlscript/TyperHelpers.scala | 153 +++++++++++++++++ 2 files changed, 159 insertions(+), 151 deletions(-) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 86461efed7..7c494216d6 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -8,7 +8,7 @@ import scala.annotation.tailrec import mlscript.utils._, shorthands._ import mlscript.Message._ -abstract class TyperDatatypes extends TyperHelpers { self: Typer => +abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => type TN = TypeName val TN: TypeName.type = TypeName @@ -42,57 +42,12 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => /** A type with universally quantified type variables * (by convention, those variables of level greater than `level` are considered quantified). */ - case class PolymorphicType(polymLevel: Level, body: SimpleType) extends SimpleType { // TODO add own prov? + case class PolymorphicType(polymLevel: Level, body: SimpleType) // TODO add own type provenance for consistency + extends SimpleType with PolymorphicTypeImpl { require(polymLevel < MaxLevel, polymLevel) val prov: TypeProvenance = body.prov lazy val level = levelBelow(polymLevel)(MutSet.empty) def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = body.levelBelow(ub min polymLevel) - def instantiate(implicit ctx:Ctx, shadows: Shadows): SimpleType = { - implicit val state: MutMap[TV, ST] = MutMap.empty - println(s"INST [${polymLevel}] $this") - println(s" where ${showBounds}") - val res = body.freshenAbove(polymLevel, rigidify = false) - println(s"TO [${lvl}] ~> $res") - println(s" where ${res.showBounds}") - res - } - def rigidify(implicit ctx:Ctx, raise:Raise, shadows: Shadows): SimpleType = { - implicit val state: MutMap[TV, ST] = MutMap.empty - body.freshenAbove(polymLevel, rigidify = true) - } - def raiseLevelTo(newPolymLevel: Level, leaveAlone: Set[TV] = Set.empty) - (implicit ctx: Ctx, shadows: Shadows): PolymorphicType = { - require(newPolymLevel >= polymLevel) - if (newPolymLevel === polymLevel) return this - implicit val freshened: MutMap[TV, ST] = MutMap.empty - PolymorphicType(newPolymLevel, - self.freshenAbove(polymLevel, body, leaveAlone = leaveAlone)( - ctx.copy(lvl = newPolymLevel + 1), // * Q: is this really fine? cf. stashing/unstashing etc. - freshened, shadows) - ) //(prov) - } - /** Tries to split a polymorphic function type - * by distributing the quantification of *some* of its type vars into the function result. */ - def splitFunction(implicit ctx: Ctx, raise: Raise, shadows: Shadows): Opt[ST] = body match { - case AliasOf(ft @ FunctionType(par, bod)) => - val couldBeDistribbed = bod.varsBetween(polymLevel, MaxLevel) - println(s"could be distribbed: $couldBeDistribbed") - if (couldBeDistribbed.isEmpty) return N - val cannotBeDistribbed = par.varsBetween(polymLevel, MaxLevel) - println(s"cannot be distribbed: $cannotBeDistribbed") - val canBeDistribbed = couldBeDistribbed -- cannotBeDistribbed - if (canBeDistribbed.isEmpty) return N // TODO - val newInnerLevel = - (polymLevel + 1) max cannotBeDistribbed.maxByOption(_.level).fold(MinLevel)(_.level) - val innerPoly = PolymorphicType(polymLevel, bod) - println(s"inner: ${innerPoly}") - val res = FunctionType(par, innerPoly.raiseLevelTo(newInnerLevel, cannotBeDistribbed))(ft.prov) - println(s"raised: ${res}") - println(s" where: ${res.showBounds}") - if (cannotBeDistribbed.isEmpty) S(res) - else S(PolymorphicType(polymLevel, res)) - case _ => N - } override def toString = s"‹∀ $polymLevel. $body›" } object PolymorphicType { @@ -182,7 +137,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => def level: Level def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]): SimpleType = - self.freshenAbove(lim, this, rigidify) + Typer.freshenAbove(lim, this, rigidify) constructedTypes += 1 } type ST = SimpleType @@ -243,7 +198,7 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => lazy val level: Level = levelBelow(MaxLevel)(MutSet.empty) def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = fields.iterator.map(_._2.levelBelow(ub)).maxOption.getOrElse(MinLevel) override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]): RecordType = - self.mapPol(this, N, false)((_, x) => x.freshenAbove(lim, rigidify)) + Typer.mapPol(this, N, false)((_, x) => x.freshenAbove(lim, rigidify)) def toInter: SimpleType = fields.map(f => RecordType(f :: Nil)(prov)).foldLeft(TopType: ST)(((l, r) => ComposedType(false, l, r)(noProv))) def mergeAllFields(fs: Iterable[Var -> FieldType]): RecordType = { @@ -392,111 +347,11 @@ abstract class TyperDatatypes extends TyperHelpers { self: Typer => } type TR = TypeRef - case class TypeRef(defn: TypeName, targs: Ls[SimpleType])(val prov: TypeProvenance) extends SimpleType { + case class TypeRef(defn: TypeName, targs: Ls[SimpleType])(val prov: TypeProvenance) extends SimpleType with TypeRefImpl { def level: Level = targs.iterator.map(_.level).maxOption.getOrElse(0) def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = targs.iterator.map(_.levelBelow(ub)).maxOption.getOrElse(MinLevel) override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]): TypeRef = TypeRef(defn, targs.map(_.freshenAbove(lim, rigidify)))(prov) - def canExpand(implicit ctx: Ctx): Bool = ctx.tyDefs2.get(defn.name).forall(_.result.isDefined) - def expand(implicit ctx: Ctx): SimpleType = expandWith(paramTags = true) - def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = //if (defn.name.isCapitalized) { - ctx.tyDefs2.get(defn.name).map { info => - info.result match { - case S(td: TypedNuAls) => - assert(td.tparams.size === targs.size) - substSyntax(td.body)(td.tparams.lazyZip(targs).map { - case (tp, ta) => SkolemTag(tp._2.level, tp._2)(noProv) -> ta - }.toMap) - case S(td: TypedNuCls) => - assert(td.tparams.size === targs.size) - clsNameToNomTag(td.td)(provTODO, ctx) & - RecordType(td.tparams.lazyZip(targs).map { - case ((tn, tv, vi), ta) => // TODO use vi - val fldNme = td.td.nme.name + "#" + tn.name - Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) - })(provTODO) - case S(d) => wat("unexpected declaration in type reference", d) - case N => lastWords("cannot expand unforced type reference") // Definition was not forced yet, which indicates an error (hopefully) - } - }.getOrElse { - val td = ctx.tyDefs(defn.name) - require(targs.size === td.tparamsargs.size) - lazy val tparamTags = - if (paramTags) RecordType.mk(td.tparamsargs.map { case (tp, tv) => - val tvv = td.getVariancesOrDefault - tparamField(defn, tp) -> FieldType( - Some(if (tvv(tv).isCovariant) BotType else tv), - if (tvv(tv).isContravariant) TopType else tv)(prov) - })(noProv) - else TopType - subst(td.kind match { - case Als => td.bodyTy - case Nms => throw new NotImplementedError("Namespaces are not supported yet.") - case Cls => clsNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags - case Trt => trtNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags - case Mxn => lastWords("mixins cannot be used as types") - }, td.targs.lazyZip(targs).toMap) //.withProv(prov) - } //tap { res => println(s"Expand $this => $res") } - private var tag: Opt[Opt[ClassTag]] = N - def expansionFallback(implicit ctx: Ctx): Opt[ST] = mkTag - def mkTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { - val res = ctx.tyDefs.get(defn.name) match { - case S(td: TypeDef) if td.kind is Cls => S(clsNameToNomTag(td)(noProv, ctx)) - case _ => N - } - tag = S(res) - res - } - def mapTargs[R](pol: Opt[Bool])(f: (Opt[Bool], ST) => R)(implicit ctx: Ctx): Ls[R] = { - // TODO factor w/ below - val (tvarVariances, tparamsargs) = ctx.tyDefs.get(defn.name) match { - case S(td) => - (td.tvarVariances, td.tparamsargs) - case N => - val td = ctx.tyDefs2(defn.name) - (N, td.tparams.map(tp => (tp._1, tp._2))) - } - tvarVariances.fold(targs.map(f(N, _))) { tvv => - assert(tparamsargs.sizeCompare(targs) === 0) - (tparamsargs lazyZip targs).map { case ((_, tv), ta) => - tvv(tv) match { - case VarianceInfo(true, true) => - f(N, TypeBounds(BotType, TopType)(noProv)) - case VarianceInfo(co, contra) => - f(if (co) pol else if (contra) pol.map(!_) else N, ta) - } - }} - } - // TODO dedup w/ above - def mapTargs[R](pol: PolMap)(f: (PolMap, ST) => R)(implicit ctx: Ctx): Ls[R] = { - // val td = ctx.tyDefs.getOrElse(defn.name, ctx.tyDefs2(defn.name)) - // td.tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => - // assert(td.tparamsargs.sizeCompare(targs) === 0) - // (td.tparamsargs lazyZip targs).map { case ((_, tv), ta) => - val (tvarVariances, tparamsargs) = ctx.tyDefs.get(defn.name) match { - case S(td) => - (td.tvarVariances, td.tparamsargs) - case N => - val td = ctx.tyDefs2(defn.name) - // (N, td.tparams) - // (td.explicitVariances, td.tparams) - // TODO computed varces - // (some[VarianceStore]( - // MutMap.from(td.tparams.iterator.map(tp => tp._2 -> tp._3.getOrElse(VarianceInfo.in))) - // ), td.tparams.map(tp => (tp._1, tp._2))) - (some(td.explicitVariances), td.tparams.map(tp => (tp._1, tp._2))) - } - tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => - assert(tparamsargs.sizeCompare(targs) === 0) - (tparamsargs lazyZip targs).map { case ((_, tv), ta) => - tvv(tv) match { - case VarianceInfo(true, true) => - f(pol.invar, TypeBounds(BotType, TopType)(noProv)) - case VarianceInfo(co, contra) => - f(if (co) pol else if (contra) pol.contravar else pol.invar, ta) - } - }} - } override def toString = showProvOver(false) { val displayName = if (primitiveTypes.contains(defn.name)) defn.name.capitalize else defn.name diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 0b87f11ef5..5ff84e7cf2 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -734,6 +734,8 @@ abstract class TyperHelpers { Typer: Typer => } + + trait TypeLikeImpl { self: TypeLike => def childrenPol(pol: PolMap)(implicit ctx: Ctx): List[PolMap -> SimpleType] = { @@ -904,6 +906,157 @@ abstract class TyperHelpers { Typer: Typer => } + + trait PolymorphicTypeImpl { self: PolymorphicType => + + def instantiate(implicit ctx:Ctx, shadows: Shadows): SimpleType = { + implicit val state: MutMap[TV, ST] = MutMap.empty + println(s"INST [${polymLevel}] $this") + println(s" where ${showBounds}") + val res = body.freshenAbove(polymLevel, rigidify = false) + println(s"TO [${lvl}] ~> $res") + println(s" where ${res.showBounds}") + res + } + def rigidify(implicit ctx:Ctx, raise:Raise, shadows: Shadows): SimpleType = { + implicit val state: MutMap[TV, ST] = MutMap.empty + body.freshenAbove(polymLevel, rigidify = true) + } + def raiseLevelTo(newPolymLevel: Level, leaveAlone: Set[TV] = Set.empty) + (implicit ctx: Ctx, shadows: Shadows): PolymorphicType = { + require(newPolymLevel >= polymLevel) + if (newPolymLevel === polymLevel) return this + implicit val freshened: MutMap[TV, ST] = MutMap.empty + PolymorphicType(newPolymLevel, + Typer.freshenAbove(polymLevel, body, leaveAlone = leaveAlone)( + ctx.copy(lvl = newPolymLevel + 1), // * Q: is this really fine? cf. stashing/unstashing etc. + freshened, shadows) + ) //(prov) + } + /** Tries to split a polymorphic function type + * by distributing the quantification of *some* of its type vars into the function result. */ + def splitFunction(implicit ctx: Ctx, raise: Raise, shadows: Shadows): Opt[ST] = body match { + case AliasOf(ft @ FunctionType(par, bod)) => + val couldBeDistribbed = bod.varsBetween(polymLevel, MaxLevel) + println(s"could be distribbed: $couldBeDistribbed") + if (couldBeDistribbed.isEmpty) return N + val cannotBeDistribbed = par.varsBetween(polymLevel, MaxLevel) + println(s"cannot be distribbed: $cannotBeDistribbed") + val canBeDistribbed = couldBeDistribbed -- cannotBeDistribbed + if (canBeDistribbed.isEmpty) return N // TODO + val newInnerLevel = + (polymLevel + 1) max cannotBeDistribbed.maxByOption(_.level).fold(MinLevel)(_.level) + val innerPoly = PolymorphicType(polymLevel, bod) + println(s"inner: ${innerPoly}") + val res = FunctionType(par, innerPoly.raiseLevelTo(newInnerLevel, cannotBeDistribbed))(ft.prov) + println(s"raised: ${res}") + println(s" where: ${res.showBounds}") + if (cannotBeDistribbed.isEmpty) S(res) + else S(PolymorphicType(polymLevel, res)) + case _ => N + } + + } + + + + trait TypeRefImpl { self: TypeRef => + + def canExpand(implicit ctx: Ctx): Bool = ctx.tyDefs2.get(defn.name).forall(_.result.isDefined) + def expand(implicit ctx: Ctx): SimpleType = expandWith(paramTags = true) + def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = //if (defn.name.isCapitalized) { + ctx.tyDefs2.get(defn.name).map { info => + info.result match { + case S(td: TypedNuAls) => + assert(td.tparams.size === targs.size) + substSyntax(td.body)(td.tparams.lazyZip(targs).map { + case (tp, ta) => SkolemTag(tp._2.level, tp._2)(noProv) -> ta + }.toMap) + case S(td: TypedNuCls) => + assert(td.tparams.size === targs.size) + clsNameToNomTag(td.td)(provTODO, ctx) & + RecordType(td.tparams.lazyZip(targs).map { + case ((tn, tv, vi), ta) => // TODO use vi + val fldNme = td.td.nme.name + "#" + tn.name + Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) + })(provTODO) + case S(d) => wat("unexpected declaration in type reference", d) + case N => lastWords("cannot expand unforced type reference") // Definition was not forced yet, which indicates an error (hopefully) + } + }.getOrElse { + val td = ctx.tyDefs(defn.name) + require(targs.size === td.tparamsargs.size) + lazy val tparamTags = + if (paramTags) RecordType.mk(td.tparamsargs.map { case (tp, tv) => + val tvv = td.getVariancesOrDefault + tparamField(defn, tp) -> FieldType( + Some(if (tvv(tv).isCovariant) BotType else tv), + if (tvv(tv).isContravariant) TopType else tv)(prov) + })(noProv) + else TopType + subst(td.kind match { + case Als => td.bodyTy + case Nms => throw new NotImplementedError("Namespaces are not supported yet.") + case Cls => clsNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags + case Trt => trtNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags + case Mxn => lastWords("mixins cannot be used as types") + }, td.targs.lazyZip(targs).toMap) //.withProv(prov) + } //tap { res => println(s"Expand $this => $res") } + private var tag: Opt[Opt[ClassTag]] = N + def expansionFallback(implicit ctx: Ctx): Opt[ST] = mkTag + def mkTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { + val res = ctx.tyDefs.get(defn.name) match { + case S(td: TypeDef) if td.kind is Cls => S(clsNameToNomTag(td)(noProv, ctx)) + case _ => N + } + tag = S(res) + res + } + def mapTargs[R](pol: Opt[Bool])(f: (Opt[Bool], ST) => R)(implicit ctx: Ctx): Ls[R] = { + // TODO factor w/ below + val (tvarVariances, tparamsargs) = ctx.tyDefs.get(defn.name) match { + case S(td) => + (td.tvarVariances, td.tparamsargs) + case N => + val td = ctx.tyDefs2(defn.name) + (N, td.tparams.map(tp => (tp._1, tp._2))) + } + tvarVariances.fold(targs.map(f(N, _))) { tvv => + assert(tparamsargs.sizeCompare(targs) === 0) + (tparamsargs lazyZip targs).map { case ((_, tv), ta) => + tvv(tv) match { + case VarianceInfo(true, true) => + f(N, TypeBounds(BotType, TopType)(noProv)) + case VarianceInfo(co, contra) => + f(if (co) pol else if (contra) pol.map(!_) else N, ta) + } + }} + } + // TODO dedup w/ above + def mapTargs[R](pol: PolMap)(f: (PolMap, ST) => R)(implicit ctx: Ctx): Ls[R] = { + val (tvarVariances, tparamsargs) = ctx.tyDefs.get(defn.name) match { + case S(td) => + (td.tvarVariances, td.tparamsargs) + case N => + val td = ctx.tyDefs2(defn.name) + // TODO use computed varces + (some(td.explicitVariances), td.tparams.map(tp => (tp._1, tp._2))) + } + tvarVariances.fold(targs.map(f(pol.invar, _))) { tvv => + assert(tparamsargs.sizeCompare(targs) === 0) + (tparamsargs lazyZip targs).map { case ((_, tv), ta) => + tvv(tv) match { + case VarianceInfo(true, true) => + f(pol.invar, TypeBounds(BotType, TopType)(noProv)) + case VarianceInfo(co, contra) => + f(if (co) pol else if (contra) pol.contravar else pol.invar, ta) + } + }} + } + + } + + def merge(pol: Bool, ts: Ls[ST]): ST = if (pol) ts.foldLeft(BotType: ST)(_ | _) else ts.foldLeft(TopType: ST)(_ & _) From d76b9b0c45f8b64e44126df66b7c8c6079c0ee8c Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 11 Mar 2023 22:25:20 +0800 Subject: [PATCH 173/498] Add `ne` and `eq` to the JS polyfill --- shared/src/main/scala/mlscript/codegen/Polyfill.scala | 2 ++ shared/src/main/scala/mlscript/codegen/Scope.scala | 2 ++ 2 files changed, 4 insertions(+) diff --git a/shared/src/main/scala/mlscript/codegen/Polyfill.scala b/shared/src/main/scala/mlscript/codegen/Polyfill.scala index 89dd16ba38..90238a76e4 100644 --- a/shared/src/main/scala/mlscript/codegen/Polyfill.scala +++ b/shared/src/main/scala/mlscript/codegen/Polyfill.scala @@ -162,6 +162,8 @@ object Polyfill { buffer += BuiltinFunc("gt", makeBinaryFunc(">")) buffer += BuiltinFunc("not", makeUnaryFunc("!")) buffer += BuiltinFunc("negate", makeUnaryFunc("-")) + buffer += BuiltinFunc("eq", makeBinaryFunc("===")) + buffer += BuiltinFunc("ne", makeBinaryFunc("!==")) buffer.toList } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index c68e1f65be..cf00085ff6 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -38,6 +38,8 @@ class Scope(name: Str, enclosing: Opt[Scope]) { "div", "gt", "not", + "ne", + "eq", "toString", "negate" ) foreach { name => From 4f0f870d6af43132bf2e589781988e533bdcf8aa Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 11 Mar 2023 22:25:54 +0800 Subject: [PATCH 174/498] No longer report inexhaustiveness when there is a default branch --- shared/src/main/scala/mlscript/ucs/Desugarer.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 0a8b7eac5f..4a246d059e 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -547,6 +547,8 @@ class Desugarer extends TypeDefs { self: Typer => case Match(scrutinee, branches, default) => scrutineePatternMap.get(getScurtineeKey(scrutinee)) match { case N => lastWords(s"unreachable case: unknown scrutinee ${scrutinee.term}") + case S(_) if default.isDefined => + printlnUCS("The match has a default branch. So, it is always safe.") case S(patternMap) => printlnUCS(s"The exhaustiveness map is ${scrutineePatternMap}") printlnUCS(s"The scrutinee key is ${getScurtineeKey(scrutinee)}") From f7f04180087cbd68b7dcbd3ae1465c1c7b156e69 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 11 Mar 2023 22:28:10 +0800 Subject: [PATCH 175/498] Add an incomplete implementation of untyped lambda calculus --- shared/src/test/diff/ucs/Lambda.mls | 247 ++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 shared/src/test/diff/ucs/Lambda.mls diff --git a/shared/src/test/diff/ucs/Lambda.mls b/shared/src/test/diff/ucs/Lambda.mls new file mode 100644 index 0000000000..53a135406f --- /dev/null +++ b/shared/src/test/diff/ucs/Lambda.mls @@ -0,0 +1,247 @@ +:NewParser + +class Option +class Some(value): Option +class None(): Option +//│ Defined class Option +//│ Defined class Some +//│ Defined class None +//│ Option: () -> Option +//│ = [Function: Option1] +//│ Some: 'value -> (Some with {value: 'value}) +//│ = [Function: Some1] +//│ None: () -> None +//│ = [Function: None1] + +class Term +class Var(name): Term +class Abs(lhs, rhs): Term +class App(lhs, rhs): Term +//│ Defined class Term +//│ Defined class Var +//│ Defined class Abs +//│ Defined class App +//│ Term: () -> Term +//│ = [Function: Term1] +//│ Var: 'name -> (Var with {name: 'name}) +//│ = [Function: Var1] +//│ Abs: ('lhs, 'rhs,) -> (Abs with {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: Abs1] +//│ App: ('lhs, 'rhs,) -> (App with {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: App1] + +fun concat2(a, b) = concat(a)(b) +fun concat3(a, b, c) = concat2(a, concat2(b, c)) +fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) +fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) +fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) +fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) +fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) +fun par(a) = concat3("(", a, ")") +//│ concat2: (string, string,) -> string +//│ = [Function: concat2] +//│ concat3: (string, string, string,) -> string +//│ = [Function: concat3] +//│ concat4: (string, string, string, string,) -> string +//│ = [Function: concat4] +//│ concat5: (string, string, string, string, string,) -> string +//│ = [Function: concat5] +//│ concat6: (string, string, string, string, string, string,) -> string +//│ = [Function: concat6] +//│ concat7: (string, string, string, string, string, string, string,) -> string +//│ = [Function: concat7] +//│ concat8: (string, string, string, string, string, string, string, string,) -> string +//│ = [Function: concat8] +//│ par: string -> string +//│ = [Function: par] + +fun showTerm(t) = + if t is + Var(name) then toString(name) + Abs(lhs, rhs) then concat4("&", showTerm(lhs), ". ", showTerm(rhs)) + App(Abs(lhs0, lhs1), rhs) then + concat8("((", "&", showTerm(lhs0), ". ", showTerm(lhs1), ") ", showTerm(rhs), ")") + App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) +//│ showTerm: 'a -> string +//│ where +//│ 'a <: Abs & {lhs: 'a, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, rhs: 'a} | ~#Abs), rhs: 'a} | Var +//│ = [Function: showTerm] + +showTerm(Var("x")) +showTerm(Abs(Var("x"), Var("y"))) +showTerm(App(Var("x"), Var("y"))) +showTerm(App(Abs(Var("x"), Var("y")), Var("z"))) +//│ res: string +//│ = 'x' +//│ res: string +//│ = '&x. y' +//│ res: string +//│ = '(x y)' +//│ res: string +//│ = '((&x. y) z)' + +fun isValue(t) = + if t is + Var then true + Abs then true + App then false +//│ isValue: (Abs | App | Var) -> bool +//│ = [Function: isValue] + +isValue(Var("x")) +isValue(Abs(Var("x"), Var("y"))) +isValue(App(Var("x"), Var("y"))) +//│ res: bool +//│ = true +//│ res: bool +//│ = true +//│ res: bool +//│ = false + +fun hasFree(t, n) = + if t is + Var(na) then eq(n)(na) + Abs(Var(name), body) and eq(name, n) then false + Abs(Var(name), body) then hasFree(body, n) + App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) + _ then false +//│ ╔══[WARNING] Found a duplicated else branch +//│ ║ l.107: _ then false +//│ ║ ^^^^^ +//│ ╟── The first else branch was declared here. +//│ ║ l.105: Abs(Var(name), body) then hasFree(body, n) +//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.104: Abs(Var(name), body) and eq(name, n) then false +//│ ║ ^^^^^^^^^^^ +//│ ╟── tuple literal of type `(?name, ?a,)` does not match type `(?b,)` +//│ ║ l.104: Abs(Var(name), body) and eq(name, n) then false +//│ ╙── ^^^^^^^^^ +//│ hasFree: ('a, anything,) -> bool +//│ where +//│ 'a <: Abs & {rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var | ~Abs & ~App & ~Var +//│ = [Function: hasFree] + +fun showHasFree(t, n) = + concat4(showTerm(t), if hasFree(t, n) then " has " else " DOES NOT have ", "free variable ", n) +//│ showHasFree: ('a & 'b, string,) -> string +//│ where +//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var +//│ 'a <: Abs & {rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var | ~Abs & ~App & ~Var +//│ = [Function: showHasFree] + +showHasFree(Var("x"), "x") +showHasFree(Var("x"), "y") +showHasFree(Abs(Var("x"), Var("x")), "x") +showHasFree(Abs(Var("x"), Var("x")), "y") +showHasFree(Abs(Var("x"), Var("y")), "x") +showHasFree(Abs(Var("x"), Var("y")), "y") +showHasFree(App(Var("x"), Var("y")), "x") +showHasFree(App(Var("x"), Var("y")), "y") +//│ res: string +//│ = 'x has free variable x' +//│ res: string +//│ = 'x DOES NOT have free variable y' +//│ res: string +//│ = '&x. x DOES NOT have free variable x' +//│ res: string +//│ = '&x. x DOES NOT have free variable y' +//│ res: string +//│ = '&x. y DOES NOT have free variable x' +//│ res: string +//│ = '&x. y has free variable y' +//│ res: string +//│ = '(x y) has free variable x' +//│ res: string +//│ = '(x y) has free variable y' + +fun subst(t, n, v) = + if t is + Var(name) and eq(name)(n) then v + Abs(Var(name), body) and + ne(name)(n) then Abs(Var(name), subst(body, n, v)) + hasFree(body, n) and freshName(name) is newName then + subst(Abs(Var(newName), subst(body, name, Var(newName))), n, v) + App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) + _ then t +//│ ╔══[ERROR] Cannot find the constructor `newName` in the context +//│ ║ l.163: hasFree(body, n) and freshName(name) is newName then +//│ ╙── ^^^^^^^ +//│ subst: (anything, anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression has not been desugared + +fun showSubst(t, n, v) = + concat8(showTerm(t), " [", n, " / ", showTerm(v), "]", " => ", showTerm(subst(t, n, v))) +//│ showSubst: ('a, string, 'a,) -> string +//│ where +//│ 'a <: Abs & {lhs: 'a, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, rhs: 'a} | ~#Abs), rhs: 'a} | Var +//│ = [Function: showSubst] + +showSubst(Var("x"), "x", Var("y")) +showSubst(Abs(Var("x"), Var("x")), "x", Var("z")) +showSubst(App(Var("x"), Var("y")), "x", Abs(Var("x"), Var("x"))) +//│ res: string +//│ Runtime error: +//│ ReferenceError: subst is not defined +//│ res: string +//│ Runtime error: +//│ ReferenceError: subst is not defined +//│ res: string +//│ Runtime error: +//│ ReferenceError: subst is not defined + +fun stepByValue(t) = + if t is + Var then None() + Abs then None() + App(lhs, rhs) and stepByValue(lhs) is + Some(lhs) then Some(App(lhs, rhs)) + None and stepByValue(rhs) is + Some(rhs) then Some(App(lhs, rhs)) + None and lhs is + Abs(Var(name), body) then Some(subst(body, name, rhs)) + _ then None() +//│ stepByValue: 'a -> (None | (Some with {value: 'rhs})) +//│ where +//│ 'rhs :> error | (App with {lhs: 'rhs, rhs: 'rhs0}) | (App with {lhs: 'lhs, rhs: 'rhs}) +//│ 'a <: Abs | App & {lhs: 'a & 'lhs & (Abs | ~#Abs), rhs: 'a & 'rhs0} | Var +//│ = [Function: stepByValue] + +fun showStepByValue(t) = + concat3(showTerm(t), " => ", if stepByValue(t) is + Some(t) then showTerm(t) + None then "stuck" + ) +//│ showStepByValue: ('a & 'b) -> string +//│ where +//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var +//│ 'a <: Abs | App & {lhs: 'a & 'lhs & (Abs | ~#Abs), rhs: 'a & 'c} | Var +//│ 'lhs <: (Abs & {lhs: 'c, rhs: 'c} | ~Abs) & 'c +//│ 'c <: Abs & {lhs: 'c, rhs: 'c} | App & {lhs: 'lhs, rhs: 'c} | Var +//│ = [Function: showStepByValue] + +showStepByValue(Var("x")) +showStepByValue(Abs(Var("x"), Var("y"))) +showStepByValue(App(Var("x"), Var("y"))) +showStepByValue(App(Abs(Var("x"), Var("x")), Var("y"))) +//│ res: string +//│ = 'x => stuck' +//│ res: string +//│ = '&x. y => stuck' +//│ res: string +//│ = '(x y) => stuck' +//│ res: string +//│ Runtime error: +//│ ReferenceError: subst is not defined + +fun equalTerm(a, b) = + if a is + Var(na) and b is Var(nb) then eq(na)(nb) + Abs(la, ra) and b is Abs(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) + App(la, ra) and b is App(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) + _ then false +//│ equalTerm: ('a, 'a,) -> bool +//│ where +//│ 'a <: Abs & {lhs: 'a, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var | ~Abs & ~App & ~Var +//│ = [Function: equalTerm] From a8db067272fac0143c4911a76c8fab65696bd4c8 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 11 Mar 2023 21:01:55 +0800 Subject: [PATCH 176/498] WIP Some cleanup --- .../src/main/scala/mlscript/NuTypeDefs.scala | 178 ++++++------------ .../main/scala/mlscript/TyperDatatypes.scala | 7 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 4 +- 3 files changed, 62 insertions(+), 127 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 544fbe68da..919d3f3520 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -18,9 +18,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypeDefInfo() extends NuDeclInfo - // * For now these are just unused stubs to be completed and used later - - sealed trait NuMember { def name: Str @@ -52,9 +49,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx): NuMember = NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)), isType) } + + + // TODO: // case class NuTypeParam(nme: TN, ty: FieldType) extends NuMember { // def name: Str = nme.name - + // // def freshenAbove(lim: Int, rigidify: Bool) // (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) // : NuParam = @@ -62,23 +62,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } - // sealed abstract class TypedNuDecl extends NuMember { sealed trait TypedNuDecl extends NuMember { def name: Str def level: Level - // def freshen(implicit ctx: Ctx): TypedNuDecl = this match { - // case m @ TypedNuMxn(td, thisTV, superTV, ttu) => - // implicit val freshened: MutMap[TV, ST] = MutMap.empty - // implicit val shadows: Shadows = Shadows.empty - // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify = false)) - // case _ => ??? - // } def freshen(implicit ctx: Ctx): TypedNuDecl = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty - // println(level) ctx.copy(lvl = level + 1) |> { implicit ctx => - freshenAbove(level, rigidify = false).asInstanceOf[TypedNuDecl] + freshenAbove(level, rigidify = false).asInstanceOf[TypedNuDecl] } } def map(f: ST => ST)(implicit ctx: Ctx): TypedNuDecl = @@ -88,49 +79,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl def force()(implicit raise: Raise): Unit = this match { - case x: TypedNuMxn => x.ttu.force() - case x: TypedNuCls => x.ttu.force() - case _: TypedNuFun => () - case _: TypedNuAls => () + case x: TypedNuMxn => x.ttu.force(); () + case x: TypedNuCls => x.ttu.force(); () + case _: TypedNuFun => + case _: TypedNuAls => } } - sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { - // def childrenTypes: Ls[ST] - /* - def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - : TypedNuTermDef = { - // implicit val freshened: MutMap[TV, ST] = MutMap.empty - // implicit val shadows: Shadows = Shadows.empty - // ctx.copy(lvl = level + 1) |> { implicit ctx => - this match { - case m @ TypedNuMxn(td, thisTV, superTV, ttu) => - // println(">>",m.level) - // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(m.level, rigidify)) - // TypedNuMxn(td, thisTV, superTV, ttu.freshenAbove(lim, rigidify)) - TypedNuMxn(td, - thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], - superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], - ttu.freshenAbove(lim, rigidify)) - case TypedNuFun(level, fd, ty) => - // TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(level, rigidify)) - TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) - case TypedNuCls(level, td, ttu, tps, params, members) => - println(">>",level,ctx.lvl) - // TypedNuCls(level, td, ttu.freshenAbove(level, rigidify), - // params.mapValues(_.freshenAbove(level, rigidify)), - // members.mapValuesIter(_.freshenAbove(level, rigidify)).toMap) - TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), - tps.mapValues(_.freshenAbove(lim, rigidify).asInstanceOf[TV]), - params.mapValues(_.freshenAbove(lim, rigidify)), - members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap) - // case _ => ??? - // } - } - } - */ - } + + sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef + sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { def nme: TypeName @@ -138,19 +96,23 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => this match { case m @ TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => TypedNuMxn(td, - thisTV.freshenAbove(lim, rigidify).asInstanceOf[TV], - superTV.freshenAbove(lim, rigidify).asInstanceOf[TV], - tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).asInstanceOf[TV], tp._3)), + thisTV.freshenAbove(lim, rigidify), + superTV.freshenAbove(lim, rigidify), + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), - tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify))( cls.instanceType.freshenAbove(lim, rigidify)) + case cls @ TypedNuAls(level, td, tparams, body) => + TypedNuAls(level, td, + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), + body.freshenAbove(lim, rigidify)) } val td: NuTypeDef val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) @@ -158,15 +120,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = ??? } + case class TypedNuAls(level: Level, td: NuTypeDef, tparams: Ls[(TN, TV, Opt[VarianceInfo])], body: ST, - ) extends TypedNuTypeDef(Als) { + ) extends TypedNuTypeDef(Als) + { def name: Str = nme.name def nme: mlscript.TypeName = td.nme - // def freshenAbove(lim: Int, rigidify: Bool) - // (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - // : TypedNuTypeDef = ??? def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl = @@ -184,16 +145,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ) } - // case class TypedNuCls(nme: TypeName) extends TypedNuTypeDef(Als) with TypedNuTermDef { - case class TypedNuCls(level: Level, td: NuTypeDef, ttu: TypedTypingUnit, + + case class TypedNuCls( + level: Level, td: NuTypeDef, ttu: TypedTypingUnit, tparams: Ls[(TN, TV, Opt[VarianceInfo])], params: Ls[Var -> FieldType], - // members: Map[Str, LazyTypeInfo]) - members: Map[Str, NuMember], - thisTy: ST - )( - val instanceType: ST, // only meant to be used in `force` and `variances` - ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { - // case class TypedNuCls(td: NuTypeDef, paramTypes: Ls[ST], ttu: TypedTypingUnit) extends TypedNuTypeDef(Cls) with TypedNuTermDef { + members: Map[Str, NuMember], thisTy: ST + )(val instanceType: ST, // * only meant to be used in `force` and `variances` + ) extends TypedNuTypeDef(Cls) with TypedNuTermDef + { + def nme: TypeName = td.nme def name: Str = nme.name @@ -210,15 +170,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => _variances match { case S(res) => res case N => - // CompletedTypingUnit(this :: Nil, N).childrenPol(PolMap.pos) - - // val vars = CompletedTypingUnit(this :: Nil, N).getVarsPol(PolMap.pos) - // MutMap.from(vars.iterator.mapValues { - // case S(true) => VarianceInfo.co - // case S(false) => VarianceInfo.contra - // case N => VarianceInfo.in - // }) - val store = VarianceStore.empty object Trav extends Traverser2.InvariantFields { override def apply(pol: PolMap)(ty: ST): Unit = @@ -238,16 +189,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } }() } - // Trav.applyLike(PolMap.pos)(CompletedTypingUnit(this :: Nil, N)) Trav(PolMap.pos)(instanceType) - // println(store) - store // TODO check consistency with explicitVariances store ++ tparams.iterator.collect { case (_, tv, S(vi)) => tv -> vi } } } + def varianceOf(tv: TV)(implicit ctx: Ctx): VarianceInfo = variances.getOrElse(tv, VarianceInfo.in) @@ -255,30 +204,29 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, ttu, tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), - // params.mapValues(_.mapPol(pol)(f)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, - f(pol.map(!_), thisTy)//.asInstanceOf[TV] + f(pol.map(!_), thisTy) )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, ttu, tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), - // params.mapValues(_.mapPol(pol)(f)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, - f(pol.contravar, thisTy)//.asInstanceOf[TV] + f(pol.contravar, thisTy) )(f(pol, instanceType)) } - case class TypedNuMxn(td: NuTypeDef, thisTV: ST, superTV: ST, + case class TypedNuMxn( + td: NuTypeDef, thisTV: ST, superTV: ST, tparams: Ls[(TN, TV, Opt[VarianceInfo])], params: Ls[Var -> FieldType], members: Map[Str, NuMember], ttu: TypedTypingUnit, - ) extends TypedNuTypeDef(Mxn) with TypedNuTermDef { + ) extends TypedNuTypeDef(Mxn) with TypedNuTermDef + { val level: Level = thisTV.level - 1 // TODO cleaner def nme: TypeName = td.nme def name: Str = nme.name - // def freshen(implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -294,6 +242,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) } + /** Note: the type `ty` is stoed *without* its polymorphic wrapper! */ case class TypedNuFun(level: Level, fd: NuFunDef, ty: ST) extends TypedNuDecl with TypedNuTermDef { def name: Str = fd.nme.name @@ -301,19 +250,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedNuFun = this match { case TypedNuFun(level, fd, ty) => - // TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(level, rigidify)) TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) } def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - // TypedNuFun(level, fd, ty.mapPol(pol, smart)(f)) TypedNuFun(level, fd, f(pol, ty)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuFun(level, fd, f(pol, ty)) } + case class CompletedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) extends OtherTypeLike { def map(f: ST => ST)(implicit ctx: Ctx): CompletedTypingUnit = CompletedTypingUnit(entities.map(_.map(f)), result.map(f)) @@ -324,8 +272,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx): CompletedTypingUnit = CompletedTypingUnit(entities.map(_.mapPolMap(pol)(f)), result.map(f(pol, _))) } + + case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) /* extends OtherTypeLike */ { - // def freshen(implicit ctx: Ctx): TypedTypingUnit = ??? def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = @@ -336,20 +285,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } + + /** Type checks a typing unit, which is a sequence of possibly-nutually-recursive type and function definitions + * interleaved with plain statements. */ def typeTypingUnit(tu: TypingUnit, allowPure: Bool) (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]): TypedTypingUnit = - trace(s"${ctx.lvl}. Typing $tu") { - // trace(s"${ctx.lvl}. Typing $tu") { ctx.nextLevel { implicit ctx: Ctx => - // val named = mutable.Map.empty[Str, LazyTypeInfo[TypedNuTermDef]] + trace(s"${ctx.lvl}. Typing $tu") + { val named = mutable.Map.empty[Str, LazyTypeInfo] - // val namedTerms = mutable.Map.empty[Var, LazyTypeInfo[TypedNuTypeDef]] - // val namedTypes = mutable.Map.empty[TypeName, LazyTypeInfo[TypedNuTypeDef]] - // val namedTerms = mutable.Map.empty[Str, LazyTypeInfo[ST]] - // val namedTypes = mutable.Map.empty[Str, LazyTypeInfo[TypedNuTypeDef]] - // val infos = tu.entities.collect { - // case fd: NuFunDef => fd.nme.name -> new LazyTypeInfo(lvl, fd) - // case td: NuTypeDef => td.nme.name -> new LazyTypeInfo(lvl, td) - // } + val infos = tu.entities.collect { case decl: NuDecl => val lti = new LazyTypeInfo(decl, implicitly) @@ -358,7 +302,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.tyDefs2 += td.nme.name -> lti case _: NuFunDef => } - // def registerTerm = named.updateWith(decl.name) { case sv @ S(v) => // * TODO allow defining a previously given signature @@ -372,28 +315,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => S(lti) } decl.name -> lti - // decl match { - // case fd: NuFunDef => - // registerTerm - // fd.nme.name -> lti - // case td: NuTypeDef => - // registerTerm - // td.nme.name -> new LazyTypeInfo(lvl, td) - // } } ctx ++= infos + def go(stmts: Ls[Statement])(implicit ctx: Ctx): Opt[ST] = stmts match { case s :: stmts => val res_ty = s match { - // case NuFunDef(isLetRec, nme, targs, rhs) => - // case fd: NuFunDef => - // ??? - // case td: NuTypeDef => - // ??? case decl: NuDecl => val lti = named.getOrElse(decl.name, die) // completeTypeInfo() - // lti.complete() // ??? + lti.complete() // ??? // UnitType N // case ds: DesugaredStatement => @@ -402,8 +333,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case s: Statement => val (diags, dss) = s.desugared diags.foreach(raise) - // typeStatement(desug, allowPure) - // go(dss ::: stmts) S(typeTerms(dss, false, Nil)(ctx, raise, TypeProvenance(s.toLoc, s match { case trm: Term => trm.describe case s => "statement" @@ -419,11 +348,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => N } val res_ty = go(tu.entities) - // TypedTypingUnit(infos.unzip._2.map(_.complete()), S(res_ty)) - // TypedTypingUnit(infos.unzip._2.map(_.complete()), res_ty) + TypedTypingUnit(infos.unzip._2, res_ty) + }() - // }(raise, noProv/*TODO*/)}() + + trait LazyTypeInfoImpl { this: LazyTypeInfo => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 7c494216d6..c9c452af6d 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -391,7 +391,12 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => override def toString = showProvOver(false)(id.idStr+s"<${parents.map(_.name).mkString(",")}>") } - sealed trait TypeVarOrRigidVar extends SimpleType + sealed trait TypeVarOrRigidVar extends SimpleType { + def assertTV: TV = this match { + case tv: TV => tv + case _ => lastWords(s"$this was not a type variable") + } + } sealed trait ObjectTag extends TypeTag { val id: SimpleTerm diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 4aab3c52fc..5b3c56c210 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -95,8 +95,8 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c,) -> 'd} -//│ this: {eval: (List[out (string, 'e,)], 't,) -> 'd & ('b, 't0,) -> ('e & 'f) & (List[in 'a out 'a | 'a0 | (string, Var,)], 't1,) -> 'g} -//│ fun eval: (List['a1] & 'b, Abs['t1] | App['t0 & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) +//│ this: {eval: ('b, 's,) -> ('e & 'f) & (List[out (string, 'f,)], 't,) -> 'd & (List[in 'a out 'a | 'a0 | (string, Var,)], 't0,) -> 'g} +//│ fun eval: (List['a1] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) //│ } //│ where //│ 'a1 :> 'a | (string, Var,) From 8894bff577a2aa159daa615c76d21e0e3edaec03 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sun, 12 Mar 2023 03:18:08 +0800 Subject: [PATCH 177/498] WIP Very large cleanup, refactoring, and bug-fixing --- .../scala/mlscript/ConstraintSolver.scala | 4 +- .../src/main/scala/mlscript/JSBackend.scala | 1 + .../src/main/scala/mlscript/NuTypeDefs.scala | 378 +++++++----------- shared/src/main/scala/mlscript/Typer.scala | 89 ++--- .../main/scala/mlscript/TyperDatatypes.scala | 23 +- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/main/scala/mlscript/helpers.scala | 1 + shared/src/main/scala/mlscript/syntax.scala | 5 +- .../main/scala/mlscript/ucs/Desugarer.scala | 46 +-- shared/src/test/diff/codegen/Mixin.mls | 4 +- .../test/diff/ecoop23/ExpressionProblem.mls | 4 +- shared/src/test/diff/ecoop23/Intro.mls | 4 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 16 +- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 12 +- shared/src/test/diff/nu/Andong.mls | 4 +- shared/src/test/diff/nu/BadClasses.mls | 30 +- shared/src/test/diff/nu/BadMixins.mls | 23 ++ shared/src/test/diff/nu/BadScopes.mls | 39 ++ shared/src/test/diff/nu/BadUCS.mls | 117 ++++++ shared/src/test/diff/nu/BasicClasses.mls | 6 +- shared/src/test/diff/nu/BasicMixins.mls | 33 +- shared/src/test/diff/nu/ClassesInMixins.mls | 31 +- shared/src/test/diff/nu/CtorStatements.mls | 23 ++ shared/src/test/diff/nu/Eql.mls | 4 +- shared/src/test/diff/nu/EvalNegNeg.mls | 4 +- .../test/diff/nu/ExpressionProblem_repro.mls | 11 +- shared/src/test/diff/nu/FilterMap.mls | 2 +- shared/src/test/diff/nu/FunPoly.mls | 68 ++++ shared/src/test/diff/nu/GenericClasses.mls | 18 +- shared/src/test/diff/nu/GenericMethods.mls | 8 +- shared/src/test/diff/nu/GenericModules.mls | 2 +- shared/src/test/diff/nu/ListConsNil.mls | 6 +- shared/src/test/diff/nu/MetaWrap.mls | 4 +- shared/src/test/diff/nu/Misc.mls | 4 +- shared/src/test/diff/nu/MutualRec.mls | 18 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 14 +- .../src/test/diff/nu/ThisRefinedClasses.mls | 4 +- shared/src/test/diff/nu/TypeAliases.mls | 6 +- shared/src/test/diff/ucs/SplitBeforeOp.mls | 25 +- .../src/test/scala/mlscript/DiffTests.scala | 36 +- 40 files changed, 666 insertions(+), 467 deletions(-) create mode 100644 shared/src/test/diff/nu/BadMixins.mls create mode 100644 shared/src/test/diff/nu/BadScopes.mls create mode 100644 shared/src/test/diff/nu/BadUCS.mls create mode 100644 shared/src/test/diff/nu/CtorStatements.mls create mode 100644 shared/src/test/diff/nu/FunPoly.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 4ef48d89e0..cd9a9d5a6c 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -44,7 +44,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case cls: TypedNuCls => val raw = cls.members.get(fld.name) match { case S(d: TypedNuFun) => - d.ty.toUpper(provTODO) + d.typeSignature.toUpper(provTODO) case S(p: NuParam) => p.ty case S(_) => @@ -636,7 +636,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // println(s"Looking up $fld in ${cls.td.nme}") val res = cls.members.get(fld.name) match { case S(d: TypedNuFun) => - d.ty.toUpper(provTODO) + d.typeSignature.toUpper(provTODO) case S(p: NuParam) => p.ty case N => diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 6d94b865ec..97159cb620 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -300,6 +300,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case S(ModuleSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(runtimeName), JSIdent(JSLit.makeStringLiteral("class")))) case S(TraitSymbol(_, runtimeName, _, _, _)) => JSIdent(runtimeName)("is")(scrut) case S(_: TypeAliasSymbol) => throw new CodeGenError(s"cannot match type alias $name") + case S(_: MixinSymbol) => throw new CodeGenError(s"cannot match mixin $name") case N => throw new CodeGenError(s"unknown match case: $name") } case lit: Lit => diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 919d3f3520..117ceed0d3 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -12,6 +12,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => import TypeProvenance.{apply => tp} + type Params = Ls[Var -> FieldType] + type TyParams = Ls[(TN, TV, Opt[VarianceInfo])] + + sealed abstract class NuDeclInfo case class FunInfo() extends NuDeclInfo @@ -20,11 +24,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed trait NuMember { def name: Str + def kind: DeclKind + + /** Used in inheritance processing, for parent types. */ + def freshen(implicit ctx: Ctx): NuMember def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuMember + def map(f: ST => ST)(implicit ctx: Ctx): NuMember = + mapPol(N, false)((_, ty) => f(ty)) + // TODO rm – just use `mapPolMap` def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember @@ -36,6 +47,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class NuParam(nme: Var, ty: FieldType, isType: Bool) extends NuMember { def name: Str = nme.name + def kind: DeclKind = Val + def typeSignature: ST = ty.ub + + def freshen(implicit ctx: Ctx): NuMember = this def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) @@ -65,33 +80,32 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed trait TypedNuDecl extends NuMember { def name: Str def level: Level - def freshen(implicit ctx: Ctx): TypedNuDecl = { + + def freshen(implicit ctx: Ctx): NuMember = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty ctx.copy(lvl = level + 1) |> { implicit ctx => - freshenAbove(level, rigidify = false).asInstanceOf[TypedNuDecl] + freshenAbove(level, rigidify = false) } } - def map(f: ST => ST)(implicit ctx: Ctx): TypedNuDecl = - mapPol(N, false)((_, ty) => f(ty)) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl - def force()(implicit raise: Raise): Unit = this match { - case x: TypedNuMxn => x.ttu.force(); () - case x: TypedNuCls => x.ttu.force(); () - case _: TypedNuFun => - case _: TypedNuAls => - } } - sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef + /** Those declarations that introduce term names in scope. */ + sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { + def typeSignature: ST + } sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { def nme: TypeName + def decl: NuTypeDef + def tparams: TyParams + override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = this match { case m @ TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => @@ -107,8 +121,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - thisTy.freshenAbove(lim, rigidify))( - cls.instanceType.freshenAbove(lim, rigidify)) + thisTy.freshenAbove(lim, rigidify), + )(cls.instanceType.freshenAbove(lim, rigidify)) case cls @ TypedNuAls(level, td, tparams, body) => TypedNuAls(level, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), @@ -121,11 +135,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - case class TypedNuAls(level: Level, td: NuTypeDef, - tparams: Ls[(TN, TV, Opt[VarianceInfo])], - body: ST, - ) extends TypedNuTypeDef(Als) + case class TypedNuAls(level: Level, td: NuTypeDef, tparams: TyParams, body: ST) + extends TypedNuTypeDef(Als) { + def decl: NuTypeDef = td + def kind: DeclKind = td.kind def name: Str = nme.name def nme: mlscript.TypeName = td.nme @@ -148,15 +162,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuCls( level: Level, td: NuTypeDef, ttu: TypedTypingUnit, - tparams: Ls[(TN, TV, Opt[VarianceInfo])], params: Ls[Var -> FieldType], - members: Map[Str, NuMember], thisTy: ST + tparams: TyParams, params: Ls[Var -> FieldType], + members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, )(val instanceType: ST, // * only meant to be used in `force` and `variances` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { - + def decl: NuTypeDef = td + def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name + def typeSignature: ST = typeSignatureOf(td, level, tparams, params) + // TODO // def checkVariances @@ -169,7 +186,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def variances(implicit ctx: Ctx): VarianceStore = { _variances match { case S(res) => res - case N => + case N => trace(s"Computing variances of ${this.name}") { val store = VarianceStore.empty object Trav extends Traverser2.InvariantFields { override def apply(pol: PolMap)(ty: ST): Unit = @@ -193,7 +210,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO check consistency with explicitVariances store ++ tparams.iterator.collect { case (_, tv, S(vi)) => tv -> vi } - + }(r => s"= $r") } } @@ -206,7 +223,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, - f(pol.map(!_), thisTy) + f(pol.map(!_), thisTy), )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -214,28 +231,31 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, - f(pol.contravar, thisTy) + f(pol.contravar, thisTy), )(f(pol, instanceType)) } + case class TypedNuMxn( td: NuTypeDef, thisTV: ST, superTV: ST, - tparams: Ls[(TN, TV, Opt[VarianceInfo])], params: Ls[Var -> FieldType], + tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], ttu: TypedTypingUnit, - ) extends TypedNuTypeDef(Mxn) with TypedNuTermDef + ) extends TypedNuTypeDef(Mxn) { val level: Level = thisTV.level - 1 // TODO cleaner + def decl: NuTypeDef = td + def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef = + (implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, f(pol.map(!_), thisTV), f(pol.map(!_), superTV), tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef = + (implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(td, f(pol.contravar, thisTV), f(pol.contravar, superTV), tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), @@ -243,9 +263,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - /** Note: the type `ty` is stoed *without* its polymorphic wrapper! */ - case class TypedNuFun(level: Level, fd: NuFunDef, ty: ST) extends TypedNuDecl with TypedNuTermDef { + /** Note: the type `bodyType` is stored *without* its polymorphic wrapper! (unlike `typeSignature`) */ + case class TypedNuFun(level: Level, fd: NuFunDef, bodyType: ST) extends TypedNuDecl with TypedNuTermDef { + def kind: DeclKind = Val def name: Str = fd.nme.name + lazy val typeSignature: ST = PolymorphicType.mk(level, bodyType) + def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedNuFun = this match { @@ -255,37 +278,56 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuFun(level, fd, f(pol, ty)) + TypedNuFun(level, fd, f(pol, bodyType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuFun(level, fd, f(pol, ty)) + TypedNuFun(level, fd, f(pol, bodyType)) } - case class CompletedTypingUnit(entities: Ls[TypedNuDecl], result: Opt[ST]) extends OtherTypeLike { - def map(f: ST => ST)(implicit ctx: Ctx): CompletedTypingUnit = - CompletedTypingUnit(entities.map(_.map(f)), result.map(f)) + case class TypedTypingUnit(entities: Ls[NuMember], result: Opt[ST]) extends OtherTypeLike { + def map(f: ST => ST)(implicit ctx: Ctx): TypedTypingUnit = + TypedTypingUnit(entities.map(_.map(f)), result.map(f)) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): CompletedTypingUnit = - CompletedTypingUnit(entities.map(_.mapPol(pol, smart)(f)), result.map(f(pol, _))) + (implicit ctx: Ctx): TypedTypingUnit = + TypedTypingUnit(entities.map(_.mapPol(pol, smart)(f)), result.map(f(pol, _))) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): CompletedTypingUnit = - CompletedTypingUnit(entities.map(_.mapPolMap(pol)(f)), result.map(f(pol, _))) - } - - - case class TypedTypingUnit(entities: Ls[LazyTypeInfo], result: Opt[ST]) /* extends OtherTypeLike */ { + (implicit ctx: Ctx): TypedTypingUnit = + TypedTypingUnit(entities.map(_.mapPolMap(pol)(f)), result.map(f(pol, _))) def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = - TypedTypingUnit(entities.map(_.map(_.freshenAbove(lim, rigidify).asInstanceOf[TypedNuTermDef])) + TypedTypingUnit(entities.map(_.freshenAbove(lim, rigidify)//.asInstanceOf[TypedNuTermDef] + ) , result.map(_.freshenAbove(lim, rigidify))) - def force()(implicit raise: Raise): CompletedTypingUnit = { - CompletedTypingUnit(entities.map(_.force()), result) - } } + def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params): ST = td.kind match { + case Nms => + ClassTag(Var(td.nme.name), + // TODO base classes + Set.single(TN("Eql")) + )(provTODO) + case Cls => + PolymorphicType.mk(level, + FunctionType( + TupleType(params.mapKeys(some))(provTODO), + ClassTag(Var(td.nme.name), + // TODO base classes + Set.single(TypeName("Eql")) + )(provTODO) & RecordType.mk( + tparams.map { case (tn, tv, vi) => // TODO use vi + Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + )(provTODO) + )(provTODO) + ) + // case k => err + case k => errType // FIXME + } + + + /** Type checks a typing unit, which is a sequence of possibly-nutually-recursive type and function definitions * interleaved with plain statements. */ def typeTypingUnit(tu: TypingUnit, allowPure: Bool) @@ -296,7 +338,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val infos = tu.entities.collect { case decl: NuDecl => - val lti = new LazyTypeInfo(decl, implicitly) + val lti = new DelayedTypeInfo(decl, implicitly) decl match { case td: NuTypeDef => ctx.tyDefs2 += td.nme.name -> lti @@ -318,18 +360,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } ctx ++= infos + // * Complete typing of block definitions and add results to context + val completedInfos = infos.mapValues(_.complete() |> (res => CompletedTypeInfo(res))) + ctx ++= completedInfos + + // * Type the block statements def go(stmts: Ls[Statement])(implicit ctx: Ctx): Opt[ST] = stmts match { case s :: stmts => val res_ty = s match { - case decl: NuDecl => - val lti = named.getOrElse(decl.name, die) - // completeTypeInfo() - lti.complete() // ??? - // UnitType - N - // case ds: DesugaredStatement => - // val (poly_ty, bindings) = typeStatement(ds, allowPure) - // poly_ty.instantiate + case decl: NuDecl => N case s: Statement => val (diags, dss) = s.desugared diags.foreach(raise) @@ -344,31 +383,33 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO check discarded non-unit values go(stmts) } - // case Nil => UnitType case Nil => N } - val res_ty = go(tu.entities) + val res_ty = trace("Typing unit statements") { go(tu.entities) } (r => s": $r") - TypedTypingUnit(infos.unzip._2, res_ty) + TypedTypingUnit(completedInfos.map(_._2.member).toList, res_ty) }() - trait LazyTypeInfoImpl { this: LazyTypeInfo => - // class LazyTypeInfo[A](level: Int, decl: NuDecl) extends TypeInfo { + trait DelayedTypeInfoImpl { this: DelayedTypeInfo => private def outerCtx = ctx - // private def outerVars = vars + + var isComputing: Bool = false // Replace by a Ctx entry? + var result: Opt[TypedNuDecl] = N val level: Level = ctx.lvl + val kind: DeclKind = decl.kind + private implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) println(s"${ctx.lvl}. Created lazy type info $decl") - lazy val tparams: Ls[(TN, TV, Opt[VarianceInfo])] = ctx.nest.nextLevel { implicit ctx => + lazy val tparams: TyParams = ctx.nest.nextLevel { implicit ctx => decl match { case td: NuTypeDef => td.tparams.map(tp => @@ -388,10 +429,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO make use of inferred vce if result is completed explicitVariances.get(tv).getOrElse(VarianceInfo.in) - // println(s"Type params ${tparams.mkString(" ")}") - lazy private implicit val vars: Map[Str, SimpleType] = - // outerVars ++ tparams.iterator.mapKeys(_.name).toMap outerVars ++ tparams.iterator.map { case (tp, tv, vi) => (tp.name, SkolemTag(tv.level, tv)(tv.prov)) } @@ -415,40 +453,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) case _ => ??? } - case fd: NuFunDef => Nil // TODO + case fd: NuFunDef => Nil } } - - // val tparams: Ls[(TN, TV, VarianceInfo)] = Nil // TODO - var isComputing: Bool = false // TODO replace by a Ctx entry - var result: Opt[TypedNuDecl] = N - // var result: Opt[A] = N - val tv: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), N, S(decl.name))(level + 1) - def map(f: TypedNuDecl => TypedNuDecl): LazyTypeInfo = { - val res = new LazyTypeInfo(decl, implicitly) - // if (result.nonEmpty) res.result = res - res.result = result.map(f) - res - } - - // TODO does this also need freshening in freshenAbove? private lazy val thisTV: TV = - // freshVar(noProv/*FIXME*/, N, S("this_"+decl.name))(lvl + 1) - freshVar(noProv/*FIXME*/, N, S(decl.name.decapitalize))(lvl + 1) + freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) + def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { if (isComputing) { - // lastWords(s"TODO cyclic defition ${decl.name}") - err(msg"Unhandled cyclic definition", decl.toLoc) // TODO better loc/explanation + val ty = err(msg"Unhandled cyclic definition", decl.toLoc) + // * Hacky: return a dummy decl to avoid possible infinite completion recursions + TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top)), ty) } - // else // TODO avert infinite completion recursion here? - trace(s"Completing ${decl.showDbg}") { + else trace(s"Completing ${decl.showDbg}") { println(s"Type params ${tparams.mkString(" ")}") println(s"Params ${typedParams.mkString(" ")}") @@ -456,7 +480,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => isComputing = true decl match { case fd: NuFunDef => - // assert(fd.isLetRec.isEmpty, fd.isLetRec) def checkNoTyParams() = if (fd.tparams.nonEmpty) err(msg"Type parameters here are not yet supported in this position", @@ -464,22 +487,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val res_ty = fd.rhs match { case R(PolyType(tps, ty)) => checkNoTyParams() - // val body_ty = typeType(ty)(ctx.nextLevel, raise, - // vars = tps.map(tp => tp.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) - val body_ty = - // ctx.nextLevel { implicit ctx: Ctx => - // // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods - // // * in the current typing unit are quantified together. - ctx.poly { implicit ctx: Ctx => + val body_ty = ctx.poly { implicit ctx: Ctx => typeType(ty)(ctx, raise, - vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(noProv/*FIXME*/, N)(1)).toMap) + vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(provTODO, N)(1)).toMap) } - // TODO check against `tv` TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) + case R(_) => die case L(body) => - // println(fd.isLetRec) - // implicit val vars: Map[Str, SimpleType] = - // outerVars ++ Map.empty // TODO tparams fd.isLetRec match { case S(true) => // * Let rec bindings checkNoTyParams() @@ -492,14 +506,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => implicit val gl: GenLambdas = true TypedNuFun(ctx.lvl, fd, typeTerm(body)) case N => - /* - implicit val gl: GenLambdas = true - val body_ty = typeLetRhs2(isrec = true, fd.nme.name, body) - // implicit val prov: TP = noProv // TODO - // subsume(body_ty, PolymorphicType(level, tv)) // TODO - TypedNuFun(ctx.lvl, fd, body_ty) - */ - // * We don't type functions polymorphically from the point of view of a typing unit // * to avoid cyclic-looking constraints due to the polymorphic recursion limitation, // * as these functions are allowed to be mutually-recursive. @@ -520,9 +526,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuFun(ctx.lvl, fd, body_ty) } } - // // subsume(res_ty, tv) - // constrain(res_ty.ty, tv) - ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.ty, tv) } + ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.bodyType, tv) } res_ty @@ -552,7 +556,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Cls | Nms => - // implicit val prov: TP = noProv // TODO ctx.nest.nextLevel { implicit ctx => if ((td.kind is Nms) && typedParams.nonEmpty) @@ -574,14 +577,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) - // val finalType = freshVar(noProv/*TODO*/, N, S("this")) val finalType = thisTV val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi val fldNme = td.nme.name + "#" + tp.name NuParam(Var(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isType = true) } - // tparamMems.map(p => p.nme -> p.ty):Int val tparamFields = tparamMems.map(p => p.nme -> p.ty) assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) @@ -589,9 +590,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]) : (ST, Ls[NuMember]) = parents match { - // def inherit(parents: Ls[Term \/ TypedTypingUnit], superType: ST, members: Ls[TypedNuDecl]): Ls[TypedNuDecl] = parents match { - // case R(p) :: ps => ??? - // case L(p) :: ps => case p :: ps => val newMembs = trace(s"${lvl}. Inheriting from $p") { val (v @ Var(mxnNme), mxnArgs) = p match { @@ -630,12 +628,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } // TODO check overriding - val bodyMems = mxn.ttu.entities.map(_.complete()).map { - case fun @ TypedNuFun(_, fd, ty) => - fun - case m: NuMember => m - // case _ => ??? - } + val bodyMems = mxn.ttu.entities paramMems ++ bodyMems @@ -646,6 +639,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO dealias first? err(msg"Cannot inherit from a type alias", p.toLoc) Nil + case als: NuParam => + // TODO first-class mixins/classes... + err(msg"Cannot inherit from a parameter", p.toLoc) + Nil case cls: TypedNuFun => err(msg"Cannot inherit from this", p.toLoc) Nil @@ -658,19 +655,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => Nil } }() - val newSuperType = - // superType & - WithType( + val newSuperType = WithType( superType, RecordType( - // newMembs.foldLeft(TopType.toUpper(provTODO))(_ && _.ty.toUpper(provTODO)) - // newMembs.map(m => m.fd.nme -> m.ty.toUpper(provTODO)) newMembs.collect{ case m: NuParam => m.nme -> m.ty - case m: TypedNuFun => m.fd.nme -> m.ty.toUpper(provTODO) + case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) } )(provTODO) - )(provTODO) + )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & @@ -690,38 +683,17 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) - // val baseMems = inherit(td.parents, baseType, Nil) val (thisType, baseMems) = inherit(td.parents, baseType, tparamMems ++ paramMems) - // ctx += thisTV - - // TODO - // ctx += "super" -> VarSymbol(superTV, Var("super")) ctx += "super" -> VarSymbol(thisType, Var("super")) - val ttu = typeTypingUnit(td.body, allowPure = false) // TODO use + val ttu = typeTypingUnit(td.body, allowPure = false) // TODO check overriding - val clsMems = ttu.entities.map(_.complete()) - // .map { - // case fun @ TypedNuFun(_, fd, ty) => - // fun - // // case _ => ??? - // case m => m - // } - - // val thisTy = ClassTag(Var(td.name), - // Set.empty//TODO - // )(provTODO) - // constrain(thisTy, thisTV) - - // val thisType = superType & - // clsNameToNomTag(td)(provTODO, ctx) & - // RecordType(tparamFields)(ttp(td.params, isType = true)) + val clsMems = ttu.entities - // val mems = baseMems ++ paramMems ++ clsMems val mems = baseMems ++ clsMems TypedNuCls(outerCtx.lvl, td, ttu, @@ -733,28 +705,23 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Mxn => if (td.parents.nonEmpty) err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) - ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) - val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) ctx.nest.nextLevel { implicit ctx => + ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) implicit val vars: Map[Str, SimpleType] = outerVars ++ Map.empty // TODO type params - val thisTV = freshVar(noProv/*FIXME*/, N, S("this")) - val superTV = freshVar(noProv/*FIXME*/, N, S("super")) + val thisTV = freshVar(provTODO, N, S("this")) + val superTV = freshVar(provTODO, N, S("super")) ctx += "this" -> VarSymbol(thisTV, Var("this")) ctx += "super" -> VarSymbol(superTV, Var("super")) - // ctx |> { implicit ctx => val ttu = typeTypingUnit(td.body, allowPure = false) - val mems = paramMems ++ttu.entities.map(_.complete()) + val mems = paramMems ++ttu.entities TypedNuMxn(td, thisTV, superTV, tparams, typedParams, mems.map(m => m.name -> m).toMap, ttu) - // } } - // case Als => ??? - // case _ => ??? } } - // } finally { result = S(res); isComputing = false } - } finally { /* result = S(res); */ isComputing = false } + } finally { isComputing = false } result = S(res) res @@ -762,95 +729,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => }() } def typeSignature(implicit raise: Raise): ST = - /* - if (isComputing) - decl match { - case _: NuFunDef => - println(s"Already computing! Using TV: $tv") - tv // TODO FIXME wrong in general (when accessed from difft scope/level) - case _ => - err(msg"Cyclic definition", decl.toLoc) - } - else complete() match { - case cls: TypedNuCls if cls.td.kind is Nms => - ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) - case _cls: TypedNuCls => - val cls = _cls.freshen.asInstanceOf[TypedNuCls] - PolymorphicType.mk(cls.level, - FunctionType( - TupleType(cls.params.mapKeys(some))(provTODO), - // cls.tparams.foldLeft( - // ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) - // ) { case (acc, (tn, tv)) => acc & } - ClassTag(Var(cls.td.nme.name), Set.empty)(provTODO) & RecordType.mk( - cls.tparams.map { case (tn, tv, vi) => // TODO use vi - Var(cls.td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } - )(provTODO) - )(provTODO) - ) - case TypedNuFun(_, fd, ty) => - // println(fd, ty) - // ??? - ty - } - */ decl match { case _: NuFunDef => if (isComputing) { println(s"Already computing! Using TV: $tv") - tv // TODO FIXME wrong in general (when accessed from difft scope/level) + tv // TODO make sure this is never misused (ie not accessed from difft scope/level) } else complete() match { case TypedNuFun(_, fd, ty) => ty case _ => die } - case td: NuTypeDef if td.kind is Nms => - ClassTag(Var(td.nme.name), - // TODO base classes - // Set.empty - Set.single(TN("Eql")) - )(provTODO) - case td: NuTypeDef if td.kind is Cls => - PolymorphicType.mk(level, - FunctionType( - TupleType(typedParams.mapKeys(some))(provTODO), - ClassTag(Var(td.nme.name), - // TODO base classes - // Set.empty - Set.single(TypeName("Eql")) - )(provTODO) & RecordType.mk( - tparams.map { case (tn, tv, vi) => // TODO use vi - Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } - )(provTODO) - )(provTODO) - ) + case td: NuTypeDef => + typeSignatureOf(td, level, tparams, typedParams) } - def force()(implicit raise: Raise): TypedNuDecl = { - val res = complete() - res.force() - // decl match { - // case td: NuTypeDef => - // td.kind match { - // case Cls | Nms => - // // implicit val prov: TP = noProv // TODO - // // val thisTy = ClassTag(Var(td.name), - // // Set.empty//TODO - // // )(provTODO) - // // constrain(thisTy, thisTV) - // case _ => - // } - // case _ => - // } - res match { - case cls: TypedNuCls => - // implicit val prov: TP = noProv // TODO - // constrain(cls.instanceType, thisTV) - // println(cls.variances) - case _ => - } - res - } override def toString: String = s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 9b9d7afcdf..ba3244e34b 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -67,7 +67,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) inPattern: Bool, tyDefs: Map[Str, TypeDef], // tyDefs2: MutMap[Str, NuTypeDef], - tyDefs2: MutMap[Str, LazyTypeInfo], + tyDefs2: MutMap[Str, DelayedTypeInfo], inRecursiveDef: Opt[Var], // TODO rm extrCtx: ExtrCtx, ) { @@ -354,14 +354,17 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) newDefsInfo.get(name) .orElse(ctx.tyDefs.get(name).map(td => (td.kind, td.tparamsargs.size))) .orElse(ctx.get(name).flatMap { - case ti: LazyTypeInfo => - // ti.complete() + case CompletedTypeInfo(mem: TypedNuTypeDef) => S(mem.td.kind, mem.tparams.size) + case ti: DelayedTypeInfo => ti.decl match { case NuTypeDef(k @ (Cls | Nms | Als), _, tps, _, _, _, _, _, _) => S(k, tps.size) - case NuTypeDef(k @ Mxn, _, tps, _, _, _, _, _, _) => - err(msg"mixins cannot be used as types", loc) + case NuTypeDef(k @ (Mxn | Trt), nme, tps, _, _, _, _, _, _) => + err(msg"${k.str} ${nme.name} cannot be used as a type", loc) S(k, tps.size) + case fd: NuFunDef => + err(msg"function ${fd.nme.name} cannot be used as a type", loc) + N } case _ => N }) @@ -751,12 +754,16 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) ) ) case VarSymbol(ty, _) => ty - case ti: LazyTypeInfo => - // ti.complete() match { - // case cls: TypedNuCls => - // cls.ctorSignature - // case TypedNuFun(fd, ty) => ??? - // } + case ti: CompletedTypeInfo => + ti.member match { + case ti: TypedNuTermDef => + ti.typeSignature + case ti: TypedNuDecl => + err(msg"${ti.kind.str} ${ti.name} cannot be used in term position", prov.loco) + case p: NuParam => + p.typeSignature + } + case ti: DelayedTypeInfo => ti.typeSignature } mkProxy(ty, prov) @@ -1003,9 +1010,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case Blk(stmts) => if (newDefs) { val ttu = typeTypingUnit(TypingUnit(stmts), allowPure = false) - ttu.force() // TODO check unused defs - // ttu.res ttu.result.getOrElse(UnitType) } else typeTerms(stmts, false, Nil)(ctx.nest, raise, prov, vars, genLambdas) case Bind(l, r) => @@ -1110,63 +1115,44 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val tpr = tp(pat.toLoc, "type pattern") ctx.tyDefs.get(nme) match { case None => - ctx.tyDefs2.get(nme) match { - case N => - err("type identifier not found: " + nme, pat.toLoc)(raise) - val e = ClassTag(ErrTypeId, Set.empty)(tpr) - return ((e -> e) :: Nil) -> e - case S(td) => - // ClassTag(v, - // Set.empty//TODO - // )(provTODO) + val bail = () => { + val e = ClassTag(ErrTypeId, Set.empty)(tpr) + return ((e -> e) :: Nil) -> e + } + ctx.get(nme) match { + case S(td: LazyTypeInfo) => + if ((td.kind isnt Cls) && (td.kind isnt Nms) && (td.kind isnt Trt)) + err(msg"can only match on classes and traits", pat.toLoc)(raise) td.complete() match { case cls: TypedNuCls => - // lookupNuTypeDef(cls.td.nme.name, v => ???) val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) val fresh_cls = { implicit val freshened: MutMap[TV, ST] = MutMap.empty - // cls.tparams.foreach { case (tn, tv) => - // val fv = freshVar(provTODO, N, S(v.name.replaceAll("#", "_"))) - // freshened += tv -> fv - // } implicit val shadows: Shadows = Shadows.empty - cls.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] + cls.freshenAbove(cls.level, rigidify = false).asInstanceOf[TypedNuCls] } val ty = - // RecordType.mk(cls.params)(provTODO) // TODO?! + // RecordType.mk(fresh_cls.params)(provTODO) // TODO?! RecordType.mk(fresh_cls.tparams.map{ case (tn, tv, vi) => // TODO use variances - // println("VVV"+fresh_cls.variances.get(tv)) (Var(nme+"#"+tn.name).withLocOf(tn), FieldType.mk(fresh_cls.varianceOf(tv), tv, tv)(provTODO)) })(provTODO) println(s"Match arm $nme: $tag & $ty") tag -> ty + case _ => bail() } - // val cls = lookupNuTypeDef(nme, { v => - // val fv = freshVar(provTODO, N, S(v.name.replaceAll("#", "_"))) - // println(v, fv) - // S(FieldType(S(fv), fv)(provTODO)) - // }) - // val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) - // // val ty = tag & - // val ty = - // // RecordType.mk(cls.params)(provTODO) // TODO?! - // RecordType.mk(cls.tparams.map{ - // case (tn, tv) => - // (Var(nme+"#"+tn.name).withLocOf(tn), FieldType(S(tv), tv)(provTODO)) - // })(provTODO) - // println(s"Match arm $nme : $ty") - // tag -> ty + case _ => + err("type identifier not found: " + nme, pat.toLoc)(raise) + bail() } case Some(td) => td.kind match { - case Als => val t = err(msg"can only match on classes and traits", pat.toLoc)(raise); t -> t - case Nms => val t = err(msg"can only match on classes and traits", pat.toLoc)(raise); t -> t + case Als | Nms | Mxn => val t = err(msg"can only match on classes and traits", pat.toLoc)(raise); t -> t case Cls => val t = clsNameToNomTag(td)(tp(pat.toLoc, "class pattern"), ctx); t -> t case Trt => val t = trtNameToNomTag(td)(tp(pat.toLoc, "trait pattern"), ctx); t -> t } @@ -1298,12 +1284,13 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // NuFunDef(S(false), Var("this"), Nil, R(go(thisTy))) :: sorted.collect { case (_, td: TypedNuDecl) => goDecl(td) - case (_, td: TypedNuFun) => ??? + // case (_, td: TypedNuFun) => ??? // case (_, p: NuParam) => ??? // case _ => die }) } - def goDecl(d: TypedNuDecl)(implicit ectx: ExpCtx): NuDecl = d match { + // def goDecl(d: TypedNuDecl)(implicit ectx: ExpCtx): NuDecl = d match { + def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil)) @@ -1338,8 +1325,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) mkTypingUnit(thisTy, members)) // mkTypingUnit(() :: members.toList.sortBy(_._1))) } - case TypedNuFun(level, fd, ty) => - NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(ty))) + case tf @ TypedNuFun(level, fd, bodyTy) => + NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature))) } def goLike(ty: TypeLike)(implicit ectx: ExpCtx): mlscript.TypeLike = ty match { case ty: SimpleType => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index c9c452af6d..a7bd260a6d 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -36,8 +36,21 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => case class VarSymbol(ty: ST, definingVar: Var) extends TypeInfo - class LazyTypeInfo(val decl: NuDecl, val outerVars: Map[Str, SimpleType]) - (implicit val ctx: Ctx, val raise: Raise) extends TypeInfo with LazyTypeInfoImpl + /** Some type information which may not yet be available. */ + sealed abstract class LazyTypeInfo extends TypeInfo { + def complete()(implicit raise: Raise): NuMember + def kind: DeclKind + } + + /** A LazyTypeInfo whose typing has been completed. */ + case class CompletedTypeInfo(member: NuMember) extends LazyTypeInfo { + def complete()(implicit raise: Raise): NuMember = member + def kind: DeclKind = member.kind + } + + /** Initialized lazy type information, to be computed soon. */ + class DelayedTypeInfo(val decl: NuDecl, val outerVars: Map[Str, SimpleType]) + (implicit val ctx: Ctx, val raise: Raise) extends LazyTypeInfo with DelayedTypeInfoImpl /** A type with universally quantified type variables @@ -123,12 +136,12 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } type TL = TypeLike - abstract class OtherTypeLike extends TypeLike { this: CompletedTypingUnit => - def self: CompletedTypingUnit = this + abstract class OtherTypeLike extends TypeLike { this: TypedTypingUnit => + def self: TypedTypingUnit = this def unwrapProvs: TypeLike = this } object OtherTypeLike { - def unapply(ot: OtherTypeLike): S[CompletedTypingUnit] = S(ot.self) + def unapply(ot: OtherTypeLike): S[TypedTypingUnit] = S(ot.self) } /** A general type form (TODO: rename to AnyType). */ diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 5ff84e7cf2..036f1b6a09 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -744,7 +744,7 @@ abstract class TyperHelpers { Typer: Typer => def childrenPolMem(m: NuMember): List[PolMap -> SimpleType] = m match { case NuParam(nme, ty, isType) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable case TypedNuFun(level, fd, ty) => pol -> ty :: Nil - case td: TypedNuTermDef => CompletedTypingUnit(td :: Nil, N).childrenPol(pol: PolMap) // TODO refactor + case td: TypedNuDecl => TypedTypingUnit(td :: Nil, N).childrenPol(pol: PolMap) // TODO refactor } this match { case tv @ AssignedVariable(ty) => @@ -778,7 +778,7 @@ abstract class TyperHelpers { Typer: Typer => // Q: PolMap.neu or pol.invar?! ta.tparams.map(pol.invar -> _._2) ::: pol -> ta.body :: Nil case tf: TypedNuFun => - PolMap.pos -> tf.ty :: Nil + PolMap.pos -> tf.bodyType :: Nil case mxn: TypedNuMxn => mxn.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> mxn.superTV) ++ @@ -864,7 +864,7 @@ abstract class TyperHelpers { Typer: Typer => // tu.childrenPol(PolMap.neu).map(tp => tp._1) val ents = tu.entities.flatMap { case tf: TypedNuFun => - tf.ty :: Nil + tf.bodyType :: Nil case als: TypedNuAls => als.tparams.iterator.map(_._2) ++ S(als.body) case mxn: TypedNuMxn => diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 4fd8ea6131..f19182001e 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -461,6 +461,7 @@ trait DeclImpl extends Located { self: Decl => trait NuDeclImpl extends Located { self: NuDecl => val body: Located + def kind: DeclKind // val name: Str = self match { // case td: NuTypeDef => td.nme.name // case fd: NuFunDef => fd.nme.name diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 879b244a1c..fdcb0a73ab 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -45,7 +45,9 @@ final case class MethodDef[RHS <: Term \/ Type]( sealed trait NameRef extends Located { val name: Str } -sealed abstract class TypeDefKind(val str: Str) +sealed abstract class DeclKind(val str: Str) +case object Val extends DeclKind("value") +sealed abstract class TypeDefKind(str: Str) extends DeclKind(str) sealed trait ObjDefKind case object Cls extends TypeDefKind("class") with ObjDefKind case object Trt extends TypeDefKind("trait") with ObjDefKind @@ -192,6 +194,7 @@ final case class NuFunDef( rhs: Term \/ Type, ) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) + def kind: DeclKind = Val } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index ebbe5d2063..ae4a4c00ec 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -5,6 +5,7 @@ import scala.collection.mutable.Buffer import mlscript._, utils._, shorthands._ import helpers._ +import Message.MessageContext /** * This class contains main desugaring methods. @@ -160,32 +161,31 @@ class Desugarer extends TypeDefs { self: Typer => // This case handles simple class tests. // x is A case classNameVar @ Var(className) => - ctx.tyDefs.get(className).orElse(ctx.tyDefs2.get(className)) match { - case N => throw new DesugaringException({ - import Message.MessageContext + ctx.tyDefs.get(className).orElse(ctx.get(className)) match { + case S(ti: LazyTypeInfo) if (ti.kind is Cls) || (ti.kind is Nms) => + case S(_: TypeDef) => + case _ => throw new DesugaringException({ msg"Cannot find constructor `$className` in scope" }, classNameVar.toLoc) - case S(_) => - printlnUCS(s"Build a Clause.MatchClass from $scrutinee where pattern is $classNameVar") - Clause.MatchClass(scrutinee, classNameVar, Nil)(collectLocations(scrutinee.term)) :: Nil } + printlnUCS(s"Build a Clause.MatchClass from $scrutinee where pattern is $classNameVar") + Clause.MatchClass(scrutinee, classNameVar, Nil)(collectLocations(scrutinee.term)) :: Nil // This case handles classes with destruction. // x is A(r, s, t) case app @ App(classNameVar @ Var(className), Tup(args)) => ctx.tyDefs.get(className).map(td => (td.kind, td.positionals)) - .orElse(ctx.tyDefs2.get(className).map(td => - (td.decl.asInstanceOf[NuTypeDef].kind, - td.complete().asInstanceOf[TypedNuCls].params.map(_._1.name)))) - match { - // ctx2.tyDefs.get(className) match { - case N => - throw new DesugaringException({ - import Message.MessageContext - msg"Cannot find class `$className` in scope" - }, classNameVar.toLoc) - // case S(td) => - // } - // case S(td) => + .orElse(ctx.get(className) match { + case S(ti: LazyTypeInfo) => ti.complete() match { + case td: TypedNuCls => + S((td.decl.kind, td.params.map(_._1.name))) + case _ => throw new DesugaringException(msg"Illegal pattern `$className`", classNameVar.toLoc) + } + case _ => throw new DesugaringException(msg"Illegal pattern `$className`", classNameVar.toLoc) + }) match { + case N => + throw new DesugaringException({ + msg"Cannot find class `$className` in scope" + }, classNameVar.toLoc) case S((kind, positionals)) => if (args.length === positionals.length) { val (subPatterns, bindings) = desugarPositionals( @@ -200,7 +200,6 @@ class Desugarer extends TypeDefs { self: Typer => clause :: destructSubPatterns(scrutinee, subPatterns) } else { throw new DesugaringException({ - import Message.MessageContext val expected = positionals.length val actual = args.length msg"${kind.str} $className expects ${expected.toString} ${ @@ -223,7 +222,6 @@ class Desugarer extends TypeDefs { self: Typer => ctx.tyDefs.get(op) match { case N => throw new DesugaringException({ - import Message.MessageContext msg"Cannot find operator `$op` in the context" }, opVar.toLoc) case S(td) if td.positionals.length === 2 => @@ -238,7 +236,6 @@ class Desugarer extends TypeDefs { self: Typer => case S(td) => val num = td.positionals.length throw new DesugaringException({ - import Message.MessageContext val expected = td.positionals.length msg"${td.kind.str} `$op` expects ${expected.toString} ${ "parameter".pluralize(expected) @@ -252,7 +249,7 @@ class Desugarer extends TypeDefs { self: Typer => // x is Cons((x, y), Nil) case tuple: Tup => desugarTuplePattern(tuple) // What else? - case _ => throw new Exception(s"illegal pattern: ${mlscript.codegen.Helpers.inspect(pattern)}") + case _ => throw new DesugaringException(msg"illegal pattern", pattern.toLoc) } }("[Desugarer.destructPattern] result: " + Clause.showClauses(_)) @@ -418,7 +415,6 @@ class Desugarer extends TypeDefs { self: Typer => interleavedLets += ((isRec, nameVar, term)) // Other statements are considered to be ill-formed. case R(statement) => throw new DesugaringException({ - import Message.MessageContext msg"Illegal interleaved statement ${statement.toString}" }, statement.toLoc) } @@ -538,7 +534,6 @@ class Desugarer extends TypeDefs { self: Typer => try t match { case _: Consequent => () case MissingCase => - import Message.MessageContext parentOpt match { case S(IfThenElse(test, whenTrue, whenFalse)) => if (whenFalse === t) @@ -570,7 +565,6 @@ class Desugarer extends TypeDefs { self: Typer => printlnUCS(s"Number of missing cases: ${missingCases.size}") if (!missingCases.isEmpty) { throw new DesugaringException({ - import Message.MessageContext val numMissingCases = missingCases.size (msg"The match is not exhaustive." -> scrutinee.matchRootLoc) :: (msg"The scrutinee at this position misses ${numMissingCases.toString} ${ diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 987a4fc70a..16a0b6d2cd 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -373,10 +373,10 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) TestLang.eval(mk(0)) -//│ fun mk: number -> (Lit | 'a) +//│ fun mk: forall 'E. number -> 'E //│ int //│ where -//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] +//│ 'E :> Add['E] | Lit | Neg['E] //│ // Prelude //│ let typing_unit6 = { cache: {} }; //│ // Query 1 diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index a9c9d0bd6c..2584f30706 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -18,7 +18,7 @@ fun eval(e) = if e is Lit(n) then n Add(l, r) then eval(l) + eval(r) -//│ fun eval: 'a -> int +//│ fun eval: forall 'a. 'a -> int //│ where //│ 'a <: Add['a] | Lit @@ -201,7 +201,7 @@ fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ fun mk: number -> 'E +//│ fun mk: forall 'E. number -> 'E //│ where //│ 'E :> Add['E] | Lit | Neg['E] diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index 4fba0e2557..8e189b3514 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -15,7 +15,7 @@ mixin ComparePoint { (lhs.x === rhs.x) && (lhs.y === rhs.y) } //│ mixin ComparePoint() { -//│ fun compare: ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b},) -> bool +//│ fun compare: forall 'a 'b. ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b},) -> bool //│ } @@ -38,7 +38,7 @@ mixin CompareColored { } //│ mixin CompareColored() { //│ super: {compare: ('a, 'b,) -> bool} -//│ fun compare: ({color: {equals: 'color -> bool}} & 'a, {color: 'color} & 'b,) -> bool +//│ fun compare: forall 'color. ({color: {equals: 'color -> bool}} & 'a, {color: 'color} & 'b,) -> bool //│ } diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index f20449ec1f..b3f2fc51e8 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -26,7 +26,7 @@ fun list_assoc(s, l) = if s === h._1 then Success(h._2) else list_assoc(s, t) Nil then NotFound() -//│ fun list_assoc: (Eql['a], Cons[{_1: 'a, _2: 'A}] | Nil,) -> (NotFound | Success['A]) +//│ fun list_assoc: forall 'a 'A. (Eql['a], Cons[{_1: 'a, _2: 'A}] | Nil,) -> (NotFound | Success['A]) // fun list_assoc(s: string, l: Cons[{ _1: string, _2: 'b }] | Nil): NotFound | Success['b] @@ -41,7 +41,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, Var,) -> (Var | 'result) +//│ fun eval: forall 'result. (Cons[{_1: string, _2: 'result}] | Nil, Var,) -> (Var | 'result) //│ } class Abs[A](x: string, t: A) @@ -73,8 +73,8 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b,) -> 'c} -//│ this: {eval: (Cons[(string, 'd,)], 't,) -> 'c & ('a, 't0,) -> ('d & 'e) & (Cons[(string, Var,) | 'A], 't1,) -> 'f} -//│ fun eval: ('a & (Cons['A] | Nil), Abs['t1] | App['t0 & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['f] | App['d | 'e] | 'c) +//│ this: {eval: ('a, 's,) -> ('d & 'e) & (Cons[(string, 'e,)], 't,) -> 'c & (Cons[(string, Var,) | 'A], 't0,) -> 'f} +//│ fun eval: ('a & (Cons['A] | Nil), Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['f] | App['d | 'e] | 'c) //│ } module Test1 extends EvalVar, EvalLambda @@ -95,7 +95,7 @@ Test1.eval(Nil, Var("a")) Test1.eval(Nil, Abs("b", Var("a"))) //│ 'a //│ where -//│ 'a :> Abs['a] | Var | App['a] +//│ 'a :> Var | App['a] | Abs['a] //│ res //│ = Abs {} @@ -126,7 +126,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) +//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) mixin EvalExpr { fun eval(sub, v) = @@ -141,7 +141,7 @@ mixin EvalExpr { //│ mixin EvalExpr() { //│ super: {eval: ('a, Var,) -> 'b} //│ this: {eval: ('a, 'c,) -> anything} -//│ fun eval: ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) +//│ fun eval: forall 'd. ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) //│ } module Test2 extends EvalVar, EvalExpr @@ -197,7 +197,7 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> 'result //│ } //│ where -//│ 'result :> App['result] | Abs['result] | Num | Var | 'b +//│ 'result :> Num | Var | 'b | App['result] | Abs['result] //│ 'b <: Add['c] | Mul['c] | Num | Var //│ 'c <: 'a //│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | 'b & ~#Abs & ~#App diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index a5ca500582..9ecc10b94d 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -45,7 +45,7 @@ fun go(x, offset) = else let shared = go(x - 1, round(offset / 2)) Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) -//│ fun go: (int, int,) -> 'Region +//│ fun go: forall 'Region. (int, int,) -> 'Region //│ where //│ 'Region :> Circle | Union[Translate['Region]] @@ -313,7 +313,7 @@ mixin Eliminate { } //│ mixin Eliminate() { //│ this: {eliminate: 'a -> 'b & 'a0 -> 'c & 'a1 -> 'd & 'a2 -> 'e & 'a3 -> 'f & 'a4 -> 'g} -//│ fun eliminate: (Intersect['a2] | Outside['a0 & (Outside['a] | ~#Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> (Intersect['e] | Outside['c] | Scale['g] | Translate['f] | Union['d] | 'b | 'h) +//│ fun eliminate: forall 'h. (Intersect['a2] | Outside['a0 & (Outside['a] | ~#Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> (Intersect['e] | Outside['c] | Scale['g] | Translate['f] | Union['d] | 'b | 'h) //│ } module TestElim extends Eliminate @@ -322,19 +322,19 @@ module TestElim extends Eliminate //│ } //│ where //│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~#Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'b :> Outside['b] | Union['b] | Intersect['b] | Translate['b] | Scale['b] +//│ 'b :> Intersect['b] | Translate['b] | Scale['b] | Outside['b] | Union['b] TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where -//│ 'a :> Scale['a] | Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] +//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Univ //│ res //│ = Univ {} TestElim.eliminate(circles) //│ 'a //│ where -//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Circle +//│ 'a :> Translate['a] | Scale['a] | Circle | Outside['a] | Union['a] | Intersect['a] //│ res //│ = Union {} @@ -344,7 +344,7 @@ fun mk(n) = if n is 3 then Intersect(mk(n), mk(n)) 4 then Translate(Vector(0, 0), mk(n)) _ then Scale(Vector(0, 0), mk(n)) -//│ fun mk: number -> 'Region +//│ fun mk: forall 'Region. number -> 'Region //│ where //│ 'Region :> Intersect['Region] | Outside['Region] | Scale['Region] | Translate['Region] | Union['Region] diff --git a/shared/src/test/diff/nu/Andong.mls b/shared/src/test/diff/nu/Andong.mls index e75a3ab5f6..ed6471fc81 100644 --- a/shared/src/test/diff/nu/Andong.mls +++ b/shared/src/test/diff/nu/Andong.mls @@ -9,9 +9,9 @@ class Union(a: Region, b: Region) // | | | | Desugared term: case x of { Union => let x = (x).a in let y = (x).b in x } fun hmm(x) = if x is Union(x, y) then x -//│ fun hmm: Union[{b: anything} & 'a] -> 'a +//│ fun hmm: forall 'a. Union[{b: anything} & 'a] -> 'a fun hmm(x) = if x is Union(z, y) then x -//│ fun hmm: Union['Region] -> Union['Region] +//│ fun hmm: forall 'Region. Union['Region] -> Union['Region] diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index fa2265bed4..043eb50c83 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -33,7 +33,7 @@ class C0 extends M0(true) //│ class C0() -// TODO catch this at typing +// TODO catch this at typing (lack of `this`) class Foo { fun foo = 0 fun bar = foo @@ -58,4 +58,32 @@ class Foo { //│ unresolved symbol foo +module Bar { + fun hello = 0 + type I = int +} +//│ module Bar() { +//│ type I = int +//│ fun hello: 0 +//│ } + +:e +:ge +hello +//│ ╔══[ERROR] identifier not found: hello +//│ ║ l.72: hello +//│ ╙── ^^^^^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol hello + +:e +1 : I +//│ ╔══[ERROR] type identifier not found: I +//│ ║ l.81: 1 : I +//│ ╙── ^ +//│ error +//│ res +//│ = 1 + diff --git a/shared/src/test/diff/nu/BadMixins.mls b/shared/src/test/diff/nu/BadMixins.mls new file mode 100644 index 0000000000..ec475ed01d --- /dev/null +++ b/shared/src/test/diff/nu/BadMixins.mls @@ -0,0 +1,23 @@ +:NewDefs + + +:e +mixin M0 +M0 +//│ ╔══[ERROR] mixin M0 cannot be used in term position +//│ ║ l.6: M0 +//│ ╙── ^^ +//│ mixin M0() +//│ error +//│ res +//│ = [Function: M0] + +:e +M0 +//│ ╔══[ERROR] mixin M0 cannot be used in term position +//│ ║ l.16: M0 +//│ ╙── ^^ +//│ error +//│ res +//│ = [Function: M0] + diff --git a/shared/src/test/diff/nu/BadScopes.mls b/shared/src/test/diff/nu/BadScopes.mls new file mode 100644 index 0000000000..c6827eb578 --- /dev/null +++ b/shared/src/test/diff/nu/BadScopes.mls @@ -0,0 +1,39 @@ +:NewDefs + + +:e +:ge +mixin Foo(x: int) +x +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.7: x +//│ ╙── ^ +//│ mixin Foo(x: int) +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol x + + +:e +:ge +class Foo(x: int) +x +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.20: x +//│ ╙── ^ +//│ class Foo(x: int) +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol x + + +:e +class Foo(x: int) +class Bar { x } +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.32: class Bar { x } +//│ ╙── ^ +//│ class Foo(x: int) +//│ class Bar() + + diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls new file mode 100644 index 0000000000..7570b54bba --- /dev/null +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -0,0 +1,117 @@ +:NewDefs + + +class Foo +//│ class Foo() + +fun foo(x) = if x is Foo then 0 +//│ fun foo: Foo -> 0 + + +module Bar { + class Foo0 +} +//│ module Bar() { +//│ class Foo0() +//│ } + +fun foo(x) = if x is Bar then 0 +//│ fun foo: Bar -> 0 + +:e +:ge +fun foo(x) = if x is Foo0 then 0 +//│ ╔══[ERROR] Cannot find constructor `Foo0` in scope +//│ ║ l.23: fun foo(x) = if x is Foo0 then 0 +//│ ╙── ^^^^ +//│ fun foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + +type F = Foo +//│ type F = Foo + +:e +:ge +fun foo(x) = if x is F then 0 +//│ ╔══[ERROR] Cannot find constructor `F` in scope +//│ ║ l.37: fun foo(x) = if x is F then 0 +//│ ╙── ^ +//│ fun foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:e +:ge +fun foo(x) = if x is F() then 0 +//│ ╔══[ERROR] Illegal pattern `F` +//│ ║ l.47: fun foo(x) = if x is F() then 0 +//│ ╙── ^ +//│ fun foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + +mixin M +//│ mixin M() + +:e +:ge +fun foo(x) = if x is M then 0 +//│ ╔══[ERROR] Cannot find constructor `M` in scope +//│ ║ l.61: fun foo(x) = if x is M then 0 +//│ ╙── ^ +//│ fun foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:e +:ge +fun foo(x) = if x is M() then 0 +//│ ╔══[ERROR] Illegal pattern `M` +//│ ║ l.71: fun foo(x) = if x is M() then 0 +//│ ╙── ^ +//│ fun foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + +:e +:ge +fun foo0(x, y) = if x is y then 0 +//│ ╔══[ERROR] Cannot find constructor `y` in scope +//│ ║ l.82: fun foo0(x, y) = if x is y then 0 +//│ ╙── ^ +//│ fun foo0: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + +fun foo = 0 +//│ fun foo: 0 + +:e +:ge +fun foo0(x) = if x is foo() then 0 +//│ ╔══[ERROR] Illegal pattern `foo` +//│ ║ l.96: fun foo0(x) = if x is foo() then 0 +//│ ╙── ^^^ +//│ fun foo0: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:e +:ge +fun foo(x) = if x is foo() then 0 +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.106: fun foo(x) = if x is foo() then 0 +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Illegal pattern `foo` +//│ ║ l.106: fun foo(x) = if x is foo() then 0 +//│ ╙── ^^^ +//│ fun foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 64e2ab454d..f898e056fe 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -26,7 +26,7 @@ fun f(x: A | 'b) = if x is A then x.n else 0 fun f(x) = x.n -//│ fun f: {n: 'n} -> 'n +//│ fun f: forall 'n. {n: 'n} -> 'n f(a) //│ int @@ -56,8 +56,8 @@ class C { fun const(x) = id } //│ class C() { -//│ fun const: anything -> 'a -> 'a -//│ fun id: 'a -> 'a +//│ fun const: forall 'a. anything -> 'a -> 'a +//│ fun id: forall 'a. 'a -> 'a //│ } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 82666f1821..5f3e171b1a 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -127,9 +127,6 @@ class Base1(x): BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations //│ ║ l.126: class Base1(x): BaseTest //│ ╙── ^ -//│ ╔══[ERROR] mixins cannot be used as types -//│ ║ l.126: class Base1(x): BaseTest -//│ ╙── ^^^^^^^^ //│ ╔══[ERROR] type signatures not yet supported for classes //│ ║ l.126: class Base1(x): BaseTest //│ ╙── ^^^^^^^^ @@ -147,37 +144,37 @@ mixin Foo { } //│ mixin Foo() { //│ super: {base: int, misc: 'misc} -//│ fun test: (int & 'a) -> (int, 'a, 'misc,) +//│ fun test: forall 'a. (int & 'a) -> (int, 'a, 'misc,) //│ } :e module Base1(base: int, misc: string) extends Foo //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.154: module Base1(base: int, misc: string) extends Foo +//│ ║ l.151: module Base1(base: int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.154: module Base1(base: int, misc: string) extends Foo +//│ ║ l.151: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'misc' -//│ ║ l.154: module Base1(base: int, misc: string) extends Foo +//│ ║ l.151: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.154: module Base1(base: int, misc: string) extends Foo +//│ ║ l.151: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.154: module Base1(base: int, misc: string) extends Foo +//│ ║ l.151: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.146: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ module Base1(base: int, misc: string) { //│ fun test: (int & 'a) -> (int, 'a, nothing,) @@ -196,7 +193,7 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase() { -//│ fun wrap: 'a -> 'a +//│ fun wrap: forall 'a. 'a -> 'a //│ fun wrapA: (x: int,) -> int //│ } @@ -260,16 +257,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.261: WrapBase1.wrapA("ok") +//│ ║ l.258: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.261: WrapBase1.wrapA("ok") +//│ ║ l.258: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.195: fun wrapA(x: int) = x : int +//│ ║ l.192: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.205: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.202: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error //│ res diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 57667bf396..1c6e5a3377 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -31,19 +31,29 @@ M.Foo //│ ╙── ^^^^ //│ error +:e // TODO +fun foo(x) = if x is M.Foo then 1 +//│ ╔══[ERROR] illegal pattern +//│ ║ l.35: fun foo(x) = if x is M.Foo then 1 +//│ ╙── ^^^^^ +//│ fun foo: anything -> error + :e mixin Test2 { let f = Foo(1) } //│ ╔══[ERROR] identifier not found: Foo -//│ ║ l.35: mixin Test2 { let f = Foo(1) } +//│ ║ l.42: mixin Test2 { let f = Foo(1) } //│ ╙── ^^^ //│ mixin Test2() { //│ let f: error //│ } -// FIXME the `Foo` class is not in scope here +:e mixin Test3 { fun f(x) = if x is Foo then 1 } +//│ ╔══[ERROR] Cannot find constructor `Foo` in scope +//│ ║ l.51: mixin Test3 { fun f(x) = if x is Foo then 1 } +//│ ╙── ^^^ //│ mixin Test3() { -//│ fun f: Foo -> 1 +//│ fun f: anything -> error //│ } @@ -55,23 +65,24 @@ mixin Test { let cached = size(this) } fun size(x) = if x is - Foo then 1 Add(l, r) then this.size(l) + this.size(r) } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.54: class Add(lhs: A, rhs: A) { +//│ ║ l.64: class Add(lhs: A, rhs: A) { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.55: let cached = size(this) +//│ ║ l.65: let cached = size(this) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.56: } +//│ ║ l.66: } //│ ╙── ^^^ +//│ ╔══[ERROR] Illegal pattern `Add` +//│ ║ l.68: Add(l, r) then this.size(l) + this.size(r) +//│ ╙── ^^^ //│ mixin Test() { -//│ this: {size: 'lhs -> int} //│ class Add[A](lhs: A, rhs: A) { -//│ let cached: int +//│ let cached: error //│ } //│ class Lit(n: int) -//│ fun size: (Add['lhs] | Foo) -> int +//│ fun size: anything -> error //│ } diff --git a/shared/src/test/diff/nu/CtorStatements.mls b/shared/src/test/diff/nu/CtorStatements.mls new file mode 100644 index 0000000000..05abdedb3d --- /dev/null +++ b/shared/src/test/diff/nu/CtorStatements.mls @@ -0,0 +1,23 @@ +:NewDefs + + +log("Hello!") +//│ unit +//│ res +//│ = undefined +//│ // Output +//│ Hello! + + +module Test0 { + log("Hello!") +} +//│ module Test0() + +// TODO should print +Test0 +//│ Test0 +//│ res +//│ = Test0 { class: [class Test0] } + + diff --git a/shared/src/test/diff/nu/Eql.mls b/shared/src/test/diff/nu/Eql.mls index 101cdff4d7..911d30a66d 100644 --- a/shared/src/test/diff/nu/Eql.mls +++ b/shared/src/test/diff/nu/Eql.mls @@ -50,11 +50,11 @@ x === x fun test1(x) = x === x -//│ fun test1: (Eql['a] & 'a) -> bool +//│ fun test1: forall 'a. (Eql['a] & 'a) -> bool fun test2(x, y) = x === y -//│ fun test2: (Eql['a], 'a,) -> bool +//│ fun test2: forall 'a. (Eql['a], 'a,) -> bool 1 : Eql['a] diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index 21e66d3733..b1aef73e5a 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -61,9 +61,9 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) TestLang.eval(mk(0)) -//│ fun mk: number -> (Lit | 'a) +//│ fun mk: forall 'E. number -> 'E //│ int //│ where -//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] +//│ 'E :> Add['E] | Lit | Neg['E] //│ res //│ = [Function: mk] diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index 2c8e947d12..b2725b3bf9 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -2,6 +2,15 @@ :NoJS +class Add0(lhs: E) +//│ class Add0[E](lhs: E) + +fun eval(e) = if e is Add0(l) then eval(l) +//│ fun eval: forall 'a. 'a -> nothing +//│ where +//│ 'a <: Add0['a] + + class Add(lhs: E, rhs: E) class Lit(value: int) //│ class Add[E](lhs: E, rhs: E) @@ -14,7 +23,7 @@ fun eval(e) = if e is Lit(n) then n: int Add(l, r) then eval(l) + eval(r) -//│ fun eval: 'a -> int +//│ fun eval: forall 'a. 'a -> int //│ where //│ 'a <: Add['a] | Lit diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 7bf201140c..29fd53758e 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -70,6 +70,6 @@ fun filtermap(f, xs) = if xs is True then filtermap(f, ys) False then Cons(y, filtermap(f, ys)) Pair(True, z) then Cons(z, filtermap(f, ys)) -//│ fun filtermap: ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) +//│ fun filtermap: forall 'head 'A. ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) diff --git a/shared/src/test/diff/nu/FunPoly.mls b/shared/src/test/diff/nu/FunPoly.mls new file mode 100644 index 0000000000..76eada40c3 --- /dev/null +++ b/shared/src/test/diff/nu/FunPoly.mls @@ -0,0 +1,68 @@ +:NewDefs + + + +fun id(x) = x +//│ fun id: forall 'a. 'a -> 'a + +[id(1), id(true)] +//│ (1, true,) +//│ res +//│ = [ 1, true ] + +not(id(true)) +//│ bool +//│ res +//│ = false + + + +fun id(x) = x +[id(1), id(true)] +//│ fun id: forall 'a. 'a -> 'a +//│ (1, true,) +//│ res +//│ = [Function: id1] + + + +// * Currently, we type entire typing units monomorphically; +// * later we should try to separate mutually-recursive components and generalize them independently. +fun test = [id(1), id(true)] +fun id(x) = x +//│ fun test: forall 'a 'b. (1 | true | 'a, 1 | true | 'b,) +//│ fun id: forall 'a 'b. ('b & 'a) -> (1 | true | 'a) + +[id(1), id(true)] +//│ (1 | true, 1 | true,) +//│ res +//│ = [ 1, true ] + +:e +not(id(true)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.42: not(id(true)) +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── integer literal of type `1` is not an instance of type `bool` +//│ ║ l.31: fun test = [id(1), id(true)] +//│ ║ ^ +//│ ╟── but it flows into application with expected type `bool` +//│ ║ l.42: not(id(true)) +//│ ╙── ^^^^^^^^ +//│ bool | error +//│ res +//│ = false + + + +fun test = [Helper.id(1), Helper.id(true)] +module Helper { + fun id(x) = x +} +//│ fun test: (1, true,) +//│ module Helper() { +//│ fun id: forall 'a. 'a -> 'a +//│ } + + + diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index ae3ec9c36d..db8e40649e 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -5,7 +5,7 @@ class C //│ class C[A]() fun f(x) = if x is C then x -//│ fun f: C['A] -> C['A] +//│ fun f: forall 'A. C['A] -> C['A] // * TODO parse class tags? // f(C : #C) @@ -16,7 +16,7 @@ class C(a: A) //│ class C[A](a: A) fun f(x) = if x is C(a) then a -//│ fun f: C['a] -> 'a +//│ fun f: forall 'a. C['a] -> 'a let c = C(1) //│ let c: C[1] @@ -37,8 +37,8 @@ class Some(value: A) { } //│ class Some[A](value: A) { //│ fun get: A -//│ fun map: (A -> 'A) -> Some['A] -//│ fun map_A: (A -> 'A0) -> Some['A0] +//│ fun map: forall 'A. (A -> 'A) -> Some['A] +//│ fun map_A: forall 'A0. (A -> 'A0) -> Some['A0] //│ fun toArray: (A,) //│ } @@ -66,7 +66,7 @@ s.toArray s.map -//│ (1 -> 'A) -> Some['A] +//│ forall 'A. (1 -> 'A) -> Some['A] //│ res //│ = [Function: map] @@ -77,7 +77,7 @@ s.map(succ) s.map_A -//│ (1 -> 'A) -> Some['A] +//│ forall 'A. (1 -> 'A) -> Some['A] //│ res //│ = [Function: map_A] @@ -155,7 +155,7 @@ if opt is Some(v) then v else 0 fun map(x, f) = if x is None then None Some(v) then Some(f(v)) -//│ fun map: (None | Some['value], 'value -> 'A,) -> (None | Some['A]) +//│ fun map: forall 'value 'A. (None | Some['value], 'value -> 'A,) -> (None | Some['A]) let mo = map(opt, succ) //│ let mo: None | Some[int] @@ -230,7 +230,7 @@ class Test(n: A) { //│ class Test[A](n: A) { //│ fun foo: A //│ fun foo1: (x: A,) -> A -//│ fun id: 'a -> 'a +//│ fun id: forall 'a. 'a -> 'a //│ } Test(1) @@ -266,7 +266,7 @@ t : Test<'a> //│ = Test2 {} t.id -//│ 'a -> 'a +//│ forall 'a. 'a -> 'a //│ res //│ = [Function: id] diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 5d6d84168a..8c129fce8b 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -20,7 +20,7 @@ foo1[int](42) fun foo2(x: A) = x -//│ fun foo2: (x: 'a,) -> 'a +//│ fun foo2: forall 'a. (x: 'a,) -> 'a foo2(42) //│ 42 @@ -38,7 +38,7 @@ foo2(42) fun foo3[A](x: A) = x -//│ fun foo3: (x: 'a,) -> 'a +//│ fun foo3: forall 'a. (x: 'a,) -> 'a foo3(42) //│ 42 @@ -105,14 +105,14 @@ module Test { //│ module Test() { //│ fun bar: nothing //│ fun foo: forall 'A. 'A -> 'A -//│ fun test: (x: 'a,) -> 'a +//│ fun test: forall 'a. (x: 'a,) -> 'a //│ } class Test(n: A) { fun test(x: A) = [x, n] } //│ class Test[A](n: A) { -//│ fun test: (x: 'a,) -> ('a, A,) +//│ fun test: forall 'a. (x: 'a,) -> ('a, A,) //│ } diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index f13dcb88a4..ae1c3c42b6 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -85,7 +85,7 @@ Test: Test<'a> fun test(x) = if x is Test then x.foo -//│ fun test: Test['A] -> 'A -> 'A +//│ fun test: forall 'A. Test['A] -> 'A -> 'A :e test(Test) diff --git a/shared/src/test/diff/nu/ListConsNil.mls b/shared/src/test/diff/nu/ListConsNil.mls index d6fdd6d715..d079e5588c 100644 --- a/shared/src/test/diff/nu/ListConsNil.mls +++ b/shared/src/test/diff/nu/ListConsNil.mls @@ -27,15 +27,15 @@ fun list_assoc(s, l) = if eq(s)(h._1) then Cons(h._2, Nil) else list_assoc(s, t) Nil then Nil -//│ fun list_assoc: (anything, Cons[{_1: anything, _2: 'A}] | Nil,) -> (Cons['A] | Nil) +//│ fun list_assoc: forall 'A. (anything, Cons[{_1: anything, _2: 'A}] | Nil,) -> (Cons['A] | Nil) fun test(x, l) = list_assoc(42, Cons(x, l)) -//│ fun test: ({_1: anything, _2: 'A}, List[{_1: anything, _2: 'A}],) -> (Cons['A] | Nil) +//│ fun test: forall 'A. ({_1: anything, _2: 'A}, List[{_1: anything, _2: 'A}],) -> (Cons['A] | Nil) fun test(x, l) = if l is Nil then list_assoc(42, Cons(x, l)) Cons(h, t) then list_assoc(42, Cons(h, t)) -//│ fun test: ({_1: anything, _2: 'A}, Cons[{_1: anything, _2: 'A}] | Nil,) -> (Cons['A] | Nil) +//│ fun test: forall 'A. ({_1: anything, _2: 'A}, Cons[{_1: anything, _2: 'A}] | Nil,) -> (Cons['A] | Nil) diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index 9890d57e01..5fadcacd0b 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -9,8 +9,8 @@ mixin Base { fun rewrap(x, f) = f(x) } //│ mixin Base() { -//│ fun rewrap: ('a, 'a -> 'b,) -> 'b -//│ fun unwrap: 'c -> 'c +//│ fun rewrap: forall 'a 'b. ('a, 'a -> 'b,) -> 'b +//│ fun unwrap: forall 'c. 'c -> 'c //│ } diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index a1732a5d63..dc97625632 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -33,10 +33,10 @@ x => x + 1 //│ = [Function: res] fun f({ y }) = y -//│ fun f: {y: 'a} -> 'a +//│ fun f: forall 'a. {y: 'a} -> 'a fun f of { y } = y -//│ fun f: {y: 'a} -> 'a +//│ fun f: forall 'a. {y: 'a} -> 'a f({y: 1}) //│ 1 diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 11dab73fdc..96026522c7 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -35,15 +35,15 @@ foo(bar) fun foo = {x: foo} -//│ fun foo: 'foo +//│ fun foo: forall 'foo. 'foo //│ where //│ 'foo :> {x: 'foo} fun foo = {x: bar} fun bar = {y: foo} -//│ fun foo: 'foo -//│ fun bar: {y: 'foo} +//│ fun foo: forall 'foo. 'foo +//│ fun bar: forall 'foo. {y: 'foo} //│ where //│ 'foo :> {x: {y: 'foo}} @@ -72,8 +72,8 @@ foo.x.y fun foo(a) = {h: a, t: bar(a)} fun bar(b) = foo(b) -//│ fun foo: 'a -> 'b -//│ fun bar: 'a -> 'b +//│ fun foo: forall 'a 'b. 'a -> 'b +//│ fun bar: forall 'a 'b. 'a -> 'b //│ where //│ 'b :> {h: 'a, t: 'b} @@ -88,8 +88,8 @@ foo fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} -//│ fun foo: 'a -> 'b -//│ fun bar: 'a -> 'c +//│ fun foo: forall 'a 'b 'c. 'a -> 'b +//│ fun bar: forall 'a 'b 'c. 'a -> 'c //│ where //│ 'b :> {h1: 'a, t1: 'c} //│ 'c :> {h2: 'a, t2: 'b} @@ -126,7 +126,7 @@ class Test0_2() { //│ } -:e // TODO +:e module Test1_1 { fun a = Test1_2.b } @@ -147,7 +147,7 @@ Test1_1.a //│ error -:e // TODO +:e class Test1_1 { fun a = Test1_2().b } diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 5b3c56c210..7d3923e1e0 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -39,7 +39,7 @@ fun list_assoc(s, l: List<'a>) = if eq(s, h._1) then Success(h._2) else list_assoc(s, t) ) -//│ fun list_assoc: (string, l: List['a],) -> (NotFound | Success['A]) +//│ fun list_assoc: forall 'a 'A. (string, l: List['a],) -> (NotFound | Success['A]) //│ where //│ 'a <: {_1: string, _2: 'A} @@ -60,7 +60,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (List[{_1: string, _2: 'b}], Var,) -> ('b | Var) +//│ fun eval: forall 'b. (List[{_1: string, _2: 'b}], Var,) -> ('b | Var) //│ } class Abs(x: string, t: A) @@ -96,7 +96,7 @@ mixin EvalLambda { //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c,) -> 'd} //│ this: {eval: ('b, 's,) -> ('e & 'f) & (List[out (string, 'f,)], 't,) -> 'd & (List[in 'a out 'a | 'a0 | (string, Var,)], 't0,) -> 'g} -//│ fun eval: (List['a1] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) +//│ fun eval: forall 'a1. (List['a1] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) //│ } //│ where //│ 'a1 :> 'a | (string, Var,) @@ -113,7 +113,7 @@ module Test1 extends EvalVar, EvalLambda Test1.eval(Nil(), Var("a")) //│ 'a //│ where -//│ 'a :> Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Var Test1.eval(Nil(), Abs("b", Var("a"))) //│ 'a @@ -143,7 +143,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) +//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) mixin EvalExpr { fun eval(sub, v) = @@ -158,7 +158,7 @@ mixin EvalExpr { //│ mixin EvalExpr() { //│ super: {eval: ('a, Var,) -> 'b} //│ this: {eval: ('a, 'c,) -> anything} -//│ fun eval: ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) +//│ fun eval: forall 'd. ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) //│ } module Test2 extends EvalVar, EvalExpr @@ -199,7 +199,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> Abs[Var] | Add[Num | Var] | Num | Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 7e7aec7c21..f005c94753 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -54,10 +54,10 @@ class Foo { class Test { this: { x: int}; fun test = this.x } //│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } -//│ ╙── ^ +//│ ╙── ^^ //│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } -//│ ╙── ^^ +//│ ╙── ^ //│ class Test() { //│ fun test: error //│ } diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index 8fc1a60689..b8454d0b7c 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -14,15 +14,13 @@ type AI1 = Array[int] type AI2 = Array //│ type AI2 = Array[int] -// TODO fail gracefully -// :e +:e type AI3(n) = Array[int] //│ ╔══[ERROR] type alias definitions cannot have value parameters -//│ ║ l.19: type AI3(n) = Array[int] +//│ ║ l.18: type AI3(n) = Array[int] //│ ╙── ^^^ //│ type AI3 = Array[int] -// TODO fail gracefully // :e type AI3[A] = Array //│ type AI3[A] = Array[A] diff --git a/shared/src/test/diff/ucs/SplitBeforeOp.mls b/shared/src/test/diff/ucs/SplitBeforeOp.mls index f6b14129b8..9e32ae567d 100644 --- a/shared/src/test/diff/ucs/SplitBeforeOp.mls +++ b/shared/src/test/diff/ucs/SplitBeforeOp.mls @@ -1,4 +1,4 @@ -:NewParser +:NewDefs :e :ge @@ -9,7 +9,7 @@ if x //│ ║ ^ //│ ║ l.6: == 0 then 0 //│ ╙── ^^^^^^ -//│ res: error +//│ error //│ Code generation encountered an error: //│ if expression was not desugared @@ -21,7 +21,20 @@ if x //│ ╔══[ERROR] Cannot find constructor `A` in scope //│ ║ l.19: is A and //│ ╙── ^ -//│ res: error +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:e +:ge +if x + is A and + y then 0 +else 1 +//│ ╔══[ERROR] Cannot find constructor `A` in scope +//│ ║ l.31: is A and +//│ ╙── ^ +//│ error //│ Code generation encountered an error: //│ if expression was not desugared @@ -32,9 +45,9 @@ if x is A() then "A" B() then "B" -//│ ╔══[ERROR] Cannot find class `A` in scope -//│ ║ l.33: A() then "A" +//│ ╔══[ERROR] Illegal pattern `A` +//│ ║ l.46: A() then "A" //│ ╙── ^ -//│ res: error +//│ error //│ Code generation encountered an error: //│ if expression was not desugared diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 83cf6b21db..bbecb28789 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -495,33 +495,15 @@ class DiffTests val (typeDefs, stmts, newDefsResults) = if (newDefs) { - // /* val vars: Map[Str, typer.SimpleType] = Map.empty - val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx.nest, raise, vars) - - val comp = tpd.force()(raise) - - tpd.entities.foreach { e => - e.complete()(raise) match { - // comp.entities.foreach { - case tf: typer.TypedNuFun => - val sign = typer.PolymorphicType.mk(ctx.lvl, tf.ty) - ctx += tf.fd.nme.name -> typer.VarSymbol(sign, tf.fd.nme) - case tt: typer.TypedNuTypeDef => - ctx += e.decl.name -> e - // ctx += e.decl.name -> - // typer.VarSymbol(e.typeSignature(raise), e.decl.nameVar) - // case tt: typer.TypedNuMxn => - } - } - - // output(exp.toString) - - // val sctx = ShowCtx.mk(tpd) + val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise, vars) def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind - ttu.entities.map(_.complete()(raise)).foreach { + // ttu.entities.map(_.complete()(raise)).foreach { + ttu.entities.foreach { + case p: typer.NuParam => + output(s"${indStr}${p.name}: ${p.ty}") case tc: typer.TypedNuAls => output(s"${indStr}type ${tc.name} = ${tc.body}") case tc: typer.TypedNuCls => @@ -543,7 +525,7 @@ class DiffTests case S(false) => "let" case S(true) => "let rec" case N => "fun" - }} ${tf.name}: ${tf.ty} where ${tf.ty.showBounds + }} ${tf.name}: ${tf.typeSignature} where ${tf.typeSignature.showBounds .indentNewLines(indStr+"|")}") } } @@ -557,13 +539,13 @@ class DiffTests } val oldDbg = typer.dbg - val sim = if (mode.noSimplification) comp else try { + val sim = if (mode.noSimplification) tpd else try { typer.dbg = mode.dbgSimplif object SimplifyPipeline extends typer.SimplifyPipeline { def debugOutput(msg: => Str): Unit = if (mode.dbgSimplif) output(msg) } - SimplifyPipeline(comp, all = false)(ctx) + SimplifyPipeline(tpd, all = false)(ctx) } finally typer.dbg = oldDbg val exp = typer.expandType(sim)(ctx) @@ -759,7 +741,7 @@ class DiffTests ctx += nme.name -> typer.VarSymbol(ty_sch, nme) declared += nme.name -> ty_sch - val exp = getType(ty_sch).asInstanceOf[Type] + val exp = getType(ty_sch) if (mode.generateTsDeclarations) tsTypegenCodeBuilder.addTypeGenTermDefinition(exp, Some(nme.name)) S(nme.name -> (s"$nme: ${exp.show}" :: Nil)) From cbd406f384b448957b3fc1187f5953dbb994f42d Mon Sep 17 00:00:00 2001 From: Andong Fan Date: Sat, 11 Mar 2023 20:56:09 +0800 Subject: [PATCH 178/498] Minor HTML fix --- local_testing.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/local_testing.html b/local_testing.html index b922c72e2f..be884ca31b 100644 --- a/local_testing.html +++ b/local_testing.html @@ -26,7 +26,7 @@

MLscript demonstration

fun eval(override Neg(d)) = 0 - this.eval(d) } -module TestLang: EvalAddLit, EvalNeg +module TestLang extends EvalAddLit, EvalNeg let res = TestLang.eval(add2negadd11) @@ -47,7 +47,7 @@

Tip: additional definitions from the paper – copy and paste to try them ou   fun eval(override Neg(Neg(d))) = this.eval(d)
}

-module TestLang2: EvalAddLit, EvalNeg, EvalMul, EvalNegNeg
+module TestLang2 extends EvalAddLit, EvalNeg, EvalMul, EvalNegNeg

let res2 = TestLang2.eval(add2negadd11)

From 51dadc38b1c3f412f9c6f9c033a639458f0b0a23 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sun, 12 Mar 2023 03:41:50 +0800 Subject: [PATCH 179/498] WIP Small additional cleanup and minor type pp improvement --- shared/src/main/scala/mlscript/Typer.scala | 49 ++++++------------- .../test/diff/codegen/IndirectRecursion.mls | 2 +- shared/src/test/diff/fcp/Church_CT.mls | 10 ++-- shared/src/test/diff/fcp/NestedDataTypes.mls | 2 +- shared/src/test/diff/fcp/PaperTable.mls | 4 +- .../diff/fcp/QML_exist_Classes_ST_Repro.mls | 2 +- .../src/test/diff/fcp/ToChurchSimplif_CT.mls | 8 +-- shared/src/test/diff/fcp/Vec.mls | 8 +-- shared/src/test/diff/mlf-examples/ex_demo.mls | 2 +- .../test/diff/mlf-examples/ex_predicative.mls | 2 +- shared/src/test/diff/mlscript/Addable.mls | 2 +- shared/src/test/diff/mlscript/TypeClasses.mls | 12 ++--- shared/src/test/diff/nu/ClassesInMixins.mls | 4 +- shared/src/test/diff/nu/MutualRec.mls | 2 +- shared/src/test/diff/nu/SelfRec.mls | 2 +- 15 files changed, 47 insertions(+), 64 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ba3244e34b..0780e9d175 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1278,18 +1278,13 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def mkTypingUnit(thisTy: ST, members: Map[Str, NuMember])(implicit ectx: ExpCtx): TypingUnit = { val sorted = members.toList.sortBy(_._1) - // def mkTypingUnit(members: Ls[Str -> NuMember]): TypingUnit = { - TypingUnit( - // Asc(Var("this"), go(thisTy)) :: - // NuFunDef(S(false), Var("this"), Nil, R(go(thisTy))) :: - sorted.collect { + TypingUnit(sorted.collect { case (_, td: TypedNuDecl) => goDecl(td) // case (_, td: TypedNuFun) => ??? // case (_, p: NuParam) => ??? // case _ => die }) } - // def goDecl(d: TypedNuDecl)(implicit ectx: ExpCtx): NuDecl = d match { def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => @@ -1301,32 +1296,24 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), N, Nil,//TODO - // S(go(superTy)), - // S(go(thisTy)), Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), - // mkTypingUnit(thisTy, - // // members - // Map.empty - // ) mkTypingUnit(thisTy, members)) } case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => - // new ExpCtx(ectx.tps ++ tparams.iterator.map{case (tn, tv, vi) => tv -> tn}) |> { implicit ectx => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, - // NuTypeDef(td.kind, td.nme, tparams.map{case (tn, tv, vi) => }, - // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), N,//TODO Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members)) - // mkTypingUnit(() :: members.toList.sortBy(_._1))) } case tf @ TypedNuFun(level, fd, bodyTy) => NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature))) + case p: NuParam => + ??? // TODO } def goLike(ty: TypeLike)(implicit ectx: ExpCtx): mlscript.TypeLike = ty match { case ty: SimpleType => @@ -1337,21 +1324,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case OtherTypeLike(tu) => val mems = tu.entities.map(goDecl) Signature(mems, tu.result.map(go)) - // case OtherTypeLike(ttu) => - // val mems = ttu.entities.map { lti => - // lti.result match { - // // // case S(td: TypedNuTermDef) => ??? - // // case S(TypedNuCls(level, td, ttu, tparams, params, members)) => - // // NuTypeDef(td.kind, td.nme, td.tparams, - // // // Tup(params.map(p => S(p._1) -> Fld(p._2.ub)))) - // // Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), - // // Nil,//TODO - // // members) - // case S(d) => goDecl(d) - // case N => lastWords("Cannot expand uncomputed type info.") - // } - // } - // Signature(mems, ttu.result.map(go)) } def go(st: SimpleType)(implicit ectx: ExpCtx): Type = @@ -1418,10 +1390,21 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case Without(base, names) => Rem(go(base), names.toList) case Overload(as) => as.map(go).reduce(Inter) case PolymorphicType(lvl, bod) => + val boundsSize = bounds.size val b = go(bod) + + // This is not completely correct: if we've already traversed TVs as part of a previous sibling PolymorphicType, + // the bounds of these TVs won't be registered again... + // FIXME in principle we'd want to compute a transitive closure... + val newBounds = bounds.reverseIterator.drop(boundsSize).toBuffer + val qvars = bod.varsBetween(lvl, MaxLevel).iterator - if (qvars.isEmpty) b else - PolyType(qvars.map(_.asTypeVar pipe (R(_))).toList, b) + val ftvs = b.freeTypeVariables ++ + newBounds.iterator.map(_._1) ++ + newBounds.iterator.flatMap(_._2.freeTypeVariables) + val fvars = qvars.filter(tv => ftvs.contains(tv.asTypeVar)) + if (fvars.isEmpty) b else + PolyType(fvars.map(_.asTypeVar pipe (R(_))).toList, b) case ConstrainedType(cs, bod) => val (ubs, others1) = cs.groupMap(_._1)(_._2).toList.partition(_._2.sizeIs > 1) val lbs = others1.mapValues(_.head).groupMap(_._2)(_._1).toList diff --git a/shared/src/test/diff/codegen/IndirectRecursion.mls b/shared/src/test/diff/codegen/IndirectRecursion.mls index 4438a67a11..068855c833 100644 --- a/shared/src/test/diff/codegen/IndirectRecursion.mls +++ b/shared/src/test/diff/codegen/IndirectRecursion.mls @@ -149,7 +149,7 @@ def z = //│ ((anything -> nothing) -> anything) -> error //│ <: z: //│ (('a -> 'b) -> ('a -> 'b & 'c)) -> 'c -//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d ?e ?f ?g. ?f -> ?c) -> ?h` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d. ?d -> ?c) -> ?e` exceeded recursion depth limit (250) //│ ║ l.148: (fun f -> (fun x -> f (fun v -> (x x) v)) (fun x -> f (fun v -> (x x) v))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/Church_CT.mls b/shared/src/test/diff/fcp/Church_CT.mls index 1b3544e992..f4b8388a34 100644 --- a/shared/src/test/diff/fcp/Church_CT.mls +++ b/shared/src/test/diff/fcp/Church_CT.mls @@ -615,7 +615,7 @@ to_church_ty = to_ch //│ 'a <: 'b -> 'd -> 'c) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch ?c ?d. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.609: to_church_ty = to_ch //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -640,7 +640,7 @@ to_church_ty = to_ch_simplif //│ 'b <: 'd -> 'e) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.634: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -950,7 +950,7 @@ to_church_ty = to_ch //│ 'd <: 'f -> 'j -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?to_ch ?d. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.941: to_church_ty = to_ch //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -969,7 +969,7 @@ to_church_ty = to_ch_simplif //│ 'd <: 'f -> 'g -> 'h) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif ?a ?b ?c ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.960: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -1001,7 +1001,7 @@ to_church_ty = to_ch_simplif //│ 'e <: 'g -> 'h -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif ?a ?b ?c ?d. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) //│ ║ l.992: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/NestedDataTypes.mls b/shared/src/test/diff/fcp/NestedDataTypes.mls index 9bb0546d38..d81f219abd 100644 --- a/shared/src/test/diff/fcp/NestedDataTypes.mls +++ b/shared/src/test/diff/fcp/NestedDataTypes.mls @@ -240,7 +240,7 @@ rec def map f tree = case tree of { :e map succ n4 -//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?A ?value ?b ?A0 ?subTree ?A1 ?subTree0. ?b) -> ?c` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b. ?b) -> ?c` exceeded recursion depth limit (250) //│ ║ l.242: map succ n4 //│ ║ ^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/PaperTable.mls b/shared/src/test/diff/fcp/PaperTable.mls index ab15ffbc13..37fe3664aa 100644 --- a/shared/src/test/diff/fcp/PaperTable.mls +++ b/shared/src/test/diff/fcp/PaperTable.mls @@ -618,7 +618,7 @@ rec def id1 x = if true then x else id1 id1 x :e // G9 id1 id1 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?id1 ?e. ?id1 <: (forall ?f ?id10 ?g ?h ?i ?j. ?id10) -> ?k` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?id1. ?id1 <: (forall ?id10. ?id10) -> ?a` exceeded recursion depth limit (250) //│ ║ l.620: id1 id1 //│ ║ ^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -968,7 +968,7 @@ rec def id1 x = if true then x else id1 id1 x :e // G9 id1 id1 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?id1 ?c ?d ?e. ?id1 <: (forall ?id10 ?f ?g ?h ?i ?j. ?id10) -> ?k` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?id1. ?id1 <: (forall ?id10. ?id10) -> ?a` exceeded recursion depth limit (250) //│ ║ l.970: id1 id1 //│ ║ ^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls b/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls index f32ab899a0..a1b05ba61b 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls @@ -55,7 +55,7 @@ def simpleStepImpl arrImpl = ArraysImpl { // * Something off is going on here (see stats) :stats simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?Rep ?Rep0 ?A ?a ?b ?Rep1 ?Rep2 ?c ?Rep3 ?A0 ?A1 ?A2 ?Rep4 ?Rep5 ?A3 ?Rep6 ?d ?e ?f ?fold ?g ?A4 ?A5 ?Rep7 ?A6 ?Rep8 ?Rep9 ?h ?init ?A7 ?Rep10 ?A8 ?i ?update ?j ?k ?sub ?A9. ?h -> ?g <: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)]` took too many steps and ran out of fuel (5000) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b. ?b -> ?a <: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)]` took too many steps and ran out of fuel (5000) //│ ║ l.57: simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls index f2c1ff1bcc..2c6689163a 100644 --- a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls +++ b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls @@ -150,7 +150,7 @@ to_church = to_ch //│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?to_ch. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) //│ ║ l.145: to_church = to_ch //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -178,7 +178,7 @@ to_church = to_ch //│ 'a <: 'b -> 'c -> 'd) | ChurchInt //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?to_ch ?b ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) //│ ║ l.173: to_church = to_ch //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -546,7 +546,7 @@ to_church = to_ch //│ 'd <: 'g -> 'h -> 'e) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) //│ ║ l.539: to_church = to_ch //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -575,7 +575,7 @@ to_church = to_ch //│ 'd <: 'e -> 'f -> 'g) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?to_ch ?c ?d. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) //│ ║ l.568: to_church = to_ch //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/fcp/Vec.mls b/shared/src/test/diff/fcp/Vec.mls index f88aeb0b40..6f0ce19b90 100644 --- a/shared/src/test/diff/fcp/Vec.mls +++ b/shared/src/test/diff/fcp/Vec.mls @@ -353,7 +353,7 @@ sum_ty = sum //│ 'a <: (((Cons[?, ?]\size with {head: int, tail: 'a}) | Nil) -> int) -> (int & 'b) //│ <: sum_ty: //│ Vec[int, 'n] -> int -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?tail ?a ?b ?c ?sum. ?sum <: forall 'n. Vec[int, 'n] -> int` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?sum. ?sum <: forall 'n. Vec[int, 'n] -> int` exceeded recursion depth limit (250) //│ ║ l.350: sum_ty = sum //│ ║ ^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -364,7 +364,7 @@ sum nil // * Note: also worked woth top/bot extrusion sum v1_0 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?sum ?tail ?b ?c. ?sum <: (forall 'a ?P ?d 'n ?N ?A ?head. ?d) -> ?e` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?sum. ?sum <: (forall ?a. ?a) -> ?b` exceeded recursion depth limit (250) //│ ║ l.366: sum v1_0 //│ ║ ^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -372,7 +372,7 @@ sum v1_0 // * Note: also worked woth top/bot extrusion sum v2 -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?tail ?c ?sum. ?sum <: (forall ?A 'p 'p0 'p1 ?N 'p2 'p3 ?d 'a ?P 'p4 'p5 ?head 'p6 'n. ?d) -> ?e` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?sum. ?sum <: (forall ?a. ?a) -> ?b` exceeded recursion depth limit (250) //│ ║ l.374: sum v2 //│ ║ ^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -419,7 +419,7 @@ sum v1_ty //│ ╟── type `Cons[int, Z]` is not a function //│ ║ l.198: v1_ty = v1_ : Cons[int, Z] //│ ║ ^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `(forall ?a ?tail ?b ?c ?d ?head. ?d -> ?a) -> ?e` +//│ ╟── but it flows into reference with expected type `(forall ?a ?b. ?b -> ?a) -> ?c` //│ ║ l.+1: sum v1_ty //│ ║ ^^^^^ //│ ╟── Note: constraint arises from application: diff --git a/shared/src/test/diff/mlf-examples/ex_demo.mls b/shared/src/test/diff/mlf-examples/ex_demo.mls index 9966a8c063..03a5ea2622 100644 --- a/shared/src/test/diff/mlf-examples/ex_demo.mls +++ b/shared/src/test/diff/mlf-examples/ex_demo.mls @@ -1146,7 +1146,7 @@ this_should_be_98_ = //│ ║ l.1140: let c_i10_ = c_mul_ c_i5_ c_i2_ in //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c ?d ?e ?f. ?d -> ?f <: (forall ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?a1 ?b1 ?c1 ?d1 ?e1 ?f1 ?g1 ?h1 ?i1 ?j1 ?k1 ?l1 ?m1 ?n1 ?o1 ?p1 ?q1 ?r1 ?s1 ?t1 ?u1 ?v1 ?w1 ?x1 ?y1 ?z1 ?a2 ?b2 ?c2 ?d2 ?e2 ?f2 ?g2 ?h2 ?i2 ?j2 ?k2 ?l2 ?m2 ?n2 ?o2 ?p2 ?q2 ?r2 ?s2 ?t2 ?u2 ?v2 ?w2 ?x2 ?y2 ?z2 ?a3 ?b3 ?c3 ?d3 ?e3 ?f3 ?g3 ?h3 ?i3 ?j3 ?k3 ?l3 ?m3 ?n3 ?o3 ?p3 ?q3 ?r3 ?s3 ?t3 ?u3 ?v3 ?w3 ?x3 ?y3 ?z3 ?a4 ?b4 ?c4 ?d4 ?e4 ?f4 ?g4 ?h4 ?i4 ?j4 ?k4 ?l4 ?m4 ?n4 ?o4 ?p4 ?q4 ?r4 ?s4 ?t4 ?u4 ?v4 ?w4 ?x4 ?y4 ?z4 ?a5 ?b5 ?c5 ?d5 ?e5 ?f5 ?g5 ?h5 ?i5 ?j5 ?k5 ?l5 ?m5 ?n5 ?o5 ?p5 ?q5 ?r5 ?s5 ?t5 ?u5 ?v5 ?w5 ?x5 ?y5 ?z5 ?a6 ?b6 ?c6 ?d6 ?e6 ?f6 ?g6 ?h6 ?i6 ?j6 ?k6 ?l6 ?m6 ?n6 ?o6 ?p6 ?q6 ?r6 ?s6 ?t6 ?u6 ?v6 ?w6 ?x6 ?y6 ?z6 ?a7 ?b7 ?c7 ?d7 ?e7 ?f7 ?g7 ?h7 ?i7 ?j7 ?k7 ?l7 ?m7 ?n7 ?o7 ?p7 ?q7 ?r7 ?s7 ?t7 ?u7 ?v7 ?w7 ?x7 ?y7 ?z7 ?a8 ?b8 ?c8 ?d8 ?e8 ?f8 ?g8 ?h8 ?i8 'a ?j8 ?k8 ?l8 ?m8 ?n8 ?o8 ?p8 ?q8 ?r8 ?s8 ?t8 ?u8 ?v8 ?w8 ?x8 ?y8 ?z8 ?a9 ?b9 ?c9 ?d9 ?e9 ?f9 ?g9 ?h9 ?i9 ?j9 ?k9 ?l9 'a0 ?m9 ?n9 ?o9 ?p9 ?q9 ?r9 ?s9 ?t9 ?u9 ?v9 ?w9 ?x9 ?y9 ?z9 ?a10 ?b10 ?c10 ?d10 ?e10 ?f10 ?g10 ?h10 ?i10 ?j10 ?k10 ?l10 ?m10. ?b10) -> ?n10` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b. ?a -> ?b <: (forall ?c. ?c) -> ?d` exceeded recursion depth limit (250) //│ ║ l.1141: let c_i9_ = c_pred_ c_i10_ in //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/mlf-examples/ex_predicative.mls b/shared/src/test/diff/mlf-examples/ex_predicative.mls index 46e13d53a7..b6d8aa1ab4 100644 --- a/shared/src/test/diff/mlf-examples/ex_predicative.mls +++ b/shared/src/test/diff/mlf-examples/ex_predicative.mls @@ -221,7 +221,7 @@ t id succ 0 :e def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) two -//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b ?c ?d ?e. ?b -> ?c -> ?e) -> ?f` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b ?c ?d. ?b -> ?c -> ?d) -> ?e` exceeded recursion depth limit (250) //│ ║ l.223: def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) two //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/mlscript/Addable.mls b/shared/src/test/diff/mlscript/Addable.mls index 5f3aac69cc..10f9e12a85 100644 --- a/shared/src/test/diff/mlscript/Addable.mls +++ b/shared/src/test/diff/mlscript/Addable.mls @@ -130,7 +130,7 @@ addSame n n //│ ╟── application of type `Num & {val: ?val}` is not a function //│ ║ l.17: n = Num { val = 1 } //│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `(forall ?a ?val0. ?a) -> ?b` +//│ ╟── but it flows into reference with expected type `(forall ?a. ?a) -> ?b` //│ ║ l.+1: addSame n n //│ ╙── ^ //│ res: error diff --git a/shared/src/test/diff/mlscript/TypeClasses.mls b/shared/src/test/diff/mlscript/TypeClasses.mls index 47e03bb156..1babcff5ca 100644 --- a/shared/src/test/diff/mlscript/TypeClasses.mls +++ b/shared/src/test/diff/mlscript/TypeClasses.mls @@ -128,7 +128,7 @@ class ComplexMonoid_bad_0[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` is not a record (expected a record with fields: real, imaginary) +//│ ╟── function of type `forall ?a ?b. ?a -> ?b` is not a record (expected a record with fields: real, imaginary) //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` @@ -143,7 +143,7 @@ class ComplexMonoid_bad_0[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `forall ?imaginary ?a ?b. ?b -> ?a` is not a record (expected a record with fields: real, imaginary) +//│ ╟── function of type `forall ?a ?b. ?b -> ?a` is not a record (expected a record with fields: real, imaginary) //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` @@ -158,7 +158,7 @@ class ComplexMonoid_bad_0[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` does not have field 'Complex#A' +//│ ╟── function of type `forall ?a ?b. ?a -> ?b` does not have field 'Complex#A' //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{Complex#A <: A}` @@ -202,7 +202,7 @@ class ComplexMonoid_bad_1[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` is not a record (expected a record with fields: real, imaginary) +//│ ╟── function of type `forall ?a ?b. ?a -> ?b` is not a record (expected a record with fields: real, imaginary) //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` @@ -217,7 +217,7 @@ class ComplexMonoid_bad_1[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `forall ?a ?b ?imaginary. ?b -> ?a` is not a record (expected a record with fields: real, imaginary) +//│ ╟── function of type `forall ?a ?b. ?b -> ?a` is not a record (expected a record with fields: real, imaginary) //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` @@ -232,7 +232,7 @@ class ComplexMonoid_bad_1[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `forall ?a ?imaginary ?b. ?a -> ?b` does not have field 'Complex#A' +//│ ╟── function of type `forall ?a ?b. ?a -> ?b` does not have field 'Complex#A' //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{Complex#A <: A}` diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 1c6e5a3377..d18a1d346a 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -31,7 +31,7 @@ M.Foo //│ ╙── ^^^^ //│ error -:e // TODO +:e // TODO support fun foo(x) = if x is M.Foo then 1 //│ ╔══[ERROR] illegal pattern //│ ║ l.35: fun foo(x) = if x is M.Foo then 1 @@ -58,7 +58,7 @@ mixin Test3 { fun f(x) = if x is Foo then 1 } -:e // TODO +:e // TODO support mixin Test { class Lit(n: int) class Add(lhs: A, rhs: A) { diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 96026522c7..3fe23e7dc7 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -89,7 +89,7 @@ foo fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} //│ fun foo: forall 'a 'b 'c. 'a -> 'b -//│ fun bar: forall 'a 'b 'c. 'a -> 'c +//│ fun bar: forall 'a 'c. 'a -> 'c //│ where //│ 'b :> {h1: 'a, t1: 'c} //│ 'c :> {h2: 'a, t2: 'b} diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 7d6bfb93df..eb7c10bbc7 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -30,7 +30,7 @@ class Foo3[A](x: A) { fun foo = Foo3 } //│ class Foo3[A](x: A) { -//│ fun foo: forall 'A. (x: A,) -> Foo3[A] +//│ fun foo: (x: A,) -> Foo3[A] //│ fun test: Foo3[1] //│ } From 03a28b8b2816a114ba2d2086efe94cc3f881d566 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sun, 12 Mar 2023 16:41:41 +0800 Subject: [PATCH 180/498] Support alias clauses and complete the ULC test cases --- .../src/main/scala/mlscript/ucs/Clause.scala | 4 + .../main/scala/mlscript/ucs/Desugarer.scala | 4 + .../main/scala/mlscript/ucs/MutCaseOf.scala | 4 +- shared/src/test/diff/ucs/Lambda.mls | 403 +++++++++++++++--- 4 files changed, 356 insertions(+), 59 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index d4c26b6b1d..3b34155592 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -38,6 +38,8 @@ object Clause { final case class BooleanTest(test: Term)(override val locations: Ls[Loc]) extends Clause + final case class Binding(name: Var, term: Term)(override val locations: Ls[Loc]) extends Clause + def showBindings(bindings: Ls[(Bool, Var, Term)]): Str = bindings match { case Nil => "" @@ -55,6 +57,8 @@ object Clause { s"«$scrutinee is $className»" case Clause.MatchTuple(scrutinee, arity, fields) => s"«$scrutinee is Tuple#$arity»" + case Clause.Binding(Var(name), term) => + s"«$name = $term»" }) + (if (clause.bindings.isEmpty) "" else " with " + showBindings(clause.bindings)) }.mkString("", " and ", "") } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 4a246d059e..4bda544f85 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -157,6 +157,10 @@ class Desugarer extends TypeDefs { self: Typer => clause.bindings = scrutinee.asBinding.toList printlnUCS(s"Add bindings to the clause: ${scrutinee.asBinding}") clause :: Nil + // This case handles name binding. + // x is a + case bindingVar @ Var(bindingName) if bindingName.headOption.exists(_.isLower) => + Clause.Binding(bindingVar, scrutinee.term)(scrutinee.term.toLoc.toList ::: bindingVar.toLoc.toList) :: Nil // This case handles simple class tests. // x is A case classNameVar @ Var(className) => diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index 37d9084999..885532cef0 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -148,7 +148,7 @@ object MutCaseOf { } } - import Clause.{MatchClass, MatchTuple, BooleanTest} + import Clause.{MatchClass, MatchTuple, BooleanTest, Binding} // A short-hand for pattern matchings with only true and false branches. final case class IfThenElse(condition: Term, var whenTrue: MutCaseOf, var whenFalse: MutCaseOf) extends MutCaseOf { @@ -345,6 +345,8 @@ object MutCaseOf { .withLocations(head.locations) ) Match(scrutinee, branches, N) + case Binding(name, term) => + rec(realTail).withBindings((false, name, term) :: Nil) }).withBindings(head.bindings) case Conjunction(Nil, trailingBindings) => Consequent(term).withBindings(trailingBindings) diff --git a/shared/src/test/diff/ucs/Lambda.mls b/shared/src/test/diff/ucs/Lambda.mls index 53a135406f..cf5dc872d4 100644 --- a/shared/src/test/diff/ucs/Lambda.mls +++ b/shared/src/test/diff/ucs/Lambda.mls @@ -1,5 +1,69 @@ :NewParser +:escape +// You can push debug messages to this magic array. +let Array: { from: anything => { push: anything => anything, join: string => string } } +let _Array = Array +let logs: { push: anything => anything, join: string => string } = _Array.from([]) +let debug: anything => anything = x => logs.push(x) +fun showDebug = logs.join("\n") +//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = +//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = [Function: Array] +//│ logs: {join: string -> string, push: anything -> anything} +//│ = [] +//│ debug: anything -> anything +//│ = [Function: debug] +//│ showDebug: string +//│ = [Function: showDebug] + +fun concat2(a, b) = concat(a)(b) +fun concat3(a, b, c) = concat2(a, concat2(b, c)) +fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) +fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) +fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) +fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) +fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) +fun par(a) = concat3("(", a, ")") +//│ concat2: (string, string,) -> string +//│ = [Function: concat2] +//│ concat3: (string, string, string,) -> string +//│ = [Function: concat3] +//│ concat4: (string, string, string, string,) -> string +//│ = [Function: concat4] +//│ concat5: (string, string, string, string, string,) -> string +//│ = [Function: concat5] +//│ concat6: (string, string, string, string, string, string,) -> string +//│ = [Function: concat6] +//│ concat7: (string, string, string, string, string, string, string,) -> string +//│ = [Function: concat7] +//│ concat8: (string, string, string, string, string, string, string, string,) -> string +//│ = [Function: concat8] +//│ par: string -> string +//│ = [Function: par] + +:escape +let String: nothing +let makeString: anything => { length: int, charCodeAt: int => int } = String +let StringInstance: { fromCharCode: int => string } = String +//│ String: nothing +//│ = +//│ makeString: anything -> {charCodeAt: int -> int, length: int} +//│ = [Function: String] +//│ StringInstance: {fromCharCode: int -> string} +//│ = [Function: String] + +fun fromCharCode(n) = StringInstance.fromCharCode(n) +fun stringCharCodeAt(s, i) = makeString(s).charCodeAt(i) +fun stringLength(s) = makeString(s).length +//│ fromCharCode: int -> string +//│ = [Function: fromCharCode] +//│ stringCharCodeAt: (anything, int,) -> int +//│ = [Function: stringCharCodeAt] +//│ stringLength: anything -> int +//│ = [Function: stringLength] + class Option class Some(value): Option class None(): Option @@ -13,6 +77,92 @@ class None(): Option //│ None: () -> None //│ = [Function: None1] +class List +class Cons(head, tail): List +class Nil(): List +//│ Defined class List +//│ Defined class Cons +//│ Defined class Nil +//│ List: () -> List +//│ = [Function: List1] +//│ Cons: ('head, 'tail,) -> (Cons with {head: 'head, tail: 'tail}) +//│ = [Function: Cons1] +//│ Nil: () -> Nil +//│ = [Function: Nil1] + +fun list1(x) = Cons(x, Nil()) +fun list2(x, y) = Cons(x, list1(y)) +fun list3(x, y, z) = Cons(x, list2(y, z)) +fun list4(x, y, z, w) = Cons(x, list3(y, z, w)) +fun list5(x, y, z, w, v) = Cons(x, list4(y, z, w, v)) +fun list6(x, y, z, w, v, u) = Cons(x, list5(y, z, w, v, u)) +fun list7(x, y, z, w, v, u, t) = Cons(x, list6(y, z, w, v, u, t)) +fun list8(x, y, z, w, v, u, t, s) = Cons(x, list7(y, z, w, v, u, t, s)) +//│ list1: 'head -> (Cons with {head: 'head, tail: Nil}) +//│ = [Function: list1] +//│ list2: ('head, 'head0,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Nil}}) +//│ = [Function: list2] +//│ list3: ('head, 'head0, 'head1,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Nil}}}) +//│ = [Function: list3] +//│ list4: ('head, 'head0, 'head1, 'head2,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Nil}}}}) +//│ = [Function: list4] +//│ list5: ('head, 'head0, 'head1, 'head2, 'head3,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Nil}}}}}) +//│ = [Function: list5] +//│ list6: ('head, 'head0, 'head1, 'head2, 'head3, 'head4,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Cons with {head: 'head4, tail: Nil}}}}}}) +//│ = [Function: list6] +//│ list7: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Cons with {head: 'head4, tail: Cons with {head: 'head5, tail: Nil}}}}}}}) +//│ = [Function: list7] +//│ list8: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5, 'head6,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Cons with {head: 'head4, tail: Cons with {head: 'head5, tail: Cons with {head: 'head6, tail: Nil}}}}}}}}) +//│ = [Function: list8] + +fun listConcat(xs, ys) = + if xs is + Nil() then ys + Cons(x, xs') then Cons(x, listConcat(xs', ys)) +//│ listConcat: ('a, 'tail,) -> 'tail +//│ where +//│ 'tail :> Cons with {head: 'head, tail: 'tail} +//│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil +//│ = [Function: listConcat] + +fun listContains(xs, x) = + if xs is + Nil() then false + Cons(x', xs') and + eq(x)(x') then true + _ then listContains(xs', x) +//│ listContains: ('a, anything,) -> bool +//│ where +//│ 'a <: Cons & {tail: 'a} | Nil +//│ = [Function: listContains] + +// Remove all occurrences of x from xs. +fun listWithout(xs, x) = + if xs is + Nil() then Nil() + Cons(x', xs') and + eq(x)(x') then listWithout(xs', x) + _ then Cons(x', listWithout(xs', x)) +//│ listWithout: ('a, anything,) -> 'tail +//│ where +//│ 'tail :> (Cons with {head: 'head, tail: 'tail}) | Nil +//│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil +//│ = [Function: listWithout] + +fun listJoin(xs, sep) = + if xs is + Nil() then "" + Cons(x, Nil()) then toString(x) + Cons(x, xs') then concat3(toString(x), sep, listJoin(xs', sep)) +//│ listJoin: ('a, string,) -> string +//│ where +//│ 'a <: Cons & {tail: 'a} | Nil +//│ = [Function: listJoin] + +listJoin(list3("x", "y", "z"), ", ") +//│ res: string +//│ = 'x, y, z' + class Term class Var(name): Term class Abs(lhs, rhs): Term @@ -30,31 +180,6 @@ class App(lhs, rhs): Term //│ App: ('lhs, 'rhs,) -> (App with {lhs: 'lhs, rhs: 'rhs}) //│ = [Function: App1] -fun concat2(a, b) = concat(a)(b) -fun concat3(a, b, c) = concat2(a, concat2(b, c)) -fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) -fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) -fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) -fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) -fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) -fun par(a) = concat3("(", a, ")") -//│ concat2: (string, string,) -> string -//│ = [Function: concat2] -//│ concat3: (string, string, string,) -> string -//│ = [Function: concat3] -//│ concat4: (string, string, string, string,) -> string -//│ = [Function: concat4] -//│ concat5: (string, string, string, string, string,) -> string -//│ = [Function: concat5] -//│ concat6: (string, string, string, string, string, string,) -> string -//│ = [Function: concat6] -//│ concat7: (string, string, string, string, string, string, string,) -> string -//│ = [Function: concat7] -//│ concat8: (string, string, string, string, string, string, string, string,) -> string -//│ = [Function: concat8] -//│ par: string -> string -//│ = [Function: par] - fun showTerm(t) = if t is Var(name) then toString(name) @@ -98,25 +223,21 @@ isValue(App(Var("x"), Var("y"))) //│ res: bool //│ = false +:w fun hasFree(t, n) = if t is + // let __ = debug(concat3(showTerm(t), ", ", n)) Var(na) then eq(n)(na) - Abs(Var(name), body) and eq(name, n) then false + Abs(Var(name), body) and eq(name)(n) then false Abs(Var(name), body) then hasFree(body, n) App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) _ then false //│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.107: _ then false +//│ ║ l.234: _ then false //│ ║ ^^^^^ //│ ╟── The first else branch was declared here. -//│ ║ l.105: Abs(Var(name), body) then hasFree(body, n) +//│ ║ l.232: Abs(Var(name), body) then hasFree(body, n) //│ ╙── ^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.104: Abs(Var(name), body) and eq(name, n) then false -//│ ║ ^^^^^^^^^^^ -//│ ╟── tuple literal of type `(?name, ?a,)` does not match type `(?b,)` -//│ ║ l.104: Abs(Var(name), body) and eq(name, n) then false -//│ ╙── ^^^^^^^^^ //│ hasFree: ('a, anything,) -> bool //│ where //│ 'a <: Abs & {rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var | ~Abs & ~App & ~Var @@ -138,6 +259,10 @@ showHasFree(Abs(Var("x"), Var("y")), "x") showHasFree(Abs(Var("x"), Var("y")), "y") showHasFree(App(Var("x"), Var("y")), "x") showHasFree(App(Var("x"), Var("y")), "y") +showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "x") +showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") +showHasFree(App(Abs(Var("x"), Var("x")), Var("y")), "y") +showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") //│ res: string //│ = 'x has free variable x' //│ res: string @@ -154,42 +279,185 @@ showHasFree(App(Var("x"), Var("y")), "y") //│ = '(x y) has free variable x' //│ res: string //│ = '(x y) has free variable y' +//│ res: string +//│ = '((&x. x) x) has free variable x' +//│ res: string +//│ = '((&x. x) x) DOES NOT have free variable y' +//│ res: string +//│ = '((&x. x) y) has free variable y' +//│ res: string +//│ = '((&x. x) x) DOES NOT have free variable y' + +fun fv(t) = + if t is + Var(name) then list1(name) + Abs(Var(name), body) then listWithout(fv(body), name) + App(lhs, rhs) then listConcat(fv(lhs), fv(rhs)) +//│ fv: 'a -> 'tail +//│ where +//│ 'tail :> Cons & {head: 'head, tail: Nil} | 'tail0 | (Cons with {head: 'head, tail: 'tail}) +//│ 'tail0 :> (Cons with {head: 'head, tail: 'tail0}) | Nil +//│ 'a <: Abs & {lhs: Var, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var & {name: 'head} +//│ = [Function: fv] +fun showFv(t) = + concat2(showTerm(t), if fv(t) is + Nil then " DOES NOT have free variables" + _ then concat2(" has free variables: ", listJoin(fv(t), ", ")) + ) +//│ showFv: ('a & 'b) -> string +//│ where +//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var +//│ 'a <: Abs & {lhs: Var, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var & {name: anything} +//│ = [Function: showFv] + +showFv(Var("x")) +showFv(Abs(Var("x"), Var("x"))) +showFv(Abs(Var("x"), Var("y"))) +showFv(App(Var("x"), Var("y"))) +showFv(App(Abs(Var("x"), Var("x")), Var("x"))) +//│ res: string +//│ = 'x has free variables: x' +//│ res: string +//│ = '&x. x DOES NOT have free variables' +//│ res: string +//│ = '&x. y has free variables: y' +//│ res: string +//│ = '(x y) has free variables: x, y' +//│ res: string +//│ = '((&x. x) x) has free variables: x' + +fun tryNextAlphabet(initialCode, currentCode, freeNames) = + if + currentCode + > 122 then tryNextAlphabet(initialCode, 97, freeNames) + == initialCode then None() + let name = fromCharCode(currentCode) + listContains(freeNames, name) then tryNextAlphabet(initialCode, currentCode + 1, freeNames) + _ then Some(name) +//│ tryNextAlphabet: (number, int, 'a,) -> (None | Some & {value: string}) +//│ where +//│ 'a <: Cons & {tail: 'a} | Nil +//│ = [Function: tryNextAlphabet] + +tryNextAlphabet(97, 97, list1("a")) +tryNextAlphabet(97, 98, list1("a")) +tryNextAlphabet(97, 98, list2("a", "b")) +tryNextAlphabet(121, 122, list1("y")) +tryNextAlphabet(121, 122, list2("y", "z")) +//│ res: None | Some & {value: string} +//│ = None {} +//│ res: None | Some & {value: string} +//│ = Some { value: 'b' } +//│ res: None | Some & {value: string} +//│ = Some { value: 'c' } +//│ res: None | Some & {value: string} +//│ = Some { value: 'z' } +//│ res: None | Some & {value: string} +//│ = Some { value: 'a' } + +fun tryAppendDigits(name, index, freeNames) = + if + let currentName = concat2(name, toString(index)) + listContains(freeNames, currentName) then + tryAppendDigits(name, index + 1, freeNames) + _ then currentName +//│ tryAppendDigits: (string, int, 'a,) -> string +//│ where +//│ 'a <: Cons & {tail: 'a} | Nil +//│ = [Function: tryAppendDigits] + +// Note: some weird behavior here... Just try the commented code. +// fun findFreshName(name, freeNames) = +// if +// stringLength(name) == 1 and +// let charCode = stringCharCodeAt(name, 0) +// tryNextAlphabet(charCode, charCode + 1, freeNames) is +// Some(newName) then newName +// _ then tryAppendDigits(name, 0, freeNames) +fun findFreshName(name, freeNames) = + if + stringLength(name) == 1 and + let charCode = stringCharCodeAt(name, 0) + tryNextAlphabet(charCode, charCode + 1, freeNames) is Some(newName) then newName + _ then tryAppendDigits(name, 0, freeNames) +//│ findFreshName: (string, 'a,) -> string +//│ where +//│ 'a <: Cons & {tail: 'a} | Nil +//│ = [Function: findFreshName] + +// Find a fresh name to replace `name` that does not conflict with any bound +// variables in the `body`. +fun freshName(name, body) = findFreshName(name, fv(body)) +//│ freshName: (string, 'a,) -> string +//│ where +//│ 'a <: Abs & {lhs: Var, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var & {name: anything} +//│ = [Function: freshName] + +:w fun subst(t, n, v) = if t is Var(name) and eq(name)(n) then v - Abs(Var(name), body) and - ne(name)(n) then Abs(Var(name), subst(body, n, v)) - hasFree(body, n) and freshName(name) is newName then + Abs(Var(name), body) and ne(name)(n) and + hasFree(v, name) and freshName(name, body) is newName then subst(Abs(Var(newName), subst(body, name, Var(newName))), n, v) + _ then Abs(Var(name), subst(body, n, v)) App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t -//│ ╔══[ERROR] Cannot find the constructor `newName` in the context -//│ ║ l.163: hasFree(body, n) and freshName(name) is newName then -//│ ╙── ^^^^^^^ -//│ subst: (anything, anything, anything,) -> error -//│ Code generation encountered an error: -//│ if expression has not been desugared +//│ ╔══[WARNING] Found a duplicated else branch +//│ ║ l.406: _ then t +//│ ║ ^ +//│ ╟── The first else branch was declared here. +//│ ║ l.404: _ then Abs(Var(name), subst(body, n, v)) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ subst: ('a, anything, 'a & 'b & 'rhs & 'c,) -> 'rhs +//│ where +//│ 'c <: Abs & {rhs: 'c} | App & {lhs: 'c, rhs: 'c} | Var | ~Abs & ~App & ~Var +//│ 'a <: Abs & 'd | App & 'e | Var & 'f | 'g & ~#Abs & ~#App & ~#Var +//│ 'd :> (Abs with {lhs: Var & {name: string}, rhs: 'rhs}) | 'rhs +//│ <: 'b & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} & 'e | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} & 'f | {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} & 'g & ~#Abs & ~#App & ~#Var) +//│ 'rhs :> (App with {lhs: 'rhs, rhs: 'rhs}) | (Abs with {lhs: Var & {name: 'name0}, rhs: 'rhs}) | Var & {name: string} | 'f | 'd | 'g +//│ 'f :> Var & {name: string} +//│ <: 'b & (Abs & {name: anything} & 'd | App & {name: anything} & 'e | Var | {name: anything} & 'g & ~#Abs & ~#App & ~#Var) +//│ 'g <: 'b & (Abs & 'd | App & 'e | Var & 'f | ~#Abs & ~#App & ~#Var) +//│ 'e <: {lhs: 'a, rhs: 'a} +//│ 'b <: Abs & {lhs: Var, rhs: 'b} | App & {lhs: 'b, rhs: 'b} | Var & {name: anything} +//│ 'name0 :> string +//│ <: 'name +//│ 'name <: string & 'name0 +//│ = [Function: subst] fun showSubst(t, n, v) = concat8(showTerm(t), " [", n, " / ", showTerm(v), "]", " => ", showTerm(subst(t, n, v))) -//│ showSubst: ('a, string, 'a,) -> string +//│ showSubst: ('a & 'b, string, 'a & 'lhs & 'c & 'd & 'e & 'b,) -> string //│ where -//│ 'a <: Abs & {lhs: 'a, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, rhs: 'a} | ~#Abs), rhs: 'a} | Var +//│ 'e <: Abs & {rhs: 'e} | App & {lhs: 'e, rhs: 'e} | Var | ~Abs & ~App & ~Var +//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var +//│ 'a <: Abs & 'f | App & 'g | Var & 'h | 'i & ~#Abs & ~#App & ~#Var +//│ 'f <: 'lhs & 'c & 'd & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} | App & {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} & 'g | Var & {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} & 'h | {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} & 'i & ~#Abs & ~#App & ~#Var) +//│ 'h <: 'lhs & 'c & 'd & (Abs & {name: anything} & 'f | App & {name: anything} & 'g | Var | {name: anything} & 'i & ~#Abs & ~#App & ~#Var) +//│ 'i <: 'lhs & 'c & 'd & (Abs & 'f | App & 'g | ~#Abs & ~#App & ~#Var | Var & 'h) +//│ 'g <: {lhs: 'a, rhs: 'a} +//│ 'd <: Abs & {lhs: Var, rhs: 'd} | App & {lhs: 'd, rhs: 'd} | Var & {name: anything} +//│ 'lhs <: Abs & {lhs: 'c, rhs: 'c} | ~Abs +//│ 'c <: Abs & {lhs: 'c, rhs: 'c} | App & {lhs: 'lhs & 'c, rhs: 'c} | Var //│ = [Function: showSubst] showSubst(Var("x"), "x", Var("y")) showSubst(Abs(Var("x"), Var("x")), "x", Var("z")) showSubst(App(Var("x"), Var("y")), "x", Abs(Var("x"), Var("x"))) +showSubst(App(Abs(Var("x"), Var("x")), Var("x")), "x", Abs(Var("y"), Var("y"))) +showSubst(Abs(Var("x"), App(Var("x"), Var("y"))), "y", Var("x")) +//│ res: string +//│ = 'x [x / y] => y' +//│ res: string +//│ = '&x. x [x / z] => &x. x' //│ res: string -//│ Runtime error: -//│ ReferenceError: subst is not defined +//│ = '(x y) [x / &x. x] => ((&x. x) y)' //│ res: string -//│ Runtime error: -//│ ReferenceError: subst is not defined +//│ = '((&x. x) x) [x / &y. y] => ((&x. x) &y. y)' //│ res: string -//│ Runtime error: -//│ ReferenceError: subst is not defined +//│ = '&x. (x y) [y / x] => &z. (z x)' fun stepByValue(t) = if t is @@ -204,8 +472,21 @@ fun stepByValue(t) = _ then None() //│ stepByValue: 'a -> (None | (Some with {value: 'rhs})) //│ where -//│ 'rhs :> error | (App with {lhs: 'rhs, rhs: 'rhs0}) | (App with {lhs: 'lhs, rhs: 'rhs}) -//│ 'a <: Abs | App & {lhs: 'a & 'lhs & (Abs | ~#Abs), rhs: 'a & 'rhs0} | Var +//│ 'rhs :> 'value | (App with {lhs: 'rhs, rhs: 'rhs0}) | (App with {lhs: 'lhs, rhs: 'rhs}) +//│ 'a <: Abs | App & {lhs: 'lhs & 'a & (Abs & {rhs: 'b} | ~#Abs), rhs: 'a & 'b & 'c & 'value & 'd & 'rhs0} | Var +//│ 'd <: Abs & {rhs: 'd} | App & {lhs: 'd, rhs: 'd} | Var | ~Abs & ~App & ~Var +//│ 'b <: Abs & 'e | App & 'f | Var & 'g | 'h & ~#Abs & ~#App & ~#Var +//│ 'e :> (Abs with {lhs: Var & {name: string}, rhs: 'value}) | 'value +//│ <: 'c & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} & 'f | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} & 'g | {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} & 'h & ~#Abs & ~#App & ~#Var) +//│ 'value :> (App with {lhs: 'value, rhs: 'value}) | (Abs with {lhs: Var & {name: 'name0}, rhs: 'value}) | Var & {name: string} | 'g | 'e | 'h +//│ 'g :> Var & {name: string} +//│ <: 'c & (Abs & {name: anything} & 'e | App & {name: anything} & 'f | Var | {name: anything} & 'h & ~#Abs & ~#App & ~#Var) +//│ 'h <: 'c & (Abs & 'e | App & 'f | Var & 'g | ~#Abs & ~#App & ~#Var) +//│ 'f <: {lhs: 'b, rhs: 'b} +//│ 'c <: Abs & {lhs: Var, rhs: 'c} | App & {lhs: 'c, rhs: 'c} | Var & {name: anything} +//│ 'name0 :> string +//│ <: 'name +//│ 'name <: string & 'name0 //│ = [Function: stepByValue] fun showStepByValue(t) = @@ -216,9 +497,16 @@ fun showStepByValue(t) = //│ showStepByValue: ('a & 'b) -> string //│ where //│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var -//│ 'a <: Abs | App & {lhs: 'a & 'lhs & (Abs | ~#Abs), rhs: 'a & 'c} | Var -//│ 'lhs <: (Abs & {lhs: 'c, rhs: 'c} | ~Abs) & 'c -//│ 'c <: Abs & {lhs: 'c, rhs: 'c} | App & {lhs: 'lhs, rhs: 'c} | Var +//│ 'a <: Abs | App & {lhs: 'a & 'lhs & 'c & (Abs & {rhs: 'd} | ~#Abs), rhs: 'a & 'd & 'lhs & 'c & 'e & 'f} | Var +//│ 'f <: Abs & {rhs: 'f} | App & {lhs: 'f, rhs: 'f} | Var | ~Abs & ~App & ~Var +//│ 'd <: Abs & 'g | App & 'h | Var & 'i | 'j & ~#Abs & ~#App & ~#Var +//│ 'g <: 'lhs & 'c & 'e & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} | App & {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} & 'h | Var & {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} & 'i | {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} & 'j & ~#Abs & ~#App & ~#Var) +//│ 'i <: 'lhs & 'c & 'e & (Abs & {name: anything} & 'g | App & {name: anything} & 'h | Var | {name: anything} & 'j & ~#Abs & ~#App & ~#Var) +//│ 'j <: 'lhs & 'c & 'e & (Abs & 'g | App & 'h | ~#Abs & ~#App & ~#Var | Var & 'i) +//│ 'h <: {lhs: 'd, rhs: 'd} +//│ 'e <: Abs & {lhs: Var, rhs: 'e} | App & {lhs: 'e, rhs: 'e} | Var & {name: anything} +//│ 'lhs <: Abs & {lhs: 'c, rhs: 'c} | ~Abs +//│ 'c <: Abs & {lhs: 'c, rhs: 'c} | App & {lhs: 'lhs & 'c, rhs: 'c} | Var //│ = [Function: showStepByValue] showStepByValue(Var("x")) @@ -232,8 +520,7 @@ showStepByValue(App(Abs(Var("x"), Var("x")), Var("y"))) //│ res: string //│ = '(x y) => stuck' //│ res: string -//│ Runtime error: -//│ ReferenceError: subst is not defined +//│ = '((&x. x) y) => y' fun equalTerm(a, b) = if a is From d30b9c9b6e8564c1711527be3cf5c2e1be70cbab Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sun, 12 Mar 2023 16:53:27 +0800 Subject: [PATCH 181/498] Update test files due to previous commits --- shared/src/test/diff/ucs/InterleavedLet.mls | 13 ++++++------- shared/src/test/diff/ucs/TrivialIf.mls | 13 ++++--------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index fc4b42fc30..ad3e0fdf43 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -272,12 +272,11 @@ fun mapPartition(f, xs) = Cons(x, xs) and mapPartition(f, xs) is tmp0 and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ ╔══[ERROR] Cannot find the constructor `tmp0` in the context -//│ ║ l.272: Cons(x, xs) and mapPartition(f, xs) is tmp0 and res.fst is l and res.snd is r and f(x) is -//│ ╙── ^^^^ -//│ mapPartition: (anything, anything,) -> error -//│ Code generation encountered an error: -//│ if expression has not been desugared +//│ mapPartition: ('head -> ((Left with {leftValue: 'head0}) | (Right with {rightValue: 'head1})), 'a,) -> (Pair with {fst: (Cons with {head: 'head0, tail: 'tail}) | 'tail, snd: (Cons with {head: 'head1, tail: 'tail}) | 'tail}) +//│ where +//│ 'tail :> (Cons with {head: 0 | 1 | 2 | 3, tail: 'tail}) | Nil +//│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil +//│ = [Function: mapPartition1] // FIXME `b` should be bound here! fun mn(a) = @@ -288,7 +287,7 @@ fun mn(a) = Right(b) then "right-defined" None then "undefined" //│ ╔══[ERROR] identifier not found: b -//│ ║ l.287: let y = b + 1 +//│ ║ l.286: let y = b + 1 //│ ╙── ^ //│ mn: (None | Some & {value: Left | Right}) -> ("left-defined" | "right-defined" | "undefined") //│ Code generation encountered an error: diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index 7d01d545ef..d7b67ed6c0 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -61,18 +61,13 @@ fun f(x, y) = // FIXME if 42 is n then n + 1 -//│ ╔══[ERROR] Cannot find the constructor `n` in the context -//│ ║ l.63: if 42 is n then n + 1 -//│ ╙── ^ -//│ res: error +//│ res: int // FIXME -:e if 42 is n then n + 1 else 0 -//│ ╔══[ERROR] Cannot find the constructor `n` in the context -//│ ║ l.71: if 42 is n then n + 1 else 0 -//│ ╙── ^ -//│ res: error +//│ ╔══[WARNING] duplicated branch +//│ ╙── +//│ res: int if Some(42) is Some(n) then n + 1 From 2a7a5a7ee98fb3a6ae58b1ee36f92d4e5cc24abe Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sun, 12 Mar 2023 18:19:07 +0800 Subject: [PATCH 182/498] Add incomplete SLTC and built-in string comparison functions --- shared/src/main/scala/mlscript/Typer.scala | 5 + .../scala/mlscript/codegen/Polyfill.scala | 4 + .../main/scala/mlscript/codegen/Scope.scala | 4 + shared/src/test/diff/tapl/SimplyTyped.mls | 284 ++++++++++++++++++ 4 files changed, 297 insertions(+) create mode 100644 shared/src/test/diff/tapl/SimplyTyped.mls diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index b018e8ef26..aab7d0a318 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -156,6 +156,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val intBinOpTy = fun(singleTup(IntType), fun(singleTup(IntType), IntType)(noProv))(noProv) val numberBinOpTy = fun(singleTup(DecType), fun(singleTup(DecType), DecType)(noProv))(noProv) val numberBinPred = fun(singleTup(DecType), fun(singleTup(DecType), BoolType)(noProv))(noProv) + val stringBinPred = fun(singleTup(StrType), fun(singleTup(StrType), BoolType)(noProv))(noProv) Map( "true" -> TrueType, "false" -> FalseType, @@ -176,6 +177,10 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) "le" -> numberBinPred, "gt" -> numberBinPred, "ge" -> numberBinPred, + "slt" -> stringBinPred, + "sle" -> stringBinPred, + "sgt" -> stringBinPred, + "sge" -> stringBinPred, "concat" -> fun(singleTup(StrType), fun(singleTup(StrType), StrType)(noProv))(noProv), "eq" -> { val v = freshVar(noProv)(1) diff --git a/shared/src/main/scala/mlscript/codegen/Polyfill.scala b/shared/src/main/scala/mlscript/codegen/Polyfill.scala index 90238a76e4..7492622299 100644 --- a/shared/src/main/scala/mlscript/codegen/Polyfill.scala +++ b/shared/src/main/scala/mlscript/codegen/Polyfill.scala @@ -164,6 +164,10 @@ object Polyfill { buffer += BuiltinFunc("negate", makeUnaryFunc("-")) buffer += BuiltinFunc("eq", makeBinaryFunc("===")) buffer += BuiltinFunc("ne", makeBinaryFunc("!==")) + buffer += BuiltinFunc("sgt", makeBinaryFunc(">")) + buffer += BuiltinFunc("slt", makeBinaryFunc("<")) + buffer += BuiltinFunc("sge", makeBinaryFunc(">=")) + buffer += BuiltinFunc("sle", makeBinaryFunc("<=")) buffer.toList } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index cf00085ff6..2bf5675e93 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -40,6 +40,10 @@ class Scope(name: Str, enclosing: Opt[Scope]) { "not", "ne", "eq", + "sgt", + "slt", + "sge", + "sle", "toString", "negate" ) foreach { name => diff --git a/shared/src/test/diff/tapl/SimplyTyped.mls b/shared/src/test/diff/tapl/SimplyTyped.mls new file mode 100644 index 0000000000..13f07042eb --- /dev/null +++ b/shared/src/test/diff/tapl/SimplyTyped.mls @@ -0,0 +1,284 @@ +:NewParser + +:escape +// You can push debug messages to this magic array. +let Array: { from: anything => { push: anything => anything, join: string => string } } +let _Array = Array +let logs: { push: anything => anything, join: string => string } = _Array.from([]) +let debug: anything => anything = x => logs.push(x) +fun showDebug = logs.join("\n") +//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = +//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = [Function: Array] +//│ logs: {join: string -> string, push: anything -> anything} +//│ = [] +//│ debug: anything -> anything +//│ = [Function: debug] +//│ showDebug: string +//│ = [Function: showDebug] + +fun concat2(a, b) = concat(a)(b) +fun concat3(a, b, c) = concat2(a, concat2(b, c)) +fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) +fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) +fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) +fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) +fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) +fun par(a) = concat3("(", a, ")") +//│ concat2: (string, string,) -> string +//│ = [Function: concat2] +//│ concat3: (string, string, string,) -> string +//│ = [Function: concat3] +//│ concat4: (string, string, string, string,) -> string +//│ = [Function: concat4] +//│ concat5: (string, string, string, string, string,) -> string +//│ = [Function: concat5] +//│ concat6: (string, string, string, string, string, string,) -> string +//│ = [Function: concat6] +//│ concat7: (string, string, string, string, string, string, string,) -> string +//│ = [Function: concat7] +//│ concat8: (string, string, string, string, string, string, string, string,) -> string +//│ = [Function: concat8] +//│ par: string -> string +//│ = [Function: par] + +class Option +class Some(value): Option +class None(): Option +//│ Defined class Option +//│ Defined class Some +//│ Defined class None +//│ Option: () -> Option +//│ = [Function: Option1] +//│ Some: 'value -> (Some with {value: 'value}) +//│ = [Function: Some1] +//│ None: () -> None +//│ = [Function: None1] + +class Result +class Ok(value): Result +class Err(message): Result +//│ Defined class Result +//│ Defined class Ok +//│ Defined class Err +//│ Result: () -> Result +//│ = [Function: Result1] +//│ Ok: 'value -> (Ok with {value: 'value}) +//│ = [Function: Ok1] +//│ Err: 'message -> (Err with {message: 'message}) +//│ = [Function: Err1] + +class Type +class FunctionType(lhs, rhs): Type +class PrimitiveType(name): Type +//│ Defined class Type +//│ Defined class FunctionType +//│ Defined class PrimitiveType +//│ Type: () -> Type +//│ = [Function: Type1] +//│ FunctionType: ('lhs, 'rhs,) -> (FunctionType with {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: FunctionType1] +//│ PrimitiveType: 'name -> (PrimitiveType with {name: 'name}) +//│ = [Function: PrimitiveType1] + +// Helpers. +fun _f(lhs, rhs) = FunctionType(lhs, rhs) +fun _t(name) = PrimitiveType(name) +//│ _f: ('lhs, 'rhs,) -> (FunctionType with {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: _f] +//│ _t: 'name -> (PrimitiveType with {name: 'name}) +//│ = [Function: _t] + +class Term +class Lit(tag, ty): Term +class Var(name): Term +class Abs(lhs, lty, rhs): Term +class App(lhs, rhs): Term +// class App(lhs: Term, rhs: Term): Term +//│ Defined class Term +//│ Defined class Lit +//│ Defined class Var +//│ Defined class Abs +//│ Defined class App +//│ Term: () -> Term +//│ = [Function: Term1] +//│ Lit: ('tag, 'ty,) -> (Lit with {tag: 'tag, ty: 'ty}) +//│ = [Function: Lit1] +//│ Var: 'name -> (Var with {name: 'name}) +//│ = [Function: Var1] +//│ Abs: ('lhs, 'lty, 'rhs,) -> (Abs with {lhs: 'lhs, lty: 'lty, rhs: 'rhs}) +//│ = [Function: Abs1] +//│ App: ('lhs, 'rhs,) -> (App with {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: App1] + +class Assumption(name, ty) +//│ Defined class Assumption +//│ Assumption: ('name, 'ty,) -> (Assumption with {name: 'name, ty: 'ty}) +//│ = [Function: Assumption1] + +class Tree +class Node(key, value, left, right): Tree +class Empty(): Tree +//│ Defined class Tree +//│ Defined class Node +//│ Defined class Empty +//│ Tree: () -> Tree +//│ = [Function: Tree1] +//│ Node: ('key, 'value, 'left, 'right,) -> (Node with {key: 'key, left: 'left, right: 'right, value: 'value}) +//│ = [Function: Node1] +//│ Empty: () -> Empty +//│ = [Function: Empty1] + +fun empty = Empty() +fun insert(t, k, v) = + if t is + Node(k', _, l, r) and + slt(k)(k') then Node(k', v, insert(l, k, v), r) + sgt(k)(k') then Node(k', v, l, insert(r, k, v)) + _ then Node(k, v, l, r) + Empty then Node(k, v, empty, empty) +fun find(t, k) = + if t is + Node(k', v, l, r) and + slt(k)(k') then find(l, k) + sgt(k)(k') then find(r, k) + _ then Some(v) + Empty then None() +//│ empty: Empty +//│ = [Function: empty] +//│ insert: ('a, string & 'key, 'value,) -> 'right +//│ where +//│ 'right :> Node with {key: 'key, left: Empty | 'left | 'right, right: Empty | 'right0 | 'right, value: 'value} +//│ 'a <: Empty | Node & {key: string & 'key, left: 'a & 'left, right: 'a & 'right0} +//│ = [Function: insert] +//│ find: ('a, string,) -> ((Some with {value: 'value}) | None) +//│ where +//│ 'a <: Empty | (Node with {key: string, left: 'a, right: 'a, value: 'value}) +//│ = [Function: find] + +fun showType(ty) = + if ty is + FunctionType(PrimitiveType(name), rhs) then concat3(name, " -> ", showType(rhs)) + FunctionType(lhs, rhs) then concat4("(", showType(lhs), ") -> ", showType(rhs)) + PrimitiveType(name) then name +//│ showType: 'a -> string +//│ where +//│ 'a <: FunctionType & {lhs: 'a & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'a} | PrimitiveType & {name: string} +//│ = [Function: showType] + +showType(_t("int")) +showType(_f(_t("int"), _t("bool"))) +showType(_f(_f(_t("int"), _t("bool")), _t("bool"))) +showType(_f(_t("bool"), _f(_t("int"), _t("bool")))) +//│ res: string +//│ = 'int' +//│ res: string +//│ = 'int -> bool' +//│ res: string +//│ = '(int -> bool) -> bool' +//│ res: string +//│ = 'bool -> int -> bool' + +fun typeEqual(t1, t2) = + if + t1 is PrimitiveType(name1) and t2 is PrimitiveType(name2) then eq(name1)(name2) + t1 is FunctionType(lhs1, rhs1) and t2 is FunctionType(lhs2, rhs2) then + typeEqual(lhs1, lhs2) and typeEqual(rhs1, rhs2) + _ then false +//│ typeEqual: ('a, 'a,) -> bool +//│ where +//│ 'a <: FunctionType & {lhs: 'a, rhs: 'a} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ = [Function: typeEqual] + +fun showTerm(t) = + if t is + Lit(tag, _) then toString(tag) + Var(name) then toString(name) + Abs(lhs, ty, rhs) then concat6("&", showTerm(lhs), ": ", showType(ty), " => ", showTerm(rhs)) + App(Abs(lhs0, ty, lhs1), rhs) then + concat5("((", showTerm(Abs(lhs0, ty, rhs)), ") ", showTerm(rhs), ")") + App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) +//│ showTerm: 'a -> string +//│ where +//│ 'a <: Abs & {lhs: 'a, lty: 'b, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, lty: 'b} | ~#Abs), rhs: 'a} | Lit | Var +//│ 'b <: FunctionType & {lhs: 'b & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'b} | PrimitiveType & {name: string} +//│ = [Function: showTerm] + +showTerm(Var("x")) +showTerm(Abs(Var("x"), _t("int"), Var("y"))) +showTerm(App(Var("x"), Var("y"))) +showTerm(App(Abs(Var("x"), _t("int"), Var("y")), Var("z"))) +//│ res: string +//│ = 'x' +//│ res: string +//│ = '&x: int => y' +//│ res: string +//│ = '(x y)' +//│ res: string +//│ = '((&x: int => z) z)' + +fun typeTerm(t, ctx) = + if t is + Lit(_, ty) then Ok(ty) + Var(name) and find(ctx, name) is + Some(ty) then Ok(ty) + None then Err(concat3("unbound variable `", name, "`")) + Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is + Ok(resTy) then Ok(FunctionType(ty, resTy)) + Err(message) then Err(message) + App(lhs, rhs) and typeTerm(lhs, ctx) is + Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is + Ok(aTy) and + typeEqual(pTy, aTy) then Ok(resTy) + _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) + Err(message) then Err(message) + Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) + Err(message) then Err(message) +//│ typeTerm: ('a, 'right,) -> (Err & {message: string} | (Ok with {value: 'rhs | 'value})) +//│ where +//│ 'right <: (Empty | Node & {key: string, left: 'right, right: 'right}) & 'b +//│ 'b <: Empty | Node & {key: string, left: 'b, right: 'b, value: 'value0 & 'c & 'd & 'rhs} +//│ 'a <: Abs & {lhs: Var & {name: string}, lty: 'lhs & 'c & 'd & 'rhs & 'value0 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Lit & {ty: 'rhs & 'value0 & 'c & 'd} | Var & {name: string} +//│ 'rhs :> 'value +//│ <: 'value0 & 'c & 'd +//│ 'value0 <: (FunctionType & {lhs: 'c & 'd, rhs: 'value0} | PrimitiveType & {name: string}) & 'rhs +//│ 'value :> FunctionType with {lhs: 'lhs, rhs: 'rhs} +//│ 'd <: FunctionType & {lhs: 'd, rhs: 'd} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'c <: FunctionType & {lhs: 'c & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'c} | PrimitiveType & {name: string} +//│ = [Function: typeTerm] + +fun showTypeTerm(t, ctx) = + if typeTerm(t, ctx) is + Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) + Err(message) then concat2("Type error: ", message) +//│ showTypeTerm: ('a & 'b, 'c & 'd,) -> string +//│ where +//│ 'd <: Empty | Node & {key: string, left: 'right, right: 'right} +//│ 'right <: 'd & 'e +//│ 'e <: Empty | Node & {key: string, left: 'e, right: 'e, value: 'rhs} +//│ 'rhs <: 'f & 'g & (FunctionType & {lhs: 'f & 'g, rhs: 'rhs} | PrimitiveType & {name: string}) +//│ 'c <: Empty | Node & {key: string, left: 'c, right: 'c, value: 'rhs0} +//│ 'rhs0 <: 'g & 'f & (FunctionType & {lhs: 'f & 'g, rhs: 'rhs0} | PrimitiveType & {name: string}) +//│ 'b <: Abs & {lhs: Var & {name: string}, lty: 'rhs1 & 'f & 'g & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'b} | App & {lhs: 'b, rhs: 'b} | Lit & {ty: 'rhs1} | Var & {name: string} +//│ 'rhs1 <: 'f & 'g & (FunctionType & {lhs: 'f & 'g, rhs: 'rhs1} | PrimitiveType & {name: string}) +//│ 'g <: FunctionType & {lhs: 'g, rhs: 'g} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'a <: Abs & {lhs: 'a, lty: 'f, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, lty: 'f} | ~#Abs), rhs: 'a} | Lit | Var +//│ 'f <: FunctionType & {lhs: 'f & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'f} | PrimitiveType & {name: string} +//│ = [Function: showTypeTerm] + +showTypeTerm(Var("x"), empty) +showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), empty) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0.2", _t("float"))), insert(empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(empty, "f", _t("string"))) +//│ res: string +//│ = 'Type error: unbound variable `x`' +//│ res: string +//│ = '&x: int => x : int -> int' +//│ res: string +//│ = '(f 0) : int' +//│ res: string +//│ = 'Type error: expect the argument to be of type `int` but found `float`' +//│ res: string +//│ = 'Type error: cannot apply primitive type `string`' From 3d1018b31b47db653645d5678bf163aa260b71d2 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sun, 12 Mar 2023 21:09:04 +0800 Subject: [PATCH 183/498] Fix missing interleaved let bindings in nested branches --- .../main/scala/mlscript/ucs/Desugarer.scala | 8 +++--- shared/src/test/diff/mlscript/Repro.mls | 26 +++++++++++++++++++ shared/src/test/diff/ucs/InterleavedLet.mls | 4 ++- shared/src/test/diff/ucs/Lambda.mls | 14 +++------- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 4bda544f85..6cc14afa4b 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -455,11 +455,12 @@ class Desugarer extends TypeDefs { self: Typer => case S(alias) => acc case N => acc } - // Create a buffer for interleaved let bindings. - val interleavedLets = Buffer.empty[(Bool, Var, Term)] + // We need to make a snapshot because the sub-branches mutate the buffer. + // But these changes should not affect sibling branches. + val interleavedLetsSnapshot = interleavedLets.clone() // Iterate each match case. lines.foreach { - desugarMatchBranch(scrutinee, _, PartialTerm.Empty, conjunction)(interleavedLets) + desugarMatchBranch(scrutinee, _, PartialTerm.Empty, conjunction)(interleavedLetsSnapshot) } // For example: "if x == 0 and y is \n ..." case IfOpApp(testPart, Var("and"), consequent) => @@ -479,6 +480,7 @@ class Desugarer extends TypeDefs { self: Typer => lines.foreach { case L(subBody) => desugarIfBody(subBody, expr, acc) case R(NuFunDef(S(isRec), nameVar, _, L(term))) => + printlnUCS(s"Found interleaved binding ${nameVar.name}") interleavedLets += ((isRec, nameVar, term)) case R(_) => throw new Error("unexpected statements at desugarIfBody") diff --git a/shared/src/test/diff/mlscript/Repro.mls b/shared/src/test/diff/mlscript/Repro.mls index e69de29bb2..18d4750181 100644 --- a/shared/src/test/diff/mlscript/Repro.mls +++ b/shared/src/test/diff/mlscript/Repro.mls @@ -0,0 +1,26 @@ +:NewParser + +class A(a) +//│ Defined class A +//│ A: 'a -> (A with {a: 'a}) +//│ = [Function: A1] + +fun f(x) = x +fun g(x, y) = x +fun h(x, y, z) = x +//│ f: 'a -> 'a +//│ = [Function: f] +//│ g: ('a, anything,) -> 'a +//│ = [Function: g] +//│ h: ('a, anything, anything,) -> 'a +//│ = [Function: h] + +fun findFreshName(x, y) = + if + f(x) == 1 and + let u = g(x, 0) + h(u, u + 1, y) is + A(a) then a + _ then h(x, 0, y) +//│ findFreshName: (int & 'a, anything,) -> 'a +//│ = [Function: findFreshName] diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index ad3e0fdf43..ccdd9ab853 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -279,6 +279,8 @@ fun mapPartition(f, xs) = //│ = [Function: mapPartition1] // FIXME `b` should be bound here! +// The example is actually wrong. `b` belongs to the consequent of `Left(b)`. +// `let y = ...` has no access to `b` because it is not in scope. fun mn(a) = if a is Some(x) and x is @@ -287,7 +289,7 @@ fun mn(a) = Right(b) then "right-defined" None then "undefined" //│ ╔══[ERROR] identifier not found: b -//│ ║ l.286: let y = b + 1 +//│ ║ l.288: let y = b + 1 //│ ╙── ^ //│ mn: (None | Some & {value: Left | Right}) -> ("left-defined" | "right-defined" | "undefined") //│ Code generation encountered an error: diff --git a/shared/src/test/diff/ucs/Lambda.mls b/shared/src/test/diff/ucs/Lambda.mls index cf5dc872d4..1ba2a25322 100644 --- a/shared/src/test/diff/ucs/Lambda.mls +++ b/shared/src/test/diff/ucs/Lambda.mls @@ -368,18 +368,12 @@ fun tryAppendDigits(name, index, freeNames) = //│ = [Function: tryAppendDigits] // Note: some weird behavior here... Just try the commented code. -// fun findFreshName(name, freeNames) = -// if -// stringLength(name) == 1 and -// let charCode = stringCharCodeAt(name, 0) -// tryNextAlphabet(charCode, charCode + 1, freeNames) is -// Some(newName) then newName -// _ then tryAppendDigits(name, 0, freeNames) fun findFreshName(name, freeNames) = if stringLength(name) == 1 and let charCode = stringCharCodeAt(name, 0) - tryNextAlphabet(charCode, charCode + 1, freeNames) is Some(newName) then newName + tryNextAlphabet(charCode, charCode + 1, freeNames) is + Some(newName) then newName _ then tryAppendDigits(name, 0, freeNames) //│ findFreshName: (string, 'a,) -> string //│ where @@ -405,10 +399,10 @@ fun subst(t, n, v) = App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t //│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.406: _ then t +//│ ║ l.400: _ then t //│ ║ ^ //│ ╟── The first else branch was declared here. -//│ ║ l.404: _ then Abs(Var(name), subst(body, n, v)) +//│ ║ l.398: _ then Abs(Var(name), subst(body, n, v)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ subst: ('a, anything, 'a & 'b & 'rhs & 'c,) -> 'rhs //│ where From 67513c100c1bcea5b34898f4f9ecc8ec777020b1 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sun, 12 Mar 2023 22:12:29 +0800 Subject: [PATCH 184/498] Fix unhygienically extracting positional class parameters --- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/ucs/Desugarer.scala | 108 ++++++++++++++++-- .../main/scala/mlscript/ucs/MutCaseOf.scala | 41 ------- .../main/scala/mlscript/ucs/Scrutinee.scala | 2 +- .../src/main/scala/mlscript/ucs/helpers.scala | 17 --- shared/src/test/diff/mlscript/Repro.mls | 26 ----- shared/src/test/diff/ucs/NestedPattern.mls | 13 +++ 7 files changed, 111 insertions(+), 98 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index aab7d0a318..713f4c3d90 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -745,7 +745,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) println("The mutable CaseOf tree") MutCaseOf.show(caseTree).foreach(println(_)) checkExhaustive(caseTree, N)(summarizePatterns(caseTree), ctx, raise) - val desugared = MutCaseOf.toTerm(caseTree) + val desugared = constructTerm(caseTree) println(s"Desugared term: ${desugared.print(false)}") iff.desugaredTerm = S(desugared) typeTerm(desugared) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 6cc14afa4b..9c364a0f14 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -43,7 +43,7 @@ class Desugarer extends TypeDefs { self: Typer => * @param positionals the corresponding field names of each parameter * @param aliasMap a map used to cache each the alias of each field * @param matchRootLoc the location to the root of the match - * @return a mapping from each field to their var + * @return two mappings: one is (variable -> sub-pattern), the other is (positional name -> variable) */ private def desugarPositionals (scrutinee: Scrutinee, params: IterableOnce[Term], positionals: Ls[Str]) @@ -53,7 +53,7 @@ class Desugarer extends TypeDefs { self: Typer => // `x is A(_)`: ignore this binding case (Var("_"), _) => N // `x is A(value)`: generate bindings directly - case (name: Var, fieldName) => S(fieldName -> name) + case (nameVar: Var, fieldName) => S(fieldName -> nameVar) // `x is B(A(x))`: generate a temporary name // use the name in the binding, and destruct sub-patterns case (pattern: Term, fieldName) => @@ -65,7 +65,7 @@ class Desugarer extends TypeDefs { self: Typer => subPatterns += ((alias, pattern)) S(fieldName -> alias) }.toList - subPatterns.toList -> bindings + (subPatterns.toList, bindings) } /** @@ -99,18 +99,26 @@ class Desugarer extends TypeDefs { self: Typer => traceUCS(s"Making a scrutinee for `$term`") { term match { case _: SimpleTerm => Scrutinee(N, term)(matchRootLoc) - case _ => - val localName = if (localizedScrutineeMap.containsKey(term)) { - localizedScrutineeMap.get(term) - } else { - val v = Var(freshName).desugaredFrom(term) - localizedScrutineeMap.put(term, v) - v - } - Scrutinee(S(localName), term)(matchRootLoc) + case _ => Scrutinee(S(makeLocalizedName(term)), term)(matchRootLoc) } }() + /** + * Create a fresh name for scrutinee to be localized. + * + * @param scrutinee the term of the scrutinee + * @param ctx the context + * @return the fresh name, as `Var` + */ + private def makeLocalizedName(scrutinee: Term)(implicit ctx: Ctx): Var = + if (localizedScrutineeMap.containsKey(scrutinee)) { + localizedScrutineeMap.get(scrutinee) + } else { + val v = Var(freshName).desugaredFrom(scrutinee) + localizedScrutineeMap.put(scrutinee, v) + v + } + /** * Destruct nested patterns to a list of simple condition with bindings. * @@ -622,4 +630,80 @@ class Desugarer extends TypeDefs { self: Typer => } Map.from(m.iterator.map { case (key, patternMap) => key -> Map.from(patternMap) }) } + + protected def constructTerm(m: MutCaseOf)(implicit ctx: Ctx): Term = { + def rec(m: MutCaseOf)(implicit defs: Set[Var]): Term = m match { + case Consequent(term) => term + case Match(scrutinee, branches, wildcard) => + def rec2(xs: Ls[MutCase]): CaseBranches = + xs match { + case MutCase(className -> fields, cases) :: next => + // TODO: expand bindings here + val consequent = rec(cases)(defs ++ fields.iterator.map(_._2)) + Case(className, mkLetFromFields(scrutinee, fields.toList, consequent), rec2(next)) + case Nil => + wildcard.fold[CaseBranches](NoCases) { rec(_) |> Wildcard } + } + val cases = rec2(branches.toList) + val resultTerm = scrutinee.local match { + case N => CaseOf(scrutinee.term, cases) + case S(aliasVar) => Let(false, aliasVar, scrutinee.term, CaseOf(aliasVar, cases)) + } + // Collect let bindings from case branches. + val bindings = branches.iterator.flatMap(_.consequent.getBindings).toList + mkBindings(bindings, resultTerm, defs) + case MissingCase => + import Message.MessageContext + throw new DesugaringException(msg"missing a default branch", N) + case IfThenElse(condition, whenTrue, whenFalse) => + val falseBody = mkBindings(whenFalse.getBindings.toList, rec(whenFalse)(defs ++ whenFalse.getBindings.iterator.map(_._2)), defs) + val trueBody = mkBindings(whenTrue.getBindings.toList, rec(whenTrue)(defs ++ whenTrue.getBindings.iterator.map(_._2)), defs) + val falseBranch = Wildcard(falseBody) + val trueBranch = Case(Var("true"), trueBody, falseBranch) + CaseOf(condition, trueBranch) + } + val term = rec(m)(Set.from(m.getBindings.iterator.map(_._2))) + mkBindings(m.getBindings.toList, term, Set.empty) + } + + /** + * Generate a chain of field selection to the given scrutinee. + * + * @param scrutinee the pattern matching scrutinee + * @param fields a list of pairs from field names to binding names + * @param body the final body + */ + private def mkLetFromFields(scrutinee: Scrutinee, fields: Ls[Str -> Var], body: Term)(implicit ctx: Ctx): Term = { + def rec(scrutineeReference: SimpleTerm, fields: Ls[Str -> Var]): Term = + fields match { + case Nil => body + case (field -> (aliasVar @ Var(alias))) :: tail => + scrutinee.term match { + // Check if the scrutinee is a `Var` and its name conflicts with + // one of the positionals. If so, we create an alias and extract + // fields by selecting the alias. + case Var(scrutineeName) if alias == scrutineeName => + val scrutineeAlias = Var(freshName) + Let( + false, + scrutineeAlias, + scrutinee.reference, + Let( + false, + aliasVar, + Sel(scrutineeAlias, Var(field)).desugaredFrom(scrutinee.term), + rec(scrutineeAlias, tail) + ) + ) + case _ => + Let( + false, + aliasVar, + Sel(scrutineeReference, Var(field)).desugaredFrom(scrutinee.term), + rec(scrutineeReference, tail) + ) + } + } + rec(scrutinee.reference, fields) + } } diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index 885532cef0..f7273c38e0 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -49,18 +49,12 @@ sealed abstract class MutCaseOf extends WithBindings { def mergeDefault (bindings: Ls[(Bool, Var, Term)], default: Term) (implicit raise: Diagnostic => Unit): Unit - def toTerm(defs: Set[Var]): Term // TODO: Make it immutable. var locations: Ls[Loc] = Nil } object MutCaseOf { - def toTerm(t: MutCaseOf): Term = { - val term = t.toTerm(Set.from(t.getBindings.iterator.map(_._2))) - mkBindings(t.getBindings.toList, term, Set.empty) - } - def showScrutinee(scrutinee: Scrutinee): Str = s"«${scrutinee.term}»" + (scrutinee.local match { case N => "" @@ -201,14 +195,6 @@ object MutCaseOf { case _: IfThenElse | _: Match => whenFalse.mergeDefault(bindings, default) } } - - def toTerm(defs: Set[Var]): Term = { - val falseBody = mkBindings(whenFalse.getBindings.toList, whenFalse.toTerm(defs ++ whenFalse.getBindings.iterator.map(_._2)), defs) - val trueBody = mkBindings(whenTrue.getBindings.toList, whenTrue.toTerm(defs ++ whenTrue.getBindings.iterator.map(_._2)), defs) - val falseBranch = Wildcard(falseBody) - val trueBranch = Case(Var("true"), trueBody, falseBranch) - CaseOf(condition, trueBranch) - } } final case class Match( scrutinee: Scrutinee, @@ -282,26 +268,6 @@ object MutCaseOf { case S(consequent) => consequent.mergeDefault(bindings, default) } } - - def toTerm(defs: Set[Var]): Term = { - def rec(xs: Ls[MutCase]): CaseBranches = - xs match { - case MutCase(className -> fields, cases) :: next => - // TODO: expand bindings here - val consequent = cases.toTerm(defs ++ fields.iterator.map(_._2)) - Case(className, mkLetFromFields(scrutinee, fields.toList, consequent), rec(next)) - case Nil => - wildcard.fold[CaseBranches](NoCases)(_.toTerm(defs) |> Wildcard) - } - val cases = rec(branches.toList) - val resultTerm = scrutinee.local match { - case N => CaseOf(scrutinee.term, cases) - case S(aliasVar) => Let(false, aliasVar, scrutinee.term, CaseOf(aliasVar, cases)) - } - // Collect let bindings from case branches. - val bindings = branches.iterator.flatMap(_.consequent.getBindings).toList - mkBindings(bindings, resultTerm, defs) - } } final case class Consequent(term: Term) extends MutCaseOf { def describe: Str = s"Consequent($term)" @@ -310,8 +276,6 @@ object MutCaseOf { raise(WarningReport(Message.fromStr("duplicated branch") -> N :: Nil)) def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Unit = () - - def toTerm(defs: Set[Var]): Term = term } final case object MissingCase extends MutCaseOf { def describe: Str = "MissingCase" @@ -320,11 +284,6 @@ object MutCaseOf { lastWords("`MissingCase` is a placeholder and cannot be merged") def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Unit = () - - def toTerm(defs: Set[Var]): Term = { - import Message.MessageContext - throw new DesugaringException(msg"missing a default branch", N) - } } private def buildFirst(conjunction: Conjunction, term: Term): MutCaseOf = { diff --git a/shared/src/main/scala/mlscript/ucs/Scrutinee.scala b/shared/src/main/scala/mlscript/ucs/Scrutinee.scala index 48a447ee51..13a5d5546f 100644 --- a/shared/src/main/scala/mlscript/ucs/Scrutinee.scala +++ b/shared/src/main/scala/mlscript/ucs/Scrutinee.scala @@ -6,7 +6,7 @@ import mlscript.utils.shorthands._ // The point is to remember where the scrutinee comes from. // Is it from nested patterns? Or is it from a `IfBody`? -final case class Scrutinee(local: Opt[Var], term: Term)(val matchRootLoc: Opt[Loc]) { +final case class Scrutinee(var local: Opt[Var], term: Term)(val matchRootLoc: Opt[Loc]) { def reference: SimpleTerm = local.getOrElse(term match { case term: SimpleTerm => term case _ => lastWords("`term` must be a `SimpleTerm` when `local` is empty") diff --git a/shared/src/main/scala/mlscript/ucs/helpers.scala b/shared/src/main/scala/mlscript/ucs/helpers.scala index 0b20c070fb..8248a30a4c 100644 --- a/shared/src/main/scala/mlscript/ucs/helpers.scala +++ b/shared/src/main/scala/mlscript/ucs/helpers.scala @@ -97,21 +97,4 @@ object helpers { } rec(bindings, defs) } - - /** - * Generate a chain of field selection to the given scrutinee. - * - * @param scrutinee the pattern matching scrutinee - * @param fields a list of pairs from field names to binding names - * @param body the final body - */ - def mkLetFromFields(scrutinee: Scrutinee, fields: Ls[Str -> Var], body: Term): Term = { - def rec(fields: Ls[Str -> Var]): Term = - fields match { - case Nil => body - case (field -> (aliasVar @ Var(alias))) :: tail => - Let(false, aliasVar, Sel(scrutinee.reference, Var(field)).desugaredFrom(scrutinee.term), rec(tail)) - } - rec(fields) - } } diff --git a/shared/src/test/diff/mlscript/Repro.mls b/shared/src/test/diff/mlscript/Repro.mls index 18d4750181..e69de29bb2 100644 --- a/shared/src/test/diff/mlscript/Repro.mls +++ b/shared/src/test/diff/mlscript/Repro.mls @@ -1,26 +0,0 @@ -:NewParser - -class A(a) -//│ Defined class A -//│ A: 'a -> (A with {a: 'a}) -//│ = [Function: A1] - -fun f(x) = x -fun g(x, y) = x -fun h(x, y, z) = x -//│ f: 'a -> 'a -//│ = [Function: f] -//│ g: ('a, anything,) -> 'a -//│ = [Function: g] -//│ h: ('a, anything, anything,) -> 'a -//│ = [Function: h] - -fun findFreshName(x, y) = - if - f(x) == 1 and - let u = g(x, 0) - h(u, u + 1, y) is - A(a) then a - _ then h(x, 0, y) -//│ findFreshName: (int & 'a, anything,) -> 'a -//│ = [Function: findFreshName] diff --git a/shared/src/test/diff/ucs/NestedPattern.mls b/shared/src/test/diff/ucs/NestedPattern.mls index f135df5590..a6569c601e 100644 --- a/shared/src/test/diff/ucs/NestedPattern.mls +++ b/shared/src/test/diff/ucs/NestedPattern.mls @@ -68,3 +68,16 @@ fun f(p) = //│ ╙── //│ f: (None | Some & {value: error}) -> (0 | error) +class Union(a, b) +//│ Defined class Union +//│ Union: ('a, 'b,) -> (Union with {a: 'a, b: 'b}) + +// Name conflict between the scrutinee and the positionals. +// Desugar result: let tmp13 = x in case tmp13 of { Union => let x = (tmp13).a in let y = (tmp13).b in x } +fun hmm(x) = + if x is Union(x, y) then x +//│ hmm: (Union with {a: 'a}) -> 'a + +hmm(Union(1, 2)) +//│ res: 1 + From 23b6af35750b298fdccf287fe5422ce406bba8b6 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 13 Mar 2023 09:35:56 +0800 Subject: [PATCH 185/498] Fix web demo --- js/src/main/scala/Main.scala | 3 +-- shared/src/test/diff/ecoop23/Intro.mls | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index 64803239ba..06676fe6cb 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -134,14 +134,13 @@ object Main { val vars: Map[Str, typer.SimpleType] = Map.empty val tpd = typer.typeTypingUnit(tu, allowPure = true)(ctx.nest, raise, vars) - val comp = tpd.force()(raise) object SimplifyPipeline extends typer.SimplifyPipeline { def debugOutput(msg: => Str): Unit = // if (mode.dbgSimplif) output(msg) println(msg) } - val sim = SimplifyPipeline(comp, all = false)(ctx) + val sim = SimplifyPipeline(tpd, all = false)(ctx) val exp = typer.expandType(sim)(ctx) diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index 8e189b3514..f94c55b600 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -2,6 +2,8 @@ :NewDefs +// * Examples from paper intro + class Some(value: A) module None From e4dbbf751d9dffedcce302fb9ed432f8ea3a2574 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Mon, 13 Mar 2023 13:06:32 +0800 Subject: [PATCH 186/498] Use `:NewDefs` in lambda calculus test cases --- .../main/scala/mlscript/ucs/Desugarer.scala | 3 +- shared/src/test/diff/nu/Andong.mls | 4 +- shared/src/test/diff/nu/BadUCS.mls | 19 +- shared/src/test/diff/tapl/SimplyTyped.mls | 310 ++++----- shared/src/test/diff/ucs/ElseIf.mls | 35 +- shared/src/test/diff/ucs/InterleavedLet.mls | 10 +- shared/src/test/diff/ucs/Lambda.mls | 639 ++++++++---------- shared/src/test/diff/ucs/NestedBranches.mls | 246 ++----- shared/src/test/diff/ucs/NestedPattern.mls | 4 +- .../src/test/diff/ucs/PlainConditionals.mls | 24 +- 10 files changed, 531 insertions(+), 763 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 5bf66d5dcf..5191c13b53 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -614,7 +614,7 @@ class Desugarer extends TypeDefs { self: Typer => case IfThenElse(_, whenTrue, whenFalse) => rec(whenTrue) rec(whenFalse) - case Match(scrutinee, branches, _) => + case Match(scrutinee, branches, default) => val key = getScurtineeKey(scrutinee) branches.foreach { mutCase => val patternMap = m.getOrElseUpdate( key, MutMap.empty) @@ -623,6 +623,7 @@ class Desugarer extends TypeDefs { self: Typer => } rec(mutCase.consequent) } + default.foreach(rec) } finally indent -= 1 } rec(t) diff --git a/shared/src/test/diff/nu/Andong.mls b/shared/src/test/diff/nu/Andong.mls index ed6471fc81..0602b7a8a0 100644 --- a/shared/src/test/diff/nu/Andong.mls +++ b/shared/src/test/diff/nu/Andong.mls @@ -5,11 +5,9 @@ class Union(a: Region, b: Region) //│ class Union[Region](a: Region, b: Region) -// * [FIXME:UCS] unhygienically desugars to: -// | | | | Desugared term: case x of { Union => let x = (x).a in let y = (x).b in x } fun hmm(x) = if x is Union(x, y) then x -//│ fun hmm: forall 'a. Union[{b: anything} & 'a] -> 'a +//│ fun hmm: forall 'a. Union['a] -> 'a fun hmm(x) = if x is Union(z, y) then x diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index 7570b54bba..6423965afd 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -77,15 +77,8 @@ fun foo(x) = if x is M() then 0 //│ if expression was not desugared -:e -:ge fun foo0(x, y) = if x is y then 0 -//│ ╔══[ERROR] Cannot find constructor `y` in scope -//│ ║ l.82: fun foo0(x, y) = if x is y then 0 -//│ ╙── ^ -//│ fun foo0: (anything, anything,) -> error -//│ Code generation encountered an error: -//│ if expression was not desugared +//│ fun foo0: (anything, anything,) -> 0 fun foo = 0 @@ -95,7 +88,7 @@ fun foo = 0 :ge fun foo0(x) = if x is foo() then 0 //│ ╔══[ERROR] Illegal pattern `foo` -//│ ║ l.96: fun foo0(x) = if x is foo() then 0 +//│ ║ l.89: fun foo0(x) = if x is foo() then 0 //│ ╙── ^^^ //│ fun foo0: anything -> error //│ Code generation encountered an error: @@ -105,11 +98,11 @@ fun foo0(x) = if x is foo() then 0 :ge fun foo(x) = if x is foo() then 0 //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.106: fun foo(x) = if x is foo() then 0 -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.99: fun foo(x) = if x is foo() then 0 +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Illegal pattern `foo` -//│ ║ l.106: fun foo(x) = if x is foo() then 0 -//│ ╙── ^^^ +//│ ║ l.99: fun foo(x) = if x is foo() then 0 +//│ ╙── ^^^ //│ fun foo: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared diff --git a/shared/src/test/diff/tapl/SimplyTyped.mls b/shared/src/test/diff/tapl/SimplyTyped.mls index 13f07042eb..27d360521b 100644 --- a/shared/src/test/diff/tapl/SimplyTyped.mls +++ b/shared/src/test/diff/tapl/SimplyTyped.mls @@ -1,4 +1,5 @@ :NewParser +:NewDefs :escape // You can push debug messages to this magic array. @@ -7,16 +8,19 @@ let _Array = Array let logs: { push: anything => anything, join: string => string } = _Array.from([]) let debug: anything => anything = x => logs.push(x) fun showDebug = logs.join("\n") -//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = -//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = [Function: Array] -//│ logs: {join: string -> string, push: anything -> anything} -//│ = [] -//│ debug: anything -> anything -//│ = [Function: debug] -//│ showDebug: string -//│ = [Function: showDebug] +//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let logs: {join: string -> string, push: anything -> anything} +//│ let debug: anything -> anything +//│ fun showDebug: string +//│ Array +//│ = +//│ _Array +//│ = [Function: Array] +//│ logs +//│ = [] +//│ debug +//│ = [Function: debug] fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) @@ -26,159 +30,101 @@ fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) fun par(a) = concat3("(", a, ")") -//│ concat2: (string, string,) -> string -//│ = [Function: concat2] -//│ concat3: (string, string, string,) -> string -//│ = [Function: concat3] -//│ concat4: (string, string, string, string,) -> string -//│ = [Function: concat4] -//│ concat5: (string, string, string, string, string,) -> string -//│ = [Function: concat5] -//│ concat6: (string, string, string, string, string, string,) -> string -//│ = [Function: concat6] -//│ concat7: (string, string, string, string, string, string, string,) -> string -//│ = [Function: concat7] -//│ concat8: (string, string, string, string, string, string, string, string,) -> string -//│ = [Function: concat8] -//│ par: string -> string -//│ = [Function: par] - -class Option -class Some(value): Option -class None(): Option -//│ Defined class Option -//│ Defined class Some -//│ Defined class None -//│ Option: () -> Option -//│ = [Function: Option1] -//│ Some: 'value -> (Some with {value: 'value}) -//│ = [Function: Some1] -//│ None: () -> None -//│ = [Function: None1] - -class Result -class Ok(value): Result -class Err(message): Result -//│ Defined class Result -//│ Defined class Ok -//│ Defined class Err -//│ Result: () -> Result -//│ = [Function: Result1] -//│ Ok: 'value -> (Ok with {value: 'value}) -//│ = [Function: Ok1] -//│ Err: 'message -> (Err with {message: 'message}) -//│ = [Function: Err1] - -class Type -class FunctionType(lhs, rhs): Type -class PrimitiveType(name): Type -//│ Defined class Type -//│ Defined class FunctionType -//│ Defined class PrimitiveType -//│ Type: () -> Type -//│ = [Function: Type1] -//│ FunctionType: ('lhs, 'rhs,) -> (FunctionType with {lhs: 'lhs, rhs: 'rhs}) -//│ = [Function: FunctionType1] -//│ PrimitiveType: 'name -> (PrimitiveType with {name: 'name}) -//│ = [Function: PrimitiveType1] +//│ fun concat2: (string, string,) -> string +//│ fun concat3: (string, string, string,) -> string +//│ fun concat4: (string, string, string, string,) -> string +//│ fun concat5: (string, string, string, string, string,) -> string +//│ fun concat6: (string, string, string, string, string, string,) -> string +//│ fun concat7: (string, string, string, string, string, string, string,) -> string +//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string +//│ fun par: string -> string + +type Option[A] = Some[A] | None +class Some[A](value: A) +module None +//│ type Option[A] = None | Some[A] +//│ class Some[A](value: A) +//│ module None() + +type Result[A, B] = Ok[A] | Err[B] +class Ok[A](value: A) +class Err[A](message: A) +//│ type Result[A, B] = Err[B] | Ok[A] +//│ class Ok[A](value: A) +//│ class Err[A](message: A) + +type Type = FunctionType | PrimitiveType +class FunctionType(lhs: Type, rhs: Type) +class PrimitiveType(name: string) +//│ type Type = FunctionType | PrimitiveType +//│ class FunctionType(lhs: Type, rhs: Type) +//│ class PrimitiveType(name: string) // Helpers. fun _f(lhs, rhs) = FunctionType(lhs, rhs) fun _t(name) = PrimitiveType(name) -//│ _f: ('lhs, 'rhs,) -> (FunctionType with {lhs: 'lhs, rhs: 'rhs}) -//│ = [Function: _f] -//│ _t: 'name -> (PrimitiveType with {name: 'name}) -//│ = [Function: _t] - -class Term -class Lit(tag, ty): Term -class Var(name): Term -class Abs(lhs, lty, rhs): Term -class App(lhs, rhs): Term +//│ fun _f: (Type, Type,) -> FunctionType +//│ fun _t: string -> PrimitiveType + +type Term = Lit | Var | Abs | App +class Lit(tag: string, ty: Type) +class Var(name: string) +class Abs(lhs: Var, lty: Type, rhs: Term) +class App(lhs: Term, rhs: Term) // class App(lhs: Term, rhs: Term): Term -//│ Defined class Term -//│ Defined class Lit -//│ Defined class Var -//│ Defined class Abs -//│ Defined class App -//│ Term: () -> Term -//│ = [Function: Term1] -//│ Lit: ('tag, 'ty,) -> (Lit with {tag: 'tag, ty: 'ty}) -//│ = [Function: Lit1] -//│ Var: 'name -> (Var with {name: 'name}) -//│ = [Function: Var1] -//│ Abs: ('lhs, 'lty, 'rhs,) -> (Abs with {lhs: 'lhs, lty: 'lty, rhs: 'rhs}) -//│ = [Function: Abs1] -//│ App: ('lhs, 'rhs,) -> (App with {lhs: 'lhs, rhs: 'rhs}) -//│ = [Function: App1] +//│ type Term = Abs | App | Lit | Var +//│ class Lit(tag: string, ty: Type) +//│ class Var(name: string) +//│ class Abs(lhs: Var, lty: Type, rhs: Term) +//│ class App(lhs: Term, rhs: Term) + +class Assumption(name: string, ty: Type) +//│ class Assumption(name: string, ty: Type) + +type Tree[A] = Node[A] | Empty +class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) +module Empty +//│ type Tree[A] = Empty | Node[A] +//│ class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) +//│ module Empty() -class Assumption(name, ty) -//│ Defined class Assumption -//│ Assumption: ('name, 'ty,) -> (Assumption with {name: 'name, ty: 'ty}) -//│ = [Function: Assumption1] - -class Tree -class Node(key, value, left, right): Tree -class Empty(): Tree -//│ Defined class Tree -//│ Defined class Node -//│ Defined class Empty -//│ Tree: () -> Tree -//│ = [Function: Tree1] -//│ Node: ('key, 'value, 'left, 'right,) -> (Node with {key: 'key, left: 'left, right: 'right, value: 'value}) -//│ = [Function: Node1] -//│ Empty: () -> Empty -//│ = [Function: Empty1] - -fun empty = Empty() fun insert(t, k, v) = if t is Node(k', _, l, r) and slt(k)(k') then Node(k', v, insert(l, k, v), r) sgt(k)(k') then Node(k', v, l, insert(r, k, v)) _ then Node(k, v, l, r) - Empty then Node(k, v, empty, empty) + Empty then Node(k, v, Empty, Empty) fun find(t, k) = if t is Node(k', v, l, r) and slt(k)(k') then find(l, k) sgt(k)(k') then find(r, k) _ then Some(v) - Empty then None() -//│ empty: Empty -//│ = [Function: empty] -//│ insert: ('a, string & 'key, 'value,) -> 'right -//│ where -//│ 'right :> Node with {key: 'key, left: Empty | 'left | 'right, right: Empty | 'right0 | 'right, value: 'value} -//│ 'a <: Empty | Node & {key: string & 'key, left: 'a & 'left, right: 'a & 'right0} -//│ = [Function: insert] -//│ find: ('a, string,) -> ((Some with {value: 'value}) | None) -//│ where -//│ 'a <: Empty | (Node with {key: string, left: 'a, right: 'a, value: 'value}) -//│ = [Function: find] + Empty then None +//│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] +//│ fun find: forall 'A0. (Empty | Node['A0], string,) -> (None | Some['A0]) fun showType(ty) = if ty is FunctionType(PrimitiveType(name), rhs) then concat3(name, " -> ", showType(rhs)) FunctionType(lhs, rhs) then concat4("(", showType(lhs), ") -> ", showType(rhs)) PrimitiveType(name) then name -//│ showType: 'a -> string -//│ where -//│ 'a <: FunctionType & {lhs: 'a & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'a} | PrimitiveType & {name: string} -//│ = [Function: showType] +//│ fun showType: (FunctionType | PrimitiveType) -> string showType(_t("int")) showType(_f(_t("int"), _t("bool"))) showType(_f(_f(_t("int"), _t("bool")), _t("bool"))) showType(_f(_t("bool"), _f(_t("int"), _t("bool")))) -//│ res: string -//│ = 'int' -//│ res: string -//│ = 'int -> bool' -//│ res: string -//│ = '(int -> bool) -> bool' -//│ res: string -//│ = 'bool -> int -> bool' +//│ string +//│ res +//│ = 'int' +//│ res +//│ = 'int -> bool' +//│ res +//│ = '(int -> bool) -> bool' +//│ res +//│ = 'bool -> int -> bool' fun typeEqual(t1, t2) = if @@ -186,10 +132,7 @@ fun typeEqual(t1, t2) = t1 is FunctionType(lhs1, rhs1) and t2 is FunctionType(lhs2, rhs2) then typeEqual(lhs1, lhs2) and typeEqual(rhs1, rhs2) _ then false -//│ typeEqual: ('a, 'a,) -> bool -//│ where -//│ 'a <: FunctionType & {lhs: 'a, rhs: 'a} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ = [Function: typeEqual] +//│ fun typeEqual: (anything, anything,) -> bool fun showTerm(t) = if t is @@ -199,26 +142,24 @@ fun showTerm(t) = App(Abs(lhs0, ty, lhs1), rhs) then concat5("((", showTerm(Abs(lhs0, ty, rhs)), ") ", showTerm(rhs), ")") App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) -//│ showTerm: 'a -> string -//│ where -//│ 'a <: Abs & {lhs: 'a, lty: 'b, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, lty: 'b} | ~#Abs), rhs: 'a} | Lit | Var -//│ 'b <: FunctionType & {lhs: 'b & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'b} | PrimitiveType & {name: string} -//│ = [Function: showTerm] +//│ fun showTerm: (Abs | App | Lit | Var) -> string showTerm(Var("x")) showTerm(Abs(Var("x"), _t("int"), Var("y"))) showTerm(App(Var("x"), Var("y"))) showTerm(App(Abs(Var("x"), _t("int"), Var("y")), Var("z"))) -//│ res: string -//│ = 'x' -//│ res: string -//│ = '&x: int => y' -//│ res: string -//│ = '(x y)' -//│ res: string -//│ = '((&x: int => z) z)' - -fun typeTerm(t, ctx) = +//│ string +//│ res +//│ = 'x' +//│ res +//│ = '&x: int => y' +//│ res +//│ = '(x y)' +//│ res +//│ = '((&x: int => z) z)' + +// Removing the return type annotation causes stack overflow. +fun typeTerm(t, ctx): Result[Type, string] = if t is Lit(_, ty) then Ok(ty) Var(name) and find(ctx, name) is @@ -231,54 +172,35 @@ fun typeTerm(t, ctx) = Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is Ok(aTy) and typeEqual(pTy, aTy) then Ok(resTy) - _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) + else Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) Err(message) then Err(message) Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) Err(message) then Err(message) -//│ typeTerm: ('a, 'right,) -> (Err & {message: string} | (Ok with {value: 'rhs | 'value})) +//│ fun typeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> Result[Type, string] //│ where -//│ 'right <: (Empty | Node & {key: string, left: 'right, right: 'right}) & 'b -//│ 'b <: Empty | Node & {key: string, left: 'b, right: 'b, value: 'value0 & 'c & 'd & 'rhs} -//│ 'a <: Abs & {lhs: Var & {name: string}, lty: 'lhs & 'c & 'd & 'rhs & 'value0 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Lit & {ty: 'rhs & 'value0 & 'c & 'd} | Var & {name: string} -//│ 'rhs :> 'value -//│ <: 'value0 & 'c & 'd -//│ 'value0 <: (FunctionType & {lhs: 'c & 'd, rhs: 'value0} | PrimitiveType & {name: string}) & 'rhs -//│ 'value :> FunctionType with {lhs: 'lhs, rhs: 'rhs} -//│ 'd <: FunctionType & {lhs: 'd, rhs: 'd} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'c <: FunctionType & {lhs: 'c & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'c} | PrimitiveType & {name: string} -//│ = [Function: typeTerm] +//│ 'A := Type fun showTypeTerm(t, ctx) = if typeTerm(t, ctx) is Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) Err(message) then concat2("Type error: ", message) -//│ showTypeTerm: ('a & 'b, 'c & 'd,) -> string +//│ fun showTypeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> string //│ where -//│ 'd <: Empty | Node & {key: string, left: 'right, right: 'right} -//│ 'right <: 'd & 'e -//│ 'e <: Empty | Node & {key: string, left: 'e, right: 'e, value: 'rhs} -//│ 'rhs <: 'f & 'g & (FunctionType & {lhs: 'f & 'g, rhs: 'rhs} | PrimitiveType & {name: string}) -//│ 'c <: Empty | Node & {key: string, left: 'c, right: 'c, value: 'rhs0} -//│ 'rhs0 <: 'g & 'f & (FunctionType & {lhs: 'f & 'g, rhs: 'rhs0} | PrimitiveType & {name: string}) -//│ 'b <: Abs & {lhs: Var & {name: string}, lty: 'rhs1 & 'f & 'g & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'b} | App & {lhs: 'b, rhs: 'b} | Lit & {ty: 'rhs1} | Var & {name: string} -//│ 'rhs1 <: 'f & 'g & (FunctionType & {lhs: 'f & 'g, rhs: 'rhs1} | PrimitiveType & {name: string}) -//│ 'g <: FunctionType & {lhs: 'g, rhs: 'g} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'a <: Abs & {lhs: 'a, lty: 'f, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, lty: 'f} | ~#Abs), rhs: 'a} | Lit | Var -//│ 'f <: FunctionType & {lhs: 'f & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'f} | PrimitiveType & {name: string} -//│ = [Function: showTypeTerm] - -showTypeTerm(Var("x"), empty) -showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), empty) -showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(empty, "f", _f(_t("int"), _t("int")))) -showTypeTerm(App(Var("f"), Lit("0.2", _t("float"))), insert(empty, "f", _f(_t("int"), _t("int")))) -showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(empty, "f", _t("string"))) -//│ res: string -//│ = 'Type error: unbound variable `x`' -//│ res: string -//│ = '&x: int => x : int -> int' -//│ res: string -//│ = '(f 0) : int' -//│ res: string -//│ = 'Type error: expect the argument to be of type `int` but found `float`' -//│ res: string -//│ = 'Type error: cannot apply primitive type `string`' +//│ 'A := Type + +showTypeTerm(Var("x"), Empty) +showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), Empty) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0.2", _t("float"))), insert(Empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _t("string"))) +//│ string +//│ res +//│ = 'Type error: unbound variable `x`' +//│ res +//│ = '&x: int => x : int -> int' +//│ res +//│ = '(f 0) : int' +//│ res +//│ = 'Type error: expect the argument to be of type `int` but found `float`' +//│ res +//│ = 'Type error: cannot apply primitive type `string`' diff --git a/shared/src/test/diff/ucs/ElseIf.mls b/shared/src/test/diff/ucs/ElseIf.mls index 2628d58c7a..561c975305 100644 --- a/shared/src/test/diff/ucs/ElseIf.mls +++ b/shared/src/test/diff/ucs/ElseIf.mls @@ -77,16 +77,7 @@ fun f(x, y) = if x is else if y is True then true False then false -//│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.75: True and y is True then true -//│ ║ ^^^^^^^^^ -//│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.75: True and y is True then true -//│ ║ ^ -//│ ╙── [Missing Case 1/1] `False` -//│ fun f: (anything, anything,) -> error -//│ Code generation encountered an error: -//│ if expression was not desugared +//│ fun f: (anything, False | True,) -> bool // TODO support `else if` fun f(x, y) = if x is @@ -96,13 +87,27 @@ fun f(x, y) = if x is True and x is False then true False and x is True then false //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.93: True and y is True then true -//│ ║ ^^^^^^^^^ +//│ ║ l.87: True and x is False then true +//│ ║ ^^^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.93: True and y is True then true +//│ ║ l.87: True and x is False then true //│ ║ ^ -//│ ╙── [Missing Case 1/1] `False` -//│ fun f: (anything, anything,) -> error +//│ ╙── [Missing Case 1/1] `True` +//│ ╔══[ERROR] The match is not exhaustive. +//│ ║ l.87: True and x is False then true +//│ ║ ^^^^^^^^^^ +//│ ╟── The scrutinee at this position misses 1 case. +//│ ║ l.87: True and x is False then true +//│ ║ ^ +//│ ╙── [Missing Case 1/1] `True` +//│ ╔══[ERROR] The match is not exhaustive. +//│ ║ l.87: True and x is False then true +//│ ║ ^^^^^^^^^^ +//│ ╟── The scrutinee at this position misses 1 case. +//│ ║ l.87: True and x is False then true +//│ ║ ^ +//│ ╙── [Missing Case 1/1] `True` +//│ fun f: (anything, anything,) -> (error | false | true) //│ Code generation encountered an error: //│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index d0e473b41f..757ef11bce 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -272,10 +272,12 @@ fun mapPartition(f, xs) = Cons(x, xs) and mapPartition(f, xs) is tmp0 and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition: ('head -> ((Left with {leftValue: 'head0}) | (Right with {rightValue: 'head1})), 'a,) -> (Pair with {fst: (Cons with {head: 'head0, tail: 'tail}) | 'tail, snd: (Cons with {head: 'head1, tail: 'tail}) | 'tail}) +//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: forall 'a. Cons & {head: 'leftValue, tail: forall 'a. 'fst | 'a} | 'fst | 'a, snd: forall 'b. Cons & {head: 'rightValue, tail: forall 'b. 'fst | 'b} | 'fst | 'b}) //│ where -//│ 'tail :> (Cons with {head: 0 | 1 | 2 | 3, tail: 'tail}) | Nil -//│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil +//│ 'b :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'b. Nil | 'b} +//│ 'a :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'a. Nil | 'a} +//│ 'fst :> Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} | Nil +//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil //│ = [Function: mapPartition1] // FIXME `b` should be bound here! @@ -289,7 +291,7 @@ fun mn(a) = Right(b) then "right-defined" None then "undefined" //│ ╔══[ERROR] identifier not found: b -//│ ║ l.288: let y = b + 1 +//│ ║ l.290: let y = b + 1 //│ ╙── ^ //│ mn: (None | Some & {value: Left | Right}) -> ("left-defined" | "right-defined" | "undefined") //│ Code generation encountered an error: diff --git a/shared/src/test/diff/ucs/Lambda.mls b/shared/src/test/diff/ucs/Lambda.mls index 1ba2a25322..72d37fdb97 100644 --- a/shared/src/test/diff/ucs/Lambda.mls +++ b/shared/src/test/diff/ucs/Lambda.mls @@ -1,4 +1,5 @@ :NewParser +:NewDefs :escape // You can push debug messages to this magic array. @@ -7,16 +8,19 @@ let _Array = Array let logs: { push: anything => anything, join: string => string } = _Array.from([]) let debug: anything => anything = x => logs.push(x) fun showDebug = logs.join("\n") -//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = -//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = [Function: Array] -//│ logs: {join: string -> string, push: anything -> anything} -//│ = [] -//│ debug: anything -> anything -//│ = [Function: debug] -//│ showDebug: string -//│ = [Function: showDebug] +//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let logs: {join: string -> string, push: anything -> anything} +//│ let debug: anything -> anything +//│ fun showDebug: string +//│ Array +//│ = +//│ _Array +//│ = [Function: Array] +//│ logs +//│ = [] +//│ debug +//│ = [Function: debug] fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) @@ -26,71 +30,64 @@ fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) fun par(a) = concat3("(", a, ")") -//│ concat2: (string, string,) -> string -//│ = [Function: concat2] -//│ concat3: (string, string, string,) -> string -//│ = [Function: concat3] -//│ concat4: (string, string, string, string,) -> string -//│ = [Function: concat4] -//│ concat5: (string, string, string, string, string,) -> string -//│ = [Function: concat5] -//│ concat6: (string, string, string, string, string, string,) -> string -//│ = [Function: concat6] -//│ concat7: (string, string, string, string, string, string, string,) -> string -//│ = [Function: concat7] -//│ concat8: (string, string, string, string, string, string, string, string,) -> string -//│ = [Function: concat8] -//│ par: string -> string -//│ = [Function: par] +//│ fun concat2: (string, string,) -> string +//│ fun concat3: (string, string, string,) -> string +//│ fun concat4: (string, string, string, string,) -> string +//│ fun concat5: (string, string, string, string, string,) -> string +//│ fun concat6: (string, string, string, string, string, string,) -> string +//│ fun concat7: (string, string, string, string, string, string, string,) -> string +//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string +//│ fun par: string -> string :escape let String: nothing let makeString: anything => { length: int, charCodeAt: int => int } = String let StringInstance: { fromCharCode: int => string } = String -//│ String: nothing -//│ = -//│ makeString: anything -> {charCodeAt: int -> int, length: int} -//│ = [Function: String] -//│ StringInstance: {fromCharCode: int -> string} -//│ = [Function: String] - -fun fromCharCode(n) = StringInstance.fromCharCode(n) -fun stringCharCodeAt(s, i) = makeString(s).charCodeAt(i) -fun stringLength(s) = makeString(s).length -//│ fromCharCode: int -> string -//│ = [Function: fromCharCode] -//│ stringCharCodeAt: (anything, int,) -> int -//│ = [Function: stringCharCodeAt] -//│ stringLength: anything -> int -//│ = [Function: stringLength] - -class Option -class Some(value): Option -class None(): Option -//│ Defined class Option -//│ Defined class Some -//│ Defined class None -//│ Option: () -> Option -//│ = [Function: Option1] -//│ Some: 'value -> (Some with {value: 'value}) -//│ = [Function: Some1] -//│ None: () -> None -//│ = [Function: None1] - -class List -class Cons(head, tail): List -class Nil(): List -//│ Defined class List -//│ Defined class Cons -//│ Defined class Nil -//│ List: () -> List -//│ = [Function: List1] -//│ Cons: ('head, 'tail,) -> (Cons with {head: 'head, tail: 'tail}) -//│ = [Function: Cons1] -//│ Nil: () -> Nil -//│ = [Function: Nil1] - -fun list1(x) = Cons(x, Nil()) +//│ let String: nothing +//│ let makeString: anything -> {charCodeAt: int -> int, length: int} +//│ let StringInstance: {fromCharCode: int -> string} +//│ String +//│ = +//│ makeString +//│ = [Function: String] +//│ StringInstance +//│ = [Function: String] + + +let anythingToString = toString +fun fromCharCode(n: int) = StringInstance.fromCharCode(n) +fun stringCharCodeAt(s: string, i) = makeString(s).charCodeAt(i) +fun stringLength(s: string) = makeString(s).length +//│ let anythingToString: anything -> string +//│ fun fromCharCode: (n: int,) -> string +//│ fun stringCharCodeAt: (s: string, int,) -> int +//│ fun stringLength: (s: string,) -> int +//│ anythingToString +//│ = [Function: toString] + +type Option[A] = Some[A] | None +class Some[A](value: A) { + fun toString() = concat3("Some(", anythingToString(value), ")") +} +module None { + fun toString() = "None" +} +//│ type Option[A] = None | Some[A] +//│ class Some[A](value: A) { +//│ fun toString: () -> string +//│ } +//│ module None() { +//│ fun toString: () -> "None" +//│ } + +type List[A] = Cons[A] | Nil +class Cons[A](head: A, tail: List[A]) +module Nil +//│ type List[A] = Cons[A] | Nil +//│ class Cons[A](head: A, tail: List[A]) +//│ module Nil() + +fun list1(x) = Cons(x, Nil) fun list2(x, y) = Cons(x, list1(y)) fun list3(x, y, z) = Cons(x, list2(y, z)) fun list4(x, y, z, w) = Cons(x, list3(y, z, w)) @@ -98,87 +95,69 @@ fun list5(x, y, z, w, v) = Cons(x, list4(y, z, w, v)) fun list6(x, y, z, w, v, u) = Cons(x, list5(y, z, w, v, u)) fun list7(x, y, z, w, v, u, t) = Cons(x, list6(y, z, w, v, u, t)) fun list8(x, y, z, w, v, u, t, s) = Cons(x, list7(y, z, w, v, u, t, s)) -//│ list1: 'head -> (Cons with {head: 'head, tail: Nil}) -//│ = [Function: list1] -//│ list2: ('head, 'head0,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Nil}}) -//│ = [Function: list2] -//│ list3: ('head, 'head0, 'head1,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Nil}}}) -//│ = [Function: list3] -//│ list4: ('head, 'head0, 'head1, 'head2,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Nil}}}}) -//│ = [Function: list4] -//│ list5: ('head, 'head0, 'head1, 'head2, 'head3,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Nil}}}}}) -//│ = [Function: list5] -//│ list6: ('head, 'head0, 'head1, 'head2, 'head3, 'head4,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Cons with {head: 'head4, tail: Nil}}}}}}) -//│ = [Function: list6] -//│ list7: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Cons with {head: 'head4, tail: Cons with {head: 'head5, tail: Nil}}}}}}}) -//│ = [Function: list7] -//│ list8: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5, 'head6,) -> (Cons with {head: 'head, tail: Cons with {head: 'head0, tail: Cons with {head: 'head1, tail: Cons with {head: 'head2, tail: Cons with {head: 'head3, tail: Cons with {head: 'head4, tail: Cons with {head: 'head5, tail: Cons with {head: 'head6, tail: Nil}}}}}}}}) -//│ = [Function: list8] +//│ fun list1: forall 'A. 'A -> Cons['A] +//│ fun list2: forall 'A. ('A, 'A,) -> Cons['A] +//│ fun list3: forall 'A. ('A, 'A, 'A,) -> Cons['A] +//│ fun list4: forall 'A. ('A, 'A, 'A, 'A,) -> Cons['A] +//│ fun list5: forall 'A. ('A, 'A, 'A, 'A, 'A,) -> Cons['A] +//│ fun list6: forall 'A. ('A, 'A, 'A, 'A, 'A, 'A,) -> Cons['A] +//│ fun list7: forall 'A. ('A, 'A, 'A, 'A, 'A, 'A, 'A,) -> Cons['A] +//│ fun list8: forall 'A. ('A, 'A, 'A, 'A, 'A, 'A, 'A, 'A,) -> Cons['A] fun listConcat(xs, ys) = if xs is - Nil() then ys + Nil then ys Cons(x, xs') then Cons(x, listConcat(xs', ys)) -//│ listConcat: ('a, 'tail,) -> 'tail +//│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) //│ where -//│ 'tail :> Cons with {head: 'head, tail: 'tail} -//│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil -//│ = [Function: listConcat] +//│ 'A <: 'A0 fun listContains(xs, x) = if xs is - Nil() then false + Nil then false Cons(x', xs') and eq(x)(x') then true _ then listContains(xs', x) -//│ listContains: ('a, anything,) -> bool -//│ where -//│ 'a <: Cons & {tail: 'a} | Nil -//│ = [Function: listContains] +//│ fun listContains: forall 'A. (Cons['A] | Nil, anything,) -> bool // Remove all occurrences of x from xs. fun listWithout(xs, x) = if xs is - Nil() then Nil() + Nil then Nil Cons(x', xs') and eq(x)(x') then listWithout(xs', x) _ then Cons(x', listWithout(xs', x)) -//│ listWithout: ('a, anything,) -> 'tail +//│ fun listWithout: forall 'A 'A0. (Cons['A] | Nil, anything,) -> (Cons['A0] | Nil) //│ where -//│ 'tail :> (Cons with {head: 'head, tail: 'tail}) | Nil -//│ 'a <: (Cons with {head: 'head, tail: 'a}) | Nil -//│ = [Function: listWithout] - +//│ 'A <: 'A0 + +// fix this: +// fun listJoin(xs, sep) = +// if xs is +// Nil then "" +// Cons(x, Nil) then toString(x) +// Cons(x, xs') then concat3(toString(x), sep, listJoin(xs', sep)) fun listJoin(xs, sep) = if xs is - Nil() then "" - Cons(x, Nil()) then toString(x) - Cons(x, xs') then concat3(toString(x), sep, listJoin(xs', sep)) -//│ listJoin: ('a, string,) -> string -//│ where -//│ 'a <: Cons & {tail: 'a} | Nil -//│ = [Function: listJoin] + Nil then "" + Cons(x, xs') and xs' is + Nil then toString(x) + _ then concat3(toString(x), sep, listJoin(xs', sep)) +//│ fun listJoin: forall 'A. (Cons['A] | Nil, string,) -> string listJoin(list3("x", "y", "z"), ", ") -//│ res: string -//│ = 'x, y, z' - -class Term -class Var(name): Term -class Abs(lhs, rhs): Term -class App(lhs, rhs): Term -//│ Defined class Term -//│ Defined class Var -//│ Defined class Abs -//│ Defined class App -//│ Term: () -> Term -//│ = [Function: Term1] -//│ Var: 'name -> (Var with {name: 'name}) -//│ = [Function: Var1] -//│ Abs: ('lhs, 'rhs,) -> (Abs with {lhs: 'lhs, rhs: 'rhs}) -//│ = [Function: Abs1] -//│ App: ('lhs, 'rhs,) -> (App with {lhs: 'lhs, rhs: 'rhs}) -//│ = [Function: App1] +//│ string +//│ res +//│ = 'x, y, z' + +type Term = Var | Abs | App +class Var(name: string) +class Abs(lhs: Var, rhs: Term) +class App(lhs: Term, rhs: Term) +//│ type Term = Abs | App | Var +//│ class Var(name: string) +//│ class Abs(lhs: Var, rhs: Term) +//│ class App(lhs: Term, rhs: Term) fun showTerm(t) = if t is @@ -187,41 +166,39 @@ fun showTerm(t) = App(Abs(lhs0, lhs1), rhs) then concat8("((", "&", showTerm(lhs0), ". ", showTerm(lhs1), ") ", showTerm(rhs), ")") App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) -//│ showTerm: 'a -> string -//│ where -//│ 'a <: Abs & {lhs: 'a, rhs: 'a} | App & {lhs: 'a & (Abs & {lhs: 'a, rhs: 'a} | ~#Abs), rhs: 'a} | Var -//│ = [Function: showTerm] +//│ fun showTerm: (Abs | App | Var) -> string showTerm(Var("x")) showTerm(Abs(Var("x"), Var("y"))) showTerm(App(Var("x"), Var("y"))) showTerm(App(Abs(Var("x"), Var("y")), Var("z"))) -//│ res: string -//│ = 'x' -//│ res: string -//│ = '&x. y' -//│ res: string -//│ = '(x y)' -//│ res: string -//│ = '((&x. y) z)' +//│ string +//│ res +//│ = 'x' +//│ res +//│ = '&x. y' +//│ res +//│ = '(x y)' +//│ res +//│ = '((&x. y) z)' fun isValue(t) = if t is Var then true Abs then true App then false -//│ isValue: (Abs | App | Var) -> bool -//│ = [Function: isValue] +//│ fun isValue: (Abs | App | Var) -> bool isValue(Var("x")) isValue(Abs(Var("x"), Var("y"))) isValue(App(Var("x"), Var("y"))) -//│ res: bool -//│ = true -//│ res: bool -//│ = true -//│ res: bool -//│ = false +//│ bool +//│ res +//│ = true +//│ res +//│ = true +//│ res +//│ = false :w fun hasFree(t, n) = @@ -233,23 +210,16 @@ fun hasFree(t, n) = App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) _ then false //│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.234: _ then false +//│ ║ l.211: _ then false //│ ║ ^^^^^ //│ ╟── The first else branch was declared here. -//│ ║ l.232: Abs(Var(name), body) then hasFree(body, n) +//│ ║ l.209: Abs(Var(name), body) then hasFree(body, n) //│ ╙── ^^^^^^^^^^^^^^^^ -//│ hasFree: ('a, anything,) -> bool -//│ where -//│ 'a <: Abs & {rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var | ~Abs & ~App & ~Var -//│ = [Function: hasFree] +//│ fun hasFree: (anything, anything,) -> bool fun showHasFree(t, n) = concat4(showTerm(t), if hasFree(t, n) then " has " else " DOES NOT have ", "free variable ", n) -//│ showHasFree: ('a & 'b, string,) -> string -//│ where -//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var -//│ 'a <: Abs & {rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var | ~Abs & ~App & ~Var -//│ = [Function: showHasFree] +//│ fun showHasFree: (Abs | App | Var, string,) -> string showHasFree(Var("x"), "x") showHasFree(Var("x"), "y") @@ -263,98 +233,91 @@ showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "x") showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") showHasFree(App(Abs(Var("x"), Var("x")), Var("y")), "y") showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") -//│ res: string -//│ = 'x has free variable x' -//│ res: string -//│ = 'x DOES NOT have free variable y' -//│ res: string -//│ = '&x. x DOES NOT have free variable x' -//│ res: string -//│ = '&x. x DOES NOT have free variable y' -//│ res: string -//│ = '&x. y DOES NOT have free variable x' -//│ res: string -//│ = '&x. y has free variable y' -//│ res: string -//│ = '(x y) has free variable x' -//│ res: string -//│ = '(x y) has free variable y' -//│ res: string -//│ = '((&x. x) x) has free variable x' -//│ res: string -//│ = '((&x. x) x) DOES NOT have free variable y' -//│ res: string -//│ = '((&x. x) y) has free variable y' -//│ res: string -//│ = '((&x. x) x) DOES NOT have free variable y' +//│ string +//│ res +//│ = 'x has free variable x' +//│ res +//│ = 'x DOES NOT have free variable y' +//│ res +//│ = '&x. x DOES NOT have free variable x' +//│ res +//│ = '&x. x DOES NOT have free variable y' +//│ res +//│ = '&x. y DOES NOT have free variable x' +//│ res +//│ = '&x. y has free variable y' +//│ res +//│ = '(x y) has free variable x' +//│ res +//│ = '(x y) has free variable y' +//│ res +//│ = '((&x. x) x) has free variable x' +//│ res +//│ = '((&x. x) x) DOES NOT have free variable y' +//│ res +//│ = '((&x. x) y) has free variable y' +//│ res +//│ = '((&x. x) x) DOES NOT have free variable y' fun fv(t) = if t is Var(name) then list1(name) Abs(Var(name), body) then listWithout(fv(body), name) App(lhs, rhs) then listConcat(fv(lhs), fv(rhs)) -//│ fv: 'a -> 'tail +//│ fun fv: forall 'A. (Abs | App | Var) -> (Cons['A] | Nil) //│ where -//│ 'tail :> Cons & {head: 'head, tail: Nil} | 'tail0 | (Cons with {head: 'head, tail: 'tail}) -//│ 'tail0 :> (Cons with {head: 'head, tail: 'tail0}) | Nil -//│ 'a <: Abs & {lhs: Var, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var & {name: 'head} -//│ = [Function: fv] +//│ 'A :> string fun showFv(t) = concat2(showTerm(t), if fv(t) is Nil then " DOES NOT have free variables" _ then concat2(" has free variables: ", listJoin(fv(t), ", ")) ) -//│ showFv: ('a & 'b) -> string -//│ where -//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var -//│ 'a <: Abs & {lhs: Var, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var & {name: anything} -//│ = [Function: showFv] +//│ fun showFv: (Abs | App | Var) -> string showFv(Var("x")) showFv(Abs(Var("x"), Var("x"))) showFv(Abs(Var("x"), Var("y"))) showFv(App(Var("x"), Var("y"))) showFv(App(Abs(Var("x"), Var("x")), Var("x"))) -//│ res: string -//│ = 'x has free variables: x' -//│ res: string -//│ = '&x. x DOES NOT have free variables' -//│ res: string -//│ = '&x. y has free variables: y' -//│ res: string -//│ = '(x y) has free variables: x, y' -//│ res: string -//│ = '((&x. x) x) has free variables: x' +//│ string +//│ res +//│ = 'x has free variables: x' +//│ res +//│ = '&x. x DOES NOT have free variables' +//│ res +//│ = '&x. y has free variables: y' +//│ res +//│ = '(x y) has free variables: x, y' +//│ res +//│ = '((&x. x) x) has free variables: x' fun tryNextAlphabet(initialCode, currentCode, freeNames) = if currentCode > 122 then tryNextAlphabet(initialCode, 97, freeNames) - == initialCode then None() + == initialCode then None let name = fromCharCode(currentCode) listContains(freeNames, name) then tryNextAlphabet(initialCode, currentCode + 1, freeNames) _ then Some(name) -//│ tryNextAlphabet: (number, int, 'a,) -> (None | Some & {value: string}) -//│ where -//│ 'a <: Cons & {tail: 'a} | Nil -//│ = [Function: tryNextAlphabet] - -tryNextAlphabet(97, 97, list1("a")) -tryNextAlphabet(97, 98, list1("a")) -tryNextAlphabet(97, 98, list2("a", "b")) -tryNextAlphabet(121, 122, list1("y")) -tryNextAlphabet(121, 122, list2("y", "z")) -//│ res: None | Some & {value: string} -//│ = None {} -//│ res: None | Some & {value: string} -//│ = Some { value: 'b' } -//│ res: None | Some & {value: string} -//│ = Some { value: 'c' } -//│ res: None | Some & {value: string} -//│ = Some { value: 'z' } -//│ res: None | Some & {value: string} -//│ = Some { value: 'a' } +//│ fun tryNextAlphabet: forall 'A. (number, int, Cons['A] | Nil,) -> (None | Some[string]) + +toString(tryNextAlphabet(97, 97, list1("a"))) +toString(tryNextAlphabet(97, 98, list1("a"))) +toString(tryNextAlphabet(97, 98, list2("a", "b"))) +toString(tryNextAlphabet(121, 122, list1("y"))) +toString(tryNextAlphabet(121, 122, list2("y", "z"))) +//│ string +//│ res +//│ = 'None' +//│ res +//│ = 'Some(b)' +//│ res +//│ = 'Some(c)' +//│ res +//│ = 'Some(z)' +//│ res +//│ = 'Some(a)' fun tryAppendDigits(name, index, freeNames) = if @@ -362,10 +325,7 @@ fun tryAppendDigits(name, index, freeNames) = listContains(freeNames, currentName) then tryAppendDigits(name, index + 1, freeNames) _ then currentName -//│ tryAppendDigits: (string, int, 'a,) -> string -//│ where -//│ 'a <: Cons & {tail: 'a} | Nil -//│ = [Function: tryAppendDigits] +//│ fun tryAppendDigits: forall 'A. (string, int, Cons['A] | Nil,) -> string // Note: some weird behavior here... Just try the commented code. fun findFreshName(name, freeNames) = @@ -375,18 +335,12 @@ fun findFreshName(name, freeNames) = tryNextAlphabet(charCode, charCode + 1, freeNames) is Some(newName) then newName _ then tryAppendDigits(name, 0, freeNames) -//│ findFreshName: (string, 'a,) -> string -//│ where -//│ 'a <: Cons & {tail: 'a} | Nil -//│ = [Function: findFreshName] +//│ fun findFreshName: forall 'A 'A0 'A1. (string, Cons[in 'A | 'A0 | 'A1 out 'A & 'A0 & 'A1] | Nil,) -> string // Find a fresh name to replace `name` that does not conflict with any bound // variables in the `body`. fun freshName(name, body) = findFreshName(name, fv(body)) -//│ freshName: (string, 'a,) -> string -//│ where -//│ 'a <: Abs & {lhs: Var, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var & {name: anything} -//│ = [Function: freshName] +//│ fun freshName: (string, Abs | App | Var,) -> string :w fun subst(t, n, v) = @@ -399,122 +353,130 @@ fun subst(t, n, v) = App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t //│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.400: _ then t +//│ ║ l.354: _ then t //│ ║ ^ //│ ╟── The first else branch was declared here. -//│ ║ l.398: _ then Abs(Var(name), subst(body, n, v)) +//│ ║ l.352: _ then Abs(Var(name), subst(body, n, v)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ subst: ('a, anything, 'a & 'b & 'rhs & 'c,) -> 'rhs -//│ where -//│ 'c <: Abs & {rhs: 'c} | App & {lhs: 'c, rhs: 'c} | Var | ~Abs & ~App & ~Var -//│ 'a <: Abs & 'd | App & 'e | Var & 'f | 'g & ~#Abs & ~#App & ~#Var -//│ 'd :> (Abs with {lhs: Var & {name: string}, rhs: 'rhs}) | 'rhs -//│ <: 'b & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} & 'e | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} & 'f | {lhs: Var & {name: 'name} | ~Var, rhs: 'a & 'b} & 'g & ~#Abs & ~#App & ~#Var) -//│ 'rhs :> (App with {lhs: 'rhs, rhs: 'rhs}) | (Abs with {lhs: Var & {name: 'name0}, rhs: 'rhs}) | Var & {name: string} | 'f | 'd | 'g -//│ 'f :> Var & {name: string} -//│ <: 'b & (Abs & {name: anything} & 'd | App & {name: anything} & 'e | Var | {name: anything} & 'g & ~#Abs & ~#App & ~#Var) -//│ 'g <: 'b & (Abs & 'd | App & 'e | Var & 'f | ~#Abs & ~#App & ~#Var) -//│ 'e <: {lhs: 'a, rhs: 'a} -//│ 'b <: Abs & {lhs: Var, rhs: 'b} | App & {lhs: 'b, rhs: 'b} | Var & {name: anything} -//│ 'name0 :> string -//│ <: 'name -//│ 'name <: string & 'name0 -//│ = [Function: subst] +//│ fun subst: forall 'a. (Abs | App | Var | Term & 'a & ~#Abs & ~#App & ~#Var, anything, Term & 'a,) -> (Abs | App | Var | 'a) fun showSubst(t, n, v) = concat8(showTerm(t), " [", n, " / ", showTerm(v), "]", " => ", showTerm(subst(t, n, v))) -//│ showSubst: ('a & 'b, string, 'a & 'lhs & 'c & 'd & 'e & 'b,) -> string -//│ where -//│ 'e <: Abs & {rhs: 'e} | App & {lhs: 'e, rhs: 'e} | Var | ~Abs & ~App & ~Var -//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var -//│ 'a <: Abs & 'f | App & 'g | Var & 'h | 'i & ~#Abs & ~#App & ~#Var -//│ 'f <: 'lhs & 'c & 'd & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} | App & {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} & 'g | Var & {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} & 'h | {lhs: Var & {name: string} | ~Var, rhs: 'a & 'd} & 'i & ~#Abs & ~#App & ~#Var) -//│ 'h <: 'lhs & 'c & 'd & (Abs & {name: anything} & 'f | App & {name: anything} & 'g | Var | {name: anything} & 'i & ~#Abs & ~#App & ~#Var) -//│ 'i <: 'lhs & 'c & 'd & (Abs & 'f | App & 'g | ~#Abs & ~#App & ~#Var | Var & 'h) -//│ 'g <: {lhs: 'a, rhs: 'a} -//│ 'd <: Abs & {lhs: Var, rhs: 'd} | App & {lhs: 'd, rhs: 'd} | Var & {name: anything} -//│ 'lhs <: Abs & {lhs: 'c, rhs: 'c} | ~Abs -//│ 'c <: Abs & {lhs: 'c, rhs: 'c} | App & {lhs: 'lhs & 'c, rhs: 'c} | Var -//│ = [Function: showSubst] +//│ fun showSubst: (Abs | App | Var, string, Abs & Term | App & Term | Var & Term,) -> string showSubst(Var("x"), "x", Var("y")) showSubst(Abs(Var("x"), Var("x")), "x", Var("z")) showSubst(App(Var("x"), Var("y")), "x", Abs(Var("x"), Var("x"))) showSubst(App(Abs(Var("x"), Var("x")), Var("x")), "x", Abs(Var("y"), Var("y"))) showSubst(Abs(Var("x"), App(Var("x"), Var("y"))), "y", Var("x")) -//│ res: string -//│ = 'x [x / y] => y' -//│ res: string -//│ = '&x. x [x / z] => &x. x' -//│ res: string -//│ = '(x y) [x / &x. x] => ((&x. x) y)' -//│ res: string -//│ = '((&x. x) x) [x / &y. y] => ((&x. x) &y. y)' -//│ res: string -//│ = '&x. (x y) [y / x] => &z. (z x)' +showSubst(Abs(Var("z"), Abs(Var("x"), App(Var("z"), App(Var("x"), Var("y"))))), "y", Var("x")) +//│ string +//│ res +//│ = 'x [x / y] => y' +//│ res +//│ = '&x. x [x / z] => &x. x' +//│ res +//│ = '(x y) [x / &x. x] => ((&x. x) y)' +//│ res +//│ = '((&x. x) x) [x / &y. y] => ((&x. x) &y. y)' +//│ res +//│ = '&x. (x y) [y / x] => &z. (z x)' +//│ res +//│ = '&z. &x. (z (x y)) [y / x] => &z. &a. (z (a x))' + +type Result = Normal | Stuck | Stepped +class Normal(term: Term) { + fun toString() = concat2("Normal form: ", showTerm(term)) +} +class Stuck(term: Term, part: Term) { + fun toString() = concat4("Stuck: ", showTerm(part), " in ", showTerm(term)) +} +class Stepped(from: Term, to: Term) { + fun toString() = concat3(showTerm(from), " => ", showTerm(to)) +} +//│ type Result = Normal | Stepped | Stuck +//│ class Normal(term: Term) { +//│ fun toString: () -> string +//│ } +//│ class Stuck(term: Term, part: Term) { +//│ fun toString: () -> string +//│ } +//│ class Stepped(from: Term, to: Term) { +//│ fun toString: () -> string +//│ } fun stepByValue(t) = if t is - Var then None() - Abs then None() + Var then Stuck(t, t) + Abs then Normal(t) App(lhs, rhs) and stepByValue(lhs) is - Some(lhs) then Some(App(lhs, rhs)) - None and stepByValue(rhs) is - Some(rhs) then Some(App(lhs, rhs)) - None and lhs is - Abs(Var(name), body) then Some(subst(body, name, rhs)) - _ then None() -//│ stepByValue: 'a -> (None | (Some with {value: 'rhs})) -//│ where -//│ 'rhs :> 'value | (App with {lhs: 'rhs, rhs: 'rhs0}) | (App with {lhs: 'lhs, rhs: 'rhs}) -//│ 'a <: Abs | App & {lhs: 'lhs & 'a & (Abs & {rhs: 'b} | ~#Abs), rhs: 'a & 'b & 'c & 'value & 'd & 'rhs0} | Var -//│ 'd <: Abs & {rhs: 'd} | App & {lhs: 'd, rhs: 'd} | Var | ~Abs & ~App & ~Var -//│ 'b <: Abs & 'e | App & 'f | Var & 'g | 'h & ~#Abs & ~#App & ~#Var -//│ 'e :> (Abs with {lhs: Var & {name: string}, rhs: 'value}) | 'value -//│ <: 'c & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} & 'f | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} & 'g | {lhs: Var & {name: 'name} | ~Var, rhs: 'b & 'c} & 'h & ~#Abs & ~#App & ~#Var) -//│ 'value :> (App with {lhs: 'value, rhs: 'value}) | (Abs with {lhs: Var & {name: 'name0}, rhs: 'value}) | Var & {name: string} | 'g | 'e | 'h -//│ 'g :> Var & {name: string} -//│ <: 'c & (Abs & {name: anything} & 'e | App & {name: anything} & 'f | Var | {name: anything} & 'h & ~#Abs & ~#App & ~#Var) -//│ 'h <: 'c & (Abs & 'e | App & 'f | Var & 'g | ~#Abs & ~#App & ~#Var) -//│ 'f <: {lhs: 'b, rhs: 'b} -//│ 'c <: Abs & {lhs: Var, rhs: 'c} | App & {lhs: 'c, rhs: 'c} | Var & {name: anything} -//│ 'name0 :> string -//│ <: 'name -//│ 'name <: string & 'name0 -//│ = [Function: stepByValue] - -fun showStepByValue(t) = - concat3(showTerm(t), " => ", if stepByValue(t) is - Some(t) then showTerm(t) - None then "stuck" - ) -//│ showStepByValue: ('a & 'b) -> string -//│ where -//│ 'b <: Abs & {lhs: 'b, rhs: 'b} | App & {lhs: 'b & (Abs & {lhs: 'b, rhs: 'b} | ~#Abs), rhs: 'b} | Var -//│ 'a <: Abs | App & {lhs: 'a & 'lhs & 'c & (Abs & {rhs: 'd} | ~#Abs), rhs: 'a & 'd & 'lhs & 'c & 'e & 'f} | Var -//│ 'f <: Abs & {rhs: 'f} | App & {lhs: 'f, rhs: 'f} | Var | ~Abs & ~App & ~Var -//│ 'd <: Abs & 'g | App & 'h | Var & 'i | 'j & ~#Abs & ~#App & ~#Var -//│ 'g <: 'lhs & 'c & 'e & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} | App & {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} & 'h | Var & {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} & 'i | {lhs: Var & {name: string} | ~Var, rhs: 'd & 'e} & 'j & ~#Abs & ~#App & ~#Var) -//│ 'i <: 'lhs & 'c & 'e & (Abs & {name: anything} & 'g | App & {name: anything} & 'h | Var | {name: anything} & 'j & ~#Abs & ~#App & ~#Var) -//│ 'j <: 'lhs & 'c & 'e & (Abs & 'g | App & 'h | ~#Abs & ~#App & ~#Var | Var & 'i) -//│ 'h <: {lhs: 'd, rhs: 'd} -//│ 'e <: Abs & {lhs: Var, rhs: 'e} | App & {lhs: 'e, rhs: 'e} | Var & {name: anything} -//│ 'lhs <: Abs & {lhs: 'c, rhs: 'c} | ~Abs -//│ 'c <: Abs & {lhs: 'c, rhs: 'c} | App & {lhs: 'lhs & 'c, rhs: 'c} | Var -//│ = [Function: showStepByValue] - -showStepByValue(Var("x")) -showStepByValue(Abs(Var("x"), Var("y"))) -showStepByValue(App(Var("x"), Var("y"))) -showStepByValue(App(Abs(Var("x"), Var("x")), Var("y"))) -//│ res: string -//│ = 'x => stuck' -//│ res: string -//│ = '&x. y => stuck' -//│ res: string -//│ = '(x y) => stuck' -//│ res: string -//│ = '((&x. x) y) => y' + Stepped(_, lhs) then Stepped(t, App(lhs, rhs)) + Stuck(_, part) then Stuck(t, part) + Normal and stepByValue(rhs) is + Stepped(_, rhs) then Stepped(t, App(lhs, rhs)) + Stuck(_, part) then Stuck(t, part) + Normal and lhs is + Abs(Var(name), body) then Stepped(t, subst(body, name, rhs)) + _ then Stuck(t, lhs) +//│ fun stepByValue: (Abs | App | Var) -> (Normal | Stepped | Stuck) + +toString of stepByValue of Var("x") +toString of stepByValue of Abs(Var("x"), Var("y")) +toString of stepByValue of App(Var("x"), Var("y")) +toString of stepByValue of App(Abs(Var("x"), Var("x")), Var("x")) +toString of stepByValue of App(Abs(Var("x"), Var("x")), Abs(Var("y"), Var("y"))) +//│ string +//│ res +//│ = 'Stuck: x in x' +//│ res +//│ = 'Normal form: &x. y' +//│ res +//│ = 'Stuck: x in (x y)' +//│ res +//│ = 'Stuck: x in ((&x. x) x)' +//│ res +//│ = '((&x. x) &y. y) => &y. y' + +fun evalByValue(t) = + if stepByValue(t) is result and result is + Stepped(_, term) then evalByValue(term) + else result +//│ fun evalByValue: (Abs | App | Var) -> (Normal | Stuck) + +// Let's program with Church encoding! +let zero = Abs(Var("f"), Abs(Var("x"), Var("x"))) +let one = Abs(Var("f"), Abs(Var("x"), App(Var("f"), Var("x")))) +toString of stepByValue of zero +toString of stepByValue of one +let succ = Abs(Var("n"), Abs(Var("f"), Abs(Var("x"), App(Var("f"), App(App(Var("n"), Var("f")), Var("x")))))) +toString of stepByValue of succ +toString of stepByValue of App(succ, zero) +//│ let zero: Abs +//│ let one: Abs +//│ let succ: Abs +//│ string +//│ zero +//│ = Abs {} +//│ one +//│ = Abs {} +//│ res +//│ = 'Normal form: &f. &x. x' +//│ res +//│ = 'Normal form: &f. &x. (f x)' +//│ succ +//│ = Abs {} +//│ res +//│ = 'Normal form: &n. &f. &x. (f ((n f) x))' +//│ res +//│ = '((&n. &f. &x. (f ((n f) x))) &f. &x. x) => &f. &x. (f (((&f. &x. x) f) x))' + +toString of evalByValue of App(succ, App(succ, zero)) +toString of evalByValue of App(succ, App(succ, App(succ, App(succ, zero)))) +//│ string +//│ res +//│ = 'Normal form: &f. &x. (f (((&f. &x. (f (((&f. &x. x) f) x))) f) x))' +//│ res +//│ = 'Normal form: &f. &x. (f (((&f. &x. (f (((&f. &x. (f (((&f. &x. (f (((&f. &x. x) f) x))) f) x))) f) x))) f) x))' fun equalTerm(a, b) = if a is @@ -522,7 +484,4 @@ fun equalTerm(a, b) = Abs(la, ra) and b is Abs(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) App(la, ra) and b is App(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) _ then false -//│ equalTerm: ('a, 'a,) -> bool -//│ where -//│ 'a <: Abs & {lhs: 'a, rhs: 'a} | App & {lhs: 'a, rhs: 'a} | Var | ~Abs & ~App & ~Var -//│ = [Function: equalTerm] +//│ fun equalTerm: (anything, anything,) -> bool diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index adcfaf54e3..a96d432f4e 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -1,163 +1,82 @@ :NewParser - - -class Option -class Some(value): Option -class None: Option -class Either -class Left(leftValue): Either -class Right(rightValue): Either -class List -class Nil: List -let Nil = Nil() -class Cons(head, tail): List -class Pair(fst, snd) -//│ Defined class Option -//│ Defined class Some -//│ Defined class None -//│ Defined class Either -//│ Defined class Left -//│ Defined class Right -//│ Defined class List -//│ Defined class Nil -//│ Defined class Cons -//│ Defined class Pair -//│ Option: () -> Option -//│ = [Function: Option1] -//│ Some: 'value -> (Some & {value: 'value}) -//│ = [Function: Some1] -//│ None: () -> None -//│ = [Function: None1] -//│ Either: () -> Either -//│ = [Function: Either1] -//│ Left: 'leftValue -> (Left & {leftValue: 'leftValue}) -//│ = [Function: Left1] -//│ Right: 'rightValue -> (Right & {rightValue: 'rightValue}) -//│ = [Function: Right1] -//│ List: () -> List -//│ = [Function: List1] -//│ Nil: () -> Nil -//│ = [Function: Nil1] -//│ Nil: Nil -//│ = Nil {} -//│ Cons: ('head, 'tail,) -> (Cons & {head: 'head, tail: 'tail}) -//│ = [Function: Cons1] -//│ Pair: ('fst, 'snd,) -> (Pair & {fst: 'fst, snd: 'snd}) -//│ = [Function: Pair1] - - +:NewDefs + +class Some[A](value: A) +module None +class Left[A](leftValue: A) +class Right[A](rightValue: A) +module Nil +class Cons[A](head: A, tail: Cons[A] | Nil) +class Pair[A, B](fst: A, snd: B) +//│ class Some[A](value: A) +//│ module None() +//│ class Left[A](leftValue: A) +//│ class Right[A](rightValue: A) +//│ module Nil() +//│ class Cons[A](head: A, tail: Cons[A] | Nil) +//│ class Pair[A, B](fst: A, snd: B) fun optionApply(x, y, f) = if x is Some(xv) and y is Some(yv) then Some(f(xv, yv)) - None() then None() - None() then None() -//│ optionApply: (None | Some & {value: 'value}, None | Some & {value: 'value0}, ('value, 'value0,) -> 'value1,) -> (None | Some & {value: 'value1}) -//│ = [Function: optionApply] + None then None + None then None +//│ fun optionApply: forall 'value 'value0 'A. (None | Some['value], None | Some['value0], ('value, 'value0,) -> 'A,) -> (None | Some['A]) let zeroToThree = Cons(0, Cons(1, Cons(2, Cons(3, Nil)))) -//│ zeroToThree: Cons & {head: 0, tail: Cons & {head: 1, tail: Cons & {head: 2, tail: Cons & {head: 3, tail: Nil}}}} -//│ = Cons { -//│ head: 0, -//│ tail: Cons { head: 1, tail: Cons { head: 2, tail: [Cons] } } -//│ } +//│ let zeroToThree: Cons['A] +//│ where +//│ 'A :> 0 | 1 | 2 | 3 +//│ zeroToThree +//│ = Cons {} fun f(x) = if x % 2 == 0 then Left(x) else Right(x) -//│ f: (int & 'leftValue) -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'leftValue}) -//│ = [Function: f] - +//│ fun f: forall 'A. (int & 'A) -> (Left['A] | Right['A]) fun mapPartition(f, xs) = if xs is - Nil then Pair(Nil(), Nil()) + Nil then Pair(Nil, Nil) Cons(x, xs) and mapPartition(f, xs) is Pair(l, r) and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: Nil then Pair(Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.72: Nil then Pair(Nil(), Nil()) -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: Nil then Pair(Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.72: Nil then Pair(Nil(), Nil()) -//│ ╙── ^^^ -//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: 'fst, snd: 'tail0}) -//│ where -//│ 'tail0 :> Cons & {head: 'rightValue, tail: 'tail0} | error -//│ 'fst :> error | Cons & {head: 'leftValue, tail: 'fst} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil -//│ = [Function: mapPartition] +//│ fun mapPartition: forall 'A 'A0 'head. ('head -> (Left['A] | Right['A0]), Cons['head] | Nil,) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(x => Left(x + 1), zeroToThree) -//│ res: Pair & {fst: 'fst, snd: 'snd} +//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] //│ where -//│ 'snd :> Cons & {head: nothing, tail: 'snd} | error -//│ 'fst :> error | Cons & {head: int, tail: 'fst} -//│ Runtime error: -//│ TypeError: Nil2 is not a function +//│ 'A :> int +//│ res +//│ = Pair {} mapPartition(f, zeroToThree) -//│ res: Pair & {fst: 'fst, snd: 'snd} +//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] //│ where -//│ 'snd :> Cons & {head: 0 | 1 | 2 | 3, tail: 'snd} | error -//│ 'fst :> error | Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} -//│ Runtime error: -//│ TypeError: Nil2 is not a function +//│ 'A0 :> 0 | 1 | 2 | 3 +//│ 'A :> 0 | 1 | 2 | 3 +//│ res +//│ = Pair {} fun mapPartition(f, xs) = if xs is - Nil then Pair(Nil(), Nil()) + Nil then Pair(Nil, Nil) Cons(x, xs) and mapPartition(f, xs) is Pair(l, r) and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.119: Nil then Pair(Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.119: Nil then Pair(Nil(), Nil()) -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.119: Nil then Pair(Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.119: Nil then Pair(Nil(), Nil()) -//│ ╙── ^^^ -//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: 'fst, snd: 'tail0}) -//│ where -//│ 'tail0 :> Cons & {head: 'rightValue, tail: 'tail0} | error -//│ 'fst :> error | Cons & {head: 'leftValue, tail: 'fst} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil -//│ = [Function: mapPartition1] +//│ fun mapPartition: forall 'head 'A 'A0. ('head -> (Left['A] | Right['A0]), Cons['head] | Nil,) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(f, zeroToThree) -//│ res: Pair & {fst: 'fst, snd: 'snd} +//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] //│ where -//│ 'snd :> Cons & {head: 0 | 1 | 2 | 3, tail: 'snd} | error -//│ 'fst :> error | Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} -//│ Runtime error: -//│ TypeError: Nil2 is not a function +//│ 'A0 :> 0 | 1 | 2 | 3 +//│ 'A :> 0 | 1 | 2 | 3 +//│ res +//│ = Pair {} fun mapPartition(f, xs) = if xs is Nil then - Pair(Nil(), Nil()) + Pair(Nil, Nil) Cons(x, xs) and mapPartition(f, xs) is Pair(l, r) and @@ -166,56 +85,33 @@ fun mapPartition(f, xs) = if xs is Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.160: Pair(Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.160: Pair(Nil(), Nil()) -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.160: Pair(Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.160: Pair(Nil(), Nil()) -//│ ╙── ^^^ -//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: 'fst, snd: 'tail0}) -//│ where -//│ 'tail0 :> Cons & {head: 'rightValue, tail: 'tail0} | error -//│ 'fst :> error | Cons & {head: 'leftValue, tail: 'fst} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil -//│ = [Function: mapPartition2] +//│ fun mapPartition: forall 'head 'A 'A0. ('head -> (Left['A] | Right['A0]), Cons['head] | Nil,) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(f, zeroToThree) -//│ res: Pair & {fst: 'fst, snd: 'snd} +//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] //│ where -//│ 'snd :> Cons & {head: 0 | 1 | 2 | 3, tail: 'snd} | error -//│ 'fst :> error | Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} -//│ Runtime error: -//│ TypeError: Nil2 is not a function - +//│ 'A0 :> 0 | 1 | 2 | 3 +//│ 'A :> 0 | 1 | 2 | 3 +//│ res +//│ = Pair {} // TODO make this one work (needs tuple support) fun mapPartition(f, xs) = if xs is - Nil then (Nil(), Nil()) + Nil then (Nil, Nil) Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is Left(v) then (Cons(v, l), r) Right(v) then (l, Cons(v, r)) //│ ╔══[ERROR] The case when this is false is not handled: is (mapPartition (f, xs,),) (l, r,) -//│ ║ l.206: Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is +//│ ║ l.101: Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ mapPartition: (anything, anything,) -> error +//│ fun mapPartition: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared // TODO mapPartition(f, zeroToThree) -//│ res: error +//│ error +//│ res //│ Runtime error: //│ ReferenceError: mapPartition3 is not defined @@ -226,42 +122,20 @@ mapPartition(f, zeroToThree) :e :ge fun mapPartition(f, xs) = if xs is - Nil then (Nil(), Nil()) + Nil then (Nil, Nil) Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is Left(v) then (Cons(v, l), r) Right(v) then (l, Cons(v, r)) //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here -//│ ║ l.232: Right(v) then (l, Cons(v, r)) +//│ ║ l.128: Right(v) then (l, Cons(v, r)) //│ ╙── ^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.231: and f(x) is Left(v) then (Cons(v, l), r) +//│ ║ l.127: and f(x) is Left(v) then (Cons(v, l), r) //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.232: Right(v) then (l, Cons(v, r)) +//│ ║ l.128: Right(v) then (l, Cons(v, r)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.229: Nil then (Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.229: Nil then (Nil(), Nil()) -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.229: Nil then (Nil(), Nil()) -//│ ║ ^^^^^ -//│ ╟── application of type `Nil` is not a function -//│ ║ l.11: class Nil: List -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `() -> ?a` -//│ ║ l.229: Nil then (Nil(), Nil()) -//│ ╙── ^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── -//│ mapPartition: (anything, 'tail,) -> ((error, error,) | error) -//│ where -//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ fun mapPartition: forall 'A. (anything, Cons['A] | Nil,) -> ((Nil, Nil,) | error) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 - - diff --git a/shared/src/test/diff/ucs/NestedPattern.mls b/shared/src/test/diff/ucs/NestedPattern.mls index 0b99c6b4e4..5d9b919bdc 100644 --- a/shared/src/test/diff/ucs/NestedPattern.mls +++ b/shared/src/test/diff/ucs/NestedPattern.mls @@ -70,13 +70,13 @@ fun f(p) = class Union(a, b) //│ Defined class Union -//│ Union: ('a, 'b,) -> (Union with {a: 'a, b: 'b}) +//│ Union: ('a, 'b,) -> (Union & {a: 'a, b: 'b}) // Name conflict between the scrutinee and the positionals. // Desugar result: let tmp13 = x in case tmp13 of { Union => let x = (tmp13).a in let y = (tmp13).b in x } fun hmm(x) = if x is Union(x, y) then x -//│ hmm: (Union with {a: 'a}) -> 'a +//│ hmm: (Union & {a: 'a}) -> 'a hmm(Union(1, 2)) //│ res: 1 diff --git a/shared/src/test/diff/ucs/PlainConditionals.mls b/shared/src/test/diff/ucs/PlainConditionals.mls index ed28f24488..21c0a7d659 100644 --- a/shared/src/test/diff/ucs/PlainConditionals.mls +++ b/shared/src/test/diff/ucs/PlainConditionals.mls @@ -52,26 +52,40 @@ fun foo(x) = if x is Pair(a, b) then a > b else false fun foo(x) = x is Pair Int -//│ /!!!\ Uncaught error: java.lang.Exception: illegal pattern: Blk(...) +//│ ╔══[ERROR] illegal pattern +//│ ║ l.53: Pair +//│ ║ ^^^^ +//│ ║ l.54: Int +//│ ╙── ^^^^^ +//│ foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared // TODO proper error fun foo(x) = x is Pair(a, b) and a > b Int -//│ /!!!\ Uncaught error: java.lang.Exception: illegal pattern: Blk(...) +//│ ╔══[ERROR] illegal pattern +//│ ║ l.66: Pair(a, b) and a > b +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.67: Int +//│ ╙── ^^^^^ +//│ foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared // TODO support `|` fun foo(x) = x is Pair(a, b) | Int fun foo(x) = x is (Pair(a, b) and a > b) | Int //│ ╔══[ERROR] Cannot find operator `|` in the context -//│ ║ l.64: fun foo(x) = x is Pair(a, b) | Int +//│ ║ l.78: fun foo(x) = x is Pair(a, b) | Int //│ ╙── ^ //│ foo: anything -> error //│ ╔══[ERROR] Cannot find operator `|` in the context -//│ ║ l.65: fun foo(x) = x is (Pair(a, b) and a > b) | Int +//│ ║ l.79: fun foo(x) = x is (Pair(a, b) and a > b) | Int //│ ╙── ^ //│ foo: anything -> error //│ Code generation encountered an error: -//│ if expression has not been desugared +//│ if expression was not desugared From 46035aef3749eb26590a8a5ea9cd46a32d096197 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 13 Mar 2023 12:41:49 +0800 Subject: [PATCH 187/498] WIP Add SelfRec test cases and harden TypeRef expansion --- .../src/main/scala/mlscript/NormalForms.scala | 6 +- .../main/scala/mlscript/TypeSimplifier.scala | 3 +- .../main/scala/mlscript/TyperHelpers.scala | 36 ++++-- shared/src/test/diff/ecoop23/Intro.mls | 2 +- shared/src/test/diff/nu/FilterMap.mls | 2 +- shared/src/test/diff/nu/GenericClasses.mls | 2 +- shared/src/test/diff/nu/MetaWrap.mls | 6 +- shared/src/test/diff/nu/MutualRec.mls | 10 +- shared/src/test/diff/nu/SelfRec.mls | 110 ++++++++++++++++++ 9 files changed, 151 insertions(+), 26 deletions(-) diff --git a/shared/src/main/scala/mlscript/NormalForms.scala b/shared/src/main/scala/mlscript/NormalForms.scala index 38db2d725b..c84f6b8e34 100644 --- a/shared/src/main/scala/mlscript/NormalForms.scala +++ b/shared/src/main/scala/mlscript/NormalForms.scala @@ -703,7 +703,7 @@ class NormalForms extends TyperDatatypes { self: Typer => // * TODO later: when proper TypeRef-based simplif. is implemented, can remove this special case if (preserveTypeRefs && !primitiveTypes.contains(defn.name) || !tr.canExpand) { of(polymLvl, cons, LhsRefined(tr.mkTag, ssEmp, RecordType.empty, SortedMap(defn -> tr))) - } else mk(polymLvl, cons, tr.expand, pol) + } else mk(polymLvl, cons, tr.expandOrCrash, pol) case TypeBounds(lb, ub) => mk(polymLvl, cons, if (pol) ub else lb, pol) case PolymorphicType(lvl, bod) => mk(lvl, cons, bod, pol) case ConstrainedType(cs, bod) => mk(polymLvl, cs ::: cons, bod, pol) @@ -743,9 +743,9 @@ class NormalForms extends TyperDatatypes { self: Typer => case tv: TypeVariable => of(SortedSet.single(tv)) case ProxyType(underlying) => mk(polymLvl, cons, underlying, pol) case tr @ TypeRef(defn, targs) => - if (preserveTypeRefs && !primitiveTypes.contains(defn.name)) { + if (preserveTypeRefs && !primitiveTypes.contains(defn.name) || !tr.canExpand) { CNF(Disjunct(RhsBases(Nil, N, SortedMap.single(defn -> tr)), ssEmp, LhsTop, ssEmp) :: Nil) - } else mk(polymLvl, cons, tr.expand, pol) + } else mk(polymLvl, cons, tr.expandOrCrash, pol) case TypeBounds(lb, ub) => mk(polymLvl, cons, if (pol) ub else lb, pol) case PolymorphicType(lvl, bod) => mk(lvl, cons, bod, pol) case ConstrainedType(cs, bod) => mk(lvl, cs ::: cons, bod, pol) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index f57c6688b4..5155080b31 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -90,7 +90,8 @@ trait TypeSimplifier { self: Typer => ProvType(process(ty, parent, canDistribForall = canDistribForall))(ty.prov) case ProvType(ty) => process(ty, parent, canDistribForall = canDistribForall) - case tr @ TypeRef(defn, targs) if builtinTypes.contains(defn) => process(tr.expand, parent) + case tr @ TypeRef(defn, targs) if builtinTypes.contains(defn) && tr.canExpand => + process(tr.expandOrCrash, parent) case RecordType(fields) => RecordType.mk(fields.flatMap { case (v @ Var(fnme), fty) => // * We make a pass to transform the LB and UB of variant type parameter fields into their exterma diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 036f1b6a09..2715c2bda8 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -513,9 +513,9 @@ abstract class TyperHelpers { Typer: Typer => case (_, NegType(und)) => (this & und) <:< BotType case (NegType(und), _) => TopType <:< (that | und) case (tr: TypeRef, _) - if (primitiveTypes contains tr.defn.name) => tr.expand <:< that + if (primitiveTypes contains tr.defn.name) && tr.canExpand => tr.expandOrCrash <:< that case (_, tr: TypeRef) - if (primitiveTypes contains tr.defn.name) => this <:< tr.expand + if (primitiveTypes contains tr.defn.name) && tr.canExpand => this <:< tr.expandOrCrash case (tr1: TypeRef, _) => ctx.tyDefs.get(tr1.defn.name) match { case S(td1) => that match { @@ -604,7 +604,7 @@ abstract class TyperHelpers { Typer: Typer => case ct: ConstrainedType => ct } def unwrapAll(implicit ctx: Ctx): SimpleType = unwrapProxies match { - case tr: TypeRef => tr.expand.unwrapAll + case tr: TypeRef if tr.canExpand => tr.expandOrCrash.unwrapAll case u => u } def negNormPos(f: SimpleType => SimpleType, p: TypeProvenance) @@ -613,7 +613,7 @@ abstract class TyperHelpers { Typer: Typer => case ComposedType(true, l, r) => l.negNormPos(f, p) & r.negNormPos(f, p) case ComposedType(false, l, r) => l.negNormPos(f, p) | r.negNormPos(f, p) case NegType(n) => f(n).withProv(p) - case tr: TypeRef if !preserveTypeRefs => tr.expand.negNormPos(f, p) + case tr: TypeRef if !preserveTypeRefs && tr.canExpand => tr.expandOrCrash.negNormPos(f, p) case _: RecordType | _: FunctionType => BotType // Only valid in positive positions! // Because Top<:{x:S}|{y:T}, any record type negation neg{x:S}<:{y:T} for any y=/=x, // meaning negated records are basically bottoms. @@ -962,8 +962,22 @@ abstract class TyperHelpers { Typer: Typer => trait TypeRefImpl { self: TypeRef => - def canExpand(implicit ctx: Ctx): Bool = ctx.tyDefs2.get(defn.name).forall(_.result.isDefined) - def expand(implicit ctx: Ctx): SimpleType = expandWith(paramTags = true) + def canExpand(implicit ctx: Ctx): Bool = + ctx.tyDefs2.get(defn.name).forall(_.result.isDefined) + def expand(implicit ctx: Ctx, raise: Raise): SimpleType = { + ctx.tyDefs2.get(defn.name) match { + case S(lti) => + lti.complete() + if (lti.result.isEmpty) // * This can only happen if completion yielded an error + return errType + case N => + } + expandWith(paramTags = true) + } + def expandOrCrash(implicit ctx: Ctx): SimpleType = { + require(canExpand) + expandWith(paramTags = true) + } def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = //if (defn.name.isCapitalized) { ctx.tyDefs2.get(defn.name).map { info => info.result match { @@ -1007,7 +1021,13 @@ abstract class TyperHelpers { Typer: Typer => def mkTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { val res = ctx.tyDefs.get(defn.name) match { case S(td: TypeDef) if td.kind is Cls => S(clsNameToNomTag(td)(noProv, ctx)) - case _ => N + case _ => ctx.tyDefs2.get(defn.name) match { + case S(lti) => lti.decl match { + case td: NuTypeDef if td.kind is Cls => S(clsNameToNomTag(td)(noProv, ctx)) + case _ => N + } + case _ => N + } } tag = S(res) res @@ -1203,7 +1223,7 @@ abstract class TyperHelpers { Typer: Typer => object AliasOf { def unapply(ty: ST)(implicit ctx: Ctx): S[ST] = { def go(ty: ST, traversedVars: Set[TV]): S[ST] = ty match { - case tr: TypeRef => go(tr.expand, traversedVars) + case tr: TypeRef if tr.canExpand => go(tr.expandOrCrash, traversedVars) case proxy: ProxyType => go(proxy.underlying, traversedVars) case tv @ AssignedVariable(ty) if !traversedVars.contains(tv) => go(ty, traversedVars + tv) diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index f94c55b600..b659ebde50 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -88,7 +88,7 @@ mixin CompareNested { class MyPoint(x: int, y: int, color: Color, parent: Some[MyPoint] | None) -//│ class MyPoint(x: int, y: int, color: Color, parent: None | Some[MyPoint]) +//│ class MyPoint(x: int, y: int, color: Color, parent: Some[MyPoint] | None) module CompareMyPoint extends ComparePoint, CompareColored, CompareNested diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 29fd53758e..8c5cd4dd2e 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -51,7 +51,7 @@ fun filtermap(f, xs) = if xs is //│ ╙── ^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── -//│ fun filtermap: ((error | Cons[nothing] | Nil) -> number & (Cons[nothing] | Nil) -> error, Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) +//│ fun filtermap: ((Cons[nothing] | error | Nil) -> number & (Cons[nothing] | Nil) -> error, Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index db8e40649e..883cd83f0b 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -109,7 +109,7 @@ None.toArray type Option = Some | None -//│ type Option[A] = None | Some[A] +//│ type Option[A] = Some[A] | None diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index 5fadcacd0b..e8b3adcaa1 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -74,9 +74,9 @@ module Test1 extends Base, WithUid, WithType //│ module Test1() { //│ fun getType: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty //│ fun getUid: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: 'ty0 | Type, underlying: 'underlying0}} -//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, ty: Type,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: 'ty0 | Type, underlying: 'underlying0}} -//│ fun setUid: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: 'ty0 | Type, underlying: 'underlying0}} +//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, ty: Type,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun setUid: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} //│ fun unwrap: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying //│ } diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 3fe23e7dc7..c415772c02 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -212,15 +212,9 @@ class Test2(n: int) { module Test3 { fun inc(t: Test2) = Test2(t.n + 1) } -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.213: fun inc(t: Test2) = Test2(t.n + 1) -//│ ║ ^^^ -//│ ╟── type `Test2` does not have field 'n' -//│ ║ l.213: fun inc(t: Test2) = Test2(t.n + 1) -//│ ║ ^^^^^ -//│ ╟── but it flows into reference with expected type `{n: ?n}` +//│ ╔══[ERROR] unsupported indirectly recursive member access //│ ║ l.213: fun inc(t: Test2) = Test2(t.n + 1) -//│ ╙── ^ +//│ ╙── ^^ //│ class Test2(n: int) { //│ fun inc: Test2 | error //│ } diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index eb7c10bbc7..d1cd843441 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -54,4 +54,114 @@ Foo3(1).foo //│ res //│ = [Function (anonymous)] { class: [class Foo3] } +:e +class Foo4 { + fun test = [Foo4.test] +} +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.59: fun test = [Foo4.test] +//│ ║ ^^^^^^^^^ +//│ ╟── reference of type `() -> #Foo4` does not have field 'test' +//│ ║ l.59: fun test = [Foo4.test] +//│ ╙── ^^^^ +//│ class Foo4() { +//│ fun test: (error,) +//│ } + +:e +class Foo5(x: int) { + fun test = [Foo5(5).test] +} +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.73: fun test = [Foo5(5).test] +//│ ╙── ^^^^^ +//│ class Foo5(x: int) { +//│ fun test: (error,) +//│ } + +:e +class Foo6[A](x: A) { + fun test1 = [Foo6(x).test] + fun test2 = [Foo6(123).test] + fun test3 = [Foo6([x]).test] +} +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.84: fun test1 = [Foo6(x).test] +//│ ╙── ^^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.85: fun test2 = [Foo6(123).test] +//│ ╙── ^^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.86: fun test3 = [Foo6([x]).test] +//│ ╙── ^^^^^ +//│ class Foo6[A](x: A) { +//│ fun test1: (error,) +//│ fun test2: (error,) +//│ fun test3: (error,) +//│ } + +:e +class Foo7[A](head: A, tail: Foo7[A] | 0) { + fun test1 = if tail is + 0 then head + _ then tail.test1 +} +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.104: class Foo7[A](head: A, tail: Foo7[A] | 0) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.105: fun test1 = if tail is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.106: 0 then head +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.107: _ then tail.test1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.108: } +//│ ╙── ^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.107: _ then tail.test1 +//│ ╙── ^^^^^^ +//│ class Foo7[A](head: A, tail: 0 | Foo7[A]) { +//│ fun test1: A | error +//│ } + +// TODO support +class Foo7_A[A](head: A, tail: Foo7_A[A] | 0) { + fun test1: A = if tail is + 0 then head + _ then tail.test1 +} +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.128: class Foo7_A[A](head: A, tail: Foo7_A[A] | 0) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.129: fun test1: A = if tail is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.130: 0 then head +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.131: _ then tail.test1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.132: } +//│ ╙── ^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.131: _ then tail.test1 +//│ ╙── ^^^^^^ +//│ class Foo7_A[A](head: A, tail: 0 | Foo7_A[A]) { +//│ fun test1: A +//│ } + +:e +class Foo8[A](x: A) { + fun test1[B](y: B): A = + let tmp = Foo6(y).test1(x) + x +} +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.154: let tmp = Foo6(y).test1(x) +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── field selection of type `(?test,)` is not a function +//│ ║ l.154: let tmp = Foo6(y).test1(x) +//│ ╙── ^^^^^^^^^^^^^ +//│ class Foo8[A](x: A) { +//│ fun test1: (y: anything,) -> A +//│ } + From 3c9f9a1ed4a7812829436a68b641dbb6912dd527 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Mon, 13 Mar 2023 13:11:12 +0800 Subject: [PATCH 188/498] Gather lambda calculus test files --- shared/src/test/diff/tapl/NuSimplyTyped.mls | 206 +++++++ .../{ucs/Lambda.mls => tapl/NuUntyped.mls} | 0 shared/src/test/diff/tapl/SimplyTyped.mls | 396 +++++++++---- shared/src/test/diff/tapl/Untyped.mls | 534 ++++++++++++++++++ 4 files changed, 1020 insertions(+), 116 deletions(-) create mode 100644 shared/src/test/diff/tapl/NuSimplyTyped.mls rename shared/src/test/diff/{ucs/Lambda.mls => tapl/NuUntyped.mls} (100%) create mode 100644 shared/src/test/diff/tapl/Untyped.mls diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls new file mode 100644 index 0000000000..27d360521b --- /dev/null +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -0,0 +1,206 @@ +:NewParser +:NewDefs + +:escape +// You can push debug messages to this magic array. +let Array: { from: anything => { push: anything => anything, join: string => string } } +let _Array = Array +let logs: { push: anything => anything, join: string => string } = _Array.from([]) +let debug: anything => anything = x => logs.push(x) +fun showDebug = logs.join("\n") +//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let logs: {join: string -> string, push: anything -> anything} +//│ let debug: anything -> anything +//│ fun showDebug: string +//│ Array +//│ = +//│ _Array +//│ = [Function: Array] +//│ logs +//│ = [] +//│ debug +//│ = [Function: debug] + +fun concat2(a, b) = concat(a)(b) +fun concat3(a, b, c) = concat2(a, concat2(b, c)) +fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) +fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) +fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) +fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) +fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) +fun par(a) = concat3("(", a, ")") +//│ fun concat2: (string, string,) -> string +//│ fun concat3: (string, string, string,) -> string +//│ fun concat4: (string, string, string, string,) -> string +//│ fun concat5: (string, string, string, string, string,) -> string +//│ fun concat6: (string, string, string, string, string, string,) -> string +//│ fun concat7: (string, string, string, string, string, string, string,) -> string +//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string +//│ fun par: string -> string + +type Option[A] = Some[A] | None +class Some[A](value: A) +module None +//│ type Option[A] = None | Some[A] +//│ class Some[A](value: A) +//│ module None() + +type Result[A, B] = Ok[A] | Err[B] +class Ok[A](value: A) +class Err[A](message: A) +//│ type Result[A, B] = Err[B] | Ok[A] +//│ class Ok[A](value: A) +//│ class Err[A](message: A) + +type Type = FunctionType | PrimitiveType +class FunctionType(lhs: Type, rhs: Type) +class PrimitiveType(name: string) +//│ type Type = FunctionType | PrimitiveType +//│ class FunctionType(lhs: Type, rhs: Type) +//│ class PrimitiveType(name: string) + +// Helpers. +fun _f(lhs, rhs) = FunctionType(lhs, rhs) +fun _t(name) = PrimitiveType(name) +//│ fun _f: (Type, Type,) -> FunctionType +//│ fun _t: string -> PrimitiveType + +type Term = Lit | Var | Abs | App +class Lit(tag: string, ty: Type) +class Var(name: string) +class Abs(lhs: Var, lty: Type, rhs: Term) +class App(lhs: Term, rhs: Term) +// class App(lhs: Term, rhs: Term): Term +//│ type Term = Abs | App | Lit | Var +//│ class Lit(tag: string, ty: Type) +//│ class Var(name: string) +//│ class Abs(lhs: Var, lty: Type, rhs: Term) +//│ class App(lhs: Term, rhs: Term) + +class Assumption(name: string, ty: Type) +//│ class Assumption(name: string, ty: Type) + +type Tree[A] = Node[A] | Empty +class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) +module Empty +//│ type Tree[A] = Empty | Node[A] +//│ class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) +//│ module Empty() + +fun insert(t, k, v) = + if t is + Node(k', _, l, r) and + slt(k)(k') then Node(k', v, insert(l, k, v), r) + sgt(k)(k') then Node(k', v, l, insert(r, k, v)) + _ then Node(k, v, l, r) + Empty then Node(k, v, Empty, Empty) +fun find(t, k) = + if t is + Node(k', v, l, r) and + slt(k)(k') then find(l, k) + sgt(k)(k') then find(r, k) + _ then Some(v) + Empty then None +//│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] +//│ fun find: forall 'A0. (Empty | Node['A0], string,) -> (None | Some['A0]) + +fun showType(ty) = + if ty is + FunctionType(PrimitiveType(name), rhs) then concat3(name, " -> ", showType(rhs)) + FunctionType(lhs, rhs) then concat4("(", showType(lhs), ") -> ", showType(rhs)) + PrimitiveType(name) then name +//│ fun showType: (FunctionType | PrimitiveType) -> string + +showType(_t("int")) +showType(_f(_t("int"), _t("bool"))) +showType(_f(_f(_t("int"), _t("bool")), _t("bool"))) +showType(_f(_t("bool"), _f(_t("int"), _t("bool")))) +//│ string +//│ res +//│ = 'int' +//│ res +//│ = 'int -> bool' +//│ res +//│ = '(int -> bool) -> bool' +//│ res +//│ = 'bool -> int -> bool' + +fun typeEqual(t1, t2) = + if + t1 is PrimitiveType(name1) and t2 is PrimitiveType(name2) then eq(name1)(name2) + t1 is FunctionType(lhs1, rhs1) and t2 is FunctionType(lhs2, rhs2) then + typeEqual(lhs1, lhs2) and typeEqual(rhs1, rhs2) + _ then false +//│ fun typeEqual: (anything, anything,) -> bool + +fun showTerm(t) = + if t is + Lit(tag, _) then toString(tag) + Var(name) then toString(name) + Abs(lhs, ty, rhs) then concat6("&", showTerm(lhs), ": ", showType(ty), " => ", showTerm(rhs)) + App(Abs(lhs0, ty, lhs1), rhs) then + concat5("((", showTerm(Abs(lhs0, ty, rhs)), ") ", showTerm(rhs), ")") + App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) +//│ fun showTerm: (Abs | App | Lit | Var) -> string + +showTerm(Var("x")) +showTerm(Abs(Var("x"), _t("int"), Var("y"))) +showTerm(App(Var("x"), Var("y"))) +showTerm(App(Abs(Var("x"), _t("int"), Var("y")), Var("z"))) +//│ string +//│ res +//│ = 'x' +//│ res +//│ = '&x: int => y' +//│ res +//│ = '(x y)' +//│ res +//│ = '((&x: int => z) z)' + +// Removing the return type annotation causes stack overflow. +fun typeTerm(t, ctx): Result[Type, string] = + if t is + Lit(_, ty) then Ok(ty) + Var(name) and find(ctx, name) is + Some(ty) then Ok(ty) + None then Err(concat3("unbound variable `", name, "`")) + Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is + Ok(resTy) then Ok(FunctionType(ty, resTy)) + Err(message) then Err(message) + App(lhs, rhs) and typeTerm(lhs, ctx) is + Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is + Ok(aTy) and + typeEqual(pTy, aTy) then Ok(resTy) + else Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) + Err(message) then Err(message) + Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) + Err(message) then Err(message) +//│ fun typeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> Result[Type, string] +//│ where +//│ 'A := Type + +fun showTypeTerm(t, ctx) = + if typeTerm(t, ctx) is + Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) + Err(message) then concat2("Type error: ", message) +//│ fun showTypeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> string +//│ where +//│ 'A := Type + +showTypeTerm(Var("x"), Empty) +showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), Empty) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0.2", _t("float"))), insert(Empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _t("string"))) +//│ string +//│ res +//│ = 'Type error: unbound variable `x`' +//│ res +//│ = '&x: int => x : int -> int' +//│ res +//│ = '(f 0) : int' +//│ res +//│ = 'Type error: expect the argument to be of type `int` but found `float`' +//│ res +//│ = 'Type error: cannot apply primitive type `string`' diff --git a/shared/src/test/diff/ucs/Lambda.mls b/shared/src/test/diff/tapl/NuUntyped.mls similarity index 100% rename from shared/src/test/diff/ucs/Lambda.mls rename to shared/src/test/diff/tapl/NuUntyped.mls diff --git a/shared/src/test/diff/tapl/SimplyTyped.mls b/shared/src/test/diff/tapl/SimplyTyped.mls index 27d360521b..eecd08ede5 100644 --- a/shared/src/test/diff/tapl/SimplyTyped.mls +++ b/shared/src/test/diff/tapl/SimplyTyped.mls @@ -1,5 +1,4 @@ :NewParser -:NewDefs :escape // You can push debug messages to this magic array. @@ -8,19 +7,16 @@ let _Array = Array let logs: { push: anything => anything, join: string => string } = _Array.from([]) let debug: anything => anything = x => logs.push(x) fun showDebug = logs.join("\n") -//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let logs: {join: string -> string, push: anything -> anything} -//│ let debug: anything -> anything -//│ fun showDebug: string -//│ Array -//│ = -//│ _Array -//│ = [Function: Array] -//│ logs -//│ = [] -//│ debug -//│ = [Function: debug] +//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = +//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = [Function: Array] +//│ logs: {join: string -> string, push: anything -> anything} +//│ = [] +//│ debug: anything -> anything +//│ = [Function: debug] +//│ showDebug: string +//│ = [Function: showDebug] fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) @@ -30,101 +26,161 @@ fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) fun par(a) = concat3("(", a, ")") -//│ fun concat2: (string, string,) -> string -//│ fun concat3: (string, string, string,) -> string -//│ fun concat4: (string, string, string, string,) -> string -//│ fun concat5: (string, string, string, string, string,) -> string -//│ fun concat6: (string, string, string, string, string, string,) -> string -//│ fun concat7: (string, string, string, string, string, string, string,) -> string -//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string -//│ fun par: string -> string - -type Option[A] = Some[A] | None -class Some[A](value: A) -module None -//│ type Option[A] = None | Some[A] -//│ class Some[A](value: A) -//│ module None() - -type Result[A, B] = Ok[A] | Err[B] -class Ok[A](value: A) -class Err[A](message: A) -//│ type Result[A, B] = Err[B] | Ok[A] -//│ class Ok[A](value: A) -//│ class Err[A](message: A) - -type Type = FunctionType | PrimitiveType -class FunctionType(lhs: Type, rhs: Type) -class PrimitiveType(name: string) -//│ type Type = FunctionType | PrimitiveType -//│ class FunctionType(lhs: Type, rhs: Type) -//│ class PrimitiveType(name: string) +//│ concat2: (string, string,) -> string +//│ = [Function: concat2] +//│ concat3: (string, string, string,) -> string +//│ = [Function: concat3] +//│ concat4: (string, string, string, string,) -> string +//│ = [Function: concat4] +//│ concat5: (string, string, string, string, string,) -> string +//│ = [Function: concat5] +//│ concat6: (string, string, string, string, string, string,) -> string +//│ = [Function: concat6] +//│ concat7: (string, string, string, string, string, string, string,) -> string +//│ = [Function: concat7] +//│ concat8: (string, string, string, string, string, string, string, string,) -> string +//│ = [Function: concat8] +//│ par: string -> string +//│ = [Function: par] + +class Option +class Some(value): Option +class None(): Option +//│ Defined class Option +//│ Defined class Some +//│ Defined class None +//│ Option: () -> Option +//│ = [Function: Option1] +//│ Some: 'value -> (Some & {value: 'value}) +//│ = [Function: Some1] +//│ None: () -> None +//│ = [Function: None1] + +class Result +class Ok(value): Result +class Err(message): Result +//│ Defined class Result +//│ Defined class Ok +//│ Defined class Err +//│ Result: () -> Result +//│ = [Function: Result1] +//│ Ok: 'value -> (Ok & {value: 'value}) +//│ = [Function: Ok1] +//│ Err: 'message -> (Err & {message: 'message}) +//│ = [Function: Err1] + +class Type +class FunctionType(lhs, rhs): Type +class PrimitiveType(name): Type +//│ Defined class Type +//│ Defined class FunctionType +//│ Defined class PrimitiveType +//│ Type: () -> Type +//│ = [Function: Type1] +//│ FunctionType: ('lhs, 'rhs,) -> (FunctionType & {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: FunctionType1] +//│ PrimitiveType: 'name -> (PrimitiveType & {name: 'name}) +//│ = [Function: PrimitiveType1] // Helpers. fun _f(lhs, rhs) = FunctionType(lhs, rhs) fun _t(name) = PrimitiveType(name) -//│ fun _f: (Type, Type,) -> FunctionType -//│ fun _t: string -> PrimitiveType - -type Term = Lit | Var | Abs | App -class Lit(tag: string, ty: Type) -class Var(name: string) -class Abs(lhs: Var, lty: Type, rhs: Term) -class App(lhs: Term, rhs: Term) +//│ _f: ('lhs, 'rhs,) -> (FunctionType & {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: _f] +//│ _t: 'name -> (PrimitiveType & {name: 'name}) +//│ = [Function: _t] + +class Term +class Lit(tag, ty): Term +class Var(name): Term +class Abs(lhs, lty, rhs): Term +class App(lhs, rhs): Term // class App(lhs: Term, rhs: Term): Term -//│ type Term = Abs | App | Lit | Var -//│ class Lit(tag: string, ty: Type) -//│ class Var(name: string) -//│ class Abs(lhs: Var, lty: Type, rhs: Term) -//│ class App(lhs: Term, rhs: Term) - -class Assumption(name: string, ty: Type) -//│ class Assumption(name: string, ty: Type) - -type Tree[A] = Node[A] | Empty -class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) -module Empty -//│ type Tree[A] = Empty | Node[A] -//│ class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) -//│ module Empty() +//│ Defined class Term +//│ Defined class Lit +//│ Defined class Var +//│ Defined class Abs +//│ Defined class App +//│ Term: () -> Term +//│ = [Function: Term1] +//│ Lit: ('tag, 'ty,) -> (Lit & {tag: 'tag, ty: 'ty}) +//│ = [Function: Lit1] +//│ Var: 'name -> (Var & {name: 'name}) +//│ = [Function: Var1] +//│ Abs: ('lhs, 'lty, 'rhs,) -> (Abs & {lhs: 'lhs, lty: 'lty, rhs: 'rhs}) +//│ = [Function: Abs1] +//│ App: ('lhs, 'rhs,) -> (App & {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: App1] +class Assumption(name, ty) +//│ Defined class Assumption +//│ Assumption: ('name, 'ty,) -> (Assumption & {name: 'name, ty: 'ty}) +//│ = [Function: Assumption1] + +class Tree +class Node(key, value, left, right): Tree +class Empty(): Tree +//│ Defined class Tree +//│ Defined class Node +//│ Defined class Empty +//│ Tree: () -> Tree +//│ = [Function: Tree1] +//│ Node: ('key, 'value, 'left, 'right,) -> (Node & {key: 'key, left: 'left, right: 'right, value: 'value}) +//│ = [Function: Node1] +//│ Empty: () -> Empty +//│ = [Function: Empty1] + +fun empty = Empty() fun insert(t, k, v) = if t is Node(k', _, l, r) and slt(k)(k') then Node(k', v, insert(l, k, v), r) sgt(k)(k') then Node(k', v, l, insert(r, k, v)) _ then Node(k, v, l, r) - Empty then Node(k, v, Empty, Empty) + Empty then Node(k, v, empty, empty) fun find(t, k) = if t is Node(k', v, l, r) and slt(k)(k') then find(l, k) sgt(k)(k') then find(r, k) _ then Some(v) - Empty then None -//│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] -//│ fun find: forall 'A0. (Empty | Node['A0], string,) -> (None | Some['A0]) + Empty then None() +//│ empty: Empty +//│ = [Function: empty] +//│ insert: ('a, string & 'key, 'value,) -> 'right +//│ where +//│ 'right :> Node & {key: 'key, left: Empty | 'left | 'right, right: Empty | 'right | 'right0, value: 'value} +//│ 'a <: Empty | Node & {key: string & 'key, left: 'left, right: 'right0} +//│ 'right0 <: 'a +//│ 'left <: 'a +//│ = [Function: insert] +//│ find: ('right, string,) -> (Some & {value: 'value} | None) +//│ where +//│ 'right <: Empty | Node & {key: string, left: 'right, right: 'right, value: 'value} +//│ = [Function: find] fun showType(ty) = if ty is FunctionType(PrimitiveType(name), rhs) then concat3(name, " -> ", showType(rhs)) FunctionType(lhs, rhs) then concat4("(", showType(lhs), ") -> ", showType(rhs)) PrimitiveType(name) then name -//│ fun showType: (FunctionType | PrimitiveType) -> string +//│ showType: 'lhs -> string +//│ where +//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} +//│ = [Function: showType] showType(_t("int")) showType(_f(_t("int"), _t("bool"))) showType(_f(_f(_t("int"), _t("bool")), _t("bool"))) showType(_f(_t("bool"), _f(_t("int"), _t("bool")))) -//│ string -//│ res -//│ = 'int' -//│ res -//│ = 'int -> bool' -//│ res -//│ = '(int -> bool) -> bool' -//│ res -//│ = 'bool -> int -> bool' +//│ res: string +//│ = 'int' +//│ res: string +//│ = 'int -> bool' +//│ res: string +//│ = '(int -> bool) -> bool' +//│ res: string +//│ = 'bool -> int -> bool' fun typeEqual(t1, t2) = if @@ -132,7 +188,10 @@ fun typeEqual(t1, t2) = t1 is FunctionType(lhs1, rhs1) and t2 is FunctionType(lhs2, rhs2) then typeEqual(lhs1, lhs2) and typeEqual(rhs1, rhs2) _ then false -//│ fun typeEqual: (anything, anything,) -> bool +//│ typeEqual: ('rhs, 'rhs,) -> bool +//│ where +//│ 'rhs <: FunctionType & {lhs: 'rhs, rhs: 'rhs} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ = [Function: typeEqual] fun showTerm(t) = if t is @@ -142,24 +201,27 @@ fun showTerm(t) = App(Abs(lhs0, ty, lhs1), rhs) then concat5("((", showTerm(Abs(lhs0, ty, rhs)), ") ", showTerm(rhs), ")") App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) -//│ fun showTerm: (Abs | App | Lit | Var) -> string +//│ showTerm: 'rhs -> string +//│ where +//│ 'rhs <: Abs & {lhs: 'rhs, lty: 'lty, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, lty: 'lty} | ~#Abs), rhs: 'rhs} | Lit | Var +//│ 'lty <: FunctionType & {lhs: 'lty & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lty} | PrimitiveType & {name: string} +//│ = [Function: showTerm] showTerm(Var("x")) showTerm(Abs(Var("x"), _t("int"), Var("y"))) showTerm(App(Var("x"), Var("y"))) showTerm(App(Abs(Var("x"), _t("int"), Var("y")), Var("z"))) -//│ string -//│ res -//│ = 'x' -//│ res -//│ = '&x: int => y' -//│ res -//│ = '(x y)' -//│ res -//│ = '((&x: int => z) z)' - -// Removing the return type annotation causes stack overflow. -fun typeTerm(t, ctx): Result[Type, string] = +//│ res: string +//│ = 'x' +//│ res: string +//│ = '&x: int => y' +//│ res: string +//│ = '(x y)' +//│ res: string +//│ = '((&x: int => z) z)' + +// FIXME +fun typeTerm(t, ctx) = if t is Lit(_, ty) then Ok(ty) Var(name) and find(ctx, name) is @@ -172,35 +234,137 @@ fun typeTerm(t, ctx): Result[Type, string] = Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is Ok(aTy) and typeEqual(pTy, aTy) then Ok(resTy) - else Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) + _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) Err(message) then Err(message) Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) Err(message) then Err(message) -//│ fun typeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> Result[Type, string] +//│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required +//│ ║ l.224: fun typeTerm(t, ctx) = +//│ ║ ^^^^^^^^^^ +//│ ║ l.225: if t is +//│ ║ ^^^^^^^^^ +//│ ║ l.226: Lit(_, ty) then Ok(ty) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.227: Var(name) and find(ctx, name) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.228: Some(ty) then Ok(ty) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.229: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.230: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.231: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.232: Err(message) then Err(message) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.233: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.234: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.235: Ok(aTy) and +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.238: Err(message) then Err(message) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.239: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.240: Err(message) then Err(message) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required +//│ ║ l.224: fun typeTerm(t, ctx) = +//│ ║ ^^^^^^^^^^ +//│ ║ l.225: if t is +//│ ║ ^^^^^^^^^ +//│ ║ l.226: Lit(_, ty) then Ok(ty) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.227: Var(name) and find(ctx, name) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.228: Some(ty) then Ok(ty) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.229: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.230: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.231: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.232: Err(message) then Err(message) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.233: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.234: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.235: Ok(aTy) and +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.236: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.237: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.238: Err(message) then Err(message) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.239: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.240: Err(message) then Err(message) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ typeTerm: ('rhs, 'right,) -> (Err & {message: 'message} | Ok & {value: 'ty}) //│ where -//│ 'A := Type +//│ 'message :> string +//│ 'right <: 'right0 & (Empty | Node & {key: string, left: 'right, right: 'right}) +//│ 'right0 <: Empty | Node & {key: string, left: 'right0, right: 'right0, value: 'ty & 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType))} +//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'lhs & 'lty & 'rhs0 & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)), rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'ty & 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType))} | Var & {name: string} +//│ 'a <: {lhs: 'rhs0 & 'lhs, rhs: 'rhs1} +//│ 'rhs1 :> 'ty +//│ <: 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) +//│ 'b <: {lhs: 'rhs2, rhs: 'rhs2} +//│ 'rhs2 <: FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'ty :> 'lty | FunctionType & {lhs: 'lty, rhs: 'ty} | 'rhs1 +//│ 'rhs0 <: FunctionType & {lhs: 'rhs0, rhs: 'rhs0} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} +//│ = [Function: typeTerm] +// FIXME fun showTypeTerm(t, ctx) = if typeTerm(t, ctx) is Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) Err(message) then concat2("Type error: ", message) -//│ fun showTypeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> string +//│ showTypeTerm: ('rhs & 'rhs0, 'right & (Empty | Node & 'a),) -> string //│ where -//│ 'A := Type - -showTypeTerm(Var("x"), Empty) -showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), Empty) -showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _f(_t("int"), _t("int")))) -showTypeTerm(App(Var("f"), Lit("0.2", _t("float"))), insert(Empty, "f", _f(_t("int"), _t("int")))) -showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _t("string"))) -//│ string -//│ res -//│ = 'Type error: unbound variable `x`' -//│ res -//│ = '&x: int => x : int -> int' -//│ res -//│ = '(f 0) : int' -//│ res -//│ = 'Type error: expect the argument to be of type `int` but found `float`' -//│ res -//│ = 'Type error: cannot apply primitive type `string`' +//│ 'a <: {key: string, left: 'right0, right: 'right0} +//│ 'right0 <: 'right1 & (Empty | Node & 'a) +//│ 'right1 <: Empty | Node & {key: string, left: 'right1, right: 'right1, value: 'rhs1} +//│ 'rhs1 <: 'lhs & (FunctionType & {lhs: 'rhs2 & 'lhs, rhs: 'rhs1} & ~#FunctionType | FunctionType & {lhs: 'rhs2 & 'lhs, rhs: 'rhs1} & 'b | PrimitiveType & {name: string}) +//│ 'b <: {lhs: 'rhs3, rhs: 'rhs3} +//│ 'rhs3 <: FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'right <: Empty | Node & {key: string, left: 'right, right: 'right, value: 'rhs4} +//│ 'rhs4 <: 'lhs & (FunctionType & {lhs: 'rhs2 & 'lhs, rhs: 'rhs4} & ~#FunctionType | FunctionType & {lhs: 'rhs2 & 'lhs, rhs: 'rhs4} & 'c | PrimitiveType & {name: string}) +//│ 'c <: {lhs: 'rhs5, rhs: 'rhs5} +//│ 'rhs5 <: FunctionType & 'c | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'rhs0 <: Abs & {lhs: 'rhs0, lty: 'lhs, rhs: 'rhs0} | App & {lhs: 'rhs0 & (Abs & {lhs: 'rhs0, lty: 'lhs} | ~#Abs), rhs: 'rhs0} | Lit | Var +//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'rhs2 & 'lhs & 'rhs6, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'rhs6} | Var & {name: string} +//│ 'rhs6 <: 'lhs & (PrimitiveType & {name: string} | {lhs: 'rhs2 & 'lhs, rhs: 'rhs6} & (FunctionType & 'd | FunctionType & ~#FunctionType)) +//│ 'd <: {lhs: 'rhs7, rhs: 'rhs7} +//│ 'rhs7 <: FunctionType & 'd | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} +//│ 'rhs2 <: FunctionType & {lhs: 'rhs2, rhs: 'rhs2} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ = [Function: showTypeTerm] + +// FIXME +showTypeTerm(Var("x"), empty) +showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), empty) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0.2", _t("float"))), insert(empty, "f", _f(_t("int"), _t("int")))) +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(empty, "f", _t("string"))) +//│ res: string +//│ = 'Type error: unbound variable `x`' +//│ res: string +//│ = '&x: int => x : int -> int' +//│ res: string +//│ = '(f 0) : int' +//│ res: string +//│ = 'Type error: expect the argument to be of type `int` but found `float`' +//│ res: string +//│ = 'Type error: cannot apply primitive type `string`' diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls new file mode 100644 index 0000000000..78f4870c7e --- /dev/null +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -0,0 +1,534 @@ +:NewParser + +:escape +// You can push debug messages to this magic array. +let Array: { from: anything => { push: anything => anything, join: string => string } } +let _Array = Array +let logs: { push: anything => anything, join: string => string } = _Array.from([]) +let debug: anything => anything = x => logs.push(x) +fun showDebug = logs.join("\n") +//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = +//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ = [Function: Array] +//│ logs: {join: string -> string, push: anything -> anything} +//│ = [] +//│ debug: anything -> anything +//│ = [Function: debug] +//│ showDebug: string +//│ = [Function: showDebug] + +fun concat2(a, b) = concat(a)(b) +fun concat3(a, b, c) = concat2(a, concat2(b, c)) +fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) +fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) +fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) +fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) +fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) +fun par(a) = concat3("(", a, ")") +//│ concat2: (string, string,) -> string +//│ = [Function: concat2] +//│ concat3: (string, string, string,) -> string +//│ = [Function: concat3] +//│ concat4: (string, string, string, string,) -> string +//│ = [Function: concat4] +//│ concat5: (string, string, string, string, string,) -> string +//│ = [Function: concat5] +//│ concat6: (string, string, string, string, string, string,) -> string +//│ = [Function: concat6] +//│ concat7: (string, string, string, string, string, string, string,) -> string +//│ = [Function: concat7] +//│ concat8: (string, string, string, string, string, string, string, string,) -> string +//│ = [Function: concat8] +//│ par: string -> string +//│ = [Function: par] + +:escape +let String: nothing +let makeString: anything => { length: int, charCodeAt: int => int } = String +let StringInstance: { fromCharCode: int => string } = String +//│ String: nothing +//│ = +//│ makeString: anything -> {charCodeAt: int -> int, length: int} +//│ = [Function: String] +//│ StringInstance: {fromCharCode: int -> string} +//│ = [Function: String] + +fun fromCharCode(n) = StringInstance.fromCharCode(n) +fun stringCharCodeAt(s, i) = makeString(s).charCodeAt(i) +fun stringLength(s) = makeString(s).length +//│ fromCharCode: int -> string +//│ = [Function: fromCharCode] +//│ stringCharCodeAt: (anything, int,) -> int +//│ = [Function: stringCharCodeAt] +//│ stringLength: anything -> int +//│ = [Function: stringLength] + +class Option +class Some(value): Option +class None(): Option +//│ Defined class Option +//│ Defined class Some +//│ Defined class None +//│ Option: () -> Option +//│ = [Function: Option1] +//│ Some: 'value -> (Some & {value: 'value}) +//│ = [Function: Some1] +//│ None: () -> None +//│ = [Function: None1] + +class List +class Cons(head, tail): List +class Nil(): List +//│ Defined class List +//│ Defined class Cons +//│ Defined class Nil +//│ List: () -> List +//│ = [Function: List1] +//│ Cons: ('head, 'tail,) -> (Cons & {head: 'head, tail: 'tail}) +//│ = [Function: Cons1] +//│ Nil: () -> Nil +//│ = [Function: Nil1] + +fun list1(x) = Cons(x, Nil()) +fun list2(x, y) = Cons(x, list1(y)) +fun list3(x, y, z) = Cons(x, list2(y, z)) +fun list4(x, y, z, w) = Cons(x, list3(y, z, w)) +fun list5(x, y, z, w, v) = Cons(x, list4(y, z, w, v)) +fun list6(x, y, z, w, v, u) = Cons(x, list5(y, z, w, v, u)) +fun list7(x, y, z, w, v, u, t) = Cons(x, list6(y, z, w, v, u, t)) +fun list8(x, y, z, w, v, u, t, s) = Cons(x, list7(y, z, w, v, u, t, s)) +//│ list1: 'head -> (Cons & {head: 'head, tail: Nil}) +//│ = [Function: list1] +//│ list2: ('head, 'head0,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Nil}}) +//│ = [Function: list2] +//│ list3: ('head, 'head0, 'head1,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Nil}}}) +//│ = [Function: list3] +//│ list4: ('head, 'head0, 'head1, 'head2,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Nil}}}}) +//│ = [Function: list4] +//│ list5: ('head, 'head0, 'head1, 'head2, 'head3,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Nil}}}}}) +//│ = [Function: list5] +//│ list6: ('head, 'head0, 'head1, 'head2, 'head3, 'head4,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Nil}}}}}}) +//│ = [Function: list6] +//│ list7: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Cons & {head: 'head5, tail: Nil}}}}}}}) +//│ = [Function: list7] +//│ list8: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5, 'head6,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Cons & {head: 'head5, tail: Cons & {head: 'head6, tail: Nil}}}}}}}}) +//│ = [Function: list8] + +fun listConcat(xs, ys) = + if xs is + Nil() then ys + Cons(x, xs') then Cons(x, listConcat(xs', ys)) +//│ listConcat: ('tail, 'tail0,) -> 'tail0 +//│ where +//│ 'tail0 :> Cons & {head: 'head, tail: 'tail0} +//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ = [Function: listConcat] + +fun listContains(xs, x) = + if xs is + Nil() then false + Cons(x', xs') and + eq(x)(x') then true + _ then listContains(xs', x) +//│ listContains: ('tail, anything,) -> bool +//│ where +//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ = [Function: listContains] + +// Remove all occurrences of x from xs. +fun listWithout(xs, x) = + if xs is + Nil() then Nil() + Cons(x', xs') and + eq(x)(x') then listWithout(xs', x) + _ then Cons(x', listWithout(xs', x)) +//│ listWithout: ('tail, anything,) -> 'tail0 +//│ where +//│ 'tail0 :> Nil | Cons & {head: 'head, tail: 'tail0} +//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ = [Function: listWithout] + +fun listJoin(xs, sep) = + if xs is + Nil() then "" + Cons(x, Nil()) then toString(x) + Cons(x, xs') then concat3(toString(x), sep, listJoin(xs', sep)) +//│ listJoin: ('tail, string,) -> string +//│ where +//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ = [Function: listJoin] + +listJoin(list3("x", "y", "z"), ", ") +//│ res: string +//│ = 'x, y, z' + +class Term +class Var(name): Term +class Abs(lhs, rhs): Term +class App(lhs, rhs): Term +//│ Defined class Term +//│ Defined class Var +//│ Defined class Abs +//│ Defined class App +//│ Term: () -> Term +//│ = [Function: Term1] +//│ Var: 'name -> (Var & {name: 'name}) +//│ = [Function: Var1] +//│ Abs: ('lhs, 'rhs,) -> (Abs & {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: Abs1] +//│ App: ('lhs, 'rhs,) -> (App & {lhs: 'lhs, rhs: 'rhs}) +//│ = [Function: App1] + +fun showTerm(t) = + if t is + Var(name) then toString(name) + Abs(lhs, rhs) then concat4("&", showTerm(lhs), ". ", showTerm(rhs)) + App(Abs(lhs0, lhs1), rhs) then + concat8("((", "&", showTerm(lhs0), ". ", showTerm(lhs1), ") ", showTerm(rhs), ")") + App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) +//│ showTerm: 'rhs -> string +//│ where +//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ = [Function: showTerm] + +showTerm(Var("x")) +showTerm(Abs(Var("x"), Var("y"))) +showTerm(App(Var("x"), Var("y"))) +showTerm(App(Abs(Var("x"), Var("y")), Var("z"))) +//│ res: string +//│ = 'x' +//│ res: string +//│ = '&x. y' +//│ res: string +//│ = '(x y)' +//│ res: string +//│ = '((&x. y) z)' + +fun isValue(t) = + if t is + Var then true + Abs then true + App then false +//│ isValue: (Abs | App | Var) -> bool +//│ = [Function: isValue] + +isValue(Var("x")) +isValue(Abs(Var("x"), Var("y"))) +isValue(App(Var("x"), Var("y"))) +//│ res: bool +//│ = true +//│ res: bool +//│ = true +//│ res: bool +//│ = false + +:w +fun hasFree(t, n) = + if t is + // let __ = debug(concat3(showTerm(t), ", ", n)) + Var(na) then eq(n)(na) + Abs(Var(name), body) and eq(name)(n) then false + Abs(Var(name), body) then hasFree(body, n) + App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) + _ then false +//│ ╔══[WARNING] Found a duplicated else branch +//│ ║ l.234: _ then false +//│ ║ ^^^^^ +//│ ╟── The first else branch was declared here. +//│ ║ l.232: Abs(Var(name), body) then hasFree(body, n) +//│ ╙── ^^^^^^^^^^^^^^^^ +//│ hasFree: ('rhs, anything,) -> bool +//│ where +//│ 'rhs <: Abs & {rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var | ~Abs & ~App & ~Var +//│ = [Function: hasFree] + +fun showHasFree(t, n) = + concat4(showTerm(t), if hasFree(t, n) then " has " else " DOES NOT have ", "free variable ", n) +//│ showHasFree: ('rhs & 'rhs0, string,) -> string +//│ where +//│ 'rhs0 <: Abs & {rhs: 'rhs0} | App & {lhs: 'rhs0, rhs: 'rhs0} | Var | ~Abs & ~App & ~Var +//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ = [Function: showHasFree] + +showHasFree(Var("x"), "x") +showHasFree(Var("x"), "y") +showHasFree(Abs(Var("x"), Var("x")), "x") +showHasFree(Abs(Var("x"), Var("x")), "y") +showHasFree(Abs(Var("x"), Var("y")), "x") +showHasFree(Abs(Var("x"), Var("y")), "y") +showHasFree(App(Var("x"), Var("y")), "x") +showHasFree(App(Var("x"), Var("y")), "y") +showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "x") +showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") +showHasFree(App(Abs(Var("x"), Var("x")), Var("y")), "y") +showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") +//│ res: string +//│ = 'x has free variable x' +//│ res: string +//│ = 'x DOES NOT have free variable y' +//│ res: string +//│ = '&x. x DOES NOT have free variable x' +//│ res: string +//│ = '&x. x DOES NOT have free variable y' +//│ res: string +//│ = '&x. y DOES NOT have free variable x' +//│ res: string +//│ = '&x. y has free variable y' +//│ res: string +//│ = '(x y) has free variable x' +//│ res: string +//│ = '(x y) has free variable y' +//│ res: string +//│ = '((&x. x) x) has free variable x' +//│ res: string +//│ = '((&x. x) x) DOES NOT have free variable y' +//│ res: string +//│ = '((&x. x) y) has free variable y' +//│ res: string +//│ = '((&x. x) x) DOES NOT have free variable y' + +fun fv(t) = + if t is + Var(name) then list1(name) + Abs(Var(name), body) then listWithout(fv(body), name) + App(lhs, rhs) then listConcat(fv(lhs), fv(rhs)) +//│ fv: 'rhs -> 'a +//│ where +//│ 'a :> forall 'tail 'tail0. Cons & {head: 'name, tail: Nil} | 'tail | 'tail0 +//│ 'tail0 :> Cons & {head: 'head, tail: 'tail0} | 'a +//│ 'tail :> Nil | Cons & {head: 'head, tail: 'tail} +//│ 'head :> 'name +//│ 'rhs <: Abs & {lhs: Var, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var & {name: 'name} +//│ = [Function: fv] + +fun showFv(t) = + concat2(showTerm(t), if fv(t) is + Nil then " DOES NOT have free variables" + _ then concat2(" has free variables: ", listJoin(fv(t), ", ")) + ) +//│ showFv: ('rhs & 'rhs0) -> string +//│ where +//│ 'rhs0 <: Abs & {lhs: Var, rhs: 'rhs0} | App & {lhs: 'rhs0, rhs: 'rhs0} | Var +//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ = [Function: showFv] + +showFv(Var("x")) +showFv(Abs(Var("x"), Var("x"))) +showFv(Abs(Var("x"), Var("y"))) +showFv(App(Var("x"), Var("y"))) +showFv(App(Abs(Var("x"), Var("x")), Var("x"))) +//│ res: string +//│ = 'x has free variables: x' +//│ res: string +//│ = '&x. x DOES NOT have free variables' +//│ res: string +//│ = '&x. y has free variables: y' +//│ res: string +//│ = '(x y) has free variables: x, y' +//│ res: string +//│ = '((&x. x) x) has free variables: x' + +fun tryNextAlphabet(initialCode, currentCode, freeNames) = + if + currentCode + > 122 then tryNextAlphabet(initialCode, 97, freeNames) + == initialCode then None() + let name = fromCharCode(currentCode) + listContains(freeNames, name) then tryNextAlphabet(initialCode, currentCode + 1, freeNames) + _ then Some(name) +//│ tryNextAlphabet: (number, int, 'tail,) -> (None | Some & {value: string}) +//│ where +//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ = [Function: tryNextAlphabet] + +tryNextAlphabet(97, 97, list1("a")) +tryNextAlphabet(97, 98, list1("a")) +tryNextAlphabet(97, 98, list2("a", "b")) +tryNextAlphabet(121, 122, list1("y")) +tryNextAlphabet(121, 122, list2("y", "z")) +//│ res: None | Some & {value: string} +//│ = None {} +//│ res: None | Some & {value: string} +//│ = Some { value: 'b' } +//│ res: None | Some & {value: string} +//│ = Some { value: 'c' } +//│ res: None | Some & {value: string} +//│ = Some { value: 'z' } +//│ res: None | Some & {value: string} +//│ = Some { value: 'a' } + +fun tryAppendDigits(name, index, freeNames) = + if + let currentName = concat2(name, toString(index)) + listContains(freeNames, currentName) then + tryAppendDigits(name, index + 1, freeNames) + _ then currentName +//│ tryAppendDigits: (string, int, 'tail,) -> string +//│ where +//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ = [Function: tryAppendDigits] + +// Note: some weird behavior here... Just try the commented code. +fun findFreshName(name, freeNames) = + if + stringLength(name) == 1 and + let charCode = stringCharCodeAt(name, 0) + tryNextAlphabet(charCode, charCode + 1, freeNames) is + Some(newName) then newName + _ then tryAppendDigits(name, 0, freeNames) +//│ findFreshName: (string, 'tail,) -> string +//│ where +//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ = [Function: findFreshName] + +// Find a fresh name to replace `name` that does not conflict with any bound +// variables in the `body`. +fun freshName(name, body) = findFreshName(name, fv(body)) +//│ freshName: (string, 'rhs,) -> string +//│ where +//│ 'rhs <: Abs & {lhs: Var, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var +//│ = [Function: freshName] + +:w +fun subst(t, n, v) = + if t is + Var(name) and eq(name)(n) then v + Abs(Var(name), body) and ne(name)(n) and + hasFree(v, name) and freshName(name, body) is newName then + subst(Abs(Var(newName), subst(body, name, Var(newName))), n, v) + _ then Abs(Var(name), subst(body, n, v)) + App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) + _ then t +//│ ╔══[WARNING] Found a duplicated else branch +//│ ║ l.402: _ then t +//│ ║ ^ +//│ ╟── The first else branch was declared here. +//│ ║ l.400: _ then Abs(Var(name), subst(body, n, v)) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ subst: ('rhs, anything, 'rhs & 'rhs0 & 'rhs1 & 'rhs2,) -> 'rhs0 +//│ where +//│ 'rhs2 <: Abs & {rhs: 'rhs2} | App & {lhs: 'rhs2, rhs: 'rhs2} | Var | ~Abs & ~App & ~Var +//│ 'rhs <: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var +//│ 'a :> Abs & {lhs: Var & {name: string}, rhs: 'rhs0} | 'e +//│ <: 'rhs1 & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} & 'b | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} & 'c | {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'rhs0 :> Var & {name: string} | 'c | 'a | 'd | (forall 'e. 'e) | App & {lhs: 'rhs0, rhs: 'rhs0} +//│ 'e :> Abs & {lhs: Var & {name: 'name}, rhs: 'rhs0} +//│ 'name := string +//│ 'c :> Var & {name: string} +//│ <: 'rhs1 & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'd <: 'rhs1 & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) +//│ 'b <: {lhs: 'rhs, rhs: 'rhs} +//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var +//│ = [Function: subst] + +fun showSubst(t, n, v) = + concat8(showTerm(t), " [", n, " / ", showTerm(v), "]", " => ", showTerm(subst(t, n, v))) +//│ showSubst: ('rhs & 'rhs0, string, 'rhs0 & 'rhs1 & 'lhs & 'rhs2 & 'rhs & 'rhs3,) -> string +//│ where +//│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var +//│ 'rhs0 <: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var +//│ 'a <: 'rhs1 & 'lhs & 'rhs2 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'b | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'c | {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'c <: 'rhs1 & 'lhs & 'rhs2 & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'd <: 'rhs1 & 'lhs & 'rhs2 & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) +//│ 'b <: {lhs: 'rhs0, rhs: 'rhs0} +//│ 'lhs <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | ~Abs +//│ 'rhs2 <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | App & {lhs: 'lhs & 'rhs2, rhs: 'rhs2} | Var +//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var +//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ = [Function: showSubst] + +showSubst(Var("x"), "x", Var("y")) +showSubst(Abs(Var("x"), Var("x")), "x", Var("z")) +showSubst(App(Var("x"), Var("y")), "x", Abs(Var("x"), Var("x"))) +showSubst(App(Abs(Var("x"), Var("x")), Var("x")), "x", Abs(Var("y"), Var("y"))) +showSubst(Abs(Var("x"), App(Var("x"), Var("y"))), "y", Var("x")) +//│ res: string +//│ = 'x [x / y] => y' +//│ res: string +//│ = '&x. x [x / z] => &x. x' +//│ res: string +//│ = '(x y) [x / &x. x] => ((&x. x) y)' +//│ res: string +//│ = '((&x. x) x) [x / &y. y] => ((&x. x) &y. y)' +//│ res: string +//│ = '&x. (x y) [y / x] => &z. (z x)' + +fun stepByValue(t) = + if t is + Var then None() + Abs then None() + App(lhs, rhs) and stepByValue(lhs) is + Some(lhs) then Some(App(lhs, rhs)) + None and stepByValue(rhs) is + Some(rhs) then Some(App(lhs, rhs)) + None and lhs is + Abs(Var(name), body) then Some(subst(body, name, rhs)) + _ then None() +//│ stepByValue: 'a -> (None | Some & {value: 'value}) +//│ where +//│ 'value :> 'value0 | App & {lhs: 'value, rhs: 'rhs} | App & {lhs: 'lhs, rhs: 'value} +//│ 'a <: Abs | App & {lhs: 'lhs, rhs: 'rhs} | Var +//│ 'lhs <: 'a & (Abs & {rhs: 'rhs0} | ~#Abs) +//│ 'rhs0 <: Abs & 'b | App & 'c | Var & 'd | 'e & ~#Abs & ~#App & ~#Var +//│ 'b :> Abs & {lhs: Var & {name: string}, rhs: 'value0} | 'f +//│ <: 'rhs1 & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} & 'c | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} & 'd | {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} & 'e & ~#Abs & ~#App & ~#Var) +//│ 'value0 :> Var & {name: string} | 'rhs | 'd | 'b | 'e | (forall 'f. 'f) | App & {lhs: 'value0, rhs: 'value0} +//│ 'f :> Abs & {lhs: Var & {name: 'name}, rhs: 'value0} +//│ 'name := string +//│ 'd :> Var & {name: string} +//│ <: 'rhs1 & (Abs & {name: anything} & 'b | App & {name: anything} & 'c | Var | {name: anything} & 'e & ~#Abs & ~#App & ~#Var) +//│ 'e <: 'rhs1 & (Abs & 'b | App & 'c | Var & 'd | ~#Abs & ~#App & ~#Var) +//│ 'c <: {lhs: 'rhs0, rhs: 'rhs0} +//│ 'rhs <: 'a & 'rhs2 & 'rhs3 +//│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var +//│ 'rhs2 <: 'rhs0 & 'rhs1 +//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var +//│ = [Function: stepByValue] + +fun showStepByValue(t) = + concat3(showTerm(t), " => ", if stepByValue(t) is + Some(t) then showTerm(t) + None then "stuck" + ) +//│ showStepByValue: ('rhs & (Abs | App & 'a | Var)) -> string +//│ where +//│ 'a <: {lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), rhs: 'rhs2 & 'lhs & 'rhs0 & 'rhs3 & (Abs | App & 'a | Var)} +//│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var +//│ 'rhs1 <: Abs & 'b | App & 'c | Var & 'd | 'e & ~#Abs & ~#App & ~#Var +//│ 'b <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'c | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'd | {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'e & ~#Abs & ~#App & ~#Var) +//│ 'd <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {name: anything} & 'b | App & {name: anything} & 'c | Var | {name: anything} & 'e & ~#Abs & ~#App & ~#Var) +//│ 'e <: 'rhs4 & 'lhs & 'rhs0 & (Abs & 'b | App & 'c | Var & 'd | ~#Abs & ~#App & ~#Var) +//│ 'c <: {lhs: 'rhs1, rhs: 'rhs1} +//│ 'rhs2 <: 'rhs1 & 'rhs4 +//│ 'rhs4 <: Abs & {lhs: Var, rhs: 'rhs4} | App & {lhs: 'rhs4, rhs: 'rhs4} | Var +//│ 'lhs <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | ~Abs +//│ 'rhs0 <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | App & {lhs: 'lhs & 'rhs0, rhs: 'rhs0} | Var +//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ = [Function: showStepByValue] + +showStepByValue(Var("x")) +showStepByValue(Abs(Var("x"), Var("y"))) +showStepByValue(App(Var("x"), Var("y"))) +showStepByValue(App(Abs(Var("x"), Var("x")), Var("y"))) +//│ res: string +//│ = 'x => stuck' +//│ res: string +//│ = '&x. y => stuck' +//│ res: string +//│ = '(x y) => stuck' +//│ res: string +//│ = '((&x. x) y) => y' + +fun equalTerm(a, b) = + if a is + Var(na) and b is Var(nb) then eq(na)(nb) + Abs(la, ra) and b is Abs(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) + App(la, ra) and b is App(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) + _ then false +//│ equalTerm: ('rhs, 'rhs0,) -> bool +//│ where +//│ 'rhs0 <: Abs & 'a | App & 'a | Var | ~Abs & ~App & ~Var +//│ 'a <: {lhs: 'rhs0, rhs: 'rhs0} +//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var | ~Abs & ~App & ~Var +//│ = [Function: equalTerm] From 117b2a8e325d6720e66bc01bc7a2066ae6abfaae Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 13 Mar 2023 16:57:10 +0800 Subject: [PATCH 189/498] WIP Do not require completion of object types to expand their type refs --- .../main/scala/mlscript/TypeSimplifier.scala | 7 +-- .../main/scala/mlscript/TyperHelpers.scala | 41 +++++++++------ shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/nu/SelfRec.mls | 52 ++++++------------- shared/src/test/diff/ucs/LitUCS.mls | 38 ++++++++++++++ 5 files changed, 84 insertions(+), 56 deletions(-) create mode 100644 shared/src/test/diff/ucs/LitUCS.mls diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 5155080b31..9d4a527eb7 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -112,8 +112,8 @@ trait TypeSimplifier { self: Typer => case N => // v -> default :: Nil ctx.tyDefs2.get(prefix) match { - case S(td) => - td.result match { + case S(info) => + info.result match { case S(cls: TypedNuCls) => cls.varianceOf(cls.tparams.find(_._1.name === postfix).getOrElse(die)._2) match { case VarianceInfo(true, true) => Nil @@ -122,7 +122,8 @@ trait TypeSimplifier { self: Typer => else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil else v -> default :: Nil } - case _ => die + case N => + ??? // TODO use info.explicitVariances } case N => die } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 2715c2bda8..a039306fc7 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -963,13 +963,18 @@ abstract class TyperHelpers { Typer: Typer => trait TypeRefImpl { self: TypeRef => def canExpand(implicit ctx: Ctx): Bool = - ctx.tyDefs2.get(defn.name).forall(_.result.isDefined) + ctx.tyDefs2.get(defn.name).forall(info => + // * Object types do not need to be completed in order to be expanded + info.kind.isInstanceOf[ObjDefKind] + || info.result.isDefined) def expand(implicit ctx: Ctx, raise: Raise): SimpleType = { ctx.tyDefs2.get(defn.name) match { - case S(lti) => - lti.complete() - if (lti.result.isEmpty) // * This can only happen if completion yielded an error - return errType + case S(info) => + if (!info.kind.isInstanceOf[ObjDefKind]) { + info.complete() + if (info.result.isEmpty) // * This can only happen if completion yielded an error + return errType + } case N => } expandWith(paramTags = true) @@ -986,16 +991,22 @@ abstract class TyperHelpers { Typer: Typer => substSyntax(td.body)(td.tparams.lazyZip(targs).map { case (tp, ta) => SkolemTag(tp._2.level, tp._2)(noProv) -> ta }.toMap) - case S(td: TypedNuCls) => - assert(td.tparams.size === targs.size) - clsNameToNomTag(td.td)(provTODO, ctx) & - RecordType(td.tparams.lazyZip(targs).map { - case ((tn, tv, vi), ta) => // TODO use vi - val fldNme = td.td.nme.name + "#" + tn.name - Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) - })(provTODO) - case S(d) => wat("unexpected declaration in type reference", d) - case N => lastWords("cannot expand unforced type reference") // Definition was not forced yet, which indicates an error (hopefully) + case _ => + info.decl match { + case td: NuTypeDef if td.kind.isInstanceOf[ObjDefKind] => + assert(td.tparams.size === targs.size) + clsNameToNomTag(td)(provTODO, ctx) & + RecordType(info.tparams.lazyZip(targs).map { + case ((tn, tv, vi), ta) => // TODO use vi + val fldNme = td.nme.name + "#" + tn.name + Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) + })(provTODO) + case td: NuTypeDef if td.kind is Als => + // * Definition was not forced yet, which indicates an error (hopefully) + lastWords("cannot expand unforced type alias") + case d => + wat("unexpected declaration in type reference", d) + } } }.getOrElse { val td = ctx.tyDefs(defn.name) diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index fdcb0a73ab..1e91511d21 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -53,7 +53,7 @@ case object Cls extends TypeDefKind("class") with ObjDefKind case object Trt extends TypeDefKind("trait") with ObjDefKind case object Mxn extends TypeDefKind("mixin") case object Als extends TypeDefKind("type alias") -case object Nms extends TypeDefKind("module") +case object Nms extends TypeDefKind("module") with ObjDefKind sealed abstract class Term extends Terms with TermImpl sealed abstract class Lit extends SimpleTerm with LitImpl diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index d1cd843441..6984609bba 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -100,66 +100,44 @@ class Foo6[A](x: A) { //│ fun test3: (error,) //│ } +module N +//│ module N() + :e -class Foo7[A](head: A, tail: Foo7[A] | 0) { +class Foo7[A](head: A, tail: Foo7[A] | N) { fun test1 = if tail is - 0 then head + N then head _ then tail.test1 } -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.104: class Foo7[A](head: A, tail: Foo7[A] | 0) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.105: fun test1 = if tail is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.106: 0 then head -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.107: _ then tail.test1 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.108: } -//│ ╙── ^ //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.107: _ then tail.test1 +//│ ║ l.110: _ then tail.test1 //│ ╙── ^^^^^^ -//│ class Foo7[A](head: A, tail: 0 | Foo7[A]) { +//│ class Foo7[A](head: A, tail: Foo7[A] | N) { //│ fun test1: A | error //│ } // TODO support -class Foo7_A[A](head: A, tail: Foo7_A[A] | 0) { +class Foo7_A[A](head: A, tail: Foo7_A[A] | N) { fun test1: A = if tail is - 0 then head + N then head _ then tail.test1 } -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.128: class Foo7_A[A](head: A, tail: Foo7_A[A] | 0) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.129: fun test1: A = if tail is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.130: 0 then head -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.131: _ then tail.test1 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.132: } -//│ ╙── ^ //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.131: _ then tail.test1 +//│ ║ l.123: _ then tail.test1 //│ ╙── ^^^^^^ -//│ class Foo7_A[A](head: A, tail: 0 | Foo7_A[A]) { +//│ class Foo7_A[A](head: A, tail: Foo7_A[A] | N) { //│ fun test1: A //│ } :e class Foo8[A](x: A) { fun test1[B](y: B): A = - let tmp = Foo6(y).test1(x) + let tmp = Foo8(y).test1(x) x } -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.154: let tmp = Foo6(y).test1(x) -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ╟── field selection of type `(?test,)` is not a function -//│ ║ l.154: let tmp = Foo6(y).test1(x) -//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ║ l.135: let tmp = Foo8(y).test1(x) +//│ ╙── ^^^^^^ //│ class Foo8[A](x: A) { //│ fun test1: (y: anything,) -> A //│ } diff --git a/shared/src/test/diff/ucs/LitUCS.mls b/shared/src/test/diff/ucs/LitUCS.mls new file mode 100644 index 0000000000..e6fd4f4196 --- /dev/null +++ b/shared/src/test/diff/ucs/LitUCS.mls @@ -0,0 +1,38 @@ +:NewDefs + + +module A +//│ module A() + +// FIXME +fun test(x: 0 | A) = if x is + 0 then 0 + A then A +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.8: fun test(x: 0 | A) = if x is +//│ ║ ^ +//│ ╟── type `A` is not an instance of type `number` +//│ ║ l.8: fun test(x: 0 | A) = if x is +//│ ║ ^ +//│ ╟── but it flows into reference with expected type `number` +//│ ║ l.8: fun test(x: 0 | A) = if x is +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.8: fun test(x: 0 | A) = if x is +//│ ║ ^^^^ +//│ ║ l.9: 0 then 0 +//│ ║ ^^^^^^^^^^ +//│ ║ l.10: A then A +//│ ║ ^^^^^^^^^^ +//│ ╟── type `0` is not an instance of type `A` +//│ ║ l.8: fun test(x: 0 | A) = if x is +//│ ║ ^ +//│ ╟── but it flows into reference with expected type `A` +//│ ║ l.8: fun test(x: 0 | A) = if x is +//│ ║ ^ +//│ ╟── Note: constraint arises from class pattern: +//│ ║ l.10: A then A +//│ ╙── ^ +//│ fun test: (x: 0 | A,) -> (0 | A) + + From c06d9347242f0bcd709c80414f4eac648941c17a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 13 Mar 2023 17:39:37 +0800 Subject: [PATCH 190/498] WIP Fix tv context when typing statements --- shared/src/main/scala/mlscript/NuTypeDefs.scala | 16 +++++++++------- .../test/diff/ecoop23/PolymorphicVariants.mls | 6 +++--- shared/src/test/diff/ecoop23/SimpleRegionDSL.mls | 10 +++++----- shared/src/test/diff/nu/BadClasses.mls | 12 ++++++++++++ shared/src/test/diff/nu/GenericMixins.mls | 2 +- .../src/test/diff/nu/PolymorphicVariants_Alt.mls | 2 +- shared/src/test/diff/nu/SelfRec.mls | 16 +++++++++++++--- 7 files changed, 44 insertions(+), 20 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 117ceed0d3..4a59e41c50 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -334,6 +334,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]): TypedTypingUnit = trace(s"${ctx.lvl}. Typing $tu") { + // println(s"vars ${vars}") + val named = mutable.Map.empty[Str, LazyTypeInfo] val infos = tu.entities.collect { @@ -365,7 +367,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx ++= completedInfos // * Type the block statements - def go(stmts: Ls[Statement])(implicit ctx: Ctx): Opt[ST] = stmts match { + def go(stmts: Ls[Statement]): Opt[ST] = stmts match { case s :: stmts => val res_ty = s match { case decl: NuDecl => N @@ -375,7 +377,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => S(typeTerms(dss, false, Nil)(ctx, raise, TypeProvenance(s.toLoc, s match { case trm: Term => trm.describe case s => "statement" - }), Map.empty, genLambdas = false)) + }), vars, genLambdas = false)) } stmts match { case Nil => res_ty @@ -457,7 +459,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - val tv: TV = freshVar( + lazy val mutRecTV: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), N, S(decl.name))(level + 1) @@ -510,7 +512,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * to avoid cyclic-looking constraints due to the polymorphic recursion limitation, // * as these functions are allowed to be mutually-recursive. // * In the future, we should type each mutual-recursion-component independently - // * and polymorphically wrt to non-recursive users of them. + // * and polymorphically wrt to external uses of them. implicit val gl: GenLambdas = false val body_ty = ctx.nextLevel { implicit ctx: Ctx => // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods @@ -526,7 +528,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuFun(ctx.lvl, fd, body_ty) } } - ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.bodyType, tv) } + ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.bodyType, mutRecTV) } res_ty @@ -732,8 +734,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => decl match { case _: NuFunDef => if (isComputing) { - println(s"Already computing! Using TV: $tv") - tv // TODO make sure this is never misused (ie not accessed from difft scope/level) + println(s"Already computing! Using TV: $mutRecTV") + mutRecTV // TODO make sure this is never misused (ie not accessed from difft scope/level) } else complete() match { case TypedNuFun(_, fd, ty) => ty diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index b3f2fc51e8..47d5ac4649 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -95,7 +95,7 @@ Test1.eval(Nil, Var("a")) Test1.eval(Nil, Abs("b", Var("a"))) //│ 'a //│ where -//│ 'a :> Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Var //│ res //│ = Abs {} @@ -109,7 +109,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var +//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] //│ res //│ = Var {} @@ -197,7 +197,7 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> 'result //│ } //│ where -//│ 'result :> Num | Var | 'b | App['result] | Abs['result] +//│ 'result :> App['result] | Abs['result] | Num | Var | 'b //│ 'b <: Add['c] | Mul['c] | Num | Var //│ 'c <: 'a //│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | 'b & ~#Abs & ~#App diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 9ecc10b94d..7f35012d8c 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -32,7 +32,7 @@ mixin SizeBase { } //│ mixin SizeBase() { //│ this: {size: ('a | 'a0 | 'a1 | 'a2) -> int} -//│ fun size: (Circle | Intersect['a2] | Outside['a0] | Translate['a] | Union['a1]) -> int +//│ fun size: (Circle | Intersect['a1] | Outside['a] | Translate['a2] | Union['a0]) -> int //│ } // ******************* Linguistic Reuse and Meta-Language Optimizations ******************* @@ -322,19 +322,19 @@ module TestElim extends Eliminate //│ } //│ where //│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~#Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'b :> Intersect['b] | Translate['b] | Scale['b] | Outside['b] | Union['b] +//│ 'b :> Outside['b] | Union['b] | Intersect['b] | Translate['b] | Scale['b] TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where -//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Univ +//│ 'a :> Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] //│ res //│ = Univ {} TestElim.eliminate(circles) //│ 'a //│ where -//│ 'a :> Translate['a] | Scale['a] | Circle | Outside['a] | Union['a] | Intersect['a] +//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Circle //│ res //│ = Union {} @@ -376,7 +376,7 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~#Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] +//│ 'c :> Translate['c] | Scale['c] | Outside['c] | Union['c] | Intersect['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] // TODO investigate diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 043eb50c83..7c55009413 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -87,3 +87,15 @@ hello //│ = 1 +:e +class Foo[A] { 42: A } +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.91: class Foo[A] { 42: A } +//│ ║ ^^ +//│ ╟── integer literal of type `42` does not match type `A` +//│ ╟── Note: constraint arises from type parameter: +//│ ║ l.91: class Foo[A] { 42: A } +//│ ╙── ^ +//│ class Foo[A]() + + diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 02b0b726d3..73d9bc9e2e 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -8,7 +8,7 @@ mixin BaseTest { //│ ╔══[ERROR] type identifier not found: A //│ ║ l.6: fun test(x: A) = x //│ ╙── ^ -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A29' +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A28' mixin BaseTest(x: A) { fun test = x diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 7d3923e1e0..22a7361d33 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -128,7 +128,7 @@ Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var +//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] class Num(n: int) class Add(l: A, r: A) diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 6984609bba..2314f68b38 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -118,14 +118,24 @@ class Foo7[A](head: A, tail: Foo7[A] | N) { // TODO support class Foo7_A[A](head: A, tail: Foo7_A[A] | N) { - fun test1: A = if tail is + test1: A + fun test1 = if tail is N then head _ then tail.test1 } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.123: _ then tail.test1 +//│ ║ l.124: _ then tail.test1 //│ ╙── ^^^^^^ //│ class Foo7_A[A](head: A, tail: Foo7_A[A] | N) { +//│ fun test1: A | error +//│ } + +class Foo7_A2[A](head: A, tail: Foo7_A[A] | N) { + fun test1: A = if tail is + N then head + _ then tail.test1 +} +//│ class Foo7_A2[A](head: A, tail: Foo7_A[A] | N) { //│ fun test1: A //│ } @@ -136,7 +146,7 @@ class Foo8[A](x: A) { x } //│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.135: let tmp = Foo8(y).test1(x) +//│ ║ l.145: let tmp = Foo8(y).test1(x) //│ ╙── ^^^^^^ //│ class Foo8[A](x: A) { //│ fun test1: (y: anything,) -> A From b886ddae725fca2fc77c1401786467361c5d26bd Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 14 Mar 2023 00:16:46 +0800 Subject: [PATCH 191/498] WIP Type indirectly-recursive methods based on given signature --- .../scala/mlscript/ConstraintSolver.scala | 17 ++- .../src/main/scala/mlscript/NuTypeDefs.scala | 118 +++++++++++++++--- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 8 +- shared/src/test/diff/nu/BadClasses.mls | 10 ++ shared/src/test/diff/nu/BasicClasses.mls | 2 +- shared/src/test/diff/nu/EncodedLists.mls | 5 +- shared/src/test/diff/nu/FieldRefinement.mls | 23 ++++ shared/src/test/diff/nu/GenericMethods.mls | 15 ++- shared/src/test/diff/nu/GenericModules.mls | 69 ++++++---- shared/src/test/diff/nu/MutualRec.mls | 11 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 5 +- shared/src/test/diff/nu/SelfRec.mls | 55 ++++---- .../src/test/diff/nu/ThisRefinedClasses.mls | 12 +- shared/src/test/diff/nu/TypeAliases.mls | 3 + .../src/test/scala/mlscript/DiffTests.scala | 2 +- 16 files changed, 252 insertions(+), 105 deletions(-) create mode 100644 shared/src/test/diff/nu/FieldRefinement.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index cd9a9d5a6c..c311086b73 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -30,14 +30,20 @@ class ConstraintSolver extends NormalForms { self: Typer => val info = ctx.tyDefs2(clsNme) // require(!info.isComputing) + // TODO intersect with found signature! + val fromRft = rfnt(fld) + if (info.isComputing) { - rfnt(fld) match { - case S(fty) => - fty + info.typedFields.get(fld) match { + case S(fty) => fty case N => - // TODO allow when annotated - err(msg"unsupported indirectly recursive member access", fld.toLoc).toUpper(noProv) + fromRft match { + case S(fty) => + fty + case N => + err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv) + } } } else info.complete() match { @@ -427,6 +433,7 @@ class ConstraintSolver extends NormalForms { self: Typer => annoyingImpl(ls, done_ls, rs, done_rs) } + // TODO improve by moving things to the right side *before* branching out in the search! def annoyingImpl(ls: Ls[SimpleType], done_ls: LhsNf, rs: Ls[SimpleType], done_rs: RhsNf) (implicit cctx: ConCtx, prevCctxs: Ls[ConCtx], ctx: Ctx, shadows: Shadows, dbgHelp: Str = "Case") : Unit = diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 4a59e41c50..46454b9ebc 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -330,7 +330,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => /** Type checks a typing unit, which is a sequence of possibly-nutually-recursive type and function definitions * interleaved with plain statements. */ - def typeTypingUnit(tu: TypingUnit, allowPure: Bool) + def typeTypingUnit(tu: TypingUnit, topLevel: Bool) (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]): TypedTypingUnit = trace(s"${ctx.lvl}. Typing $tu") { @@ -338,7 +338,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val named = mutable.Map.empty[Str, LazyTypeInfo] - val infos = tu.entities.collect { + // * Not sure we should support declaring signature with the `ident: type` syntax + // val (signatures, otherEntities) = tu.entities.partitionMap { + // case Asc(v: Var, ty) => L(v -> ty) + // case s => R(s) + // } + val (decls, statements) = tu.entities.partitionMap { + case decl: NuDecl => L(decl) + case s => R(s) + } + val implems = if (topLevel) decls else decls.filter { + case NuFunDef(N, nme, tparams, R(rhs)) => false // There will already be typed in DelayedTypeInfo + case _ => true + } + val infos = implems.map { case decl: NuDecl => val lti = new DelayedTypeInfo(decl, implicitly) decl match { @@ -387,9 +400,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case Nil => N } - val res_ty = trace("Typing unit statements") { go(tu.entities) } (r => s": $r") + val res_ty = trace("Typing unit statements") { go(statements) } (r => s": $r") - TypedTypingUnit(completedInfos.map(_._2.member).toList, res_ty) + TypedTypingUnit(completedInfos.map(_._2.member), res_ty) }() @@ -409,7 +422,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => private implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) - println(s"${ctx.lvl}. Created lazy type info $decl") + println(s"${ctx.lvl}. Created lazy type info for $decl") lazy val tparams: TyParams = ctx.nest.nextLevel { implicit ctx => decl match { @@ -459,6 +472,47 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } + lazy val paramSymbols = typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + + // TODO also import signatures from base classes and mixins! + lazy val typedSignatures: Ls[(NuFunDef, ST)] = decl match { + case td: NuTypeDef => ctx.nest.nextLevel { implicit ctx => + val (signatures, rest) = td.body.entities.partitionMap { + case fd @ NuFunDef(N, nme, tparams, R(rhs)) => + L((fd, rhs)) + // TODO also pick up signature off implems with typed params/results + case s => R(s) + } + // TODO use `rest` + + ctx ++= paramSymbols + + signatures.map { case (fd, rhs) => + (fd, ctx.poly { implicit ctx: Ctx => + vars ++ fd.tparams.map { tn => + tn.name -> freshVar(TypeProvenance(tn.toLoc, "method type parameter", + originName = S(tn.name), + isType = true), N, S(tn.name)) + } |> { implicit vars => + + typeType(rhs).withProv( + TypeProvenance(Loc(rhs :: fd.nme :: fd.tparams), s"signature of member ${fd.nme.name}") + ) + + } + }) + } + } + case _: NuFunDef => Nil + } + lazy val typedSignatureMembers: Ls[Str -> TypedNuFun] = + typedSignatures.iterator.map { case (fd, ty) => + fd.nme.name -> TypedNuFun(level, fd, ty) + }.toList + + lazy val typedFields: Map[Var, FieldType] = + typedParams.toMap ++ typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) + lazy val mutRecTV: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), N, @@ -520,11 +574,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => vars ++ fd.tparams.map { tn => tn.name -> freshVar(TypeProvenance(tn.toLoc, "method type parameter", originName = S(tn.name), - isType = true), N) + isType = true), N, S(tn.name)) } |> { implicit vars => typeTerm(body) } - } + }.withProv(TypeProvenance(fd.toLoc, s"definition of method ${fd.nme.name}")) TypedNuFun(ctx.lvl, fd, body_ty) } } @@ -534,7 +588,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case td: NuTypeDef => - td.kind match { + val signatures = typedSignatures + ctx ++= signatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) + + val (res, funMembers) = td.kind match { case Trt => err(msg"traits are not yet supported" -> td.toLoc :: Nil) @@ -554,7 +611,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"type alias definition requires a right-hand side", td.toLoc) } - TypedNuAls(outerCtx.lvl, td, tparams, body_ty) + TypedNuAls(outerCtx.lvl, td, tparams, body_ty) -> Nil case Cls | Nms => @@ -565,7 +622,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"${td.kind.str} parameters are not supported", Loc(typedParams.iterator.map(_._1))) - ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + ctx ++= paramSymbols ctx += "this" -> VarSymbol(thisTV, Var("this")) @@ -691,24 +748,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "super" -> VarSymbol(thisType, Var("super")) - val ttu = typeTypingUnit(td.body, allowPure = false) + val ttu = typeTypingUnit(td.body, topLevel = false) + // TODO report non-unit result/statements? // TODO check overriding val clsMems = ttu.entities - val mems = baseMems ++ clsMems + val impltdMems = baseMems ++ clsMems + val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems.map(d => d.name -> d).toMap, + tparams, typedParams, mems, // if (td.kind is Nms) TopType else thisTV TopType - )(thisType) + )(thisType) -> impltdMems } case Mxn => if (td.parents.nonEmpty) err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) ctx.nest.nextLevel { implicit ctx => - ctx ++= typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + ctx ++= paramSymbols val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) implicit val vars: Map[Str, SimpleType] = outerVars ++ Map.empty // TODO type params @@ -716,11 +775,34 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val superTV = freshVar(provTODO, N, S("super")) ctx += "this" -> VarSymbol(thisTV, Var("this")) ctx += "super" -> VarSymbol(superTV, Var("super")) - val ttu = typeTypingUnit(td.body, allowPure = false) - val mems = paramMems ++ttu.entities - TypedNuMxn(td, thisTV, superTV, tparams, typedParams, mems.map(m => m.name -> m).toMap, ttu) + val ttu = typeTypingUnit(td.body, topLevel = false) + val impltdMems = paramMems ++ ttu.entities + val mems = impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers + TypedNuMxn(td, thisTV, superTV, tparams, typedParams, mems, ttu) -> impltdMems + } + } + + // TODO check member duplication? in mems or before? + + // * Check signatures + // val isAbstract = // TODO + ctx.nextLevel { implicit ctx: Ctx => + typedSignatures.foreach { case (fd, sign) => + implicit val prov: TP = sign.prov + funMembers.find(m => m.name === fd.nme.name) match { + case S(mem: TypedNuTermDef) => + val memSign = mem.typeSignature + implicit val prov: TP = memSign.prov + constrain(memSign, sign) + case S(mem: NuParam) => + case S(_) => ??? // TODO + case N => + err(msg"Member ${fd.nme.name} is declared but not defined", fd.nme.toLoc) } + } } + + res } } finally { isComputing = false } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 0780e9d175..ceb0038012 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1009,7 +1009,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // typeTerm(Blk(stmts))(newCtx, lvl, raise) case Blk(stmts) => if (newDefs) { - val ttu = typeTypingUnit(TypingUnit(stmts), allowPure = false) + val ttu = typeTypingUnit(TypingUnit(stmts), topLevel = false) // TODO check unused defs ttu.result.getOrElse(UnitType) } else typeTerms(stmts, false, Nil)(ctx.nest, raise, prov, vars, genLambdas) diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 7f35012d8c..58fc6b9319 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -186,16 +186,16 @@ mixin Text { :e module SizeText extends Text -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation //│ ║ l.180: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation //│ ║ l.179: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation //│ ║ l.178: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation //│ ║ l.177: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText() { diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 7c55009413..db9709bbbc 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -99,3 +99,13 @@ class Foo[A] { 42: A } //│ class Foo[A]() +:e // TODO better error +class C1 { fun oops = this.x } +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.103: class C1 { fun oops = this.x } +//│ ╙── ^^ +//│ class C1() { +//│ fun oops: error +//│ } + + diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index f898e056fe..ab4da8550a 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -71,7 +71,7 @@ class Base0(n) { //│ ╔══[ERROR] Class parameters currently need type annotations //│ ║ l.65: class Base0(n) { //│ ╙── ^ -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.69: fun oops = this.my //│ ╙── ^^^ //│ class Base0(n: error) { diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index 174d5e95ad..0531319ff9 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -4,6 +4,7 @@ class List { fun match: forall 'res; (ifNil: () => 'res, ifCons: ('res, List[A]) => 'res) => 'res + fun match = error // TODO use self-type... } let Nil: List let Cons: (head: 'a, tail: List<'a>) => List<'a> @@ -19,11 +20,11 @@ let x: List // FIXME x: List //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.20: x: List +//│ ║ l.21: x: List //│ ║ ^ //│ ╟── expression of type `anything` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.16: let x: List +//│ ║ l.17: let x: List //│ ║ ^^^ //│ ╟── Note: type parameter A is defined at: //│ ║ l.5: class List { diff --git a/shared/src/test/diff/nu/FieldRefinement.mls b/shared/src/test/diff/nu/FieldRefinement.mls new file mode 100644 index 0000000000..ce1064a1bc --- /dev/null +++ b/shared/src/test/diff/nu/FieldRefinement.mls @@ -0,0 +1,23 @@ +:NewDefs + + +class Foo(x: int) { + fun bar = x +} +//│ class Foo(x: int) { +//│ fun bar: int +//│ } + +let foo: Foo & { x: 0 | 1 } +//│ let foo: Foo & {x: 0 | 1} +//│ foo +//│ = + +// TODO refine +foo.x +//│ int +//│ res +//│ = +//│ foo is not implemented + + diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 8c129fce8b..8cae325ac9 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -20,7 +20,7 @@ foo1[int](42) fun foo2(x: A) = x -//│ fun foo2: forall 'a. (x: 'a,) -> 'a +//│ fun foo2: forall 'A. (x: 'A,) -> 'A foo2(42) //│ 42 @@ -38,7 +38,7 @@ foo2(42) fun foo3[A](x: A) = x -//│ fun foo3: forall 'a. (x: 'a,) -> 'a +//│ fun foo3: forall 'A. (x: 'A,) -> 'A foo3(42) //│ 42 @@ -97,22 +97,29 @@ fun bar: A => A //│ term App(App(Var(>:), Tup(_: Var(A))), Tup(_: Var(A))) is not a valid pattern +:e module Test { fun foo: 'A => 'A fun bar: 'A fun test(x: A) = x } +//│ ╔══[ERROR] Member foo is declared but not defined +//│ ║ l.102: fun foo: 'A => 'A +//│ ╙── ^^^ +//│ ╔══[ERROR] Member bar is declared but not defined +//│ ║ l.103: fun bar: 'A +//│ ╙── ^^^ //│ module Test() { //│ fun bar: nothing //│ fun foo: forall 'A. 'A -> 'A -//│ fun test: forall 'a. (x: 'a,) -> 'a +//│ fun test: forall 'A0. (x: 'A0,) -> 'A0 //│ } class Test(n: A) { fun test(x: A) = [x, n] } //│ class Test[A](n: A) { -//│ fun test: forall 'a. (x: 'a,) -> ('a, A,) +//│ fun test: forall 'A. (x: 'A,) -> ('A, A,) //│ } diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index ae1c3c42b6..dc4cd6275d 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -1,42 +1,32 @@ :NewDefs -// TODO complain abstract +:e module Test { fun foo: A => A } +//│ ╔══[ERROR] Member foo is declared but not defined +//│ ║ l.6: fun foo: A => A +//│ ╙── ^^^ //│ module Test[A]() { //│ fun foo: A -> A //│ } Test.foo -//│ (??A & 'A) -> ('A | ??A0) +//│ forall 'A. 'A -> 'A //│ res //│ = undefined -:e +:re Test.foo(1) -//│ ╔══[ERROR] Type error in application -//│ ║ l.18: Test.foo(1) -//│ ║ ^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.18: Test.foo(1) -//│ ╙── ^ -//│ error | ??A +//│ 1 //│ res //│ Runtime error: //│ TypeError: Test.foo is not a function -:e +:re Test.foo(error) + 1 -//│ ╔══[ERROR] Type error in operator application -//│ ║ l.31: Test.foo(error) + 1 -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.31: Test.foo(error) + 1 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╙── into type `int` -//│ error | int +//│ int //│ res //│ Runtime error: //│ Error: unexpected runtime error @@ -44,7 +34,7 @@ Test.foo(error) + 1 :e Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.45: Test .foo +//│ ║ l.35: Test .foo //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -53,7 +43,7 @@ Test .foo :e (Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.54: (Test).foo +//│ ║ l.44: (Test).foo //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -68,10 +58,10 @@ Test :e Test: Test<'a> //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.69: Test: Test<'a> +//│ ║ l.59: Test: Test<'a> //│ ║ ^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.69: Test: Test<'a> +//│ ║ l.59: Test: Test<'a> //│ ║ ^^ //│ ╟── back into type variable `A` //│ ║ l.5: module Test { @@ -85,19 +75,46 @@ Test: Test<'a> fun test(x) = if x is Test then x.foo -//│ fun test: forall 'A. Test['A] -> 'A -> 'A +//│ fun test: forall 'A. Test['A] -> (forall 'A0. 'A0 -> 'A0) :e test(Test) //│ ╔══[ERROR] Type error in application -//│ ║ l.91: test(Test) +//│ ║ l.81: test(Test) //│ ║ ^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope //│ ║ l.5: module Test { //│ ╙── ^ -//│ (??A & 'A) -> ('A | ??A0) | error +//│ forall 'A. 'A -> 'A | error //│ res //│ = undefined +module Test { + fun foo = id +} +//│ module Test[A]() { +//│ fun foo: forall 'a. 'a -> 'a +//│ } + +Test.foo +//│ forall 'a. 'a -> 'a +//│ res +//│ = [Function: id] + + +module Test { + fun foo: A => A + fun foo = id +} +//│ module Test[A]() { +//│ fun foo: A -> A +//│ } + +Test.foo +//│ forall 'A. 'A -> 'A +//│ res +//│ = [Function: id] + + diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index c415772c02..25072cd5aa 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -133,7 +133,7 @@ module Test1_1 { module Test1_2 { fun b = Test1_1.a } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.134: fun b = Test1_1.a //│ ╙── ^^ //│ module Test1_1() { @@ -154,7 +154,7 @@ class Test1_1 { class Test1_2 { fun b = Test1_1().a } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.155: fun b = Test1_1().a //│ ╙── ^^ //│ class Test1_1() { @@ -177,7 +177,7 @@ module Test2_2 { fun c = Test2_1.a fun e = Test2_1.n } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.177: fun c = Test2_1.a //│ ╙── ^^ //│ module Test2_1() { @@ -212,11 +212,8 @@ class Test2(n: int) { module Test3 { fun inc(t: Test2) = Test2(t.n + 1) } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.213: fun inc(t: Test2) = Test2(t.n + 1) -//│ ╙── ^^ //│ class Test2(n: int) { -//│ fun inc: Test2 | error +//│ fun inc: Test2 //│ } //│ module Test3() { //│ fun inc: (t: Test2,) -> Test2 diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 22a7361d33..baf5cf4161 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -13,6 +13,7 @@ class List { fun match: forall 'res; (ifNil: () => 'res, ifCons: (A, List[A]) => 'res) => 'res + fun match = error } let Nil: () => List<'a> let Cons: (head: 'a, tail: List<'a>) => List<'a> @@ -118,7 +119,7 @@ Test1.eval(Nil(), Var("a")) Test1.eval(Nil(), Abs("b", Var("a"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'a :> Var | App['a] | Abs['a] Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) //│ 'a @@ -143,7 +144,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) +//│ fun map_expr: forall 'A 'l 'A0 'l0. ('l -> 'A0 & 'l0 -> 'A, Add['l] | Mul['l0] | Num | Var,) -> (Add['A0] | Mul['A] | Num | Var) mixin EvalExpr { fun eval(sub, v) = diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 2314f68b38..cab2ae05b9 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -6,22 +6,16 @@ class Foo1(x: int) { fun test = Foo1(1).x } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.7: fun test = Foo1(1).x -//│ ╙── ^^ //│ class Foo1(x: int) { -//│ fun test: error +//│ fun test: int //│ } // TODO class Foo2[A](x: A) { fun test = Foo2(1).x } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.18: fun test = Foo2(1).x -//│ ╙── ^^ //│ class Foo2[A](x: A) { -//│ fun test: error +//│ fun test: A //│ } @@ -59,10 +53,10 @@ class Foo4 { fun test = [Foo4.test] } //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.59: fun test = [Foo4.test] +//│ ║ l.53: fun test = [Foo4.test] //│ ║ ^^^^^^^^^ //│ ╟── reference of type `() -> #Foo4` does not have field 'test' -//│ ║ l.59: fun test = [Foo4.test] +//│ ║ l.53: fun test = [Foo4.test] //│ ╙── ^^^^ //│ class Foo4() { //│ fun test: (error,) @@ -72,8 +66,8 @@ class Foo4 { class Foo5(x: int) { fun test = [Foo5(5).test] } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.73: fun test = [Foo5(5).test] +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.67: fun test = [Foo5(5).test] //│ ╙── ^^^^^ //│ class Foo5(x: int) { //│ fun test: (error,) @@ -85,14 +79,14 @@ class Foo6[A](x: A) { fun test2 = [Foo6(123).test] fun test3 = [Foo6([x]).test] } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.84: fun test1 = [Foo6(x).test] +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.78: fun test1 = [Foo6(x).test] //│ ╙── ^^^^^ -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.85: fun test2 = [Foo6(123).test] +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.79: fun test2 = [Foo6(123).test] //│ ╙── ^^^^^ -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.86: fun test3 = [Foo6([x]).test] +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.80: fun test3 = [Foo6([x]).test] //│ ╙── ^^^^^ //│ class Foo6[A](x: A) { //│ fun test1: (error,) @@ -109,25 +103,21 @@ class Foo7[A](head: A, tail: Foo7[A] | N) { N then head _ then tail.test1 } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.110: _ then tail.test1 +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.104: _ then tail.test1 //│ ╙── ^^^^^^ //│ class Foo7[A](head: A, tail: Foo7[A] | N) { //│ fun test1: A | error //│ } -// TODO support class Foo7_A[A](head: A, tail: Foo7_A[A] | N) { - test1: A + fun test1: A fun test1 = if tail is N then head _ then tail.test1 } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.124: _ then tail.test1 -//│ ╙── ^^^^^^ //│ class Foo7_A[A](head: A, tail: Foo7_A[A] | N) { -//│ fun test1: A | error +//│ fun test1: A //│ } class Foo7_A2[A](head: A, tail: Foo7_A[A] | N) { @@ -139,14 +129,23 @@ class Foo7_A2[A](head: A, tail: Foo7_A[A] | N) { //│ fun test1: A //│ } +class Foo7_2_A[A](head: A, tail: Foo7_A[int] | N) { + fun test1: int | A = if tail is + N then head + _ then tail.test1 +} +//│ class Foo7_2_A[A](head: A, tail: Foo7_A[int] | N) { +//│ fun test1: A | int +//│ } + :e class Foo8[A](x: A) { fun test1[B](y: B): A = let tmp = Foo8(y).test1(x) x } -//│ ╔══[ERROR] unsupported indirectly recursive member access -//│ ║ l.145: let tmp = Foo8(y).test1(x) +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.144: let tmp = Foo8(y).test1(x) //│ ╙── ^^^^^^ //│ class Foo8[A](x: A) { //│ fun test1: (y: anything,) -> A diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index f005c94753..21192498d5 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -9,7 +9,7 @@ :e class Foo { fun test = this.x } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.11: class Foo { fun test = this.x } //│ ╙── ^^ //│ class Foo() { @@ -19,7 +19,7 @@ class Foo { fun test = this.x } :e class Foo(n: int) { fun test = this.x } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.21: class Foo(n: int) { fun test = this.x } //│ ╙── ^^ //│ class Foo(n: int) { @@ -29,7 +29,7 @@ class Foo(n: int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.31: class Foo(n: A) { fun test = this.x } //│ ╙── ^^ //│ class Foo[A](n: A) { @@ -43,7 +43,7 @@ class Foo { this: { x: 'a } // fun test = this.x } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.43: this: { x: 'a } //│ ╙── ^ //│ class Foo() @@ -52,10 +52,10 @@ class Foo { // TODO // * All on one line: class Test { this: { x: int}; fun test = this.x } -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^^ -//│ ╔══[ERROR] unsupported indirectly recursive member access +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^ //│ class Test() { diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index b8454d0b7c..a9c5d082a7 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -16,6 +16,9 @@ type AI2 = Array :e type AI3(n) = Array[int] +//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ║ l.18: type AI3(n) = Array[int] +//│ ╙── ^ //│ ╔══[ERROR] type alias definitions cannot have value parameters //│ ║ l.18: type AI3(n) = Array[int] //│ ╙── ^^^ diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index bbecb28789..0828a21607 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -496,7 +496,7 @@ class DiffTests val (typeDefs, stmts, newDefsResults) = if (newDefs) { val vars: Map[Str, typer.SimpleType] = Map.empty - val tpd = typer.typeTypingUnit(TypingUnit(p.tops), allowPure = true)(ctx, raise, vars) + val tpd = typer.typeTypingUnit(TypingUnit(p.tops), topLevel = true)(ctx, raise, vars) def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind From 02b707b5e1d5854e6fdcca51fbfb50cb3bd27aa0 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 14 Mar 2023 00:37:24 +0800 Subject: [PATCH 192/498] WIP Improve field-access error messages --- .../main/scala/mlscript/ConstraintSolver.scala | 12 +++++++++--- .../src/main/scala/mlscript/NuTypeDefs.scala | 9 +++++++++ .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 8 ++++---- shared/src/test/diff/nu/BadClasses.mls | 4 ++-- shared/src/test/diff/nu/BasicClasses.mls | 2 +- shared/src/test/diff/nu/SelfRec.mls | 18 +++++++++--------- shared/src/test/diff/nu/ThisRefinedClasses.mls | 12 ++++++------ 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index c311086b73..228cd93920 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -33,6 +33,10 @@ class ConstraintSolver extends NormalForms { self: Typer => // TODO intersect with found signature! val fromRft = rfnt(fld) + def nope = + err(msg"${info.decl.kind.str.capitalize} `${info.decl.name}` does not contain member `${fld.name}`", + fld.toLoc).toUpper(noProv) + if (info.isComputing) { info.typedFields.get(fld) match { @@ -42,7 +46,10 @@ class ConstraintSolver extends NormalForms { self: Typer => case S(fty) => fty case N => - err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv) + if (info.allFields.contains(fld)) + err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv) + else + nope } } @@ -57,8 +64,7 @@ class ConstraintSolver extends NormalForms { self: Typer => err(msg"access to ${cls.td.kind.str} member not yet supported", fld.toLoc).toUpper(noProv) case N => - err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", - fld.toLoc).toUpper(noProv) + nope } println(s"Lookup ${cls.td.nme.name}.${fld.name} : $raw where ${raw.ub.showBounds}") diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 46454b9ebc..a6257dc746 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -510,6 +510,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => fd.nme.name -> TypedNuFun(level, fd, ty) }.toList + lazy val allFields: Set[Var] = decl match { + case td: NuTypeDef => + // TODO also get fields from parents! + (td.params.fields.iterator.flatMap(_._1) ++ td.body.entities.iterator.collect { + case fd: NuFunDef => fd.nme + }).toSet + case _: NuFunDef => Set.empty + } + lazy val typedFields: Map[Var, FieldType] = typedParams.toMap ++ typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 58fc6b9319..eaad25f32e 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -186,16 +186,16 @@ mixin Text { :e module SizeText extends Text -//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation +//│ ╔══[ERROR] Module `SizeText` does not contain member `size` //│ ║ l.180: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation +//│ ╔══[ERROR] Module `SizeText` does not contain member `size` //│ ║ l.179: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation +//│ ╔══[ERROR] Module `SizeText` does not contain member `size` //│ ║ l.178: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Indirectly-recursive member should have type annotoation +//│ ╔══[ERROR] Module `SizeText` does not contain member `size` //│ ║ l.177: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText() { diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index db9709bbbc..95398cc426 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -99,9 +99,9 @@ class Foo[A] { 42: A } //│ class Foo[A]() -:e // TODO better error +:e class C1 { fun oops = this.x } -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ╔══[ERROR] Class `C1` does not contain member `x` //│ ║ l.103: class C1 { fun oops = this.x } //│ ╙── ^^ //│ class C1() { diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index ab4da8550a..72503d1e5b 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -172,7 +172,7 @@ b.me :e b.getBaseTypo -//│ ╔══[ERROR] class `Base1` does not contain member `getBaseTypo` +//│ ╔══[ERROR] Class `Base1` does not contain member `getBaseTypo` //│ ║ l.174: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index cab2ae05b9..f790f7f2fd 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -75,19 +75,19 @@ class Foo5(x: int) { :e class Foo6[A](x: A) { - fun test1 = [Foo6(x).test] - fun test2 = [Foo6(123).test] - fun test3 = [Foo6([x]).test] + fun test1 = [Foo6(x).test1] + fun test2 = [Foo6(123).test2] + fun test3 = [Foo6([x]).test3] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.78: fun test1 = [Foo6(x).test] -//│ ╙── ^^^^^ +//│ ║ l.78: fun test1 = [Foo6(x).test1] +//│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.79: fun test2 = [Foo6(123).test] -//│ ╙── ^^^^^ +//│ ║ l.79: fun test2 = [Foo6(123).test2] +//│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.80: fun test3 = [Foo6([x]).test] -//│ ╙── ^^^^^ +//│ ║ l.80: fun test3 = [Foo6([x]).test3] +//│ ╙── ^^^^^^ //│ class Foo6[A](x: A) { //│ fun test1: (error,) //│ fun test2: (error,) diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 21192498d5..19cb4e3dca 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -9,7 +9,7 @@ :e class Foo { fun test = this.x } -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ╔══[ERROR] Class `Foo` does not contain member `x` //│ ║ l.11: class Foo { fun test = this.x } //│ ╙── ^^ //│ class Foo() { @@ -19,7 +19,7 @@ class Foo { fun test = this.x } :e class Foo(n: int) { fun test = this.x } -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ╔══[ERROR] Class `Foo` does not contain member `x` //│ ║ l.21: class Foo(n: int) { fun test = this.x } //│ ╙── ^^ //│ class Foo(n: int) { @@ -29,7 +29,7 @@ class Foo(n: int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ╔══[ERROR] Class `Foo` does not contain member `x` //│ ║ l.31: class Foo(n: A) { fun test = this.x } //│ ╙── ^^ //│ class Foo[A](n: A) { @@ -43,7 +43,7 @@ class Foo { this: { x: 'a } // fun test = this.x } -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ╔══[ERROR] Class `Foo` does not contain member `x` //│ ║ l.43: this: { x: 'a } //│ ╙── ^ //│ class Foo() @@ -52,10 +52,10 @@ class Foo { // TODO // * All on one line: class Test { this: { x: int}; fun test = this.x } -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ╔══[ERROR] Class `Test` does not contain member `x` //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^^ -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ╔══[ERROR] Class `Test` does not contain member `x` //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^ //│ class Test() { From a9c80d8c6fe27567630dd86945639ae473e8e296 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Tue, 14 Mar 2023 12:17:37 +0800 Subject: [PATCH 193/498] Add incomplete JSON test cases and support escape chars in `Lexer` --- shared/src/main/scala/mlscript/NewLexer.scala | 30 +- shared/src/test/diff/tapl/NuSimplyTyped.mls | 29 +- shared/src/test/diff/ucs/JSON.mls | 336 ++++++++++++++++++ 3 files changed, 378 insertions(+), 17 deletions(-) create mode 100644 shared/src/test/diff/ucs/JSON.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 57c2f88b4a..fd278f7eb0 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -55,6 +55,34 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { def takeWhile(i: Int, cur: Ls[Char] = Nil)(pred: Char => Bool): (Str, Int) = if (i < length && pred(bytes(i))) takeWhile(i + 1, bytes(i) :: cur)(pred) else (cur.reverseIterator.mkString, i) + + @tailrec final + def str(i: Int, escapeMode: Bool = false, cur: Ls[Char] = Nil): (Str, Int) = + if (escapeMode) + if (i < length) + bytes(i) match { + case '"' => str(i + 1, false, '"' :: cur) + case 'n' => str(i + 1, false, '\n' :: cur) + case 't' => str(i + 1, false, '\t' :: cur) + case 'r' => str(i + 1, false, '\r' :: cur) + case ch => + raise(WarningReport(msg"Found invalid escape character" -> S(loc(i, i + 1)) :: Nil, source = Lexing)) + str(i + 1, false, ch :: cur) + } + else { + raise(ErrorReport(msg"Expect an escape character" -> S(loc(i, i + 1)) :: Nil, source = Lexing)) + (cur.reverseIterator.mkString, i) + } + else { + if (i < length) + bytes(i) match { + case '\\' => str(i + 1, true, cur) + case '"' | '\n' => (cur.reverseIterator.mkString, i) + case ch => str(i + 1, false, ch :: cur) + } + else + (cur.reverseIterator.mkString, i) + } def loc(start: Int, end: Int): Loc = Loc(start, end, origin) @@ -78,7 +106,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { lex(j, ind, next(j, COMMA)) case '"' => val j = i + 1 - val (chars, k) = takeWhile(j)(c => c =/= '"' && c =/= '\n') + val (chars, k) = str(j) val k2 = if (bytes.lift(k) === Some('"')) k + 1 else { pe(msg"unclosed quotation mark") k diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls index 27d360521b..a87212a257 100644 --- a/shared/src/test/diff/tapl/NuSimplyTyped.mls +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -22,6 +22,7 @@ fun showDebug = logs.join("\n") //│ debug //│ = [Function: debug] +let str = toString fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) @@ -30,6 +31,7 @@ fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) fun par(a) = concat3("(", a, ")") +//│ let str: anything -> string //│ fun concat2: (string, string,) -> string //│ fun concat3: (string, string, string,) -> string //│ fun concat4: (string, string, string, string,) -> string @@ -38,6 +40,8 @@ fun par(a) = concat3("(", a, ")") //│ fun concat7: (string, string, string, string, string, string, string,) -> string //│ fun concat8: (string, string, string, string, string, string, string, string,) -> string //│ fun par: string -> string +//│ str +//│ = [Function: toString] type Option[A] = Some[A] | None class Some[A](value: A) @@ -54,11 +58,11 @@ class Err[A](message: A) //│ class Err[A](message: A) type Type = FunctionType | PrimitiveType -class FunctionType(lhs: Type, rhs: Type) class PrimitiveType(name: string) +class FunctionType(lhs: Type, rhs: Type) //│ type Type = FunctionType | PrimitiveType -//│ class FunctionType(lhs: Type, rhs: Type) //│ class PrimitiveType(name: string) +//│ class FunctionType(lhs: Type, rhs: Type) // Helpers. fun _f(lhs, rhs) = FunctionType(lhs, rhs) @@ -78,14 +82,11 @@ class App(lhs: Term, rhs: Term) //│ class Abs(lhs: Var, lty: Type, rhs: Term) //│ class App(lhs: Term, rhs: Term) -class Assumption(name: string, ty: Type) -//│ class Assumption(name: string, ty: Type) - -type Tree[A] = Node[A] | Empty -class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) +type TreeMap[A] = Node[A] | Empty +class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) module Empty -//│ type Tree[A] = Empty | Node[A] -//│ class Node[A](key: string, value: A, left: Tree[A], right: Tree[A]) +//│ type TreeMap[A] = Empty | Node[A] +//│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) //│ module Empty() fun insert(t, k, v) = @@ -159,7 +160,7 @@ showTerm(App(Abs(Var("x"), _t("int"), Var("y")), Var("z"))) //│ = '((&x: int => z) z)' // Removing the return type annotation causes stack overflow. -fun typeTerm(t, ctx): Result[Type, string] = +fun typeTerm(t: Term, ctx: TreeMap[Type]): Result[Type, string] = if t is Lit(_, ty) then Ok(ty) Var(name) and find(ctx, name) is @@ -176,17 +177,13 @@ fun typeTerm(t, ctx): Result[Type, string] = Err(message) then Err(message) Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) Err(message) then Err(message) -//│ fun typeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> Result[Type, string] -//│ where -//│ 'A := Type +//│ fun typeTerm: (t: Term, ctx: TreeMap[Type],) -> Result[Type, string] fun showTypeTerm(t, ctx) = if typeTerm(t, ctx) is Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) Err(message) then concat2("Type error: ", message) -//│ fun showTypeTerm: forall 'A. (Abs | App | Lit | Var, Empty | Node['A],) -> string -//│ where -//│ 'A := Type +//│ fun showTypeTerm: (Term, TreeMap[Type],) -> string showTypeTerm(Var("x"), Empty) showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), Empty) diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls new file mode 100644 index 0000000000..494ca6d20d --- /dev/null +++ b/shared/src/test/diff/ucs/JSON.mls @@ -0,0 +1,336 @@ +:NewParser +:NewDefs + +:escape +// You can push debug messages to this magic array. +let Array: { from: anything => { push: anything => anything, join: string => string } } +let _Array = Array +let logs: { push: anything => anything, join: string => string } = _Array.from([]) +let debug: anything => anything = x => logs.push(x) +fun showDebug = logs.join("\n") +// We need to use some native methods on `String`. +let String: nothing +let asNativeString: anything => { length: int, charCodeAt: int => int, charAt: int => string, slice: int => string } = String +let StringInstance: { fromCharCode: int => string } = String +// We will validate our implementation with the built-in `JSON.parse`. +let JSON: { parse: string => anything, stringify: anything => string } +//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} +//│ let logs: {join: string -> string, push: anything -> anything} +//│ let debug: anything -> anything +//│ fun showDebug: string +//│ let String: nothing +//│ let asNativeString: anything -> {charAt: int -> string, charCodeAt: int -> int, length: int, slice: int -> string} +//│ let StringInstance: {fromCharCode: int -> string} +//│ let JSON: {parse: string -> anything, stringify: anything -> string} +//│ Array +//│ = +//│ _Array +//│ = [Function: Array] +//│ logs +//│ = [] +//│ debug +//│ = [Function: debug] +//│ String +//│ = [Function: showDebug] +//│ asNativeString +//│ = +//│ StringInstance +//│ = [Function: String] +//│ JSON +//│ = [Function: String] + +JSON.parse("{ \"xs\": [1, 2, 3], \"yes\": true, \"no\": false, \"insane\": null }") +//│ anything +//│ res +//│ = { xs: [ 1, 2, 3 ], yes: true, no: false, insane: null } + +let getStringOf = toString +fun fromCharCode(n) = StringInstance.fromCharCode(n) +fun firstCharCode(s) = asNativeString(s).charCodeAt(0) +fun getCharAtIndex(s, i) = asNativeString(s).charAt(i) +fun strlen(s) = asNativeString(s).length +fun stringHead(s) = asNativeString(s).charAt(0) +fun stringTail(s) = asNativeString(s).slice(1) +//│ let getStringOf: anything -> string +//│ fun fromCharCode: int -> string +//│ fun firstCharCode: anything -> int +//│ fun getCharAtIndex: (anything, int,) -> string +//│ fun strlen: anything -> int +//│ fun stringHead: anything -> string +//│ fun stringTail: anything -> string +//│ getStringOf +//│ = [Function: toString] + +fun isWhiteSpace(ch) = + if (firstCharCode of ch) == + 9 then true // horizontal tab + 10 then true // linefeed + 32 then true // space + _ then false +//│ fun isWhiteSpace: anything -> bool + +fun isDigit(ch) = + let n = firstCharCode of ch + if 48 <= n and n <= 57 then true else false +//│ fun isDigit: anything -> bool + +fun isAlphabet(ch) = + let n = firstCharCode of ch + if n <= + 90 and n >= 65 then true + 122 and n >= 97 then true + else false +//│ fun isAlphabet: anything -> bool + +fun concat2(a, b) = concat(a)(b) +fun concat3(a, b, c) = concat2(a, concat2(b, c)) +fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) +fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) +fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) +fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) +fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) +fun par(a) = concat3("(", a, ")") +//│ fun concat2: (string, string,) -> string +//│ fun concat3: (string, string, string,) -> string +//│ fun concat4: (string, string, string, string,) -> string +//│ fun concat5: (string, string, string, string, string,) -> string +//│ fun concat6: (string, string, string, string, string, string,) -> string +//│ fun concat7: (string, string, string, string, string, string, string,) -> string +//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string +//│ fun par: string -> string + +type Option[A] = Some[A] | None +module None +class Some[A](value: A) +//│ type Option[A] = None | Some[A] +//│ module None() +//│ class Some[A](value: A) + +type List[A] = Cons[A] | Nil +module Nil +class Cons[A](head: A, tail: List[A]) +fun listConcat(xs, ys) = + if xs is + Nil then ys + Cons(x, xs') then Cons(x, listConcat(xs', ys)) +fun listJoin(xs, sep) = + if xs is + Nil then "" + Cons(x, xs') and xs' is + Nil then toString(x) + _ then concat3(toString(x), sep, listJoin(xs', sep)) +//│ type List[A] = Cons[A] | Nil +//│ module Nil() +//│ class Cons[A](head: A, tail: List[A]) +//│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) +//│ fun listJoin: forall 'A1. (Cons['A1] | Nil, string,) -> string +//│ where +//│ 'A <: 'A0 + +type TreeMap[A] = Node[A] | Empty +module Empty +class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) +fun insert(t, k, v) = + if t is + Node(k', _, l, r) and + slt(k)(k') then Node(k', v, insert(l, k, v), r) + sgt(k)(k') then Node(k', v, l, insert(r, k, v)) + _ then Node(k, v, l, r) + Empty then Node(k, v, Empty, Empty) +fun find(t, k) = + if t is + Node(k', v, l, r) and + slt(k)(k') then find(l, k) + sgt(k)(k') then find(r, k) + _ then Some(v) + Empty then None +fun traverse(t, f) = + if t is + Empty then Nil + Node(key, value, left, right) then + listConcat(traverse(left, f), Cons(f(key, value), traverse(right, f))) +//│ type TreeMap[A] = Empty | Node[A] +//│ module Empty() +//│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) +//│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] +//│ fun find: forall 'A0. (Empty | Node['A0], string,) -> (None | Some['A0]) +//│ fun traverse: forall 'A1 'A2. (Empty | Node['A1], (string, 'A1,) -> 'A2,) -> (Cons['A2] | Nil) + +type JsonValue = JsonNull | JsonNumber | JsonString | JsonBoolean | JsonObject | JsonArray +module JsonNull { + fun toString() = "null" +} +class JsonBoolean(value: bool) { + fun toString() = getStringOf(value) +} +class JsonNumber(value: number) { + fun toString() = getStringOf(value) +} +class JsonString(value: string) { + fun toString() = JSON.stringify(value) +} +class JsonObject(entries: TreeMap[JsonValue]) { + fun toString() = + if entries is Empty then "{}" + else concat3("{ ", listJoin(traverse(entries, (k, v) => concat3(k, ": ", getStringOf(v))), ", "), " }") +} +class JsonArray(elements: List[JsonValue]) { + fun toString() = concat3("[", listJoin(elements, ", "), "]") +} +//│ type JsonValue = JsonArray | JsonBoolean | JsonNull | JsonNumber | JsonObject | JsonString +//│ module JsonNull() { +//│ fun toString: () -> "null" +//│ } +//│ class JsonBoolean(value: bool) { +//│ fun toString: () -> string +//│ } +//│ class JsonNumber(value: number) { +//│ fun toString: () -> string +//│ } +//│ class JsonString(value: string) { +//│ fun toString: () -> string +//│ } +//│ class JsonObject(entries: TreeMap[JsonValue]) { +//│ fun toString: () -> string +//│ } +//│ class JsonArray(elements: List[JsonValue]) { +//│ fun toString: () -> string +//│ } + +toString of JsonNull +toString of JsonBoolean(true) +toString of JsonBoolean(false) +toString of JsonNumber(42) +toString of JsonArray of Nil +toString of JsonArray of Cons(JsonNumber(0), Cons(JsonNull, Cons(JsonNumber(1), Nil))) +toString of JsonObject of Empty +toString of JsonObject of insert(Empty, "hello", JsonString("world")) +//│ string +//│ res +//│ = 'null' +//│ res +//│ = 'true' +//│ res +//│ = 'false' +//│ res +//│ = '42' +//│ res +//│ = '[]' +//│ res +//│ = '[0, null, 1]' +//│ res +//│ = '{}' +//│ res +//│ = '{ hello: "world" }' + +class Scanner(source: string, at: int) { + fun peek: Option[string] = + if at < strlen(source) then Some(getCharAtIndex(source, at)) else None + fun advance: Scanner = + if at < strlen(source) then Scanner(source, at + 1) else this +} +fun scan(source) = Scanner(source, 0) +fun skipWhiteSpace(s: Scanner) = + if s.peek is Some(ch) and isWhiteSpace(ch) then + skipWhiteSpace(s.advance) + else + s +//│ class Scanner(source: string, at: int) { +//│ fun advance: Scanner +//│ fun peek: Option[string] +//│ } +//│ fun scan: string -> Scanner +//│ fun skipWhiteSpace: (s: Scanner,) -> Scanner + +type ParseResult[T] = ParseSuccess[T] | ParseFailure +class ParseSuccess[T](value: T, scanner: Scanner) { + fun toString() = concat2("Success: ", getStringOf(value)) +} +class ParseFailure(message: string, scanner: Scanner) { + fun toString() = concat4("Failure at ", getStringOf(scanner.at), ": ", message) +} +//│ type ParseResult[T] = ParseFailure | ParseSuccess[T] +//│ class ParseSuccess[T](value: T, scanner: Scanner) { +//│ fun toString: () -> string +//│ } +//│ class ParseFailure(message: string, scanner: Scanner) { +//│ fun toString: () -> string +//│ } + +fun expect(scanner, ch) = + if skipWhiteSpace(scanner).peek is + Some(ch') and + eq(ch)(ch') then ParseSuccess((), scanner.advance) + else ParseFailure(concat4("expect '", ch, "' but found ", ch'), scanner) + None then ParseFailure(concat3("expect '", ch, "' but found EOF"), scanner) +//│ fun expect: (Scanner & {advance: Scanner}, string,) -> (ParseFailure | ParseSuccess[()]) + +fun expectWord(scanner, word, result) = + if + strlen(word) > 0 and + let head = stringHead(word) + let tail = stringTail(word) + expect(scanner, head) is + ParseSuccess(_, scanner) then expectWord(scanner, tail, result) + ParseFailure(m, s) then ParseFailure(m, s) + scanner.peek is + Some(ch) and isAlphabet(ch) then + ParseFailure(concat3("there should not be other alphabets after\"", word, "\""), scanner) + else + ParseSuccess(result, scanner) +//│ fun expectWord: forall 'T. (Scanner & {advance: Scanner, peek: anything}, string, 'T,) -> (ParseFailure | ParseSuccess['T]) + +// If we put this function together with the next block, there will be type +// mismatch errors. +fun parseMatched(scanner, closingSymbol, parse, fn) = + if parse(scanner.advance) is + ParseSuccess(outcome, scanner) and expect(scanner, closingSymbol) is + ParseSuccess(_, scanner) then ParseSuccess(fn(outcome), scanner) + ParseFailure(message, scanner) then ParseFailure(message, scanner) + ParseFailure(message, scanner) then ParseFailure(message, scanner) +//│ fun parseMatched: forall 'advance 'value 'T. ({advance: 'advance}, string, 'advance -> (ParseFailure | ParseSuccess['value]), 'value -> 'T,) -> (ParseFailure | ParseSuccess['T]) + +:ng +fun parseEntries(scanner): ParseResult[TreeMap[JsonValue]] = error +fun parseElements(scanner): ParseResult[List[JsonValue]] = + let scanner' = skipWhiteSpace(scanner) + if scanner'.peek is + Some(ch) and + eq(ch)("]") then ParseSuccess(Nil, scanner') + parse(scanner') is + ParseSuccess(head, scanner') and scanner'.peek is + Some(ch) and eq(ch)(",") and parseElements(scanner'.advance) is + ParseSuccess(tail, scanner') then ParseSuccess(Cons(head, tail), scanner') + ParseFailure(m, s) then ParseFailure(m, s) + _ then ParseFailure("expect ']' or ',' instead of EOF", scanner') + ParseFailure(m, s) then ParseFailure(m, s) + None then ParseFailure("unexpected EOF", scanner) +fun parseStringContent(scanner): ParseResult[string] = error +fun parseNumber(scanner): ParseResult[JsonNumber] = error +fun parse(scanner) = + let scanner' = skipWhiteSpace(scanner) + if scanner'.peek is + None then ParseFailure("expect a JSON value instead of EOF", scanner') + Some(ch) and + eq(ch)("{") then parseMatched(scanner', "}", parseEntries, JsonObject) + eq(ch)("[") then parseMatched(scanner', "]", parseElements, JsonArray) + eq(ch)("\"") then parseMatched(scanner', "\"", parseStringContent, JsonString) + eq(ch)("-") then parseNumber(scanner') + eq(ch)("t") then expectWord(scanner', "true", JsonBoolean(true)) + eq(ch)("f") then expectWord(scanner', "false", JsonBoolean(false)) + eq(ch)("n") then expectWord(scanner', "null", JsonNull) + else + ParseFailure(concat3("unrecognized character '", ch, "'"), scanner) +//│ fun parseEntries: anything -> ParseResult[TreeMap[JsonValue]] +//│ fun parseElements: Scanner -> ParseResult[List[JsonValue]] +//│ fun parseStringContent: anything -> ParseResult[string] +//│ fun parseNumber: anything -> ParseResult[JsonNumber] +//│ fun parse: Scanner -> (ParseFailure | ParseSuccess[JsonArray | JsonBoolean | JsonNull | JsonObject | JsonString] | ParseResult[JsonNumber]) + +:ng +toString of parse of scan of " true" +toString of parse of scan of " false" +toString of parse of scan of " null" +toString of parse of scan of "[null]" +//│ string From 556eb26bcfb4e54f3fe03af553152ad327b68342 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Tue, 14 Mar 2023 12:34:49 +0800 Subject: [PATCH 194/498] Append test file updates --- shared/src/test/diff/tapl/NuSimplyTyped.mls | 4 ++-- shared/src/test/diff/tapl/NuUntyped.mls | 6 +++--- shared/src/test/diff/ucs/JSON.mls | 12 ++++++------ shared/src/test/diff/ucs/NestedBranches.mls | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls index a87212a257..e9d8c66fa1 100644 --- a/shared/src/test/diff/tapl/NuSimplyTyped.mls +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -46,7 +46,7 @@ fun par(a) = concat3("(", a, ")") type Option[A] = Some[A] | None class Some[A](value: A) module None -//│ type Option[A] = None | Some[A] +//│ type Option[A] = Some[A] | None //│ class Some[A](value: A) //│ module None() @@ -85,7 +85,7 @@ class App(lhs: Term, rhs: Term) type TreeMap[A] = Node[A] | Empty class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) module Empty -//│ type TreeMap[A] = Empty | Node[A] +//│ type TreeMap[A] = Node[A] | Empty //│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) //│ module Empty() diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index 72d37fdb97..eeb72430f6 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -72,7 +72,7 @@ class Some[A](value: A) { module None { fun toString() = "None" } -//│ type Option[A] = None | Some[A] +//│ type Option[A] = Some[A] | None //│ class Some[A](value: A) { //│ fun toString: () -> string //│ } @@ -108,9 +108,9 @@ fun listConcat(xs, ys) = if xs is Nil then ys Cons(x, xs') then Cons(x, listConcat(xs', ys)) -//│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) +//│ fun listConcat: forall 'A 'a 'A0. (Cons['A0] | Nil, List['A] & 'a,) -> (Cons['A] | 'a) //│ where -//│ 'A <: 'A0 +//│ 'A0 <: 'A fun listContains(xs, x) = if xs is diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index 494ca6d20d..35aa3c9bf0 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -103,7 +103,7 @@ fun par(a) = concat3("(", a, ")") type Option[A] = Some[A] | None module None class Some[A](value: A) -//│ type Option[A] = None | Some[A] +//│ type Option[A] = Some[A] | None //│ module None() //│ class Some[A](value: A) @@ -123,10 +123,10 @@ fun listJoin(xs, sep) = //│ type List[A] = Cons[A] | Nil //│ module Nil() //│ class Cons[A](head: A, tail: List[A]) -//│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) +//│ fun listConcat: forall 'A 'a 'A0. (Cons['A0] | Nil, List['A] & 'a,) -> (Cons['A] | 'a) //│ fun listJoin: forall 'A1. (Cons['A1] | Nil, string,) -> string //│ where -//│ 'A <: 'A0 +//│ 'A0 <: 'A type TreeMap[A] = Node[A] | Empty module Empty @@ -150,7 +150,7 @@ fun traverse(t, f) = Empty then Nil Node(key, value, left, right) then listConcat(traverse(left, f), Cons(f(key, value), traverse(right, f))) -//│ type TreeMap[A] = Empty | Node[A] +//│ type TreeMap[A] = Node[A] | Empty //│ module Empty() //│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) //│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] @@ -178,7 +178,7 @@ class JsonObject(entries: TreeMap[JsonValue]) { class JsonArray(elements: List[JsonValue]) { fun toString() = concat3("[", listJoin(elements, ", "), "]") } -//│ type JsonValue = JsonArray | JsonBoolean | JsonNull | JsonNumber | JsonObject | JsonString +//│ type JsonValue = JsonArray | JsonBoolean | JsonNumber | JsonObject | JsonString | JsonNull //│ module JsonNull() { //│ fun toString: () -> "null" //│ } @@ -279,7 +279,7 @@ fun expectWord(scanner, word, result) = ParseFailure(concat3("there should not be other alphabets after\"", word, "\""), scanner) else ParseSuccess(result, scanner) -//│ fun expectWord: forall 'T. (Scanner & {advance: Scanner, peek: anything}, string, 'T,) -> (ParseFailure | ParseSuccess['T]) +//│ fun expectWord: forall 'T. (Scanner & {peek: anything, advance: Scanner}, string, 'T,) -> (ParseFailure | ParseSuccess['T]) // If we put this function together with the next block, there will be type // mismatch errors. diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index a96d432f4e..3ed7a23d98 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -39,7 +39,7 @@ fun mapPartition(f, xs) = if xs is Cons(x, xs) and mapPartition(f, xs) is Pair(l, r) and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ fun mapPartition: forall 'A 'A0 'head. ('head -> (Left['A] | Right['A0]), Cons['head] | Nil,) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] +//│ fun mapPartition: forall 'head 'A 'A0. ('head -> (Left['A] | Right['A0]), Cons['head] | Nil,) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(x => Left(x + 1), zeroToThree) //│ Pair[Cons['A] | Nil, Cons['A0] | Nil] From 32c70de0c79d5a517c59c88dc8210cc796e14d4a Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Tue, 14 Mar 2023 12:54:34 +0800 Subject: [PATCH 195/498] No duplication when the else branch is taken at least once --- .../main/scala/mlscript/ucs/MutCaseOf.scala | 49 ++++++++++--------- shared/src/test/diff/tapl/NuUntyped.mls | 14 ------ shared/src/test/diff/tapl/Untyped.mls | 14 ------ shared/src/test/diff/ucs/DirectLines.mls | 16 ++---- shared/src/test/diff/ucs/MultiwayIf.mls | 12 ----- 5 files changed, 30 insertions(+), 75 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index f7273c38e0..93e04c789a 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -48,7 +48,7 @@ sealed abstract class MutCaseOf extends WithBindings { (implicit raise: Diagnostic => Unit): Unit def mergeDefault (bindings: Ls[(Bool, Var, Term)], default: Term) - (implicit raise: Diagnostic => Unit): Unit + (implicit raise: Diagnostic => Unit): Int // TODO: Make it immutable. var locations: Ls[Loc] = Nil @@ -153,7 +153,12 @@ object MutCaseOf { branch match { // The CC is a wildcard. So, we call `mergeDefault`. case Conjunction(Nil, trailingBindings) -> term => - this.mergeDefault(trailingBindings, term) + if (mergeDefault(trailingBindings, term) == 0) { + import Message.MessageContext + raise(WarningReport( + msg"Found a redundant else branch" -> term.toLoc :: Nil + )) + } // The CC is an if-then-else. We create a pattern match of true/false. case Conjunction((head @ BooleanTest(test)) :: tail, trailingBindings) -> term => // If the test is the same. So, we merge. @@ -181,18 +186,15 @@ object MutCaseOf { } } - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Unit = { - whenTrue.mergeDefault(bindings, default) - whenFalse match { - case Consequent(term) => - import Message.MessageContext - raise(WarningReport( - msg"Found a duplicated else branch" -> default.toLoc :: - (msg"The first else branch was declared here." -> term.toLoc) :: - Nil)) - case MissingCase => - whenFalse = Consequent(default).withBindings(bindings) - case _: IfThenElse | _: Match => whenFalse.mergeDefault(bindings, default) + def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = { + whenTrue.mergeDefault(bindings, default) + { + whenFalse match { + case Consequent(term) => 0 + case MissingCase => + whenFalse = Consequent(default).withBindings(bindings) + 1 + case _: IfThenElse | _: Match => whenFalse.mergeDefault(bindings, default) + } } } } @@ -259,13 +261,16 @@ object MutCaseOf { } } - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Unit = { - branches.foreach { + def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = { + branches.iterator.map { case MutCase(_, consequent) => consequent.mergeDefault(bindings, default) - } - wildcard match { - case N => wildcard = S(Consequent(default).withBindings(bindings)) - case S(consequent) => consequent.mergeDefault(bindings, default) + }.sum + { + wildcard match { + case N => + wildcard = S(Consequent(default).withBindings(bindings)) + 1 + case S(consequent) => consequent.mergeDefault(bindings, default) + } } } } @@ -275,7 +280,7 @@ object MutCaseOf { def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = raise(WarningReport(Message.fromStr("duplicated branch") -> N :: Nil)) - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Unit = () + def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 } final case object MissingCase extends MutCaseOf { def describe: Str = "MissingCase" @@ -283,7 +288,7 @@ object MutCaseOf { def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = lastWords("`MissingCase` is a placeholder and cannot be merged") - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Unit = () + def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 } private def buildFirst(conjunction: Conjunction, term: Term): MutCaseOf = { diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index eeb72430f6..d50352f920 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -200,7 +200,6 @@ isValue(App(Var("x"), Var("y"))) //│ res //│ = false -:w fun hasFree(t, n) = if t is // let __ = debug(concat3(showTerm(t), ", ", n)) @@ -209,12 +208,6 @@ fun hasFree(t, n) = Abs(Var(name), body) then hasFree(body, n) App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) _ then false -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.211: _ then false -//│ ║ ^^^^^ -//│ ╟── The first else branch was declared here. -//│ ║ l.209: Abs(Var(name), body) then hasFree(body, n) -//│ ╙── ^^^^^^^^^^^^^^^^ //│ fun hasFree: (anything, anything,) -> bool fun showHasFree(t, n) = @@ -342,7 +335,6 @@ fun findFreshName(name, freeNames) = fun freshName(name, body) = findFreshName(name, fv(body)) //│ fun freshName: (string, Abs | App | Var,) -> string -:w fun subst(t, n, v) = if t is Var(name) and eq(name)(n) then v @@ -352,12 +344,6 @@ fun subst(t, n, v) = _ then Abs(Var(name), subst(body, n, v)) App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.354: _ then t -//│ ║ ^ -//│ ╟── The first else branch was declared here. -//│ ║ l.352: _ then Abs(Var(name), subst(body, n, v)) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun subst: forall 'a. (Abs | App | Var | Term & 'a & ~#Abs & ~#App & ~#Var, anything, Term & 'a,) -> (Abs | App | Var | 'a) fun showSubst(t, n, v) = diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls index 78f4870c7e..4a2c6d937b 100644 --- a/shared/src/test/diff/tapl/Untyped.mls +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -223,7 +223,6 @@ isValue(App(Var("x"), Var("y"))) //│ res: bool //│ = false -:w fun hasFree(t, n) = if t is // let __ = debug(concat3(showTerm(t), ", ", n)) @@ -232,12 +231,6 @@ fun hasFree(t, n) = Abs(Var(name), body) then hasFree(body, n) App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) _ then false -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.234: _ then false -//│ ║ ^^^^^ -//│ ╟── The first else branch was declared here. -//│ ║ l.232: Abs(Var(name), body) then hasFree(body, n) -//│ ╙── ^^^^^^^^^^^^^^^^ //│ hasFree: ('rhs, anything,) -> bool //│ where //│ 'rhs <: Abs & {rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var | ~Abs & ~App & ~Var @@ -390,7 +383,6 @@ fun freshName(name, body) = findFreshName(name, fv(body)) //│ 'rhs <: Abs & {lhs: Var, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var //│ = [Function: freshName] -:w fun subst(t, n, v) = if t is Var(name) and eq(name)(n) then v @@ -400,12 +392,6 @@ fun subst(t, n, v) = _ then Abs(Var(name), subst(body, n, v)) App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.402: _ then t -//│ ║ ^ -//│ ╟── The first else branch was declared here. -//│ ║ l.400: _ then Abs(Var(name), subst(body, n, v)) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ subst: ('rhs, anything, 'rhs & 'rhs0 & 'rhs1 & 'rhs2,) -> 'rhs0 //│ where //│ 'rhs2 <: Abs & {rhs: 'rhs2} | App & {lhs: 'rhs2, rhs: 'rhs2} | Var | ~Abs & ~App & ~Var diff --git a/shared/src/test/diff/ucs/DirectLines.mls b/shared/src/test/diff/ucs/DirectLines.mls index a9c25364bf..ec7cad0909 100644 --- a/shared/src/test/diff/ucs/DirectLines.mls +++ b/shared/src/test/diff/ucs/DirectLines.mls @@ -33,7 +33,6 @@ fun f(x, allowNone) = //│ f: (anything, anything,) -> ("bad" | "good" | "okay") //│ = [Function: f1] -:w fun f(x, y, z) = if x == 0 then "x" @@ -45,12 +44,6 @@ fun f(x, y, z) = _ then "bruh" 3 then "y = 3" _ then "bruh" -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.47: _ then "bruh" -//│ ║ ^^^^^^ -//│ ╟── The first else branch was declared here. -//│ ║ l.45: _ then "bruh" -//│ ╙── ^^^^^^ //│ f: (number, number, number,) -> ("bruh" | "x" | "y = 1" | "y = 3" | "z = 0" | "z = 9") //│ = [Function: f2] @@ -63,11 +56,8 @@ fun f(a, b) = 2 then 2 _ then 7 else 3 -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.65: else 3 -//│ ║ ^ -//│ ╟── The first else branch was declared here. -//│ ║ l.64: _ then 7 -//│ ╙── ^ +//│ ╔══[WARNING] Found a redundant else branch +//│ ║ l.58: else 3 +//│ ╙── ^ //│ f: (number, number,) -> (0 | 1 | 2 | 7) //│ = [Function: f3] diff --git a/shared/src/test/diff/ucs/MultiwayIf.mls b/shared/src/test/diff/ucs/MultiwayIf.mls index 6a59d9b55d..086c6245d8 100644 --- a/shared/src/test/diff/ucs/MultiwayIf.mls +++ b/shared/src/test/diff/ucs/MultiwayIf.mls @@ -18,12 +18,6 @@ fun f(x) = _ then false x == 0 then true _ then false -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.20: _ then false -//│ ║ ^^^^^ -//│ ╟── The first else branch was declared here. -//│ ║ l.18: _ then false -//│ ╙── ^^^^^ //│ f: int -> bool //│ = [Function: f1] @@ -35,12 +29,6 @@ fun f(x) = else false x == 0 then true else false -//│ ╔══[WARNING] Found a duplicated else branch -//│ ║ l.37: else false -//│ ║ ^^^^^ -//│ ╟── The first else branch was declared here. -//│ ║ l.35: else false -//│ ╙── ^^^^^ //│ f: int -> bool //│ = [Function: f2] From c8ddd6e87dd7a5e9d2258fb3085cb37222579627 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Tue, 14 Mar 2023 21:47:12 +0800 Subject: [PATCH 196/498] Add a more essential test case --- shared/src/test/diff/ucs/LitUCS.mls | 62 +++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/shared/src/test/diff/ucs/LitUCS.mls b/shared/src/test/diff/ucs/LitUCS.mls index e6fd4f4196..f6f4760a44 100644 --- a/shared/src/test/diff/ucs/LitUCS.mls +++ b/shared/src/test/diff/ucs/LitUCS.mls @@ -5,34 +5,62 @@ module A //│ module A() // FIXME +// This one is easy to fix but what about the next one? +// The following example can better reveal the essence of the problem. fun test(x: 0 | A) = if x is 0 then 0 A then A //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.8: fun test(x: 0 | A) = if x is -//│ ║ ^ +//│ ║ l.10: fun test(x: 0 | A) = if x is +//│ ║ ^ //│ ╟── type `A` is not an instance of type `number` -//│ ║ l.8: fun test(x: 0 | A) = if x is -//│ ║ ^ +//│ ║ l.10: fun test(x: 0 | A) = if x is +//│ ║ ^ //│ ╟── but it flows into reference with expected type `number` -//│ ║ l.8: fun test(x: 0 | A) = if x is -//│ ╙── ^ +//│ ║ l.10: fun test(x: 0 | A) = if x is +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.8: fun test(x: 0 | A) = if x is -//│ ║ ^^^^ -//│ ║ l.9: 0 then 0 -//│ ║ ^^^^^^^^^^ -//│ ║ l.10: A then A +//│ ║ l.10: fun test(x: 0 | A) = if x is +//│ ║ ^^^^ +//│ ║ l.11: 0 then 0 +//│ ║ ^^^^^^^^^^ +//│ ║ l.12: A then A //│ ║ ^^^^^^^^^^ //│ ╟── type `0` is not an instance of type `A` -//│ ║ l.8: fun test(x: 0 | A) = if x is -//│ ║ ^ +//│ ║ l.10: fun test(x: 0 | A) = if x is +//│ ║ ^ //│ ╟── but it flows into reference with expected type `A` -//│ ║ l.8: fun test(x: 0 | A) = if x is -//│ ║ ^ +//│ ║ l.10: fun test(x: 0 | A) = if x is +//│ ║ ^ //│ ╟── Note: constraint arises from class pattern: -//│ ║ l.10: A then A +//│ ║ l.12: A then A //│ ╙── ^ //│ fun test: (x: 0 | A,) -> (0 | A) - +// FIXME +fun test(x: 0 | A) = + if + x == 0 then 0 + x is A then A +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.43: x == 0 then 0 +//│ ║ ^^^^ +//│ ╟── type `A` is not an instance of type `number` +//│ ║ l.41: fun test(x: 0 | A) = +//│ ║ ^ +//│ ╟── but it flows into reference with expected type `number` +//│ ║ l.43: x == 0 then 0 +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.44: x is A then A +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── type `0` is not an instance of type `A` +//│ ║ l.41: fun test(x: 0 | A) = +//│ ║ ^ +//│ ╟── but it flows into reference with expected type `A` +//│ ║ l.44: x is A then A +//│ ║ ^ +//│ ╟── Note: constraint arises from class pattern: +//│ ║ l.44: x is A then A +//│ ╙── ^ +//│ fun test: (x: 0 | A,) -> (0 | A) From aab8d27620dbbd3a956a54c62e0a4ef5d0cb2dca Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 15 Mar 2023 11:53:45 +0800 Subject: [PATCH 197/498] Remove syntax highlight overrides for .mls files --- .vscode/settings.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 23778bfa88..3e44ed841b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,6 @@ { "files.associations": { - "*.fun": "typescript", - "*.mls": "scala" + "*.fun": "typescript" }, "typescript.validate.enable": false, "files.watcherExclude": { From fef2c0cef108702f1af6d0bb91ce9dae021a267d Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 15 Mar 2023 12:58:58 +0800 Subject: [PATCH 198/498] No longer translate literal patterns to `==` applications --- .../src/main/scala/mlscript/ucs/Clause.scala | 45 +++--- .../main/scala/mlscript/ucs/Conjunction.scala | 14 +- .../main/scala/mlscript/ucs/Desugarer.scala | 145 +++++++++++------- .../main/scala/mlscript/ucs/MutCaseOf.scala | 110 +++++++++---- shared/src/test/diff/codegen/Mixin.mls | 12 +- .../test/diff/ecoop23/ExpressionProblem.mls | 2 +- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 10 +- shared/src/test/diff/nu/EvalNegNeg.mls | 2 +- shared/src/test/diff/nu/FilterMap.mls | 22 +-- shared/src/test/diff/ucs/Humiliation.mls | 4 +- shared/src/test/diff/ucs/LitUCS.mls | 40 +---- shared/src/test/diff/ucs/WeirdIf.mls | 21 ++- 12 files changed, 245 insertions(+), 182 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index 3b34155592..5f0bd38bbd 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -21,24 +21,46 @@ abstract class Clause { * @return */ val locations: Ls[Loc] + + protected final def bindingsToString: String = + (if (bindings.isEmpty) "" else " with " + Clause.showBindings(bindings)) } object Clause { + final case class MatchLiteral( + scrutinee: Scrutinee, + literal: SimpleTerm + )(override val locations: Ls[Loc]) extends Clause { + override def toString(): String = s"«$scrutinee is $literal" + bindingsToString + } + final case class MatchClass( scrutinee: Scrutinee, className: Var, fields: Ls[Str -> Var] - )(override val locations: Ls[Loc]) extends Clause + )(override val locations: Ls[Loc]) extends Clause { + override def toString(): String = s"«$scrutinee is $className»" + bindingsToString + } final case class MatchTuple( scrutinee: Scrutinee, arity: Int, fields: Ls[Str -> Var] - )(override val locations: Ls[Loc]) extends Clause + )(override val locations: Ls[Loc]) extends Clause { + override def toString(): String = s"«$scrutinee is Tuple#$arity»" + bindingsToString + } - final case class BooleanTest(test: Term)(override val locations: Ls[Loc]) extends Clause + final case class BooleanTest(test: Term)( + override val locations: Ls[Loc] + ) extends Clause { + override def toString(): String = s"«$test»" + bindingsToString + } - final case class Binding(name: Var, term: Term)(override val locations: Ls[Loc]) extends Clause + final case class Binding(name: Var, term: Term)( + override val locations: Ls[Loc] + ) extends Clause { + override def toString(): String = s"«$name = $term»" + bindingsToString + } def showBindings(bindings: Ls[(Bool, Var, Term)]): Str = bindings match { @@ -48,20 +70,7 @@ object Clause { }.mkString("(", ", ", ")") } - - def showClauses(clauses: Iterable[Clause]): Str = { - clauses.iterator.map { clause => - (clause match { - case Clause.BooleanTest(test) => s"«$test»" - case Clause.MatchClass(scrutinee, Var(className), fields) => - s"«$scrutinee is $className»" - case Clause.MatchTuple(scrutinee, arity, fields) => - s"«$scrutinee is Tuple#$arity»" - case Clause.Binding(Var(name), term) => - s"«$name = $term»" - }) + (if (clause.bindings.isEmpty) "" else " with " + showBindings(clause.bindings)) - }.mkString("", " and ", "") - } + def showClauses(clauses: Iterable[Clause]): Str = clauses.mkString("", " and ", "") def print(println: (=> Any) => Unit, conjunctions: Iterable[Conjunction -> Term]): Unit = { println("Flattened conjunctions") diff --git a/shared/src/main/scala/mlscript/ucs/Conjunction.scala b/shared/src/main/scala/mlscript/ucs/Conjunction.scala index ff9c6a2fb3..a849f42f11 100644 --- a/shared/src/main/scala/mlscript/ucs/Conjunction.scala +++ b/shared/src/main/scala/mlscript/ucs/Conjunction.scala @@ -3,6 +3,7 @@ package mlscript.ucs import mlscript._, utils._, shorthands._ import Clause._, helpers._ import scala.collection.mutable.Buffer +import scala.annotation.tailrec /** * A `Conjunction` represents a list of `Clause`s. @@ -53,13 +54,20 @@ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[(Bool, Va def +(lastBinding: (Bool, Var, Term)): Conjunction = Conjunction(clauses, trailingBindings :+ lastBinding) - def separate(expectedScrutinee: Scrutinee): Opt[(MatchClass, Conjunction)] = { - def rec(past: Ls[Clause], upcoming: Ls[Clause]): Opt[(Ls[Clause], MatchClass, Ls[Clause])] = { + def separate(expectedScrutinee: Scrutinee): Opt[(MatchClass \/ MatchLiteral, Conjunction)] = { + @tailrec + def rec(past: Ls[Clause], upcoming: Ls[Clause]): Opt[(Ls[Clause], MatchClass \/ MatchLiteral, Ls[Clause])] = { upcoming match { case Nil => N + case (head @ MatchLiteral(scrutinee, _)) :: tail => + if (scrutinee === expectedScrutinee) { + S((past, R(head), tail)) + } else { + rec(past :+ head, tail) + } case (head @ MatchClass(scrutinee, _, _)) :: tail => if (scrutinee === expectedScrutinee) { - S((past, head, tail)) + S((past, L(head), tail)) } else { rec(past :+ head, tail) } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 5191c13b53..a442be6c08 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -99,8 +99,13 @@ class Desugarer extends TypeDefs { self: Typer => def makeScrutinee(term: Term, matchRootLoc: Opt[Loc])(implicit ctx: Ctx): Scrutinee = traceUCS(s"Making a scrutinee for `$term`") { term match { - case _: SimpleTerm => Scrutinee(N, term)(matchRootLoc) - case _ => Scrutinee(S(makeLocalizedName(term)), term)(matchRootLoc) + case _: Var => + printlnUCS(s"The scrutinee does not need an alias.") + Scrutinee(N, term)(matchRootLoc) + case _ => + val localizedName = makeLocalizedName(term) + printlnUCS(s"The scrutinee needs an alias: $localizedName") + Scrutinee(S(localizedName), term)(matchRootLoc) } }() @@ -160,9 +165,13 @@ class Desugarer extends TypeDefs { self: Typer => case Var("_") => Nil // This case handles literals. // x is true | x is false | x is 0 | x is "text" | ... - case literal @ (Var("true") | Var("false") | _: Lit) => - val test = mkBinOp(scrutinee.reference, Var("=="), literal) - val clause = Clause.BooleanTest(test)(scrutinee.term.toLoc.toList ::: literal.toLoc.toList) + case literal: Var if literal.name === "true" || literal.name === "false" => + val clause = Clause.MatchLiteral(scrutinee, literal)(scrutinee.term.toLoc.toList ::: literal.toLoc.toList) + clause.bindings = scrutinee.asBinding.toList + printlnUCS(s"Add bindings to the clause: ${scrutinee.asBinding}") + clause :: Nil + case literal: Lit => + val clause = Clause.MatchLiteral(scrutinee, literal)(scrutinee.term.toLoc.toList ::: literal.toLoc.toList) clause.bindings = scrutinee.asBinding.toList printlnUCS(s"Add bindings to the clause: ${scrutinee.asBinding}") clause :: Nil @@ -515,22 +524,34 @@ class Desugarer extends TypeDefs { self: Typer => */ type ExhaustivenessMap = Map[Str \/ Int, Map[Var, MutCase]] - def getScurtineeKey(scrutinee: Scrutinee)(implicit ctx: Ctx, raise: Raise): Str \/ Int = { - scrutinee.term match { - // The original scrutinee is an reference. - case v @ Var(name) => - ctx.env.get(name) match { - case S(VarSymbol(_, defVar)) => defVar.uid.fold[Str \/ Int](L(v.name))(R(_)) - case S(_) | N => L(v.name) - } - // Otherwise, the scrutinee has a temporary name. - case _ => - scrutinee.local match { - case N => throw new Error("check your `makeScrutinee`") - case S(localNameVar) => L(localNameVar.name) - } - } - } + /** + * This method obtains a proper key of the given scrutinee + * for memorizing patterns belongs to the scrutinee. + * + * @param scrutinee the scrutinee + * @param ctx the context + * @param raise we need this to raise errors. + * @return the variable name or the variable ID + */ + def getScurtineeKey(scrutinee: Scrutinee)(implicit ctx: Ctx, raise: Raise): Str \/ Int = + traceUCS(s"[getScrutineeKey] $scrutinee") { + scrutinee.term match { + // The original scrutinee is an reference. + case v @ Var(name) => + printlnUCS("The original scrutinee is an reference.") + ctx.env.get(name) match { + case S(VarSymbol(_, defVar)) => defVar.uid.fold[Str \/ Int](L(v.name))(R(_)) + case S(_) | N => L(v.name) + } + // Otherwise, the scrutinee was localized because it might be effectful. + case _ => + printlnUCS("The scrutinee was localized because it might be effectful.") + scrutinee.local match { + case N => throw new Error("check your `makeScrutinee`") + case S(localNameVar) => L(localNameVar.name) + } + } + }() /** * Check the exhaustiveness of the given `MutCaseOf`. @@ -542,10 +563,8 @@ class Desugarer extends TypeDefs { self: Typer => def checkExhaustive (t: MutCaseOf, parentOpt: Opt[MutCaseOf]) (implicit scrutineePatternMap: ExhaustivenessMap, ctx: Ctx, raise: Raise) - : Unit = { - printlnUCS(s"Check exhaustiveness of ${t.describe}") - indent += 1 - try t match { + : Unit = traceUCS(s"[checkExhaustive] ${t.describe}") { + t match { case _: Consequent => () case MissingCase => parentOpt match { @@ -567,7 +586,10 @@ class Desugarer extends TypeDefs { self: Typer => case S(_) if default.isDefined => printlnUCS("The match has a default branch. So, it is always safe.") case S(patternMap) => - printlnUCS(s"The exhaustiveness map is ${scrutineePatternMap}") + printlnUCS(s"The exhaustiveness map is") + scrutineePatternMap.foreach { case (key, matches) => + printlnUCS(s"- $key -> ${matches.keysIterator.mkString(", ")}") + } printlnUCS(s"The scrutinee key is ${getScurtineeKey(scrutinee)}") printlnUCS("Pattern map of the scrutinee:") if (patternMap.isEmpty) @@ -575,10 +597,15 @@ class Desugarer extends TypeDefs { self: Typer => else patternMap.foreach { case (key, mutCase) => printlnUCS(s"- $key => $mutCase")} // Filter out missing cases in `branches`. - val missingCases = patternMap.removedAll(branches.iterator.map { - case MutCase(classNameVar -> _, _) => classNameVar + val missingCases = patternMap.removedAll(branches.iterator.flatMap { + case MutCase.Literal(tof @ Var(n), _) if n === "true" || n === "false" => Some(tof) + case MutCase.Literal(_, _) => None + case MutCase.Constructor(classNameVar -> _, _) => Some(classNameVar) }) - printlnUCS(s"Number of missing cases: ${missingCases.size}") + printlnUCS("Missing cases") + missingCases.foreach { case (key, m) => + printlnUCS(s"- $key -> ${m}") + } if (!missingCases.isEmpty) { throw new DesugaringException({ val numMissingCases = missingCases.size @@ -597,18 +624,16 @@ class Desugarer extends TypeDefs { self: Typer => } } default.foreach(checkExhaustive(_, S(t))) - branches.foreach { case MutCase(_, consequent) => - checkExhaustive(consequent, S(t)) + branches.foreach { branch => + checkExhaustive(branch.consequent, S(t)) } - } finally indent -= 1 - } + } + }() - def summarizePatterns(t: MutCaseOf)(implicit ctx: Ctx, raise: Raise): ExhaustivenessMap = { + def summarizePatterns(t: MutCaseOf)(implicit ctx: Ctx, raise: Raise): ExhaustivenessMap = traceUCS("[summarizePatterns]") { val m = MutMap.empty[Str \/ Int, MutMap[Var, MutCase]] - def rec(t: MutCaseOf): Unit = { - printlnUCS(s"Summarize pattern of ${t.describe}") - indent += 1 - try t match { + def rec(t: MutCaseOf): Unit = traceUCS(s"[rec] ${t.describe}") { + t match { case Consequent(term) => () case MissingCase => () case IfThenElse(_, whenTrue, whenFalse) => @@ -616,23 +641,36 @@ class Desugarer extends TypeDefs { self: Typer => rec(whenFalse) case Match(scrutinee, branches, default) => val key = getScurtineeKey(scrutinee) - branches.foreach { mutCase => - val patternMap = m.getOrElseUpdate( key, MutMap.empty) - if (!patternMap.contains(mutCase.patternFields._1)) { - patternMap += ((mutCase.patternFields._1, mutCase)) - } - rec(mutCase.consequent) + val patternMap = m.getOrElseUpdate(key, MutMap.empty) + branches.foreach { + case mutCase @ MutCase.Literal(literal, consequent) => + literal match { + case tof @ Var(n) if n === "true" || n === "false" => + if (!patternMap.contains(tof)) { + patternMap += ((tof, mutCase)) + } + case _ => () // TODO: Summarize literals. + } + rec(consequent) + case mutCase @ MutCase.Constructor((className, _), consequent) => + if (!patternMap.contains(className)) { + patternMap += ((className, mutCase)) + } + rec(consequent) } default.foreach(rec) - } finally indent -= 1 - } + } + }() rec(t) - printlnUCS("Exhaustiveness map") - m.foreach { case (scrutinee, patterns) => - printlnUCS(s"- $scrutinee => " + patterns.keys.mkString(", ")) - } + printlnUCS("Summarized patterns") + if (m.isEmpty) + printlnUCS("") + else + m.foreach { case (scrutinee, patterns) => + printlnUCS(s"- $scrutinee => " + patterns.keysIterator.mkString(", ")) + } Map.from(m.iterator.map { case (key, patternMap) => key -> Map.from(patternMap) }) - } + }() protected def constructTerm(m: MutCaseOf)(implicit ctx: Ctx): Term = { def rec(m: MutCaseOf)(implicit defs: Set[Var]): Term = m match { @@ -640,10 +678,13 @@ class Desugarer extends TypeDefs { self: Typer => case Match(scrutinee, branches, wildcard) => def rec2(xs: Ls[MutCase]): CaseBranches = xs match { - case MutCase(className -> fields, cases) :: next => + case MutCase.Constructor(className -> fields, cases) :: next => // TODO: expand bindings here val consequent = rec(cases)(defs ++ fields.iterator.map(_._2)) Case(className, mkLetFromFields(scrutinee, fields.toList, consequent), rec2(next)) + case MutCase.Literal(literal, cases) :: next => + val consequent = rec(cases) + Case(literal, consequent, rec2(next)) case Nil => wildcard.fold[CaseBranches](NoCases) { rec(_) |> Wildcard } } diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index 93e04c789a..9281d07942 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -79,12 +79,16 @@ object MutCaseOf { rec(whenFalse, indent + 1, "") case Match(scrutinee, branches, default) => lines += baseIndent + leading + bindingNames + showScrutinee(scrutinee) + " match" - branches.foreach { case MutCase(Var(className) -> fields, consequent) => - lines += s"$baseIndent case $className =>" - fields.foreach { case (field, Var(alias)) => - lines += s"$baseIndent let $alias = .$field" - } - rec(consequent, indent + 2, "") + branches.foreach { + case MutCase.Literal(literal, consequent) => + lines += s"$baseIndent case $literal =>" + rec(consequent, indent + 1, "") + case MutCase.Constructor(Var(className) -> fields, consequent) => + lines += s"$baseIndent case $className =>" + fields.foreach { case (field, Var(alias)) => + lines += s"$baseIndent let $alias = .$field" + } + rec(consequent, indent + 2, "") } default.foreach { consequent => lines += s"$baseIndent default" @@ -100,20 +104,12 @@ object MutCaseOf { lines.toList } - /** - * MutCase is a _mutable_ representation of a case in `MutCaseOf.Match`. - * - * @param patternFields the alias to the fields - * @param consequent the consequential `MutCaseOf` - */ - final case class MutCase( - val patternFields: Var -> Buffer[Str -> Var], - var consequent: MutCaseOf, - ) { - def matches(expected: Var): Bool = matches(expected.name) - def matches(expected: Str): Bool = patternFields._1.name === expected - def addFields(fields: Iterable[Str -> Var]): Unit = - patternFields._2 ++= fields.iterator.filter(!patternFields._2.contains(_)) + sealed abstract class MutCase { + var consequent: MutCaseOf + + def matches(expected: Var): Bool + def matches(expected: Str): Bool + def matches(expected: Lit): Bool // Note 1 // ====== @@ -142,7 +138,38 @@ object MutCaseOf { } } - import Clause.{MatchClass, MatchTuple, BooleanTest, Binding} + object MutCase { + final case class Literal( + val literal: SimpleTerm, + var consequent: MutCaseOf, + ) extends MutCase { + override def matches(expected: Var): Bool = literal match { + case tof @ Var(n) if n === "true" || n === "false" => expected === tof + case _ => false + } + override def matches(expected: Str): Bool = false + override def matches(expected: Lit): Bool = literal === expected + } + + /** + * MutCase is a _mutable_ representation of a case in `MutCaseOf.Match`. + * + * @param patternFields the alias to the fields + * @param consequent the consequential `MutCaseOf` + */ + final case class Constructor( + val patternFields: Var -> Buffer[Str -> Var], + var consequent: MutCaseOf, + ) extends MutCase { + override def matches(expected: Var): Bool = matches(expected.name) + override def matches(expected: Str): Bool = patternFields._1.name === expected + override def matches(expected: Lit): Bool = false + def addFields(fields: Iterable[Str -> Var]): Unit = + patternFields._2 ++= fields.iterator.filter(!patternFields._2.contains(_)) + } + } + + import Clause.{MatchLiteral, MatchClass, MatchTuple, BooleanTest, Binding} // A short-hand for pattern matchings with only true and false branches. final case class IfThenElse(condition: Term, var whenTrue: MutCaseOf, var whenFalse: MutCaseOf) extends MutCaseOf { @@ -223,16 +250,17 @@ object MutCaseOf { case N => val newBranch = buildFirst(Conjunction(tail, trailingBindings), term) newBranch.addBindings(head.bindings) - branches += MutCase(tupleClassName -> Buffer.from(fields), newBranch) + branches += MutCase.Constructor(tupleClassName -> Buffer.from(fields), newBranch) .withLocations(head.locations) // Found existing pattern. - case S(branch) => + case S(branch: MutCase.Constructor) => branch.consequent.addBindings(head.bindings) branch.addFields(fields) branch.consequent.merge(Conjunction(tail, trailingBindings) -> term) } // A wild card case. We should propagate wildcard to every default positions. - case Conjunction(Nil, trailingBindings) -> term => mergeDefault(trailingBindings, term) + case Conjunction(Nil, trailingBindings) -> term => + mergeDefault(trailingBindings, term) // TODO: Handle the int result here. // The conditions to be inserted does not overlap with me. case conjunction -> term => wildcard match { @@ -243,27 +271,44 @@ object MutCaseOf { } } // Found a match condition against the same scrutinee - case S((head @ MatchClass(_, className, fields), remainingConditions)) => + case S(L(head @ MatchClass(_, className, fields)) -> remainingConditions) => branches.find(_.matches(className)) match { // No such pattern. We should create a new one. case N => val newBranch = buildFirst(remainingConditions, branch._2) newBranch.addBindings(head.bindings) - branches += MutCase(className -> Buffer.from(fields), newBranch) + branches += MutCase.Constructor(className -> Buffer.from(fields), newBranch) .withLocations(head.locations) // Found existing pattern. - case S(matchCase) => + case S(matchCase: MutCase.Constructor) => // Merge interleaved bindings. matchCase.consequent.addBindings(head.bindings) matchCase.addFields(fields) matchCase.consequent.merge(remainingConditions -> branch._2) } + case S(R(head @ MatchLiteral(_, literal)) -> remainingConditions) => + branches.find(branch => literal match { + case v: Var => branch.matches(v) + case l: Lit => branch.matches(l) + }) match { + // No such pattern. We should create a new one. + case N => + val newConsequent = buildFirst(remainingConditions, branch._2) + newConsequent.addBindings(head.bindings) + branches += MutCase.Literal(literal, newConsequent) + .withLocations(head.locations) + case S(matchCase: MutCase.Literal) => + // Merge interleaved bindings. + matchCase.consequent.addBindings(head.bindings) + matchCase.consequent.merge(remainingConditions -> branch._2) + } } } def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = { branches.iterator.map { - case MutCase(_, consequent) => consequent.mergeDefault(bindings, default) + case MutCase.Constructor(_, consequent) => consequent.mergeDefault(bindings, default) + case MutCase.Literal(_, consequent) => consequent.mergeDefault(bindings, default) }.sum + { wildcard match { case N => @@ -296,16 +341,21 @@ object MutCaseOf { case Conjunction(head :: tail, trailingBindings) => val realTail = Conjunction(tail, trailingBindings) (head match { + case MatchLiteral(scrutinee, literal) => + val branches = Buffer( + MutCase.Literal(literal, rec(realTail)).withLocation(literal.toLoc) + ) + Match(scrutinee, branches, N) case BooleanTest(test) => IfThenElse(test, rec(realTail), MissingCase) case MatchClass(scrutinee, className, fields) => val branches = Buffer( - MutCase(className -> Buffer.from(fields), rec(realTail)) + MutCase.Constructor(className -> Buffer.from(fields), rec(realTail)) .withLocations(head.locations) ) Match(scrutinee, branches, N) case MatchTuple(scrutinee, arity, fields) => val branches = Buffer( - MutCase(Var(s"Tuple#$arity") -> Buffer.from(fields), rec(realTail)) + MutCase.Constructor(Var(s"Tuple#$arity") -> Buffer.from(fields), rec(realTail)) .withLocations(head.locations) ) Match(scrutinee, branches, N) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 16a0b6d2cd..b10c745fba 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -373,7 +373,7 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) TestLang.eval(mk(0)) -//│ fun mk: forall 'E. number -> 'E +//│ fun mk: forall 'E. anything -> 'E //│ int //│ where //│ 'E :> Add['E] | Lit | Neg['E] @@ -381,7 +381,8 @@ TestLang.eval(mk(0)) //│ let typing_unit6 = { cache: {} }; //│ // Query 1 //│ globalThis.mk = function mk(n) { -//│ return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); +//│ let a; +//│ return a = n, a === 0 ? Lit(0) : a === 1 ? Neg(mk(n)) : Add(mk(n), mk(n)); //│ }; //│ // Query 2 //│ res = TestLang.eval(mk(0)); @@ -396,7 +397,8 @@ TestLang.eval(mk(0)) //│ │ ├── Prelude: //│ │ ├── Code: //│ │ ├── globalThis.mk = function mk(n) { -//│ │ ├── return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); +//│ │ ├── let a; +//│ │ ├── return a = n, a === 0 ? Lit(0) : a === 1 ? Neg(mk(n)) : Add(mk(n), mk(n)); //│ │ ├── }; //│ │ ├── Intermediate: [Function: mk] //│ │ └── Reply: [success] [Function: mk] @@ -417,7 +419,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.418: class Bar(x: int, y: int) extends Foo(x + y) +//│ ║ l.420: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -530,7 +532,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.530: fun x = y +//│ ║ l.532: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index 2584f30706..659cb988d0 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -201,7 +201,7 @@ fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ fun mk: forall 'E. number -> 'E +//│ fun mk: forall 'E. anything -> 'E //│ where //│ 'E :> Add['E] | Lit | Neg['E] diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index eaad25f32e..8e9f462598 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -45,7 +45,7 @@ fun go(x, offset) = else let shared = go(x - 1, round(offset / 2)) Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) -//│ fun go: forall 'Region. (int, int,) -> 'Region +//│ fun go: forall 'Region. (0 | int & ~0, int,) -> 'Region //│ where //│ 'Region :> Circle | Union[Translate['Region]] @@ -116,7 +116,7 @@ TestSize.size(Scale(Vector(1, 1), circles)) fun pow(x, a) = if a is 0 then 1 else x * pow(x, a - 1) -//│ fun pow: (int, int,) -> int +//│ fun pow: (int, 0 | int & ~0,) -> int mixin Contains { fun contains(a, p) = @@ -327,7 +327,7 @@ module TestElim extends Eliminate TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where -//│ 'a :> Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ 'a :> Scale['a] | Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] //│ res //│ = Univ {} @@ -344,7 +344,7 @@ fun mk(n) = if n is 3 then Intersect(mk(n), mk(n)) 4 then Translate(Vector(0, 0), mk(n)) _ then Scale(Vector(0, 0), mk(n)) -//│ fun mk: forall 'Region. number -> 'Region +//│ fun mk: forall 'Region. anything -> 'Region //│ where //│ 'Region :> Intersect['Region] | Outside['Region] | Scale['Region] | Translate['Region] | Union['Region] @@ -376,7 +376,7 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~#Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'c :> Translate['c] | Scale['c] | Outside['c] | Union['c] | Intersect['c] +//│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] // TODO investigate diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index b1aef73e5a..94db7f6f61 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -61,7 +61,7 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) TestLang.eval(mk(0)) -//│ fun mk: forall 'E. number -> 'E +//│ fun mk: forall 'E. anything -> 'E //│ int //│ where //│ 'E :> Add['E] | Lit | Neg['E] diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 8c5cd4dd2e..4285f53f88 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -31,27 +31,9 @@ fun filtermap(f, xs) = if xs is //│ ╔══[ERROR] identifier not found: ys //│ ║ l.27: Cons(y, ys) and f(ys) is //│ ╙── ^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.27: Cons(y, ys) and f(ys) is -//│ ║ ^^^^^^^^ -//│ ║ l.28: false then filtermap(f, ys) -//│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `number` -//│ ║ l.28: false then filtermap(f, ys) -//│ ╙── ^^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.27: Cons(y, ys) and f(ys) is -//│ ║ ^^^^^^^^ -//│ ║ l.28: false then filtermap(f, ys) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.29: true then Cons(y, filtermap(f, ys)) -//│ ║ ^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `number` -//│ ║ l.29: true then Cons(y, filtermap(f, ys)) -//│ ╙── ^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── -//│ fun filtermap: ((Cons[nothing] | error | Nil) -> number & (Cons[nothing] | Nil) -> error, Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) +//│ fun filtermap: ((Cons[nothing] | error | Nil) -> anything & (Cons[nothing] | Nil) -> (error | false | true), Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 @@ -70,6 +52,6 @@ fun filtermap(f, xs) = if xs is True then filtermap(f, ys) False then Cons(y, filtermap(f, ys)) Pair(True, z) then Cons(z, filtermap(f, ys)) -//│ fun filtermap: forall 'head 'A. ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) +//│ fun filtermap: forall 'A 'head. ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) diff --git a/shared/src/test/diff/ucs/Humiliation.mls b/shared/src/test/diff/ucs/Humiliation.mls index bb55ab0a1c..7629b41a94 100644 --- a/shared/src/test/diff/ucs/Humiliation.mls +++ b/shared/src/test/diff/ucs/Humiliation.mls @@ -11,7 +11,7 @@ if 1 is 1 then 1 else 0 //│ = 1 fun test(x) = if x is 1 then 0 else 1 -//│ test: number -> (0 | 1) +//│ test: anything -> (0 | 1) //│ = [Function: test] // It should report duplicated branches. @@ -47,7 +47,7 @@ fun f(x) = Pair(1, 1) then "ones" Pair(y, 1) then x _ then "nah" -//│ f: (Pair & {fst: number, snd: number} & 'a | ~Pair) -> ("nah" | "ones" | "zeros" | 'a) +//│ f: (Pair & 'a | ~Pair) -> ("nah" | "ones" | "zeros" | 'a) //│ = [Function: f] class Z() diff --git a/shared/src/test/diff/ucs/LitUCS.mls b/shared/src/test/diff/ucs/LitUCS.mls index f6f4760a44..a9fd1c900a 100644 --- a/shared/src/test/diff/ucs/LitUCS.mls +++ b/shared/src/test/diff/ucs/LitUCS.mls @@ -4,37 +4,11 @@ module A //│ module A() -// FIXME // This one is easy to fix but what about the next one? // The following example can better reveal the essence of the problem. fun test(x: 0 | A) = if x is 0 then 0 A then A -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.10: fun test(x: 0 | A) = if x is -//│ ║ ^ -//│ ╟── type `A` is not an instance of type `number` -//│ ║ l.10: fun test(x: 0 | A) = if x is -//│ ║ ^ -//│ ╟── but it flows into reference with expected type `number` -//│ ║ l.10: fun test(x: 0 | A) = if x is -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.10: fun test(x: 0 | A) = if x is -//│ ║ ^^^^ -//│ ║ l.11: 0 then 0 -//│ ║ ^^^^^^^^^^ -//│ ║ l.12: A then A -//│ ║ ^^^^^^^^^^ -//│ ╟── type `0` is not an instance of type `A` -//│ ║ l.10: fun test(x: 0 | A) = if x is -//│ ║ ^ -//│ ╟── but it flows into reference with expected type `A` -//│ ║ l.10: fun test(x: 0 | A) = if x is -//│ ║ ^ -//│ ╟── Note: constraint arises from class pattern: -//│ ║ l.12: A then A -//│ ╙── ^ //│ fun test: (x: 0 | A,) -> (0 | A) // FIXME @@ -43,24 +17,24 @@ fun test(x: 0 | A) = x == 0 then 0 x is A then A //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.43: x == 0 then 0 +//│ ║ l.17: x == 0 then 0 //│ ║ ^^^^ //│ ╟── type `A` is not an instance of type `number` -//│ ║ l.41: fun test(x: 0 | A) = +//│ ║ l.15: fun test(x: 0 | A) = //│ ║ ^ //│ ╟── but it flows into reference with expected type `number` -//│ ║ l.43: x == 0 then 0 +//│ ║ l.17: x == 0 then 0 //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.44: x is A then A +//│ ║ l.18: x is A then A //│ ║ ^^^^^^^^^^^^^ //│ ╟── type `0` is not an instance of type `A` -//│ ║ l.41: fun test(x: 0 | A) = +//│ ║ l.15: fun test(x: 0 | A) = //│ ║ ^ //│ ╟── but it flows into reference with expected type `A` -//│ ║ l.44: x is A then A +//│ ║ l.18: x is A then A //│ ║ ^ //│ ╟── Note: constraint arises from class pattern: -//│ ║ l.44: x is A then A +//│ ║ l.18: x is A then A //│ ╙── ^ //│ fun test: (x: 0 | A,) -> (0 | A) diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index 708280aa36..4fe9061ee8 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -79,20 +79,17 @@ fun f(x) = //│ f: anything -> "bruh" //│ = [Function: f3] -:e -:ge // Hmmmmmm, this one is valid but how to get it work? fun boolToStr(x) = if x is true then "yah" false then "nah" -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (false,) -//│ ║ l.86: if x is -//│ ║ ^^^^ -//│ ║ l.87: true then "yah" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.88: false then "nah" -//│ ╙── ^^^^^^^^^ -//│ boolToStr: anything -> error -//│ Code generation encountered an error: -//│ if expression was not desugared +//│ boolToStr: bool -> ("nah" | "yah") +//│ = [Function: boolToStr] + +boolToStr of true +boolToStr of false +//│ res: "nah" | "yah" +//│ = 'yah' +//│ res: "nah" | "yah" +//│ = 'nah' From 8ac73ee639c6b2875845be94d3a49de853f00655 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 15 Mar 2023 16:37:58 +0800 Subject: [PATCH 199/498] Categorize let bindings so no longer missing alias patterns --- .../src/main/scala/mlscript/ucs/Clause.scala | 13 +- .../main/scala/mlscript/ucs/Conjunction.scala | 6 +- .../main/scala/mlscript/ucs/Desugarer.scala | 152 +++++++++++------- .../main/scala/mlscript/ucs/LetBinding.scala | 40 +++++ .../main/scala/mlscript/ucs/MutCaseOf.scala | 41 ++--- .../main/scala/mlscript/ucs/Scrutinee.scala | 4 +- .../src/main/scala/mlscript/ucs/helpers.scala | 10 +- shared/src/test/diff/nu/BadUCS.mls | 15 +- shared/src/test/diff/nu/FilterMap.mls | 36 ++++- shared/src/test/diff/ucs/InterleavedLet.mls | 24 ++- 10 files changed, 227 insertions(+), 114 deletions(-) create mode 100644 shared/src/main/scala/mlscript/ucs/LetBinding.scala diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index 5f0bd38bbd..9cb87af63f 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -13,7 +13,7 @@ abstract class Clause { /** * Local interleaved let bindings declared before this condition. */ - var bindings: Ls[(Bool, Var, Term)] = Nil + var bindings: Ls[LetBinding] = Nil /** * Locations of terms that build this `Clause`. @@ -56,18 +56,19 @@ object Clause { override def toString(): String = s"«$test»" + bindingsToString } - final case class Binding(name: Var, term: Term)( + /** + * @param isField whether this binding is extracting a class field + */ + final case class Binding(name: Var, term: Term, isField: Bool)( override val locations: Ls[Loc] ) extends Clause { override def toString(): String = s"«$name = $term»" + bindingsToString } - def showBindings(bindings: Ls[(Bool, Var, Term)]): Str = + def showBindings(bindings: Ls[LetBinding]): Str = bindings match { case Nil => "" - case bindings => bindings.map { - case (_, Var(name), _) => name - }.mkString("(", ", ", ")") + case bindings => bindings.map(_.name.name).mkString("(", ", ", ")") } def showClauses(clauses: Iterable[Clause]): Str = clauses.mkString("", " and ", "") diff --git a/shared/src/main/scala/mlscript/ucs/Conjunction.scala b/shared/src/main/scala/mlscript/ucs/Conjunction.scala index a849f42f11..875a6b0489 100644 --- a/shared/src/main/scala/mlscript/ucs/Conjunction.scala +++ b/shared/src/main/scala/mlscript/ucs/Conjunction.scala @@ -8,7 +8,7 @@ import scala.annotation.tailrec /** * A `Conjunction` represents a list of `Clause`s. */ -final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[(Bool, Var, Term)]) { +final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[LetBinding]) { /** * Concatenate two `Conjunction` together. * @@ -51,7 +51,7 @@ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[(Bool, Va * @param suffix the list of clauses to append to this conjunction * @return a new conjunction with clauses from `this` and `suffix` */ - def +(lastBinding: (Bool, Var, Term)): Conjunction = + def +(lastBinding: LetBinding): Conjunction = Conjunction(clauses, trailingBindings :+ lastBinding) def separate(expectedScrutinee: Scrutinee): Opt[(MatchClass \/ MatchLiteral, Conjunction)] = { @@ -87,7 +87,7 @@ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[(Bool, Va * @param interleavedLets the buffer of let bindings in the current context * @return idential to `conditions` */ - def withBindings(implicit interleavedLets: Buffer[(Bool, Var, Term)]): Conjunction = { + def withBindings(implicit interleavedLets: Buffer[LetBinding]): Conjunction = { clauses match { case Nil => Conjunction(Nil, interleavedLets.toList ::: trailingBindings) case head :: _ => diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index a442be6c08..1fa839909e 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -80,7 +80,7 @@ class Desugarer extends TypeDefs { self: Typer => private def destructSubPatterns(scrutinee: Scrutinee, subPatterns: Iterable[Var -> Term]) (implicit ctx: Ctx, raise: Raise, aliasMap: FieldAliasMap): Ls[Clause] = { subPatterns.iterator.flatMap[Clause] { case (subScrutinee, subPattern) => - destructPattern(makeScrutinee(subScrutinee, scrutinee.matchRootLoc), subPattern) + destructPattern(makeScrutinee(subScrutinee, scrutinee.matchRootLoc), subPattern, false) }.toList } @@ -130,6 +130,7 @@ class Desugarer extends TypeDefs { self: Typer => * * @param scrutinee the scrutinee of the pattern matching * @param pattern the pattern we will destruct + * @param isTopLevel whether this pattern just follows the `is` operator * @param raise the `Raise` function * @param aliasMap the field alias map * @param matchRootLoc the location of the root of the pattern matching @@ -140,7 +141,7 @@ class Desugarer extends TypeDefs { self: Typer => * do not contain interleaved let bindings. */ private def destructPattern - (scrutinee: Scrutinee, pattern: Term) + (scrutinee: Scrutinee, pattern: Term, isTopLevel: Bool) (implicit ctx: Ctx, raise: Raise, aliasMap: FieldAliasMap, @@ -178,7 +179,7 @@ class Desugarer extends TypeDefs { self: Typer => // This case handles name binding. // x is a case bindingVar @ Var(bindingName) if bindingName.headOption.exists(_.isLower) => - Clause.Binding(bindingVar, scrutinee.term)(scrutinee.term.toLoc.toList ::: bindingVar.toLoc.toList) :: Nil + Clause.Binding(bindingVar, scrutinee.term, !isTopLevel)(scrutinee.term.toLoc.toList ::: bindingVar.toLoc.toList) :: Nil // This case handles simple class tests. // x is A case classNameVar @ Var(className) => @@ -246,12 +247,12 @@ class Desugarer extends TypeDefs { self: Typer => msg"Cannot find operator `$op` in the context" }, opVar.toLoc) case S(td) if td.positionals.length === 2 => - val (subPatterns, bindings) = desugarPositionals( + val (subPatterns, fields) = desugarPositionals( scrutinee, lhs :: rhs :: Nil, td.positionals ) - val clause = Clause.MatchClass(scrutinee, opVar, bindings)(collectLocations(scrutinee.term)) + val clause = Clause.MatchClass(scrutinee, opVar, fields)(collectLocations(scrutinee.term)) printlnUCS(s"Build a Clause.MatchClass from $scrutinee where operator is $opVar") clause :: destructSubPatterns(scrutinee, subPatterns) case S(td) => @@ -293,7 +294,7 @@ class Desugarer extends TypeDefs { self: Typer => def desugarIf (body: IfBody, fallback: Opt[Term]) (implicit ctx: Ctx, raise: Raise) - : Ls[Conjunction -> Term] = { + : Ls[Conjunction -> Term] = traceUCS(s"[desugarIf] with fallback $fallback") { // We allocate temporary variable names for nested patterns. // This prevents aliasing problems. implicit val scrutineeFieldAliasMap: FieldAliasMap = MutMap.empty @@ -317,7 +318,7 @@ class Desugarer extends TypeDefs { self: Typer => // This is an inline `x is Class` match test. val inlineMatchLoc = isApp.toLoc val inlineScrutinee = makeScrutinee(scrutinee, inlineMatchLoc) - destructPattern(inlineScrutinee, pattern)(ctx, raise, scrutineeFieldAliasMap) + destructPattern(inlineScrutinee, pattern, true)(ctx, raise, scrutineeFieldAliasMap) case test => val clause = Clause.BooleanTest(test)(collectLocations(test)) Iterable.single(clause) @@ -339,7 +340,7 @@ class Desugarer extends TypeDefs { self: Typer => body: IfBody \/ Statement, partialPattern: PartialTerm, collectedConditions: Conjunction, - )(implicit interleavedLets: Buffer[(Bool, Var, Term)]): Unit = + )(implicit interleavedLets: Buffer[LetBinding]): Unit = traceUCS("[desugarMatchBranch]") { body match { // This case handles default branches. For example, // if x is @@ -360,7 +361,7 @@ class Desugarer extends TypeDefs { self: Typer => // B(...) and ... then ... // Case 2: more conjunctions case L(IfThen(patTest, consequent)) => val (patternPart, extraTestOpt) = separatePattern(patTest) - val clauses = destructPattern(scrutinee, partialPattern.addTerm(patternPart).term) + val clauses = destructPattern(scrutinee, partialPattern.addTerm(patternPart).term, true) val conditions = collectedConditions + Conjunction(clauses, Nil).withBindings printlnUCS(s"result conditions: " + Clause.showClauses(conditions.clauses)) extraTestOpt match { @@ -380,7 +381,7 @@ class Desugarer extends TypeDefs { self: Typer => // B(...) then ... case L(IfOpApp(patLhs, Var("and"), consequent)) => val (pattern, optTests) = separatePattern(patLhs) - val patternConditions = destructPattern(scrutinee, pattern) + val patternConditions = destructPattern(scrutinee, pattern, true) val tailTestConditions = optTests.fold(Nil: Ls[Clause])(x => desugarConditions(splitAnd(x))) val conditions = collectedConditions + Conjunction(patternConditions ::: tailTestConditions, Nil).withBindings @@ -391,7 +392,7 @@ class Desugarer extends TypeDefs { self: Typer => // The pattern is completed. There is also a conjunction. // So, we need to separate the pattern from remaining parts. case (pattern, S(extraTests)) => - val patternConditions = destructPattern(scrutinee, pattern) + val patternConditions = destructPattern(scrutinee, pattern, true) val extraConditions = desugarConditions(splitAnd(extraTests)) val conditions = collectedConditions + Conjunction(patternConditions ::: extraConditions, Nil).withBindings @@ -413,7 +414,7 @@ class Desugarer extends TypeDefs { self: Typer => desugarMatchBranch(scrutinee, L(consequent), partialPattern2.addOp(op), collectedConditions) } case (patternPart, S(extraTests)) => - val patternConditions = destructPattern(scrutinee, partialPattern.addTerm(patternPart).term) + val patternConditions = destructPattern(scrutinee, partialPattern.addTerm(patternPart).term, true) val testTerms = splitAnd(extraTests) val middleConditions = desugarConditions(testTerms.init) val conditions = @@ -433,16 +434,18 @@ class Desugarer extends TypeDefs { self: Typer => TODO("please add this rare case to test files") // This case handles interleaved lets. case R(NuFunDef(S(isRec), nameVar, _, L(term))) => - interleavedLets += ((isRec, nameVar, term)) + interleavedLets += (LetBinding(LetBinding.Kind.InterleavedLet, isRec, nameVar, term)) // Other statements are considered to be ill-formed. case R(statement) => throw new DesugaringException({ msg"Illegal interleaved statement ${statement.toString}" }, statement.toLoc) } + }(_ => "[desugarMatchBranch]") + def desugarIfBody (body: IfBody, expr: PartialTerm, acc: Conjunction) - (implicit interleavedLets: Buffer[(Bool, Var, Term)]) - : Unit = { + (implicit interleavedLets: Buffer[LetBinding]) + : Unit = traceUCS("[desugarIfBody]") { body match { case IfOpsApp(exprPart, opsRhss) => val exprStart = expr.addTerm(exprPart) @@ -502,20 +505,21 @@ class Desugarer extends TypeDefs { self: Typer => case L(subBody) => desugarIfBody(subBody, expr, acc) case R(NuFunDef(S(isRec), nameVar, _, L(term))) => printlnUCS(s"Found interleaved binding ${nameVar.name}") - interleavedLets += ((isRec, nameVar, term)) + interleavedLets += LetBinding(LetBinding.Kind.InterleavedLet, isRec, nameVar, term) case R(_) => throw new Error("unexpected statements at desugarIfBody") } } - } + }(_ => "[desugarIfBody]") + // Top-level interleaved let bindings. - val interleavedLets = Buffer.empty[(Bool, Var, Term)] + val interleavedLets = Buffer.empty[LetBinding] desugarIfBody(body, PartialTerm.Empty, Conjunction.empty)(interleavedLets) // Add the fallback case to conjunctions if there is any. fallback.foreach { branches += Conjunction.empty -> _ } Clause.print(printlnUCS, branches) branches.toList - } + }(r => s"[desugarIf] produces ${r.size} branch(es)") import MutCaseOf.{MutCase, IfThenElse, Match, MissingCase, Consequent} @@ -628,7 +632,7 @@ class Desugarer extends TypeDefs { self: Typer => checkExhaustive(branch.consequent, S(t)) } } - }() + }(_ => s"[checkExhaustive] ${t.describe}") def summarizePatterns(t: MutCaseOf)(implicit ctx: Ctx, raise: Raise): ExhaustivenessMap = traceUCS("[summarizePatterns]") { val m = MutMap.empty[Str \/ Int, MutMap[Var, MutCase]] @@ -670,45 +674,81 @@ class Desugarer extends TypeDefs { self: Typer => printlnUCS(s"- $scrutinee => " + patterns.keysIterator.mkString(", ")) } Map.from(m.iterator.map { case (key, patternMap) => key -> Map.from(patternMap) }) - }() + }(_ => "[summarizePatterns]") - protected def constructTerm(m: MutCaseOf)(implicit ctx: Ctx): Term = { - def rec(m: MutCaseOf)(implicit defs: Set[Var]): Term = m match { - case Consequent(term) => term - case Match(scrutinee, branches, wildcard) => - def rec2(xs: Ls[MutCase]): CaseBranches = - xs match { - case MutCase.Constructor(className -> fields, cases) :: next => - // TODO: expand bindings here - val consequent = rec(cases)(defs ++ fields.iterator.map(_._2)) - Case(className, mkLetFromFields(scrutinee, fields.toList, consequent), rec2(next)) - case MutCase.Literal(literal, cases) :: next => - val consequent = rec(cases) - Case(literal, consequent, rec2(next)) - case Nil => - wildcard.fold[CaseBranches](NoCases) { rec(_) |> Wildcard } + /** + * Make a term from a mutable case tree. + * This should be called after exhaustiveness checking. + * + * @param m the mutable case tree + * @param ctx the context + * @return the case expression + */ + protected def constructTerm(m: MutCaseOf)(implicit ctx: Ctx): Term = traceUCS("[constructTerm]") { + /** + * Reconstruct case branches. + */ + def rec2(xs: Ls[MutCase])( + implicit defs: Set[Var], scrutinee: Scrutinee, wildcard: Option[MutCaseOf] + ): CaseBranches = { + xs match { + case MutCase.Constructor(className -> fields, cases) :: next => + printlnUCS(s"• Constructor pattern: $className(${fields.iterator.map(x => s"${x._1} -> ${x._2}").mkString(", ")})") + // TODO: expand bindings here + val consequent = rec(cases)(defs ++ fields.iterator.map(_._2)) + Case(className, mkLetFromFields(scrutinee, fields.toList, consequent), rec2(next)) + case MutCase.Literal(literal, cases) :: next => + printlnUCS(s"• Literal pattern: $literal") + Case(literal, rec(cases), rec2(next)) + case Nil => + wildcard match { + case None => + printlnUCS("• No wildcard branch") + NoCases + case Some(value) => + printlnUCS("• Wildcard branch") + Wildcard(rec(value)) } - val cases = rec2(branches.toList) - val resultTerm = scrutinee.local match { - case N => CaseOf(scrutinee.term, cases) - case S(aliasVar) => Let(false, aliasVar, scrutinee.term, CaseOf(aliasVar, cases)) - } - // Collect let bindings from case branches. - val bindings = branches.iterator.flatMap(_.consequent.getBindings).toList - mkBindings(bindings, resultTerm, defs) - case MissingCase => - import Message.MessageContext - throw new DesugaringException(msg"missing a default branch", N) - case IfThenElse(condition, whenTrue, whenFalse) => - val falseBody = mkBindings(whenFalse.getBindings.toList, rec(whenFalse)(defs ++ whenFalse.getBindings.iterator.map(_._2)), defs) - val trueBody = mkBindings(whenTrue.getBindings.toList, rec(whenTrue)(defs ++ whenTrue.getBindings.iterator.map(_._2)), defs) - val falseBranch = Wildcard(falseBody) - val trueBranch = Case(Var("true"), trueBody, falseBranch) - CaseOf(condition, trueBranch) + } } - val term = rec(m)(Set.from(m.getBindings.iterator.map(_._2))) + /** + * Reconstruct the entire match. + */ + def rec(m: MutCaseOf)(implicit defs: Set[Var]): Term = traceUCS(s"[rec] ${m.describe} -| {${defs.mkString(", ")}}") { + m match { + case Consequent(term) => term + case Match(scrutinee, branches, wildcard) => + val cases = traceUCS("• For each case branch"){ + rec2(branches.toList)(defs, scrutinee, wildcard) + }(_ => "• End for each") + val resultTerm = scrutinee.local match { + case N => CaseOf(scrutinee.term, cases) + case S(aliasVar) => Let(false, aliasVar, scrutinee.term, CaseOf(aliasVar, cases)) + } + // Collect interleaved let bindings from case branches. + val bindings = branches.iterator.flatMap(_.consequent.getBindings).filter { + _.kind === LetBinding.Kind.InterleavedLet + }.toList + printlnUCS("• Collect interleaved let bindings from case branches") + bindings.foreach { case LetBinding(_, _, name, value) => + printlnUCS(s" - $name = $value") + } + mkBindings(bindings, resultTerm, defs) + case MissingCase => + import Message.MessageContext + throw new DesugaringException(msg"missing a default branch", N) + case IfThenElse(condition, whenTrue, whenFalse) => + val falseBody = mkBindings(whenFalse.getBindings.toList, rec(whenFalse)(defs ++ whenFalse.getBindings.iterator.map(_.name)), defs) + val trueBody = mkBindings(whenTrue.getBindings.toList, rec(whenTrue)(defs ++ whenTrue.getBindings.iterator.map(_.name)), defs) + val falseBranch = Wildcard(falseBody) + val trueBranch = Case(Var("true"), trueBody, falseBranch) + CaseOf(condition, trueBranch) + } + }() + val term = rec(m)(Set.from(m.getBindings.iterator.map(_.name))) + // Create immutable map from the mutable map. mkBindings(m.getBindings.toList, term, Set.empty) - } + }(_ => "[constructTerm]") /** * Generate a chain of field selection to the given scrutinee. @@ -726,7 +766,7 @@ class Desugarer extends TypeDefs { self: Typer => // Check if the scrutinee is a `Var` and its name conflicts with // one of the positionals. If so, we create an alias and extract // fields by selecting the alias. - case Var(scrutineeName) if alias == scrutineeName => + case Var(scrutineeName) if alias === scrutineeName => val scrutineeAlias = Var(freshName) Let( false, diff --git a/shared/src/main/scala/mlscript/ucs/LetBinding.scala b/shared/src/main/scala/mlscript/ucs/LetBinding.scala new file mode 100644 index 0000000000..dba1314dd9 --- /dev/null +++ b/shared/src/main/scala/mlscript/ucs/LetBinding.scala @@ -0,0 +1,40 @@ +package mlscript.ucs + +import mlscript._ +import mlscript.utils._ +import mlscript.utils.shorthands._ +import scala.collection.immutable.Set +import scala.collection.mutable.{Set => MutSet, Buffer} + +case class LetBinding(val kind: LetBinding.Kind, val recursive: Bool, val name: Var, val term: Term) + +object LetBinding { + sealed abstract class Kind + + object Kind { + case object ScrutineeAlias extends Kind + case object FieldExtraction extends Kind + case object InterleavedLet extends Kind + } +} + +trait WithBindings { this: MutCaseOf => + private val bindingsSet: MutSet[LetBinding] = MutSet.empty + private val bindings: Buffer[LetBinding] = Buffer.empty + + def addBindings(newBindings: IterableOnce[LetBinding]): Unit = { + newBindings.iterator.foreach { + case binding if bindingsSet.contains(binding) => () + case binding => + bindingsSet += binding + bindings += binding + } + } + + def getBindings: Iterable[LetBinding] = bindings + + def withBindings(newBindings: IterableOnce[LetBinding]): MutCaseOf = { + addBindings(newBindings) + this + } +} diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index 9281d07942..f1373a9e66 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -9,27 +9,6 @@ import scala.collection.mutable.{Map => MutMap, Set => MutSet, Buffer} import helpers._ import mlscript.ucs.MutCaseOf.Consequent -trait WithBindings { this: MutCaseOf => - private val bindingsSet: MutSet[(Bool, Var, Term)] = MutSet.empty - private val bindings: Buffer[(Bool, Var, Term)] = Buffer.empty - - def addBindings(newBindings: IterableOnce[(Bool, Var, Term)]): Unit = { - newBindings.iterator.foreach { - case binding if bindingsSet.contains(binding) => () - case binding => - bindingsSet += binding - bindings += binding - } - } - - def getBindings: Iterable[(Bool, Var, Term)] = bindings - - def withBindings(newBindings: IterableOnce[(Bool, Var, Term)]): MutCaseOf = { - addBindings(newBindings) - this - } -} - sealed abstract class MutCaseOf extends WithBindings { def kind: Str = { import MutCaseOf._ @@ -47,7 +26,7 @@ sealed abstract class MutCaseOf extends WithBindings { (branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit): Unit def mergeDefault - (bindings: Ls[(Bool, Var, Term)], default: Term) + (bindings: Ls[LetBinding], default: Term) (implicit raise: Diagnostic => Unit): Int // TODO: Make it immutable. @@ -67,7 +46,7 @@ object MutCaseOf { val baseIndent = " " * indent val bindingNames = t.getBindings match { case Nil => "" - case bindings => bindings.iterator.map(_._2.name).mkString("[", ", ", "] ") + case bindings => bindings.iterator.map(_.name.name).mkString("[", ", ", "] ") } t match { case IfThenElse(condition, whenTrue, whenFalse) => @@ -213,7 +192,7 @@ object MutCaseOf { } } - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = { + def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = { whenTrue.mergeDefault(bindings, default) + { whenFalse match { case Consequent(term) => 0 @@ -305,7 +284,7 @@ object MutCaseOf { } } - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = { + def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = { branches.iterator.map { case MutCase.Constructor(_, consequent) => consequent.mergeDefault(bindings, default) case MutCase.Literal(_, consequent) => consequent.mergeDefault(bindings, default) @@ -325,7 +304,7 @@ object MutCaseOf { def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = raise(WarningReport(Message.fromStr("duplicated branch") -> N :: Nil)) - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 + def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 } final case object MissingCase extends MutCaseOf { def describe: Str = "MissingCase" @@ -333,7 +312,7 @@ object MutCaseOf { def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = lastWords("`MissingCase` is a placeholder and cannot be merged") - def mergeDefault(bindings: Ls[(Bool, Var, Term)], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 + def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 } private def buildFirst(conjunction: Conjunction, term: Term): MutCaseOf = { @@ -359,8 +338,12 @@ object MutCaseOf { .withLocations(head.locations) ) Match(scrutinee, branches, N) - case Binding(name, term) => - rec(realTail).withBindings((false, name, term) :: Nil) + case Binding(name, term, isField) => + val kind = if (isField) + LetBinding.Kind.FieldExtraction + else + LetBinding.Kind.ScrutineeAlias + rec(realTail).withBindings(LetBinding(kind, false, name, term) :: Nil) }).withBindings(head.bindings) case Conjunction(Nil, trailingBindings) => Consequent(term).withBindings(trailingBindings) diff --git a/shared/src/main/scala/mlscript/ucs/Scrutinee.scala b/shared/src/main/scala/mlscript/ucs/Scrutinee.scala index 13a5d5546f..a0ce56d3e0 100644 --- a/shared/src/main/scala/mlscript/ucs/Scrutinee.scala +++ b/shared/src/main/scala/mlscript/ucs/Scrutinee.scala @@ -18,7 +18,9 @@ final case class Scrutinee(var local: Opt[Var], term: Term)(val matchRootLoc: Op * * @return `Some` if the scrutinee is localized, otherwise, `None`. */ - def asBinding: Opt[(Bool, Var, Term)] = local.map((false, _, term)) + def asBinding: Opt[LetBinding] = local.map { + LetBinding(LetBinding.Kind.ScrutineeAlias, false, _, term) + } override def toString: String = (local match { diff --git a/shared/src/main/scala/mlscript/ucs/helpers.scala b/shared/src/main/scala/mlscript/ucs/helpers.scala index 8248a30a4c..5aaa37bbbc 100644 --- a/shared/src/main/scala/mlscript/ucs/helpers.scala +++ b/shared/src/main/scala/mlscript/ucs/helpers.scala @@ -84,15 +84,15 @@ object helpers { * @param bindings a list of bindings, * @param body the final body */ - def mkBindings(bindings: Ls[(Bool, Var, Term)], body: Term, defs: Set[Var]): Term = { - def rec(bindings: Ls[(Bool, Var, Term)], defs: Set[Var]): Term = + def mkBindings(bindings: Ls[LetBinding], body: Term, defs: Set[Var]): Term = { + def rec(bindings: Ls[LetBinding], defs: Set[Var]): Term = bindings match { case Nil => body - case (head @ (isRec, nameVar, value)) :: tail => - if (defs.contains(head._2)) { + case LetBinding(_, isRec, nameVar, value) :: tail => + if (defs.contains(nameVar)) { rec(tail, defs) } else { - Let(isRec, nameVar, value, rec(tail, defs + head._2)) + Let(isRec, nameVar, value, rec(tail, defs + nameVar)) } } rec(bindings, defs) diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index 6423965afd..a2e80ac2b0 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -107,4 +107,17 @@ fun foo(x) = if x is foo() then 0 //│ Code generation encountered an error: //│ if expression was not desugared - +module Nil +class Cons[out A](head: A, tail: Cons[A] | Nil) +//│ module Nil() +//│ class Cons[A](head: A, tail: Cons[A] | Nil) + +:w +fun join(xs) = + if xs is + Nil then "" + Cons(x, Nil) then toString(x) + Cons(x, xs') then concat(toString(x))(concat(", ")(join(xs'))) +//│ ╔══[WARNING] duplicated branch +//│ ╙── +//│ fun join: (Cons[anything] | Nil) -> string diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 4285f53f88..1cde1664e2 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -28,12 +28,9 @@ fun filtermap(f, xs) = if xs is false then filtermap(f, ys) true then Cons(y, filtermap(f, ys)) [true, z] then Cons(y, filtermap(f, ys)) -//│ ╔══[ERROR] identifier not found: ys -//│ ║ l.27: Cons(y, ys) and f(ys) is -//│ ╙── ^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── -//│ fun filtermap: ((Cons[nothing] | error | Nil) -> anything & (Cons[nothing] | Nil) -> (error | false | true), Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) +//│ fun filtermap: ((Cons[nothing] | Nil) -> (error | false | true), Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 @@ -52,6 +49,35 @@ fun filtermap(f, xs) = if xs is True then filtermap(f, ys) False then Cons(y, filtermap(f, ys)) Pair(True, z) then Cons(z, filtermap(f, ys)) -//│ fun filtermap: forall 'A 'head. ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) +//│ fun filtermap: forall 'head 'A. ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) +fun mkString(xs) = + if xs is + Nil then "" + Cons(x, xs') and xs' is + Nil then toString(x) + else concat(toString(x))(concat(", ")(mkString(xs'))) +//│ fun mkString: (Cons[anything] | Nil) -> string +let list = Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Cons(6, Cons(7, Nil))))))) +mkString of list +//│ let list: Cons[1 | 2 | 3 | 4 | 5 | 6 | 7] +//│ string +//│ list +//│ = Cons {} +//│ res +//│ = '1, 2, 3, 4, 5, 6, 7' + +mkString of filtermap(x => if x % 2 == 0 then True else False, list) +mkString of filtermap(x => if x % 2 == 0 then False else True, list) +mkString of filtermap(x => (if + x % 2 == 0 then False + x % 3 == 0 then Pair(True, x / 3) + else True), list) +//│ string +//│ res +//│ = '1, 3, 5, 7' +//│ res +//│ = '2, 4, 6' +//│ res +//│ = '2, 1, 4, 6' diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index 757ef11bce..93187d357c 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -272,13 +272,21 @@ fun mapPartition(f, xs) = Cons(x, xs) and mapPartition(f, xs) is tmp0 and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: forall 'a. Cons & {head: 'leftValue, tail: forall 'a. 'fst | 'a} | 'fst | 'a, snd: forall 'b. Cons & {head: 'rightValue, tail: forall 'b. 'fst | 'b} | 'fst | 'b}) -//│ where -//│ 'b :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'b. Nil | 'b} -//│ 'a :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'a. Nil | 'a} -//│ 'fst :> Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} | Nil -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil -//│ = [Function: mapPartition1] +//│ ╔══[ERROR] identifier not found: l +//│ ║ l.273: Left(v) then Pair(Cons(v, l), r) +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: r +//│ ║ l.273: Left(v) then Pair(Cons(v, l), r) +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: l +//│ ║ l.274: Right(v) then Pair(l, Cons(v, r)) +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: r +//│ ║ l.274: Right(v) then Pair(l, Cons(v, r)) +//│ ╙── ^ +//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), Cons & {head: 'head} | Nil,) -> (Pair & {fst: Cons & {head: 'leftValue, tail: error} | Nil | error, snd: Cons & {head: 'rightValue, tail: error} | Nil | error}) +//│ Code generation encountered an error: +//│ unresolved symbol l // FIXME `b` should be bound here! // The example is actually wrong. `b` belongs to the consequent of `Left(b)`. @@ -291,7 +299,7 @@ fun mn(a) = Right(b) then "right-defined" None then "undefined" //│ ╔══[ERROR] identifier not found: b -//│ ║ l.290: let y = b + 1 +//│ ║ l.298: let y = b + 1 //│ ╙── ^ //│ mn: (None | Some & {value: Left | Right}) -> ("left-defined" | "right-defined" | "undefined") //│ Code generation encountered an error: From c8707c520eb02b53f45c7f15d46bafb8ef812b17 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 15 Mar 2023 16:54:48 +0800 Subject: [PATCH 200/498] Improve warnings of duplicated branches --- .../main/scala/mlscript/ucs/MutCaseOf.scala | 18 ++++++- shared/src/test/diff/nu/BadUCS.mls | 9 +++- shared/src/test/diff/ucs/Humiliation.mls | 29 ++++++----- shared/src/test/diff/ucs/InterleavedLet.mls | 23 ++++---- shared/src/test/diff/ucs/TrivialIf.mls | 10 ++-- shared/src/test/diff/ucs/WeirdIf.mls | 52 +++++++++++++------ 6 files changed, 98 insertions(+), 43 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index f1373a9e66..fb2f1b1eb4 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -8,6 +8,7 @@ import scala.collection.mutable.{Map => MutMap, Set => MutSet, Buffer} import helpers._ import mlscript.ucs.MutCaseOf.Consequent +import scala.collection.immutable sealed abstract class MutCaseOf extends WithBindings { def kind: Str = { @@ -302,7 +303,22 @@ object MutCaseOf { def describe: Str = s"Consequent($term)" def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = - raise(WarningReport(Message.fromStr("duplicated branch") -> N :: Nil)) + raise { + import scala.collection.mutable.ListBuffer + val buffer = ListBuffer.empty[Message -> Opt[Loc]] + buffer += Message.fromStr("Found duplicated branch") -> N + buffer += Message.fromStr("This decision path tries to fit") -> { + val (Conjunction(clauses, _) -> consequent) = branch + consequent.toLoc + // TODO: Make a complete location. + // clauses match { + // case head :: _ => head. + // case Nil => consequent.toLoc + // } + } + buffer += Message.fromStr("But there is already a consequent term") -> term.toLoc + WarningReport(buffer.toList) + } def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 } diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index a2e80ac2b0..cfc770d84b 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -118,6 +118,11 @@ fun join(xs) = Nil then "" Cons(x, Nil) then toString(x) Cons(x, xs') then concat(toString(x))(concat(", ")(join(xs'))) -//│ ╔══[WARNING] duplicated branch -//│ ╙── +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.120: Cons(x, xs') then concat(toString(x))(concat(", ")(join(xs'))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── But there is already a consequent term +//│ ║ l.119: Cons(x, Nil) then toString(x) +//│ ╙── ^^^^^^^^^^^ //│ fun join: (Cons[anything] | Nil) -> string diff --git a/shared/src/test/diff/ucs/Humiliation.mls b/shared/src/test/diff/ucs/Humiliation.mls index 7629b41a94..39ab377994 100644 --- a/shared/src/test/diff/ucs/Humiliation.mls +++ b/shared/src/test/diff/ucs/Humiliation.mls @@ -19,8 +19,13 @@ fun test(x) = if x is 1 then 0 else 1 fun testF(x) = if x is Foo(a) then a Foo(a) then a -//│ ╔══[WARNING] duplicated branch -//│ ╙── +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.21: Foo(a) then a +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.20: Foo(a) then a +//│ ╙── ^ //│ testF: (Foo & {x: 'x}) -> 'x //│ = [Function: testF] @@ -66,14 +71,14 @@ fun foo(x) = if x is Pair(Z(), Z()) then "zeros" Pair(O(), O()) then "ones" //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.65: fun foo(x) = if x is +//│ ║ l.70: fun foo(x) = if x is //│ ║ ^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.66: Pair(Z(), Z()) then "zeros" +//│ ║ l.71: Pair(Z(), Z()) then "zeros" //│ ║ ^^^ //│ ╟── [Missing Case 1/1] `O` //│ ╟── It first appears here. -//│ ║ l.67: Pair(O(), O()) then "ones" +//│ ║ l.72: Pair(O(), O()) then "ones" //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: @@ -86,14 +91,14 @@ fun foo(x) = if x is (Z(), Z()) then "zeros" (O(), O()) then "ones" //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.85: fun foo(x) = if x is +//│ ║ l.90: fun foo(x) = if x is //│ ║ ^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.86: (Z(), Z()) then "zeros" +//│ ║ l.91: (Z(), Z()) then "zeros" //│ ║ ^^^ //│ ╟── [Missing Case 1/1] `O` //│ ╟── It first appears here. -//│ ║ l.87: (O(), O()) then "ones" +//│ ║ l.92: (O(), O()) then "ones" //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: @@ -159,14 +164,14 @@ fun foo(x) = if x is Pair(O(), O()) then "ones" Pair(y, O()) then x //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.157: fun foo(x) = if x is +//│ ║ l.162: fun foo(x) = if x is //│ ║ ^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.158: Pair(Z(), Z()) then "zeros" +//│ ║ l.163: Pair(Z(), Z()) then "zeros" //│ ║ ^^^ //│ ╟── [Missing Case 1/1] `Z` //│ ╟── It first appears here. -//│ ║ l.158: Pair(Z(), Z()) then "zeros" +//│ ║ l.163: Pair(Z(), Z()) then "zeros" //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: @@ -180,7 +185,7 @@ fun foo(x, y) = if x is Z() and y is O() then 0 else 1 fun foo(x, y) = if x is Z() and y is O() then 0 else 1 //│ ╔══[PARSE ERROR] Unexpected 'else' keyword here -//│ ║ l.181: Z() and y is O() then 0 else 1 +//│ ║ l.186: Z() and y is O() then 0 else 1 //│ ╙── ^^^^ //│ foo: (Z, O,) -> 0 //│ = [Function: foo8] diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index 93187d357c..fa7e1def8c 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -46,8 +46,13 @@ fun p(x, y) = x is Some and y is None then 0 y is Some and x is Some then 1 x is Some and y is Some then 0 -//│ ╔══[WARNING] duplicated branch -//│ ╙── +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.48: x is Some and y is Some then 0 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.47: y is Some and x is Some then 1 +//│ ╙── ^ //│ p: (Some, None | Some,) -> (0 | 1) //│ = [Function: p] @@ -88,9 +93,9 @@ fun q(a) = let y = a + 1 then y //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.88: let y = a + 1 +//│ ║ l.93: let y = a + 1 //│ ║ ^^^^^ -//│ ║ l.89: then y +//│ ║ l.94: then y //│ ╙── ^^^^^^^^^^ //│ q: (Left & {leftValue: 'leftValue}) -> 'leftValue //│ = [Function: q1] @@ -273,16 +278,16 @@ fun mapPartition(f, xs) = Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) //│ ╔══[ERROR] identifier not found: l -//│ ║ l.273: Left(v) then Pair(Cons(v, l), r) +//│ ║ l.278: Left(v) then Pair(Cons(v, l), r) //│ ╙── ^ //│ ╔══[ERROR] identifier not found: r -//│ ║ l.273: Left(v) then Pair(Cons(v, l), r) +//│ ║ l.278: Left(v) then Pair(Cons(v, l), r) //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.274: Right(v) then Pair(l, Cons(v, r)) +//│ ║ l.279: Right(v) then Pair(l, Cons(v, r)) //│ ╙── ^ //│ ╔══[ERROR] identifier not found: r -//│ ║ l.274: Right(v) then Pair(l, Cons(v, r)) +//│ ║ l.279: Right(v) then Pair(l, Cons(v, r)) //│ ╙── ^ //│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), Cons & {head: 'head} | Nil,) -> (Pair & {fst: Cons & {head: 'leftValue, tail: error} | Nil | error, snd: Cons & {head: 'rightValue, tail: error} | Nil | error}) //│ Code generation encountered an error: @@ -299,7 +304,7 @@ fun mn(a) = Right(b) then "right-defined" None then "undefined" //│ ╔══[ERROR] identifier not found: b -//│ ║ l.298: let y = b + 1 +//│ ║ l.303: let y = b + 1 //│ ╙── ^ //│ mn: (None | Some & {value: Left | Right}) -> ("left-defined" | "right-defined" | "undefined") //│ Code generation encountered an error: diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index e8d8fa8455..fffc4f8b2d 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -59,14 +59,18 @@ fun f(x, y) = -// FIXME if 42 is n then n + 1 //│ res: int // FIXME if 42 is n then n + 1 else 0 -//│ ╔══[WARNING] duplicated branch -//│ ╙── +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.66: if 42 is n then n + 1 else 0 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.66: if 42 is n then n + 1 else 0 +//│ ╙── ^^^^^ //│ res: int diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index 4fe9061ee8..6a8e996421 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -6,24 +6,44 @@ if _ then 0 else 0 else 1 -//│ ╔══[WARNING] duplicated branch -//│ ╙── -//│ ╔══[WARNING] duplicated branch -//│ ╙── +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.7: else 0 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.6: _ then 0 +//│ ╙── ^ +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.8: else 1 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.6: _ then 0 +//│ ╙── ^ //│ res: 0 //│ = 0 :w if else 0 else 1 -//│ ╔══[WARNING] duplicated branch -//│ ╙── +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.27: if else 0 else 1 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.27: if else 0 else 1 +//│ ╙── ^ //│ res: 0 //│ = 0 :w fun f(x) = if x is else 0 else 1 -//│ ╔══[WARNING] duplicated branch -//│ ╙── +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.39: fun f(x) = if x is else 0 else 1 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.39: fun f(x) = if x is else 0 else 1 +//│ ╙── ^ //│ f: anything -> 0 //│ = [Function: f] @@ -36,7 +56,7 @@ fun f(x) = if x is else 0 if true then 0 //│ ╔══[ERROR] The case when this is false is not handled: true -//│ ║ l.36: if true +//│ ║ l.56: if true //│ ╙── ^^^^ //│ res: error //│ Code generation encountered an error: @@ -50,23 +70,23 @@ fun f(x) = if x == else "bruh" //│ ╔══[PARSE ERROR] Unexpected indented block in expression position -//│ ║ l.51: else "bruh" +//│ ║ l.71: else "bruh" //│ ╙── ^^^^ //│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here -//│ ║ l.51: else "bruh" +//│ ║ l.71: else "bruh" //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead -//│ ║ l.50: if x == +//│ ║ l.70: if x == //│ ║ ^^^^ -//│ ║ l.51: else "bruh" +//│ ║ l.71: else "bruh" //│ ║ ^^^^ //│ ╟── Note: 'if' expression started here: -//│ ║ l.50: if x == +//│ ║ l.70: if x == //│ ╙── ^^ //│ ╔══[ERROR] The case when this is false is not handled: == (x,) (undefined,) -//│ ║ l.50: if x == +//│ ║ l.70: if x == //│ ║ ^^^^ -//│ ║ l.51: else "bruh" +//│ ║ l.71: else "bruh" //│ ╙── ^^^^ //│ f: anything -> error //│ Code generation encountered an error: From 73dee4c5a2b734ffe6f078fb9660ea896556ef05 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 15 Mar 2023 17:48:09 +0800 Subject: [PATCH 201/498] Improve the debug display of `MutCaseOf` --- .../main/scala/mlscript/ucs/MutCaseOf.scala | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index fb2f1b1eb4..f760d75db4 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -43,44 +43,50 @@ object MutCaseOf { def show(t: MutCaseOf): Ls[Str] = { val lines = Buffer.empty[String] - def rec(t: MutCaseOf, indent: Int, leading: String): Unit = { + def rec(t: MutCaseOf, indent: Int): Unit = { val baseIndent = " " * indent - val bindingNames = t.getBindings match { - case Nil => "" - case bindings => bindings.iterator.map(_.name.name).mkString("[", ", ", "] ") - } + lazy val bindingLines = t.getBindings.iterator.map { + case LetBinding(_, recursive, name, term) => + // Show bindings + s"[binding $name = $term]" + }.toList t match { case IfThenElse(condition, whenTrue, whenFalse) => // Output the `whenTrue` with the prefix "if". - lines += baseIndent + leading + bindingNames + s"if «$condition»" - rec(whenTrue, indent + 1, "") + bindingLines.foreach { lines += baseIndent + _ } + lines += baseIndent + s"if «$condition»" + rec(whenTrue, indent + 1) // Output the `whenFalse` case with the prefix "else". - lines += s"$baseIndent${leading}else" - rec(whenFalse, indent + 1, "") + lines += s"${baseIndent}else" + rec(whenFalse, indent + 1) case Match(scrutinee, branches, default) => - lines += baseIndent + leading + bindingNames + showScrutinee(scrutinee) + " match" + bindingLines.foreach { lines += baseIndent + _ } + lines += baseIndent + showScrutinee(scrutinee) + " match" branches.foreach { case MutCase.Literal(literal, consequent) => lines += s"$baseIndent case $literal =>" - rec(consequent, indent + 1, "") + rec(consequent, indent + 1) case MutCase.Constructor(Var(className) -> fields, consequent) => lines += s"$baseIndent case $className =>" fields.foreach { case (field, Var(alias)) => - lines += s"$baseIndent let $alias = .$field" + // Show pattern bindings. + lines += s"$baseIndent [pattern $alias = ${scrutinee.reference}.$field]" } - rec(consequent, indent + 2, "") + rec(consequent, indent + 2) } default.foreach { consequent => lines += s"$baseIndent default" - rec(consequent, indent + 2, "") + rec(consequent, indent + 2) } case Consequent(term) => - lines += s"$baseIndent$leading$bindingNames«$term»" + bindingLines.foreach { lines += baseIndent + _ } + lines += s"$baseIndent«$term»" case MissingCase => - lines += s"$baseIndent$leading$bindingNames" + bindingLines.foreach { lines += baseIndent + _ } + lines += s"$baseIndent" } } - rec(t, 0, "") + rec(t, 0) lines.toList } From e0f426a3321e839a4464b3b1b453880e0c6981e7 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 16 Mar 2023 14:47:05 +0800 Subject: [PATCH 202/498] Fix duplicated interleaved bindings and missing alias bindings I really need to go through the binding logic next. --- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../src/main/scala/mlscript/ucs/Clause.scala | 24 ++----- .../main/scala/mlscript/ucs/Desugarer.scala | 71 +++++++++++++++---- .../main/scala/mlscript/ucs/LetBinding.scala | 12 +++- .../main/scala/mlscript/ucs/MutCaseOf.scala | 55 +++++++------- shared/src/test/diff/ucs/InterleavedLet.mls | 71 +++++++------------ 6 files changed, 127 insertions(+), 110 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 90b56440a8..5204da7c1a 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1047,9 +1047,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case iff @ If(body, fallback) => import mlscript.ucs._ try { - val caseTree = MutCaseOf.build(desugarIf(body, fallback)) - println("The mutable CaseOf tree") - MutCaseOf.show(caseTree).foreach(println(_)) + val caseTree = buildCaseTree(desugarIf(body, fallback)) checkExhaustive(caseTree, N)(summarizePatterns(caseTree), ctx, raise) val desugared = constructTerm(caseTree) println(s"Desugared term: ${desugared.print(false)}") diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index 9cb87af63f..402a78781e 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -23,7 +23,10 @@ abstract class Clause { val locations: Ls[Loc] protected final def bindingsToString: String = - (if (bindings.isEmpty) "" else " with " + Clause.showBindings(bindings)) + if (bindings.isEmpty) "" else " with " + (bindings match { + case Nil => "" + case bindings => bindings.map(_.name.name).mkString("(", ", ", ")") + }) } object Clause { @@ -64,23 +67,4 @@ object Clause { ) extends Clause { override def toString(): String = s"«$name = $term»" + bindingsToString } - - def showBindings(bindings: Ls[LetBinding]): Str = - bindings match { - case Nil => "" - case bindings => bindings.map(_.name.name).mkString("(", ", ", ")") - } - - def showClauses(clauses: Iterable[Clause]): Str = clauses.mkString("", " and ", "") - - def print(println: (=> Any) => Unit, conjunctions: Iterable[Conjunction -> Term]): Unit = { - println("Flattened conjunctions") - conjunctions.foreach { case Conjunction(clauses, trailingBindings) -> term => - println("+ " + showClauses(clauses) + { - (if (trailingBindings.isEmpty) "" else " ") + - showBindings(trailingBindings) + - s" => $term" - }) - } - } } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 1fa839909e..695ebf2677 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -273,7 +273,7 @@ class Desugarer extends TypeDefs { self: Typer => // What else? case _ => throw new DesugaringException(msg"illegal pattern", pattern.toLoc) } - }("[Desugarer.destructPattern] result: " + Clause.showClauses(_)) + }("[Desugarer.destructPattern] Result: " + _.mkString(", ")) /** * Collect `Loc`s from a synthetic term. @@ -363,7 +363,7 @@ class Desugarer extends TypeDefs { self: Typer => val (patternPart, extraTestOpt) = separatePattern(patTest) val clauses = destructPattern(scrutinee, partialPattern.addTerm(patternPart).term, true) val conditions = collectedConditions + Conjunction(clauses, Nil).withBindings - printlnUCS(s"result conditions: " + Clause.showClauses(conditions.clauses)) + printlnUCS(s"Result: " + conditions.clauses.mkString(", ")) extraTestOpt match { // Case 1. Just a pattern. Easy! case N => @@ -517,9 +517,19 @@ class Desugarer extends TypeDefs { self: Typer => desugarIfBody(body, PartialTerm.Empty, Conjunction.empty)(interleavedLets) // Add the fallback case to conjunctions if there is any. fallback.foreach { branches += Conjunction.empty -> _ } - Clause.print(printlnUCS, branches) + printlnUCS("Decision paths:") + branches.foreach { case Conjunction(clauses, trailingBindings) -> term => + printlnUCS("+ " + clauses.mkString("", " and ", "") + { + (if (trailingBindings.isEmpty) "" else " ") + + (trailingBindings match { + case Nil => "" + case bindings => bindings.map(_.name.name).mkString("(", ", ", ")") + }) + + s" => $term" + }) + } branches.toList - }(r => s"[desugarIf] produces ${r.size} branch(es)") + }(r => s"[desugarIf] produces ${r.size} ${"path".pluralize(r.size)}") import MutCaseOf.{MutCase, IfThenElse, Match, MissingCase, Consequent} @@ -718,6 +728,28 @@ class Desugarer extends TypeDefs { self: Typer => m match { case Consequent(term) => term case Match(scrutinee, branches, wildcard) => + printlnUCS("• Owned let bindings") + val ownedBindings = m.getBindings.iterator.filterNot { + _.kind === LetBinding.Kind.InterleavedLet + }.toList + if (ownedBindings.isEmpty) + printlnUCS(" * ") + else + ownedBindings.foreach { case LetBinding(kind, _, name, value) => + printlnUCS(s" * ($kind) $name = $value") + } + // Collect interleaved let bindings from case branches. + // Because they should be declared before + val interleavedBindings = branches.iterator.map(_.consequent).concat(wildcard).flatMap(_.getBindings).filter { + _.kind === LetBinding.Kind.InterleavedLet + }.toList + printlnUCS("• Collect interleaved let bindings from case branches") + if (interleavedBindings.isEmpty) + printlnUCS(" * ") + else + interleavedBindings.foreach { case LetBinding(_, _, name, value) => + printlnUCS(s" * $name = $value") + } val cases = traceUCS("• For each case branch"){ rec2(branches.toList)(defs, scrutinee, wildcard) }(_ => "• End for each") @@ -725,15 +757,7 @@ class Desugarer extends TypeDefs { self: Typer => case N => CaseOf(scrutinee.term, cases) case S(aliasVar) => Let(false, aliasVar, scrutinee.term, CaseOf(aliasVar, cases)) } - // Collect interleaved let bindings from case branches. - val bindings = branches.iterator.flatMap(_.consequent.getBindings).filter { - _.kind === LetBinding.Kind.InterleavedLet - }.toList - printlnUCS("• Collect interleaved let bindings from case branches") - bindings.foreach { case LetBinding(_, _, name, value) => - printlnUCS(s" - $name = $value") - } - mkBindings(bindings, resultTerm, defs) + mkBindings(ownedBindings, mkBindings(interleavedBindings, resultTerm, defs), defs) case MissingCase => import Message.MessageContext throw new DesugaringException(msg"missing a default branch", N) @@ -790,4 +814,25 @@ class Desugarer extends TypeDefs { self: Typer => } rec(scrutinee.reference, fields) } + + protected def buildCaseTree + (paths: Ls[Conjunction -> Term]) + (implicit raise: Diagnostic => Unit) + : MutCaseOf = traceUCS("[buildCaseTree]") { + paths match { + case Nil => MissingCase + case (conditions -> term) :: remaining => + val root = MutCaseOf.buildFirst(conditions, term) + traceUCS("*** Initial tree ***") { + MutCaseOf.show(root).foreach(printlnUCS(_)) + }() + remaining.foreach { path => + root.merge(path) + traceUCS("*** Updated tree ***") { + MutCaseOf.show(root).foreach(printlnUCS(_)) + }() + } + root + } + }(_ => "[buildCaseTree]") } diff --git a/shared/src/main/scala/mlscript/ucs/LetBinding.scala b/shared/src/main/scala/mlscript/ucs/LetBinding.scala index dba1314dd9..167877245d 100644 --- a/shared/src/main/scala/mlscript/ucs/LetBinding.scala +++ b/shared/src/main/scala/mlscript/ucs/LetBinding.scala @@ -12,9 +12,15 @@ object LetBinding { sealed abstract class Kind object Kind { - case object ScrutineeAlias extends Kind - case object FieldExtraction extends Kind - case object InterleavedLet extends Kind + case object ScrutineeAlias extends Kind { + override def toString(): String = "scrutinee alias" + } + case object FieldExtraction extends Kind { + override def toString(): String = "pattern destruction" + } + case object InterleavedLet extends Kind { + override def toString(): String = "interleaved let" + } } } diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index f760d75db4..a4653b6b73 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -223,7 +223,16 @@ object MutCaseOf { })" } - def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = { + def merge(originalBranch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = { + // Remove let bindings that already has been declared. + val branch = originalBranch._1.copy(clauses = originalBranch._1.clauses.filter { + case Binding(name, value, false) if (getBindings.exists { + case LetBinding(LetBinding.Kind.ScrutineeAlias, _, n, v) => + n === name && v === value + case _ => false + }) => false + case _ => true + }) -> originalBranch._2 branch._1.separate(scrutinee) match { // No conditions against the same scrutinee. case N => @@ -337,53 +346,51 @@ object MutCaseOf { def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 } - private def buildFirst(conjunction: Conjunction, term: Term): MutCaseOf = { + def buildFirst(conjunction: Conjunction, term: Term): MutCaseOf = { def rec(conjunction: Conjunction): MutCaseOf = conjunction match { case Conjunction(head :: tail, trailingBindings) => - val realTail = Conjunction(tail, trailingBindings) + lazy val (beforeHeadBindings, afterHeadBindings) = head.bindings.partition { + case LetBinding(LetBinding.Kind.InterleavedLet, _, _, _) => false + case LetBinding(_, _, _, _) => true + } + val consequentTree = rec(Conjunction(tail, trailingBindings)) (head match { case MatchLiteral(scrutinee, literal) => val branches = Buffer( - MutCase.Literal(literal, rec(realTail)).withLocation(literal.toLoc) + MutCase.Literal(literal, consequentTree.withBindings(afterHeadBindings)).withLocation(literal.toLoc) ) Match(scrutinee, branches, N) - case BooleanTest(test) => IfThenElse(test, rec(realTail), MissingCase) + .withBindings(beforeHeadBindings) + case BooleanTest(test) => + IfThenElse(test, consequentTree, MissingCase) + .withBindings(beforeHeadBindings) + .withBindings(afterHeadBindings) case MatchClass(scrutinee, className, fields) => val branches = Buffer( - MutCase.Constructor(className -> Buffer.from(fields), rec(realTail)) + MutCase.Constructor(className -> Buffer.from(fields), consequentTree.withBindings(afterHeadBindings)) .withLocations(head.locations) ) - Match(scrutinee, branches, N) + Match(scrutinee, branches, N).withBindings(beforeHeadBindings) case MatchTuple(scrutinee, arity, fields) => val branches = Buffer( - MutCase.Constructor(Var(s"Tuple#$arity") -> Buffer.from(fields), rec(realTail)) + MutCase.Constructor(Var(s"Tuple#$arity") -> Buffer.from(fields), consequentTree.withBindings(afterHeadBindings)) .withLocations(head.locations) ) - Match(scrutinee, branches, N) + Match(scrutinee, branches, N).withBindings(beforeHeadBindings) case Binding(name, term, isField) => val kind = if (isField) LetBinding.Kind.FieldExtraction else LetBinding.Kind.ScrutineeAlias - rec(realTail).withBindings(LetBinding(kind, false, name, term) :: Nil) - }).withBindings(head.bindings) + consequentTree + .withBindings(beforeHeadBindings) + .withBindings(LetBinding(kind, false, name, term) :: Nil) + .withBindings(afterHeadBindings) + }) case Conjunction(Nil, trailingBindings) => Consequent(term).withBindings(trailingBindings) } rec(conjunction) } - - def build - (cnf: Ls[Conjunction -> Term]) - (implicit raise: Diagnostic => Unit) - : MutCaseOf = { - cnf match { - case Nil => MissingCase - case (conditions -> term) :: next => - val root = MutCaseOf.buildFirst(conditions, term) - next.foreach(root.merge(_)) - root - } - } } diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index fa7e1def8c..070b1cd253 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -244,7 +244,6 @@ showList(zeroToThree) //│ res: string //│ = '0, 1, 2, 3' -// FIXME: This needs lifting functions. fun mapPartition(f, xs) = if xs is Nil then Pair(Nil(), Nil()) @@ -261,60 +260,38 @@ fun mapPartition(f, xs) = //│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil //│ = [Function: mapPartition] -// FIXME: Something wrong with code generation. mapPartition(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) //│ res: Pair & {fst: 'fst, snd: 'snd} //│ where //│ 'snd :> Cons & {head: 0 | 1 | 2 | 3, tail: 'snd} | Nil //│ 'fst :> Nil | Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} -//│ Runtime error: -//│ RangeError: Maximum call stack size exceeded +//│ = Pair { +//│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, +//│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } +//│ } -// TODO this should be the desugaring of the above: -fun mapPartition(f, xs) = +// This should be the desugaring of the above: +fun mapPartition2(f, xs) = if xs is Nil then Pair(Nil(), Nil()) - Cons(x, xs) and mapPartition(f, xs) is tmp0 and res.fst is l and res.snd is r and f(x) is + Cons(x, xs) and mapPartition(f, xs) is res and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ ╔══[ERROR] identifier not found: l -//│ ║ l.278: Left(v) then Pair(Cons(v, l), r) -//│ ╙── ^ -//│ ╔══[ERROR] identifier not found: r -//│ ║ l.278: Left(v) then Pair(Cons(v, l), r) -//│ ╙── ^ -//│ ╔══[ERROR] identifier not found: l -//│ ║ l.279: Right(v) then Pair(l, Cons(v, r)) -//│ ╙── ^ -//│ ╔══[ERROR] identifier not found: r -//│ ║ l.279: Right(v) then Pair(l, Cons(v, r)) -//│ ╙── ^ -//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), Cons & {head: 'head} | Nil,) -> (Pair & {fst: Cons & {head: 'leftValue, tail: error} | Nil | error, snd: Cons & {head: 'rightValue, tail: error} | Nil | error}) -//│ Code generation encountered an error: -//│ unresolved symbol l - -// FIXME `b` should be bound here! -// The example is actually wrong. `b` belongs to the consequent of `Left(b)`. -// `let y = ...` has no access to `b` because it is not in scope. -fun mn(a) = - if a is - Some(x) and x is - Left(b) then "left-defined" - let y = b + 1 - Right(b) then "right-defined" - None then "undefined" -//│ ╔══[ERROR] identifier not found: b -//│ ║ l.303: let y = b + 1 -//│ ╙── ^ -//│ mn: (None | Some & {value: Left | Right}) -> ("left-defined" | "right-defined" | "undefined") -//│ Code generation encountered an error: -//│ unresolved symbol b - -:ng -mn(Some(Left(0))) -mn(Some(Right(0))) -mn(None()) -//│ res: "left-defined" | "right-defined" | "undefined" -//│ res: "left-defined" | "right-defined" | "undefined" -//│ res: "left-defined" | "right-defined" | "undefined" +//│ mapPartition2: ('head -> (Left | Right) & 'head0 -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), Cons & {head: 'head0, tail: 'tail} | Nil,) -> (Pair & {fst: forall 'a. Cons & {head: 'leftValue, tail: forall 'a. 'fst | 'a} | 'fst | 'a, snd: forall 'b. Cons & {head: 'rightValue, tail: forall 'b. 'fst | 'b} | 'fst | 'b}) +//│ where +//│ 'b :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'b. Nil | 'b} +//│ 'a :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'a. Nil | 'a} +//│ 'fst :> Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} | Nil +//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ = [Function: mapPartition2] +mapPartition2(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) +//│ res: Pair & {fst: forall 'a. Cons & {head: 0, tail: forall 'a. 'fst | 'a} | 'fst | 'a, snd: forall 'b. Cons & {head: 0, tail: forall 'b. 'fst | 'b} | 'fst | 'b} +//│ where +//│ 'b :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'b. Nil | 'b} +//│ 'a :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'a. Nil | 'a} +//│ 'fst :> Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} | Nil +//│ = Pair { +//│ fst: Cons { head: 0, tail: Cons { head: 0, tail: [Cons] } }, +//│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } +//│ } From 1784ecb5c66c796adb47d30aa42566b72ac69f37 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 16 Mar 2023 20:52:30 +0800 Subject: [PATCH 203/498] Gather exhaustiveness information on the fly --- shared/src/main/scala/mlscript/Typer.scala | 14 +- .../src/main/scala/mlscript/ucs/Clause.scala | 7 + .../main/scala/mlscript/ucs/Desugarer.scala | 202 ++++++++++++------ shared/src/test/diff/ucs/ElseIf.mls | 44 ++-- shared/src/test/diff/ucs/Exhaustiveness.mls | 8 +- 5 files changed, 186 insertions(+), 89 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 5204da7c1a..6ceaac171f 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1044,17 +1044,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case ((a_ty, tv), req) => a_ty & tv | req & a_ty.neg() } con(s_ty, req, cs_ty) - case iff @ If(body, fallback) => - import mlscript.ucs._ - try { - val caseTree = buildCaseTree(desugarIf(body, fallback)) - checkExhaustive(caseTree, N)(summarizePatterns(caseTree), ctx, raise) - val desugared = constructTerm(caseTree) - println(s"Desugared term: ${desugared.print(false)}") - iff.desugaredTerm = S(desugared) - typeTerm(desugared) - } catch { - case e: DesugaringException => err(e.messages) + case elf: If => + try typeTerm(desugarIf(elf)) catch { + case e: ucs.DesugaringException => err(e.messages) } case New(S((nmedTy, trm)), TypingUnit(Nil)) => typeMonomorphicTerm(App(Var(nmedTy.base.name).withLocOf(nmedTy), trm)) diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index 402a78781e..a6a6698e77 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -37,6 +37,13 @@ object Clause { override def toString(): String = s"«$scrutinee is $literal" + bindingsToString } + final case class MatchNot( + scrutinee: Scrutinee, + classNames: List[Var] + )(override val locations: Ls[Loc]) extends Clause { + override def toString(): String = s"«$scrutinee ∉ ${classNames.mkString("{", ", ", "}")}»" + bindingsToString + } + final case class MatchClass( scrutinee: Scrutinee, className: Var, diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 695ebf2677..8a5055eed9 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -36,6 +36,24 @@ class Desugarer extends TypeDefs { self: Typer => res } + /** + * A map from each scrutinee term to all its cases and the first `MutCase`. + */ + private type ExhaustivenessMap = Map[Str \/ Int, Map[Either[Int, SimpleTerm], Buffer[Loc]]] + + private type MutExhaustivenessMap = MutMap[Str \/ Int, MutMap[Either[Int, SimpleTerm], Buffer[Loc]]] + + private def addToExhaustivenessMap(scrutinee: Scrutinee, tupleArity: Int, loc: Iterable[Loc]) + (implicit ctx: Ctx, raise: Raise, map: MutExhaustivenessMap) = { + map.getOrElseUpdate(getScurtineeKey(scrutinee), MutMap.empty) + .getOrElseUpdate(L(tupleArity), Buffer.empty) ++= loc + } + private def addToExhaustivenessMap(scrutinee: Scrutinee, litOrCls: SimpleTerm, loc: Iterable[Loc]) + (implicit ctx: Ctx, raise: Raise, map: MutExhaustivenessMap) = { + map.getOrElseUpdate(getScurtineeKey(scrutinee), MutMap.empty) + .getOrElseUpdate(R(litOrCls), Buffer.empty) ++= loc + } + /** * * @@ -78,7 +96,7 @@ class Desugarer extends TypeDefs { self: Typer => * @return desugared conditions representing the sub-patterns */ private def destructSubPatterns(scrutinee: Scrutinee, subPatterns: Iterable[Var -> Term]) - (implicit ctx: Ctx, raise: Raise, aliasMap: FieldAliasMap): Ls[Clause] = { + (implicit ctx: Ctx, raise: Raise, exhaustivenessMap: MutExhaustivenessMap, aliasMap: FieldAliasMap): Ls[Clause] = { subPatterns.iterator.flatMap[Clause] { case (subScrutinee, subPattern) => destructPattern(makeScrutinee(subScrutinee, scrutinee.matchRootLoc), subPattern, false) }.toList @@ -96,7 +114,7 @@ class Desugarer extends TypeDefs { self: Typer => * @param matchRootLoc the caller is expect to be in a match environment, * this parameter indicates the location of the match root */ - def makeScrutinee(term: Term, matchRootLoc: Opt[Loc])(implicit ctx: Ctx): Scrutinee = + private def makeScrutinee(term: Term, matchRootLoc: Opt[Loc])(implicit ctx: Ctx): Scrutinee = traceUCS(s"Making a scrutinee for `$term`") { term match { case _: Var => @@ -144,6 +162,7 @@ class Desugarer extends TypeDefs { self: Typer => (scrutinee: Scrutinee, pattern: Term, isTopLevel: Bool) (implicit ctx: Ctx, raise: Raise, + exhaustivenessMap: MutExhaustivenessMap, aliasMap: FieldAliasMap, fragments: Ls[Term] = Nil): Ls[Clause] = trace(s"[Desugarer.destructPattern] scrutinee = ${scrutinee.term}; pattern = $pattern") { @@ -154,6 +173,7 @@ class Desugarer extends TypeDefs { self: Typer => tuple.fields.iterator.map(_._2.value), 1.to(tuple.fields.length).map("_" + _).toList ) + addToExhaustivenessMap(scrutinee, tuple.fields.length, tuple.toLoc) Clause.MatchTuple( scrutinee, tuple.fields.length, @@ -167,11 +187,13 @@ class Desugarer extends TypeDefs { self: Typer => // This case handles literals. // x is true | x is false | x is 0 | x is "text" | ... case literal: Var if literal.name === "true" || literal.name === "false" => + addToExhaustivenessMap(scrutinee, literal, literal.toLoc) val clause = Clause.MatchLiteral(scrutinee, literal)(scrutinee.term.toLoc.toList ::: literal.toLoc.toList) clause.bindings = scrutinee.asBinding.toList printlnUCS(s"Add bindings to the clause: ${scrutinee.asBinding}") clause :: Nil case literal: Lit => + addToExhaustivenessMap(scrutinee, literal, literal.toLoc) val clause = Clause.MatchLiteral(scrutinee, literal)(scrutinee.term.toLoc.toList ::: literal.toLoc.toList) clause.bindings = scrutinee.asBinding.toList printlnUCS(s"Add bindings to the clause: ${scrutinee.asBinding}") @@ -191,6 +213,7 @@ class Desugarer extends TypeDefs { self: Typer => }, classNameVar.toLoc) } printlnUCS(s"Build a Clause.MatchClass from $scrutinee where pattern is $classNameVar") + addToExhaustivenessMap(scrutinee, classNameVar, classNameVar.toLoc) Clause.MatchClass(scrutinee, classNameVar, Nil)(collectLocations(scrutinee.term)) :: Nil // This case handles classes with destruction. // x is A(r, s, t) @@ -215,6 +238,7 @@ class Desugarer extends TypeDefs { self: Typer => args.iterator.map(_._2.value), positionals ) + addToExhaustivenessMap(scrutinee, classNameVar, app.toLoc) val clause = Clause.MatchClass(scrutinee, classNameVar, bindings)(pattern.toLoc.toList ::: collectLocations(scrutinee.term)) printlnUCS(s"Build a Clause.MatchClass from $scrutinee where pattern is $pattern") printlnUCS(s"Fragments: $fragments") @@ -252,6 +276,7 @@ class Desugarer extends TypeDefs { self: Typer => lhs :: rhs :: Nil, td.positionals ) + addToExhaustivenessMap(scrutinee, opVar, app.toLoc) val clause = Clause.MatchClass(scrutinee, opVar, fields)(collectLocations(scrutinee.term)) printlnUCS(s"Build a Clause.MatchClass from $scrutinee where operator is $opVar") clause :: destructSubPatterns(scrutinee, subPatterns) @@ -282,7 +307,7 @@ class Desugarer extends TypeDefs { self: Typer => * @param fragments the fragment terms * @return all original locations */ - def collectLocations(term: Term)(implicit fragments: Ls[Term]): Ls[Loc] = { + private def collectLocations(term: Term)(implicit fragments: Ls[Term]): Ls[Loc] = { val locations = Buffer.empty[Loc] def rec(term: Term): Unit = term.children.foreach { located => if (fragments.contains(located)) locations ++= located.toLoc @@ -290,10 +315,53 @@ class Desugarer extends TypeDefs { self: Typer => locations.toList } + /** + * The entry point of UCS desugarer. + * + * @param elf the root `If` term + * @param ctx the typing context + * @param raise the function to raise errors + * @return the desugared term + */ + def desugarIf(elf: If)(implicit ctx: Ctx, raise: Raise): Term = traceUCS("[desugarIf]") { + val exhaustivenessMap: MutExhaustivenessMap = MutMap.empty + printlnUCS("### Desugar the UCS to decision paths ###") + val paths = desugarIf(elf.body, elf.els)(ctx, raise, exhaustivenessMap) + printlnUCS("Exhaustiveness map") + if (exhaustivenessMap.isEmpty) + printlnUCS(" * ") + else + exhaustivenessMap.foreach { case (symbol, patternMap) => + printlnUCS(s" * Patterns of $symbol") + if (patternMap.isEmpty) + printlnUCS(s" + ") + else + patternMap.foreach { case (pattern, locations) => + val first = pattern match { + case Left(tupleArity) => s"()^$tupleArity" + case Right(litOrCls) => litOrCls.toString() + } + val second = locations.mkString("[", ", ", "]") + printlnUCS(s" + $first -> $second") + } + } + printlnUCS("### Build a case tree from decision paths ###") + val caseTree = buildCaseTree(paths) + printlnUCS("### Checking exhaustiveness of the case tree ###") + checkExhaustive(caseTree, N)({ + Map.from(exhaustivenessMap.iterator.map { case (k, m) => k -> Map.from(m) }) + }, ctx, raise) + printlnUCS("### Construct a term from the case tree ###") + val desugared = constructTerm(caseTree) + println(s"Desugared term: ${desugared.print(false)}") + elf.desugaredTerm = S(desugared) + desugared + }() + - def desugarIf + private def desugarIf (body: IfBody, fallback: Opt[Term]) - (implicit ctx: Ctx, raise: Raise) + (implicit ctx: Ctx, raise: Raise, exhaustivenessMap: MutExhaustivenessMap) : Ls[Conjunction -> Term] = traceUCS(s"[desugarIf] with fallback $fallback") { // We allocate temporary variable names for nested patterns. // This prevents aliasing problems. @@ -318,7 +386,7 @@ class Desugarer extends TypeDefs { self: Typer => // This is an inline `x is Class` match test. val inlineMatchLoc = isApp.toLoc val inlineScrutinee = makeScrutinee(scrutinee, inlineMatchLoc) - destructPattern(inlineScrutinee, pattern, true)(ctx, raise, scrutineeFieldAliasMap) + destructPattern(inlineScrutinee, pattern, true)(ctx, raise, exhaustivenessMap, scrutineeFieldAliasMap) case test => val clause = Clause.BooleanTest(test)(collectLocations(test)) Iterable.single(clause) @@ -533,11 +601,6 @@ class Desugarer extends TypeDefs { self: Typer => import MutCaseOf.{MutCase, IfThenElse, Match, MissingCase, Consequent} - /** - * A map from each scrutinee term to all its cases and the first `MutCase`. - */ - type ExhaustivenessMap = Map[Str \/ Int, Map[Var, MutCase]] - /** * This method obtains a proper key of the given scrutinee * for memorizing patterns belongs to the scrutinee. @@ -547,7 +610,7 @@ class Desugarer extends TypeDefs { self: Typer => * @param raise we need this to raise errors. * @return the variable name or the variable ID */ - def getScurtineeKey(scrutinee: Scrutinee)(implicit ctx: Ctx, raise: Raise): Str \/ Int = + private def getScurtineeKey(scrutinee: Scrutinee)(implicit ctx: Ctx, raise: Raise): Str \/ Int = traceUCS(s"[getScrutineeKey] $scrutinee") { scrutinee.term match { // The original scrutinee is an reference. @@ -574,7 +637,7 @@ class Desugarer extends TypeDefs { self: Typer => * @param parentOpt the parent `MutCaseOf` * @param scrutineePatternMap the exhaustiveness map */ - def checkExhaustive + private def checkExhaustive (t: MutCaseOf, parentOpt: Opt[MutCaseOf]) (implicit scrutineePatternMap: ExhaustivenessMap, ctx: Ctx, raise: Raise) : Unit = traceUCS(s"[checkExhaustive] ${t.describe}") { @@ -611,10 +674,17 @@ class Desugarer extends TypeDefs { self: Typer => else patternMap.foreach { case (key, mutCase) => printlnUCS(s"- $key => $mutCase")} // Filter out missing cases in `branches`. - val missingCases = patternMap.removedAll(branches.iterator.flatMap { - case MutCase.Literal(tof @ Var(n), _) if n === "true" || n === "false" => Some(tof) - case MutCase.Literal(_, _) => None - case MutCase.Constructor(classNameVar -> _, _) => Some(classNameVar) + val missingCases = patternMap.removedAll(branches.iterator.map { + case MutCase.Literal(lit, _) => R(lit) + case MutCase.Constructor(classNameVar -> _, _) => + classNameVar.name.split('#').toList match { + case "Tuple" :: ns :: Nil => + ns.toIntOption match { + case N => R(classNameVar) + case S(arity) => L(arity) + } + case _ => R(classNameVar) + } }) printlnUCS("Missing cases") missingCases.foreach { case (key, m) => @@ -627,11 +697,15 @@ class Desugarer extends TypeDefs { self: Typer => (msg"The scrutinee at this position misses ${numMissingCases.toString} ${ "case".pluralize(numMissingCases) }." -> scrutinee.term.toLoc) :: - missingCases.iterator.zipWithIndex.flatMap { case ((classNameVar, firstMutCase), index) => + missingCases.iterator.zipWithIndex.flatMap { case ((pattern, locations), index) => + val patternName = pattern match { + case L(tupleArity) => s"$tupleArity-ary tuple" + case R(litOrCls) => litOrCls.toString() + } val progress = s"[Missing Case ${index + 1}/$numMissingCases]" - (msg"$progress `${classNameVar.name}`" -> N) :: - firstMutCase.locations.iterator.zipWithIndex.map { case (loc, index) => - (if (index === 0) msg"It first appears here." else msg"continued at") -> S(loc) + (msg"$progress `$patternName`" -> N) :: + locations.iterator.zipWithIndex.map { case (loc, index) => + (if (index === 0) msg"It first appears here." else msg"And here.") -> S(loc) }.toList }.toList }) @@ -644,47 +718,47 @@ class Desugarer extends TypeDefs { self: Typer => } }(_ => s"[checkExhaustive] ${t.describe}") - def summarizePatterns(t: MutCaseOf)(implicit ctx: Ctx, raise: Raise): ExhaustivenessMap = traceUCS("[summarizePatterns]") { - val m = MutMap.empty[Str \/ Int, MutMap[Var, MutCase]] - def rec(t: MutCaseOf): Unit = traceUCS(s"[rec] ${t.describe}") { - t match { - case Consequent(term) => () - case MissingCase => () - case IfThenElse(_, whenTrue, whenFalse) => - rec(whenTrue) - rec(whenFalse) - case Match(scrutinee, branches, default) => - val key = getScurtineeKey(scrutinee) - val patternMap = m.getOrElseUpdate(key, MutMap.empty) - branches.foreach { - case mutCase @ MutCase.Literal(literal, consequent) => - literal match { - case tof @ Var(n) if n === "true" || n === "false" => - if (!patternMap.contains(tof)) { - patternMap += ((tof, mutCase)) - } - case _ => () // TODO: Summarize literals. - } - rec(consequent) - case mutCase @ MutCase.Constructor((className, _), consequent) => - if (!patternMap.contains(className)) { - patternMap += ((className, mutCase)) - } - rec(consequent) - } - default.foreach(rec) - } - }() - rec(t) - printlnUCS("Summarized patterns") - if (m.isEmpty) - printlnUCS("") - else - m.foreach { case (scrutinee, patterns) => - printlnUCS(s"- $scrutinee => " + patterns.keysIterator.mkString(", ")) - } - Map.from(m.iterator.map { case (key, patternMap) => key -> Map.from(patternMap) }) - }(_ => "[summarizePatterns]") + // private def summarizePatterns(t: MutCaseOf)(implicit ctx: Ctx, raise: Raise): ExhaustivenessMap = traceUCS("[summarizePatterns]") { + // val m = MutMap.empty[Str \/ Int, MutMap[Var, MutCase]] + // def rec(t: MutCaseOf): Unit = traceUCS(s"[rec] ${t.describe}") { + // t match { + // case Consequent(term) => () + // case MissingCase => () + // case IfThenElse(_, whenTrue, whenFalse) => + // rec(whenTrue) + // rec(whenFalse) + // case Match(scrutinee, branches, default) => + // val key = getScurtineeKey(scrutinee) + // val patternMap = m.getOrElseUpdate(key, MutMap.empty) + // branches.foreach { + // case mutCase @ MutCase.Literal(literal, consequent) => + // literal match { + // case tof @ Var(n) if n === "true" || n === "false" => + // if (!patternMap.contains(tof)) { + // patternMap += ((tof, mutCase)) + // } + // case _ => () // TODO: Summarize literals. + // } + // rec(consequent) + // case mutCase @ MutCase.Constructor((className, _), consequent) => + // if (!patternMap.contains(className)) { + // patternMap += ((className, mutCase)) + // } + // rec(consequent) + // } + // default.foreach(rec) + // } + // }() + // rec(t) + // printlnUCS("Summarized patterns") + // if (m.isEmpty) + // printlnUCS(" ") + // else + // m.foreach { case (scrutinee, patterns) => + // printlnUCS(s" * $scrutinee => " + patterns.keysIterator.mkString(", ")) + // } + // Map.from(m.iterator.map { case (key, patternMap) => key -> Map.from(patternMap) }) + // }(_ => "[summarizePatterns]") /** * Make a term from a mutable case tree. @@ -694,7 +768,7 @@ class Desugarer extends TypeDefs { self: Typer => * @param ctx the context * @return the case expression */ - protected def constructTerm(m: MutCaseOf)(implicit ctx: Ctx): Term = traceUCS("[constructTerm]") { + private def constructTerm(m: MutCaseOf)(implicit ctx: Ctx): Term = traceUCS("[constructTerm]") { /** * Reconstruct case branches. */ @@ -815,7 +889,7 @@ class Desugarer extends TypeDefs { self: Typer => rec(scrutinee.reference, fields) } - protected def buildCaseTree + private def buildCaseTree (paths: Ls[Conjunction -> Term]) (implicit raise: Diagnostic => Unit) : MutCaseOf = traceUCS("[buildCaseTree]") { diff --git a/shared/src/test/diff/ucs/ElseIf.mls b/shared/src/test/diff/ucs/ElseIf.mls index 561c975305..605996aaba 100644 --- a/shared/src/test/diff/ucs/ElseIf.mls +++ b/shared/src/test/diff/ucs/ElseIf.mls @@ -40,7 +40,10 @@ fun f(x, y) = if x is //│ ╟── The scrutinee at this position misses 1 case. //│ ║ l.35: True and y is True then true //│ ║ ^ -//│ ╙── [Missing Case 1/1] `False` +//│ ╟── [Missing Case 1/1] `False` +//│ ╟── It first appears here. +//│ ║ l.36: False and y is False then false +//│ ╙── ^^^^^ //│ fun f: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared @@ -60,12 +63,18 @@ fun f(x, y) = if x is True then true False then false //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.57: True and y is True then true +//│ ║ l.60: True and y is True then true //│ ║ ^^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.57: True and y is True then true +//│ ║ l.60: True and y is True then true //│ ║ ^ -//│ ╙── [Missing Case 1/1] `False` +//│ ╟── [Missing Case 1/1] `False` +//│ ╟── It first appears here. +//│ ║ l.61: False and y is False then false +//│ ║ ^^^^^ +//│ ╟── And here. +//│ ║ l.64: False then false +//│ ╙── ^^^^^ //│ fun f: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared @@ -87,26 +96,35 @@ fun f(x, y) = if x is True and x is False then true False and x is True then false //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.87: True and x is False then true +//│ ║ l.96: True and x is False then true //│ ║ ^^^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.87: True and x is False then true +//│ ║ l.96: True and x is False then true //│ ║ ^ -//│ ╙── [Missing Case 1/1] `True` +//│ ╟── [Missing Case 1/1] `True` +//│ ╟── It first appears here. +//│ ║ l.97: False and x is True then false +//│ ╙── ^^^^ //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.87: True and x is False then true +//│ ║ l.96: True and x is False then true //│ ║ ^^^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.87: True and x is False then true +//│ ║ l.96: True and x is False then true //│ ║ ^ -//│ ╙── [Missing Case 1/1] `True` +//│ ╟── [Missing Case 1/1] `True` +//│ ╟── It first appears here. +//│ ║ l.97: False and x is True then false +//│ ╙── ^^^^ //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.87: True and x is False then true +//│ ║ l.96: True and x is False then true //│ ║ ^^^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.87: True and x is False then true +//│ ║ l.96: True and x is False then true //│ ║ ^ -//│ ╙── [Missing Case 1/1] `True` +//│ ╟── [Missing Case 1/1] `True` +//│ ╟── It first appears here. +//│ ║ l.97: False and x is True then false +//│ ╙── ^^^^ //│ fun f: (anything, anything,) -> (error | false | true) //│ Code generation encountered an error: //│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/Exhaustiveness.mls b/shared/src/test/diff/ucs/Exhaustiveness.mls index c56f142300..716d3b35dd 100644 --- a/shared/src/test/diff/ucs/Exhaustiveness.mls +++ b/shared/src/test/diff/ucs/Exhaustiveness.mls @@ -29,5 +29,11 @@ fun f(x, y) = //│ ║ l.23: x is //│ ║ ^ //│ ╟── [Missing Case 1/2] `B` -//│ ╙── [Missing Case 2/2] `C` +//│ ╟── It first appears here. +//│ ║ l.20: B then 1 +//│ ║ ^ +//│ ╟── [Missing Case 2/2] `C` +//│ ╟── It first appears here. +//│ ║ l.21: C then 2 +//│ ╙── ^ //│ f: (anything, anything,) -> error From 09a0fb96eed40ec840d0a8377a6be346e3a88194 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 16 Mar 2023 21:13:00 +0800 Subject: [PATCH 204/498] Support basic `else if` composition --- .../main/scala/mlscript/ucs/Desugarer.scala | 17 +++++- shared/src/test/diff/ucs/ElseIf.mls | 55 ++++++------------- shared/src/test/diff/ucs/TrivialIf.mls | 2 +- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 8a5055eed9..604290504d 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -315,6 +315,20 @@ class Desugarer extends TypeDefs { self: Typer => locations.toList } + private def unfoldNestedIf(elf: If, acc: Ls[IfBody] = Nil): (IfBody, Opt[Term]) = + traceUCS("[unfoldNestedIf]") { + elf.els match { + case S(innerElf: If) => unfoldNestedIf(innerElf, elf.body :: acc) + case default if acc.isEmpty => (elf.body, default) + case default => + val lines = (elf.body :: acc).reverseIterator.flatMap { + case IfBlock(subLines) => subLines + case other => Iterable.single(L(other)) + }.toList + (IfBlock(lines), default) + } + }(r => s"[unfoldNestedIf] (${r._1.getClass().getSimpleName()}, ${r._2})") + /** * The entry point of UCS desugarer. * @@ -324,9 +338,10 @@ class Desugarer extends TypeDefs { self: Typer => * @return the desugared term */ def desugarIf(elf: If)(implicit ctx: Ctx, raise: Raise): Term = traceUCS("[desugarIf]") { + val (body, els) = unfoldNestedIf(elf) val exhaustivenessMap: MutExhaustivenessMap = MutMap.empty printlnUCS("### Desugar the UCS to decision paths ###") - val paths = desugarIf(elf.body, elf.els)(ctx, raise, exhaustivenessMap) + val paths = desugarIf(body, els)(ctx, raise, exhaustivenessMap) printlnUCS("Exhaustiveness map") if (exhaustivenessMap.isEmpty) printlnUCS(" * ") diff --git a/shared/src/test/diff/ucs/ElseIf.mls b/shared/src/test/diff/ucs/ElseIf.mls index 605996aaba..1e9e0d09e2 100644 --- a/shared/src/test/diff/ucs/ElseIf.mls +++ b/shared/src/test/diff/ucs/ElseIf.mls @@ -86,48 +86,27 @@ fun f(x, y) = if x is else if y is True then true False then false -//│ fun f: (anything, False | True,) -> bool - -// TODO support `else if` -fun f(x, y) = if x is - True and y is True then true - False and y is False then false - else if y is - True and x is False then true - False and x is True then false -//│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.96: True and x is False then true -//│ ║ ^^^^^^^^^^ -//│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.96: True and x is False then true -//│ ║ ^ -//│ ╟── [Missing Case 1/1] `True` -//│ ╟── It first appears here. -//│ ║ l.97: False and x is True then false -//│ ╙── ^^^^ -//│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.96: True and x is False then true -//│ ║ ^^^^^^^^^^ -//│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.96: True and x is False then true -//│ ║ ^ -//│ ╟── [Missing Case 1/1] `True` -//│ ╟── It first appears here. -//│ ║ l.97: False and x is True then false -//│ ╙── ^^^^ //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.96: True and x is False then true -//│ ║ ^^^^^^^^^^ +//│ ║ l.84: True and y is True then true +//│ ║ ^^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.96: True and x is False then true +//│ ║ l.84: True and y is True then true //│ ║ ^ -//│ ╟── [Missing Case 1/1] `True` +//│ ╟── [Missing Case 1/1] `False` //│ ╟── It first appears here. -//│ ║ l.97: False and x is True then false -//│ ╙── ^^^^ -//│ fun f: (anything, anything,) -> (error | false | true) +//│ ║ l.85: False and y is False then false +//│ ║ ^^^^^ +//│ ╟── And here. +//│ ║ l.88: False then false +//│ ╙── ^^^^^ +//│ fun f: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared - - +fun f(x, y) = if x is + True and y is True then true + False and y is False then false + else if y is + True and x is False then true + False and x is True then false +//│ fun f: (False | True, False | True,) -> bool diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index fffc4f8b2d..af0837fe75 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -55,7 +55,7 @@ fun f(x, y) = //│ ╔══[ERROR] The case when this is false is not handled: == (x,) (+ (y,) (7,),) //│ ║ l.54: else if x == y + 7 then 0 //│ ╙── ^^^^^^^^^^ -//│ f: (number, int,) -> (0 | error) +//│ f: (anything, anything,) -> error From ae1ca1374d727db34e62b9259ecb415641cbff32 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 15:36:18 +0800 Subject: [PATCH 205/498] Support wildcard followed by more clauses --- .../src/main/scala/mlscript/ucs/Clause.scala | 23 +-- .../main/scala/mlscript/ucs/Conjunction.scala | 25 ++- .../main/scala/mlscript/ucs/Desugarer.scala | 32 +-- .../main/scala/mlscript/ucs/MutCaseOf.scala | 91 ++++++--- shared/src/test/diff/ucs/ElseIf.mls | 79 ++++---- shared/src/test/diff/ucs/JSON.mls | 4 +- shared/src/test/diff/ucs/SplitAroundOp.mls | 182 +++++++++++++++++- 7 files changed, 336 insertions(+), 100 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index a6a6698e77..2eeed3d8cb 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -9,7 +9,7 @@ import scala.collection.mutable.Buffer * A `Clause` represents a minimal unit of logical predicate in the UCS. * There are three kinds of clauses: boolean test, class match, and tuple match. */ -abstract class Clause { +sealed abstract class Clause { /** * Local interleaved let bindings declared before this condition. */ @@ -29,26 +29,27 @@ abstract class Clause { }) } +sealed abstract class MatchClause extends Clause { + val scrutinee: Scrutinee +} + object Clause { final case class MatchLiteral( - scrutinee: Scrutinee, + override val scrutinee: Scrutinee, literal: SimpleTerm - )(override val locations: Ls[Loc]) extends Clause { + )(override val locations: Ls[Loc]) extends MatchClause { override def toString(): String = s"«$scrutinee is $literal" + bindingsToString } - final case class MatchNot( - scrutinee: Scrutinee, - classNames: List[Var] - )(override val locations: Ls[Loc]) extends Clause { - override def toString(): String = s"«$scrutinee ∉ ${classNames.mkString("{", ", ", "}")}»" + bindingsToString - } + // final case class MatchNot(override val scrutinee: Scrutinee)(override val locations: Ls[Loc]) extends MatchClause { + // override def toString(): String = s"otherwise of «$scrutinee»" + bindingsToString + // } final case class MatchClass( - scrutinee: Scrutinee, + override val scrutinee: Scrutinee, className: Var, fields: Ls[Str -> Var] - )(override val locations: Ls[Loc]) extends Clause { + )(override val locations: Ls[Loc]) extends MatchClause { override def toString(): String = s"«$scrutinee is $className»" + bindingsToString } diff --git a/shared/src/main/scala/mlscript/ucs/Conjunction.scala b/shared/src/main/scala/mlscript/ucs/Conjunction.scala index 875a6b0489..f657b0b347 100644 --- a/shared/src/main/scala/mlscript/ucs/Conjunction.scala +++ b/shared/src/main/scala/mlscript/ucs/Conjunction.scala @@ -45,6 +45,17 @@ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[LetBindin } } + /** + * This is a shorthand if you only have one clause. + * + * @param last the list of clauses to append to this conjunction + * @return a new conjunction with clauses from `this` and `last` + */ + def +(last: Clause): Conjunction = { + last.bindings = trailingBindings ::: last.bindings + Conjunction(clauses :+ last, Nil) + } + /** * This is a shorthand if you only have the last binding. * @@ -54,23 +65,29 @@ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[LetBindin def +(lastBinding: LetBinding): Conjunction = Conjunction(clauses, trailingBindings :+ lastBinding) - def separate(expectedScrutinee: Scrutinee): Opt[(MatchClass \/ MatchLiteral, Conjunction)] = { + def separate(expectedScrutinee: Scrutinee): Opt[(MatchClause, Conjunction)] = { @tailrec - def rec(past: Ls[Clause], upcoming: Ls[Clause]): Opt[(Ls[Clause], MatchClass \/ MatchLiteral, Ls[Clause])] = { + def rec(past: Ls[Clause], upcoming: Ls[Clause]): Opt[(Ls[Clause], MatchClause, Ls[Clause])] = { upcoming match { case Nil => N case (head @ MatchLiteral(scrutinee, _)) :: tail => if (scrutinee === expectedScrutinee) { - S((past, R(head), tail)) + S((past, head, tail)) } else { rec(past :+ head, tail) } case (head @ MatchClass(scrutinee, _, _)) :: tail => if (scrutinee === expectedScrutinee) { - S((past, L(head), tail)) + S((past, head, tail)) } else { rec(past :+ head, tail) } + // case (head @ MatchNot(scrutinee)) :: tail => + // if (scrutinee === expectedScrutinee) { + // S((past, head, tail)) + // } else { + // rec(past :+ head, tail) + // } case head :: tail => rec(past :+ head, tail) } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 604290504d..cf1e9953c0 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -16,6 +16,7 @@ class Desugarer extends TypeDefs { self: Typer => private def traceUCS[T](pre: => String)(thunk: => T)(post: T => String = noPostTrace) = if (dbgUCS) trace(pre)(thunk)(post) else thunk + import Desugarer.ExhaustivenessMap import Clause.{MatchClass, MatchTuple, BooleanTest} type FieldAliasMap = MutMap[SimpleTerm, MutMap[Str, Var]] @@ -36,11 +37,6 @@ class Desugarer extends TypeDefs { self: Typer => res } - /** - * A map from each scrutinee term to all its cases and the first `MutCase`. - */ - private type ExhaustivenessMap = Map[Str \/ Int, Map[Either[Int, SimpleTerm], Buffer[Loc]]] - private type MutExhaustivenessMap = MutMap[Str \/ Int, MutMap[Either[Int, SimpleTerm], Buffer[Loc]]] private def addToExhaustivenessMap(scrutinee: Scrutinee, tupleArity: Int, loc: Iterable[Loc]) @@ -183,6 +179,8 @@ class Desugarer extends TypeDefs { self: Typer => pattern match { // This case handles top-level wildcard `Var`. // We don't make any conditions in this level. + // case wildcard @ Var("_") if isTopLevel => + // Clause.MatchNot(scrutinee)(wildcard.toLoc.toList) :: Nil case Var("_") => Nil // This case handles literals. // x is true | x is false | x is 0 | x is "text" | ... @@ -361,11 +359,10 @@ class Desugarer extends TypeDefs { self: Typer => } } printlnUCS("### Build a case tree from decision paths ###") - val caseTree = buildCaseTree(paths) + val imExhaustivenessMap = Map.from(exhaustivenessMap.iterator.map { case (k, m) => k -> Map.from(m) }) + val caseTree = buildCaseTree(paths)(raise, getScurtineeKey, imExhaustivenessMap) printlnUCS("### Checking exhaustiveness of the case tree ###") - checkExhaustive(caseTree, N)({ - Map.from(exhaustivenessMap.iterator.map { case (k, m) => k -> Map.from(m) }) - }, ctx, raise) + checkExhaustive(caseTree, N)(imExhaustivenessMap, ctx, raise) printlnUCS("### Construct a term from the case tree ###") val desugared = constructTerm(caseTree) println(s"Desugared term: ${desugared.print(false)}") @@ -429,15 +426,17 @@ class Desugarer extends TypeDefs { self: Typer => // if x is // A(...) then ... // else ... - case L(IfElse(consequent)) => + case L(els @ IfElse(consequent)) => // Because this pattern matching is incomplete, it's not included in // `acc`. This means that we discard this incomplete pattern matching. + // branches += (collectedConditions + Clause.MatchNot(scrutinee)(els.toLoc.toList) -> consequent) branches += (collectedConditions -> consequent) // This case handles default branches indicated by wildcards. // if x is // A(...) then ... // _ then ... - case L(IfThen(Var("_"), consequent)) => + case L(IfThen(wildcard @ Var("_"), consequent)) => + // branches += (collectedConditions + Clause.MatchNot(scrutinee)(wildcard.toLoc.toList) -> consequent) branches += (collectedConditions -> consequent) // if x is // A(...) then ... // Case 1: no conjunctions @@ -906,7 +905,9 @@ class Desugarer extends TypeDefs { self: Typer => private def buildCaseTree (paths: Ls[Conjunction -> Term]) - (implicit raise: Diagnostic => Unit) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap) : MutCaseOf = traceUCS("[buildCaseTree]") { paths match { case Nil => MissingCase @@ -925,3 +926,10 @@ class Desugarer extends TypeDefs { self: Typer => } }(_ => "[buildCaseTree]") } + +object Desugarer { + /** + * A map from each scrutinee term to all its cases and the first `MutCase`. + */ + type ExhaustivenessMap = Map[Str \/ Int, Map[Either[Int, SimpleTerm], Buffer[Loc]]] +} \ No newline at end of file diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index a4653b6b73..bcd068dad5 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -9,6 +9,7 @@ import scala.collection.mutable.{Map => MutMap, Set => MutSet, Buffer} import helpers._ import mlscript.ucs.MutCaseOf.Consequent import scala.collection.immutable +import Desugarer.ExhaustivenessMap sealed abstract class MutCaseOf extends WithBindings { def kind: Str = { @@ -23,12 +24,16 @@ sealed abstract class MutCaseOf extends WithBindings { def describe: Str + def tryMerge + (branch: Conjunction -> Term) + (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, exhaustivenessMap: ExhaustivenessMap): Unit = + merge(branch)(_ => (), getScrutineeKey, exhaustivenessMap) def merge (branch: Conjunction -> Term) - (implicit raise: Diagnostic => Unit): Unit + (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, exhaustivenessMap: ExhaustivenessMap): Unit def mergeDefault (bindings: Ls[LetBinding], default: Term) - (implicit raise: Diagnostic => Unit): Int + (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, exhaustivenessMap: ExhaustivenessMap): Int // TODO: Make it immutable. var locations: Ls[Loc] = Nil @@ -155,14 +160,17 @@ object MutCaseOf { } } - import Clause.{MatchLiteral, MatchClass, MatchTuple, BooleanTest, Binding} + import Clause.{MatchLiteral /*, MatchNot */, MatchClass, MatchTuple, BooleanTest, Binding} // A short-hand for pattern matchings with only true and false branches. final case class IfThenElse(condition: Term, var whenTrue: MutCaseOf, var whenFalse: MutCaseOf) extends MutCaseOf { def describe: Str = s"IfThenElse($condition, whenTrue = ${whenTrue.kind}, whenFalse = ${whenFalse.kind})" - def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = + def merge(branch: Conjunction -> Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Unit = branch match { // The CC is a wildcard. So, we call `mergeDefault`. case Conjunction(Nil, trailingBindings) -> term => @@ -173,22 +181,13 @@ object MutCaseOf { )) } // The CC is an if-then-else. We create a pattern match of true/false. - case Conjunction((head @ BooleanTest(test)) :: tail, trailingBindings) -> term => - // If the test is the same. So, we merge. - if (test === condition) { - whenTrue.addBindings(head.bindings) - whenTrue.merge(Conjunction(tail, trailingBindings) -> term) - } else { - whenFalse match { - case Consequent(_) => - raise(WarningReport(Message.fromStr("duplicated else in the if-then-else") -> N :: Nil)) - case MissingCase => - whenFalse = buildFirst(branch._1, branch._2) - whenFalse.addBindings(head.bindings) - case _ => whenFalse.merge(branch) - } - } + case Conjunction((head @ BooleanTest(test)) :: tail, trailingBindings) -> term if test === condition => + // If the test is the same. So, we can insert the path to the true branch. + whenTrue.addBindings(head.bindings) + whenTrue.merge(Conjunction(tail, trailingBindings) -> term) + // Otherwise, we try to insert to the true branch. case Conjunction(head :: _, _) -> _ => + whenTrue.tryMerge(branch) whenFalse match { case Consequent(_) => raise(WarningReport(Message.fromStr("duplicated else in the if-then-else") -> N :: Nil)) @@ -199,7 +198,10 @@ object MutCaseOf { } } - def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = { + def mergeDefault(bindings: Ls[LetBinding], default: Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Int = { whenTrue.mergeDefault(bindings, default) + { whenFalse match { case Consequent(term) => 0 @@ -223,7 +225,10 @@ object MutCaseOf { })" } - def merge(originalBranch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = { + def merge(originalBranch: Conjunction -> Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Unit = { // Remove let bindings that already has been declared. val branch = originalBranch._1.copy(clauses = originalBranch._1.clauses.filter { case Binding(name, value, false) if (getBindings.exists { @@ -233,6 +238,7 @@ object MutCaseOf { }) => false case _ => true }) -> originalBranch._2 + // Promote the match against the same scrutinee. branch._1.separate(scrutinee) match { // No conditions against the same scrutinee. case N => @@ -258,6 +264,9 @@ object MutCaseOf { mergeDefault(trailingBindings, term) // TODO: Handle the int result here. // The conditions to be inserted does not overlap with me. case conjunction -> term => + branches.foreach { + _.consequent.tryMerge(conjunction -> term) + } wildcard match { // No wildcard. We will create a new one. case N => wildcard = S(buildFirst(conjunction, term)) @@ -266,7 +275,7 @@ object MutCaseOf { } } // Found a match condition against the same scrutinee - case S(L(head @ MatchClass(_, className, fields)) -> remainingConditions) => + case S((head @ MatchClass(_, className, fields)) -> remainingConditions) => branches.find(_.matches(className)) match { // No such pattern. We should create a new one. case N => @@ -281,7 +290,7 @@ object MutCaseOf { matchCase.addFields(fields) matchCase.consequent.merge(remainingConditions -> branch._2) } - case S(R(head @ MatchLiteral(_, literal)) -> remainingConditions) => + case S((head @ MatchLiteral(_, literal)) -> remainingConditions) => branches.find(branch => literal match { case v: Var => branch.matches(v) case l: Lit => branch.matches(l) @@ -297,10 +306,20 @@ object MutCaseOf { matchCase.consequent.addBindings(head.bindings) matchCase.consequent.merge(remainingConditions -> branch._2) } + // case S((head @ MatchNot(_)) -> remainingConditions) => + // wildcard match { + // // No wildcard. We will create a new one. + // case N => wildcard = S(buildFirst(remainingConditions, branch._2)) + // // There is a wildcard case. Just merge! + // case S(consequent) => consequent.merge(remainingConditions -> branch._2) + // } } } - def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = { + def mergeDefault(bindings: Ls[LetBinding], default: Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Int = { branches.iterator.map { case MutCase.Constructor(_, consequent) => consequent.mergeDefault(bindings, default) case MutCase.Literal(_, consequent) => consequent.mergeDefault(bindings, default) @@ -317,7 +336,10 @@ object MutCaseOf { final case class Consequent(term: Term) extends MutCaseOf { def describe: Str = s"Consequent($term)" - def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = + def merge(branch: Conjunction -> Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Unit = raise { import scala.collection.mutable.ListBuffer val buffer = ListBuffer.empty[Message -> Opt[Loc]] @@ -335,18 +357,29 @@ object MutCaseOf { WarningReport(buffer.toList) } - def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 + def mergeDefault(bindings: Ls[LetBinding], default: Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Int = 0 } final case object MissingCase extends MutCaseOf { def describe: Str = "MissingCase" - def merge(branch: Conjunction -> Term)(implicit raise: Diagnostic => Unit): Unit = + def merge(branch: Conjunction -> Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Unit = lastWords("`MissingCase` is a placeholder and cannot be merged") - def mergeDefault(bindings: Ls[LetBinding], default: Term)(implicit raise: Diagnostic => Unit): Int = 0 + def mergeDefault(bindings: Ls[LetBinding], default: Term) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Int = 0 } - def buildFirst(conjunction: Conjunction, term: Term): MutCaseOf = { + def buildFirst(conjunction: Conjunction, term: Term) + (implicit getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): MutCaseOf = { def rec(conjunction: Conjunction): MutCaseOf = conjunction match { case Conjunction(head :: tail, trailingBindings) => lazy val (beforeHeadBindings, afterHeadBindings) = head.bindings.partition { diff --git a/shared/src/test/diff/ucs/ElseIf.mls b/shared/src/test/diff/ucs/ElseIf.mls index 1e9e0d09e2..d960bc750b 100644 --- a/shared/src/test/diff/ucs/ElseIf.mls +++ b/shared/src/test/diff/ucs/ElseIf.mls @@ -20,34 +20,31 @@ fun f(x, y) = if x == _ then false //│ fun f: (number, number,) -> bool - - -// TODO use real booleans module True module False //│ module True() //│ module False() - :e :ge fun f(x, y) = if x is True and y is True then true False and y is False then false //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.35: True and y is True then true +//│ ║ l.31: True and y is True then true //│ ║ ^^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.35: True and y is True then true +//│ ║ l.31: True and y is True then true //│ ║ ^ //│ ╟── [Missing Case 1/1] `False` //│ ╟── It first appears here. -//│ ║ l.36: False and y is False then false +//│ ║ l.32: False and y is False then false //│ ╙── ^^^^^ //│ fun f: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared +// The base case. fun f(x, y) = if x is True and y is True then true False and y is False then false @@ -55,53 +52,46 @@ fun f(x, y) = if x is False and y is True then true //│ fun f: (False | True, False | True,) -> bool -// FIXME +// Replace the `x is False` with `_` fun f(x, y) = if x is True and y is True then true False and y is False then false _ and y is True then true False then false -//│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.60: True and y is True then true -//│ ║ ^^^^^^^^^ -//│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.60: True and y is True then true -//│ ║ ^ -//│ ╟── [Missing Case 1/1] `False` -//│ ╟── It first appears here. -//│ ║ l.61: False and y is False then false -//│ ║ ^^^^^ -//│ ╟── And here. -//│ ║ l.64: False then false -//│ ╙── ^^^^^ -//│ fun f: (anything, anything,) -> error -//│ Code generation encountered an error: -//│ if expression was not desugared +//│ fun f: (anything, False | True,) -> bool -// TODO support `else if` +f(True, True) +f(True, False) +f(False, True) +f(False, False) +//│ bool +//│ res +//│ = true +//│ res +//│ = false +//│ res +//│ = true +//│ res +//│ = false + +// Test with real booleans +fun g(x, y) = if x is + true and y is true then true + false and y is false then false + _ and y is + true then true + false then false +//│ fun g: (anything, bool,) -> bool + +// Chained UCS terms fun f(x, y) = if x is True and y is True then true False and y is False then false else if y is True then true False then false -//│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.84: True and y is True then true -//│ ║ ^^^^^^^^^ -//│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.84: True and y is True then true -//│ ║ ^ -//│ ╟── [Missing Case 1/1] `False` -//│ ╟── It first appears here. -//│ ║ l.85: False and y is False then false -//│ ║ ^^^^^ -//│ ╟── And here. -//│ ║ l.88: False then false -//│ ╙── ^^^^^ -//│ fun f: (anything, anything,) -> error -//│ Code generation encountered an error: -//│ if expression was not desugared +//│ fun f: (anything, False | True,) -> bool fun f(x, y) = if x is True and y is True then true @@ -110,3 +100,10 @@ fun f(x, y) = if x is True and x is False then true False and x is True then false //│ fun f: (False | True, False | True,) -> bool + +fun h(x, y, p) = if + x and p(x) then 0 + y is + True then 1 + False then 2 +//│ fun h: (anything, False | True, true -> anything,) -> (0 | 1 | 2) diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index 35aa3c9bf0..40a2cbdbb7 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -123,10 +123,10 @@ fun listJoin(xs, sep) = //│ type List[A] = Cons[A] | Nil //│ module Nil() //│ class Cons[A](head: A, tail: List[A]) -//│ fun listConcat: forall 'A 'a 'A0. (Cons['A0] | Nil, List['A] & 'a,) -> (Cons['A] | 'a) +//│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) //│ fun listJoin: forall 'A1. (Cons['A1] | Nil, string,) -> string //│ where -//│ 'A0 <: 'A +//│ 'A <: 'A0 type TreeMap[A] = Node[A] | Empty module Empty diff --git a/shared/src/test/diff/ucs/SplitAroundOp.mls b/shared/src/test/diff/ucs/SplitAroundOp.mls index 1ff84e7f36..dfd03d5db2 100644 --- a/shared/src/test/diff/ucs/SplitAroundOp.mls +++ b/shared/src/test/diff/ucs/SplitAroundOp.mls @@ -73,6 +73,186 @@ fun f(x, b) = //│ ╟── string literal of type `"2"` is not an instance of type `number` //│ ║ l.14: "2" then "s2" //│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"0"` is not an instance of type `number` +//│ ║ l.12: "0" then "s0" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.13: "1" then "s1" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"1"` is not an instance of type `number` +//│ ║ l.13: "1" then "s1" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.13: "1" then "s1" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.14: "2" then "s2" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"2"` is not an instance of type `number` +//│ ║ l.14: "2" then "s2" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"0"` is not an instance of type `number` +//│ ║ l.12: "0" then "s0" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.13: "1" then "s1" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"1"` is not an instance of type `number` +//│ ║ l.13: "1" then "s1" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.13: "1" then "s1" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.14: "2" then "s2" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"2"` is not an instance of type `number` +//│ ║ l.14: "2" then "s2" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"0"` is not an instance of type `number` +//│ ║ l.12: "0" then "s0" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.13: "1" then "s1" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"1"` is not an instance of type `number` +//│ ║ l.13: "1" then "s1" +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.6: if x +//│ ║ ^ +//│ ║ l.7: == +//│ ║ ^^^^^^ +//│ ║ l.8: 0 and b then "n0" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.9: 1 and b then "n1" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.10: 2 then "n2" +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.11: == +//│ ║ ^^^^^^ +//│ ║ l.12: "0" then "s0" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.13: "1" then "s1" +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.14: "2" then "s2" +//│ ║ ^^^^^^^^^ +//│ ╟── string literal of type `"2"` is not an instance of type `number` +//│ ║ l.14: "2" then "s2" +//│ ╙── ^^^ //│ f: (number, anything,) -> (":p" | "n0" | "n1" | "n2" | "s0" | "s1" | "s2") //│ = [Function: f] @@ -112,7 +292,7 @@ if x is > 0 then 1 < 0 then 2 //│ ╔══[ERROR] Cannot find operator `==` in the context -//│ ║ l.111: == 0 then 0 +//│ ║ l.291: == 0 then 0 //│ ╙── ^^ //│ res: error //│ Code generation encountered an error: From 281bb1d233168447995dace51814b21c6914421c Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 15:36:45 +0800 Subject: [PATCH 206/498] Ignore .DS_Store :^( --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1e05d21e31..4a989b4c7d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ metals.sbt project/Dependencies.scala project/metals.sbt **.worksheet.sc +.DS_Store From 62833517180cf4588afdcf637d9ff00af4657fbf Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 15:43:20 +0800 Subject: [PATCH 207/498] Add more `_ and t`-like test cases --- shared/src/test/diff/ucs/Wildcard.mls | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 shared/src/test/diff/ucs/Wildcard.mls diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls new file mode 100644 index 0000000000..12f42cb69f --- /dev/null +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -0,0 +1,54 @@ +:NewParser +:NewDefs + +type Option[T] = None | Some[T] +module None +class Some[T](value: T) +//│ type Option[T] = Some[T] | None +//│ module None() +//│ class Some[T](value: T) + +type Either[A, B] = Left[A] | Right[B] +class Left[A](leftValue: A) +class Right[B](rightValue: B) +//│ type Either[A, B] = Left[A] | Right[B] +//│ class Left[A](leftValue: A) +//│ class Right[B](rightValue: B) + +// FIXME +fun w1(x, e_0, e_1) = + if x is + Left(None) then 1 + Right(None) then 2 + _ and e_0 is y_0 and x is + Left(Some(lv)) then 3 + _ and e_1 is y_1 and x is + Right(Some(rv)) then 4 +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.24: Left(Some(lv)) then 3 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.21: Left(None) then 1 +//│ ╙── ^ +//│ ╔══[WARNING] Found duplicated branch +//│ ╟── This decision path tries to fit +//│ ║ l.26: Right(Some(rv)) then 4 +//│ ║ ^ +//│ ╟── But there is already a consequent term +//│ ║ l.22: Right(None) then 2 +//│ ╙── ^ +//│ fun w1: (Left[anything] | Right[anything], anything, anything,) -> (1 | 2) + +// FIXME +fun w2(x, p) = + if x is + Some then 1 + _ and p(x) then 2 + None then 3 +//│ ╔══[ERROR] The case when this is false is not handled: p (x,) +//│ ║ l.47: _ and p(x) then 2 +//│ ╙── ^^^^ +//│ fun w2: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared From 14344e6eff3e600b66d08584d296e686b073f6bb Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:17:07 +0800 Subject: [PATCH 208/498] Support wildcard followed by clauses by copying existing wildcard --- .../main/scala/mlscript/ucs/MutCaseOf.scala | 76 +++++++++++++++++-- shared/src/test/diff/ucs/Wildcard.mls | 8 +- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index bcd068dad5..e9550fb912 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -22,8 +22,14 @@ sealed abstract class MutCaseOf extends WithBindings { } } + def duplicate(): MutCaseOf + + def fill(subTree: MutCaseOf): Unit + def describe: Str + def isComplete: Bool + def tryMerge (branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, exhaustivenessMap: ExhaustivenessMap): Unit = @@ -98,6 +104,8 @@ object MutCaseOf { sealed abstract class MutCase { var consequent: MutCaseOf + def duplicate(): MutCase + def matches(expected: Var): Bool def matches(expected: Str): Bool def matches(expected: Lit): Bool @@ -123,7 +131,7 @@ object MutCaseOf { locations ++= locOpt this } - def withLocations(locs: Ls[Loc]): MutCase = { + def withLocations(locs: IterableOnce[Loc]): MutCase = { locations ++= locs this } @@ -134,6 +142,8 @@ object MutCaseOf { val literal: SimpleTerm, var consequent: MutCaseOf, ) extends MutCase { + override def duplicate(): MutCase = + Literal(literal, consequent.duplicate()).withLocations(locations) override def matches(expected: Var): Bool = literal match { case tof @ Var(n) if n === "true" || n === "false" => expected === tof case _ => false @@ -152,6 +162,9 @@ object MutCaseOf { val patternFields: Var -> Buffer[Str -> Var], var consequent: MutCaseOf, ) extends MutCase { + override def duplicate(): MutCase = + Constructor(patternFields.copy(_2 = patternFields._2.clone()), consequent.duplicate()) + .withLocations(locations) override def matches(expected: Var): Bool = matches(expected.name) override def matches(expected: Str): Bool = patternFields._1.name === expected override def matches(expected: Lit): Bool = false @@ -167,6 +180,20 @@ object MutCaseOf { def describe: Str = s"IfThenElse($condition, whenTrue = ${whenTrue.kind}, whenFalse = ${whenFalse.kind})" + def duplicate(): MutCaseOf = + IfThenElse(condition, whenTrue.duplicate(), whenFalse.duplicate()) + .withBindings(getBindings) + + override def fill(subTree: MutCaseOf): Unit = { + whenTrue.fill(subTree) + if (whenFalse === MissingCase) + whenFalse = subTree + else + whenFalse.fill(subTree) + } + + def isComplete: Bool = whenTrue.isComplete && whenFalse.isComplete + def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, @@ -225,6 +252,18 @@ object MutCaseOf { })" } + def duplicate(): MutCaseOf = + Match(scrutinee, branches.map(_.duplicate()), wildcard.map(_.duplicate())) + .withBindings(getBindings) + + override def fill(subTree: MutCaseOf): Unit = { + branches.foreach(_.consequent.fill(subTree)) + wildcard.foreach(_.fill(subTree)) + } + + def isComplete: Bool = + branches.forall(_.consequent.isComplete) && wildcard.forall(_.isComplete) + def merge(originalBranch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, @@ -279,10 +318,19 @@ object MutCaseOf { branches.find(_.matches(className)) match { // No such pattern. We should create a new one. case N => - val newBranch = buildFirst(remainingConditions, branch._2) - newBranch.addBindings(head.bindings) - branches += MutCase.Constructor(className -> Buffer.from(fields), newBranch) - .withLocations(head.locations) + wildcard match { + case S(default) if !default.isComplete => + val subTree = default.duplicate() + subTree.fill(buildFirst(remainingConditions, branch._2)) + subTree.addBindings(head.bindings) + branches += MutCase.Constructor(className -> Buffer.from(fields), subTree) + .withLocations(head.locations) + case S | N => + val newBranch = buildFirst(remainingConditions, branch._2) + newBranch.addBindings(head.bindings) + branches += MutCase.Constructor(className -> Buffer.from(fields), newBranch) + .withLocations(head.locations) + } // Found existing pattern. case S(matchCase: MutCase.Constructor) => // Merge interleaved bindings. @@ -336,6 +384,12 @@ object MutCaseOf { final case class Consequent(term: Term) extends MutCaseOf { def describe: Str = s"Consequent($term)" + override def fill(subTree: MutCaseOf): Unit = () + + override def duplicate(): MutCaseOf = Consequent(term).withBindings(getBindings) + + def isComplete: Bool = true + def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, @@ -365,6 +419,12 @@ object MutCaseOf { final case object MissingCase extends MutCaseOf { def describe: Str = "MissingCase" + override def duplicate() = MissingCase + + override def fill(subTree: MutCaseOf): Unit = () + + def isComplete: Bool = false + def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, @@ -389,7 +449,7 @@ object MutCaseOf { val consequentTree = rec(Conjunction(tail, trailingBindings)) (head match { case MatchLiteral(scrutinee, literal) => - val branches = Buffer( + val branches = Buffer[MutCase]( MutCase.Literal(literal, consequentTree.withBindings(afterHeadBindings)).withLocation(literal.toLoc) ) Match(scrutinee, branches, N) @@ -399,13 +459,13 @@ object MutCaseOf { .withBindings(beforeHeadBindings) .withBindings(afterHeadBindings) case MatchClass(scrutinee, className, fields) => - val branches = Buffer( + val branches = Buffer[MutCase]( MutCase.Constructor(className -> Buffer.from(fields), consequentTree.withBindings(afterHeadBindings)) .withLocations(head.locations) ) Match(scrutinee, branches, N).withBindings(beforeHeadBindings) case MatchTuple(scrutinee, arity, fields) => - val branches = Buffer( + val branches = Buffer[MutCase]( MutCase.Constructor(Var(s"Tuple#$arity") -> Buffer.from(fields), consequentTree.withBindings(afterHeadBindings)) .withLocations(head.locations) ) diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index 12f42cb69f..ec4ab09cb1 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -46,9 +46,5 @@ fun w2(x, p) = Some then 1 _ and p(x) then 2 None then 3 -//│ ╔══[ERROR] The case when this is false is not handled: p (x,) -//│ ║ l.47: _ and p(x) then 2 -//│ ╙── ^^^^ -//│ fun w2: (anything, anything,) -> error -//│ Code generation encountered an error: -//│ if expression was not desugared + _ then 4 +//│ fun w2: forall 'a. (None | Some[anything] | 'a & ~#None & ~#Some, (None | 'a) -> anything,) -> (1 | 2 | 3 | 4) From 9997ddf0985421cd5041bc9e5a1323f1fc4f141b Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:25:23 +0800 Subject: [PATCH 209/498] Fix making module names (e.g. `None`) as positional binding names --- .../main/scala/mlscript/ucs/Desugarer.scala | 3 +- shared/src/test/diff/nu/BadUCS.mls | 8 --- shared/src/test/diff/nu/FilterMap.mls | 2 +- shared/src/test/diff/ucs/Wildcard.mls | 54 +++++++++++-------- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index cf1e9953c0..1a4848a32c 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -68,7 +68,8 @@ class Desugarer extends TypeDefs { self: Typer => // `x is A(_)`: ignore this binding case (Var("_"), _) => N // `x is A(value)`: generate bindings directly - case (nameVar: Var, fieldName) => S(fieldName -> nameVar) + case (nameVar @ Var(n), fieldName) if (n.headOption.exists(_.isLower)) => + S(fieldName -> nameVar) // `x is B(A(x))`: generate a temporary name // use the name in the binding, and destruct sub-patterns case (pattern: Term, fieldName) => diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index cfc770d84b..7c34104d7a 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -112,17 +112,9 @@ class Cons[out A](head: A, tail: Cons[A] | Nil) //│ module Nil() //│ class Cons[A](head: A, tail: Cons[A] | Nil) -:w fun join(xs) = if xs is Nil then "" Cons(x, Nil) then toString(x) Cons(x, xs') then concat(toString(x))(concat(", ")(join(xs'))) -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit -//│ ║ l.120: Cons(x, xs') then concat(toString(x))(concat(", ")(join(xs'))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── But there is already a consequent term -//│ ║ l.119: Cons(x, Nil) then toString(x) -//│ ╙── ^^^^^^^^^^^ //│ fun join: (Cons[anything] | Nil) -> string diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 1cde1664e2..916cfcdd35 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -49,7 +49,7 @@ fun filtermap(f, xs) = if xs is True then filtermap(f, ys) False then Cons(y, filtermap(f, ys)) Pair(True, z) then Cons(z, filtermap(f, ys)) -//│ fun filtermap: forall 'head 'A. ('head -> (False | Pair[anything, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) +//│ fun filtermap: forall 'head 'A. ('head -> (False | Pair[True, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) fun mkString(xs) = if xs is diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index ec4ab09cb1..9a35985928 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -15,32 +15,30 @@ class Right[B](rightValue: B) //│ class Left[A](leftValue: A) //│ class Right[B](rightValue: B) -// FIXME fun w1(x, e_0, e_1) = if x is - Left(None) then 1 - Right(None) then 2 + Left(None) then "Left of None" + Right(None) then "Right of None" _ and e_0 is y_0 and x is - Left(Some(lv)) then 3 + Left(Some(lv)) then concat("Left of Some of ")(toString(lv)) _ and e_1 is y_1 and x is - Right(Some(rv)) then 4 -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit -//│ ║ l.24: Left(Some(lv)) then 3 -//│ ║ ^ -//│ ╟── But there is already a consequent term -//│ ║ l.21: Left(None) then 1 -//│ ╙── ^ -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit -//│ ║ l.26: Right(Some(rv)) then 4 -//│ ║ ^ -//│ ╟── But there is already a consequent term -//│ ║ l.22: Right(None) then 2 -//│ ╙── ^ -//│ fun w1: (Left[anything] | Right[anything], anything, anything,) -> (1 | 2) + Right(Some(rv)) then concat("Right of Some of ")(toString(rv)) +//│ fun w1: (Left[None | Some[anything]] | Right[None | Some[anything]], anything, anything,) -> string + +w1(Left(None), "a", "b") +w1(Right(None), "a", "b") +w1(Left(Some(0)), "a", "b") +w1(Right(Some(0)), "a", "b") +//│ string +//│ res +//│ = 'Left of None' +//│ res +//│ = 'Right of None' +//│ res +//│ = 'Left of Some of 0' +//│ res +//│ = 'Right of Some of 0' -// FIXME fun w2(x, p) = if x is Some then 1 @@ -48,3 +46,17 @@ fun w2(x, p) = None then 3 _ then 4 //│ fun w2: forall 'a. (None | Some[anything] | 'a & ~#None & ~#Some, (None | 'a) -> anything,) -> (1 | 2 | 3 | 4) + +w2(Some(0), x => true) +w2(None, x => true) +w2(None, x => false) +w2(0, x => false) +//│ 1 | 2 | 3 | 4 +//│ res +//│ = 1 +//│ res +//│ = 2 +//│ res +//│ = 3 +//│ res +//│ = 4 From f5ba54025dec238d59184bcef5ae2618db8fce63 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:28:14 +0800 Subject: [PATCH 210/498] Use the new definition typing on `SplitAroundOp.mls` --- shared/src/test/diff/ucs/SplitAroundOp.mls | 282 ++------------------- 1 file changed, 17 insertions(+), 265 deletions(-) diff --git a/shared/src/test/diff/ucs/SplitAroundOp.mls b/shared/src/test/diff/ucs/SplitAroundOp.mls index dfd03d5db2..86dfebdc77 100644 --- a/shared/src/test/diff/ucs/SplitAroundOp.mls +++ b/shared/src/test/diff/ucs/SplitAroundOp.mls @@ -1,299 +1,51 @@ :NewParser +:NewDefs -// Why? Can the type of `x` be `number | string`? -:e fun f(x, b) = if x - == + === 0 and b then "n0" 1 and b then "n1" 2 then "n2" - == + === "0" then "s0" "1" then "s1" "2" then "s2" else ":p" -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"0"` is not an instance of type `number` -//│ ║ l.12: "0" then "s0" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"1"` is not an instance of type `number` -//│ ║ l.13: "1" then "s1" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.14: "2" then "s2" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"2"` is not an instance of type `number` -//│ ║ l.14: "2" then "s2" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"0"` is not an instance of type `number` -//│ ║ l.12: "0" then "s0" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"1"` is not an instance of type `number` -//│ ║ l.13: "1" then "s1" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.14: "2" then "s2" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"2"` is not an instance of type `number` -//│ ║ l.14: "2" then "s2" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"0"` is not an instance of type `number` -//│ ║ l.12: "0" then "s0" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"1"` is not an instance of type `number` -//│ ║ l.13: "1" then "s1" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.14: "2" then "s2" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"2"` is not an instance of type `number` -//│ ║ l.14: "2" then "s2" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"0"` is not an instance of type `number` -//│ ║ l.12: "0" then "s0" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"1"` is not an instance of type `number` -//│ ║ l.13: "1" then "s1" -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.6: if x -//│ ║ ^ -//│ ║ l.7: == -//│ ║ ^^^^^^ -//│ ║ l.8: 0 and b then "n0" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.9: 1 and b then "n1" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.10: 2 then "n2" -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.11: == -//│ ║ ^^^^^^ -//│ ║ l.12: "0" then "s0" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.13: "1" then "s1" -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.14: "2" then "s2" -//│ ║ ^^^^^^^^^ -//│ ╟── string literal of type `"2"` is not an instance of type `number` -//│ ║ l.14: "2" then "s2" -//│ ╙── ^^^ -//│ f: (number, anything,) -> (":p" | "n0" | "n1" | "n2" | "s0" | "s1" | "s2") -//│ = [Function: f] +//│ fun f: (Eql["0" | "1" | "2" | 0 | 1 | 2], anything,) -> (":p" | "n0" | "n1" | "n2" | "s0" | "s1" | "s2") fun f(x, y, a, b) = - if x == 0 + if x === 0 and - y == 0 then "x, y" - a == 0 then "x, a" - b == 0 then "x, b" + y === 0 then "x, y" + a === 0 then "x, a" + b === 0 then "x, b" else "nah" -//│ f: (number, number, number, number,) -> ("nah" | "x, a" | "x, b" | "x, y") -//│ = [Function: f1] +//│ fun f: (Eql[0], Eql[0], Eql[0], Eql[0],) -> ("nah" | "x, a" | "x, b" | "x, y") class A() class B() -//│ Defined class A -//│ Defined class B -//│ A: () -> A -//│ = [Function: A1] -//│ B: () -> B -//│ = [Function: B1] +//│ class A() +//│ class B() fun f(x) = if x is A() then 0 B() then 1 -//│ f: (A | B) -> (0 | 1) -//│ = [Function: f2] +//│ fun f: (A | B) -> (0 | 1) // It fails because we interpret == as a constructor. :e :ge if x is A() - == 0 then 0 + === 0 then 0 > 0 then 1 < 0 then 2 -//│ ╔══[ERROR] Cannot find operator `==` in the context -//│ ║ l.291: == 0 then 0 -//│ ╙── ^^ -//│ res: error +//│ ╔══[ERROR] Cannot find operator `===` in the context +//│ ║ l.43: === 0 then 0 +//│ ╙── ^^^ +//│ error //│ Code generation encountered an error: //│ if expression was not desugared From f036769ea28bf83aa4b0ba5e72c44d8849f35698 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:33:32 +0800 Subject: [PATCH 211/498] Add an interesting case in `LitUCS.mls`. --- shared/src/test/diff/ucs/LitUCS.mls | 42 +++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/shared/src/test/diff/ucs/LitUCS.mls b/shared/src/test/diff/ucs/LitUCS.mls index a9fd1c900a..e92d2fc7d6 100644 --- a/shared/src/test/diff/ucs/LitUCS.mls +++ b/shared/src/test/diff/ucs/LitUCS.mls @@ -1,6 +1,5 @@ :NewDefs - module A //│ module A() @@ -12,19 +11,11 @@ fun test(x: 0 | A) = if x is //│ fun test: (x: 0 | A,) -> (0 | A) // FIXME +// case === (x,) (0,) of { true => 0; _ => case x of { A => A } } fun test(x: 0 | A) = if - x == 0 then 0 + x === 0 then 0 x is A then A -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.17: x == 0 then 0 -//│ ║ ^^^^ -//│ ╟── type `A` is not an instance of type `number` -//│ ║ l.15: fun test(x: 0 | A) = -//│ ║ ^ -//│ ╟── but it flows into reference with expected type `number` -//│ ║ l.17: x == 0 then 0 -//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.18: x is A then A //│ ║ ^^^^^^^^^^^^^ @@ -38,3 +29,32 @@ fun test(x: 0 | A) = //│ ║ l.18: x is A then A //│ ╙── ^ //│ fun test: (x: 0 | A,) -> (0 | A) + +fun test2(x) = + if + x === 0 then 0 + x is A then A +//│ fun test2: (A & Eql[0]) -> (0 | A) + +// FIXME +test2(0) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.40: test2(0) +//│ ║ ^^^^^^^^ +//│ ╟── integer literal of type `0` is not an instance of type `A` +//│ ║ l.40: test2(0) +//│ ║ ^ +//│ ╟── Note: constraint arises from class pattern: +//│ ║ l.36: x is A then A +//│ ║ ^ +//│ ╟── from reference: +//│ ║ l.36: x is A then A +//│ ╙── ^ +//│ 0 | A | error +//│ res +//│ = 0 + +test2(A) +//│ 0 | A +//│ res +//│ = A { class: [class A] } From d972ee30385523a1934d11b49f5915a2ac984e44 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:40:18 +0800 Subject: [PATCH 212/498] Add an interleaved let example revealing a code generation problem --- shared/src/test/diff/ucs/InterleavedLet.mls | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index 070b1cd253..bbbda293b3 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -295,3 +295,48 @@ mapPartition2(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) //│ fst: Cons { head: 0, tail: Cons { head: 0, tail: [Cons] } }, //│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } //│ } + +fun log(x) = () +//│ log: anything -> () +//│ = [Function: log] + +// FIXME: Code generation problem... +:js +fun mn(a) = + if a is + Some(x) and x is + Left(b) and b is + 0 then "b is 1" + let _ = log(b) + 1 then "b is 2" + 2 then "b is 3" + Right(b) then "right-defined" + None then "undefined" +mn(None()) +//│ // Query 1 +//│ globalThis.mn = function mn(a) { +//│ return ((() => { +//│ let a; +//│ return (a = a, a instanceof Some ? ((x) => { +//│ let a; +//│ return (a = x, a instanceof Left ? ((b) => ((_) => { +//│ let a; +//│ return (a = b, a === 0 ? "b is 1" : a === 1 ? "b is 2" : a === 2 ? "b is 3" : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })(log(b)))(x.leftValue) : a instanceof Right ? ((b) => "right-defined")(x.rightValue) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })(a.value) : a instanceof None ? "undefined" : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })()); +//│ }; +//│ // Query 2 +//│ res = mn(None1()); +//│ // End of generated code +//│ mn: (None | Some & {value: Left & {leftValue: 0 | 1 | 2} | Right}) -> ("b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined") +//│ = [Function: mn] +//│ res: "b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined" +//│ Runtime error: +//│ Error: non-exhaustive case expression From a2a5180e1c91f91c93fe958409bf93f32d699281 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:47:23 +0800 Subject: [PATCH 213/498] Improve the warning message for duplicated branches --- .../main/scala/mlscript/ucs/MutCaseOf.scala | 6 ++--- shared/src/test/diff/ucs/Humiliation.mls | 6 ++--- shared/src/test/diff/ucs/InterleavedLet.mls | 6 ++--- shared/src/test/diff/ucs/TrivialIf.mls | 6 ++--- shared/src/test/diff/ucs/WeirdIf.mls | 24 +++++++++---------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index e9550fb912..c3ae6bc90b 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -397,8 +397,8 @@ object MutCaseOf { raise { import scala.collection.mutable.ListBuffer val buffer = ListBuffer.empty[Message -> Opt[Loc]] - buffer += Message.fromStr("Found duplicated branch") -> N - buffer += Message.fromStr("This decision path tries to fit") -> { + buffer += Message.fromStr("Found a duplicated branch") -> N + buffer += Message.fromStr("This branch") -> { val (Conjunction(clauses, _) -> consequent) = branch consequent.toLoc // TODO: Make a complete location. @@ -407,7 +407,7 @@ object MutCaseOf { // case Nil => consequent.toLoc // } } - buffer += Message.fromStr("But there is already a consequent term") -> term.toLoc + buffer += Message.fromStr("is subsumed by the branch here.") -> term.toLoc WarningReport(buffer.toList) } diff --git a/shared/src/test/diff/ucs/Humiliation.mls b/shared/src/test/diff/ucs/Humiliation.mls index 39ab377994..6485e0de6b 100644 --- a/shared/src/test/diff/ucs/Humiliation.mls +++ b/shared/src/test/diff/ucs/Humiliation.mls @@ -19,11 +19,11 @@ fun test(x) = if x is 1 then 0 else 1 fun testF(x) = if x is Foo(a) then a Foo(a) then a -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch //│ ║ l.21: Foo(a) then a //│ ║ ^ -//│ ╟── But there is already a consequent term +//│ ╟── is subsumed by the branch here. //│ ║ l.20: Foo(a) then a //│ ╙── ^ //│ testF: (Foo & {x: 'x}) -> 'x diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index bbbda293b3..cdfc459c44 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -46,11 +46,11 @@ fun p(x, y) = x is Some and y is None then 0 y is Some and x is Some then 1 x is Some and y is Some then 0 -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch //│ ║ l.48: x is Some and y is Some then 0 //│ ║ ^ -//│ ╟── But there is already a consequent term +//│ ╟── is subsumed by the branch here. //│ ║ l.47: y is Some and x is Some then 1 //│ ╙── ^ //│ p: (Some, None | Some,) -> (0 | 1) diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index af0837fe75..946c68be1b 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -64,11 +64,11 @@ if 42 is n then n + 1 // FIXME if 42 is n then n + 1 else 0 -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch //│ ║ l.66: if 42 is n then n + 1 else 0 //│ ║ ^ -//│ ╟── But there is already a consequent term +//│ ╟── is subsumed by the branch here. //│ ║ l.66: if 42 is n then n + 1 else 0 //│ ╙── ^^^^^ //│ res: int diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index 6a8e996421..5cbae091a0 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -6,18 +6,18 @@ if _ then 0 else 0 else 1 -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch //│ ║ l.7: else 0 //│ ║ ^ -//│ ╟── But there is already a consequent term +//│ ╟── is subsumed by the branch here. //│ ║ l.6: _ then 0 //│ ╙── ^ -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch //│ ║ l.8: else 1 //│ ║ ^ -//│ ╟── But there is already a consequent term +//│ ╟── is subsumed by the branch here. //│ ║ l.6: _ then 0 //│ ╙── ^ //│ res: 0 @@ -25,11 +25,11 @@ else 1 :w if else 0 else 1 -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch //│ ║ l.27: if else 0 else 1 //│ ║ ^ -//│ ╟── But there is already a consequent term +//│ ╟── is subsumed by the branch here. //│ ║ l.27: if else 0 else 1 //│ ╙── ^ //│ res: 0 @@ -37,11 +37,11 @@ if else 0 else 1 :w fun f(x) = if x is else 0 else 1 -//│ ╔══[WARNING] Found duplicated branch -//│ ╟── This decision path tries to fit +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch //│ ║ l.39: fun f(x) = if x is else 0 else 1 //│ ║ ^ -//│ ╟── But there is already a consequent term +//│ ╟── is subsumed by the branch here. //│ ║ l.39: fun f(x) = if x is else 0 else 1 //│ ╙── ^ //│ f: anything -> 0 From 15d0c5739df3ce3d207c321c52d47b050b970d6b Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:51:39 +0800 Subject: [PATCH 214/498] Fix all warnings --- .../src/main/scala/mlscript/ucs/MutCaseOf.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index c3ae6bc90b..2ed7ebf0ce 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -201,7 +201,7 @@ object MutCaseOf { branch match { // The CC is a wildcard. So, we call `mergeDefault`. case Conjunction(Nil, trailingBindings) -> term => - if (mergeDefault(trailingBindings, term) == 0) { + if (mergeDefault(trailingBindings, term) === 0) { import Message.MessageContext raise(WarningReport( msg"Found a redundant else branch" -> term.toLoc :: Nil @@ -287,7 +287,7 @@ object MutCaseOf { val tupleClassName = Var(s"Tuple#$arity") // TODO: Find a name known by Typer. branches.find(_.matches(tupleClassName)) match { // No such pattern. We should create a new one. - case N => + case N | S(MutCase.Literal(_, _)) => val newBranch = buildFirst(Conjunction(tail, trailingBindings), term) newBranch.addBindings(head.bindings) branches += MutCase.Constructor(tupleClassName -> Buffer.from(fields), newBranch) @@ -300,7 +300,12 @@ object MutCaseOf { } // A wild card case. We should propagate wildcard to every default positions. case Conjunction(Nil, trailingBindings) -> term => - mergeDefault(trailingBindings, term) // TODO: Handle the int result here. + if (mergeDefault(trailingBindings, term) === 0) { + import Message.MessageContext + raise(WarningReport( + msg"Found a redundant else branch" -> term.toLoc :: Nil + )) + } // The conditions to be inserted does not overlap with me. case conjunction -> term => branches.foreach { @@ -317,7 +322,7 @@ object MutCaseOf { case S((head @ MatchClass(_, className, fields)) -> remainingConditions) => branches.find(_.matches(className)) match { // No such pattern. We should create a new one. - case N => + case N | S(MutCase.Literal(_, _)) => wildcard match { case S(default) if !default.isComplete => val subTree = default.duplicate() @@ -344,7 +349,7 @@ object MutCaseOf { case l: Lit => branch.matches(l) }) match { // No such pattern. We should create a new one. - case N => + case N | S(MutCase.Constructor(_, _)) => val newConsequent = buildFirst(remainingConditions, branch._2) newConsequent.addBindings(head.bindings) branches += MutCase.Literal(literal, newConsequent) From 24c438636fc3f377077038a95e00cddd648f8a69 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 17 Mar 2023 23:56:27 +0800 Subject: [PATCH 215/498] Fix warnings and make CI happy :-P --- js/src/main/scala/Main.scala | 2 +- shared/src/main/scala/mlscript/ucs/Desugarer.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index 06676fe6cb..e761fcafb9 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -133,7 +133,7 @@ object Main { implicit val extrCtx: Opt[typer.ExtrCtx] = N val vars: Map[Str, typer.SimpleType] = Map.empty - val tpd = typer.typeTypingUnit(tu, allowPure = true)(ctx.nest, raise, vars) + val tpd = typer.typeTypingUnit(tu)(ctx.nest, raise, vars) object SimplifyPipeline extends typer.SimplifyPipeline { def debugOutput(msg: => Str): Unit = diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 1a4848a32c..feda393f21 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -421,7 +421,7 @@ class Desugarer extends TypeDefs { self: Typer => body: IfBody \/ Statement, partialPattern: PartialTerm, collectedConditions: Conjunction, - )(implicit interleavedLets: Buffer[LetBinding]): Unit = traceUCS("[desugarMatchBranch]") { + )(implicit interleavedLets: Buffer[LetBinding]): Unit = traceUCS[Unit]("[desugarMatchBranch]") { body match { // This case handles default branches. For example, // if x is @@ -528,7 +528,7 @@ class Desugarer extends TypeDefs { self: Typer => def desugarIfBody (body: IfBody, expr: PartialTerm, acc: Conjunction) (implicit interleavedLets: Buffer[LetBinding]) - : Unit = traceUCS("[desugarIfBody]") { + : Unit = traceUCS[Unit]("[desugarIfBody]") { body match { case IfOpsApp(exprPart, opsRhss) => val exprStart = expr.addTerm(exprPart) From 1bd5ee7a2e650c250cb920864c11bc307ced80f1 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 18 Mar 2023 01:07:49 +0800 Subject: [PATCH 216/498] Mark expected errors and warnings --- shared/src/test/diff/ucs/InterleavedLet.mls | 9 ++++----- shared/src/test/diff/ucs/LitUCS.mls | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index cdfc459c44..786029f9ea 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -39,7 +39,6 @@ fun q(x) = //│ q: Some -> 0 //│ = [Function: q] -// FIXME :w fun p(x, y) = if @@ -48,10 +47,10 @@ fun p(x, y) = x is Some and y is Some then 0 //│ ╔══[WARNING] Found a duplicated branch //│ ╟── This branch -//│ ║ l.48: x is Some and y is Some then 0 +//│ ║ l.47: x is Some and y is Some then 0 //│ ║ ^ //│ ╟── is subsumed by the branch here. -//│ ║ l.47: y is Some and x is Some then 1 +//│ ║ l.46: y is Some and x is Some then 1 //│ ╙── ^ //│ p: (Some, None | Some,) -> (0 | 1) //│ = [Function: p] @@ -93,9 +92,9 @@ fun q(a) = let y = a + 1 then y //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.93: let y = a + 1 +//│ ║ l.92: let y = a + 1 //│ ║ ^^^^^ -//│ ║ l.94: then y +//│ ║ l.93: then y //│ ╙── ^^^^^^^^^^ //│ q: (Left & {leftValue: 'leftValue}) -> 'leftValue //│ = [Function: q1] diff --git a/shared/src/test/diff/ucs/LitUCS.mls b/shared/src/test/diff/ucs/LitUCS.mls index e92d2fc7d6..ea76bb8481 100644 --- a/shared/src/test/diff/ucs/LitUCS.mls +++ b/shared/src/test/diff/ucs/LitUCS.mls @@ -10,7 +10,7 @@ fun test(x: 0 | A) = if x is A then A //│ fun test: (x: 0 | A,) -> (0 | A) -// FIXME +:e // case === (x,) (0,) of { true => 0; _ => case x of { A => A } } fun test(x: 0 | A) = if @@ -36,7 +36,7 @@ fun test2(x) = x is A then A //│ fun test2: (A & Eql[0]) -> (0 | A) -// FIXME +:e test2(0) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.40: test2(0) From 572e61871abbbb5c975b2c0c01685995e21aaa6b Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 18 Mar 2023 01:10:00 +0800 Subject: [PATCH 217/498] Fix the parameter error in the previous CI fix --- js/src/main/scala/Main.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index e761fcafb9..89e211129a 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -133,7 +133,7 @@ object Main { implicit val extrCtx: Opt[typer.ExtrCtx] = N val vars: Map[Str, typer.SimpleType] = Map.empty - val tpd = typer.typeTypingUnit(tu)(ctx.nest, raise, vars) + val tpd = typer.typeTypingUnit(tu, topLevel = true)(ctx.nest, raise, vars) object SimplifyPipeline extends typer.SimplifyPipeline { def debugOutput(msg: => Str): Unit = From 4963caaa724a97a29239871620831e0116e784ba Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 18 Mar 2023 11:32:35 +0800 Subject: [PATCH 218/498] Remove two `FIXME` in `MultiwayIf.mls` --- shared/src/test/diff/ucs/MultiwayIf.mls | 31 ++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/shared/src/test/diff/ucs/MultiwayIf.mls b/shared/src/test/diff/ucs/MultiwayIf.mls index 086c6245d8..e7d8c01ebe 100644 --- a/shared/src/test/diff/ucs/MultiwayIf.mls +++ b/shared/src/test/diff/ucs/MultiwayIf.mls @@ -10,7 +10,6 @@ fun f(x) = //│ = [Function: f] -// FIXME fun f(x) = if x > 0 and @@ -21,7 +20,22 @@ fun f(x) = //│ f: int -> bool //│ = [Function: f1] -// FIXME +f(0) +f(2) +f(3) +f(0 - 1) +f(0 - 2) +//│ res: bool +//│ = true +//│ res: bool +//│ = true +//│ res: bool +//│ = false +//│ res: bool +//│ = false +//│ res: bool +//│ = false + fun f(x) = if x > 0 and @@ -32,4 +46,15 @@ fun f(x) = //│ f: int -> bool //│ = [Function: f2] - +f(0) +f(2) +f(1) +f(0 - 1) +//│ res: bool +//│ = true +//│ res: bool +//│ = true +//│ res: bool +//│ = false +//│ res: bool +//│ = false From 8b40fec555f6c67a56ead3274d3b3bde59e4a37e Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 18 Mar 2023 11:47:10 +0800 Subject: [PATCH 219/498] Fix temporary name generation in `JSBackend` --- .../main/scala/mlscript/codegen/Scope.scala | 11 ++- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 74 ++++++------------- shared/src/test/diff/ucs/Humiliation.mls | 12 ++- shared/src/test/diff/ucs/InterleavedLet.mls | 42 ++++------- shared/src/test/diff/ucs/SimpleUCS.mls | 5 +- 5 files changed, 54 insertions(+), 90 deletions(-) diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 1a0ae5065c..56a2895f0f 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -67,11 +67,20 @@ class Scope(name: Str, enclosing: Opt[Scope]) { i <- (1 to Int.MaxValue).iterator c <- Scope.nameAlphabet.combinations(i) name = c.mkString - if !runtimeSymbols.contains(name) + if !hasRuntimeName(name) } yield { name } + /** + * Check if a runtime name is used recursively. + * + * @param name the name + * @return whether it's available or not + */ + private def hasRuntimeName(name: Str): Bool = + runtimeSymbols.contains(name) || enclosing.exists(_.hasRuntimeName(name)) + /** * Allocate a non-sense runtime name. */ diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 8e9f462598..9d4f72dfd3 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -87,29 +87,20 @@ module TestSize extends SizeBase, SizeExt //│ where //│ 'a <: Circle | Empty | Intersect['a] | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ -// TODO investigate -:re TestSize.size(Empty()) //│ int //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = 1 -// TODO investigate -:re TestSize.size(circles) //│ int //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = 13 -// TODO investigate -:re TestSize.size(Scale(Vector(1, 1), circles)) //│ int //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = 14 // ******************* Adding a New Interpretation ******************* // a stupid power (int ** int) implementation @@ -139,29 +130,20 @@ module TestContains extends Contains //│ where //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] -// TODO investigate -:re TestContains.contains(Translate(Vector(0, 0), Circle(1)), Vector(0, 0)) //│ bool //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = true -// TODO investigate -:re TestContains.contains(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1)), Vector(0, 0)) //│ bool //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = true -// TODO investigate -:re TestContains.contains(circles, Vector(0, 0)) //│ bool //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = false // ******************* Dependencies, Complex Interpretations, and Domain-Specific Optimizations ******************* @@ -187,16 +169,16 @@ mixin Text { :e module SizeText extends Text //│ ╔══[ERROR] Module `SizeText` does not contain member `size` -//│ ║ l.180: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.162: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Module `SizeText` does not contain member `size` -//│ ║ l.179: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.161: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Module `SizeText` does not contain member `size` -//│ ║ l.178: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.160: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Module `SizeText` does not contain member `size` -//│ ║ l.177: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.159: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -379,29 +361,20 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] -// TODO investigate -:re Lang.size(circles) //│ int //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = 13 -// TODO investigate -:re Lang.contains(circles, Vector(0, 0)) //│ bool //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = false -// TODO investigate -:re Lang.text(circles) //│ string //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = 'the union of two regions of size ' Lang.isUniv(circles) //│ bool @@ -413,13 +386,10 @@ Lang.isEmpty(circles) //│ res //│ = false -// TODO investigate -:re Lang.size(Lang.eliminate(circles)) //│ int //│ res -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = 13 :re Lang.size(mk(100)) @@ -432,16 +402,16 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.433: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.403: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.346: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.328: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.433: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.403: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.123: if a is +//│ ║ l.114: if a is //│ ╙── ^ //│ error | bool //│ res @@ -452,16 +422,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.453: Lang.text(mk(100)) +//│ ║ l.423: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.346: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.328: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.453: Lang.text(mk(100)) +//│ ║ l.423: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.175: if e is +//│ ║ l.157: if e is //│ ╙── ^ //│ error | string //│ res diff --git a/shared/src/test/diff/ucs/Humiliation.mls b/shared/src/test/diff/ucs/Humiliation.mls index 6485e0de6b..c650b48040 100644 --- a/shared/src/test/diff/ucs/Humiliation.mls +++ b/shared/src/test/diff/ucs/Humiliation.mls @@ -151,11 +151,9 @@ fun foo(x) = if x is //│ foo: (Pair & {fst: O | Z, snd: S & {pred: 'pred} | ~S}) -> ("???" | "zeros" | 'pred) //│ = [Function: foo5] -:re foo(Pair(Z(), Z())) //│ res: "???" | "zeros" -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = '???' :e :ge @@ -164,14 +162,14 @@ fun foo(x) = if x is Pair(O(), O()) then "ones" Pair(y, O()) then x //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.162: fun foo(x) = if x is +//│ ║ l.160: fun foo(x) = if x is //│ ║ ^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.163: Pair(Z(), Z()) then "zeros" +//│ ║ l.161: Pair(Z(), Z()) then "zeros" //│ ║ ^^^ //│ ╟── [Missing Case 1/1] `Z` //│ ╟── It first appears here. -//│ ║ l.163: Pair(Z(), Z()) then "zeros" +//│ ║ l.161: Pair(Z(), Z()) then "zeros" //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: @@ -185,7 +183,7 @@ fun foo(x, y) = if x is Z() and y is O() then 0 else 1 fun foo(x, y) = if x is Z() and y is O() then 0 else 1 //│ ╔══[PARSE ERROR] Unexpected 'else' keyword here -//│ ║ l.186: Z() and y is O() then 0 else 1 +//│ ║ l.184: Z() and y is O() then 0 else 1 //│ ╙── ^^^^ //│ foo: (Z, O,) -> 0 //│ = [Function: foo8] diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index 786029f9ea..a8b4c2d669 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -299,8 +299,6 @@ fun log(x) = () //│ log: anything -> () //│ = [Function: log] -// FIXME: Code generation problem... -:js fun mn(a) = if a is Some(x) and x is @@ -311,31 +309,21 @@ fun mn(a) = 2 then "b is 3" Right(b) then "right-defined" None then "undefined" -mn(None()) -//│ // Query 1 -//│ globalThis.mn = function mn(a) { -//│ return ((() => { -//│ let a; -//│ return (a = a, a instanceof Some ? ((x) => { -//│ let a; -//│ return (a = x, a instanceof Left ? ((b) => ((_) => { -//│ let a; -//│ return (a = b, a === 0 ? "b is 1" : a === 1 ? "b is 2" : a === 2 ? "b is 3" : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })(log(b)))(x.leftValue) : a instanceof Right ? ((b) => "right-defined")(x.rightValue) : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })(a.value) : a instanceof None ? "undefined" : (() => { -//│ throw new Error("non-exhaustive case expression"); -//│ })()); -//│ })()); -//│ }; -//│ // Query 2 -//│ res = mn(None1()); -//│ // End of generated code //│ mn: (None | Some & {value: Left & {leftValue: 0 | 1 | 2} | Right}) -> ("b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined") //│ = [Function: mn] + +mn(None()) +mn(Some(Left(0))) +mn(Some(Left(1))) +mn(Some(Left(2))) +mn(Some(Right(()))) +//│ res: "b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined" +//│ = 'undefined' +//│ res: "b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined" +//│ = 'b is 1' +//│ res: "b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined" +//│ = 'b is 2' +//│ res: "b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined" +//│ = 'b is 3' //│ res: "b is 1" | "b is 2" | "b is 3" | "right-defined" | "undefined" -//│ Runtime error: -//│ Error: non-exhaustive case expression +//│ = 'right-defined' diff --git a/shared/src/test/diff/ucs/SimpleUCS.mls b/shared/src/test/diff/ucs/SimpleUCS.mls index 929d3111e4..541e5fdc39 100644 --- a/shared/src/test/diff/ucs/SimpleUCS.mls +++ b/shared/src/test/diff/ucs/SimpleUCS.mls @@ -297,7 +297,6 @@ fun g(a, b) = //│ g: (int, None | Some & {value: int},) -> int //│ = [Function: g1] -// TODO: Fix the NaN. g(5, None()) g(5, Some(7)) g(0 - 5, None()) @@ -307,7 +306,7 @@ g(0 - 5, Some(9)) //│ res: int //│ = 35 //│ res: int -//│ = NaN +//│ = 25 //│ res: int //│ = 4 @@ -355,7 +354,7 @@ fun f(x) = 0 :: Nil() then "oh" //│ ╔══[ERROR] Cannot find operator `::` in the context -//│ ║ l.355: 0 :: +//│ ║ l.354: 0 :: //│ ╙── ^^ //│ f: anything -> error //│ Code generation encountered an error: From 9eb14bdabd8d783602eb113cb2f053b5ae9f4adf Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 18 Mar 2023 12:55:17 +0800 Subject: [PATCH 220/498] Always check the exhaustiveness of the outer if-then-else first --- .../main/scala/mlscript/ucs/Desugarer.scala | 2 +- shared/src/test/diff/ucs/SplitAfterOp.mls | 70 ++++++++++--------- shared/src/test/diff/ucs/SplitOps.mls | 9 +-- shared/src/test/diff/ucs/TrivialIf.mls | 4 +- 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index feda393f21..79d40420fb 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -670,8 +670,8 @@ class Desugarer extends TypeDefs { self: Typer => case S(Consequent(_)) | S(MissingCase) | N => die // unreachable } case IfThenElse(condition, whenTrue, whenFalse) => - checkExhaustive(whenTrue, S(t)) checkExhaustive(whenFalse, S(t)) + checkExhaustive(whenTrue, S(t)) case Match(scrutinee, branches, default) => scrutineePatternMap.get(getScurtineeKey(scrutinee)) match { case N => lastWords(s"unreachable case: unknown scrutinee ${scrutinee.term}") diff --git a/shared/src/test/diff/ucs/SplitAfterOp.mls b/shared/src/test/diff/ucs/SplitAfterOp.mls index b8d8df041e..3f0a234740 100644 --- a/shared/src/test/diff/ucs/SplitAfterOp.mls +++ b/shared/src/test/diff/ucs/SplitAfterOp.mls @@ -5,9 +5,11 @@ fun f(x, b) = if x == 0 and b then 0 -//│ ╔══[ERROR] The case when this is false is not handled: b +//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) +//│ ║ l.6: if x == +//│ ║ ^^^^^ //│ ║ l.7: 0 and b then 0 -//│ ╙── ^ +//│ ╙── ^^^^^^ //│ f: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared @@ -18,11 +20,11 @@ if x == y + 5 then 0 7 then 0 //│ ╔══[ERROR] The case when this is false is not handled: + (== (x,) (y,),) (7,) -//│ ║ l.17: if x == y + +//│ ║ l.19: if x == y + //│ ║ ^^^^^^^^ -//│ ║ l.18: 5 then 0 +//│ ║ l.20: 5 then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.19: 7 then 0 +//│ ║ l.21: 7 then 0 //│ ╙── ^^^^ //│ res: error //│ Code generation encountered an error: @@ -34,11 +36,11 @@ if x == y * 5 then 0 6 + 7 then 0 //│ ╔══[ERROR] The case when this is false is not handled: * (== (x,) (y,),) (+ (6,) (7,),) -//│ ║ l.33: if x == y * +//│ ║ l.35: if x == y * //│ ║ ^^^^^^^^ -//│ ║ l.34: 5 then 0 +//│ ║ l.36: 5 then 0 //│ ║ ^^^^^^^^^^ -//│ ║ l.35: 6 + 7 then 0 +//│ ║ l.37: 6 + 7 then 0 //│ ╙── ^^^^^^^ //│ res: error //│ Code generation encountered an error: @@ -51,13 +53,13 @@ if x == 5 then 0 7 then 0 //│ ╔══[ERROR] The case when this is false is not handled: + (== (x,) (y,),) (7,) -//│ ║ l.49: if x == +//│ ║ l.51: if x == //│ ║ ^^^^ -//│ ║ l.50: y + +//│ ║ l.52: y + //│ ║ ^^^^^ -//│ ║ l.51: 5 then 0 +//│ ║ l.53: 5 then 0 //│ ║ ^^^^^^^^^^^^ -//│ ║ l.52: 7 then 0 +//│ ║ l.54: 7 then 0 //│ ╙── ^^^^^ //│ res: error //│ Code generation encountered an error: @@ -67,9 +69,11 @@ if x == :ge if x == 1 and b then 0 -//│ ╔══[ERROR] The case when this is false is not handled: b -//│ ║ l.69: 1 and b then 0 -//│ ╙── ^ +//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (1,) +//│ ║ l.70: if x == +//│ ║ ^^^^ +//│ ║ l.71: 1 and b then 0 +//│ ╙── ^^^^ //│ res: error //│ Code generation encountered an error: //│ if expression was not desugared @@ -82,11 +86,11 @@ fun toEnglish(x) = true then "t" 0 then "z" //│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) -//│ ║ l.81: if x == +//│ ║ l.85: if x == //│ ║ ^^^^ -//│ ║ l.82: true then "t" +//│ ║ l.86: true then "t" //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.83: 0 then "z" +//│ ║ l.87: 0 then "z" //│ ╙── ^^^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: @@ -99,11 +103,11 @@ fun toEnglish(x) = 0 then "z" true then "t" //│ ╔══[ERROR] The case when this is false is not handled: == (x,) (true,) -//│ ║ l.98: if x == -//│ ║ ^^^^ -//│ ║ l.99: 0 then "z" -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.100: true then "t" +//│ ║ l.102: if x == +//│ ║ ^^^^ +//│ ║ l.103: 0 then "z" +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.104: true then "t" //│ ╙── ^^^^^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: @@ -116,11 +120,11 @@ fun toEnglish(x) = 1 then "o" 0 then "z" //│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) -//│ ║ l.115: if x == +//│ ║ l.119: if x == //│ ║ ^^^^ -//│ ║ l.116: 1 then "o" +//│ ║ l.120: 1 then "o" //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.117: 0 then "z" +//│ ║ l.121: 0 then "z" //│ ╙── ^^^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: @@ -140,23 +144,23 @@ fun toEnglish(x) = if x == else 1 //│ ╔══[PARSE ERROR] Unexpected indented block in expression position -//│ ║ l.141: else 1 +//│ ║ l.145: else 1 //│ ╙── ^^^^ //│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here -//│ ║ l.141: else 1 +//│ ║ l.145: else 1 //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead -//│ ║ l.140: if x == +//│ ║ l.144: if x == //│ ║ ^^^^ -//│ ║ l.141: else 1 +//│ ║ l.145: else 1 //│ ║ ^^^^ //│ ╟── Note: 'if' expression started here: -//│ ║ l.140: if x == +//│ ║ l.144: if x == //│ ╙── ^^ //│ ╔══[ERROR] The case when this is false is not handled: == (x,) (undefined,) -//│ ║ l.140: if x == +//│ ║ l.144: if x == //│ ║ ^^^^ -//│ ║ l.141: else 1 +//│ ║ l.145: else 1 //│ ╙── ^^^^ //│ toEnglish: anything -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/ucs/SplitOps.mls b/shared/src/test/diff/ucs/SplitOps.mls index 37943bd5ae..6aee50f35c 100644 --- a/shared/src/test/diff/ucs/SplitOps.mls +++ b/shared/src/test/diff/ucs/SplitOps.mls @@ -86,7 +86,6 @@ class C() //│ C: () -> C //│ = [Function: C1] -// * FIXME: the missing otherwise is for `a == 0` :p :e :ge @@ -97,9 +96,11 @@ fun f(a, b, c) = //│ Parsed: fun f = (a, b, c,) => {if a ‹· == (and (and (0,) (is (b,) (B (),),),) (is (c,) (C (),),)) then 0›}; //│ Desugared: rec def f: (a, b, c,) => {if a ‹· == (and (and (0,) (is (b,) (B (),),),) (is (c,) (C (),),)) then 0›} //│ AST: Def(true, f, Lam(Tup(_: Var(a), _: Var(b), _: Var(c)), Blk(...)), true) -//│ ╔══[ERROR] The case when this is false is not handled: and (is (b,) (B (),),) (is (c,) (C (),),) -//│ ║ l.95: == 0 and b is B() and c is C() then 0 -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] The case when this is false is not handled: == (a,) (0,) +//│ ║ l.93: if a +//│ ║ ^ +//│ ║ l.94: == 0 and b is B() and c is C() then 0 +//│ ╙── ^^^^^^^^ //│ f: (anything, anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index 946c68be1b..80a5ad9c98 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -43,9 +43,9 @@ map(None(), inc) :e fun f(a, b) = if a and b then 0 -//│ ╔══[ERROR] The case when this is false is not handled: b +//│ ╔══[ERROR] The case when this is false is not handled: a //│ ║ l.45: fun f(a, b) = if a and b then 0 -//│ ╙── ^ +//│ ╙── ^ //│ f: (anything, anything,) -> error :e From 31f856f6ff051c58ca3f65c29e3c9abc04519129 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Tue, 21 Mar 2023 20:45:42 +0800 Subject: [PATCH 221/498] Implement proper constructor code-gen and fix various bugs (#6) Co-authored-by: Lionel Parreaux --- .../src/main/scala/mlscript/JSBackend.scala | 200 ++++++---- .../main/scala/mlscript/codegen/Codegen.scala | 15 +- .../main/scala/mlscript/codegen/Scope.scala | 28 +- .../main/scala/mlscript/codegen/Symbol.scala | 35 +- .../src/test/diff/codegen/ConstructorStmt.mls | 345 ++++++++++++++++++ shared/src/test/diff/codegen/NuClasses.mls | 118 ++++++ shared/src/test/diff/codegen/NuFuns.mls | 30 ++ shared/src/test/diff/codegen/Super.mls | 46 ++- shared/src/test/diff/nu/BadClasses.mls | 16 +- shared/src/test/diff/nu/BadScopes.mls | 5 +- .../test/diff/nu/BasicClassInheritance.mls | 2 +- shared/src/test/diff/nu/BasicClasses.mls | 32 +- shared/src/test/diff/nu/BasicMixins.mls | 2 +- shared/src/test/diff/nu/CtorStatements.mls | 3 +- shared/src/test/diff/nu/GenericClasses.mls | 14 +- 15 files changed, 727 insertions(+), 164 deletions(-) create mode 100644 shared/src/test/diff/codegen/ConstructorStmt.mls create mode 100644 shared/src/test/diff/codegen/NuFuns.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 97159cb620..1e8bd0828f 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -19,7 +19,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { */ protected val polyfill = Polyfill() - protected val visitedSymbols = MutSet[ValueSymbol]() + protected val visitedSymbols = MutSet[RuntimeSymbol]() /** * This function translates parameter destructions in `def` declarations. @@ -103,6 +103,15 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSIdent(sym.runtimeName) case S(sym: NewClassSymbol) => JSIdent(sym.runtimeName) + case S(sym: NewClassMemberSymbol) => + if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") + scope.resolveValue("this") match { + case Some(selfSymbol) => + visitedSymbols += selfSymbol + val ident = JSIdent(selfSymbol.runtimeName).member(sym.runtimeName) + if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident + case _ => throw CodeGenError(s"unexpected new class member $name") + } case S(sym: ClassSymbol) => if (isCallee) JSNew(JSIdent(sym.runtimeName)) @@ -296,8 +305,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSBinary("===", scrut.member("constructor"), JSLit("String")) case Var(name) => topLevelScope.getType(name) match { case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(runtimeName)) - case S(NewClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(runtimeName), JSIdent(JSLit.makeStringLiteral("class")))) - case S(ModuleSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(runtimeName), JSIdent(JSLit.makeStringLiteral("class")))) + case S(NewClassSymbol(lexicalName, _, _, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(lexicalName), JSIdent(JSLit.makeStringLiteral("class")))) + case S(ModuleSymbol(lexicalName, _, _, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(lexicalName), JSIdent(JSLit.makeStringLiteral("class")))) case S(TraitSymbol(_, runtimeName, _, _, _)) => JSIdent(runtimeName)("is")(scrut) case S(_: TypeAliasSymbol) => throw new CodeGenError(s"cannot match type alias $name") case S(_: MixinSymbol) => throw new CodeGenError(s"cannot match mixin $name") @@ -451,6 +460,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val fields = mixinSymbol.body.collectFields ++ mixinSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + mixinSymbol.methods.foreach { + case MethodDef(_, _, Var(nme), _, _) => mixinScope.declareNewClassMember(nme, N, true) + } + mixinSymbol.ctor.foreach { + case NuFunDef(rec, Var(nme), _, _) => mixinScope.declareNewClassMember(nme, rec, false) + case _ => () + } val members = mixinSymbol.methods.map { translateNewClassMember(_, fields)(mixinScope) } @@ -458,6 +474,15 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { fields.foreach(constructorScope.declareValue(_, Some(false), false)) val rest = constructorScope.declareValue("rest", Some(false), false) val base = getterScope.declareValue("base", Some(false), false) + val getters = new ListBuffer[Str]() + val stmts = mixinSymbol.ctor.flatMap { + case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil + case NuFunDef(_, Var(nme), _, Left(rhs)) => getters += nme; Ls[JSStmt]( + JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), + JSConstDecl(constructorScope.declareValue(nme, S(false), false).runtimeName, JSIdent(s"this.#$nme")) + ) + case _ => Nil + } val traits = mixinSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { @@ -468,8 +493,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } } - val classBody = JSClassNewDecl(mixinSymbol.runtimeName, fields, S(JSIdent(base.runtimeName)), - Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, traits) + val classBody = JSClassNewDecl(mixinSymbol.lexicalName, fields, fields ::: getters.toList, S(JSIdent(base.runtimeName)), + Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, traits, stmts) JSClassMethod(mixinSymbol.lexicalName, Ls(JSNamePattern(base.runtimeName)), R(Ls( JSReturnStmt(S(JSClassExpr(classBody))) ))) @@ -514,8 +539,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def translateModuleDeclaration( - moduleSymbol: ModuleSymbol, - superFields: Ls[Term] = Nil + moduleSymbol: ModuleSymbol )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") @@ -523,9 +547,25 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Collect class fields. val fields = moduleSymbol.body.collectFields ++ moduleSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + moduleSymbol.methods.foreach { + case MethodDef(_, _, Var(nme), _, _) => moduleScope.declareNewClassMember(nme, N, true) + } + moduleSymbol.ctor.foreach { + case NuFunDef(rec, Var(nme), _, _) => moduleScope.declareNewClassMember(nme, rec, false) + case _ => () + } val members = moduleSymbol.methods.map { translateNewClassMember(_, fields)(moduleScope) } + val getters = new ListBuffer[Str]() + val stmts = moduleSymbol.ctor.flatMap { + case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil + case NuFunDef(_, Var(nme), _, Left(rhs)) => getters += nme; Ls[JSStmt]( + JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), + JSConstDecl(constructorScope.declareValue(nme, S(false), false).runtimeName, JSIdent(s"this.#$nme")) + ) + case _ => Nil + } val traits = moduleSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) @@ -536,62 +576,61 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } val rest = constructorScope.declareValue("rest", Some(false), false) val base: Opt[JSExpr] = - translateParents(superFields, constructorScope) - val superParameters = (superFields map { + translateParents(moduleSymbol.superParameters, constructorScope) + val superParameters = (moduleSymbol.superParameters map { case App(lhs, Tup(rhs)) => rhs map { case (_, Fld(mut, spec, trm)) => translateTerm(trm)(getterScope) } case _ => Nil - }).map(_.reverse).flatten - val decl = JSClassNewDecl(moduleSymbol.runtimeName, + }).flatMap(_.reverse) + val decl = JSClassNewDecl(moduleSymbol.lexicalName, fields, + fields ::: getters.toList, base, superParameters.reverse, N, members, - traits) + traits, + stmts) - JSClassGetter(moduleSymbol.runtimeName, R(Ls( - JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), JSIdent("undefined")), Ls( + JSClassGetter(moduleSymbol.lexicalName, R(Ls( + JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), JSIdent("undefined")), Ls( decl, - JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), - JSNew(JSInvoke(JSIdent(moduleSymbol.runtimeName), Nil)))), - JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(moduleSymbol.runtimeName))), + JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), + JSNew(JSInvoke(JSIdent(moduleSymbol.lexicalName), Nil)))), + JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(moduleSymbol.lexicalName))), )), - JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.runtimeName))) + JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName))) ))) } protected def translateNewClassDeclaration( - classSymbol: NewClassSymbol, - superFields: Ls[Term] = Nil, - rest: Opt[Str] = N + classSymbol: NewClassSymbol )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"${classSymbol.lexicalName} getter") val cacheSymbol = getterScope.declareValue("cache", Some(false), false) - val classBody = translateNewClassExpression(classSymbol, superFields, rest, cacheSymbol.runtimeName)(getterScope) + val classBody = translateNewClassExpression(classSymbol, N, cacheSymbol.runtimeName)(getterScope) val constructor = classBody match { - case JSClassNewDecl(_, fields, _, _, _, _, _) => fields.map(JSNamePattern(_)) + case JSClassNewDecl(_, fields, _, _, _, _, _, _, _) => fields.map(JSNamePattern(_)) } val params = classBody match { - case JSClassNewDecl(_, fields, _, _, _, _, _) => fields.map(JSIdent(_)) + case JSClassNewDecl(_, fields, _, _, _, _, _, _, _) => fields.map(JSIdent(_)) } - JSClassGetter(classSymbol.runtimeName, R(Ls( + JSClassGetter(classSymbol.lexicalName, R(Ls( JSConstDecl(cacheSymbol.runtimeName, JSField(JSIdent("this"), "cache")), - JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), classSymbol.runtimeName), JSIdent("undefined")), Ls( + JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSIdent("undefined")), Ls( JSExprStmt(JSClassExpr(classBody)), - JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), classSymbol.runtimeName), - JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.runtimeName)), params))))), - JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), classSymbol.runtimeName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(classSymbol.runtimeName))) + JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), + JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), + JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(classSymbol.lexicalName))) )), - JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), classSymbol.runtimeName))) + JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName))) ))) } protected def translateNewClassExpression( classSymbol: NewClassSymbol, - superFields: Ls[Term] = Nil, rest: Opt[Str] = N, cacheName: Str )(implicit scope: Scope): JSClassNewDecl = { @@ -600,15 +639,22 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Collect class fields. val fields = classSymbol.body.collectFields ++ classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) + classSymbol.methods.foreach { + case MethodDef(_, _, Var(nme), _, _) => classScope.declareNewClassMember(nme, N, true) + } + classSymbol.ctor.foreach { + case NuFunDef(rec, Var(nme), _, _) => classScope.declareNewClassMember(nme, rec, false) + case _ => () + } val members = classSymbol.methods.map { - translateNewClassMember(_, fields, S(JSConstDecl(classSymbol.runtimeName, JSField(JSIdent(cacheName), classSymbol.runtimeName))))(classScope) + translateNewClassMember(_, fields, S(JSConstDecl(classSymbol.lexicalName, JSField(JSIdent(cacheName), classSymbol.lexicalName))))(classScope) } val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") fields.foreach(constructorScope.declareValue(_, Some(false), false)) val restRuntime = rest.flatMap(name => S(constructorScope.declareValue(name, Some(false), false).runtimeName)) val base: Opt[JSExpr] = - translateParents(superFields, constructorScope) + translateParents(classSymbol.superParameters, constructorScope) val traits = classSymbol.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) @@ -618,17 +664,26 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } } - val superParameters = (superFields map { + val superParameters = (classSymbol.superParameters map { case App(lhs, Tup(rhs)) => rhs map { case (_, Fld(mut, spec, trm)) => translateTerm(trm)(constructorScope) } case _ => Nil - }).map(_.reverse).flatten + }).flatMap(_.reverse) + val getters = new ListBuffer[Str]() + val stmts = classSymbol.ctor.flatMap { + case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil + case NuFunDef(_, Var(nme), _, Left(rhs)) => getters += nme; Ls[JSStmt]( + JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), + JSConstDecl(constructorScope.declareValue(nme, S(false), false).runtimeName, JSIdent(s"this.#$nme")) + ) + case _ => Nil + } - JSClassNewDecl(classSymbol.runtimeName, fields, base, restRuntime match { + JSClassNewDecl(classSymbol.lexicalName, fields, fields ::: getters.toList, base, restRuntime match { case Some(restRuntime) => superParameters.reverse :+ JSIdent(s"...$restRuntime") case _ => superParameters.reverse - }, restRuntime, members, traits) + }, restRuntime, members, traits, stmts) } /** @@ -740,12 +795,11 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def declareNewTypeDefs(typeDefs: Ls[NuTypeDef]): - (Ls[TraitSymbol], Ls[NewClassSymbol], Ls[MixinSymbol], Ls[ModuleSymbol], HashMap[String, Ls[Term]]) = { + (Ls[TraitSymbol], Ls[NewClassSymbol], Ls[MixinSymbol], Ls[ModuleSymbol]) = { val traits = new ListBuffer[TraitSymbol]() val classes = new ListBuffer[NewClassSymbol]() val mixins = new ListBuffer[MixinSymbol]() val modules = new ListBuffer[ModuleSymbol]() - val superParameters = HashMap[String, Ls[Term]]() def tt(trm: Term): Type = trm.toType match { case L(ds) => Top case R(ty) => ty @@ -760,44 +814,48 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case _ => die } val body = pars.map(tt).foldRight(Record(params): Type)(Inter) - val members = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { - case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) + val members = unit.entities.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + case NuFunDef(isLetRec, mnme, tys, Left(rhs)) if (isLetRec.isEmpty || isLetRec.getOrElse(false)) => + lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) + case _ => lst + }) + val stmts = unit.entities.foldLeft(List[Statement]())((lst, loc) => loc match { + case Asc(Var("this"), _) => lst + case Asc(Super(), _) => lst + case lt @ NuFunDef(S(false), _, _, Left(rhs)) => lst :+ lt + case t: Term => lst :+ t case _ => lst }) - (body, members) + (body, members, stmts) } typeDefs.foreach { case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members) = prepare(mxName, fs, pars, unit) - val sym = topLevelScope.declareMixin(mxName, tps map { _._2.name }, body, members) + val (body, members, stmts) = prepare(mxName, fs, pars, unit) + val sym = topLevelScope.declareMixin(mxName, tps map { _._2.name }, body, members, stmts) mixins += sym - superParameters.put(sym.runtimeName, pars) } case NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members) = prepare(nme, fs, pars, unit) - val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members) + val (body, members, stmts) = prepare(nme, fs, pars, unit) + val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members, stmts, pars) modules += sym - superParameters.put(sym.runtimeName, pars) } case NuTypeDef(Als, TypeName(nme), tps, _, sig, pars, _, _, _) => { topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) } case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members) = prepare(nme, fs, pars, unit) - val sym = topLevelScope.declareNewClass(nme, tps map { _._2.name }, body, members) + val (body, members, stmts) = prepare(nme, fs, pars, unit) + val sym = topLevelScope.declareNewClass(nme, tps map { _._2.name }, body, members, stmts, pars) classes += sym - superParameters.put(sym.runtimeName, pars) } - case NuTypeDef(k @ Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members) = prepare(nme, fs, pars, unit) + case NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + val (body, members, _) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareTrait(nme, tps map { _._2.name }, body, members) traits += sym - superParameters.put(sym.runtimeName, pars) } } - (traits.toList, classes.toList, mixins.toList, modules.toList, superParameters) + (traits.toList, classes.toList, mixins.toList, modules.toList) } /** @@ -921,7 +979,7 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { val mlsModule = topLevelScope.declareValue("typing_unit", Some(false), false) val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared - val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols, superParameters) = declareNewTypeDefs(typeDefs) + val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDefs) def include(typeName: Str, moduleName: Str) = JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) val includes = @@ -933,18 +991,8 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { val defs = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ - moduleSymbols.map((m) => - translateModuleDeclaration(m, superParameters.get(m.runtimeName) match { - case Some(lst) => lst - case _ => Nil - })(topLevelScope) - ) ++ - classSymbols.map { sym => - superParameters.get(sym.runtimeName) match { - case Some(sp) => translateNewClassDeclaration(sym, sp)(topLevelScope) - case _ => translateNewClassDeclaration(sym)(topLevelScope) - } - }.toList + moduleSymbols.map { translateModuleDeclaration(_)(topLevelScope) } ++ + classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) }.toList val defStmts = JSLetDecl(Ls(mlsModule.runtimeName -> S(JSRecord(Ls("cache" -> JSRecord(Ls())), defs)))) :: includes @@ -1123,22 +1171,12 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { val mlsModule = topLevelScope.declareValue("typing_unit", Some(false), false) val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared - val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols, superParameters) = declareNewTypeDefs(typeDefs) + val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ - moduleSymbols.map((m) => - translateModuleDeclaration(m, superParameters.get(m.runtimeName) match { - case Some(lst) => lst - case _ => Nil - })(topLevelScope) - ) ++ - classSymbols.map { sym => - superParameters.get(sym.runtimeName) match { - case Some(sp) => translateNewClassDeclaration(sym, sp)(topLevelScope) - case _ => translateNewClassDeclaration(sym)(topLevelScope) - } - }.toList + moduleSymbols.map { translateModuleDeclaration(_)(topLevelScope) } ++ + classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) }.toList def include(typeName: Str, moduleName: Str) = JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 37e216454d..09ab204cf9 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -829,11 +829,13 @@ final case class JSClassDecl( final case class JSClassNewDecl( name: Str, fields: Ls[Str], + privateMem: Ls[Str], `extends`: Opt[JSExpr] = N, superFields: Ls[JSExpr] = Nil, rest: Opt[Str] = N, methods: Ls[JSClassMemberDecl] = Nil, implements: Ls[Str] = Nil, + initStmts: Ls[JSStmt] = Nil ) extends JSStmt { def toSourceCode: SourceCode = { val constructor: SourceCode = { @@ -845,9 +847,9 @@ final case class JSClassNewDecl( })((p, s) => if (s.isEmpty) s"${p._1}" else s"${p._1}, $s") - if (!fields.isEmpty) { - fields.foreach(f => buffer += s" #${f};") - fields.foreach(f => buffer += s" get ${f}() { return this.#${f}; }") + if (!privateMem.isEmpty) { + privateMem.foreach(f => buffer += s" #${f};") + privateMem.foreach(f => buffer += s" get ${f}() { return this.#${f}; }") } buffer += s" constructor($params) {" if (`extends`.isDefined) { @@ -863,6 +865,11 @@ final case class JSClassNewDecl( fields.iterator.zipWithIndex.foreach { pair => buffer += s" this.#${pair._1} = ${pair._1};" // TODO: invalid name? } + initStmts.foreach { s => + s.toSourceCode.indented.indented.toString.split("\n").foreach { + line => buffer += line + } + } buffer += " }" SourceCode(buffer.toList) } @@ -876,7 +883,7 @@ final case class JSClassNewDecl( SourceCode(s"class $name extends ") ++ base.toSourceCode ++ SourceCode(" {") + constructor + methodsSourceCode + epilogue case None => - if (fields.isEmpty && methods.isEmpty && implements.isEmpty) { + if (fields.isEmpty && methods.isEmpty && implements.isEmpty && initStmts.isEmpty) { SourceCode(s"class $name {}") } else { SourceCode( diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index efedf902c6..d96effd883 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -6,7 +6,7 @@ import mlscript.Type import scala.reflect.ClassTag import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls, Nms} import mlscript.MethodDef -import mlscript.Term +import mlscript.{Term, Statement} import mlscript.utils.{AnyOps, lastWords} import mlscript.JSField @@ -226,10 +226,11 @@ class Scope(name: Str, enclosing: Opt[Scope]) { lexicalName: Str, params: Ls[Str], base: Type, - methods: Ls[MethodDef[Left[Term, Type]]] + methods: Ls[MethodDef[Left[Term, Type]]], + ctor: Ls[Statement], + superParameters: Ls[Term] ): NewClassSymbol = { - val runtimeName = allocateRuntimeName(lexicalName) - val symbol = NewClassSymbol(lexicalName, runtimeName, params.sorted, base, methods) + val symbol = NewClassSymbol(lexicalName, params.sorted, base, methods, ctor, superParameters) register(symbol) symbol } @@ -238,10 +239,10 @@ class Scope(name: Str, enclosing: Opt[Scope]) { lexicalName: Str, params: Ls[Str], base: Type, - methods: Ls[MethodDef[Left[Term, Type]]] + methods: Ls[MethodDef[Left[Term, Type]]], + ctor: Ls[Statement] ): MixinSymbol = { - val runtimeName = allocateRuntimeName(lexicalName) - val symbol = MixinSymbol(lexicalName, runtimeName, params.sorted, base, methods) + val symbol = MixinSymbol(lexicalName, params.sorted, base, methods, ctor) register(symbol) symbol } @@ -250,10 +251,11 @@ class Scope(name: Str, enclosing: Opt[Scope]) { lexicalName: Str, params: Ls[Str], base: Type, - methods: Ls[MethodDef[Left[Term, Type]]] + methods: Ls[MethodDef[Left[Term, Type]]], + ctor: Ls[Statement], + superParameters: Ls[Term] ): ModuleSymbol = { - val runtimeName = allocateRuntimeName(lexicalName) - val symbol = ModuleSymbol(lexicalName, runtimeName, params.sorted, base, methods) + val symbol = ModuleSymbol(lexicalName, params.sorted, base, methods, ctor, superParameters) register(symbol) symbol } @@ -296,6 +298,12 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } + def declareNewClassMember(name: Str, isByvalueRec: Option[Boolean], isLam: Boolean): NewClassMemberSymbol = { + val symbol = NewClassMemberSymbol(name, isByvalueRec, isLam) + register(symbol) + symbol + } + def declareStubValue(lexicalName: Str)(implicit accessible: Bool): StubValueSymbol = declareStubValue(lexicalName, N) diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index b9f757e24a..95b9f2c1e4 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -4,7 +4,7 @@ import mlscript.utils.shorthands._ import mlscript.Type import mlscript.JSClassDecl import mlscript.MethodDef -import mlscript.Term +import mlscript.{Term, Statement} import mlscript.TypeName sealed trait LexicalSymbol { @@ -85,12 +85,29 @@ final case class ClassSymbol( override def toString: Str = s"class $lexicalName ($runtimeName)" } +sealed class NewClassMemberSymbol( + val lexicalName: Str, + val isByvalueRec: Option[Boolean], + val isLam: Boolean +) extends RuntimeSymbol { + override def toString: Str = s"new class member $lexicalName" + + // Class members should have fixed names determined by users + override def runtimeName: Str = lexicalName +} + +object NewClassMemberSymbol { + def apply(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean): NewClassMemberSymbol = + new NewClassMemberSymbol(lexicalName, isByvalueRec, isLam) +} + final case class NewClassSymbol( lexicalName: Str, - runtimeName: Str, params: Ls[Str], body: Type, methods: Ls[MethodDef[Left[Term, Type]]], + ctor: Ls[Statement], + superParameters: Ls[Term] ) extends TypeSymbol with RuntimeSymbol with Ordered[NewClassSymbol] { @@ -99,14 +116,17 @@ final case class NewClassSymbol( override def compare(that: NewClassSymbol): Int = lexicalName.compare(that.lexicalName) override def toString: Str = s"new class $lexicalName ($runtimeName)" + + // Classes should have fixed names determined by users + override def runtimeName: Str = lexicalName } final case class MixinSymbol( lexicalName: Str, - runtimeName: Str, params: Ls[Str], body: Type, methods: Ls[MethodDef[Left[Term, Type]]], + ctor: Ls[Statement] ) extends TypeSymbol with RuntimeSymbol with Ordered[MixinSymbol] { @@ -115,14 +135,18 @@ final case class MixinSymbol( override def compare(that: MixinSymbol): Int = lexicalName.compare(that.lexicalName) override def toString: Str = s"mixin $lexicalName ($runtimeName)" + + // Mixins should have fixed names determined by users + override def runtimeName: Str = lexicalName } final case class ModuleSymbol( lexicalName: Str, - runtimeName: Str, params: Ls[Str], body: Type, methods: Ls[MethodDef[Left[Term, Type]]], + ctor: Ls[Statement], + superParameters: Ls[Term] ) extends TypeSymbol with RuntimeSymbol with Ordered[ModuleSymbol] { @@ -131,6 +155,9 @@ final case class ModuleSymbol( override def compare(that: ModuleSymbol): Int = lexicalName.compare(that.lexicalName) override def toString: Str = s"module $lexicalName ($runtimeName)" + + // Modules should have fixed names determined by users + override def runtimeName: Str = lexicalName } final case class TraitSymbol( diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls new file mode 100644 index 0000000000..b7fb35da06 --- /dev/null +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -0,0 +1,345 @@ +:NewParser +:NewDefs + +:js +module Test0 { + log("Hello!") +} +//│ module Test0() +//│ // Prelude +//│ function log(x) { +//│ return console.info(x); +//│ } +//│ let res; +//│ let typing_unit = { +//│ cache: {}, +//│ get Test0() { +//│ if (this.cache.Test0 === undefined) { +//│ class Test0 { +//│ constructor() { +//│ log("Hello!"); +//│ } +//│ } +//│ this.cache.Test0 = new Test0(); +//│ this.cache.Test0["class"] = Test0; +//│ } +//│ return this.cache.Test0; +//│ } +//│ }; +//│ globalThis.Test0 = typing_unit.Test0; +//│ // End of generated code + +:js +Test0 +//│ Test0 +//│ // Prelude +//│ let typing_unit1 = { cache: {} }; +//│ // Query 1 +//│ res = Test0; +//│ // End of generated code +//│ res +//│ = Test0 { class: [class Test0] } +//│ // Output +//│ Hello! + +:js +Test0 +//│ Test0 +//│ // Prelude +//│ let typing_unit2 = { cache: {} }; +//│ // Query 1 +//│ res = Test0; +//│ // End of generated code +//│ res +//│ = Test0 { class: [class Test0] } + +:js +class A(a: int) { + log(a) +} +//│ class A(a: int) +//│ // Prelude +//│ let typing_unit3 = { +//│ cache: {}, +//│ get A() { +//│ const cache = this.cache; +//│ if (this.cache.A === undefined) { +//│ class A { +//│ #a; +//│ get a() { return this.#a; } +//│ constructor(a) { +//│ this.#a = a; +//│ log(a); +//│ } +//│ }; +//│ this.cache.A = ((a) => new A(a)); +//│ this.cache.A["class"] = A; +//│ } +//│ return this.cache.A; +//│ } +//│ }; +//│ globalThis.A = typing_unit3.A; +//│ // End of generated code + +:js +let aa = A(42) +//│ let aa: A +//│ // Prelude +//│ let typing_unit4 = { cache: {} }; +//│ // Query 1 +//│ globalThis.aa = A(42); +//│ // End of generated code +//│ aa +//│ = A {} +//│ // Output +//│ 42 + +:js +aa +//│ A +//│ // Prelude +//│ let typing_unit5 = { cache: {} }; +//│ // Query 1 +//│ res = aa; +//│ // End of generated code +//│ res +//│ = A {} + +:js +let ab = A(0) +//│ let ab: A +//│ // Prelude +//│ let typing_unit6 = { cache: {} }; +//│ // Query 1 +//│ globalThis.ab = A(0); +//│ // End of generated code +//│ ab +//│ = A {} +//│ // Output +//│ 0 + +:e +:js +class Foo { + this: { x: int } +} +//│ ╔══[ERROR] Class `Foo` does not contain member `x` +//│ ║ l.124: this: { x: int } +//│ ╙── ^ +//│ class Foo() +//│ // Prelude +//│ let typing_unit7 = { +//│ cache: {}, +//│ get Foo() { +//│ const cache = this.cache; +//│ if (this.cache.Foo === undefined) { +//│ class Foo {}; +//│ this.cache.Foo = (() => new Foo()); +//│ this.cache.Foo["class"] = Foo; +//│ } +//│ return this.cache.Foo; +//│ } +//│ }; +//│ globalThis.Foo = typing_unit7.Foo; +//│ // End of generated code + +:e +:js +class Bar { + super: { x: int } +} +//│ ╔══[ERROR] Illegal use of `super` +//│ ║ l.149: super: { x: int } +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Class `Bar` does not contain member `x` +//│ ║ l.149: super: { x: int } +//│ ╙── ^ +//│ class Bar() +//│ // Prelude +//│ let typing_unit8 = { +//│ cache: {}, +//│ get Bar() { +//│ const cache = this.cache; +//│ if (this.cache.Bar === undefined) { +//│ class Bar {}; +//│ this.cache.Bar = (() => new Bar()); +//│ this.cache.Bar["class"] = Bar; +//│ } +//│ return this.cache.Bar; +//│ } +//│ }; +//│ globalThis.Bar = typing_unit8.Bar; +//│ // End of generated code + +:js +class Baz { + let x = 123 + log((1, x)) + let y = + log((2, x)) + x + 1 + log((3, y)) +} +//│ class Baz() { +//│ let x: 123 +//│ let y: int +//│ } +//│ // Prelude +//│ let typing_unit9 = { +//│ cache: {}, +//│ get Baz() { +//│ const cache = this.cache; +//│ if (this.cache.Baz === undefined) { +//│ class Baz { +//│ #x; +//│ #y; +//│ get x() { return this.#x; } +//│ get y() { return this.#y; } +//│ constructor() { +//│ this.#x = 123; +//│ const x = this.#x; +//│ log([ +//│ 1, +//│ x +//│ ]); +//│ this.#y = (() => { +//│ log([ +//│ 2, +//│ x +//│ ]); +//│ return x + 1; +//│ })(); +//│ const y = this.#y; +//│ log([ +//│ 3, +//│ y +//│ ]); +//│ } +//│ }; +//│ this.cache.Baz = (() => new Baz()); +//│ this.cache.Baz["class"] = Baz; +//│ } +//│ return this.cache.Baz; +//│ } +//│ }; +//│ globalThis.Baz = typing_unit9.Baz; +//│ // End of generated code + +let baz = Baz() +log((baz.x, baz.y)) +//│ let baz: Baz +//│ unit +//│ baz +//│ = Baz {} +//│ // Output +//│ [ 1, 123 ] +//│ [ 2, 123 ] +//│ [ 3, 124 ] +//│ res +//│ = undefined +//│ // Output +//│ [ 123, 124 ] + +:js +class Q() { + let q = 42 + fun qq = + let f = (x: int) => {q: x + q}; f(1) +} +//│ class Q() { +//│ let q: 42 +//│ fun qq: {q: int} +//│ } +//│ // Prelude +//│ let typing_unit11 = { +//│ cache: {}, +//│ get Q() { +//│ const cache = this.cache; +//│ if (this.cache.Q === undefined) { +//│ class Q { +//│ #q; +//│ get q() { return this.#q; } +//│ constructor() { +//│ this.#q = 42; +//│ const q = this.#q; +//│ } +//│ get qq() { +//│ const Q = cache.Q; +//│ const self = this; +//│ return ((() => { +//│ let f = (x) => ({ q: x + self.q }); +//│ return f(1); +//│ })()); +//│ } +//│ }; +//│ this.cache.Q = (() => new Q()); +//│ this.cache.Q["class"] = Q; +//│ } +//│ return this.cache.Q; +//│ } +//│ }; +//│ globalThis.Q = typing_unit11.Q; +//│ // End of generated code + +let q = Q() +q.qq.q +//│ let q: Q +//│ int +//│ q +//│ = Q {} +//│ res +//│ = 43 + +:js +class W() { + let x = 42 + fun add(self: int) = x + self +} +//│ class W() { +//│ fun add: (self: int,) -> int +//│ let x: 42 +//│ } +//│ // Prelude +//│ let typing_unit13 = { +//│ cache: {}, +//│ get W() { +//│ const cache = this.cache; +//│ if (this.cache.W === undefined) { +//│ class W { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor() { +//│ this.#x = 42; +//│ const x = this.#x; +//│ } +//│ add(self1) { +//│ const W = cache.W; +//│ const self = this; +//│ return self.x + self1; +//│ } +//│ }; +//│ this.cache.W = (() => new W()); +//│ this.cache.W["class"] = W; +//│ } +//│ return this.cache.W; +//│ } +//│ }; +//│ globalThis.W = typing_unit13.W; +//│ // End of generated code + +:js +let www = W() +www.add(42) +//│ let www: W +//│ int +//│ // Prelude +//│ let typing_unit14 = { cache: {} }; +//│ // Query 1 +//│ globalThis.www = W(); +//│ // Query 2 +//│ res = www.add(42); +//│ // End of generated code +//│ www +//│ = W {} +//│ res +//│ = 84 diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index 4333dcd844..5e44dc5c22 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -58,4 +58,122 @@ Test2(0).inc.n //│ res //│ = 1 +class C[A](n: A) { + fun f = g + fun g = n +} +//│ class C[A](n: A) { +//│ fun f: A +//│ fun g: A +//│ } + +:e +let a = C[int](42) +a.f +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.71: let a = C[int](42) +//│ ╙── ^^^^^^ +//│ let a: error +//│ error +//│ a +//│ = C {} +//│ res +//│ = 42 + + +// FIXME +module Foo { + fun f = C0() + class C0() +} +//│ module Foo() { +//│ class C0() +//│ fun f: C0 +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol C0 + + +mixin M0(n: int) { + let m = n // this refers to specifically the `n` we had in parameter, not necessarily this.n + fun bar = m + fun foo = [n, m, bar] // should this be the same as `[this.n, this.m, this.bar]`? +} +//│ mixin M0(n: int) { +//│ fun bar: int +//│ fun foo: (int, int, int,) +//│ let m: int +//│ } + +module M1 extends M0(123) { + fun n = "n" + fun m = "m" + fun bar = "bar" +} +//│ module M1() { +//│ fun bar: "bar" +//│ fun foo: (int, int, int,) +//│ fun m: "m" +//│ fun n: "n" +//│ } + +[M1.n, M1.m, M1.bar] +//│ ("n", "m", "bar",) +//│ res +//│ = [ 'n', 'm', 'bar' ] + +// FIXME typing/runtime mismatch +M1.foo +//│ (int, int, int,) +//│ res +//│ = [ 123, 'm', 'bar' ] + +:e +:js +module M2 { + let m = 100 + fun foo(y) = + fun bar(x) = x + y + this.m + bar(10) +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.136: fun bar(x) = x + y + this.m +//│ ╙── ^^ +//│ module M2() { +//│ fun foo: int -> int +//│ let m: 100 +//│ } +//│ // Prelude +//│ let typing_unit11 = { +//│ cache: {}, +//│ get M2() { +//│ if (this.cache.M2 === undefined) { +//│ class M2 { +//│ #m; +//│ get m() { return this.#m; } +//│ constructor() { +//│ this.#m = 100; +//│ const m = this.#m; +//│ } +//│ foo(y) { +//│ const self = this; +//│ return ((() => { +//│ let bar = (x) => x + y + self.m; +//│ return bar(10); +//│ })()); +//│ } +//│ } +//│ this.cache.M2 = new M2(); +//│ this.cache.M2["class"] = M2; +//│ } +//│ return this.cache.M2; +//│ } +//│ }; +//│ globalThis.M2 = typing_unit11.M2; +//│ // End of generated code + +M2.foo(1) +//│ int +//│ res +//│ = 111 diff --git a/shared/src/test/diff/codegen/NuFuns.mls b/shared/src/test/diff/codegen/NuFuns.mls new file mode 100644 index 0000000000..d5e902adf7 --- /dev/null +++ b/shared/src/test/diff/codegen/NuFuns.mls @@ -0,0 +1,30 @@ +:NewDefs + + +:js +fun foo = + fun bar(x) = x + 1 + bar(10) +//│ fun foo: int +//│ // Prelude +//│ let res; +//│ let typing_unit = { cache: {} }; +//│ // Query 1 +//│ globalThis.foo = function foo() { +//│ return ((() => { +//│ let bar = (x) => x + 1; +//│ return bar(10); +//│ })()); +//│ }; +//│ // End of generated code + + +// TODO +fun foo = + class C(a: int) { fun bar(x) = a + x + 1 } + C(100).bar(10) +//│ fun foo: int +//│ Code generation encountered an error: +//│ unsupported definitions in blocks + + diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 1f51042189..9bb7a0f841 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -3,7 +3,6 @@ -// * FIXME `let` fields should not be getters :js mixin Foo0 { let foo0 = 0 @@ -17,11 +16,12 @@ mixin Foo0 { //│ cache: {}, //│ Foo0(base) { //│ return (class Foo0 extends base { +//│ #foo0; +//│ get foo0() { return this.#foo0; } //│ constructor(...rest) { //│ super(...rest); -//│ } -//│ get foo0() { -//│ return 0; +//│ this.#foo0 = 0; +//│ const foo0 = this.#foo0; //│ } //│ }); //│ } @@ -44,14 +44,16 @@ mixin Foo1 { //│ cache: {}, //│ Foo1(base) { //│ return (class Foo1 extends base { +//│ #foo0; +//│ #foo1; +//│ get foo0() { return this.#foo0; } +//│ get foo1() { return this.#foo1; } //│ constructor(...rest) { //│ super(...rest); -//│ } -//│ get foo0() { -//│ return 1; -//│ } -//│ get foo1() { -//│ return super.foo0; +//│ this.#foo0 = 1; +//│ const foo0 = this.#foo0; +//│ this.#foo1 = super.foo0; +//│ const foo1 = this.#foo1; //│ } //│ }); //│ } @@ -78,7 +80,7 @@ mixin Foo2 { fun foo2 = super } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.78: fun foo2 = super +//│ ║ l.80: fun foo2 = super //│ ╙── ^^^^^ //│ mixin Foo2() { //│ super: 'super @@ -112,37 +114,33 @@ module Test0 extends Foo2 //│ // Prelude //│ let typing_unit5 = { //│ cache: {}, -//│ get Test01() { -//│ if (this.cache.Test01 === undefined) { -//│ class Test01 extends Foo2(Object) { +//│ get Test0() { +//│ if (this.cache.Test0 === undefined) { +//│ class Test0 extends Foo2(Object) { //│ constructor() { //│ super(); //│ } //│ } -//│ this.cache.Test01 = new Test01(); -//│ this.cache.Test01["class"] = Test01; +//│ this.cache.Test0 = new Test0(); +//│ this.cache.Test0["class"] = Test0; //│ } -//│ return this.cache.Test01; +//│ return this.cache.Test0; //│ } //│ }; -//│ globalThis.Test01 = typing_unit5.Test01; +//│ globalThis.Test0 = typing_unit5.Test0; //│ // End of generated code //│ Runtime error: //│ ReferenceError: Foo2 is not defined -:re Test0 //│ Test0 //│ res -//│ Runtime error: -//│ ReferenceError: Test01 is not defined +//│ = Test0 { class: [Function: Test0] } -:re Test0.foo2 //│ anything //│ res -//│ Runtime error: -//│ ReferenceError: Test01 is not defined +//│ = undefined class Foo extends Foo0 { diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 95398cc426..87bfefeb07 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -42,8 +42,6 @@ class Foo { //│ fun bar: 0 //│ fun foo: 0 //│ } -//│ Code generation encountered an error: -//│ unresolved symbol foo // FIXME class Foo { @@ -54,8 +52,6 @@ class Foo { //│ fun bar: 0 //│ let foo: 0 //│ } -//│ Code generation encountered an error: -//│ unresolved symbol foo module Bar { @@ -71,7 +67,7 @@ module Bar { :ge hello //│ ╔══[ERROR] identifier not found: hello -//│ ║ l.72: hello +//│ ║ l.68: hello //│ ╙── ^^^^^ //│ error //│ Code generation encountered an error: @@ -80,7 +76,7 @@ hello :e 1 : I //│ ╔══[ERROR] type identifier not found: I -//│ ║ l.81: 1 : I +//│ ║ l.77: 1 : I //│ ╙── ^ //│ error //│ res @@ -90,11 +86,11 @@ hello :e class Foo[A] { 42: A } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.91: class Foo[A] { 42: A } +//│ ║ l.87: class Foo[A] { 42: A } //│ ║ ^^ //│ ╟── integer literal of type `42` does not match type `A` //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.91: class Foo[A] { 42: A } +//│ ║ l.87: class Foo[A] { 42: A } //│ ╙── ^ //│ class Foo[A]() @@ -102,8 +98,8 @@ class Foo[A] { 42: A } :e class C1 { fun oops = this.x } //│ ╔══[ERROR] Class `C1` does not contain member `x` -//│ ║ l.103: class C1 { fun oops = this.x } -//│ ╙── ^^ +//│ ║ l.99: class C1 { fun oops = this.x } +//│ ╙── ^^ //│ class C1() { //│ fun oops: error //│ } diff --git a/shared/src/test/diff/nu/BadScopes.mls b/shared/src/test/diff/nu/BadScopes.mls index c6827eb578..a348199ca2 100644 --- a/shared/src/test/diff/nu/BadScopes.mls +++ b/shared/src/test/diff/nu/BadScopes.mls @@ -28,12 +28,15 @@ x :e +:ge class Foo(x: int) class Bar { x } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.32: class Bar { x } +//│ ║ l.33: class Bar { x } //│ ╙── ^ //│ class Foo(x: int) //│ class Bar() +//│ Code generation encountered an error: +//│ unresolved symbol x diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 5789edbd21..330b8b6a45 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -22,7 +22,7 @@ class B(m: int) extends A(n + 1) //│ ╙── ^^^^^^^^ //│ class B(m: int) //│ Code generation encountered an error: -//│ unresolved symbol in parents: A1 +//│ unresolved symbol n diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 72503d1e5b..ce4e152fcb 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -80,45 +80,35 @@ class Base0(n) { //│ fun my: error //│ fun oops: error //│ } -//│ Code generation encountered an error: -//│ unresolved symbol my // :d // Base0 -:re let b1 = Base0(42) //│ let b1: Base0 //│ b1 -//│ Runtime error: -//│ ReferenceError: Base0 is not defined +//│ = Base0 {} -:re let n1 = b1.n //│ let n1: error //│ n1 -//│ Runtime error: -//│ ReferenceError: b1 is not defined +//│ = 42 // TODO n1 + 1 //│ int //│ res -//│ Runtime error: -//│ ReferenceError: n1 is not defined +//│ = 43 -:re let b2 = Base0("hi") let n2 = b2.n //│ let b2: Base0 //│ let n2: error //│ b2 -//│ Runtime error: -//│ ReferenceError: Base0 is not defined +//│ = Base0 {} //│ n2 -//│ Runtime error: -//│ ReferenceError: b2 is not defined +//│ = 'hi' @@ -147,12 +137,12 @@ class Base1(base: int) { Base1 //│ (base: int,) -> Base1 //│ res -//│ = [Function (anonymous)] { class: [class Base11] } +//│ = [Function (anonymous)] { class: [class Base1] } let b = Base1(1) //│ let b: Base1 //│ b -//│ = Base11 {} +//│ = Base1 {} b.base //│ int @@ -168,12 +158,12 @@ b.getBase1 b.me //│ Base1 & {base: int} //│ res -//│ = Base11 {} +//│ = Base1 {} :e b.getBaseTypo //│ ╔══[ERROR] Class `Base1` does not contain member `getBaseTypo` -//│ ║ l.174: b.getBaseTypo +//│ ║ l.164: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error //│ res @@ -183,7 +173,7 @@ b.getBaseTypo b : Base1 //│ Base1 //│ res -//│ = Base11 {} +//│ = Base1 {} class Rec(n: int) { @@ -218,6 +208,8 @@ class Annots(base: 0 | 1) { //│ class Annots(base: 0 | 1) { //│ fun a: 0 | 1 //│ } +//│ Code generation encountered an error: +//│ unexpected new class member a diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 5f3e171b1a..159ca3893a 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -135,7 +135,7 @@ class Base1(x): BaseTest Base1 //│ (x: error,) -> Base1 //│ res -//│ = [Function (anonymous)] { class: [class Base11] } +//│ = [Function (anonymous)] { class: [class Base1] } // :ns diff --git a/shared/src/test/diff/nu/CtorStatements.mls b/shared/src/test/diff/nu/CtorStatements.mls index 05abdedb3d..e9a7f45544 100644 --- a/shared/src/test/diff/nu/CtorStatements.mls +++ b/shared/src/test/diff/nu/CtorStatements.mls @@ -14,10 +14,11 @@ module Test0 { } //│ module Test0() -// TODO should print Test0 //│ Test0 //│ res //│ = Test0 { class: [class Test0] } +//│ // Output +//│ Hello! diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 883cd83f0b..9c55c8e2b2 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -21,7 +21,7 @@ fun f(x) = if x is C(a) then a let c = C(1) //│ let c: C[1] //│ c -//│ = C1 {} +//│ = C {} f(c) //│ 1 @@ -214,12 +214,12 @@ class Test(n: A) { Test(1) //│ Test[1] //│ res -//│ = Test1 {} +//│ = Test {} Test(true) //│ Test[true] //│ res -//│ = Test1 {} +//│ = Test {} class Test(n: A) { @@ -236,7 +236,7 @@ class Test(n: A) { Test(1) //│ Test[1] //│ res -//│ = Test2 {} +//│ = Test {} Test(1).foo //│ 1 @@ -251,7 +251,7 @@ Test("ok").foo let t = Test(1) //│ let t: Test[1] //│ t -//│ = Test2 {} +//│ = Test {} t.foo1(true) //│ 1 | true @@ -263,7 +263,7 @@ t : Test<'a> //│ where //│ 'a :> 1 | true //│ res -//│ = Test2 {} +//│ = Test {} t.id //│ forall 'a. 'a -> 'a @@ -369,7 +369,7 @@ let w = Weird(c) w.x //│ C['a] //│ res -//│ = C1 {} +//│ = C {} // FIXME not(w.x.a) From e227ec3a38cd867ab42b792ebb2ae37b46c2447f Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 22 Mar 2023 21:34:06 +0800 Subject: [PATCH 222/498] Add test cases in the poster and gather parse failures --- shared/src/test/diff/tapl/NuUntyped.mls | 12 ++++- shared/src/test/diff/ucs/Exhaustiveness.mls | 51 ++++++++++++++++----- shared/src/test/diff/ucs/Humiliation.mls | 11 +---- shared/src/test/diff/ucs/ParseFailures.mls | 39 ++++++++++++++++ shared/src/test/diff/ucs/Tree.mls | 42 +++++++++++++++++ shared/src/test/diff/ucs/WeirdIf.mls | 1 - 6 files changed, 131 insertions(+), 25 deletions(-) create mode 100644 shared/src/test/diff/ucs/ParseFailures.mls create mode 100644 shared/src/test/diff/ucs/Tree.mls diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index d50352f920..f39f502a7d 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -104,13 +104,21 @@ fun list8(x, y, z, w, v, u, t, s) = Cons(x, list7(y, z, w, v, u, t, s)) //│ fun list7: forall 'A. ('A, 'A, 'A, 'A, 'A, 'A, 'A,) -> Cons['A] //│ fun list8: forall 'A. ('A, 'A, 'A, 'A, 'A, 'A, 'A, 'A,) -> Cons['A] +fun findFirst(list, p) = + if list is + Nil then None + Cons(x, xs) and + p(x) then Some(x) + else findFirst(xs, p) +//│ fun findFirst: forall 'A. (Cons['A] | Nil, 'A -> anything,) -> (None | Some['A]) + fun listConcat(xs, ys) = if xs is Nil then ys Cons(x, xs') then Cons(x, listConcat(xs', ys)) -//│ fun listConcat: forall 'A 'a 'A0. (Cons['A0] | Nil, List['A] & 'a,) -> (Cons['A] | 'a) +//│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) //│ where -//│ 'A0 <: 'A +//│ 'A <: 'A0 fun listContains(xs, x) = if xs is diff --git a/shared/src/test/diff/ucs/Exhaustiveness.mls b/shared/src/test/diff/ucs/Exhaustiveness.mls index 716d3b35dd..cd476faa27 100644 --- a/shared/src/test/diff/ucs/Exhaustiveness.mls +++ b/shared/src/test/diff/ucs/Exhaustiveness.mls @@ -1,15 +1,12 @@ -:NewParser +:NewDefs :NoJS class A() class B() class C() -//│ Defined class A -//│ Defined class B -//│ Defined class C -//│ A: () -> A -//│ B: () -> B -//│ C: () -> C +//│ class A() +//│ class B() +//│ class C() :e fun f(x, y) = @@ -23,17 +20,47 @@ fun f(x, y) = x is A then 4 //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.23: x is +//│ ║ l.20: x is //│ ║ ^^^^ //│ ╟── The scrutinee at this position misses 2 cases. -//│ ║ l.23: x is +//│ ║ l.20: x is //│ ║ ^ //│ ╟── [Missing Case 1/2] `B` //│ ╟── It first appears here. -//│ ║ l.20: B then 1 +//│ ║ l.17: B then 1 //│ ║ ^ //│ ╟── [Missing Case 2/2] `C` //│ ╟── It first appears here. -//│ ║ l.21: C then 2 +//│ ║ l.18: C then 2 //│ ╙── ^ -//│ f: (anything, anything,) -> error +//│ fun f: (anything, anything,) -> error + +:e +// These operators are uninterpreted. So, it's impossible to reason the +// exhaustiveness without SMT solvers. +type Tree[A] = Node[A] | Empty +module Empty { + fun contains(wanted) = false +} +class Node[A](value: int, left: Tree[A], right: Tree[A]) { + fun contains(wanted) = if wanted + <= value then left.find(wanted) + >= value then right.find(wanted) + == value then true +} +//│ ╔══[ERROR] The case when this is false is not handled: == (wanted,) (value,) +//│ ║ l.46: fun contains(wanted) = if wanted +//│ ║ ^^^^^^ +//│ ║ l.47: <= value then left.find(wanted) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.48: >= value then right.find(wanted) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.49: == value then true +//│ ╙── ^^^^^^^^^^^^ +//│ type Tree[A] = Node[A] | Empty +//│ module Empty() { +//│ fun contains: anything -> false +//│ } +//│ class Node[A](value: int, left: Tree[A], right: Tree[A]) { +//│ fun contains: anything -> error +//│ } diff --git a/shared/src/test/diff/ucs/Humiliation.mls b/shared/src/test/diff/ucs/Humiliation.mls index c650b48040..72c293c0b1 100644 --- a/shared/src/test/diff/ucs/Humiliation.mls +++ b/shared/src/test/diff/ucs/Humiliation.mls @@ -179,18 +179,9 @@ fun foo(x, y) = if x is Z() and y is O() then 0 else 1 //│ foo: (anything, anything,) -> (0 | 1) //│ = [Function: foo7] -:pe -fun foo(x, y) = if x is - Z() and y is O() then 0 else 1 -//│ ╔══[PARSE ERROR] Unexpected 'else' keyword here -//│ ║ l.184: Z() and y is O() then 0 else 1 -//│ ╙── ^^^^ -//│ foo: (Z, O,) -> 0 -//│ = [Function: foo8] - fun foo(x, y) = if x is Z() and y is O() then 0 else 1 //│ foo: (anything, anything,) -> (0 | 1) -//│ = [Function: foo9] +//│ = [Function: foo8] diff --git a/shared/src/test/diff/ucs/ParseFailures.mls b/shared/src/test/diff/ucs/ParseFailures.mls new file mode 100644 index 0000000000..2e9428c8be --- /dev/null +++ b/shared/src/test/diff/ucs/ParseFailures.mls @@ -0,0 +1,39 @@ +:NewDefs +:NoJS + +// FIXME +type Tree[A] = Node[A] | Empty +module Empty { + fun contains(wanted) = false +} +class Node[A](value: int, left: Tree[A], right: Tree[A]) { + fun contains(wanted) = if wanted + <= value then left.find(wanted) + >= value then right.find(wanted) + else true +} +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + +// FIXME +type Tree[A] = Node[A] | Empty +module Empty { + fun contains(wanted) = false +} +class Node[A](value: int, left: Tree[A], right: Tree[A]) { + fun contains(wanted) = if wanted + <= value then left.find(wanted) + >= value then right.find(wanted) + _ true +} +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + +// FIXME +fun foo(x, y) = if x is + Z() and y is O() then 0 else 1 +//│ ╔══[PARSE ERROR] Unexpected 'else' keyword here +//│ ║ l.32: Z() and y is O() then 0 else 1 +//│ ╙── ^^^^ +//│ ╔══[ERROR] Illegal pattern `Z` +//│ ║ l.32: Z() and y is O() then 0 else 1 +//│ ╙── ^ +//│ fun foo: (anything, anything,) -> error diff --git a/shared/src/test/diff/ucs/Tree.mls b/shared/src/test/diff/ucs/Tree.mls new file mode 100644 index 0000000000..c4af73ef95 --- /dev/null +++ b/shared/src/test/diff/ucs/Tree.mls @@ -0,0 +1,42 @@ +:NewDefs + +type Option[A] = Some[A] | None +class Some[A](value: A) +module None +//│ type Option[A] = Some[A] | None +//│ class Some[A](value: A) +//│ module None() + +type Tree[A] = Node[A] | Empty +module Empty +class Node[A](value: int, left: Tree[A], right: Tree[A]) +//│ type Tree[A] = Node[A] | Empty +//│ module Empty() +//│ class Node[A](value: int, left: Tree[A], right: Tree[A]) + +fun find(t, v) = if t is + Node(v', l, r) and + v < v' then find(l, v) + v > v' then find(r, v) + _ then Some(v) + Empty then None +//│ fun find: forall 'A 'A0. (Empty | Node['A], number & 'A0,) -> (None | Some['A0]) + +fun insert(t, v) = if t is + Node(v', l, r) and + v < v' then Node(v', insert(l, v), r) + v > v' then Node(v', l, insert(r, v)) + _ then t + Empty then Node(v, Empty, Empty) +//│ fun insert: forall 'A. (Empty | Node['A], int,) -> Node['A] + +find(Empty, 0) +find(Node(0, Empty, Empty), 0) +find(Node(1, Empty, Empty), 0) +//│ None | Some[0] +//│ res +//│ = None { class: [class None] } +//│ res +//│ = Some {} +//│ res +//│ = None { class: [class None] } diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index 5cbae091a0..bda4d5a855 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -99,7 +99,6 @@ fun f(x) = //│ f: anything -> "bruh" //│ = [Function: f3] -// Hmmmmmm, this one is valid but how to get it work? fun boolToStr(x) = if x is true then "yah" From 9a8e6aa6355f9e2831aef7c85eea8f5dc238d0e9 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 23 Mar 2023 12:13:11 +0800 Subject: [PATCH 223/498] Support subclass refinement and preemptive wildcard branches --- .../src/main/scala/mlscript/ucs/Clause.scala | 6 +- .../main/scala/mlscript/ucs/Conjunction.scala | 21 ++- .../main/scala/mlscript/ucs/Desugarer.scala | 173 ++++++++++++++--- .../main/scala/mlscript/ucs/MutCaseOf.scala | 178 +++++++++++------- shared/src/test/diff/nu/FilterMap.mls | 2 +- shared/src/test/diff/tapl/Untyped.mls | 8 +- shared/src/test/diff/ucs/InterleavedLet.mls | 22 +-- .../src/test/diff/ucs/OverlappedBranches.mls | 100 ++++++++++ shared/src/test/diff/ucs/TrivialIf.mls | 10 +- shared/src/test/diff/ucs/Wildcard.mls | 156 +++++++++++++++ 10 files changed, 553 insertions(+), 123 deletions(-) create mode 100644 shared/src/test/diff/ucs/OverlappedBranches.mls diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index 2eeed3d8cb..12cd4c1c04 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -41,9 +41,9 @@ object Clause { override def toString(): String = s"«$scrutinee is $literal" + bindingsToString } - // final case class MatchNot(override val scrutinee: Scrutinee)(override val locations: Ls[Loc]) extends MatchClause { - // override def toString(): String = s"otherwise of «$scrutinee»" + bindingsToString - // } + final case class MatchAny(override val scrutinee: Scrutinee)(override val locations: Ls[Loc]) extends MatchClause { + override def toString(): String = s"«$scrutinee is any" + bindingsToString + } final case class MatchClass( override val scrutinee: Scrutinee, diff --git a/shared/src/main/scala/mlscript/ucs/Conjunction.scala b/shared/src/main/scala/mlscript/ucs/Conjunction.scala index f657b0b347..685f99f2e8 100644 --- a/shared/src/main/scala/mlscript/ucs/Conjunction.scala +++ b/shared/src/main/scala/mlscript/ucs/Conjunction.scala @@ -9,6 +9,15 @@ import scala.annotation.tailrec * A `Conjunction` represents a list of `Clause`s. */ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[LetBinding]) { + override def toString(): String = + clauses.mkString("", " and ", "") + { + (if (trailingBindings.isEmpty) "" else " ") + + (trailingBindings match { + case Nil => "" + case bindings => bindings.map(_.name.name).mkString("(", ", ", ")") + }) + } + /** * Concatenate two `Conjunction` together. * @@ -82,12 +91,12 @@ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[LetBindin } else { rec(past :+ head, tail) } - // case (head @ MatchNot(scrutinee)) :: tail => - // if (scrutinee === expectedScrutinee) { - // S((past, head, tail)) - // } else { - // rec(past :+ head, tail) - // } + case (head @ MatchAny(scrutinee)) :: tail => + if (scrutinee === expectedScrutinee) { + rec(past, tail) // Hmmmm, does it always work? + } else { + rec(past :+ head, tail) + } case head :: tail => rec(past :+ head, tail) } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 79d40420fb..98888beb50 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -6,6 +6,7 @@ import scala.collection.mutable.Buffer import mlscript._, utils._, shorthands._ import helpers._ import Message.MessageContext +import mlscript.ucs.MutCaseOf.MutCase.Constructor /** * This class contains main desugaring methods. @@ -16,7 +17,7 @@ class Desugarer extends TypeDefs { self: Typer => private def traceUCS[T](pre: => String)(thunk: => T)(post: T => String = noPostTrace) = if (dbgUCS) trace(pre)(thunk)(post) else thunk - import Desugarer.ExhaustivenessMap + import Desugarer.{ExhaustivenessMap, SubClassMap, SuperClassMap} import Clause.{MatchClass, MatchTuple, BooleanTest} type FieldAliasMap = MutMap[SimpleTerm, MutMap[Str, Var]] @@ -39,6 +40,11 @@ class Desugarer extends TypeDefs { self: Typer => private type MutExhaustivenessMap = MutMap[Str \/ Int, MutMap[Either[Int, SimpleTerm], Buffer[Loc]]] + private def addToExhaustivenessMap(scrutinee: Scrutinee, loc: Iterable[Loc]) + (implicit ctx: Ctx, raise: Raise, map: MutExhaustivenessMap) = { + map.getOrElseUpdate(getScurtineeKey(scrutinee), MutMap.empty) + } + private def addToExhaustivenessMap(scrutinee: Scrutinee, tupleArity: Int, loc: Iterable[Loc]) (implicit ctx: Ctx, raise: Raise, map: MutExhaustivenessMap) = { map.getOrElseUpdate(getScurtineeKey(scrutinee), MutMap.empty) @@ -180,8 +186,10 @@ class Desugarer extends TypeDefs { self: Typer => pattern match { // This case handles top-level wildcard `Var`. // We don't make any conditions in this level. - // case wildcard @ Var("_") if isTopLevel => - // Clause.MatchNot(scrutinee)(wildcard.toLoc.toList) :: Nil + case wildcard @ Var("_") if isTopLevel => + addToExhaustivenessMap(scrutinee, wildcard.toLoc) + Clause.MatchAny(scrutinee)(wildcard.toLoc.toList) :: Nil + // If it's not top-level, wildcard means we don't care. case Var("_") => Nil // This case handles literals. // x is true | x is false | x is 0 | x is "text" | ... @@ -200,7 +208,18 @@ class Desugarer extends TypeDefs { self: Typer => // This case handles name binding. // x is a case bindingVar @ Var(bindingName) if bindingName.headOption.exists(_.isLower) => - Clause.Binding(bindingVar, scrutinee.term, !isTopLevel)(scrutinee.term.toLoc.toList ::: bindingVar.toLoc.toList) :: Nil + val locations = scrutinee.term.toLoc.toList ::: bindingVar.toLoc.toList + if (isTopLevel) { + // If the binding name is at the top-level. We create decision path like + // ... /\ x is any /\ a = x /\ ... + addToExhaustivenessMap(scrutinee, bindingVar.toLoc) + Clause.MatchAny(scrutinee)(locations) :: + Clause.Binding(bindingVar, scrutinee.reference, !isTopLevel)(locations) :: + Nil + } else { + // Otherwise, we just create the binding. + Clause.Binding(bindingVar, scrutinee.term, !isTopLevel)(locations) :: Nil + } // This case handles simple class tests. // x is A case classNameVar @ Var(className) => @@ -337,6 +356,10 @@ class Desugarer extends TypeDefs { self: Typer => * @return the desugared term */ def desugarIf(elf: If)(implicit ctx: Ctx, raise: Raise): Term = traceUCS("[desugarIf]") { + val superClassMap = getClassHierarchy() + Desugarer.printGraph(superClassMap, printlnUCS, "Super-class map", "<:") + val subClassMap = Desugarer.reverseGraph(superClassMap) + Desugarer.printGraph(subClassMap, printlnUCS, "Sub-class map", ":>") val (body, els) = unfoldNestedIf(elf) val exhaustivenessMap: MutExhaustivenessMap = MutMap.empty printlnUCS("### Desugar the UCS to decision paths ###") @@ -361,9 +384,9 @@ class Desugarer extends TypeDefs { self: Typer => } printlnUCS("### Build a case tree from decision paths ###") val imExhaustivenessMap = Map.from(exhaustivenessMap.iterator.map { case (k, m) => k -> Map.from(m) }) - val caseTree = buildCaseTree(paths)(raise, getScurtineeKey, imExhaustivenessMap) + val caseTree = buildCaseTree(paths)(raise, getScurtineeKey, imExhaustivenessMap, superClassMap) printlnUCS("### Checking exhaustiveness of the case tree ###") - checkExhaustive(caseTree, N)(imExhaustivenessMap, ctx, raise) + checkExhaustive(caseTree, N)(ctx, raise, imExhaustivenessMap, subClassMap) printlnUCS("### Construct a term from the case tree ###") val desugared = constructTerm(caseTree) println(s"Desugared term: ${desugared.print(false)}") @@ -601,15 +624,8 @@ class Desugarer extends TypeDefs { self: Typer => // Add the fallback case to conjunctions if there is any. fallback.foreach { branches += Conjunction.empty -> _ } printlnUCS("Decision paths:") - branches.foreach { case Conjunction(clauses, trailingBindings) -> term => - printlnUCS("+ " + clauses.mkString("", " and ", "") + { - (if (trailingBindings.isEmpty) "" else " ") + - (trailingBindings match { - case Nil => "" - case bindings => bindings.map(_.name.name).mkString("(", ", ", ")") - }) + - s" => $term" - }) + branches.foreach { case conjunction -> term => + printlnUCS(s"+ $conjunction => $term") } branches.toList }(r => s"[desugarIf] produces ${r.size} ${"path".pluralize(r.size)}") @@ -654,7 +670,10 @@ class Desugarer extends TypeDefs { self: Typer => */ private def checkExhaustive (t: MutCaseOf, parentOpt: Opt[MutCaseOf]) - (implicit scrutineePatternMap: ExhaustivenessMap, ctx: Ctx, raise: Raise) + (implicit ctx: Ctx, + raise: Raise, + exhaustivenessMap: ExhaustivenessMap, + subClassMap: SubClassMap) : Unit = traceUCS(s"[checkExhaustive] ${t.describe}") { t match { case _: Consequent => () @@ -673,13 +692,13 @@ class Desugarer extends TypeDefs { self: Typer => checkExhaustive(whenFalse, S(t)) checkExhaustive(whenTrue, S(t)) case Match(scrutinee, branches, default) => - scrutineePatternMap.get(getScurtineeKey(scrutinee)) match { + exhaustivenessMap.get(getScurtineeKey(scrutinee)) match { case N => lastWords(s"unreachable case: unknown scrutinee ${scrutinee.term}") case S(_) if default.isDefined => printlnUCS("The match has a default branch. So, it is always safe.") case S(patternMap) => printlnUCS(s"The exhaustiveness map is") - scrutineePatternMap.foreach { case (key, matches) => + exhaustivenessMap.foreach { case (key, matches) => printlnUCS(s"- $key -> ${matches.keysIterator.mkString(", ")}") } printlnUCS(s"The scrutinee key is ${getScurtineeKey(scrutinee)}") @@ -688,6 +707,14 @@ class Desugarer extends TypeDefs { self: Typer => printlnUCS("") else patternMap.foreach { case (key, mutCase) => printlnUCS(s"- $key => $mutCase")} + // Compute all classes that can be covered by this match. + val coveredClassNames = Set.from[String](branches.iterator.flatMap { + case MutCase.Literal(_, _) => Nil + case Constructor(Var(className) -> _, _) => + subClassMap.get(className).fold[List[String]](Nil)(identity) + }) + printlnUCS("The match can cover following classes") + printlnUCS(coveredClassNames.mkString("{", ", ", "}")) // Filter out missing cases in `branches`. val missingCases = patternMap.removedAll(branches.iterator.map { case MutCase.Literal(lit, _) => R(lit) @@ -700,7 +727,12 @@ class Desugarer extends TypeDefs { self: Typer => } case _ => R(classNameVar) } - }) + }).filter { // Remove classes subsumed by super classes. + case R(Var(className)) -> _ => + !coveredClassNames.contains(className) + case L(_) -> _ => true // Tuple. Don't remove. + case R(_) -> _ => true // Literals. Don't remove. + } printlnUCS("Missing cases") missingCases.foreach { case (key, m) => printlnUCS(s"- $key -> ${m}") @@ -815,7 +847,8 @@ class Desugarer extends TypeDefs { self: Typer => */ def rec(m: MutCaseOf)(implicit defs: Set[Var]): Term = traceUCS(s"[rec] ${m.describe} -| {${defs.mkString(", ")}}") { m match { - case Consequent(term) => term + case Consequent(term) => + mkBindings(m.getBindings.toList, term, defs) case Match(scrutinee, branches, wildcard) => printlnUCS("• Owned let bindings") val ownedBindings = m.getBindings.iterator.filterNot { @@ -839,12 +872,34 @@ class Desugarer extends TypeDefs { self: Typer => interleavedBindings.foreach { case LetBinding(_, _, name, value) => printlnUCS(s" * $name = $value") } - val cases = traceUCS("• For each case branch"){ - rec2(branches.toList)(defs, scrutinee, wildcard) - }(_ => "• End for each") - val resultTerm = scrutinee.local match { - case N => CaseOf(scrutinee.term, cases) - case S(aliasVar) => Let(false, aliasVar, scrutinee.term, CaseOf(aliasVar, cases)) + val resultTerm = if (branches.isEmpty) { + // If the match does not have any branches. + wildcard match { + case None => + // Internal error! + printlnUCS("• The match has neither branches nor default case") + throw new DesugaringException({ + import Message.MessageContext + msg"found an empty match" + }, scrutinee.term.toLoc) + case Some(default) => + printlnUCS("• Degenerated case: the match only has a wildcard") + val subTerm = rec(default) + scrutinee.local match { + case N => subTerm + case S(aliasVar) => Let(false, aliasVar, scrutinee.term, subTerm) + } + } + } else { + // If the match has some branches. + printlnUCS("• The match has some case branches") + val cases = traceUCS("• For each case branch"){ + rec2(branches.toList)(defs, scrutinee, wildcard) + }(_ => "• End for each") + scrutinee.local match { + case N => CaseOf(scrutinee.term, cases) + case S(aliasVar) => Let(false, aliasVar, scrutinee.term, CaseOf(aliasVar, cases)) + } } mkBindings(ownedBindings, mkBindings(interleavedBindings, resultTerm, defs), defs) case MissingCase => @@ -908,7 +963,8 @@ class Desugarer extends TypeDefs { self: Typer => (paths: Ls[Conjunction -> Term]) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap) + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap) : MutCaseOf = traceUCS("[buildCaseTree]") { paths match { case Nil => MissingCase @@ -919,6 +975,7 @@ class Desugarer extends TypeDefs { self: Typer => }() remaining.foreach { path => root.merge(path) + printlnUCS(s"*** Merging `${path._1} => ${path._2}` ***") traceUCS("*** Updated tree ***") { MutCaseOf.show(root).foreach(printlnUCS(_)) }() @@ -926,6 +983,28 @@ class Desugarer extends TypeDefs { self: Typer => root } }(_ => "[buildCaseTree]") + + private def getClassHierarchy()(implicit ctx: Ctx): SuperClassMap = + traceUCS("[getClassHierarchy]") { + // ctx.tyDefs + val superClassMap = ctx.tyDefs.iterator + .filter(_._2.toLoc.isDefined) + .map { case (className, td) => + className -> td.baseClasses.iterator.map(_.name).toList + } |> Map.from + Desugarer.transitiveClosure(superClassMap) + // ctx.tyDefs2 + // val superClassMap = ctx.tyDefs2.iterator.map { case (className, dti) => + // className -> dti.decl.body + // } |> Map.from + // printlnUCS("• ctx.tyDefs") + // if (superClassMap.isEmpty) + // printlnUCS(" * ") + // else + // superClassMap.foreach { case (className, superClassNames) => + // printlnUCS(s" * $className <- ${superClassNames.mkString(", ")}") + // } + }(_ => "[getClassHierarchy]") } object Desugarer { @@ -933,4 +1012,44 @@ object Desugarer { * A map from each scrutinee term to all its cases and the first `MutCase`. */ type ExhaustivenessMap = Map[Str \/ Int, Map[Either[Int, SimpleTerm], Buffer[Loc]]] + + type SuperClassMap = Map[String, List[String]] + + type SubClassMap = Map[String, List[String]] + + def reverseGraph(graph: Map[String, List[String]]): Map[String, List[String]] = { + graph.iterator.flatMap { case (source, targets) => targets.iterator.map(_ -> source) } + .foldLeft(Map.empty[String, List[String]]) { case (map, target -> source) => + map.updatedWith(target) { + case None => Some(source :: Nil) + case Some(sources) => Some(source :: sources) + } + } + } + + def transitiveClosure(graph: Map[String, List[String]]): Map[String, List[String]] = { + def dfs(vertex: String, visited: Set[String]): Set[String] = { + if (visited.contains(vertex)) visited + else graph.getOrElse(vertex, List()) + .foldLeft(visited + vertex)((acc, v) => dfs(v, acc)) + } + + graph.keys.map { vertex => + val closure = dfs(vertex, Set()) + vertex -> (closure - vertex).toList + }.toMap + } + + def printGraph(graph: Map[String, List[String]], print: (=> Any) => Unit, title: String, arrow: String): Unit = { + print(s"• $title") + if (graph.isEmpty) + print(" + ") + else + graph.foreach { case (source, targets) => + print(s" + $source $arrow " + { + if (targets.isEmpty) s"{}" + else targets.mkString("{ ", ", ", " }") + }) + } + } } \ No newline at end of file diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index 2ed7ebf0ce..6c39d12785 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -9,7 +9,8 @@ import scala.collection.mutable.{Map => MutMap, Set => MutSet, Buffer} import helpers._ import mlscript.ucs.MutCaseOf.Consequent import scala.collection.immutable -import Desugarer.ExhaustivenessMap +import Desugarer.{ExhaustivenessMap, SuperClassMap} +import mlscript.ucs.Clause.MatchAny sealed abstract class MutCaseOf extends WithBindings { def kind: Str = { @@ -32,14 +33,25 @@ sealed abstract class MutCaseOf extends WithBindings { def tryMerge (branch: Conjunction -> Term) - (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, exhaustivenessMap: ExhaustivenessMap): Unit = - merge(branch)(_ => (), getScrutineeKey, exhaustivenessMap) + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Unit = + merge(branch)(_ => (), getScrutineeKey, exhaustivenessMap, superClassMap) + def merge (branch: Conjunction -> Term) - (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, exhaustivenessMap: ExhaustivenessMap): Unit + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Unit + def mergeDefault (bindings: Ls[LetBinding], default: Term) - (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, exhaustivenessMap: ExhaustivenessMap): Int + (implicit raise: Diagnostic => Unit, + getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Int // TODO: Make it immutable. var locations: Ls[Loc] = Nil @@ -106,9 +118,14 @@ object MutCaseOf { def duplicate(): MutCase - def matches(expected: Var): Bool - def matches(expected: Str): Bool - def matches(expected: Lit): Bool + /** + * Check whether this case can cover the expected class or literal. + * + * @param expected the expected class name or literal + * @param superClassMap a map from each class to its super classes + * @return whether the given pattern can be covered by this case + */ + def covers(expected: SimpleTerm)(implicit superClassMap: SuperClassMap): Bool // Note 1 // ====== @@ -144,12 +161,11 @@ object MutCaseOf { ) extends MutCase { override def duplicate(): MutCase = Literal(literal, consequent.duplicate()).withLocations(locations) - override def matches(expected: Var): Bool = literal match { - case tof @ Var(n) if n === "true" || n === "false" => expected === tof - case _ => false - } - override def matches(expected: Str): Bool = false - override def matches(expected: Lit): Bool = literal === expected + override def covers(expected: SimpleTerm)(implicit superClassMap: SuperClassMap): Bool = + expected match { + case _: Lit | Var("true") | Var("false") => expected === literal + case Var(_) => false + } } /** @@ -165,15 +181,25 @@ object MutCaseOf { override def duplicate(): MutCase = Constructor(patternFields.copy(_2 = patternFields._2.clone()), consequent.duplicate()) .withLocations(locations) - override def matches(expected: Var): Bool = matches(expected.name) - override def matches(expected: Str): Bool = patternFields._1.name === expected - override def matches(expected: Lit): Bool = false + override def covers(expected: SimpleTerm)(implicit superClassMap: SuperClassMap): Bool = + expected match { + case lit: Lit => false + case Var(tof) if tof === "true" || tof === "false" => false + case Var(expectedClassName) if expectedClassName === patternFields._1.name => true + case Var(expectedClassName) => + (superClassMap.get(expectedClassName) match { + case Some(superClasses) => superClasses.contains(patternFields._1.name) + case None => + // Should we raise? + false + }) + } def addFields(fields: Iterable[Str -> Var]): Unit = patternFields._2 ++= fields.iterator.filter(!patternFields._2.contains(_)) } } - import Clause.{MatchLiteral /*, MatchNot */, MatchClass, MatchTuple, BooleanTest, Binding} + import Clause.{MatchLiteral, MatchAny, MatchClass, MatchTuple, BooleanTest, Binding} // A short-hand for pattern matchings with only true and false branches. final case class IfThenElse(condition: Term, var whenTrue: MutCaseOf, var whenFalse: MutCaseOf) extends MutCaseOf { @@ -197,7 +223,8 @@ object MutCaseOf { def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Unit = + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Unit = branch match { // The CC is a wildcard. So, we call `mergeDefault`. case Conjunction(Nil, trailingBindings) -> term => @@ -228,7 +255,8 @@ object MutCaseOf { def mergeDefault(bindings: Ls[LetBinding], default: Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Int = { + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Int = { whenTrue.mergeDefault(bindings, default) + { whenFalse match { case Consequent(term) => 0 @@ -267,7 +295,8 @@ object MutCaseOf { def merge(originalBranch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Unit = { + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Unit = { // Remove let bindings that already has been declared. val branch = originalBranch._1.copy(clauses = originalBranch._1.clauses.filter { case Binding(name, value, false) if (getBindings.exists { @@ -285,7 +314,7 @@ object MutCaseOf { case Conjunction((head @ MatchTuple(scrutinee2, arity, fields)) :: tail, trailingBindings) -> term if scrutinee2 === scrutinee => // Same scrutinee! val tupleClassName = Var(s"Tuple#$arity") // TODO: Find a name known by Typer. - branches.find(_.matches(tupleClassName)) match { + branches.find(_.covers(tupleClassName)) match { // No such pattern. We should create a new one. case N | S(MutCase.Literal(_, _)) => val newBranch = buildFirst(Conjunction(tail, trailingBindings), term) @@ -320,34 +349,48 @@ object MutCaseOf { } // Found a match condition against the same scrutinee case S((head @ MatchClass(_, className, fields)) -> remainingConditions) => - branches.find(_.matches(className)) match { + // Find all branches which can cover the `className`. + val inclusiveBranches = branches.iterator.filter(_.covers(className)) + if (inclusiveBranches.isEmpty) { // No such pattern. We should create a new one. - case N | S(MutCase.Literal(_, _)) => - wildcard match { - case S(default) if !default.isComplete => - val subTree = default.duplicate() - subTree.fill(buildFirst(remainingConditions, branch._2)) - subTree.addBindings(head.bindings) - branches += MutCase.Constructor(className -> Buffer.from(fields), subTree) - .withLocations(head.locations) - case S | N => - val newBranch = buildFirst(remainingConditions, branch._2) - newBranch.addBindings(head.bindings) - branches += MutCase.Constructor(className -> Buffer.from(fields), newBranch) - .withLocations(head.locations) - } - // Found existing pattern. - case S(matchCase: MutCase.Constructor) => - // Merge interleaved bindings. - matchCase.consequent.addBindings(head.bindings) - matchCase.addFields(fields) - matchCase.consequent.merge(remainingConditions -> branch._2) + wildcard match { + case Some(default) if !default.isComplete => + val subTree = default.duplicate() + subTree.fill(buildFirst(remainingConditions, branch._2)) + subTree.addBindings(head.bindings) + branches += MutCase.Constructor(className -> Buffer.from(fields), subTree) + .withLocations(head.locations) + case Some(_) | None => + val newBranch = buildFirst(remainingConditions, branch._2) + newBranch.addBindings(head.bindings) + branches += MutCase.Constructor(className -> Buffer.from(fields), newBranch) + .withLocations(head.locations) + } + } else { + // Found some branches that can cover the `className`. + inclusiveBranches.foreach { + case MutCase.Literal(_, _) => () // This shouldn't happen. + case matchedCase @ MutCase.Constructor(Var(branchClassName) -> _, _) => + if (branchClassName === className.name) { + // This branch exactly matches the given class name. + // So, we just do a simple merge. + // Merge interleaved bindings. + matchedCase.consequent.addBindings(head.bindings) + matchedCase.addFields(fields) + matchedCase.consequent.merge(remainingConditions -> branch._2) + } else { + // This branch matches the super classes of the given class name. + // There will be refinement matches inside the consequent. + // Therefore, we should not merge with `remainingConditions`. + // Instead, we should use the original conjunction. + matchedCase.consequent.addBindings(head.bindings) + matchedCase.addFields(fields) + matchedCase.consequent.merge(branch) + } + } } case S((head @ MatchLiteral(_, literal)) -> remainingConditions) => - branches.find(branch => literal match { - case v: Var => branch.matches(v) - case l: Lit => branch.matches(l) - }) match { + branches.find(_.covers(literal)) match { // No such pattern. We should create a new one. case N | S(MutCase.Constructor(_, _)) => val newConsequent = buildFirst(remainingConditions, branch._2) @@ -359,20 +402,21 @@ object MutCaseOf { matchCase.consequent.addBindings(head.bindings) matchCase.consequent.merge(remainingConditions -> branch._2) } - // case S((head @ MatchNot(_)) -> remainingConditions) => - // wildcard match { - // // No wildcard. We will create a new one. - // case N => wildcard = S(buildFirst(remainingConditions, branch._2)) - // // There is a wildcard case. Just merge! - // case S(consequent) => consequent.merge(remainingConditions -> branch._2) - // } + case S((head @ MatchAny(_)) -> remainingConditions) => + wildcard match { + // No wildcard. We will create a new one. + case N => wildcard = S(buildFirst(remainingConditions, branch._2)) + // There is a wildcard case. Just merge! + case S(consequent) => consequent.merge(remainingConditions -> branch._2) + } } } def mergeDefault(bindings: Ls[LetBinding], default: Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Int = { + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Int = { branches.iterator.map { case MutCase.Constructor(_, consequent) => consequent.mergeDefault(bindings, default) case MutCase.Literal(_, consequent) => consequent.mergeDefault(bindings, default) @@ -398,7 +442,8 @@ object MutCaseOf { def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Unit = + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Unit = raise { import scala.collection.mutable.ListBuffer val buffer = ListBuffer.empty[Message -> Opt[Loc]] @@ -419,7 +464,8 @@ object MutCaseOf { def mergeDefault(bindings: Ls[LetBinding], default: Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Int = 0 + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Int = 0 } final case object MissingCase extends MutCaseOf { def describe: Str = "MissingCase" @@ -433,18 +479,21 @@ object MutCaseOf { def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Unit = + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Unit = lastWords("`MissingCase` is a placeholder and cannot be merged") def mergeDefault(bindings: Ls[LetBinding], default: Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): Int = 0 + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): Int = 0 } def buildFirst(conjunction: Conjunction, term: Term) (implicit getScrutineeKey: Scrutinee => Str \/ Int, - exhaustivenessMap: ExhaustivenessMap): MutCaseOf = { + exhaustivenessMap: ExhaustivenessMap, + superClassMap: SuperClassMap): MutCaseOf = { def rec(conjunction: Conjunction): MutCaseOf = conjunction match { case Conjunction(head :: tail, trailingBindings) => lazy val (beforeHeadBindings, afterHeadBindings) = head.bindings.partition { @@ -459,10 +508,9 @@ object MutCaseOf { ) Match(scrutinee, branches, N) .withBindings(beforeHeadBindings) - case BooleanTest(test) => - IfThenElse(test, consequentTree, MissingCase) + case MatchAny(scrutinee) => + Match(scrutinee, Buffer.empty, S(consequentTree.withBindings(afterHeadBindings))) .withBindings(beforeHeadBindings) - .withBindings(afterHeadBindings) case MatchClass(scrutinee, className, fields) => val branches = Buffer[MutCase]( MutCase.Constructor(className -> Buffer.from(fields), consequentTree.withBindings(afterHeadBindings)) @@ -475,6 +523,10 @@ object MutCaseOf { .withLocations(head.locations) ) Match(scrutinee, branches, N).withBindings(beforeHeadBindings) + case BooleanTest(test) => + IfThenElse(test, consequentTree, MissingCase) + .withBindings(beforeHeadBindings) + .withBindings(afterHeadBindings) case Binding(name, term, isField) => val kind = if (isField) LetBinding.Kind.FieldExtraction diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 916cfcdd35..56b9cecccb 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -49,7 +49,7 @@ fun filtermap(f, xs) = if xs is True then filtermap(f, ys) False then Cons(y, filtermap(f, ys)) Pair(True, z) then Cons(z, filtermap(f, ys)) -//│ fun filtermap: forall 'head 'A. ('head -> (False | Pair[True, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) +//│ fun filtermap: forall 'A 'head. ('head -> (False | Pair[True, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) fun mkString(xs) = if xs is diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls index 4a2c6d937b..ace6292343 100644 --- a/shared/src/test/diff/tapl/Untyped.mls +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -479,14 +479,14 @@ fun showStepByValue(t) = ) //│ showStepByValue: ('rhs & (Abs | App & 'a | Var)) -> string //│ where -//│ 'a <: {lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), rhs: 'rhs2 & 'lhs & 'rhs0 & 'rhs3 & (Abs | App & 'a | Var)} -//│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var +//│ 'a <: {lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), rhs: 'lhs & 'rhs0 & 'rhs2 & 'rhs3 & (Abs | App & 'a | Var)} +//│ 'rhs2 <: Abs & {rhs: 'rhs2} | App & {lhs: 'rhs2, rhs: 'rhs2} | Var | ~Abs & ~App & ~Var //│ 'rhs1 <: Abs & 'b | App & 'c | Var & 'd | 'e & ~#Abs & ~#App & ~#Var -//│ 'b <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'c | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'd | {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'e & ~#Abs & ~#App & ~#Var) +//│ 'b <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'c | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'd | {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'e & ~#Abs & ~#App & ~#Var) //│ 'd <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {name: anything} & 'b | App & {name: anything} & 'c | Var | {name: anything} & 'e & ~#Abs & ~#App & ~#Var) //│ 'e <: 'rhs4 & 'lhs & 'rhs0 & (Abs & 'b | App & 'c | Var & 'd | ~#Abs & ~#App & ~#Var) //│ 'c <: {lhs: 'rhs1, rhs: 'rhs1} -//│ 'rhs2 <: 'rhs1 & 'rhs4 +//│ 'rhs3 <: 'rhs1 & 'rhs4 //│ 'rhs4 <: Abs & {lhs: Var, rhs: 'rhs4} | App & {lhs: 'rhs4, rhs: 'rhs4} | Var //│ 'lhs <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | ~Abs //│ 'rhs0 <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | App & {lhs: 'lhs & 'rhs0, rhs: 'rhs0} | Var diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index a8b4c2d669..da9652d912 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -252,10 +252,10 @@ fun mapPartition(f, xs) = let r = res.snd Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: 'fst, snd: 'tail0}) +//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: 'fst, snd: 'snd}) //│ where -//│ 'tail0 :> Cons & {head: 'rightValue, tail: 'tail0} | Nil -//│ 'fst :> Nil | Cons & {head: 'leftValue, tail: 'fst} +//│ 'snd :> Cons & {head: 'rightValue, tail: 'snd} +//│ 'fst :> Cons & {head: 'leftValue, tail: 'fst} //│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil //│ = [Function: mapPartition] @@ -276,22 +276,20 @@ fun mapPartition2(f, xs) = Cons(x, xs) and mapPartition(f, xs) is res and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition2: ('head -> (Left | Right) & 'head0 -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), Cons & {head: 'head0, tail: 'tail} | Nil,) -> (Pair & {fst: forall 'a. Cons & {head: 'leftValue, tail: forall 'a. 'fst | 'a} | 'fst | 'a, snd: forall 'b. Cons & {head: 'rightValue, tail: forall 'b. 'fst | 'b} | 'fst | 'b}) +//│ mapPartition2: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}) & 'head0 -> (Left & {leftValue: 'leftValue0} | Right & {rightValue: 'rightValue0}) & 'head1 -> (Left | Right), Cons & {head: 'head0, tail: 'tail & 'tail0} | Nil,) -> (Pair & {fst: forall 'fst. Cons & {head: 'leftValue0, tail: forall 'fst. Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}} | Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}, snd: forall 'snd. Cons & {head: 'rightValue0, tail: forall 'snd. Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd}} | Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd}}) //│ where -//│ 'b :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'b. Nil | 'b} -//│ 'a :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'a. Nil | 'a} -//│ 'fst :> Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} | Nil +//│ 'snd :> Nil | Cons & {head: 'rightValue, tail: 'snd} +//│ 'fst :> Nil | Cons & {head: 'leftValue, tail: 'fst} +//│ 'tail0 <: Cons & {head: 'head1, tail: 'tail0} | Nil //│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil //│ = [Function: mapPartition2] mapPartition2(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) -//│ res: Pair & {fst: forall 'a. Cons & {head: 0, tail: forall 'a. 'fst | 'a} | 'fst | 'a, snd: forall 'b. Cons & {head: 0, tail: forall 'b. 'fst | 'b} | 'fst | 'b} +//│ res: Pair & {fst: forall 'fst. Cons & {head: 0, tail: forall 'fst. Nil | 'fst | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst}} | Nil | 'fst | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst}, snd: forall 'fst. Cons & {head: 0, tail: forall 'fst. Nil | 'fst | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst}} | Nil | 'fst | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst}} //│ where -//│ 'b :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'b. Nil | 'b} -//│ 'a :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'a. Nil | 'a} -//│ 'fst :> Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} | Nil +//│ 'fst :> Nil | Cons & {head: 1 | 2 | 3, tail: 'fst} //│ = Pair { -//│ fst: Cons { head: 0, tail: Cons { head: 0, tail: [Cons] } }, +//│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, //│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } //│ } diff --git a/shared/src/test/diff/ucs/OverlappedBranches.mls b/shared/src/test/diff/ucs/OverlappedBranches.mls new file mode 100644 index 0000000000..1bac22866b --- /dev/null +++ b/shared/src/test/diff/ucs/OverlappedBranches.mls @@ -0,0 +1,100 @@ +:NewParser + +class Base +class Derived1 extends Base +class Derived2 extends Base +class Derived3 extends Derived2 +//│ Defined class Base +//│ Defined class Derived1 +//│ Defined class Derived2 +//│ Defined class Derived3 +//│ Base: () -> Base +//│ = [Function: Base1] +//│ Derived1: () -> Derived1 +//│ = [Function: Derived11] +//│ Derived2: () -> Derived2 +//│ = [Function: Derived21] +//│ Derived3: () -> Derived3 +//│ = [Function: Derived31] + +// The very basic case. +:w +fun f1(x) = if x is + Base then "b" + Derived1 then "d1" + Derived2 then "d2" +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch +//│ ║ l.24: Derived1 then "d1" +//│ ║ ^^^^ +//│ ╟── is subsumed by the branch here. +//│ ║ l.23: Base then "b" +//│ ╙── ^^^ +//│ ╔══[WARNING] Found a duplicated branch +//│ ╟── This branch +//│ ║ l.25: Derived2 then "d2" +//│ ║ ^^^^ +//│ ╟── is subsumed by the branch here. +//│ ║ l.23: Base then "b" +//│ ╙── ^^^ +//│ f1: Base -> "b" +//│ = [Function: f1] + +f1(Base()) +f1(Derived1()) +f1(Derived2()) +//│ res: "b" +//│ = 'b' +//│ res: "b" +//│ = 'b' +//│ res: "b" +//│ = 'b' + +// Decision paths: +// + «x is Base» and «p (x,)» => "b and p" +// + «x is Derived1» => "d1" +// + «x is Derived2» => "d2" +// + => "otherwise" +// The case tree: +// «x» match +// case Base => +// if «p (x,)» +// «"b and p"» +// else +// «x» match +// case Derived1 => +// «"d1"» +// case Derived2 => +// «"d2"» +// default +// «"otherwise"» +// default +// «"otherwise"» +fun f2(x, p) = if x is + Base and p(x) then "b and p" + Derived1 then "d1" + Derived2 then "d2" + else "otherwise" +//│ f2: (Base & 'a | ~Base, 'a -> anything,) -> ("b and p" | "d1" | "d2" | "otherwise") +//│ = [Function: f2] + +f2(Base(), _ => true) // => b and p +f2(Base(), _ => false) // otherwise +//│ res: "b and p" | "d1" | "d2" | "otherwise" +//│ = 'b and p' +//│ res: "b and p" | "d1" | "d2" | "otherwise" +//│ = 'otherwise' + +f2(Derived1(), _ => true) // => b and p +f2(Derived2(), _ => true) // => b and p +//│ res: "b and p" | "d1" | "d2" | "otherwise" +//│ = 'b and p' +//│ res: "b and p" | "d1" | "d2" | "otherwise" +//│ = 'b and p' + +f2(Derived1(), _ => false) // => d1 +f2(Derived2(), _ => false) // => d2 +//│ res: "b and p" | "d1" | "d2" | "otherwise" +//│ = 'd1' +//│ res: "b and p" | "d1" | "d2" | "otherwise" +//│ = 'd2' diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index 80a5ad9c98..674a24768f 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -62,15 +62,11 @@ fun f(x, y) = if 42 is n then n + 1 //│ res: int -// FIXME +:w if 42 is n then n + 1 else 0 -//│ ╔══[WARNING] Found a duplicated branch -//│ ╟── This branch +//│ ╔══[WARNING] Found a redundant else branch //│ ║ l.66: if 42 is n then n + 1 else 0 -//│ ║ ^ -//│ ╟── is subsumed by the branch here. -//│ ║ l.66: if 42 is n then n + 1 else 0 -//│ ╙── ^^^^^ +//│ ╙── ^ //│ res: int diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index 9a35985928..8f046a6677 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -60,3 +60,159 @@ w2(0, x => false) //│ = 3 //│ res //│ = 4 + +fun w3(x, p) = if x is + _ and p(x) then "r1" + Some(xv) then concat("r2: ")(toString(xv)) + None then "r3" + _ then "r4" +//│ fun w3: forall 'a. (None | Some[anything] | 'a & ~#None & ~#Some, (None | Some[nothing] | 'a) -> anything,) -> string + +// Expect "r1" +w3(0, _ => true) +w3(None, _ => true) +w3(Some(0), _ => true) +//│ string +//│ res +//│ = 'r1' +//│ res +//│ = 'r1' +//│ res +//│ = 'r1' + +// Expect "r2" +w3(Some(0), _ => false) +//│ string +//│ res +//│ = 'r2: 0' + +// Expect "r3" +w3(None, _ => false) +//│ string +//│ res +//│ = 'r3' + +// Expect "r4" +w3(0, _ => false) +//│ string +//│ res +//│ = 'r4' + +:w +// Decision paths: +// + «tmp2 @ f (x,) is any => 0 +// + => 1 +fun w3_1(x, f) = + if f(x) is _ then 0 else 1 +//│ ╔══[WARNING] Found a redundant else branch +//│ ║ l.106: if f(x) is _ then 0 else 1 +//│ ╙── ^ +//│ fun w3_1: forall 'a. ('a, 'a -> anything,) -> 0 + +// FIXME +// Accidentally found some code generator errors. +w3_1(0, _ => true) +w3_1(0, _ => false) +//│ 0 +//│ res +//│ = 0 +//│ res +//│ = 0 + +:w +fun w3_1_1(x, f) = + if f(x) is a then a else 0 +//│ ╔══[WARNING] Found a redundant else branch +//│ ║ l.124: if f(x) is a then a else 0 +//│ ╙── ^ +//│ fun w3_1_1: forall 'a 'b. ('a, 'a -> 'b,) -> 'b + +w3_1_1(0, x => x) +w3_1_1(0, x => x + 1) +//│ int +//│ res +//│ = 0 +//│ res +//│ = 1 + +// Decision paths: +// + «a = x» and «p (x,)» => "r1" +// + «x is Some» => concat ("r2: ",) (toString (xv,),) +// + «x is None» => "r3" +fun w4(x, p) = if x is + a and p(x) then "r1" + Some(xv) then concat("r2: ")(toString(xv)) + None then "r3" + _ then "r4" +//│ fun w4: forall 'a. (None | Some[anything] | 'a & ~#None & ~#Some, (None | Some[nothing] | 'a) -> anything,) -> string + + +// Expect "r1" +w4(0, _ => true) +w4(None, _ => true) +w4(Some(0), _ => true) +//│ string +//│ res +//│ = 'r1' +//│ res +//│ = 'r1' +//│ res +//│ = 'r1' + +// Expect "r2" +w4(Some(0), _ => false) +//│ string +//│ res +//│ = 'r2: 0' + +// Expect "r3" +w4(None, _ => false) +//│ string +//│ res +//│ = 'r3' + +// Expect "r4" +w4(0, _ => false) +//│ string +//│ res +//│ = 'r4' + +class Alpha +class Beta +class Gamma +class Delta +//│ class Alpha() +//│ class Beta() +//│ class Gamma() +//│ class Delta() + +// This should generate only one case expression instead of a chain of case +// expressions. DO check the desugared term! +fun w5(y) = + if y is + Alpha then "alpha" + _ and y is + Beta then "beta" + _ and y is + Gamma then "gamma" + _ and y is + Delta then "delta" + _ then "unknown" +//│ fun w5: anything -> ("alpha" | "beta" | "delta" | "gamma" | "unknown") + +w5(0) +w5(Alpha()) +w5(Beta()) +w5(Gamma()) +w5(Delta()) +//│ "alpha" | "beta" | "delta" | "gamma" | "unknown" +//│ res +//│ = 'unknown' +//│ res +//│ = 'alpha' +//│ res +//│ = 'beta' +//│ res +//│ = 'gamma' +//│ res +//│ = 'delta' From 522f8fbc813629956eb622c4a1adc478294212de Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 23 Mar 2023 16:03:21 +0800 Subject: [PATCH 224/498] Consume `MatchAny` and try to merge inexhaustive branches --- .../main/scala/mlscript/ucs/Conjunction.scala | 18 ++++---- .../main/scala/mlscript/ucs/MutCaseOf.scala | 46 ++++++++++++++++++- shared/src/test/diff/ucs/InterleavedLet.mls | 3 +- shared/src/test/diff/ucs/Wildcard.mls | 19 ++++++++ 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/shared/src/main/scala/mlscript/ucs/Conjunction.scala b/shared/src/main/scala/mlscript/ucs/Conjunction.scala index 685f99f2e8..18f03eff28 100644 --- a/shared/src/main/scala/mlscript/ucs/Conjunction.scala +++ b/shared/src/main/scala/mlscript/ucs/Conjunction.scala @@ -74,35 +74,35 @@ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[LetBindin def +(lastBinding: LetBinding): Conjunction = Conjunction(clauses, trailingBindings :+ lastBinding) - def separate(expectedScrutinee: Scrutinee): Opt[(MatchClause, Conjunction)] = { + def findClauseMatches(expectedScrutinee: Scrutinee): Opt[(MatchClause, Conjunction)] = { @tailrec - def rec(past: Ls[Clause], upcoming: Ls[Clause]): Opt[(Ls[Clause], MatchClause, Ls[Clause])] = { + def rec(past: Ls[Clause], upcoming: Ls[Clause], firstAny: Opt[(Ls[Clause], MatchAny, Ls[Clause])]): Opt[(Ls[Clause], MatchClause, Ls[Clause])] = { upcoming match { - case Nil => N + case Nil => firstAny case (head @ MatchLiteral(scrutinee, _)) :: tail => if (scrutinee === expectedScrutinee) { S((past, head, tail)) } else { - rec(past :+ head, tail) + rec(past :+ head, tail, firstAny) } case (head @ MatchClass(scrutinee, _, _)) :: tail => if (scrutinee === expectedScrutinee) { S((past, head, tail)) } else { - rec(past :+ head, tail) + rec(past :+ head, tail, firstAny) } case (head @ MatchAny(scrutinee)) :: tail => if (scrutinee === expectedScrutinee) { - rec(past, tail) // Hmmmm, does it always work? + rec(past, tail, firstAny.orElse(S((past, head, tail)))) } else { - rec(past :+ head, tail) + rec(past :+ head, tail, firstAny) } case head :: tail => - rec(past :+ head, tail) + rec(past :+ head, tail, firstAny) } } - rec(Nil, clauses).map { case (past, wanted, remaining) => + rec(Nil, clauses, None).map { case (past, wanted, remaining) => (wanted, Conjunction(past ::: remaining, trailingBindings)) } } diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index 6c39d12785..1b5f7e6d40 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -31,6 +31,9 @@ sealed abstract class MutCaseOf extends WithBindings { def isComplete: Bool + def isExhaustive(implicit getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Bool + def tryMerge (branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, @@ -116,6 +119,9 @@ object MutCaseOf { sealed abstract class MutCase { var consequent: MutCaseOf + @inline + def isComplete: Bool = consequent.isComplete + def duplicate(): MutCase /** @@ -220,6 +226,10 @@ object MutCaseOf { def isComplete: Bool = whenTrue.isComplete && whenFalse.isComplete + def isExhaustive(implicit getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Bool = + whenTrue.isExhaustive && whenFalse.isExhaustive + def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, @@ -292,6 +302,26 @@ object MutCaseOf { def isComplete: Bool = branches.forall(_.consequent.isComplete) && wildcard.forall(_.isComplete) + def isExhaustive(implicit getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Bool = { + exhaustivenessMap.get(getScrutineeKey(scrutinee)) match { + case None => ??? // TODO: Raise. + case Some(patternLocationsMap) => + // Find patterns that are not included in `branches`. + patternLocationsMap.keysIterator.filterNot { + case L(tupleArity) => branches.iterator.exists { + case MutCase.Literal(_, _) => false + case MutCase.Constructor(Var(className) -> _, _) => + className === s"Tuple#$tupleArity" + } + case R(litOrCls) => branches.iterator.exists { + case MutCase.Literal(lit, _) => litOrCls === lit + case MutCase.Constructor(cls -> _, _) => litOrCls === cls + } + }.isEmpty + } + } + def merge(originalBranch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, @@ -307,7 +337,7 @@ object MutCaseOf { case _ => true }) -> originalBranch._2 // Promote the match against the same scrutinee. - branch._1.separate(scrutinee) match { + branch._1.findClauseMatches(scrutinee) match { // No conditions against the same scrutinee. case N => branch match { @@ -354,6 +384,8 @@ object MutCaseOf { if (inclusiveBranches.isEmpty) { // No such pattern. We should create a new one. wildcard match { + // If the wildcard branch is incomplete, there might be some + // preemptive branches in front of this branch. case Some(default) if !default.isComplete => val subTree = default.duplicate() subTree.fill(buildFirst(remainingConditions, branch._2)) @@ -403,6 +435,12 @@ object MutCaseOf { matchCase.consequent.merge(remainingConditions -> branch._2) } case S((head @ MatchAny(_)) -> remainingConditions) => + // Existing branches may be complete but not exhaustive. + // Find inexhaustiveness branches and try to merge. + branches.iterator.filterNot(_.consequent.isExhaustive).foreach { + _.consequent.tryMerge(remainingConditions -> branch._2) + } + // Then, let's consider the wildcard branch. wildcard match { // No wildcard. We will create a new one. case N => wildcard = S(buildFirst(remainingConditions, branch._2)) @@ -439,6 +477,9 @@ object MutCaseOf { def isComplete: Bool = true + def isExhaustive(implicit getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Bool = true + def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, @@ -476,6 +517,9 @@ object MutCaseOf { def isComplete: Bool = false + def isExhaustive(implicit getScrutineeKey: Scrutinee => Str \/ Int, + exhaustivenessMap: ExhaustivenessMap): Bool = false + def merge(branch: Conjunction -> Term) (implicit raise: Diagnostic => Unit, getScrutineeKey: Scrutinee => Str \/ Int, diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index da9652d912..e89530159c 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -276,11 +276,10 @@ fun mapPartition2(f, xs) = Cons(x, xs) and mapPartition(f, xs) is res and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition2: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}) & 'head0 -> (Left & {leftValue: 'leftValue0} | Right & {rightValue: 'rightValue0}) & 'head1 -> (Left | Right), Cons & {head: 'head0, tail: 'tail & 'tail0} | Nil,) -> (Pair & {fst: forall 'fst. Cons & {head: 'leftValue0, tail: forall 'fst. Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}} | Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}, snd: forall 'snd. Cons & {head: 'rightValue0, tail: forall 'snd. Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd}} | Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd}}) +//│ mapPartition2: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}) & 'head0 -> (Left & {leftValue: 'leftValue0} | Right & {rightValue: 'rightValue0}), Cons & {head: 'head0, tail: 'tail} | Nil,) -> (Pair & {fst: forall 'fst. Cons & {head: 'leftValue0, tail: forall 'fst. Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}} | Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}, snd: forall 'snd. Cons & {head: 'rightValue0, tail: forall 'snd. Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd}} | Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd}}) //│ where //│ 'snd :> Nil | Cons & {head: 'rightValue, tail: 'snd} //│ 'fst :> Nil | Cons & {head: 'leftValue, tail: 'fst} -//│ 'tail0 <: Cons & {head: 'head1, tail: 'tail0} | Nil //│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil //│ = [Function: mapPartition2] diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index 8f046a6677..6b3b38b8f7 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -216,3 +216,22 @@ w5(Delta()) //│ = 'gamma' //│ res //│ = 'delta' + +fun w6(x, y) = + if x is + _ and y is + Some(z) then z + None then 0 + else x +//│ fun w6: forall 'value. ('value, Some['value] | ~Some[anything],) -> (0 | 'value) + +w6("42", Some(42)) +w6("42", None) +w6("42", "42") +//│ "42" | 0 +//│ res +//│ = 42 +//│ res +//│ = 0 +//│ res +//│ = '42' From a35a41667c15507bb6fcb98afacbc10e70ce4822 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Mar 2023 18:33:48 +0800 Subject: [PATCH 225/498] Add new UCS test cases --- shared/src/test/diff/ucs/Hygiene.mls | 15 +++++++ shared/src/test/diff/ucs/LeadingAnd.mls | 52 +++++++++++++++++++++++++ shared/src/test/diff/ucs/Or.mls | 21 ++++++++++ 3 files changed, 88 insertions(+) create mode 100644 shared/src/test/diff/ucs/Hygiene.mls create mode 100644 shared/src/test/diff/ucs/LeadingAnd.mls create mode 100644 shared/src/test/diff/ucs/Or.mls diff --git a/shared/src/test/diff/ucs/Hygiene.mls b/shared/src/test/diff/ucs/Hygiene.mls new file mode 100644 index 0000000000..554635f1be --- /dev/null +++ b/shared/src/test/diff/ucs/Hygiene.mls @@ -0,0 +1,15 @@ +:NewDefs + +class Some[T](value: T) +class Left[T](value: T) +class Right[T](value: T) +//│ class Some[T](value: T) +//│ class Left[T](value: T) +//│ class Right[T](value: T) + +// FIXME unhygienic +fun foo(x) = if x is + Some(Left(y)) then x + Some(x) then x +//│ fun foo: forall 'value. Some['value & (Left[anything] | ~#Left)] -> 'value + diff --git a/shared/src/test/diff/ucs/LeadingAnd.mls b/shared/src/test/diff/ucs/LeadingAnd.mls new file mode 100644 index 0000000000..194cbe59de --- /dev/null +++ b/shared/src/test/diff/ucs/LeadingAnd.mls @@ -0,0 +1,52 @@ +:NewDefs + + + +class Some[T](value: T) +//│ class Some[T](value: T) + + + +// TODO +fun f(a, b) = if a is + Some(av) + and b is Some(bv) then av + bv +//│ ╔══[ERROR] Cannot find operator `and` in the context +//│ ║ l.13: and b is Some(bv) then av + bv +//│ ╙── ^^^ +//│ fun f: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:p +fun f(a, b) = if a is Some(av) + and b is Some(bv) + then av + bv +//│ |#fun| |f|(|a|,| |b|)| |#=| |#if| |a| |is| |Some|(|av|)|→|and| |b| |is| |Some|(|bv|)|↵|#then| |av| |+| |bv|←| +//│ Parsed: fun f = (a, b,) => if a is Some (av,) ‹· and (is (b,) (Some (bv,),)) then + (av,) (bv,)›; +//│ fun f: (Some[int], Some[int],) -> int + +// TODO +:p +fun f(a, b) = if a is + Some(av) + and b is Some(bv) + then av + bv +//│ |#fun| |f|(|a|,| |b|)| |#=| |#if| |a| |is|→|Some|(|av|)|→|and| |b| |is| |Some|(|bv|)|↵|#then| |av| |+| |bv|←|←| +//│ Parsed: fun f = (a, b,) => if a is ‹Some (av,) ‹· and (is (b,) (Some (bv,),)) then + (av,) (bv,)››; +//│ ╔══[ERROR] Cannot find operator `and` in the context +//│ ║ l.33: and b is Some(bv) +//│ ╙── ^^^ +//│ fun f: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + + +// FIXME (parser) +fun f(a, b) = if a is + Some(av) + and b is Some(bv) then av + bv + +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + diff --git a/shared/src/test/diff/ucs/Or.mls b/shared/src/test/diff/ucs/Or.mls new file mode 100644 index 0000000000..334ecb9af2 --- /dev/null +++ b/shared/src/test/diff/ucs/Or.mls @@ -0,0 +1,21 @@ +:NewDefs + + +class Some[T](value: T) +//│ class Some[T](value: T) + + +// TODO support `or` in UCS +fun f(a, b) = if a is + Some(v) + and b is Some(v') then v + v' + or b is Some(v) then v + else 0 +//│ ╔══[ERROR] Cannot find operator `and` in the context +//│ ║ l.11: and b is Some(v') then v + v' +//│ ╙── ^^^ +//│ fun f: (anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + From 3fff2fed5f36f81f5e09cdcbf102f75d5eab3d52 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 24 Mar 2023 12:11:19 +0800 Subject: [PATCH 226/498] WIP Use intersections to refine member access types and fix various bugs --- .../scala/mlscript/ConstraintSolver.scala | 132 ++++--- .../src/main/scala/mlscript/NormalForms.scala | 10 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 8 +- .../main/scala/mlscript/TypeSimplifier.scala | 8 +- .../main/scala/mlscript/TyperDatatypes.scala | 8 +- .../main/scala/mlscript/TyperHelpers.scala | 1 + shared/src/test/diff/codegen/Mixin.mls | 11 +- shared/src/test/diff/codegen/NewClasses.mls | 16 + .../test/diff/ecoop23/ExpressionProblem.mls | 10 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 337 ++++++++++++++++-- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 27 +- shared/src/test/diff/fcp/Church_CT.mls | 4 +- shared/src/test/diff/fcp/Church_ST.mls | 4 +- shared/src/test/diff/fcp/ListBuild.mls | 2 +- .../diff/fcp/QML_exist_Classes_ST_Repro.mls | 18 +- .../test/diff/mlf-examples/ex_validate.mls | 2 +- shared/src/test/diff/mlscript/Arrays.mls | 12 +- shared/src/test/diff/mlscript/BadInherit2.mls | 2 +- .../src/test/diff/mlscript/BadInherit2Co.mls | 2 +- shared/src/test/diff/mlscript/BadMethods.mls | 4 +- shared/src/test/diff/mlscript/BadTypes.mls | 2 +- shared/src/test/diff/mlscript/HeadOption.mls | 8 +- shared/src/test/diff/mlscript/Methods.mls | 4 +- .../diff/mlscript/PolyVariantCodeReuse.mls | 4 + shared/src/test/diff/mlscript/Random2.mls | 4 +- .../src/test/diff/mlscript/RecursiveTypes.mls | 6 +- .../test/diff/mlscript/RecursiveTypes2.mls | 18 +- shared/src/test/diff/mlscript/StressUgly.mls | 6 +- shared/src/test/diff/mlscript/TypeClasses.mls | 4 +- shared/src/test/diff/mlscript/TypeRanges.mls | 14 +- shared/src/test/diff/nu/BasicClasses.mls | 11 +- shared/src/test/diff/nu/EncodedLists.mls | 8 +- shared/src/test/diff/nu/EvalNegNeg.mls | 5 +- .../test/diff/nu/ExpressionProblem_repro.mls | 2 - shared/src/test/diff/nu/FieldRefinement.mls | 31 +- shared/src/test/diff/nu/GenericClasses.mls | 47 ++- shared/src/test/diff/nu/GenericModules.mls | 89 ++++- .../test/diff/nu/PolymorphicVariants_Alt.mls | 43 +-- shared/src/test/diff/nu/SelfRec.mls | 20 +- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 62 ++++ .../diff/nu/repro_PolymorphicVariants.mls | 32 ++ 41 files changed, 776 insertions(+), 262 deletions(-) create mode 100644 shared/src/test/diff/codegen/NewClasses.mls create mode 100644 shared/src/test/diff/nu/repro_EvalNegNeg.mls create mode 100644 shared/src/test/diff/nu/repro_PolymorphicVariants.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 228cd93920..b9d2d209f6 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -37,87 +37,100 @@ class ConstraintSolver extends NormalForms { self: Typer => err(msg"${info.decl.kind.str.capitalize} `${info.decl.name}` does not contain member `${fld.name}`", fld.toLoc).toUpper(noProv) - if (info.isComputing) { + // * The raw type of this member, with original references to the class' type variables/type parameters + val raw = if (info.isComputing) { info.typedFields.get(fld) match { - case S(fty) => fty + case S(fty) => S(fty) case N => fromRft match { case S(fty) => - fty + N case N => if (info.allFields.contains(fld)) - err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv) + S(err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv)) else - nope + S(nope) } } } else info.complete() match { case cls: TypedNuCls => - val raw = cls.members.get(fld.name) match { + cls.members.get(fld.name) match { case S(d: TypedNuFun) => - d.typeSignature.toUpper(provTODO) + S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => - p.ty + S(p.ty) case S(_) => - err(msg"access to ${cls.td.kind.str} member not yet supported", - fld.toLoc).toUpper(noProv) + S(err(msg"access to ${cls.td.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) case N => - nope + fromRft match { + case S(fty) => N + case N => S(nope) + } } - println(s"Lookup ${cls.td.nme.name}.${fld.name} : $raw where ${raw.ub.showBounds}") - - - // TODO dedup with below - - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - cls.tparams.foreach { case (tn, _tv, vi) => - val targ = rfnt(Var(cls.nme.name + "#" + tn.name)) match { - case S(fty) => - TypeBounds( - fty.lb.getOrElse(BotType), - fty.ub, - )(_tv.prov) - case N => - // FIXME type bounds are kind of wrong for this - TypeBounds( - // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), - // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), - _tv.lowerBounds.foldLeft( - Extruded(false, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST - // ^ TODO provide extrusion reason? - )(_ | _), - _tv.upperBounds.foldLeft( - Extruded(true, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST - // ^ TODO provide extrusion reason? - )(_ & _), - )(_tv.prov) - } - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) // TODO safe not to set original?! - println(s"Set ${_tv} ~> $tv") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - freshened += _tv -> tv + case _ => ??? // TODO + } + + println(s"Lookup ${info.decl.name}.${fld.name} : $raw where ${raw.fold("")(_.ub.showBounds)}") + + + val freshenedRaw = raw.fold(TopType.toUpper(noProv)) { raw => + + // TODO dedup with below logic from `lookupNuTypeDef` + + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + + info.tparams.foreach { case (tn, _tv, vi) => + val targ = rfnt(Var(info.decl.name + "#" + tn.name)) match { + case S(fty) => + TypeBounds.mk( + fty.lb.getOrElse(BotType), + fty.ub, + ) + case N => + // FIXME type bounds are kind of wrong for this + TypeBounds( + // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), + _tv.lowerBounds.foldLeft( + Extruded(false, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ | _), + _tv.upperBounds.foldLeft( + Extruded(true, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ & _), + )(_tv.prov) } + freshened += _tv -> (targ match { + case tv: TypeVarOrRigidVar => tv + case _ => + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) - val res = - raw.freshenAbove(cls.level, rigidify = false)//.asInstanceOf[TypedNuCls] - - println(s"Fresh ${cls.td.nme.name}.${fld.name} : $res where ${res.ub.showBounds}") - - res - - case _ => ??? + } + + raw.freshenAbove(info.level, rigidify = false) } + println(s"Fresh ${info.decl.name}.${fld.name} : $freshenedRaw where ${freshenedRaw.ub.showBounds}") + + println(s" & ${fromRft} (from refinement)") + + fromRft.foldRight(freshenedRaw)(_ && _) + } @@ -989,6 +1002,11 @@ class ConstraintSolver extends NormalForms { self: Typer => } } case (tr: TypeRef, _) => rec(tr.expand, rhs, true) + case (err @ ClassTag(ErrTypeId, _), tr: TypeRef) => + // rec(tr.copy(targs = tr.targs.map(_ => err))(noProv), tr, true) + // * ^ Nicely propagates more errors to the result, + // * but can incur vast amounts of unnecessary constraining in the context of recursive types! + () case (_, tr: TypeRef) => if (tr.canExpand) rec(lhs, tr.expand, true) else { diff --git a/shared/src/main/scala/mlscript/NormalForms.scala b/shared/src/main/scala/mlscript/NormalForms.scala index c84f6b8e34..5035b87e58 100644 --- a/shared/src/main/scala/mlscript/NormalForms.scala +++ b/shared/src/main/scala/mlscript/NormalForms.scala @@ -665,7 +665,7 @@ class NormalForms extends TyperDatatypes { self: Typer => def merge(pol: Bool)(l: DNF, r: DNF)(implicit ctx: Ctx, etf: ExpandTupleFields): DNF = if (pol) l | r else l & (r, pol) def mkDeep(polymLvl: Level, cons: Constrs, ty: SimpleType, pol: Bool) - (implicit ctx: Ctx, ptr: PreserveTypeRefs = false, etf: ExpandTupleFields = true): DNF = { + (implicit ctx: Ctx, ptr: PreserveTypeRefs = false, etf: ExpandTupleFields = true, expandedTVs: Set[TV] = Set.empty): DNF = { mk(polymLvl, cons, mkDeepST(polymLvl, cons, ty, pol), pol) } def mkDeepST(polymLvl: Level, cons: Constrs, ty: SimpleType, pol: Bool) @@ -688,7 +688,7 @@ class NormalForms extends TyperDatatypes { self: Typer => } // }(r => s"= $r") - def mk(polymLvl: Level, cons: Constrs, ty: SimpleType, pol: Bool)(implicit ctx: Ctx, ptr: PreserveTypeRefs = false, etf: ExpandTupleFields = true): DNF = + def mk(polymLvl: Level, cons: Constrs, ty: SimpleType, pol: Bool)(implicit ctx: Ctx, ptr: PreserveTypeRefs = false, etf: ExpandTupleFields = true, expandedTVs: Set[TV] = Set.empty): DNF = // trace(s"DNF[$pol,$ptr,$etf,$polymLvl](${ty})") { (if (pol) ty.pushPosWithout else ty) match { case bt: BaseType => DNF.of(polymLvl, cons, LhsRefined(S(bt), ssEmp, if (expandTupleFields) bt.toRecord else RecordType.empty, smEmp)) @@ -697,6 +697,8 @@ class NormalForms extends TyperDatatypes { self: Typer => case ExtrType(pol) => extr(!pol) case ty @ ComposedType(p, l, r) => merge(p)(mk(polymLvl, cons, l, pol), mk(polymLvl, cons, r, pol)) case NegType(und) => DNF.of(polymLvl, cons, CNF.mk(polymLvl, Nil, und, !pol).ds.map(_.neg)) + case tv @ AssignedVariable(ty) if !preserveTypeRefs && !expandedTVs.contains(tv) => + (expandedTVs + tv) |> { implicit expandedTVs => DNF.mk(polymLvl, cons, ty, pol) } case tv: TypeVariable => DNF.of(polymLvl, cons, Conjunct.of(SortedSet.single(tv)) :: Nil) case ProxyType(underlying) => mk(polymLvl, cons, underlying, pol) case tr @ TypeRef(defn, targs) => @@ -731,7 +733,7 @@ class NormalForms extends TyperDatatypes { self: Typer => Disjunct(RhsField(f._1, f._2), ssEmp, LhsTop, ssEmp)).toList) def extr(pol: Bool): CNF = if (pol) CNF(Nil) else of(RhsBot) def merge(pol: Bool)(l: CNF, r: CNF)(implicit ctx: Ctx, etf: ExpandTupleFields): CNF = if (pol) l | (r, pol) else l & r - def mk(polymLvl: Level, cons: Constrs, ty: SimpleType, pol: Bool)(implicit ctx: Ctx, ptr: PreserveTypeRefs, etf: ExpandTupleFields): CNF = + def mk(polymLvl: Level, cons: Constrs, ty: SimpleType, pol: Bool)(implicit ctx: Ctx, ptr: PreserveTypeRefs, etf: ExpandTupleFields, expandedTVs: Set[TV] = Set.empty): CNF = // trace(s"?CNF $ty") { ty match { case bt: BaseType => of(bt) @@ -740,6 +742,8 @@ class NormalForms extends TyperDatatypes { self: Typer => case ExtrType(pol) => extr(!pol) case ty @ ComposedType(p, l, r) => merge(p)(mk(polymLvl, cons, l, pol), mk(polymLvl, cons, r, pol)) case NegType(und) => CNF(DNF.mk(polymLvl, cons, und, !pol).cs.map(_.neg)) + case tv @ AssignedVariable(ty) if !preserveTypeRefs && !expandedTVs.contains(tv) => + (expandedTVs + tv) |> { implicit expandedTVs => CNF.mk(polymLvl, cons, ty, pol) } case tv: TypeVariable => of(SortedSet.single(tv)) case ProxyType(underlying) => mk(polymLvl, cons, underlying, pol) case tr @ TypeRef(defn, targs) => diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index a6257dc746..51f4ff10a5 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -209,7 +209,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => Trav(PolMap.pos)(instanceType) // TODO check consistency with explicitVariances - store ++ tparams.iterator.collect { case (_, tv, S(vi)) => tv -> vi } + val res = store ++ tparams.iterator.collect { case (_, tv, S(vi)) => tv -> vi } + + _variances = S(res) + + res }(r => s"= $r") } } @@ -507,7 +511,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } lazy val typedSignatureMembers: Ls[Str -> TypedNuFun] = typedSignatures.iterator.map { case (fd, ty) => - fd.nme.name -> TypedNuFun(level, fd, ty) + fd.nme.name -> TypedNuFun(level + 1, fd, ty) }.toList lazy val allFields: Set[Var] = decl match { diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 9d4a527eb7..68a61898fd 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -56,14 +56,15 @@ trait TypeSimplifier { self: Typer => // * Maybe we should process with the appropriate parent, but still generate an `assignedTo`? // * (Tried it, and it makes almost no difference in the end result.) allVarPols(tv) match { + case p if p.isEmpty || nv.assignedTo.nonEmpty => + nv.assignedTo = S(process(ty, N)) + case N => die // covered case S(true) => nv.lowerBounds = (process(ty, S(true -> tv)) :: Nil).filterNot(_.isBot) case S(false) => nv.upperBounds = (process(ty, S(false -> tv)) :: Nil).filterNot(_.isTop) - case N => - nv.assignedTo = S(process(ty, N)) } case N => nv.lowerBounds = if (allVarPols(tv).forall(_ === true)) @@ -501,7 +502,7 @@ trait TypeSimplifier { self: Typer => // * coincides with that of the later `transform` function. // * In particular, the traversal of fields with identical UB/LB is considered invariant. object Analyze1 extends Traverser2.InvariantFields { - override def apply(pol: PolMap)(st: ST): Unit = trace(s"analyze1[${printPol(pol)}] $st") { + override def apply(pol: PolMap)(st: ST): Unit = trace(s"analyze1[${(pol)}] $st") { st match { case tv: TV => pol(tv) match { @@ -607,6 +608,7 @@ trait TypeSimplifier { self: Typer => */ + // FIXME Currently we don't traverse TVs witht he correct PolMap, which introduces misatches with other analyses in tricky cases def analyze2(st: TL, pol: PolMap): Unit = Analyze2.applyLike(pol)(st.unwrapProvs) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index a7bd260a6d..dac3240f55 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -507,10 +507,10 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } // * Bounds shoudl always be disregarded when `equatedTo` is defined, as they are then irrelevant: - def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty); _lowerBounds } - def upperBounds: List[SimpleType] = { require(assignedTo.isEmpty); _upperBounds } - def lowerBounds_=(bs: Ls[ST]): Unit = { require(assignedTo.isEmpty); _lowerBounds = bs } - def upperBounds_=(bs: Ls[ST]): Unit = { require(assignedTo.isEmpty); _upperBounds = bs } + def lowerBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _lowerBounds } + def upperBounds: List[SimpleType] = { require(assignedTo.isEmpty, this); _upperBounds } + def lowerBounds_=(bs: Ls[ST]): Unit = { require(assignedTo.isEmpty, this); _lowerBounds = bs } + def upperBounds_=(bs: Ls[ST]): Unit = { require(assignedTo.isEmpty, this); _upperBounds = bs } private val creationRun = currentConstrainingRun def original: TV = diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index a039306fc7..68f8dc34f1 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1109,6 +1109,7 @@ abstract class TyperHelpers { Typer: Typer => case NegType(n) => apply(pol.map(!_))(n) case ExtrType(_) => () case ProxyType(und) => apply(pol)(und) + case SkolemTag(_, id) => apply(pol)(id) case _: TypeTag => () case tr: TypeRef => tr.mapTargs(pol)(apply(_)(_)); () case Without(b, ns) => apply(pol)(b) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 16a0b6d2cd..4dd1ff464d 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -320,11 +320,10 @@ mixin EvalNegNeg { :ShowRepl module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: 'A -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] -//│ 'A <: 'a +//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] //│ // Prelude //│ let typing_unit5 = { //│ cache: {}, @@ -386,7 +385,7 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:371 +//│ ┌ Block at Mixin.mls:370 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let typing_unit6 = { cache: {} }; @@ -417,7 +416,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.418: class Bar(x: int, y: int) extends Foo(x + y) +//│ ║ l.417: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -530,7 +529,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.530: fun x = y +//│ ║ l.529: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error diff --git a/shared/src/test/diff/codegen/NewClasses.mls b/shared/src/test/diff/codegen/NewClasses.mls new file mode 100644 index 0000000000..b8f40dcaef --- /dev/null +++ b/shared/src/test/diff/codegen/NewClasses.mls @@ -0,0 +1,16 @@ +:NewDefs + + +:ge // FIXME +class C[A](n: A) { + fun f = g + fun g = 0 +} +//│ class C[A](n: A) { +//│ fun f: 0 +//│ fun g: 0 +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol g + + diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index 2584f30706..09623fe14a 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -191,11 +191,10 @@ mixin EvalNegNeg { module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: 'A -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] -//│ 'A <: 'a +//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] fun mk(n) = if n is 0 then Lit(0) @@ -206,10 +205,9 @@ fun mk(n) = if n is //│ 'E :> Add['E] | Lit | Neg['E] TestLang.eval -//│ 'a -> int +//│ 'A -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] -//│ 'A <: 'a +//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] //│ res //│ = [Function: eval] diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 47d5ac4649..c05c6bb0fe 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -77,13 +77,93 @@ mixin EvalLambda { //│ fun eval: ('a & (Cons['A] | Nil), Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['f] | App['d | 'e] | 'c) //│ } +// FIXME type simplification +:ns module Test1 extends EvalVar, EvalLambda //│ module Test1() { -//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> 'result +//│ fun eval: ('a, 'b,) -> ('c | 'd | 'e | 'f) //│ } //│ where -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | Var -//│ 'result :> Var | App['result] | Abs['result] +//│ 'b <: #App & {App#A <: 'A} | (#Abs & {Abs#A <: 'A0} | 'g & ~#Abs) & ~#App +//│ 'g <: 'h +//│ 'h <: 'i +//│ 'i <: #Var +//│ 'A0 <: 't +//│ 't <: 't0 +//│ 't0 <: 'b +//│ 'A <: 't1 & 's +//│ 's <: (#Abs & {Abs#A <: 'A1} | 'j & ~#Abs) & 's0 +//│ 's0 <: 'b +//│ 'A1 <: 't2 +//│ 't2 <: 't3 +//│ 't3 <: 'b +//│ 't1 <: 't4 +//│ 't4 <: 'b +//│ 'a :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} +//│ <: 'k & (Cons['A6] | Nil) & 'l & 'm +//│ 'm :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} +//│ <: 'a +//│ 'l :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} +//│ <: 'a +//│ 'A6 :> 'A3 & 'A7 | 'A5 & 'A8 | 'A4 | ('x, 'n,) +//│ <: ('A2 | 'A7) & ('A4 | 'A8) & 'A5 +//│ 'A8 := in 'A4 out 'A5 +//│ 'k :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} +//│ <: 'o +//│ 'o :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} +//│ <: 'p +//│ 'p :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} | Cons['A9] | Nil +//│ <: #Cons & {Cons#A <: 'A10} | #Nil & ~#Cons +//│ 'A9 := out 'A10 +//│ 'A10 :> 'A3 & 'A11 | 'A5 & 'A12 +//│ <: 'head +//│ 'head :> 'A3 & 'A11 | 'A5 & 'A12 +//│ <: {_2: 'q} & {_1: 'r} +//│ 'A12 := in 'A4 out 'A5 +//│ 'A11 := in 'A2 out 'A3 +//│ 'A5 :> 'A3 & 'A7 | 'A4 | ('x0, 'u,) +//│ <: 'A2 & {_1: 'r} & {_2: 'q} +//│ 'A2 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | ('x, 'n,) & {_2: 'n, _1: 'x} | ('x1, 'v,) | 'A3 & 'A7 +//│ <: 'A4 & {_1: 'r} & {_2: 'q} +//│ 'A3 :> 'A2 | ('x1, 'v,) +//│ <: 'A4 & {_1: 'r} & {_2: 'q} +//│ 'A4 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | 'A3 & 'A7 | ('x1, 'v,) | ('x, 'n,) & {_2: 'n, _1: 'x} +//│ <: ('A2 | 'A7) & 'A2 & {_1: 'r} & {_2: 'q} +//│ 'A7 := in 'A2 out 'A3 +//│ 'n :> #Var +//│ <: 'u +//│ 'x :> string +//│ <: 'x0 +//│ 'u :> #Var +//│ <: 'q +//│ 'x0 :> string +//│ <: 'r +//│ 'v :> 'w +//│ <: 'q +//│ 'w :> 'c | 'd | 'e | 'f +//│ <: 'q +//│ 'q :> 'c | 'd | 'e | 'f | #Var +//│ <: 'A13 +//│ 'A13 :> 'c | 'd | 'e | 'f | #Var +//│ <: 'A14 +//│ 'A14 :> 'c | 'd | 'e | 'f | #Var +//│ <: 'result +//│ 'c :> 'y +//│ 'y :> 'c | 'd | 'e | 'f +//│ 'd :> #App & {App#A = 'A15} +//│ 'A15 :> 'w | 'z +//│ 'z :> 'c | 'd | 'e | 'f +//│ 'e :> #Abs & {Abs#A = 'A16} +//│ 'A16 :> 'a1 +//│ 'a1 :> 'c | 'd | 'e | 'f +//│ 'f :> 'b1 +//│ 'b1 :> #Var | 'result +//│ 'result :> 'c | 'd | 'e | 'f | #Var +//│ 'x1 :> string +//│ <: 'r +//│ 'r :> string +//│ <: 'c1 +//│ 'c1 := string Test1.eval(Nil, Var("a")) //│ 'a @@ -109,7 +189,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var //│ res //│ = Var {} @@ -126,7 +206,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) +//│ fun map_expr: forall 'A 'l 'A0 'l0. ('l -> 'A0 & 'l0 -> 'A, Add['l] | Mul['l0] | Num | Var,) -> (Add['A0] | Mul['A] | Num | Var) mixin EvalExpr { fun eval(sub, v) = @@ -171,16 +251,16 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.172: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.252: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.172: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.252: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.124: if v is +//│ ║ l.204: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.134: let vv = map_expr(eta, v) +//│ ║ l.214: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -192,20 +272,132 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) //│ res //│ = Add {} +// FIXME type simplification +:ns module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> 'result +//│ fun eval: ('a, 'b,) -> ('c | 'd | 'e | 'f) //│ } //│ where -//│ 'result :> App['result] | Abs['result] | Num | Var | 'b -//│ 'b <: Add['c] | Mul['c] | Num | Var -//│ 'c <: 'a -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | 'b & ~#Abs & ~#App +//│ 'a :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'g & (Cons['A3] | Nil) & 'h & 'i +//│ 'i :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'a +//│ 'h :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'a +//│ 'A3 :> 'A0 & 'A4 | 'A2 & 'A5 | 'A1 | ('x, 'j,) +//│ <: ('A | 'A4) & ('A1 | 'A5) & 'A2 +//│ 'A5 := in 'A1 out 'A2 +//│ 'g :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'k +//│ 'k :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'm & 'n +//│ 'n :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'a +//│ 'm :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'o +//│ 'o :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'p +//│ 'p :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} | Cons['A6] | Nil +//│ <: #Cons & {Cons#A <: 'A7} | #Nil & ~#Cons +//│ 'A6 := out 'A7 +//│ 'A7 :> 'A0 & 'A8 | 'A2 & 'A9 +//│ <: 'head +//│ 'head :> 'A0 & 'A8 | 'A2 & 'A9 +//│ <: {_2: 'q} & {_1: 'u} +//│ 'A9 := in 'A1 out 'A2 +//│ 'A8 := in 'A out 'A0 +//│ 'A2 :> 'A0 & 'A4 | 'A1 | ('x0, 'v,) +//│ <: 'A & {_1: 'u} & {_2: 'q} +//│ 'A :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | ('x, 'j,) & {_2: 'j, _1: 'x} | ('x1, 'w,) | 'A0 & 'A4 +//│ <: 'A1 & {_1: 'u} & {_2: 'q} +//│ 'A0 :> 'A | ('x1, 'w,) +//│ <: 'A1 & {_1: 'u} & {_2: 'q} +//│ 'A1 :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | 'A0 & 'A4 | ('x1, 'w,) | ('x, 'j,) & {_2: 'j, _1: 'x} +//│ <: ('A | 'A4) & 'A & {_1: 'u} & {_2: 'q} +//│ 'A4 := in 'A out 'A0 +//│ 'j :> #Var +//│ <: 'v +//│ 'x :> string +//│ <: 'x0 +//│ 'v :> #Var +//│ <: 'q +//│ 'x0 :> string +//│ <: 'u +//│ 'w :> 'y +//│ <: 'q +//│ 'y :> 'c | 'd | 'e | 'f +//│ <: 'q +//│ 'q :> 'c | 'd | 'e | 'f | #Var +//│ <: 'A10 +//│ 'A10 :> 'c | 'd | 'e | 'f | #Var +//│ <: 'A11 +//│ 'A11 :> 'c | 'd | 'e | 'f | #Var +//│ <: 'result +//│ 'c :> 'z +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'z :> 'c | 'd | 'e | 'f +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'd :> #App & {App#A = 'A12} +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'A12 :> 'y | 'e1 +//│ 'e1 :> 'c | 'd | 'e | 'f +//│ 'e :> #Abs & {Abs#A = 'A13} +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'A13 :> 'f1 +//│ 'f1 :> 'c | 'd | 'e | 'f +//│ 'f :> 'g1 +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'g1 :> 'h1 | 'i1 | 'j1 | 'k1 +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'k1 :> #Num +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'j1 <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) & 'l1 +//│ 'l1 <: #Var | (#Num | (#Add & {Add#A <: 'A14} | #Mul & {Mul#A <: 'A15} & ~#Add) & ~#Num) & ~#Var +//│ 'A15 <: 'r & 'l +//│ 'l <: 'm1 +//│ 'r <: 'm1 +//│ 'A14 <: 'r0 & 'l0 +//│ 'l0 <: 'm1 +//│ 'r0 <: 'm1 +//│ 'm1 <: 'n1 +//│ 'n1 <: 'b +//│ 'b <: #App & {App#A <: 'A16} | (#Abs & {Abs#A <: 'A17} | 'o1 & ~#Abs) & ~#App +//│ 'o1 <: 'p1 +//│ 'p1 <: 'j1 +//│ 'A17 <: 't +//│ 't <: 't0 +//│ 't0 <: 'b +//│ 'A16 <: 't1 & 's +//│ 's <: (#Abs & {Abs#A <: 'A18} | 'q1 & ~#Abs) & 's0 +//│ 's0 <: 'b +//│ 'A18 <: 't2 +//│ 't2 <: 't3 +//│ 't3 <: 'b +//│ 't1 <: 't4 +//│ 't4 <: 'b +//│ 'i1 :> #Num +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'h1 :> 'r1 +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'r1 :> #Var | 'result +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'result :> 'c | 'd | 'e | 'f | #Var +//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) +//│ 'd1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} +//│ 'c1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} +//│ 'b1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} +//│ 'a1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} +//│ 'x1 :> string +//│ <: 'u +//│ 'u :> string +//│ <: 's1 +//│ 's1 := string Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Num | Var +//│ 'a :> Abs['a] | Abs[Var] | Num | Var | App['a] //│ res //│ = Abs {} @@ -216,31 +408,130 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num //│ res //│ = Var {} +// FIXME type simplification +:ns // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> ('a | 'result) +//│ fun eval: ('a, 'b,) -> ('c | 'd | 'b | 'e) //│ } //│ where -//│ 'result :> Abs['result] | App['result] | Var | Num | 'a -//│ 'a <: Add['b] | Mul['b] | Num | Var -//│ 'b <: 'a +//│ 'a :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'f & 'g +//│ 'g :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'a +//│ 'f :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'h +//│ 'h :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'i & (Cons['A3] | Nil) & 'j & 'k +//│ 'k :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'a +//│ 'j :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'a +//│ 'A3 :> 'A0 & 'A4 | 'A2 & 'A5 | 'A1 | ('x, 'm,) +//│ <: ('A | 'A4) & ('A1 | 'A5) & 'A2 +//│ 'A5 := in 'A1 out 'A2 +//│ 'i :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'n +//│ 'n :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ <: 'o +//│ 'o :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} | Cons['A6] | Nil +//│ <: #Cons & {Cons#A <: 'A7} | #Nil & ~#Cons +//│ 'A6 := out 'A7 +//│ 'A7 :> 'A0 & 'A8 | 'A2 & 'A9 +//│ <: 'head +//│ 'head :> 'A0 & 'A8 | 'A2 & 'A9 +//│ <: {_2: 'p} & {_1: 'q} +//│ 'A9 := in 'A1 out 'A2 +//│ 'A8 := in 'A out 'A0 +//│ 'A2 :> 'A0 & 'A4 | 'A1 | ('x0, 's,) +//│ <: 'A & {_1: 'q} & {_2: 'p} +//│ 'A :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | ('x, 'm,) & {_2: 'm, _1: 'x} | ('x1, 't,) | 'A0 & 'A4 +//│ <: 'A1 & {_1: 'q} & {_2: 'p} +//│ 'A0 :> 'A | ('x1, 't,) +//│ <: 'A1 & {_1: 'q} & {_2: 'p} +//│ 'A1 :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | 'A0 & 'A4 | ('x1, 't,) | ('x, 'm,) & {_2: 'm, _1: 'x} +//│ <: ('A | 'A4) & 'A & {_1: 'q} & {_2: 'p} +//│ 'A4 := in 'A out 'A0 +//│ 'm :> #Var +//│ <: 's +//│ 'x :> string +//│ <: 'x0 +//│ 's :> #Var +//│ <: 'p +//│ 'x0 :> string +//│ <: 'q +//│ 't :> 'u +//│ <: 'p +//│ 'u :> 'c | 'd | 'b | 'e +//│ <: 'p +//│ 'p :> 'c | 'd | 'b | 'e | #Var +//│ <: 'A10 +//│ 'A10 :> 'c | 'd | 'b | 'e | #Var +//│ <: 'A11 +//│ 'A11 :> 'c | 'd | 'b | 'e | #Var +//│ <: 'result +//│ 'c :> 'v +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'v :> 'b1 | 'c1 | 'd1 | 'e1 +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'e1 :> 'f1 +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'f1 :> #Var | 'result +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'result :> 'c | 'd | 'b | 'e | #Var +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'd1 :> #Abs & {Abs#A = 'A12} +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'c1 :> #App & {App#A = 'A13} +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'b1 :> 'g1 +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'g1 :> 'c | 'd | 'b | 'e +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'd :> #Num +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'w :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} +//│ 'A12 :> 'h1 +//│ 'h1 :> 'c | 'd | 'b | 'e +//│ 'b <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & 'i1 +//│ 'i1 <: #Var | (#Num | (#Add & {Add#A <: 'A14} | #Mul & {Mul#A <: 'A15} & ~#Add) & ~#Num) & ~#Var +//│ 'A15 <: 'r & 'l +//│ 'l <: 'j1 +//│ 'r <: 'j1 +//│ 'A14 <: 'r0 & 'l0 +//│ 'l0 <: 'j1 +//│ 'r0 <: 'j1 +//│ 'j1 <: 'k1 +//│ 'k1 <: 'b +//│ 'y :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} +//│ 'A13 :> 'u | 'l1 +//│ 'l1 :> 'c | 'd | 'b | 'e +//│ 'e :> #Num +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'a1 :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} +//│ 'z :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} +//│ 'x1 :> string +//│ <: 'q +//│ 'q :> string +//│ <: 'm1 +//│ 'm1 := string // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.232: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.523: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.232: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.523: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.124: if v is +//│ ║ l.204: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.134: let vv = map_expr(eta, v) +//│ ║ l.214: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'a //│ where diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index eaad25f32e..0e42519908 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -202,13 +202,15 @@ module SizeText extends Text //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string //│ } +// * Note: this inferred type got *much worse* after this commit (field access type refinement) module SizeText extends SizeBase, Text //│ module SizeText() { //│ fun size: 'a -> int -//│ fun text: (Circle | Intersect['Region] | Outside['a] | Translate['Region0] | Union['Region1]) -> string +//│ fun text: (Circle | Intersect[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]] | Outside['a] | Translate[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]] | Union[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]]) -> string //│ } //│ where -//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['Region0] | Union['Region1] +//│ 'a <: Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2] +//│ 'Region2 <: 'a //│ 'Region1 <: 'a //│ 'Region0 <: 'a //│ 'Region <: 'a @@ -327,7 +329,7 @@ module TestElim extends Eliminate TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where -//│ 'a :> Univ | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ 'a :> Intersect['a] | Translate['a] | Scale['a] | Univ | Outside['a] | Union['a] //│ res //│ = Univ {} @@ -366,12 +368,11 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ fun isEmpty: 'd -> bool //│ fun isUniv: 'e -> bool //│ fun size: 'f -> int -//│ fun text: (Circle | Intersect['Region] | Outside['f] | Translate['Region0] | Union['Region1]) -> string +//│ fun text: (Circle | Intersect[Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ] | Outside['f] | Translate[Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ]) -> string //│ } //│ where -//│ 'f <: Circle | Empty | Intersect['Region] | Outside['f] | Scale['f] | Translate['Region0] | Union['Region1] | Univ -//│ 'Region1 <: 'f -//│ 'Region0 <: 'f +//│ 'f <: Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ +//│ 'g <: Circle | Intersect['f] | Outside['f] | Translate['f] | Union['f] //│ 'Region <: 'f //│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ @@ -432,13 +433,13 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.433: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.434: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.346: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.433: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.434: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.123: if a is @@ -452,13 +453,13 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.453: Lang.text(mk(100)) +//│ ║ l.454: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.346: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.453: Lang.text(mk(100)) +//│ ║ l.454: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.175: if e is diff --git a/shared/src/test/diff/fcp/Church_CT.mls b/shared/src/test/diff/fcp/Church_CT.mls index f4b8388a34..6965026c3a 100644 --- a/shared/src/test/diff/fcp/Church_CT.mls +++ b/shared/src/test/diff/fcp/Church_CT.mls @@ -349,9 +349,9 @@ s: ChurchInt -> ChurchInt //│ ╙── ^ //│ res: ChurchInt -> ChurchInt //│ = [Function: s] -//│ constrain calls : 104 +//│ constrain calls : 103 //│ annoying calls : 0 -//│ subtyping calls : 322 +//│ subtyping calls : 321 diff --git a/shared/src/test/diff/fcp/Church_ST.mls b/shared/src/test/diff/fcp/Church_ST.mls index eeada66a6a..d7e7374430 100644 --- a/shared/src/test/diff/fcp/Church_ST.mls +++ b/shared/src/test/diff/fcp/Church_ST.mls @@ -351,9 +351,9 @@ s: ChurchInt -> ChurchInt //│ ╙── ^ //│ res: ChurchInt -> ChurchInt //│ = [Function: s] -//│ constrain calls : 110 +//│ constrain calls : 109 //│ annoying calls : 0 -//│ subtyping calls : 383 +//│ subtyping calls : 382 diff --git a/shared/src/test/diff/fcp/ListBuild.mls b/shared/src/test/diff/fcp/ListBuild.mls index 727bd1a701..69c8849a62 100644 --- a/shared/src/test/diff/fcp/ListBuild.mls +++ b/shared/src/test/diff/fcp/ListBuild.mls @@ -187,7 +187,7 @@ build: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] //│ ╟── Note: constraint arises from type variable: //│ ║ l.137: def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> cons (x, xs)) nil //│ ╙── ^^ -//│ res: (('a -> Ls['a] -> Ls['a | error]) -> Ls['a | error] -> Ls['a]) -> Ls['a | error] +//│ res: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] //│ = [Function: build] diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls b/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls index a1b05ba61b..36407d7021 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_ST_Repro.mls @@ -60,12 +60,10 @@ simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)] -//│ where -//│ 'a :> error //│ = [Function: simpleStepImpl] -//│ constrain calls : 5230 +//│ constrain calls : 4942 //│ annoying calls : 62 -//│ subtyping calls : 32236 +//│ subtyping calls : 31637 // :ResetFuel // * Note that the above incidentally can be checked using recursive types @@ -99,18 +97,18 @@ mkArrays impl k = k impl :e def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) //│ ╔══[ERROR] Type error in application -//│ ║ l.100: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.98: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'Rep` leaks out of its scope //│ ║ l.35: type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this function: -//│ ║ l.100: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.98: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.100: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) -//│ ║ ^^^ +//│ ║ l.98: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) +//│ ║ ^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.41: sub = fun ((r0, r1)) -> fun i -> arrImpl.Sub r0 i; //│ ╙── ^^ diff --git a/shared/src/test/diff/mlf-examples/ex_validate.mls b/shared/src/test/diff/mlf-examples/ex_validate.mls index e73dbd09e5..9272443f84 100644 --- a/shared/src/test/diff/mlf-examples/ex_validate.mls +++ b/shared/src/test/diff/mlf-examples/ex_validate.mls @@ -812,7 +812,7 @@ def a = fun f -> f id //│ = [Function: church_succ] //│ f: Sa -> Sid //│ = [Function: f] -//│ f_: ((forall 'a 'b. ('a -> 'b & 'a) -> 'b) -> 'c & (forall 'd 'e. ((forall 'f. anything -> 'f -> 'f) -> 'd -> anything) -> 'd -> 'e -> 'e) -> anything) -> 'c +//│ f_: ((forall 'a 'b. ('b -> 'a & 'b) -> 'a) -> 'c & (forall 'd 'e. ((forall 'f. anything -> 'f -> 'f) -> 'd -> anything) -> 'd -> 'e -> 'e) -> anything) -> 'c //│ = [Function: f_] //│ a: ((forall 'a. 'a -> 'a) -> 'b) -> 'b //│ = [Function: a] diff --git a/shared/src/test/diff/mlscript/Arrays.mls b/shared/src/test/diff/mlscript/Arrays.mls index d1db957f75..68e9c914ff 100644 --- a/shared/src/test/diff/mlscript/Arrays.mls +++ b/shared/src/test/diff/mlscript/Arrays.mls @@ -78,9 +78,9 @@ ty3B = ty3A //│ 'a //│ where //│ 'a := MyArray[MyArray['a]] -//│ constrain calls : 82 -//│ annoying calls : 25 -//│ subtyping calls : 215 +//│ constrain calls : 78 +//│ annoying calls : 23 +//│ subtyping calls : 211 :stats ty3A = ty3B @@ -91,9 +91,9 @@ ty3A = ty3B //│ 'a //│ where //│ 'a := MyArray['a] -//│ constrain calls : 82 -//│ annoying calls : 25 -//│ subtyping calls : 215 +//│ constrain calls : 78 +//│ annoying calls : 23 +//│ subtyping calls : 211 def ty4B: MyArray[MyArray[MyArray['a]]] as 'a //│ ty4B: 'a diff --git a/shared/src/test/diff/mlscript/BadInherit2.mls b/shared/src/test/diff/mlscript/BadInherit2.mls index d34b702c63..3afc034543 100644 --- a/shared/src/test/diff/mlscript/BadInherit2.mls +++ b/shared/src/test/diff/mlscript/BadInherit2.mls @@ -41,7 +41,7 @@ class A0: S0[int] & T0[string] //│ ╟── Hint: method Foo0 is abstract //│ ║ l.14: class A0: S0[int] & T0[string] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ res: 'A -> ('A | error) +//│ res: 'A -> 'A //│ = undefined :e diff --git a/shared/src/test/diff/mlscript/BadInherit2Co.mls b/shared/src/test/diff/mlscript/BadInherit2Co.mls index e9df18f313..804f075d65 100644 --- a/shared/src/test/diff/mlscript/BadInherit2Co.mls +++ b/shared/src/test/diff/mlscript/BadInherit2Co.mls @@ -55,7 +55,7 @@ class A0: S0[int] & T0[string] //│ ╟── Hint: method Foo0 is abstract //│ ║ l.44: class A0: S0[int] & T0[string] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ res: error +//│ res: nothing //│ = undefined :e diff --git a/shared/src/test/diff/mlscript/BadMethods.mls b/shared/src/test/diff/mlscript/BadMethods.mls index 25dc7eb755..5aebf8c5ab 100644 --- a/shared/src/test/diff/mlscript/BadMethods.mls +++ b/shared/src/test/diff/mlscript/BadMethods.mls @@ -566,9 +566,9 @@ t : Dup[int, bool] //│ ║ l.558: t : Dup[int, bool] //│ ╙── ^^^^ //│ res: Dup[?, bool] -//│ constrain calls : 39 +//│ constrain calls : 30 //│ annoying calls : 24 -//│ subtyping calls : 109 +//│ subtyping calls : 95 :stats t.MthDup (fun x -> mul 2 x) diff --git a/shared/src/test/diff/mlscript/BadTypes.mls b/shared/src/test/diff/mlscript/BadTypes.mls index 4d03245b6a..0f96665a3e 100644 --- a/shared/src/test/diff/mlscript/BadTypes.mls +++ b/shared/src/test/diff/mlscript/BadTypes.mls @@ -165,7 +165,7 @@ someRec: BadRec //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.+1: someRec: BadRec //│ ║ ^^^^^^^ -//│ ╟── type `{y: 'a}` does not have field 'x' +//│ ╟── type `forall 'a. 'a` is not a record (expected a record with fields: x, y) //│ ║ l.157: def someRec: { y: 'a } as 'a //│ ║ ^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{x: 'a0, y: BadRec}` diff --git a/shared/src/test/diff/mlscript/HeadOption.mls b/shared/src/test/diff/mlscript/HeadOption.mls index 52a56e055d..3ad9b4afc1 100644 --- a/shared/src/test/diff/mlscript/HeadOption.mls +++ b/shared/src/test/diff/mlscript/HeadOption.mls @@ -124,9 +124,9 @@ rec def lr1 = Cons { head = 0; tail = lr1 } :stats Cons.HeadOption lr1 //│ res: Some[0] -//│ constrain calls : 51 +//│ constrain calls : 48 //│ annoying calls : 21 -//│ subtyping calls : 170 +//│ subtyping calls : 167 :stats rec def lr2 = Cons { head = 0; tail = Cons { head = 1; tail = Cons { head = 3; tail = lr2 } } } @@ -140,9 +140,9 @@ rec def lr2 = Cons { head = 0; tail = Cons { head = 1; tail = Cons { head = 3; t :stats Cons.HeadOption lr2 //│ res: Some[0] -//│ constrain calls : 50 +//│ constrain calls : 47 //│ annoying calls : 21 -//│ subtyping calls : 164 +//│ subtyping calls : 161 :e diff --git a/shared/src/test/diff/mlscript/Methods.mls b/shared/src/test/diff/mlscript/Methods.mls index c914f6250c..83f8ac8d89 100644 --- a/shared/src/test/diff/mlscript/Methods.mls +++ b/shared/src/test/diff/mlscript/Methods.mls @@ -288,7 +288,7 @@ Test3A.F //│ ╔══[ERROR] identifier not found: Test3A //│ ║ l.284: Test3A.F //│ ╙── ^^^^^^ -//│ res: error +//│ res: nothing //│ = undefined class Test3A: Test1[forall 'a. 'a -> 'a] @@ -306,7 +306,7 @@ Test3B.F //│ ╔══[ERROR] identifier not found: Test3B //│ ║ l.302: Test3B.F //│ ╙── ^^^^^^ -//│ res: error +//│ res: nothing //│ = undefined diff --git a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls index df0b443a77..a83eee4eab 100644 --- a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls +++ b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls @@ -414,6 +414,7 @@ rec def eval4 subst = eval_lexpr' eval4 subst :Fuel 20000 +:stats rec def eval4 subst = eval_lexpr' eval4 subst //│ eval4: (List[?] & 'tail) -> 'b -> 'rhs //│ where @@ -434,6 +435,9 @@ rec def eval4 subst = eval_lexpr' eval4 subst //│ 'c <: {body: 'b, name: string} //│ = //│ eval_lexpr', eval_var, list_assoc and eq are not implemented +//│ constrain calls : 16185 +//│ annoying calls : 2300 +//│ subtyping calls : 595519 :ResetFuel diff --git a/shared/src/test/diff/mlscript/Random2.mls b/shared/src/test/diff/mlscript/Random2.mls index b79b604f35..2869cfbc53 100644 --- a/shared/src/test/diff/mlscript/Random2.mls +++ b/shared/src/test/diff/mlscript/Random2.mls @@ -57,9 +57,7 @@ rec def f a = a a //│ ╔══[ERROR] Type mismatch in def definition: //│ ║ l.51: rec def f a = a a //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> ?b` does not have field 'x' -//│ ║ l.51: rec def f a = a a -//│ ║ ^^^^^^^ +//│ ╟── expression of type `forall ?f. ?f` does not have field 'x' //│ ╟── Note: constraint arises from record type: //│ ║ l.8: def f: { x: 'a } as 'a //│ ╙── ^^^^^^^^^ diff --git a/shared/src/test/diff/mlscript/RecursiveTypes.mls b/shared/src/test/diff/mlscript/RecursiveTypes.mls index d2d94e7716..2ccaf21359 100644 --- a/shared/src/test/diff/mlscript/RecursiveTypes.mls +++ b/shared/src/test/diff/mlscript/RecursiveTypes.mls @@ -360,7 +360,7 @@ bar2_ty2 = bar_ty2 //│ ╔══[ERROR] Type mismatch in def definition: //│ ║ l.352: bar2_ty2 = bar_ty2 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── type `C['r]` does not have field 'x' +//│ ╟── type `forall 'r. 'r` does not have field 'x' //│ ║ l.285: def bar_ty2: C['r] as 'r //│ ║ ^^^^^ //│ ╟── but it flows into reference with expected type `{x: 'r0}` @@ -587,9 +587,9 @@ f_manual_ns ainf //│ ╟── Note: constraint arises from record type: //│ ║ l.571: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) //│ ║ ^^^^^^^^^^^^ -//│ ╟── from intersection type: +//│ ╟── from local type binding: //│ ║ l.571: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) -//│ ╙── ^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ res: error def f_manual_2: (({a: 'a} as 'a) & 'b) -> ('b | 'c\a & {a: int} as 'c) diff --git a/shared/src/test/diff/mlscript/RecursiveTypes2.mls b/shared/src/test/diff/mlscript/RecursiveTypes2.mls index 35d144d86f..88615bb3fc 100644 --- a/shared/src/test/diff/mlscript/RecursiveTypes2.mls +++ b/shared/src/test/diff/mlscript/RecursiveTypes2.mls @@ -40,9 +40,9 @@ f.x //│ res: 'a & (T1 & T3 & {x: T2} | T1 & T2 & {x: T3}) //│ where //│ 'a :> T3 & {x: T1 & 'a} -//│ constrain calls : 6 -//│ annoying calls : 5 -//│ subtyping calls : 148 +//│ constrain calls : 4 +//│ annoying calls : 4 +//│ subtyping calls : 136 g = error : T1 & { x: T2 | 'a } as 'a //│ g: 'a @@ -54,9 +54,9 @@ g.x //│ res: T1 & {x: T1} & 'a | T1 & T2 & {x: T1} //│ where //│ 'a :> T1 & {x: 'a | T2} -//│ constrain calls : 6 -//│ annoying calls : 5 -//│ subtyping calls : 85 +//│ constrain calls : 4 +//│ annoying calls : 4 +//│ subtyping calls : 78 :stats f = g @@ -67,8 +67,8 @@ f = g //│ 'a //│ where //│ 'a :> T3 & {x: T1 & 'a} -//│ constrain calls : 69 -//│ annoying calls : 97 -//│ subtyping calls : 3493 +//│ constrain calls : 48 +//│ annoying calls : 60 +//│ subtyping calls : 2389 diff --git a/shared/src/test/diff/mlscript/StressUgly.mls b/shared/src/test/diff/mlscript/StressUgly.mls index 95e1115d8f..8a4aff8795 100644 --- a/shared/src/test/diff/mlscript/StressUgly.mls +++ b/shared/src/test/diff/mlscript/StressUgly.mls @@ -44,7 +44,7 @@ eval1_ty = eval1_ty_ugly //│ ╙── ^^^ //│ = //│ eval1_ty_ugly is not implemented -//│ constrain calls : 60 -//│ annoying calls : 46 -//│ subtyping calls : 517 +//│ constrain calls : 49 +//│ annoying calls : 42 +//│ subtyping calls : 451 diff --git a/shared/src/test/diff/mlscript/TypeClasses.mls b/shared/src/test/diff/mlscript/TypeClasses.mls index 1babcff5ca..b3578ce409 100644 --- a/shared/src/test/diff/mlscript/TypeClasses.mls +++ b/shared/src/test/diff/mlscript/TypeClasses.mls @@ -217,7 +217,7 @@ class ComplexMonoid_bad_1[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in method definition: //│ ║ l.+2: method Empty = Complex { real = this.base.Empty; imaginary = this.imaginary.Empty } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `forall ?a ?b. ?b -> ?a` is not a record (expected a record with fields: real, imaginary) +//│ ╟── function of type `forall ?a ?b. ?a -> ?b` is not a record (expected a record with fields: real, imaginary) //│ ║ l.31: def Complex real imaginary = Complex { real; imaginary } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `{imaginary: A, real: A}` @@ -245,7 +245,7 @@ class ComplexMonoid_bad_1[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ║ l.3: method Empty: A //│ ╙── ^^^^^^^^ //│ Defined class ComplexMonoid_bad_1[=A] -//│ Defined ComplexMonoid_bad_1.Empty: ComplexMonoid_bad_1['A] -> 'A0 -> (Complex['A0 | {imaginary: error, real: 'A}] with {imaginary: 'A0, real: {imaginary: error, real: 'A}}) +//│ Defined ComplexMonoid_bad_1.Empty: ComplexMonoid_bad_1['A] -> 'A0 -> (Complex['A0 | {imaginary: nothing, real: 'A}] with {imaginary: 'A0, real: {imaginary: nothing, real: 'A}}) //│ Defined ComplexMonoid_bad_1.Add: ComplexMonoid_bad_1['A] -> anything -> anything -> nothing diff --git a/shared/src/test/diff/mlscript/TypeRanges.mls b/shared/src/test/diff/mlscript/TypeRanges.mls index 1a8a514fc8..f0e58102c9 100644 --- a/shared/src/test/diff/mlscript/TypeRanges.mls +++ b/shared/src/test/diff/mlscript/TypeRanges.mls @@ -414,7 +414,7 @@ foo: R['a] //│ ╙── ^^^^^^^^^^^ //│ res: R['a] //│ where -//│ 'a :> error | number +//│ 'a :> number //│ <: int //│ = { get: 0, set: [Function: set] } @@ -432,12 +432,12 @@ foo: R['a..'b] //│ ╟── from type bounds: //│ ║ l.388: def foo: R[int..number] //│ ╙── ^^^^^^^^^^^ -//│ res: R['b | error | number] +//│ res: R['b | number] //│ = { get: 0, set: [Function: set] } // * FIXME res.get -//│ res: error | number +//│ res: number //│ = 0 type S[A] = { get: A; set: A -> () } @@ -459,7 +459,7 @@ foo: S['a] //│ ╙── ^^^^^^^^^^^ //│ res: S['a] //│ where -//│ 'a :> error | number +//│ 'a :> number //│ <: int //│ = { get: 0, set: [Function: set] } @@ -477,7 +477,7 @@ foo: S['a..'b] //│ ╟── from type bounds: //│ ║ l.388: def foo: R[int..number] //│ ╙── ^^^^^^^^^^^ -//│ res: S['b | error | number] +//│ res: S['b | number] //│ = { get: 0, set: [Function: set] } foo: { get: number; set: int -> () } @@ -535,7 +535,7 @@ foo2: S['a] //│ ╙── ^^ //│ res: S['a] //│ where -//│ 'a :> error | number +//│ 'a :> number //│ <: int //│ = { get: 0, set: [Function: set] } @@ -553,7 +553,7 @@ foo2: S['a..'b] //│ ╟── from type variable: //│ ║ l.518: foo2 = foo: { get: 'a; set: 'b -> () } //│ ╙── ^^ -//│ res: S['b | error | number] +//│ res: S['b | number] //│ = { get: 0, set: [Function: set] } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 72503d1e5b..b414454122 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -14,6 +14,11 @@ let a = A(42) //│ a //│ = A {} +a.n +//│ int +//│ res +//│ = 42 + fun f(x: A) = x.n //│ fun f: (x: A,) -> int @@ -69,10 +74,10 @@ class Base0(n) { fun oops = this.my } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.65: class Base0(n) { +//│ ║ l.70: class Base0(n) { //│ ╙── ^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.69: fun oops = this.my +//│ ║ l.74: fun oops = this.my //│ ╙── ^^^ //│ class Base0(n: error) { //│ fun me: Base0 & {n: error} @@ -173,7 +178,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] Class `Base1` does not contain member `getBaseTypo` -//│ ║ l.174: b.getBaseTypo +//│ ║ l.179: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index 0531319ff9..14ad4af65f 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -22,13 +22,7 @@ x: List //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.21: x: List //│ ║ ^ -//│ ╟── expression of type `anything` is not an instance of type `int` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.17: let x: List -//│ ║ ^^^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.5: class List { -//│ ╙── ^ +//│ ╙── expression of type `anything` does not match type `int` //│ List[anything] diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index b1aef73e5a..a62b491cd3 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -49,11 +49,10 @@ mixin EvalNegNeg { module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: 'A -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['A & (~#Neg | Neg['a])] -//│ 'A <: 'a +//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] fun mk(n) = if n is diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index b2725b3bf9..240b86972d 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -55,8 +55,6 @@ mixin EvalAdd { //│ fun eval: Add['lhs] -> 'a //│ } -// FIXME type vars are wrongly refreshed when tying the knot - module TestLang extends EvalAdd //│ module TestLang() { //│ fun eval: 'a -> nothing diff --git a/shared/src/test/diff/nu/FieldRefinement.mls b/shared/src/test/diff/nu/FieldRefinement.mls index ce1064a1bc..ed653aef73 100644 --- a/shared/src/test/diff/nu/FieldRefinement.mls +++ b/shared/src/test/diff/nu/FieldRefinement.mls @@ -1,23 +1,36 @@ :NewDefs +:NoJS class Foo(x: int) { fun bar = x + fun baz: 1 | 2 = 1 } //│ class Foo(x: int) { //│ fun bar: int +//│ fun baz: 1 | 2 //│ } -let foo: Foo & { x: 0 | 1 } -//│ let foo: Foo & {x: 0 | 1} -//│ foo -//│ = +let foo: Foo & { x: 0 | 1, bar: 0 | 1, baz: 0 | 1, y: bool } +//│ let foo: Foo & {y: bool, bar: 0 | 1, baz: 0 | 1, x: 0 | 1} -// TODO refine foo.x -//│ int -//│ res -//│ = -//│ foo is not implemented +//│ 0 | 1 + +foo.bar +//│ 0 | 1 + +foo.baz +//│ 1 + +foo.y +//│ bool + +:e +foo.z +//│ ╔══[ERROR] Class `Foo` does not contain member `z` +//│ ║ l.30: foo.z +//│ ╙── ^^ +//│ error diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 883cd83f0b..558e7895e0 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -11,24 +11,38 @@ fun f(x) = if x is C then x // f(C : #C) -// :d class C(a: A) //│ class C[A](a: A) -fun f(x) = if x is C(a) then a -//│ fun f: forall 'a. C['a] -> 'a - let c = C(1) //│ let c: C[1] //│ c //│ = C1 {} +c.a +//│ 1 +//│ res +//│ = 1 + +fun f(x) = if x is C(a) then a +//│ fun f: forall 'a. C['a] -> 'a + f(c) //│ 1 //│ res //│ = 1 +class C[A](n: A) { + fun f = this.n + fun g = C(12).n +} +//│ class C[A](n: A) { +//│ fun f: A +//│ fun g: 12 +//│ } + + class Some(value: A) { fun get = value fun toArray = [value] @@ -175,7 +189,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.173: class Test(n) { +//│ ║ l.187: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -199,13 +213,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.199: fun foo = n + 1 +//│ ║ l.213: fun foo = n + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.199: fun foo = n + 1 +//│ ║ l.213: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.198: class Test(n: A) { +//│ ║ l.212: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: error | int @@ -282,13 +296,13 @@ class TestBad { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.282: fun foo2(x: A) = x + 1 +//│ ║ l.296: fun foo2(x: A) = x + 1 //│ ║ ^^^ //│ ╟── reference of type `A` is not an instance of type `int` -//│ ║ l.282: fun foo2(x: A) = x + 1 +//│ ║ l.296: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.280: class TestBad { +//│ ║ l.294: class TestBad { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A @@ -371,10 +385,19 @@ w.x //│ res //│ = C1 {} -// FIXME +not(w.x.n) +//│ bool +//│ res +//│ = true + +:e not(w.x.a) +//│ ╔══[ERROR] Class `C` does not contain member `a` +//│ ║ l.394: not(w.x.a) +//│ ╙── ^^ //│ bool //│ res //│ = false + diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index dc4cd6275d..5e74d9bf43 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -4,29 +4,83 @@ :e module Test { fun foo: A => A + fun bar: A => A = id + fun baz(x: A) = x + fun poly0: 'a -> 'a + fun poly1: forall 'a; 'a -> 'a + fun poly2: 'a -> 'a = id } //│ ╔══[ERROR] Member foo is declared but not defined //│ ║ l.6: fun foo: A => A //│ ╙── ^^^ +//│ ╔══[ERROR] Member poly0 is declared but not defined +//│ ║ l.9: fun poly0: 'a -> 'a +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Member poly1 is declared but not defined +//│ ║ l.10: fun poly1: forall 'a; 'a -> 'a +//│ ╙── ^^^^^ //│ module Test[A]() { +//│ fun bar: A -> A +//│ fun baz: (x: A,) -> A //│ fun foo: A -> A +//│ fun poly0: forall 'a. 'a -> 'a +//│ fun poly1: forall 'a0. 'a0 -> 'a0 +//│ fun poly2: forall 'a1. 'a1 -> 'a1 //│ } Test.foo -//│ forall 'A. 'A -> 'A +//│ (??A & 'A) -> ('A | ??A0) //│ res //│ = undefined -:re +Test.bar +//│ (??A & 'A) -> ('A | ??A0) +//│ res +//│ = [Function: id] + +Test.baz +//│ (x: ??A & 'A,) -> ('A | ??A0) +//│ res +//│ = [Function: baz] + +Test.poly0 +//│ forall 'a. 'a -> 'a +//│ res +//│ = undefined + +Test.poly1 +//│ forall 'a. 'a -> 'a +//│ res +//│ = undefined + +Test.poly2 +//│ forall 'a. 'a -> 'a +//│ res +//│ = [Function: id] + +:e Test.foo(1) -//│ 1 +//│ ╔══[ERROR] Type error in application +//│ ║ l.62: Test.foo(1) +//│ ║ ^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.62: Test.foo(1) +//│ ╙── ^ +//│ error | ??A //│ res //│ Runtime error: //│ TypeError: Test.foo is not a function -:re +:e Test.foo(error) + 1 -//│ int +//│ ╔══[ERROR] Type error in operator application +//│ ║ l.75: Test.foo(error) + 1 +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.75: Test.foo(error) + 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╙── into type `int` +//│ error | int //│ res //│ Runtime error: //│ Error: unexpected runtime error @@ -34,7 +88,7 @@ Test.foo(error) + 1 :e Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.35: Test .foo +//│ ║ l.89: Test .foo //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -43,7 +97,7 @@ Test .foo :e (Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.44: (Test).foo +//│ ║ l.98: (Test).foo //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -58,34 +112,34 @@ Test :e Test: Test<'a> //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.59: Test: Test<'a> -//│ ║ ^^^^ +//│ ║ l.113: Test: Test<'a> +//│ ║ ^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.59: Test: Test<'a> -//│ ║ ^^ +//│ ║ l.113: Test: Test<'a> +//│ ║ ^^ //│ ╟── back into type variable `A` //│ ║ l.5: module Test { //│ ╙── ^ //│ Test['a] //│ where -//│ 'a :> error | ??A +//│ 'a :> ??A //│ <: ??A0 //│ res //│ = Test { class: [class Test] } fun test(x) = if x is Test then x.foo -//│ fun test: forall 'A. Test['A] -> (forall 'A0. 'A0 -> 'A0) +//│ fun test: forall 'A. Test['A] -> 'A -> 'A :e test(Test) //│ ╔══[ERROR] Type error in application -//│ ║ l.81: test(Test) -//│ ║ ^^^^^^^^^^ +//│ ║ l.135: test(Test) +//│ ║ ^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope //│ ║ l.5: module Test { //│ ╙── ^ -//│ forall 'A. 'A -> 'A | error +//│ (??A & 'A) -> ('A | ??A0) | error //│ res //│ = undefined @@ -112,9 +166,10 @@ module Test { //│ } Test.foo -//│ forall 'A. 'A -> 'A +//│ (??A & 'A) -> ('A | ??A0) //│ res //│ = [Function: id] + diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index baf5cf4161..f510799a12 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -96,40 +96,40 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c,) -> 'd} -//│ this: {eval: ('b, 's,) -> ('e & 'f) & (List[out (string, 'f,)], 't,) -> 'd & (List[in 'a out 'a | 'a0 | (string, Var,)], 't0,) -> 'g} -//│ fun eval: forall 'a1. (List['a1] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) +//│ this: {eval: ('b, 's,) -> ('e & 'f) & (List[in 'a out 'a | (string, 'f,)], 't,) -> 'd & (List[in 'a0 out 'a0 | 'a1 | (string, Var,)], 't0,) -> 'g} +//│ fun eval: forall 'a2. (List['a2] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) //│ } //│ where -//│ 'a1 :> 'a | (string, Var,) -//│ <: 'a0 +//│ 'a2 :> 'a0 | (string, Var,) +//│ <: 'a1 module Test1 extends EvalVar, EvalLambda //│ module Test1() { -//│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> 'result +//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> 'b //│ } //│ where //│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | Var -//│ 'result :> anything +//│ 'b :> App['b] | Abs['b] | Var Test1.eval(Nil(), Var("a")) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'a :> Abs['a] | Var | App['a] Test1.eval(Nil(), Abs("b", Var("a"))) //│ 'a //│ where -//│ 'a :> Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Var Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'a :> Abs['a] | Var | App['a] Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> Abs[Var] | Var | App['a] | Abs['a] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var class Num(n: int) class Add(l: A, r: A) @@ -144,7 +144,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'A 'l 'A0 'l0. ('l -> 'A0 & 'l0 -> 'A, Add['l] | Mul['l0] | Num | Var,) -> (Add['A0] | Mul['A] | Num | Var) +//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) mixin EvalExpr { fun eval(sub, v) = @@ -184,29 +184,30 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: (List[{_1: string, _2: 'result}], 'a,) -> anything +//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> 'b //│ } //│ where -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | (Add['b] | Mul['b] | Num | Var) & ~#Abs & ~#App -//│ 'b <: 'a -//│ 'result :> anything -//│ <: Num +//│ 'b :> Num | Var | 'c | App['b] | Abs['b] +//│ 'c <: Add['d] | Mul['d] | Num | Var +//│ 'd <: 'a +//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | 'c & ~#Abs & ~#App Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Num | Var +//│ 'a :> Abs[Var] | Var | Num | App['a] | Abs['a] Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) //│ 'a //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var | Add[Num | Var] | Num module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: (List[{_1: string, _2: 'result}], nothing,) -> anything +//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> ('a | 'b) //│ } //│ where -//│ 'result :> anything -//│ <: Num +//│ 'b :> Abs['b] | App['b] | Var | Num | 'a +//│ 'a <: Add['c] | Mul['c] | Num | Var +//│ 'c <: 'a diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index f790f7f2fd..d930812b52 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -2,7 +2,6 @@ -// TODO use available type signatures! class Foo1(x: int) { fun test = Foo1(1).x } @@ -10,12 +9,11 @@ class Foo1(x: int) { //│ fun test: int //│ } -// TODO class Foo2[A](x: A) { fun test = Foo2(1).x } //│ class Foo2[A](x: A) { -//│ fun test: A +//│ fun test: 1 //│ } @@ -53,10 +51,10 @@ class Foo4 { fun test = [Foo4.test] } //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.53: fun test = [Foo4.test] +//│ ║ l.51: fun test = [Foo4.test] //│ ║ ^^^^^^^^^ //│ ╟── reference of type `() -> #Foo4` does not have field 'test' -//│ ║ l.53: fun test = [Foo4.test] +//│ ║ l.51: fun test = [Foo4.test] //│ ╙── ^^^^ //│ class Foo4() { //│ fun test: (error,) @@ -67,7 +65,7 @@ class Foo5(x: int) { fun test = [Foo5(5).test] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.67: fun test = [Foo5(5).test] +//│ ║ l.65: fun test = [Foo5(5).test] //│ ╙── ^^^^^ //│ class Foo5(x: int) { //│ fun test: (error,) @@ -80,13 +78,13 @@ class Foo6[A](x: A) { fun test3 = [Foo6([x]).test3] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.78: fun test1 = [Foo6(x).test1] +//│ ║ l.76: fun test1 = [Foo6(x).test1] //│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.79: fun test2 = [Foo6(123).test2] +//│ ║ l.77: fun test2 = [Foo6(123).test2] //│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.80: fun test3 = [Foo6([x]).test3] +//│ ║ l.78: fun test3 = [Foo6([x]).test3] //│ ╙── ^^^^^^ //│ class Foo6[A](x: A) { //│ fun test1: (error,) @@ -104,7 +102,7 @@ class Foo7[A](head: A, tail: Foo7[A] | N) { _ then tail.test1 } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.104: _ then tail.test1 +//│ ║ l.102: _ then tail.test1 //│ ╙── ^^^^^^ //│ class Foo7[A](head: A, tail: Foo7[A] | N) { //│ fun test1: A | error @@ -145,7 +143,7 @@ class Foo8[A](x: A) { x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.144: let tmp = Foo8(y).test1(x) +//│ ║ l.142: let tmp = Foo8(y).test1(x) //│ ╙── ^^^^^^ //│ class Foo8[A](x: A) { //│ fun test1: (y: anything,) -> A diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls new file mode 100644 index 0000000000..11cd86598a --- /dev/null +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -0,0 +1,62 @@ +:NewDefs + + +class Add(lhs: E, rhs: E) +class Lit(n: int) +class Neg(expr: A) +//│ class Add[E](lhs: E, rhs: E) +//│ class Lit(n: int) +//│ class Neg[A](expr: A) + + +// Note the inferred type because of current UCS limitation +mixin EvalBase { + fun eval(e) = + if e is Neg(Neg(d)) then this.eval(d) + else if e is Neg(d) then 0 - this.eval(d) + else if e is + Lit(n) then n + Add(l, r) then this.eval(l) + this.eval(r) +} +//│ mixin EvalBase() { +//│ this: {eval: nothing -> 'a & 'lhs -> int} +//│ fun eval: (Add['lhs] | Lit | Neg[nothing]) -> (int | 'a) +//│ } + +// module TestLang extends EvalBase, EvalNeg +module TestLang extends EvalBase +//│ module TestLang() { +//│ fun eval: 'a -> int +//│ } +//│ where +//│ 'a <: Add['a] | Lit | Neg[nothing] + + +fun mk(n) = if n is + 0 then Lit(0) + 1 then Neg(mk(n)) + _ then Add(mk(n), mk(n)) +//│ fun mk: forall 'E. number -> 'E +//│ where +//│ 'E :> Add['E] | Lit | Neg['E] + +// TODO support this in UCS +:stats +TestLang.eval(mk(0)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.45: TestLang.eval(mk(0)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Lit` does not match type `nothing` +//│ ║ l.36: 0 then Lit(0) +//│ ║ ^^^^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.6: class Neg(expr: A) +//│ ╙── ^ +//│ error | int +//│ res +//│ = 0 +//│ constrain calls : 242 +//│ annoying calls : 116 +//│ subtyping calls : 4071 + + diff --git a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls new file mode 100644 index 0000000000..b995026755 --- /dev/null +++ b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls @@ -0,0 +1,32 @@ +:NewDefs + +// Test that reprduces subtle type simplification bug + +class Cons[out A](head: A, tail: Cons[A] | Nil) +module Nil +//│ class Cons[A](head: A, tail: Cons[A] | Nil) +//│ module Nil() + +class Abs[A](x: string, t: A) +class App[A](s: A, t: A) +//│ class Abs[A](x: string, t: A) +//│ class App[A](s: A, t: A) + +mixin EvalLambda { + fun eval(sub, v) = + if v is + Abs(x, t) then + this.eval(Cons((error, error), Nil), error) + this.eval(Cons((x, error), sub), error) + error +} +//│ mixin EvalLambda() { +//│ this: {eval: (Cons[(string, nothing,) | 'A], nothing,) -> anything} +//│ fun eval: (Cons['A] | Nil, Abs[anything],) -> nothing +//│ } + +// FIXME type simplification bug: analyze2 does not traverse TVs witht he correct PolMap +// :ds +module Test1 extends EvalLambda +//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: x46_115' has no occurrences... + From d6fe4bb7c7944053e553bf729effea0332bcd183 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 25 Mar 2023 01:17:28 +0800 Subject: [PATCH 227/498] WIP Very basic support for parameterless type selection --- .../scala/mlscript/ConstraintSolver.scala | 45 +++++++++++++++---- shared/src/main/scala/mlscript/Typer.scala | 28 ++++++++++++ shared/src/main/scala/mlscript/helpers.scala | 4 ++ shared/src/main/scala/mlscript/syntax.scala | 1 + shared/src/test/diff/nu/ClassesInMixins.mls | 2 +- shared/src/test/diff/nu/NestedClasses.mls | 2 +- shared/src/test/diff/nu/TypeSelections.mls | 43 ++++++++++++++++++ 7 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 shared/src/test/diff/nu/TypeSelections.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index b9d2d209f6..8441794ea4 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -23,7 +23,34 @@ class ConstraintSolver extends NormalForms { self: Typer => protected var currentConstrainingRun = 0 + private def noSuchMember(info: DelayedTypeInfo, fld: Var): Diagnostic = + ErrorReport( + msg"${info.decl.kind.str.capitalize} `${info.decl.name}` does not contain member `${fld.name}`" -> fld.toLoc :: Nil) + def lookupMember(clsNme: Str, rfnt: Var => Opt[FieldType], fld: Var) + (implicit ctx: Ctx, raise: Raise) + : Either[Diagnostic, NuMember] + = { + val info = ctx.tyDefs2(clsNme) + + if (info.isComputing) { + + ??? // TODO support? + + } else info.complete() match { + + case cls: TypedNuCls => + cls.members.get(fld.name) match { + case S(m) => R(m) + case N => L(noSuchMember(info, fld)) + } + + case _ => ??? // TODO + + } + + } + def lookupField(clsNme: Str, rfnt: Var => Opt[FieldType], fld: Var) (implicit ctx: Ctx, raise: Raise) : FieldType = { @@ -34,8 +61,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val fromRft = rfnt(fld) def nope = - err(msg"${info.decl.kind.str.capitalize} `${info.decl.name}` does not contain member `${fld.name}`", - fld.toLoc).toUpper(noProv) + err(noSuchMember(info, fld)).toUpper(noProv) // * The raw type of this member, with original references to the class' type variables/type parameters val raw = if (info.isComputing) { @@ -61,8 +87,8 @@ class ConstraintSolver extends NormalForms { self: Typer => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => S(p.ty) - case S(_) => - S(err(msg"access to ${cls.td.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) + case S(m) => + S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) case N => fromRft match { case S(fty) => N @@ -593,7 +619,7 @@ class ConstraintSolver extends NormalForms { self: Typer => if ctx.tyDefs2.contains(nme) => if (newDefs && fldNme.name === "Eql#A") { val info = ctx.tyDefs2(nme) info.typedParams.foreach { p => - val fty = lookupMember(nme, r.fields.toMap.get, p._1) + val fty = lookupField(nme, r.fields.toMap.get, p._1) rec(fldTy.lb.get, RecordType(p._1 -> TypeRef(TypeName("Eql"), fty.ub // FIXME check mutable? :: Nil @@ -605,7 +631,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? // else { // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) - val fty = lookupMember(nme, r.fields.toMap.get, fldNme) + val fty = lookupField(nme, r.fields.toMap.get, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) // } @@ -835,7 +861,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case (fldNme @ Var("Eql#A"), fldTy) => goToWork(lhs, RecordType(fldNme -> fldTy :: Nil)(noProv)) case (fldNme, fldTy) => - val fty = lookupMember(nme, _ => N, fldNme) + val fty = lookupField(nme, _ => N, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) } @@ -1443,7 +1469,10 @@ class ConstraintSolver extends NormalForms { self: Typer => err(msg -> loco :: Nil) } def err(msgs: List[Message -> Opt[Loc]])(implicit raise: Raise): SimpleType = { - raise(ErrorReport(msgs)) + err(ErrorReport(msgs)) + } + def err(diag: Diagnostic)(implicit raise: Raise): SimpleType = { + raise(diag) errType } def errType: SimpleType = ClassTag(ErrTypeId, Set.empty)(noProv) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index ceb0038012..0afe848adc 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -478,6 +478,34 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) TypeRef(base, realTargs)(prov) case L(e) => e() } + case Selection(base, nme) => + implicit val gl: GenLambdas = false + // val base_ty = typeTerm(base) + val base_ty = rec(base) + def go(b_ty: ST, rfnt: Var => Opt[FieldType]): ST = b_ty.unwrapAll match { + case ct: TypeRef => die // TODO actually + case ClassTag(Var(clsNme), _) => + // ctx.tyDefs2.get(clsNme) match { + // case S(lti) => + // ??? + // case N => die + // } + + // TODO we should still succeed even if the member is not completed... + lookupMember(clsNme, rfnt, nme.toVar) match { + case R(cls: TypedNuCls) => + if (cls.tparams.nonEmpty) ??? // TODO + clsNameToNomTag(cls.td)(TypeProvenance(ty.toLoc, "type selection", isType = true), ctx) + case R(als: TypedNuAls) => + if (als.tparams.nonEmpty) ??? // TODO + als.body + case R(m) => err(msg"Illegal selection of ${m.kind.str} member in type position", nme.toLoc) + case L(d) => err(d) + } + case _ => + err(msg"Illegal prefix of type selection: ${b_ty.expPos}", base.toLoc) + } + go(base_ty, _ => N) case Recursive(uv, body) => val tv = freshVar(tyTp(ty.toLoc, "local type binding"), N, uv.name) val bod = rec(body)(ctx, recVars + (uv -> tv)) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index f19182001e..46f5f31ebb 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -81,6 +81,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => // case AppliedType(n, args) => s"${n.name}${args.map(_.showIn(ctx, 0)).mkString(ctx.<, ", ", ctx.>)}" + case Selection(b, n) => b.showIn(ctx, 100) + "." + n.name case Rem(b, ns) => s"${b.showIn(ctx, 90)}${ns.map("\\"+_).mkString}" case Literal(IntLit(n)) => n.toString case Literal(DecLit(n)) => n.toString @@ -168,6 +169,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Inter(l, r) => l :: r :: Nil case Recursive(n, b) => b :: Nil case AppliedType(n, ts) => ts + case Selection(b, nme) => b :: nme :: Nil case Rem(b, _) => b :: Nil case WithExtension(b, r) => b :: r :: Nil case PolyType(targs, body) => targs.map(_.fold(identity, identity)) :+ body @@ -668,6 +670,8 @@ trait TermImpl extends StatementImpl { self: Term => case Forall(ps, bod) => PolyType(ps.map(R(_)), bod.toType_!) // + case Sel(receiver, field) => + Selection(receiver.toType_!, TypeName(field.name).withLocOf(field)) case Sel(receiver, fieldName) => receiver match { case Var(name) if !name.startsWith("`") => TypeName(s"$name.$fieldName") case _ => throw new NotAType(this) diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 1e91511d21..10c840c2ee 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -135,6 +135,7 @@ final case class Record(fields: Ls[Var -> Field]) extends Type final case class Tuple(fields: Ls[Opt[Var] -> Field]) extends Type final case class Recursive(uv: TypeVar, body: Type) extends Type final case class AppliedType(base: TypeName, targs: List[Type]) extends Type with NamedType +final case class Selection(base: Type, name: TypeName) extends Type final case class Neg(base: Type) extends Type final case class Rem(base: Type, names: Ls[Var]) extends Type final case class Bounds(lb: Type, ub: Type) extends Type diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index d18a1d346a..5dd8012c96 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -26,7 +26,7 @@ M.f.n :e M.Foo -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] access to class member not yet supported //│ ║ l.28: M.Foo //│ ╙── ^^^^ //│ error diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index b8663f5687..0b013ee43e 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -32,7 +32,7 @@ module M0 { :e M0.NC0 -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] access to class member not yet supported //│ ║ l.34: M0.NC0 //│ ╙── ^^^^ //│ error diff --git a/shared/src/test/diff/nu/TypeSelections.mls b/shared/src/test/diff/nu/TypeSelections.mls new file mode 100644 index 0000000000..7a007c27f5 --- /dev/null +++ b/shared/src/test/diff/nu/TypeSelections.mls @@ -0,0 +1,43 @@ +:NewDefs + + +:ge // TODO +module M { + type T = int -> int + class C(n: int) + fun mkC = C +} +//│ module M() { +//│ class C(n: int) +//│ type T = int -> int +//│ fun mkC: (n: int,) -> C +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol C + +let x: M.T = id +//│ let x: int -> int +//│ x +//│ = [Function: id] + +fun foo(x: M.C) = x +//│ fun foo: (x: C,) -> C + +:re // TODO +foo(M.mkC(42)) +//│ C +//│ res +//│ Runtime error: +//│ ReferenceError: M is not defined + + +:e +42 : M.mkC +//│ ╔══[ERROR] Illegal selection of value member in type position +//│ ║ l.35: 42 : M.mkC +//│ ╙── ^^^^ +//│ error +//│ res +//│ = 42 + + From 96cdb816fc4d8e33cfd2b181440908848dee1170 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sun, 26 Mar 2023 23:52:53 +0800 Subject: [PATCH 228/498] Add zipWith tests --- shared/src/test/diff/ucs/zipWith.mls | 207 +++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 shared/src/test/diff/ucs/zipWith.mls diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls new file mode 100644 index 0000000000..2191a095f1 --- /dev/null +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -0,0 +1,207 @@ +:NewDefs + + + +:escape +let undefined: nothing +//│ let undefined: nothing +//│ undefined +//│ = + +module None { + fun value = undefined +} +class Some[out A](value: A) +//│ module None() { +//│ fun value: nothing +//│ } +//│ class Some[A](value: A) + +type List[out A] = Cons[A] | Nil +module Nil { + fun toArray = [] +} +class Cons[out A](head: A, tail: List[A]) { + fun toArray: Array[anything] + fun toArray = [head, tail.toArray] +} +//│ type List[A] = Cons[A] | Nil +//│ module Nil() { +//│ fun toArray: () +//│ } +//│ class Cons[A](head: A, tail: List[A]) { +//│ fun toArray: Array[anything] +//│ } + +fun pairup(x, y) = [x, y] +//│ fun pairup: forall 'a 'b. ('a, 'b,) -> ('a, 'b,) + + + +// FIXME parsing +fun zipWith_wrong(f, xs, ys) = + if xs is Cons(x, xs) + and ys is Cons(y, ys) + and zipWith_wrong(f, xs, ys) is Some(tail) + then Some(Cons(f(x, y), tail)) + else None +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application followed by newline instead +//│ ║ l.43: if xs is Cons(x, xs) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.44: and ys is Cons(y, ys) +//│ ║ ^^ +//│ ╟── Note: 'if' expression started here: +//│ ║ l.43: if xs is Cons(x, xs) +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Unexpected operator in expression position +//│ ║ l.44: and ys is Cons(y, ys) +//│ ╙── ^^^ +//│ ╔══[PARSE ERROR] Unexpected operator in expression position +//│ ║ l.45: and zipWith_wrong(f, xs, ys) is Some(tail) +//│ ╙── ^^^ +//│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead +//│ ║ l.43: if xs is Cons(x, xs) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.44: and ys is Cons(y, ys) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.45: and zipWith_wrong(f, xs, ys) is Some(tail) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.46: then Some(Cons(f(x, y), tail)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.47: else None +//│ ╙── ^^^^^^^^^^^ +//│ fun zipWith_wrong: (anything, anything, anything,) -> undefined + + +// FIXME parsing +fun zipWith_wrong(f, xs, ys) = + if xs is Cons(x, xs) + and ys is Cons(y, ys) + and zipWith_wrong(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) + else None +//│ ╔══[ERROR] illegal pattern +//│ ║ l.78: if xs is Cons(x, xs) +//│ ║ ^^^^^^^^^^^ +//│ ║ l.79: and ys is Cons(y, ys) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ fun zipWith_wrong: (anything, anything, anything,) -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + +fun zipWith_wrong(f, xs, ys) = + if xs is Cons(x, xs) + and ys is Cons(y, ys) and zipWith_wrong(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) + else None +//│ fun zipWith_wrong: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A]]) + +// * Notice the result is wrong (duh) +zipWith_wrong(pairup, Nil, Nil) +//│ None | Some[Cons[(nothing, nothing,)]] +//│ res +//│ = None { class: [class None] } + + + +fun zipWith(f, xs, ys) = + if xs is + Cons(x, xs) and ys is Cons(y, ys) and zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) + Nil and ys is Nil then Some(Nil) + else None +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) + +zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray +//│ Array[anything] +//│ res +//│ = [ [ 0, '0' ], [] ] + + +fun zipWith(f, xs, ys) = + if xs is + Cons(x, xs) and ys is Cons(y, ys) and zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) + Nil and ys is Nil then Some(Nil) + else None +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) + +zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray +//│ Array[anything] +//│ res +//│ = [ [ 0, '0' ], [] ] + + +fun zipWith(f, xs, ys) = + if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) + else if xs is Nil and ys is Nil then Some(Nil) + else None +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) + +zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray +//│ Array[anything] +//│ res +//│ = [ [ 0, '0' ], [] ] + + +fun zipWith(f, xs, ys) = + if xs is Cons(x, xs) and ys is Cons(y, ys) then + if zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) + else None + else if xs is Nil and ys is Nil then Some(Nil) + else None +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) + +zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray +//│ Array[anything] +//│ res +//│ = [ [ 0, '0' ], [] ] + + +fun zipWith(f, xs, ys) = + if xs is + Cons(x, xs) then + if ys is + Cons(y, ys) then + if zipWith(f, xs, ys) is + Some(tail) then Some(Cons(f(x, y), tail)) + None then None + Nil then None + Nil then + if ys is Nil then Some(Nil) else None +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Nil, Cons['head0] | Nil,) -> (None | Some[Cons['A] | Nil]) + +zipWith(pairup, Nil, Nil).value.toArray +//│ Array[anything] +//│ res +//│ = [] + +:re +zipWith(pairup, Nil, Cons(0, Nil)).value.toArray +//│ Array[anything] +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'toArray') + +zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray +//│ Array[anything] +//│ res +//│ = [ [ 0, '0' ], [] ] + +zipWith(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))).value.toArray +//│ Array[anything] +//│ res +//│ = [ [ 0, '0' ], [ [ 1, '1' ], [] ] ] + + + +fun zipWith_wrong2(f, xs, ys) = + if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith_wrong2(f, xs, ys) is Some(tail) then Cons(Some(f(x, y)), tail) + else if xs is Nil and ys is Nil then Some(Nil) + else None +//│ fun zipWith_wrong2: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (Cons[Some['A]] | None | Some[Nil]) + +// * No type error! The definition and use are well-typed... +zipWith_wrong2(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))) +//│ Cons[Some[(0 | 1, "0" | "1",)]] | None | Some[Nil] +//│ res +//│ = None { class: [class None] } + + From ba3091b2eae22e9e2916331bc2387f8cbfc5b75e Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Mar 2023 12:13:50 +0800 Subject: [PATCH 229/498] WIP Parse `declare` keyword and avoid codegen accordingly --- .../src/main/scala/mlscript/JSBackend.scala | 48 +++++++---- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 60 +++++++++++-- .../src/main/scala/mlscript/NuTypeDefs.scala | 5 +- shared/src/main/scala/mlscript/Typer.scala | 14 +--- .../main/scala/mlscript/codegen/Scope.scala | 8 +- shared/src/main/scala/mlscript/helpers.scala | 84 +------------------ shared/src/main/scala/mlscript/syntax.scala | 4 +- shared/src/test/diff/nu/Declarations.mls | 77 +++++++++++++++++ 9 files changed, 175 insertions(+), 126 deletions(-) create mode 100644 shared/src/test/diff/nu/Declarations.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 1e8bd0828f..f3285bc8d6 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -831,28 +831,28 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } typeDefs.foreach { - case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members, stmts) = prepare(mxName, fs, pars, unit) val sym = topLevelScope.declareMixin(mxName, tps map { _._2.name }, body, members, stmts) - mixins += sym + if (!td.isDecl) mixins += sym } - case NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members, stmts) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members, stmts, pars) - modules += sym + if (!td.isDecl) modules += sym } - case NuTypeDef(Als, TypeName(nme), tps, _, sig, pars, _, _, _) => { + case td @ NuTypeDef(Als, TypeName(nme), tps, _, sig, pars, _, _, _) => { topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) } - case NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members, stmts) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareNewClass(nme, tps map { _._2.name }, body, members, stmts, pars) - classes += sym + if (!td.isDecl) classes += sym } - case NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members, _) = prepare(nme, fs, pars, unit) val sym = topLevelScope.declareTrait(nme, tps map { _._2.name }, body, members) - traits += sym + if (!td.isDecl) traits += sym } } (traits.toList, classes.toList, mixins.toList, modules.toList) @@ -977,7 +977,12 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { private def generateNewDef(pgrm: Pgrm): (Ls[Str], Ls[Str]) = { val mlsModule = topLevelScope.declareValue("typing_unit", Some(false), false) - val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared + val (typeDefs, otherStmts) = pgrm.tops.partitionMap { + case ot: Terms => R(ot) + case fd: NuFunDef => R(fd) + case nd: NuTypeDef => L(nd) + case _ => die + } val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDefs) def include(typeName: Str, moduleName: Str) = @@ -986,13 +991,13 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { traitSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ mixinSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ moduleSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - classSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)).toList + classSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) val defs = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ moduleSymbols.map { translateModuleDeclaration(_)(topLevelScope) } ++ - classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) }.toList + classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) } val defStmts = JSLetDecl(Ls(mlsModule.runtimeName -> S(JSRecord(Ls("cache" -> JSRecord(Ls())), defs)))) :: includes @@ -1169,14 +1174,19 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { val mlsModule = topLevelScope.declareValue("typing_unit", Some(false), false) - val (diags, (typeDefs, otherStmts)) = pgrm.newDesugared + val (typeDefs, otherStmts) = pgrm.tops.partitionMap { + case ot: Terms => R(ot) + case fd: NuFunDef => R(fd) + case nd: NuTypeDef => L(nd) + case _ => die + } val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDefs) val defStmts = traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ moduleSymbols.map { translateModuleDeclaration(_)(topLevelScope) } ++ - classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) }.toList + classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) } def include(typeName: Str, moduleName: Str) = JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) @@ -1184,7 +1194,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { traitSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ mixinSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ moduleSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - classSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)).toList + classSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) val zeroWidthSpace = JSLit("\"\\u200B\"") val catchClause = JSCatchClause( @@ -1194,7 +1204,9 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { // Generate statements. val queries = otherStmts.map { - case Def(recursive, Var(name), L(body), isByname) => + case NuFunDef(isLetRec, nme @ Var(name), tys, rhs @ L(body)) => + val recursive = isLetRec.getOrElse(true) + val isByname = isLetRec.isEmpty val bodyIsLam = body match { case _: Lam => true case _ => false } (if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) @@ -1241,8 +1253,8 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { ) case L(reason) => JSTestBackend.AbortedQuery(reason) } - case Def(_, Var(name), _, _) => - scope.declareStubValue(name) + case fd @ NuFunDef(isLetRec, Var(name), tys, R(ty)) => + scope.declareStubValue(name)(allowEscape || fd.isDecl) JSTestBackend.EmptyQuery case term: Term => try { diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 57c2f88b4a..07f4629160 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -261,6 +261,7 @@ object NewLexer { // "any", // "all", "mut", + "declare", "class", "trait", "mixin", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index cc1c150aba..286f983122 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -150,6 +150,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D private var _cur: Ls[TokLoc] = tokens + private var _modifiersCache: ModifierSet = ModifierSet.empty + def resetCur(newCur: Ls[TokLoc]): Unit = { + _cur = newCur + _modifiersCache = ModifierSet.empty + } private def summarizeCur = NewLexer.printTokens(_cur.take(5)) + (if (_cur.sizeIs > 5) "..." else "") @@ -165,7 +170,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D final def consume(implicit l: Line, n: Name): Unit = { if (dbg) printDbg(s"! ${n.value}\t\tconsumes ${NewLexer.printTokens(_cur.take(1))} [at l.${l.value}]") - _cur = _cur.tailOption.getOrElse(Nil) // FIXME throw error if empty? + resetCur(_cur.tailOption.getOrElse(Nil)) // FIXME throw error if empty? } // TODO simplify logic – this is no longer used much @@ -251,6 +256,40 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case R(ty) => ty } + case class ModifierSet(mods: Map[Str, Loc]) { + def handle(mod: Str): (Opt[Loc], ModifierSet) = + mods.get(mod) -> copy(mods = mods - mod) + def done: Unit = mods.foreach { + case (mod, loc) => + err(msg"Unrecognized modifier `${mod}` in this position" -> S(loc) :: Nil) + } + } + object ModifierSet { + val empty: ModifierSet = ModifierSet(Map.empty) + private def go(acc: ModifierSet): ModifierSet = cur match { + case (KEYWORD(kw), l0) :: c if acc.mods.contains(kw) => + err(msg"Repeated modifier `${kw}`" -> S(l0) :: Nil) + consume + yeetSpaces + go(acc) + case (KEYWORD("declare"), l0) :: c => + consume + yeetSpaces + go(acc.copy(acc.mods + ("declare" -> l0))) + case _ if acc.mods.isEmpty => acc + case (KEYWORD("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module" | "fun"), l0) :: _ => + acc + case (tok, loc) :: _ => + // TODO support indented blocks of modified declarations... + err(msg"Unexpected ${tok.describe} token after modifier${if (acc.mods.sizeIs > 1) "s" else ""}" -> S(loc) :: Nil) + acc + } + def unapply(__ : Ls[TokLoc]): S[ModifierSet -> Ls[TokLoc]] = { + val res = go(_modifiersCache) + _modifiersCache = res + S(res, _cur) + } + } final def block(implicit et: ExpectThen, fe: FoundErr): Ls[IfBody \/ Statement] = cur match { case Nil => Nil @@ -258,8 +297,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (SPACE, _) :: _ => consume; block case c => val t = c match { - case (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c => + case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c) => consume + val (isDecl, mods2) = mods.handle("declare") + mods2.done val kind = k match { case "class" => Cls case "trait" => Trt @@ -329,12 +370,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => Nil } val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body) + val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body)(isDecl) R(res.withLoc(S(l0 ++ res.getLoc))) - // TODO make `fun` by-name and `let` by-value - case (KEYWORD(kwStr @ ("fun" | "let")), l0) :: c => // TODO support rec? + case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "let")), l0) :: c) => // TODO support rec? consume + val (isDecl, mods2) = mods.handle("declare") + mods2.done val isLetRec = yeetSpaces match { case (KEYWORD("rec"), l1) :: _ if kwStr === "let" => consume @@ -368,7 +410,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } val (ps, transformBody) = yeetSpaces match { case (br @ BRACKETS(Round, Spaces(cons, (KEYWORD("override"), ovLoc) :: rest)), loc) :: rest2 => - _cur = BRACKETS(Round, rest)(br.innerLoc) -> loc :: rest2 + resetCur(BRACKETS(Round, rest)(br.innerLoc) -> loc :: rest2) funParams match { case ps @ Tup(N -> Fld(false, false, pat) :: Nil) :: Nil => val fv = freshVar @@ -397,7 +439,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D val body = expr(0) val newBody = transformBody.fold(body)(_(body)) val annotatedBody = asc.fold(newBody)(ty => Asc(newBody, ty)) - R(NuFunDef(isLetRec, v, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))))) + R(NuFunDef(isLetRec, v, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))))(isDecl)) case c => asc match { case S(ty) => @@ -405,14 +447,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D R(NuFunDef(isLetRec, v, tparams, R(PolyType(Nil, ps.foldRight(ty)((p, r) => Function(p.toType match { case L(diag) => raise(diag); Top // TODO better case R(tp) => tp - }, r)))))) // TODO rm PolyType after FCP is merged + }, r)))))(isDecl)) // TODO rm PolyType after FCP is merged case N => // TODO dedup: val (tkstr, loc) = c.headOption.fold(("end of input", lastLoc))(_.mapFirst(_.describe).mapSecond(some)) err(( msg"Expected ':' or '=' followed by a function body or signature; found ${tkstr} instead" -> loc :: Nil)) consume - R(NuFunDef(isLetRec, v, Nil, L(ps.foldRight(errExpr: Term)((i, acc) => Lam(i, acc))))) + R(NuFunDef(isLetRec, v, Nil, L(ps.foldRight(errExpr: Term)((i, acc) => Lam(i, acc))))(isDecl)) } } } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 51f4ff10a5..88eaf4bff1 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -539,7 +539,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if (isComputing) { val ty = err(msg"Unhandled cyclic definition", decl.toLoc) // * Hacky: return a dummy decl to avoid possible infinite completion recursions - TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top)), ty) + TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top))(N), ty) } else trace(s"Completing ${decl.showDbg}") { println(s"Type params ${tparams.mkString(" ")}") @@ -810,7 +810,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(mem: NuParam) => case S(_) => ??? // TODO case N => - err(msg"Member ${fd.nme.name} is declared but not defined", fd.nme.toLoc) + if (!td.isDecl) + err(msg"Member ${fd.nme.name} is declared but not defined", fd.nme.toLoc) } } } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 0afe848adc..027ac7b42b 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -485,12 +485,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def go(b_ty: ST, rfnt: Var => Opt[FieldType]): ST = b_ty.unwrapAll match { case ct: TypeRef => die // TODO actually case ClassTag(Var(clsNme), _) => - // ctx.tyDefs2.get(clsNme) match { - // case S(lti) => - // ??? - // case N => die - // } - // TODO we should still succeed even if the member is not completed... lookupMember(clsNme, rfnt, nme.toVar) match { case R(cls: TypedNuCls) => @@ -1316,7 +1310,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => - NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil)) + NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))(td.declareLoc) } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => ectx(tparams) |> { implicit ectx => @@ -1326,7 +1320,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members)) + mkTypingUnit(thisTy, members))(td.declareLoc) } case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => ectx(tparams) |> { implicit ectx => @@ -1336,10 +1330,10 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members)) + mkTypingUnit(thisTy, members))(td.declareLoc) } case tf @ TypedNuFun(level, fd, bodyTy) => - NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature))) + NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc) case p: NuParam => ??? // TODO } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index d96effd883..a23704d1bc 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -304,16 +304,16 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } - def declareStubValue(lexicalName: Str)(implicit accessible: Bool): StubValueSymbol = + def declareStubValue(lexicalName: Str)(implicit allowEscape: Bool): StubValueSymbol = declareStubValue(lexicalName, N) def declareStubValue(lexicalName: Str, previous: StubValueSymbol)(implicit - accessible: Bool + allowEscape: Bool ): StubValueSymbol = declareStubValue(lexicalName, S(previous)) private def declareStubValue(lexicalName: Str, previous: Opt[StubValueSymbol])(implicit - accessible: Bool + allowEscape: Bool ): StubValueSymbol = { val symbol = lexicalValueSymbols.get(lexicalName) match { @@ -327,7 +327,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { } def stubize(sym: ValueSymbol, previous: StubValueSymbol)(implicit - accessible: Bool + allowEscape: Bool ): StubValueSymbol = { unregister(sym) declareStubValue(sym.lexicalName, S(previous)) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 46f5f31ebb..02cd4c9f00 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -350,84 +350,7 @@ trait PgrmImpl { self: Pgrm => } diags.toList -> res } - lazy val newDesugared: (Ls[Diagnostic] -> (Ls[NuTypeDef], Ls[Terms])) = { - val diags = Buffer.empty[Diagnostic] - val res = tops.flatMap { s => s match { - case nd: NuTypeDef => { - diags ++= tryDesugaredNewDec(nd) - Ls(nd) - } - case _ => { - val (ds, d) = s.desugared - diags ++= ds - d - } - } - }.partitionMap { - case ot: Terms => R(ot) - case nd: NuTypeDef => L(nd) - case NuFunDef(isLetRec, nme, tys, rhs) => - R(Def(isLetRec.getOrElse(true), nme, rhs, isLetRec.isEmpty)) - } - diags.toList -> res - } override def toString = tops.map("" + _ + ";").mkString(" ") - - // TODO remove this senseless method - private def tryDesugaredNewDec(nd: NuTypeDef): Ls[Diagnostic] = nd match { - case NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => - val bases = pars.foldLeft(Var("base"): Term)((res, p) => p match { - case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) - case _ => Var("anything") // ?? FIXME - }) - tryDesugaredNewDec(NuTypeDef(Cls, TypeName(mxName), tps, tup, sig, Ls(bases), sup, ths, unit)) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => - if (pars.length > 0) { - val bases = pars.drop(1).foldLeft(App(pars.head, Tup(Ls())): Term)((res, p) => p match { - case Var(pname) => App(Var(pname), Tup(Ls(None -> Fld(false, false, res)))) - case App(pname, _) => App(pname, Tup(Ls(None -> Fld(false, false, res)))) - case _ => Var("anything") // ?? FIXME - }) - tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, sig, Ls(bases), sup, ths, unit)) - } - else { - tryDesugaredNewDec(NuTypeDef(Cls, nme, tps, tup, sig, Ls(), sup, ths, unit)) - } - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => - // TODO properly check: - // require(fs.isEmpty, fs) - // require(sig.isDefined) - // require(pars.size === 0, pars) - require(ths.isEmpty, ths) - require(unit.entities.isEmpty, unit) - // val (diags, rhs) = sig.get match { - // case L(ds) => (ds :: Nil) -> Top - // case R(ty) => Nil -> ty - // } - Nil - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => - val diags = Buffer.empty[Diagnostic] - def tt(trm: Term): Type = trm.toType match { - case L(ds) => diags += ds; Top - case R(ty) => ty - } - val params = fs.map { - case (S(nme), Fld(mut, spec, trm)) => - val ty = tt(trm) - nme -> Field(if (mut) S(ty) else N, ty) - case (N, Fld(mut, spec, nme: Var)) => nme -> Field(if (mut) S(Bot) else N, Top) - case _ => die - } - val pos = params.unzip._1 - val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) - val termName = Var(nme.name).withLocOf(nme) - val mthDefs = unit.children.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { - case NuFunDef(isLetRec, mnme, tys, Left(rhs)) => lst :+ MethodDef(isLetRec.getOrElse(false), nme, mnme, tys, Left(rhs)) - case _ => lst - }) - // TODO: mthDecls - diags.toList - } } object OpApp { @@ -464,10 +387,9 @@ trait DeclImpl extends Located { self: Decl => trait NuDeclImpl extends Located { self: NuDecl => val body: Located def kind: DeclKind - // val name: Str = self match { - // case td: NuTypeDef => td.nme.name - // case fd: NuFunDef => fd.nme.name - // } + val declareLoc: Opt[Loc] + def isDecl: Bool = declareLoc.nonEmpty + def declStr: Str = if (isDecl) "declare " else "" val nameVar: Var = self match { case td: NuTypeDef => td.nme.toVar case fd: NuFunDef => fd.nme diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 10c840c2ee..fba2e39ded 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -186,14 +186,14 @@ final case class NuTypeDef( superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit -) extends NuDecl with Statement +)(val declareLoc: Opt[Loc]) extends NuDecl with Statement final case class NuFunDef( isLetRec: Opt[Bool], // None means it's a `fun`, which is always recursive; Some means it's a `let` nme: Var, tparams: Ls[TypeName], rhs: Term \/ Type, -) extends NuDecl with DesugaredStatement { +)(val declareLoc: Opt[Loc]) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) def kind: DeclKind = Val } diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls new file mode 100644 index 0000000000..a5a960892c --- /dev/null +++ b/shared/src/test/diff/nu/Declarations.mls @@ -0,0 +1,77 @@ +:NewDefs + + + +declare fun console: nothing +//│ fun console: nothing + +console.error("hello") +//│ nothing +//│ res +//│ = undefined +//│ // Output +//│ hello + + +declare module console { + fun error: string -> unit +} +//│ module console() { +//│ fun error: string -> unit +//│ } + +console.error("hello") +//│ unit +//│ res +//│ = undefined +//│ // Output +//│ hello + +:e +console.log("hello") +//│ ╔══[ERROR] Module `console` does not contain member `log` +//│ ║ l.31: console.log("hello") +//│ ╙── ^^^^ +//│ error +//│ res +//│ = undefined + + +declare module Foo { + fun foo: int +} +//│ module Foo() { +//│ fun foo: int +//│ } + +:re +Foo.foo +//│ int +//│ res +//│ Runtime error: +//│ ReferenceError: Foo is not defined + + +declare type A = int +//│ type A = int + +42 : A +//│ A +//│ res +//│ = 42 + + + +:pe +declare 42 +//│ ╔══[PARSE ERROR] Unexpected literal token after modifier +//│ ║ l.66: declare 42 +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Unexpected literal token after modifier +//│ ║ l.66: declare 42 +//│ ╙── ^^ +//│ 42 +//│ res +//│ = 42 + + From 534ece1a64a87473cbbb1089016803992e2531b0 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 27 Mar 2023 12:04:05 +0800 Subject: [PATCH 230/498] WIP Add some tests & fix handling of codegen errors --- shared/src/test/diff/gadt/Exp1.mls | 90 +++++++++++++++++++ shared/src/test/diff/nu/BadClasses.mls | 11 ++- shared/src/test/diff/nu/BadScopes.mls | 9 +- shared/src/test/diff/nu/BadUCS.mls | 30 +++---- shared/src/test/diff/nu/GenericMethods.mls | 15 ++-- shared/src/test/diff/nu/OverrideShorthand.mls | 9 +- shared/src/test/diff/nu/TypeVariables.mls | 23 +++++ .../src/test/scala/mlscript/DiffTests.scala | 2 +- 8 files changed, 144 insertions(+), 45 deletions(-) create mode 100644 shared/src/test/diff/gadt/Exp1.mls create mode 100644 shared/src/test/diff/nu/TypeVariables.mls diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls new file mode 100644 index 0000000000..2134a738bc --- /dev/null +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -0,0 +1,90 @@ +:NewDefs + + +// TODO enable class signatures +class Exp[A]: Pair | Lit { + fun test = if this is + Lit then 0 + Pair then 1 +} +// TODO enable class inheritance +class Lit(n: int) extends Exp[int] +class Pair[L, R](lhs: L, rhs: R) extends Exp[A] +//│ ╔══[ERROR] Type Pair takes parameters +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ╙── ^^^^ +//│ ╔══[ERROR] type signatures not yet supported for classes +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.11: class Lit(n: int) extends Exp[int] +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.6: fun test = if this is +//│ ║ ^^^^^^^ +//│ ║ l.7: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.8: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── reference of type `#Exp & {Exp#A = ?A}` does not match type `Lit | Pair[?L, ?R]` +//│ ║ l.6: fun test = if this is +//│ ╙── ^^^^ +//│ class Exp[A]() { +//│ fun test: 0 | 1 +//│ } +//│ class Lit(n: int) +//│ class Pair[L, R](lhs: L, rhs: R) + +:e // TODO +Lit(0).test +//│ ╔══[ERROR] Class `Lit` does not contain member `test` +//│ ║ l.42: Lit(0).test +//│ ╙── ^^^^^ +//│ error +//│ res +//│ Runtime error: +//│ ReferenceError: a is not defined + + +fun f(p: Pair['a, 'b]) = p.lhs +//│ fun f: forall 'a 'b. (p: Pair['a, 'b],) -> 'a + + +fun f(e) = if e is + Pair(l, r) then [l, r] +//│ fun f: forall 'lhs 'rhs. Pair['lhs, 'rhs] -> ('lhs, 'rhs,) +// f: (Exp['a] & Pair) -> 0 + + +:e // TODO support +fun f(e) = if e is + Pair['a, 'b](l, r) then [l, r] +//│ ╔══[ERROR] illegal pattern +//│ ║ l.64: Pair['a, 'b](l, r) then [l, r] +//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ fun f: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + +:e // TODO support +fun f(e) = if e is + Pair(l: a, r) then + fun f(x: a) = x + f(l) +//│ ╔══[ERROR] type identifier not found: a +//│ ║ l.76: fun f(x: a) = x +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: l +//│ ║ l.77: f(l) +//│ ╙── ^ +//│ fun f: Pair[anything, anything] -> error +//│ Code generation encountered an error: +//│ unresolved symbol l +// fun f: forall 'lhs 'rhs. Pair['lhs, 'rhs] -> ('lhs, 'rhs,) + + + diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 87bfefeb07..f758d40b27 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -64,10 +64,9 @@ module Bar { //│ } :e -:ge hello //│ ╔══[ERROR] identifier not found: hello -//│ ║ l.68: hello +//│ ║ l.67: hello //│ ╙── ^^^^^ //│ error //│ Code generation encountered an error: @@ -76,7 +75,7 @@ hello :e 1 : I //│ ╔══[ERROR] type identifier not found: I -//│ ║ l.77: 1 : I +//│ ║ l.76: 1 : I //│ ╙── ^ //│ error //│ res @@ -86,11 +85,11 @@ hello :e class Foo[A] { 42: A } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.87: class Foo[A] { 42: A } +//│ ║ l.86: class Foo[A] { 42: A } //│ ║ ^^ //│ ╟── integer literal of type `42` does not match type `A` //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.87: class Foo[A] { 42: A } +//│ ║ l.86: class Foo[A] { 42: A } //│ ╙── ^ //│ class Foo[A]() @@ -98,7 +97,7 @@ class Foo[A] { 42: A } :e class C1 { fun oops = this.x } //│ ╔══[ERROR] Class `C1` does not contain member `x` -//│ ║ l.99: class C1 { fun oops = this.x } +//│ ║ l.98: class C1 { fun oops = this.x } //│ ╙── ^^ //│ class C1() { //│ fun oops: error diff --git a/shared/src/test/diff/nu/BadScopes.mls b/shared/src/test/diff/nu/BadScopes.mls index a348199ca2..9cdea7ca24 100644 --- a/shared/src/test/diff/nu/BadScopes.mls +++ b/shared/src/test/diff/nu/BadScopes.mls @@ -2,11 +2,10 @@ :e -:ge mixin Foo(x: int) x //│ ╔══[ERROR] identifier not found: x -//│ ║ l.7: x +//│ ║ l.6: x //│ ╙── ^ //│ mixin Foo(x: int) //│ error @@ -15,11 +14,10 @@ x :e -:ge class Foo(x: int) x //│ ╔══[ERROR] identifier not found: x -//│ ║ l.20: x +//│ ║ l.18: x //│ ╙── ^ //│ class Foo(x: int) //│ error @@ -28,11 +26,10 @@ x :e -:ge class Foo(x: int) class Bar { x } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.33: class Bar { x } +//│ ║ l.30: class Bar { x } //│ ╙── ^ //│ class Foo(x: int) //│ class Bar() diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index 7570b54bba..26ecfc6c8a 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -19,10 +19,9 @@ fun foo(x) = if x is Bar then 0 //│ fun foo: Bar -> 0 :e -:ge fun foo(x) = if x is Foo0 then 0 //│ ╔══[ERROR] Cannot find constructor `Foo0` in scope -//│ ║ l.23: fun foo(x) = if x is Foo0 then 0 +//│ ║ l.22: fun foo(x) = if x is Foo0 then 0 //│ ╙── ^^^^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -33,20 +32,18 @@ type F = Foo //│ type F = Foo :e -:ge fun foo(x) = if x is F then 0 //│ ╔══[ERROR] Cannot find constructor `F` in scope -//│ ║ l.37: fun foo(x) = if x is F then 0 +//│ ║ l.35: fun foo(x) = if x is F then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared :e -:ge fun foo(x) = if x is F() then 0 //│ ╔══[ERROR] Illegal pattern `F` -//│ ║ l.47: fun foo(x) = if x is F() then 0 +//│ ║ l.44: fun foo(x) = if x is F() then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -57,20 +54,18 @@ mixin M //│ mixin M() :e -:ge fun foo(x) = if x is M then 0 //│ ╔══[ERROR] Cannot find constructor `M` in scope -//│ ║ l.61: fun foo(x) = if x is M then 0 +//│ ║ l.57: fun foo(x) = if x is M then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared :e -:ge fun foo(x) = if x is M() then 0 //│ ╔══[ERROR] Illegal pattern `M` -//│ ║ l.71: fun foo(x) = if x is M() then 0 +//│ ║ l.66: fun foo(x) = if x is M() then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -78,10 +73,9 @@ fun foo(x) = if x is M() then 0 :e -:ge fun foo0(x, y) = if x is y then 0 //│ ╔══[ERROR] Cannot find constructor `y` in scope -//│ ║ l.82: fun foo0(x, y) = if x is y then 0 +//│ ║ l.76: fun foo0(x, y) = if x is y then 0 //│ ╙── ^ //│ fun foo0: (anything, anything,) -> error //│ Code generation encountered an error: @@ -92,24 +86,22 @@ fun foo = 0 //│ fun foo: 0 :e -:ge fun foo0(x) = if x is foo() then 0 //│ ╔══[ERROR] Illegal pattern `foo` -//│ ║ l.96: fun foo0(x) = if x is foo() then 0 +//│ ║ l.89: fun foo0(x) = if x is foo() then 0 //│ ╙── ^^^ //│ fun foo0: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared :e -:ge fun foo(x) = if x is foo() then 0 //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.106: fun foo(x) = if x is foo() then 0 -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.98: fun foo(x) = if x is foo() then 0 +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Illegal pattern `foo` -//│ ║ l.106: fun foo(x) = if x is foo() then 0 -//│ ╙── ^^^ +//│ ║ l.98: fun foo(x) = if x is foo() then 0 +//│ ╙── ^^^ //│ fun foo: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 8cae325ac9..2ed49e0fe0 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -74,23 +74,22 @@ fun bar : A => A :pe :e :w -:ge fun bar: A => A //│ ╔══[PARSE ERROR] Unmatched opening angle bracket -//│ ║ l.78: fun bar: A => A +//│ ║ l.77: fun bar: A => A //│ ║ ^ //│ ╙── Note that `<` without spaces around it is considered as an angle bracket and not as an operator //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position -//│ ║ l.78: fun bar: A => A +//│ ║ l.77: fun bar: A => A //│ ╙── ^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.78: fun bar: A => A +//│ ║ l.77: fun bar: A => A //│ ╙── ^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.78: fun bar: A => A +//│ ║ l.77: fun bar: A => A //│ ╙── ^^^^^ //│ ╔══[ERROR] identifier not found: A -//│ ║ l.78: fun bar: A => A +//│ ║ l.77: fun bar: A => A //│ ╙── ^ //│ error -> error //│ Code generation encountered an error: @@ -104,10 +103,10 @@ module Test { fun test(x: A) = x } //│ ╔══[ERROR] Member foo is declared but not defined -//│ ║ l.102: fun foo: 'A => 'A +//│ ║ l.101: fun foo: 'A => 'A //│ ╙── ^^^ //│ ╔══[ERROR] Member bar is declared but not defined -//│ ║ l.103: fun bar: 'A +//│ ║ l.102: fun bar: 'A //│ ╙── ^^^ //│ module Test() { //│ fun bar: nothing diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls index 6f193ced97..a7b1c2a0c9 100644 --- a/shared/src/test/diff/nu/OverrideShorthand.mls +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -30,19 +30,18 @@ mixin Test { :pe :e -:ge fun f(override Pair(x, y), z) = x + y //│ ╔══[PARSE ERROR] Unsupported 'override' parameter list shape -//│ ║ l.34: fun f(override Pair(x, y), z) = x + y +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.34: fun f(override Pair(x, y), z) = x + y +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: x -//│ ║ l.34: fun f(override Pair(x, y), z) = x + y +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y //│ ╙── ^ //│ ╔══[ERROR] identifier not found: y -//│ ║ l.34: fun f(override Pair(x, y), z) = x + y +//│ ║ l.33: fun f(override Pair(x, y), z) = x + y //│ ╙── ^ //│ fun f: (error, anything,) -> int //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/TypeVariables.mls b/shared/src/test/diff/nu/TypeVariables.mls new file mode 100644 index 0000000000..642989389a --- /dev/null +++ b/shared/src/test/diff/nu/TypeVariables.mls @@ -0,0 +1,23 @@ +:NewDefs + + +fun x: 'a -> 'a = succ +//│ fun x: int -> int + +:e +fun x: forall 'a; 'a -> 'a = succ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ +//│ ║ ^^^^ +//│ ╟── type `'a` is not an instance of type `int` +//│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ +//│ ║ ^^ +//│ ╟── Note: quantified type variable 'a is defined at: +//│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ +//│ ╙── ^^ +//│ fun x: forall 'a. 'a -> 'a + +fun x: [int -> int,] = [id : forall 'a; 'a -> 'a,] +//│ fun x: (int -> int,) + + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 0828a21607..3f60095f59 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -922,7 +922,7 @@ class DiffTests case _: TestCode => () // Impossible case. case IllFormedCode(message) => totalCodeGenErrors += 1 - if (!mode.expectCodeGenErrors && !mode.fixme) + if (!mode.expectCodeGenErrors && !mode.fixme && !mode.expectTypeErrors) failures += blockLineNum output("Code generation encountered an error:") output(s" ${message}") From 73dcda1224352fe3a50a12022c91a9cf1583e9f6 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 4 Apr 2023 13:59:24 +0800 Subject: [PATCH 231/498] Add a couple small test cases --- shared/src/test/diff/parser/Ops.mls | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/shared/src/test/diff/parser/Ops.mls b/shared/src/test/diff/parser/Ops.mls index db31346ce9..a86338ee14 100644 --- a/shared/src/test/diff/parser/Ops.mls +++ b/shared/src/test/diff/parser/Ops.mls @@ -206,3 +206,22 @@ a + //│ Parsed: {+ (a,) ({+ (* b 2) (* 1 3)},)} +a + + b * + c +//│ |a| |+|→|b| |*|→|c|←|←| +//│ Parsed: {+ (a,) ({* (b,) ({c},)},)} + +a * + b + + c +//│ |a| |*|→|b| |+|→|c|←|←| +//│ Parsed: {* (a,) ({+ (b,) ({c},)},)} + +a * + let x = 1 + b + + c +//│ |a| |*|→|#let| |x| |#=| |1|↵|b| |+|→|c|←|←| +//│ Parsed: {* (a,) ({let x = 1; + (b,) ({c},)},)} + From 21ec2b543b15f910f8878aac3c85b43b7f1e0e74 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Fri, 7 Apr 2023 12:57:33 +0800 Subject: [PATCH 232/498] Generate Code for Nested Classes/Mixins/Modules (#8) --- js/src/main/scala/Main.scala | 4 +- .../src/main/scala/mlscript/JSBackend.scala | 625 ++++---- .../main/scala/mlscript/codegen/Codegen.scala | 31 +- .../main/scala/mlscript/codegen/Scope.scala | 94 +- .../main/scala/mlscript/codegen/Symbol.scala | 61 +- .../src/test/diff/codegen/ConstructorStmt.mls | 158 +- shared/src/test/diff/codegen/Mixin.mls | 280 ++-- shared/src/test/diff/codegen/Nested.mls | 1404 +++++++++++++++++ shared/src/test/diff/codegen/NuClasses.mls | 47 +- shared/src/test/diff/codegen/NuFuns.mls | 22 +- shared/src/test/diff/codegen/Super.mls | 47 +- shared/src/test/diff/gadt/Exp1.mls | 9 +- shared/src/test/diff/nu/BasicClasses.mls | 2 - shared/src/test/diff/nu/LetRec.mls | 12 +- shared/src/test/diff/nu/NestedClasses.mls | 6 +- shared/src/test/diff/nu/TypeSelections.mls | 10 +- 16 files changed, 2220 insertions(+), 592 deletions(-) create mode 100644 shared/src/test/diff/codegen/Nested.mls diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index 06676fe6cb..cf4f7017d8 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -133,8 +133,8 @@ object Main { implicit val extrCtx: Opt[typer.ExtrCtx] = N val vars: Map[Str, typer.SimpleType] = Map.empty - val tpd = typer.typeTypingUnit(tu, allowPure = true)(ctx.nest, raise, vars) - + val tpd = typer.typeTypingUnit(tu, topLevel = true)(ctx.nest, raise, vars) + object SimplifyPipeline extends typer.SimplifyPipeline { def debugOutput(msg: => Str): Unit = // if (mode.dbgSimplif) output(msg) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index f3285bc8d6..86a51002c7 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -7,6 +7,7 @@ import scala.collection.mutable.{ListBuffer, HashMap} import mlscript.{JSField, JSLit} import scala.collection.mutable.{Set => MutSet} import scala.util.control.NonFatal +import scala.util.chaining._ class JSBackend(allowUnresolvedSymbols: Boolean) { /** @@ -67,7 +68,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { translatePattern(base) case Inst(bod) => translatePattern(bod) case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf | _: Subs | _: Assign - | If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where => + | If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super => throw CodeGenError(s"term ${inspect(t)} is not a valid pattern") } @@ -79,6 +80,18 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case _ => throw CodeGenError(s"term $t is not a valid parameter list") } + private def translateNuTypeSymbol(sym: NuTypeSymbol with RuntimeSymbol)(implicit scope: Scope): JSExpr = + if (!sym.isNested) JSIdent(sym.runtimeName) else + scope.resolveValue("this") match { + case Some(selfSymbol) => + visitedSymbols += selfSymbol + JSIdent(selfSymbol.runtimeName).member(sym.runtimeName) + case _ => throw CodeGenError(s"unexpected NuType symbol ${sym.runtimeName}") + } + + protected def translateCapture(sym: CapturedSymbol): JSExpr = + JSIdent(sym.outsiderSym.runtimeName).member(sym.actualSym.lexicalName) + protected def translateVar(name: Str, isCallee: Bool)(implicit scope: Scope): JSExpr = scope.resolveValue(name) match { case S(sym: BuiltinSymbol) => @@ -97,12 +110,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { visitedSymbols += sym val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident - case S(sym: MixinSymbol) => - JSIdent(sym.runtimeName) - case S(sym: ModuleSymbol) => - JSIdent(sym.runtimeName) - case S(sym: NewClassSymbol) => - JSIdent(sym.runtimeName) + case S(sym: NuTypeSymbol with RuntimeSymbol) => + translateNuTypeSymbol(sym) case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") scope.resolveValue("this") match { @@ -112,6 +121,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case _ => throw CodeGenError(s"unexpected new class member $name") } + case S(sym: CapturedSymbol) => + translateCapture(sym) case S(sym: ClassSymbol) => if (isCallee) JSNew(JSIdent(sym.runtimeName)) @@ -201,7 +212,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { ) case Blk(stmts) => val blkScope = scope.derive("Blk") - val flattened = stmts.iterator.flatMap(_.desugared._2).toList + val flattened = stmts.iterator.flatMap { + case nt: NuTypeDef => nt :: Nil + case nf @ NuFunDef(_, Var(nme), _, _) => + blkScope.declareStubValue(nme)(true) + nf.desugared._2 + case other => other.desugared._2 + }.toList JSImmEvalFn( N, Nil, @@ -212,8 +229,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val pat = blkScope.declareValue(nme, isLetRec, isLetRec.isEmpty) JSLetDecl(Ls(pat.runtimeName -> S(translateTerm(rhs)(blkScope)))) } + case (nt: NuTypeDef, _) => translateLocalNewType(nt)(blkScope) // TODO: find out if we need to support this. - case (_: Def | _: TypeDef | _: NuFunDef /* | _: NuTypeDef */, _) => + case (_: Def | _: TypeDef | _: NuFunDef | _: DataDefn | _: DatatypeDefn | _: LetS, _) => throw CodeGenError("unsupported definitions in blocks") }.toList)), Nil @@ -223,7 +241,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSCommaExpr(translateTerm(trm) :: translateTerm(default) :: Nil) // Pattern match with two branches -> tenary operator case CaseOf(trm, Case(tst, csq, Wildcard(alt))) => - translateCase(translateTerm(trm), tst)(translateTerm(csq), translateTerm(alt)) + translateCase(translateTerm(trm), tst)(scope)(translateTerm(csq), translateTerm(alt)) // Pattern match with more branches -> chain of ternary expressions with cache case CaseOf(trm, cases) => val arg = translateTerm(trm) @@ -283,7 +301,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { scope: Scope ): JSExpr = branch match { case Case(pat, body, rest) => - translateCase(scrut, pat)(translateTerm(body), translateCaseBranch(scrut, rest)) + translateCase(scrut, pat)(scope)(translateTerm(body), translateCaseBranch(scrut, rest)) case Wildcard(body) => translateTerm(body) case NoCases => JSImmEvalFn(N, Nil, R(JSInvoke( JSNew(JSIdent("Error")), @@ -291,7 +309,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { ).`throw` :: Nil), Nil) } - private def translateCase(scrut: JSExpr, pat: SimpleTerm) = { + private def translateCase(scrut: JSExpr, pat: SimpleTerm)(implicit scope: Scope) = { JSTenary( pat match { case Var("int") => @@ -303,14 +321,24 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case Var("string") => // JS is dumb so `instanceof String` won't actually work on "primitive" strings... JSBinary("===", scrut.member("constructor"), JSLit("String")) - case Var(name) => topLevelScope.getType(name) match { - case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(runtimeName)) - case S(NewClassSymbol(lexicalName, _, _, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(lexicalName), JSIdent(JSLit.makeStringLiteral("class")))) - case S(ModuleSymbol(lexicalName, _, _, _, _, _)) => JSInstanceOf(scrut, JSMember(JSIdent(lexicalName), JSIdent(JSLit.makeStringLiteral("class")))) - case S(TraitSymbol(_, runtimeName, _, _, _)) => JSIdent(runtimeName)("is")(scrut) - case S(_: TypeAliasSymbol) => throw new CodeGenError(s"cannot match type alias $name") + case Var(name) => scope.resolveValue(name) match { + case S(sym: NewClassSymbol) => + JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) + case S(sym: ModuleSymbol) => + JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) + case S(CapturedSymbol(out, cls: NewClassSymbol)) => + JSInstanceOf(scrut, translateCapture(CapturedSymbol(out, cls)).member("class")) + case S(CapturedSymbol(out, mdl: ModuleSymbol)) => + JSInstanceOf(scrut, translateCapture(CapturedSymbol(out, mdl)).member("class")) case S(_: MixinSymbol) => throw new CodeGenError(s"cannot match mixin $name") - case N => throw new CodeGenError(s"unknown match case: $name") + case S(CapturedSymbol(out, mdl: MixinSymbol)) => + throw new CodeGenError(s"cannot match mixin $name") + case _ => topLevelScope.getType(name) match { + case S(ClassSymbol(_, runtimeName, _, _, _)) => JSInstanceOf(scrut, JSIdent(runtimeName)) + case S(TraitSymbol(_, runtimeName, _, _, _)) => JSIdent(runtimeName)("is")(scrut) + case S(_: TypeAliasSymbol) => throw new CodeGenError(s"cannot match type alias $name") + case _ => throw new CodeGenError(s"unknown match case: $name") + } } case lit: Lit => JSBinary("===", scrut, JSLit(lit.idStr)) @@ -451,211 +479,239 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSClassDecl(classSymbol.runtimeName, fields, base, members, traits) } + protected def translateSelfDeclaration(self: ValueSymbol): Ls[JSStmt] = + if (visitedSymbols(self)) { + visitedSymbols -= self + JSConstDecl(self.runtimeName, JSIdent("this")) :: Nil + } + else Nil + + protected def translateLocalNewType(typeDef: NuTypeDef)(implicit scope: Scope): JSConstDecl = { + // TODO: support traitSymbols + val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDef :: Nil, false) + if (!traitSymbols.isEmpty) throw CodeGenError("traits are not supported yet.") + + val sym = classSymbols match { + case s :: _ => S(s) + case Nil => mixinSymbols match { + case s :: _ => S(s) + case Nil => moduleSymbols match { + case s :: _ => S(s) + case _ => N + } + } + } + sym match { + case S(sym: NewClassSymbol) => + val localScope = scope.derive(s"local ${sym.lexicalName}") + val nd = translateNewTypeDefinition(sym, N, false)(localScope) + val ctorMth = localScope.declareValue("ctor", Some(false), false).runtimeName + val (constructor, params) = translateNewClassParameters(nd) + JSConstDecl(sym.lexicalName, JSImmEvalFn( + N, Nil, R(Ls( + nd, JSLetDecl.from(Ls(ctorMth)), + JSAssignExpr(JSIdent(ctorMth), JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(sym.lexicalName)), params)))).stmt, + JSExprStmt(JSAssignExpr(JSIdent(ctorMth).member("class"), JSIdent(sym.lexicalName))), + JSReturnStmt(S(JSIdent(ctorMth))) + )), Nil + )) + case S(sym: MixinSymbol) => + val localScope = scope.derive(s"local ${sym.lexicalName}") + val base = localScope.declareValue("base", Some(false), false) + val nd = translateNewTypeDefinition(sym, S(base), false)(localScope) + JSConstDecl(sym.lexicalName, JSArrowFn( + Ls(JSNamePattern(base.runtimeName)), R(Ls( + JSReturnStmt(S(JSClassExpr(nd))) + )) + )) + case S(sym: ModuleSymbol) => + val localScope = scope.derive(s"local ${sym.lexicalName}") + val nd = translateNewTypeDefinition(sym, N, false)(localScope) + val ins = localScope.declareValue("ins", Some(false), false).runtimeName + JSConstDecl(sym.lexicalName, JSImmEvalFn( + N, Nil, R(Ls( + nd, JSLetDecl.from(Ls(ins)), + JSAssignExpr(JSIdent(ins), JSInvoke(JSNew(JSIdent(sym.lexicalName)), Nil)).stmt, + JSExprStmt(JSAssignExpr(JSIdent(ins).member("class"), JSIdent(sym.lexicalName))), + JSReturnStmt(S(JSIdent(ins))) + )), Nil + )) + case _ => throw CodeGenError(s"unsupported NuTypeDef in local blocks: $typeDef") + } + } + protected def translateMixinDeclaration( - mixinSymbol: MixinSymbol + mixinSymbol: MixinSymbol, + siblingsMembers: Ls[RuntimeSymbol] )(implicit scope: Scope): JSClassMethod = { val getterScope = scope.derive(s"getter ${mixinSymbol.lexicalName}") - val mixinScope = getterScope.derive(s"mixin ${mixinSymbol.lexicalName}") - // Collect class fields. - val fields = mixinSymbol.body.collectFields ++ - mixinSymbol.body.collectTypeNames.flatMap(resolveTraitFields) - - mixinSymbol.methods.foreach { - case MethodDef(_, _, Var(nme), _, _) => mixinScope.declareNewClassMember(nme, N, true) - } - mixinSymbol.ctor.foreach { - case NuFunDef(rec, Var(nme), _, _) => mixinScope.declareNewClassMember(nme, rec, false) - case _ => () - } - val members = mixinSymbol.methods.map { - translateNewClassMember(_, fields)(mixinScope) - } - val constructorScope = mixinScope.derive(s"${mixinSymbol.lexicalName} constructor") - fields.foreach(constructorScope.declareValue(_, Some(false), false)) - val rest = constructorScope.declareValue("rest", Some(false), false) val base = getterScope.declareValue("base", Some(false), false) - val getters = new ListBuffer[Str]() - val stmts = mixinSymbol.ctor.flatMap { - case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil - case NuFunDef(_, Var(nme), _, Left(rhs)) => getters += nme; Ls[JSStmt]( - JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), - JSConstDecl(constructorScope.declareValue(nme, S(false), false).runtimeName, JSIdent(s"this.#$nme")) - ) - case _ => Nil + val outerSymbol = getterScope.declareOuterSymbol() + siblingsMembers.foreach(getterScope.captureSymbol(outerSymbol, _)) + + val classBody = translateNewTypeDefinition(mixinSymbol, S(base), false)(getterScope) + JSClassMethod(mixinSymbol.lexicalName, Ls(JSNamePattern(base.runtimeName)), + R((JSConstDecl(outerSymbol.runtimeName, JSIdent("this")) :: Nil) ::: Ls( + JSReturnStmt(S(JSClassExpr(classBody))) + )) + ) + } + + private def translateParents(superFields: Ls[Term], constructorScope: Scope)(implicit scope: Scope): Opt[JSExpr] = { + val bases = superFields.map { + case App(lhs, _) => translateTerm(App(lhs, Tup(Ls())))(constructorScope) + case t => translateTerm(t)(constructorScope) } - val traits = mixinSymbol.body.collectTypeNames.flatMap { - name => scope.getType(name) match { - case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) - case S(_: ClassSymbol) => N - case S(_: TypeSymbol) => N - case N => N + def translateParent(current: JSExpr, base: JSExpr, mixinOnly: Bool): JSExpr = { + val name = current match { + case JSIdent(nme) => nme + case JSInvoke(JSIdent(nme), _) => nme + case f: JSField => f.property.name + case JSInvoke(f: JSField, _) => f.property.name + case _ => throw CodeGenError("unsupported parents.") } - } - - val classBody = JSClassNewDecl(mixinSymbol.lexicalName, fields, fields ::: getters.toList, S(JSIdent(base.runtimeName)), - Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName), members, traits, stmts) - JSClassMethod(mixinSymbol.lexicalName, Ls(JSNamePattern(base.runtimeName)), R(Ls( - JSReturnStmt(S(JSClassExpr(classBody))) - ))) - } - private def translateParents(superFields: Ls[Term], constructorScope: Scope)(implicit scope: Scope): Opt[JSExpr] = { - val bases = superFields.map { sym => sym match { - case App(lhs, _) => S(translateTerm(App(lhs, Tup(Ls())))(constructorScope)) - case _ => S(translateTerm(sym)(constructorScope)) - } } + scope.resolveValue(name) match { + case Some(CapturedSymbol(out, sym: MixinSymbol)) => + JSInvoke(translateCapture(CapturedSymbol(out, sym)), Ls(base)) + case Some(CapturedSymbol(out, sym: NuTypeSymbol)) if !mixinOnly => + translateCapture(CapturedSymbol(out, sym)).member("class") + case Some(sym: MixinSymbol) => + JSInvoke(translateVar(name, false), Ls(base)) + case Some(_: NuTypeSymbol) if !mixinOnly => + translateVar(name, false).member("class") + case _ => throw CodeGenError(s"unresolved parent $name.") + } + } + // for non-first parent classes, they must be mixins or we would get more than one parent classes, + // which is not allowed in JS bases match { - case head :: tail => tail.foldLeft( - head match { - case Some(JSIdent(nme)) => scope.resolveValue(nme) match { - case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls(JSIdent("Object")))) - case Some(_) => Some(JSMember(JSIdent(nme), JSLit(JSLit.makeStringLiteral("class")))) - case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") - } - case Some(JSInvoke(JSIdent(nme), _)) => scope.resolveValue(nme) match { - case Some(sym: MixinSymbol) => Some(JSInvoke(JSIdent(nme), Ls(JSIdent("Object")))) - case Some(_) => Some(JSMember(JSIdent(nme), JSLit(JSLit.makeStringLiteral("class")))) - case _ => throw CodeGenError(s"unresolved symbol in parents: $nme") - } - case _ => throw CodeGenError("unresolved parents.") - } - )((res, next) => (res, next) match { - case (S(res), S(JSIdent(next))) => scope.resolveValue(next) match { - case Some(sym: MixinSymbol) => S(JSInvoke(JSIdent(next), Ls(res))) - case Some(_) => throw CodeGenError("can not have more than one parents.") - case _ => throw CodeGenError(s"unresolved symbol in parents: $res") - } - case (S(res), S(JSInvoke(JSIdent(next), _))) => scope.resolveValue(next) match { - case Some(sym: MixinSymbol) => S(JSInvoke(JSIdent(next), Ls(res))) - case Some(_) => throw CodeGenError("can not have more than one parents.") - case _ => throw CodeGenError(s"unresolved symbol in parents: $res") - } - case _ => throw CodeGenError("unresolved parents.") - }) + case head :: tail => S(tail.foldLeft( + translateParent(head, JSIdent("Object"), false) + )((res, next) => translateParent(next, res, true))) case Nil => N } } + protected def translateTopModuleDeclaration( + moduleSymbol: ModuleSymbol, + keepTopLevelScope: Bool + )(implicit scope: Scope): JSClassNewDecl = + translateNewTypeDefinition(moduleSymbol, N, keepTopLevelScope) + protected def translateModuleDeclaration( - moduleSymbol: ModuleSymbol + moduleSymbol: ModuleSymbol, + siblingsMembers: Ls[RuntimeSymbol] )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"getter ${moduleSymbol.lexicalName}") - val moduleScope = scope.derive(s"module ${moduleSymbol.lexicalName}") - val constructorScope = moduleScope.derive(s"${moduleSymbol.lexicalName} constructor") - // Collect class fields. - val fields = moduleSymbol.body.collectFields ++ - moduleSymbol.body.collectTypeNames.flatMap(resolveTraitFields) - moduleSymbol.methods.foreach { - case MethodDef(_, _, Var(nme), _, _) => moduleScope.declareNewClassMember(nme, N, true) - } - moduleSymbol.ctor.foreach { - case NuFunDef(rec, Var(nme), _, _) => moduleScope.declareNewClassMember(nme, rec, false) - case _ => () - } - val members = moduleSymbol.methods.map { - translateNewClassMember(_, fields)(moduleScope) - } - val getters = new ListBuffer[Str]() - val stmts = moduleSymbol.ctor.flatMap { - case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil - case NuFunDef(_, Var(nme), _, Left(rhs)) => getters += nme; Ls[JSStmt]( - JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), - JSConstDecl(constructorScope.declareValue(nme, S(false), false).runtimeName, JSIdent(s"this.#$nme")) - ) - case _ => Nil + val outerSymbol = getterScope.declareOuterSymbol() + siblingsMembers.foreach(getterScope.captureSymbol(outerSymbol, _)) + + val decl = translateNewTypeDefinition(moduleSymbol, N, false)(getterScope) + val privateIdent = JSIdent(s"this.#${moduleSymbol.lexicalName}") + JSClassGetter(moduleSymbol.lexicalName, R((JSConstDecl(outerSymbol.runtimeName, JSIdent("this")) :: Nil) ::: + Ls( + JSIfStmt(JSBinary("===", privateIdent, JSIdent("undefined")), Ls( + decl, + JSExprStmt(JSAssignExpr(privateIdent, + JSNew(JSInvoke(JSIdent(moduleSymbol.lexicalName), Nil)))), + JSExprStmt(JSAssignExpr(privateIdent.member("class"), JSIdent(moduleSymbol.lexicalName))), + )), + JSReturnStmt(S(privateIdent)) + ))) + } + + protected def translateNewClassParameters(classBody: JSClassNewDecl) = { + val constructor = classBody match { + case dec: JSClassNewDecl => dec.fields.map(JSNamePattern(_)) } - val traits = moduleSymbol.body.collectTypeNames.flatMap { - name => scope.getType(name) match { - case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) - case S(_: ClassSymbol) => N - case S(_: TypeSymbol) => N - case N => N - } + val params = classBody match { + case dec: JSClassNewDecl => dec.fields.map(JSIdent(_)) } - val rest = constructorScope.declareValue("rest", Some(false), false) - val base: Opt[JSExpr] = - translateParents(moduleSymbol.superParameters, constructorScope) - val superParameters = (moduleSymbol.superParameters map { - case App(lhs, Tup(rhs)) => rhs map { - case (_, Fld(mut, spec, trm)) => translateTerm(trm)(getterScope) - } - case _ => Nil - }).flatMap(_.reverse) - val decl = JSClassNewDecl(moduleSymbol.lexicalName, - fields, - fields ::: getters.toList, - base, - superParameters.reverse, - N, - members, - traits, - stmts) - - JSClassGetter(moduleSymbol.lexicalName, R(Ls( - JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), JSIdent("undefined")), Ls( - decl, - JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), - JSNew(JSInvoke(JSIdent(moduleSymbol.lexicalName), Nil)))), - JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(moduleSymbol.lexicalName))), - )), - JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), moduleSymbol.lexicalName))) - ))) + + (constructor, params) } protected def translateNewClassDeclaration( - classSymbol: NewClassSymbol + classSymbol: NewClassSymbol, + siblingsMembers: Ls[RuntimeSymbol] )(implicit scope: Scope): JSClassGetter = { val getterScope = scope.derive(s"${classSymbol.lexicalName} getter") - val cacheSymbol = getterScope.declareValue("cache", Some(false), false) - val classBody = translateNewClassExpression(classSymbol, N, cacheSymbol.runtimeName)(getterScope) - val constructor = classBody match { - case JSClassNewDecl(_, fields, _, _, _, _, _, _, _) => fields.map(JSNamePattern(_)) - } - val params = classBody match { - case JSClassNewDecl(_, fields, _, _, _, _, _, _, _) => fields.map(JSIdent(_)) - } + val outerSymbol = getterScope.declareOuterSymbol() + siblingsMembers.foreach(getterScope.captureSymbol(outerSymbol, _)) + + val classBody = + translateNewTypeDefinition(classSymbol, N, false)(getterScope) + val (constructor, params) = translateNewClassParameters(classBody) - JSClassGetter(classSymbol.lexicalName, R(Ls( - JSConstDecl(cacheSymbol.runtimeName, JSField(JSIdent("this"), "cache")), - JSIfStmt(JSBinary("===", JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSIdent("undefined")), Ls( + val privateIdent = JSIdent(s"this.#${classSymbol.lexicalName}") + val outerStmt = JSConstDecl(outerSymbol.runtimeName, JSIdent("this")) + JSClassGetter(classSymbol.lexicalName, R(outerStmt :: Ls( + JSIfStmt(JSBinary("===", privateIdent, JSIdent("undefined")), Ls( JSExprStmt(JSClassExpr(classBody)), - JSExprStmt(JSAssignExpr(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), + JSExprStmt(JSAssignExpr(privateIdent, JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), - JSExprStmt(JSAssignExpr(JSMember(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName), JSLit(JSLit.makeStringLiteral("class"))), JSIdent(classSymbol.lexicalName))) + JSExprStmt(JSAssignExpr(privateIdent.member("class"), JSIdent(classSymbol.lexicalName))) )), - JSReturnStmt(S(JSField(JSField(JSIdent("this"), "cache"), classSymbol.lexicalName))) + JSReturnStmt(S(privateIdent)) ))) } - protected def translateNewClassExpression( - classSymbol: NewClassSymbol, - rest: Opt[Str] = N, - cacheName: Str + protected def translateNewTypeDefinition( + sym: TypeSymbol with RuntimeSymbol with NuTypeSymbol, + baseSym: Opt[ValueSymbol], + keepTopLevelScope: Bool )(implicit scope: Scope): JSClassNewDecl = { - // Translate class methods and getters. - val classScope = scope.derive(s"class ${classSymbol.lexicalName}") - // Collect class fields. - val fields = classSymbol.body.collectFields ++ - classSymbol.body.collectTypeNames.flatMap(resolveTraitFields) - classSymbol.methods.foreach { - case MethodDef(_, _, Var(nme), _, _) => classScope.declareNewClassMember(nme, N, true) + val nuTypeScope = scope.derive(sym.toString) + val constructorScope = nuTypeScope.derive(s"${sym.lexicalName} constructor") + val selfSymbol = constructorScope.declareThisAlias() + + val memberList = ListBuffer[RuntimeSymbol]() // pass to the getter of nested types + val typeList = ListBuffer[Str]() + + val fields = sym.body.collectFields ++ + sym.body.collectTypeNames.flatMap(resolveTraitFields) + + val ctorParams = fields.map { f => + memberList += NewClassMemberSymbol(f, Some(false), false).tap(nuTypeScope.register) + constructorScope.declareValue(f, Some(false), false).runtimeName } - classSymbol.ctor.foreach { - case NuFunDef(rec, Var(nme), _, _) => classScope.declareNewClassMember(nme, rec, false) + + sym.methods.foreach { + case MethodDef(_, _, Var(nme), _, _) => memberList += NewClassMemberSymbol(nme, N, true).tap(nuTypeScope.register) + } + sym.ctor.foreach { + case NuFunDef(rec, Var(nme), _, _) => memberList += NewClassMemberSymbol(nme, rec, false).tap(nuTypeScope.register) case _ => () } - val members = classSymbol.methods.map { - translateNewClassMember(_, fields, S(JSConstDecl(classSymbol.lexicalName, JSField(JSIdent(cacheName), classSymbol.lexicalName))))(classScope) + + // TODO: support traitSymbols + val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(sym.nested, true)(nuTypeScope) + if (!traitSymbols.isEmpty) throw CodeGenError("traits are not supported yet.") + + if (keepTopLevelScope) // also declare in the top level for diff tests + declareNewTypeDefs(sym.nested, false)(topLevelScope) + classSymbols.foreach(s => {memberList += s; typeList += s.lexicalName}) + mixinSymbols.foreach(s => {memberList += s;}) + moduleSymbols.foreach(s => {memberList += s; typeList += s.lexicalName}) + val members = sym.methods.map { + translateNewClassMember(_, fields)(nuTypeScope) + } ++ + mixinSymbols.map + { translateMixinDeclaration(_, memberList.toList)(nuTypeScope) } ++ + moduleSymbols.map + { translateModuleDeclaration(_, memberList.toList)(nuTypeScope) } ++ + classSymbols.map + { translateNewClassDeclaration(_, memberList.toList)(nuTypeScope) } + + val base: Opt[JSExpr] = baseSym match { + case Some(base) => S(JSIdent(base.runtimeName)) + case _ => translateParents(sym.superParameters, constructorScope) } - val constructorScope = classScope.derive(s"${classSymbol.lexicalName} constructor") - fields.foreach(constructorScope.declareValue(_, Some(false), false)) - val restRuntime = rest.flatMap(name => S(constructorScope.declareValue(name, Some(false), false).runtimeName)) - val base: Opt[JSExpr] = - translateParents(classSymbol.superParameters, constructorScope) - val traits = classSymbol.body.collectTypeNames.flatMap { + val traits = sym.body.collectTypeNames.flatMap { name => scope.getType(name) match { case S(TraitSymbol(_, runtimeName, _, _, _)) => S(runtimeName) case S(_: ClassSymbol) => N @@ -664,14 +720,20 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } } - val superParameters = (classSymbol.superParameters map { - case App(lhs, Tup(rhs)) => rhs map { - case (_, Fld(mut, spec, trm)) => translateTerm(trm)(constructorScope) - } - case _ => Nil - }).flatMap(_.reverse) + val (superParameters, rest) = if (baseSym.isDefined) { + val rest = constructorScope.declareValue("rest", Some(false), false) + (Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName)) + } + else + (sym.superParameters.map { + case App(lhs, Tup(rhs)) => rhs map { + case (_, Fld(mut, spec, trm)) => translateTerm(trm)(constructorScope) + } + case _ => Nil + }.flatMap(_.reverse).reverse, N) + val getters = new ListBuffer[Str]() - val stmts = classSymbol.ctor.flatMap { + val stmts = sym.ctor.flatMap { case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil case NuFunDef(_, Var(nme), _, Left(rhs)) => getters += nme; Ls[JSStmt]( JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), @@ -680,10 +742,24 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case _ => Nil } - JSClassNewDecl(classSymbol.lexicalName, fields, fields ::: getters.toList, base, restRuntime match { - case Some(restRuntime) => superParameters.reverse :+ JSIdent(s"...$restRuntime") - case _ => superParameters.reverse - }, restRuntime, members, traits, stmts) + val tempDecs = constructorScope.tempVars.emit() match { + case S(decs) => decs :: Nil + case _ => Nil + } + + JSClassNewDecl( + sym.lexicalName, + fields, + fields ::: getters.toList, + base, + superParameters, + ctorParams, + rest, + members, + traits, + translateSelfDeclaration(selfSymbol) ::: tempDecs ::: stmts, + typeList.toList + ) } /** @@ -726,9 +802,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } private def translateNewClassMember( - method: MethodDef[Left[Term, Type]], - props: Ls[Str] = Nil, - selfClass: Opt[JSConstDecl] = N + method: MethodDef[Left[Term, Type]], + props: Ls[Str] // for overriding )(implicit scope: Scope): JSClassMemberDecl = { val name = method.nme.name // Create the method/getter scope. @@ -752,20 +827,17 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } // Translate class member body. val bodyResult = translateTerm(body)(memberScope).`return` + val tempDecs = memberScope.tempVars.emit() match { + case S(decs) => decs :: Nil + case _ => Nil + } + // If `this` is accessed, add `const self = this`. val bodyStmts = if (visitedSymbols(selfSymbol)) { val thisDecl = JSConstDecl(selfSymbol.runtimeName, JSIdent("this")) visitedSymbols -= selfSymbol - selfClass match { - case Some(selfClass) => R((selfClass :: preDecs) ::: (thisDecl :: bodyResult :: Nil)) - case _ => R(preDecs ::: (thisDecl :: bodyResult :: Nil)) - } - } else { - selfClass match { - case Some(selfClass) => R((selfClass :: preDecs) ::: (bodyResult :: Nil)) - case _ => R(preDecs ::: (bodyResult :: Nil)) - } - } + R(preDecs ::: tempDecs ::: (thisDecl :: bodyResult :: Nil)) + } else R(preDecs ::: tempDecs ::: (bodyResult :: Nil)) // Returns members depending on what it is. memberParams match { case S(memberParams) => JSClassMethod(name, memberParams, bodyStmts) @@ -789,12 +861,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { traits += topLevelScope.declareTrait(name, tparams map { _.name }, body, methods) case TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _) => classes += topLevelScope.declareClass(name, tparams map { _.name }, baseType, members) + case TypeDef(Mxn, _, _, _, _, _, _) => throw CodeGenError("Mixins are not supported yet.") case TypeDef(Nms, _, _, _, _, _, _) => throw CodeGenError("Namespaces are not supported yet.") } (traits.toList, classes.toList) } - protected def declareNewTypeDefs(typeDefs: Ls[NuTypeDef]): + protected def declareNewTypeDefs(typeDefs: Ls[NuTypeDef], isNested: Bool)(implicit scope: Scope): (Ls[TraitSymbol], Ls[NewClassSymbol], Ls[MixinSymbol], Ls[ModuleSymbol]) = { val traits = new ListBuffer[TraitSymbol]() val classes = new ListBuffer[NewClassSymbol]() @@ -814,44 +887,49 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case _ => die } val body = pars.map(tt).foldRight(Record(params): Type)(Inter) - val members = unit.entities.foldLeft(List[MethodDef[Left[Term, Type]]]())((lst, loc) => loc match { + val members = unit.entities.collect { case NuFunDef(isLetRec, mnme, tys, Left(rhs)) if (isLetRec.isEmpty || isLetRec.getOrElse(false)) => - lst :+ MethodDef(isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) - case _ => lst - }) - val stmts = unit.entities.foldLeft(List[Statement]())((lst, loc) => loc match { - case Asc(Var("this"), _) => lst - case Asc(Super(), _) => lst - case lt @ NuFunDef(S(false), _, _, Left(rhs)) => lst :+ lt - case t: Term => lst :+ t - case _ => lst - }) + MethodDef[Left[Term, Type]](isLetRec.getOrElse(false), TypeName(nme), mnme, tys, Left(rhs)) + } + + val stmts = unit.entities.filter { + case Asc(Var("this"), _) => false + case Asc(Super(), _) => false + case NuFunDef(S(false), _, _, Left(rhs)) => true + case _: Term => true + case _ => false + } + + val nested = unit.entities.collect { + case nd: NuTypeDef => nd + } - (body, members, stmts) + (body, members, stmts, nested) } typeDefs.foreach { case td @ NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members, stmts) = prepare(mxName, fs, pars, unit) - val sym = topLevelScope.declareMixin(mxName, tps map { _._2.name }, body, members, stmts) + val (body, members, stmts, nested) = prepare(mxName, fs, pars, unit) + val sym = MixinSymbol(mxName, tps map { _._2.name }, body, members, stmts, nested, isNested).tap(scope.register) if (!td.isDecl) mixins += sym } case td @ NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members, stmts) = prepare(nme, fs, pars, unit) - val sym = topLevelScope.declareModule(nme, tps map { _._2.name }, body, members, stmts, pars) + val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) + val sym = ModuleSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) if (!td.isDecl) modules += sym } case td @ NuTypeDef(Als, TypeName(nme), tps, _, sig, pars, _, _, _) => { - topLevelScope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) + scope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) } case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members, stmts) = prepare(nme, fs, pars, unit) - val sym = topLevelScope.declareNewClass(nme, tps map { _._2.name }, body, members, stmts, pars) + val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) + val sym = + NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) if (!td.isDecl) classes += sym } case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { - val (body, members, _) = prepare(nme, fs, pars, unit) - val sym = topLevelScope.declareTrait(nme, tps map { _._2.name }, body, members) + val (body, members, _, _) = prepare(nme, fs, pars, unit) + val sym = scope.declareTrait(nme, tps map { _._2.name }, body, members) if (!td.isDecl) traits += sym } } @@ -885,6 +963,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case S(sym: TraitSymbol) => N // TODO: inherit from traits case S(sym: TypeAliasSymbol) => throw new CodeGenError(s"cannot inherit from type alias $name" ) + case S(_: NuTypeSymbol) => + throw new CodeGenError(s"NuType symbol $name is not supported when resolving base classes") case N => throw new CodeGenError(s"undeclared type name $name when resolving base classes") } @@ -976,7 +1056,6 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { } private def generateNewDef(pgrm: Pgrm): (Ls[Str], Ls[Str]) = { - val mlsModule = topLevelScope.declareValue("typing_unit", Some(false), false) val (typeDefs, otherStmts) = pgrm.tops.partitionMap { case ot: Terms => R(ot) case fd: NuFunDef => R(fd) @@ -984,55 +1063,56 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { case _ => die } - val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDefs) + // don't pass `otherStmts` to the top-level module, because we need to execute them one by one later + val topModule = topLevelScope.declareTopModule("TypingUnit", Nil, typeDefs, true) + val moduleIns = topLevelScope.declareValue("typing_unit", Some(false), false) + val moduleDecl = translateTopModuleDeclaration(topModule, true)(topLevelScope) + val insDecl = + JSConstDecl(moduleIns.runtimeName, JSNew(JSIdent(topModule.runtimeName))) + def include(typeName: Str, moduleName: Str) = JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) val includes = - traitSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - mixinSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - moduleSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - classSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) - - val defs = - traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ - mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ - moduleSymbols.map { translateModuleDeclaration(_)(topLevelScope) } ++ - classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) } - - val defStmts = - JSLetDecl(Ls(mlsModule.runtimeName -> S(JSRecord(Ls("cache" -> JSRecord(Ls())), defs)))) :: includes + typeDefs.filter(!_.isDecl).map { + case nu: NuTypeDef => + include(nu.nme.name, moduleIns.runtimeName) + } val resultsIdent = JSIdent(resultsName) val resultNames = ListBuffer[Str]() val stmts: Ls[JSStmt] = JSConstDecl(resultsName, JSArray(Nil)) :: - defStmts + (moduleDecl :: insDecl :: includes) // Generate something like: // ```js // const = ; // .push(); // ``` .concat(otherStmts.flatMap { - case Def(recursive, Var(name), L(body), isByname) => - val (originalExpr, sym) = if (recursive) { + case NuFunDef(isLetRec, nme @ Var(name), tys, rhs @ L(body)) => + val recursive = isLetRec.getOrElse(true) + val isByname = isLetRec.isEmpty + val bodyIsLam = body match { case _: Lam => true case _ => false } + val (originalExpr, sym) = (if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) - val sym = topLevelScope.declareValue(name, isByvalueRecIn, body.isInstanceOf[Lam]) + val sym = topLevelScope.declareValue(name, isByvalueRecIn, bodyIsLam) val translated = translateTerm(body)(topLevelScope) topLevelScope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - (translated, topLevelScope.declareValue(name, isByvalueRecOut, body.isInstanceOf[Lam])) + (translated, topLevelScope.declareValue(name, isByvalueRecOut, bodyIsLam)) } else { - val translatedBody = translateTerm(body)(topLevelScope) + val translated = translateTerm(body)(topLevelScope) val isByvalueRec = if (isByname) None else Some(false) - (translatedBody, topLevelScope.declareValue(name, isByvalueRec, body.isInstanceOf[Lam])) - } + (translated, topLevelScope.declareValue(name, isByvalueRec, bodyIsLam)) + }) val translatedBody = if (sym.isByvalueRec.isEmpty && !sym.isLam) JSArrowFn(Nil, L(originalExpr)) else originalExpr resultNames += sym.runtimeName topLevelScope.tempVars `with` JSConstDecl(sym.runtimeName, translatedBody) :: JSInvoke(resultsIdent("push"), JSIdent(sym.runtimeName) :: Nil).stmt :: Nil - // Ignore type declarations. - case Def(_, _, R(_), isByname) => Nil - // `exprs.push()`. + case fd @ NuFunDef(isLetRec, Var(name), tys, R(ty)) => + Nil + case _: Def | _: TypeDef => + throw CodeGenError("Def and TypeDef are not supported in NewDef files.") case term: Term => val name = translateTerm(term)(topLevelScope) resultNames += name.toSourceCode.toString @@ -1173,28 +1253,27 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { } private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { - val mlsModule = topLevelScope.declareValue("typing_unit", Some(false), false) val (typeDefs, otherStmts) = pgrm.tops.partitionMap { case ot: Terms => R(ot) case fd: NuFunDef => R(fd) case nd: NuTypeDef => L(nd) case _ => die - } + } - val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDefs) - val defStmts = - traitSymbols.map { translateTraitDeclaration(_)(topLevelScope) } ++ - mixinSymbols.map { translateMixinDeclaration(_)(topLevelScope) } ++ - moduleSymbols.map { translateModuleDeclaration(_)(topLevelScope) } ++ - classSymbols.map { translateNewClassDeclaration(_)(topLevelScope) } + // don't pass `otherStmts` to the top-level module, because we need to execute them one by one later + val topModule = topLevelScope.declareTopModule("TypingUnit", Nil, typeDefs, true) + val moduleIns = topLevelScope.declareValue("typing_unit", Some(false), false) + val moduleDecl = translateTopModuleDeclaration(topModule, true) + val insDecl = + JSConstDecl(moduleIns.runtimeName, JSNew(JSIdent(topModule.runtimeName))) def include(typeName: Str, moduleName: Str) = JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) val includes = - traitSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - mixinSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - moduleSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) ++ - classSymbols.map((sym) => include(sym.runtimeName, mlsModule.runtimeName)) + typeDefs.filter(!_.isDecl).map { + case nu: NuTypeDef => + include(nu.nme.name, moduleIns.runtimeName) + } val zeroWidthSpace = JSLit("\"\\u200B\"") val catchClause = JSCatchClause( @@ -1266,10 +1345,12 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case e: UnimplementedError => JSTestBackend.AbortedQuery(e.getMessage()) case e: Throwable => throw e } + case _: Def | _: TypeDef => + throw CodeGenError("Def and TypeDef are not supported in NewDef files.") } // If this is the first time, insert the declaration of `res`. - var prelude: Ls[JSStmt] = JSLetDecl(Ls(mlsModule.runtimeName -> S(JSRecord(Ls("cache" -> JSRecord(Ls())), defStmts)))) :: includes + var prelude: Ls[JSStmt] = Ls(moduleDecl, insDecl) ::: includes if (numRun === 0) prelude = JSLetDecl(lastResultSymbol.runtimeName -> N :: Nil) :: prelude diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 09ab204cf9..def01ddca8 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -598,12 +598,12 @@ object JSMember { def apply(`object`: JSExpr, property: JSExpr): JSMember = new JSMember(`object`, property) } -class JSField(`object`: JSExpr, property: JSIdent) extends JSMember(`object`, property) { +class JSField(`object`: JSExpr, val property: JSIdent) extends JSMember(`object`, property) { override def toSourceCode: SourceCode = `object`.toSourceCode.parenthesized( `object`.precedence < precedence || `object`.isInstanceOf[JSRecord] ) ++ SourceCode( - if (JSField.isValidIdentifier(property.name)) { + if (JSField.isValidFieldName(property.name)) { s".${property.name}" } else { s"[${JSLit.makeStringLiteral(property.name)}]" @@ -618,6 +618,10 @@ object JSField { def isValidIdentifier(s: Str): Bool = identifierPattern.matches(s) && !Symbol.isKeyword(s) + // in this case, a keyword can be used as a field name + // e.g. `something.class` is valid + def isValidFieldName(s: Str): Bool = identifierPattern.matches(s) + def emitValidFieldName(s: Str): Str = if (isValidIdentifier(s)) s else JSLit.makeStringLiteral(s) } @@ -830,23 +834,26 @@ final case class JSClassNewDecl( name: Str, fields: Ls[Str], privateMem: Ls[Str], - `extends`: Opt[JSExpr] = N, - superFields: Ls[JSExpr] = Nil, - rest: Opt[Str] = N, - methods: Ls[JSClassMemberDecl] = Nil, - implements: Ls[Str] = Nil, - initStmts: Ls[JSStmt] = Nil + `extends`: Opt[JSExpr], + superFields: Ls[JSExpr], + ctorParams: Ls[Str], + rest: Opt[Str], + methods: Ls[JSClassMemberDecl], + implements: Ls[Str], + initStmts: Ls[JSStmt], + nestedTypes: Ls[Str] ) extends JSStmt { def toSourceCode: SourceCode = { val constructor: SourceCode = { val buffer = new ListBuffer[Str]() val params = - fields.iterator.zipWithIndex.foldRight(rest match { + ctorParams.iterator.zipWithIndex.foldRight(rest match { case Some(rest) => s"...$rest" case _ => "" })((p, s) => if (s.isEmpty) s"${p._1}" else s"${p._1}, $s") + nestedTypes.foreach(t => buffer += s" #$t;") if (!privateMem.isEmpty) { privateMem.foreach(f => buffer += s" #${f};") privateMem.foreach(f => buffer += s" get ${f}() { return this.#${f}; }") @@ -862,8 +869,10 @@ final case class JSClassNewDecl( implements.foreach { name => buffer += s" $name.implement(this);" } - fields.iterator.zipWithIndex.foreach { pair => - buffer += s" this.#${pair._1} = ${pair._1};" // TODO: invalid name? + + assert(fields.length === ctorParams.length, s"fields and ctorParams have different size in class $name.") + fields.lazyZip(ctorParams).foreach { (field, param) => + buffer += s" this.#$field = $param;" // TODO: invalid name? } initStmts.foreach { s => s.toSourceCode.indented.indented.toString.split("\n").foreach { diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index a23704d1bc..3f2f222e0e 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -4,17 +4,24 @@ import mlscript.utils.shorthands._ import mlscript.{JSStmt, JSExpr, JSLetDecl} import mlscript.Type import scala.reflect.ClassTag -import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls, Nms} -import mlscript.MethodDef -import mlscript.{Term, Statement} +import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls, Nms, Mxn} +import mlscript.{MethodDef, Var} +import mlscript.{Term, Statement, Record} import mlscript.utils.{AnyOps, lastWords} import mlscript.JSField +import mlscript.{NuTypeDef, NuFunDef} class Scope(name: Str, enclosing: Opt[Scope]) { private val lexicalTypeSymbols = scala.collection.mutable.HashMap[Str, TypeSymbol]() private val lexicalValueSymbols = scala.collection.mutable.HashMap[Str, RuntimeSymbol]() private val runtimeSymbols = scala.collection.mutable.HashSet[Str]() + // To allow a class method/getter/constructor to access members of an outer class, + // we insert `const outer = this;` before the class definition starts. + // To access ALL outer variables correctly, we need to make sure + // none of them would be shadowed. + private val outerSymbols = scala.collection.mutable.HashSet[Str]() + val tempVars: TemporaryVariableEmitter = TemporaryVariableEmitter() /** @@ -109,7 +116,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { /** * Register a lexical symbol in both runtime name set and lexical name set. */ - private def register(symbol: TypeSymbol with RuntimeSymbol): Unit = { + def register(symbol: TypeSymbol with RuntimeSymbol): Unit = { lexicalTypeSymbols.put(symbol.lexicalName, symbol) lexicalValueSymbols.put(symbol.lexicalName, symbol) runtimeSymbols += symbol.runtimeName @@ -119,7 +126,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { /** * Register a lexical symbol in both runtime name set and lexical name set. */ - private def register(symbol: RuntimeSymbol): Unit = { + def register(symbol: RuntimeSymbol): Unit = { lexicalValueSymbols.put(symbol.lexicalName, symbol) runtimeSymbols += symbol.runtimeName () @@ -173,6 +180,8 @@ class Scope(name: Str, enclosing: Opt[Scope]) { case S(sym: TraitSymbol) => N case S(sym: TypeAliasSymbol) => throw new CodeGenError(s"cannot inherit from type alias $name" ) + case S(_: NuTypeSymbol) => + throw new CodeGenError(s"NuType symbol $name is not supported when resolving base classes") case N => throw new CodeGenError(s"undeclared type name $name when resolving base classes") } @@ -193,6 +202,8 @@ class Scope(name: Str, enclosing: Opt[Scope]) { case S(sym: TraitSymbol) => S(sym) case S(sym: TypeAliasSymbol) => throw new CodeGenError(s"cannot inherit from type alias $name" ) + case S(sym: NuTypeSymbol) => + throw new CodeGenError(s"NuType symbol $name is not supported when resolving implemented traits") case N => throw new CodeGenError(s"undeclared type name $name when resolving implemented traits") } @@ -206,6 +217,8 @@ class Scope(name: Str, enclosing: Opt[Scope]) { declareTrait(name, tparams map { _.name }, body, mthdDefs) case TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _) => declareClass(name, tparams map { _.name }, baseType, members) + case TypeDef(Mxn, _, _, _, _, _, _) => + throw CodeGenError("Mixins are not supported yet.") case TypeDef(Nms, _, _, _, _, _, _) => throw CodeGenError("Namespaces are not supported yet.") } @@ -222,42 +235,43 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } - def declareNewClass( - lexicalName: Str, - params: Ls[Str], - base: Type, - methods: Ls[MethodDef[Left[Term, Type]]], - ctor: Ls[Statement], - superParameters: Ls[Term] - ): NewClassSymbol = { - val symbol = NewClassSymbol(lexicalName, params.sorted, base, methods, ctor, superParameters) + // in DiffTests, we need to rename `TypingUnit` to some other names + // because we would not indicate different names manually + def declareTopModule( + lexicalName: Str, + stmts: Ls[Statement], + nuTypes: Ls[NuTypeDef], + allowRenaming: Bool + ): ModuleSymbol = { + val finalName = + if (allowRenaming) allocateRuntimeName(lexicalName) else lexicalName + val (ctor, mths) = stmts.partitionMap { + case NuFunDef(isLetRec, Var(nme), tys, Left(rhs)) if (isLetRec.isEmpty || isLetRec.getOrElse(false)) => + Right(MethodDef[Left[Term, Type]](isLetRec.getOrElse(false), TypeName(finalName), Var(nme), tys, Left(rhs))) + case s => Left(s) + } + val symbol = ModuleSymbol(finalName, Nil, Record(Nil), mths, ctor, Nil, nuTypes, false) register(symbol) symbol } - def declareMixin( - lexicalName: Str, - params: Ls[Str], - base: Type, - methods: Ls[MethodDef[Left[Term, Type]]], - ctor: Ls[Statement] - ): MixinSymbol = { - val symbol = MixinSymbol(lexicalName, params.sorted, base, methods, ctor) - register(symbol) - symbol + def captureSymbol( + outsiderSym: RuntimeSymbol, + capturedSym: RuntimeSymbol + ): Unit = { + val symbol = CapturedSymbol(outsiderSym, capturedSym) + lexicalValueSymbols.put(symbol.lexicalName, symbol); () } - def declareModule( - lexicalName: Str, - params: Ls[Str], - base: Type, - methods: Ls[MethodDef[Left[Term, Type]]], - ctor: Ls[Statement], - superParameters: Ls[Term] - ): ModuleSymbol = { - val symbol = ModuleSymbol(lexicalName, params.sorted, base, methods, ctor, superParameters) - register(symbol) - symbol + // We don't want `outer` symbols to be shadowed by each other + // Add all runtime names of `outer` symbols from the parent scope + private def pullOuterSymbols(syms: scala.collection.mutable.HashSet[Str]) = { + syms.foreach { s => + runtimeSymbols += s + outerSymbols += s + } + + this } def declareTrait( @@ -298,9 +312,10 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } - def declareNewClassMember(name: Str, isByvalueRec: Option[Boolean], isLam: Boolean): NewClassMemberSymbol = { - val symbol = NewClassMemberSymbol(name, isByvalueRec, isLam) - register(symbol) + def declareOuterSymbol(): ValueSymbol = { + val lexicalName = "outer" + val symbol = declareValue(lexicalName, Some(false), false) + outerSymbols += symbol.runtimeName symbol } @@ -367,7 +382,8 @@ class Scope(name: Str, enclosing: Opt[Scope]) { /** * Shorthands for deriving normal scopes. */ - def derive(name: Str): Scope = new Scope(name, S(this)) + def derive(name: Str): Scope = + (new Scope(name, S(this))).pullOuterSymbols(outerSymbols) def refreshRes(): Unit = { diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index 95b9f2c1e4..b2ef4b5811 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -6,6 +6,7 @@ import mlscript.JSClassDecl import mlscript.MethodDef import mlscript.{Term, Statement} import mlscript.TypeName +import mlscript.NuTypeDef sealed trait LexicalSymbol { @@ -26,6 +27,14 @@ sealed trait TypeSymbol extends LexicalSymbol { val body: Type } +sealed trait NuTypeSymbol { + val isNested: Bool // is nested in another class/mixin/module + val methods: Ls[MethodDef[Left[Term, Type]]] + val ctor: Ls[Statement] // statements in the constructor + val nested: Ls[NuTypeDef] // nested class/mixin/module + val superParameters: Ls[Term] // parameters that need to be passed to the `super()` +} + sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol { override def toString: Str = s"value $lexicalName" } @@ -107,15 +116,12 @@ final case class NewClassSymbol( body: Type, methods: Ls[MethodDef[Left[Term, Type]]], ctor: Ls[Statement], - superParameters: Ls[Term] + superParameters: Ls[Term], + nested: Ls[NuTypeDef], + isNested: Bool ) extends TypeSymbol - with RuntimeSymbol with Ordered[NewClassSymbol] { - - import scala.math.Ordered.orderingToOrdered - - override def compare(that: NewClassSymbol): Int = lexicalName.compare(that.lexicalName) - - override def toString: Str = s"new class $lexicalName ($runtimeName)" + with RuntimeSymbol with NuTypeSymbol { + override def toString: Str = s"new class $lexicalName" // Classes should have fixed names determined by users override def runtimeName: Str = lexicalName @@ -126,18 +132,19 @@ final case class MixinSymbol( params: Ls[Str], body: Type, methods: Ls[MethodDef[Left[Term, Type]]], - ctor: Ls[Statement] + ctor: Ls[Statement], + nested: Ls[NuTypeDef], + isNested: Bool ) extends TypeSymbol - with RuntimeSymbol with Ordered[MixinSymbol] { - - import scala.math.Ordered.orderingToOrdered - - override def compare(that: MixinSymbol): Int = lexicalName.compare(that.lexicalName) - - override def toString: Str = s"mixin $lexicalName ($runtimeName)" + with RuntimeSymbol with NuTypeSymbol { + override def toString: Str = s"mixin $lexicalName" // Mixins should have fixed names determined by users override def runtimeName: Str = lexicalName + + // Mixins should pass `...rest` to the `super()` + // But the variable name is not sure when we create the symbol object + override val superParameters: Ls[Term] = Nil } final case class ModuleSymbol( @@ -146,20 +153,26 @@ final case class ModuleSymbol( body: Type, methods: Ls[MethodDef[Left[Term, Type]]], ctor: Ls[Statement], - superParameters: Ls[Term] + superParameters: Ls[Term], + nested: Ls[NuTypeDef], + isNested: Bool ) extends TypeSymbol - with RuntimeSymbol with Ordered[ModuleSymbol] { - - import scala.math.Ordered.orderingToOrdered - - override def compare(that: ModuleSymbol): Int = lexicalName.compare(that.lexicalName) - - override def toString: Str = s"module $lexicalName ($runtimeName)" + with RuntimeSymbol with NuTypeSymbol { + override def toString: Str = s"module $lexicalName" // Modules should have fixed names determined by users override def runtimeName: Str = lexicalName } +// capture runtime symbols in the outside module/class/mixin +final case class CapturedSymbol( + outsiderSym: RuntimeSymbol, + actualSym: RuntimeSymbol +) extends RuntimeSymbol { + override def lexicalName: Str = actualSym.lexicalName + override def runtimeName: Str = actualSym.runtimeName +} + final case class TraitSymbol( lexicalName: Str, runtimeName: Str, diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index b7fb35da06..b910fd2931 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -11,21 +11,25 @@ module Test0 { //│ return console.info(x); //│ } //│ let res; -//│ let typing_unit = { -//│ cache: {}, +//│ class TypingUnit { +//│ #Test0; +//│ constructor() { +//│ } //│ get Test0() { -//│ if (this.cache.Test0 === undefined) { +//│ const outer = this; +//│ if (this.#Test0 === undefined) { //│ class Test0 { //│ constructor() { //│ log("Hello!"); //│ } //│ } -//│ this.cache.Test0 = new Test0(); -//│ this.cache.Test0["class"] = Test0; +//│ this.#Test0 = new Test0(); +//│ this.#Test0.class = Test0; //│ } -//│ return this.cache.Test0; +//│ return this.#Test0; //│ } -//│ }; +//│ } +//│ const typing_unit = new TypingUnit; //│ globalThis.Test0 = typing_unit.Test0; //│ // End of generated code @@ -33,7 +37,8 @@ module Test0 { Test0 //│ Test0 //│ // Prelude -//│ let typing_unit1 = { cache: {} }; +//│ class TypingUnit1 {} +//│ const typing_unit1 = new TypingUnit1; //│ // Query 1 //│ res = Test0; //│ // End of generated code @@ -46,7 +51,8 @@ Test0 Test0 //│ Test0 //│ // Prelude -//│ let typing_unit2 = { cache: {} }; +//│ class TypingUnit2 {} +//│ const typing_unit2 = new TypingUnit2; //│ // Query 1 //│ res = Test0; //│ // End of generated code @@ -59,11 +65,13 @@ class A(a: int) { } //│ class A(a: int) //│ // Prelude -//│ let typing_unit3 = { -//│ cache: {}, +//│ class TypingUnit3 { +//│ #A; +//│ constructor() { +//│ } //│ get A() { -//│ const cache = this.cache; -//│ if (this.cache.A === undefined) { +//│ const outer = this; +//│ if (this.#A === undefined) { //│ class A { //│ #a; //│ get a() { return this.#a; } @@ -72,12 +80,13 @@ class A(a: int) { //│ log(a); //│ } //│ }; -//│ this.cache.A = ((a) => new A(a)); -//│ this.cache.A["class"] = A; +//│ this.#A = ((a) => new A(a)); +//│ this.#A.class = A; //│ } -//│ return this.cache.A; +//│ return this.#A; //│ } -//│ }; +//│ } +//│ const typing_unit3 = new TypingUnit3; //│ globalThis.A = typing_unit3.A; //│ // End of generated code @@ -85,7 +94,8 @@ class A(a: int) { let aa = A(42) //│ let aa: A //│ // Prelude -//│ let typing_unit4 = { cache: {} }; +//│ class TypingUnit4 {} +//│ const typing_unit4 = new TypingUnit4; //│ // Query 1 //│ globalThis.aa = A(42); //│ // End of generated code @@ -98,7 +108,8 @@ let aa = A(42) aa //│ A //│ // Prelude -//│ let typing_unit5 = { cache: {} }; +//│ class TypingUnit5 {} +//│ const typing_unit5 = new TypingUnit5; //│ // Query 1 //│ res = aa; //│ // End of generated code @@ -109,7 +120,8 @@ aa let ab = A(0) //│ let ab: A //│ // Prelude -//│ let typing_unit6 = { cache: {} }; +//│ class TypingUnit6 {} +//│ const typing_unit6 = new TypingUnit6; //│ // Query 1 //│ globalThis.ab = A(0); //│ // End of generated code @@ -124,22 +136,25 @@ class Foo { this: { x: int } } //│ ╔══[ERROR] Class `Foo` does not contain member `x` -//│ ║ l.124: this: { x: int } +//│ ║ l.136: this: { x: int } //│ ╙── ^ //│ class Foo() //│ // Prelude -//│ let typing_unit7 = { -//│ cache: {}, +//│ class TypingUnit7 { +//│ #Foo; +//│ constructor() { +//│ } //│ get Foo() { -//│ const cache = this.cache; -//│ if (this.cache.Foo === undefined) { +//│ const outer = this; +//│ if (this.#Foo === undefined) { //│ class Foo {}; -//│ this.cache.Foo = (() => new Foo()); -//│ this.cache.Foo["class"] = Foo; +//│ this.#Foo = (() => new Foo()); +//│ this.#Foo.class = Foo; //│ } -//│ return this.cache.Foo; +//│ return this.#Foo; //│ } -//│ }; +//│ } +//│ const typing_unit7 = new TypingUnit7; //│ globalThis.Foo = typing_unit7.Foo; //│ // End of generated code @@ -149,25 +164,28 @@ class Bar { super: { x: int } } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.149: super: { x: int } +//│ ║ l.164: super: { x: int } //│ ╙── ^^^^^ //│ ╔══[ERROR] Class `Bar` does not contain member `x` -//│ ║ l.149: super: { x: int } +//│ ║ l.164: super: { x: int } //│ ╙── ^ //│ class Bar() //│ // Prelude -//│ let typing_unit8 = { -//│ cache: {}, +//│ class TypingUnit8 { +//│ #Bar; +//│ constructor() { +//│ } //│ get Bar() { -//│ const cache = this.cache; -//│ if (this.cache.Bar === undefined) { +//│ const outer = this; +//│ if (this.#Bar === undefined) { //│ class Bar {}; -//│ this.cache.Bar = (() => new Bar()); -//│ this.cache.Bar["class"] = Bar; +//│ this.#Bar = (() => new Bar()); +//│ this.#Bar.class = Bar; //│ } -//│ return this.cache.Bar; +//│ return this.#Bar; //│ } -//│ }; +//│ } +//│ const typing_unit8 = new TypingUnit8; //│ globalThis.Bar = typing_unit8.Bar; //│ // End of generated code @@ -185,11 +203,13 @@ class Baz { //│ let y: int //│ } //│ // Prelude -//│ let typing_unit9 = { -//│ cache: {}, +//│ class TypingUnit9 { +//│ #Baz; +//│ constructor() { +//│ } //│ get Baz() { -//│ const cache = this.cache; -//│ if (this.cache.Baz === undefined) { +//│ const outer = this; +//│ if (this.#Baz === undefined) { //│ class Baz { //│ #x; //│ #y; @@ -216,12 +236,13 @@ class Baz { //│ ]); //│ } //│ }; -//│ this.cache.Baz = (() => new Baz()); -//│ this.cache.Baz["class"] = Baz; +//│ this.#Baz = (() => new Baz()); +//│ this.#Baz.class = Baz; //│ } -//│ return this.cache.Baz; +//│ return this.#Baz; //│ } -//│ }; +//│ } +//│ const typing_unit9 = new TypingUnit9; //│ globalThis.Baz = typing_unit9.Baz; //│ // End of generated code @@ -251,11 +272,13 @@ class Q() { //│ fun qq: {q: int} //│ } //│ // Prelude -//│ let typing_unit11 = { -//│ cache: {}, +//│ class TypingUnit11 { +//│ #Q; +//│ constructor() { +//│ } //│ get Q() { -//│ const cache = this.cache; -//│ if (this.cache.Q === undefined) { +//│ const outer = this; +//│ if (this.#Q === undefined) { //│ class Q { //│ #q; //│ get q() { return this.#q; } @@ -264,7 +287,6 @@ class Q() { //│ const q = this.#q; //│ } //│ get qq() { -//│ const Q = cache.Q; //│ const self = this; //│ return ((() => { //│ let f = (x) => ({ q: x + self.q }); @@ -272,12 +294,13 @@ class Q() { //│ })()); //│ } //│ }; -//│ this.cache.Q = (() => new Q()); -//│ this.cache.Q["class"] = Q; +//│ this.#Q = (() => new Q()); +//│ this.#Q.class = Q; //│ } -//│ return this.cache.Q; +//│ return this.#Q; //│ } -//│ }; +//│ } +//│ const typing_unit11 = new TypingUnit11; //│ globalThis.Q = typing_unit11.Q; //│ // End of generated code @@ -300,11 +323,13 @@ class W() { //│ let x: 42 //│ } //│ // Prelude -//│ let typing_unit13 = { -//│ cache: {}, +//│ class TypingUnit13 { +//│ #W; +//│ constructor() { +//│ } //│ get W() { -//│ const cache = this.cache; -//│ if (this.cache.W === undefined) { +//│ const outer = this; +//│ if (this.#W === undefined) { //│ class W { //│ #x; //│ get x() { return this.#x; } @@ -313,17 +338,17 @@ class W() { //│ const x = this.#x; //│ } //│ add(self1) { -//│ const W = cache.W; //│ const self = this; //│ return self.x + self1; //│ } //│ }; -//│ this.cache.W = (() => new W()); -//│ this.cache.W["class"] = W; +//│ this.#W = (() => new W()); +//│ this.#W.class = W; //│ } -//│ return this.cache.W; +//│ return this.#W; //│ } -//│ }; +//│ } +//│ const typing_unit13 = new TypingUnit13; //│ globalThis.W = typing_unit13.W; //│ // End of generated code @@ -333,7 +358,8 @@ www.add(42) //│ let www: W //│ int //│ // Prelude -//│ let typing_unit14 = { cache: {} }; +//│ class TypingUnit14 {} +//│ const typing_unit14 = new TypingUnit14; //│ // Query 1 //│ globalThis.www = W(); //│ // Query 2 diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 4dd1ff464d..b72e833b59 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -9,11 +9,14 @@ class Lit(n: int) //│ class Lit(n: int) //│ // Prelude //│ let res; -//│ let typing_unit = { -//│ cache: {}, +//│ class TypingUnit { +//│ #Add; +//│ #Lit; +//│ constructor() { +//│ } //│ get Add() { -//│ const cache = this.cache; -//│ if (this.cache.Add === undefined) { +//│ const outer = this; +//│ if (this.#Add === undefined) { //│ class Add { //│ #lhs; //│ #rhs; @@ -24,14 +27,14 @@ class Lit(n: int) //│ this.#rhs = rhs; //│ } //│ }; -//│ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); -//│ this.cache.Add["class"] = Add; +//│ this.#Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ this.#Add.class = Add; //│ } -//│ return this.cache.Add; -//│ }, +//│ return this.#Add; +//│ } //│ get Lit() { -//│ const cache = this.cache; -//│ if (this.cache.Lit === undefined) { +//│ const outer = this; +//│ if (this.#Lit === undefined) { //│ class Lit { //│ #n; //│ get n() { return this.#n; } @@ -39,12 +42,13 @@ class Lit(n: int) //│ this.#n = n; //│ } //│ }; -//│ this.cache.Lit = ((n) => new Lit(n)); -//│ this.cache.Lit["class"] = Lit; +//│ this.#Lit = ((n) => new Lit(n)); +//│ this.#Lit.class = Lit; //│ } -//│ return this.cache.Lit; +//│ return this.#Lit; //│ } -//│ }; +//│ } +//│ const typing_unit = new TypingUnit; //│ globalThis.Add = typing_unit.Add; //│ globalThis.Lit = typing_unit.Lit; //│ // End of generated code @@ -52,11 +56,14 @@ class Lit(n: int) //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ let res; -//│ │ │ let typing_unit = { -//│ │ │ cache: {}, +//│ │ │ class TypingUnit { +//│ │ │ #Add; +//│ │ │ #Lit; +//│ │ │ constructor() { +//│ │ │ } //│ │ │ get Add() { -//│ │ │ const cache = this.cache; -//│ │ │ if (this.cache.Add === undefined) { +//│ │ │ const outer = this; +//│ │ │ if (this.#Add === undefined) { //│ │ │ class Add { //│ │ │ #lhs; //│ │ │ #rhs; @@ -67,14 +74,14 @@ class Lit(n: int) //│ │ │ this.#rhs = rhs; //│ │ │ } //│ │ │ }; -//│ │ │ this.cache.Add = ((lhs, rhs) => new Add(lhs, rhs)); -//│ │ │ this.cache.Add["class"] = Add; +//│ │ │ this.#Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ │ │ this.#Add.class = Add; //│ │ │ } -//│ │ │ return this.cache.Add; -//│ │ │ }, +//│ │ │ return this.#Add; +//│ │ │ } //│ │ │ get Lit() { -//│ │ │ const cache = this.cache; -//│ │ │ if (this.cache.Lit === undefined) { +//│ │ │ const outer = this; +//│ │ │ if (this.#Lit === undefined) { //│ │ │ class Lit { //│ │ │ #n; //│ │ │ get n() { return this.#n; } @@ -82,12 +89,13 @@ class Lit(n: int) //│ │ │ this.#n = n; //│ │ │ } //│ │ │ }; -//│ │ │ this.cache.Lit = ((n) => new Lit(n)); -//│ │ │ this.cache.Lit["class"] = Lit; +//│ │ │ this.#Lit = ((n) => new Lit(n)); +//│ │ │ this.#Lit.class = Lit; //│ │ │ } -//│ │ │ return this.cache.Lit; +//│ │ │ return this.#Lit; //│ │ │ } -//│ │ │ }; +//│ │ │ } +//│ │ │ const typing_unit = new TypingUnit; //│ │ │ globalThis.Add = typing_unit.Add; //│ │ │ globalThis.Lit = typing_unit.Lit; //│ │ └── Reply @@ -107,9 +115,11 @@ mixin EvalBase { //│ fun eval: (Add['lhs] | Lit) -> int //│ } //│ // Prelude -//│ let typing_unit1 = { -//│ cache: {}, +//│ class TypingUnit1 { +//│ constructor() { +//│ } //│ EvalBase(base) { +//│ const outer = this; //│ return (class EvalBase extends base { //│ constructor(...rest) { //│ super(...rest); @@ -118,22 +128,25 @@ mixin EvalBase { //│ const self = this; //│ return ((() => { //│ let a; -//│ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ return (a = e, a instanceof Lit.class ? ((n) => n)(e.n) : a instanceof Add.class ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { //│ throw new Error("non-exhaustive case expression"); //│ })()); //│ })()); //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit1 = new TypingUnit1; //│ globalThis.EvalBase = typing_unit1.EvalBase; //│ // End of generated code -//│ ┌ Block at Mixin.mls:99 +//│ ┌ Block at Mixin.mls:107 //│ ├─┬ Prelude //│ │ ├── Code -//│ │ │ let typing_unit1 = { -//│ │ │ cache: {}, +//│ │ │ class TypingUnit1 { +//│ │ │ constructor() { +//│ │ │ } //│ │ │ EvalBase(base) { +//│ │ │ const outer = this; //│ │ │ return (class EvalBase extends base { //│ │ │ constructor(...rest) { //│ │ │ super(...rest); @@ -142,14 +155,15 @@ mixin EvalBase { //│ │ │ const self = this; //│ │ │ return ((() => { //│ │ │ let a; -//│ │ │ return (a = e, a instanceof Lit["class"] ? ((n) => n)(e.n) : a instanceof Add["class"] ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { +//│ │ │ return (a = e, a instanceof Lit.class ? ((n) => n)(e.n) : a instanceof Add.class ? ((l) => ((r) => self.eval(l) + self.eval(r))(e.rhs))(e.lhs) : (() => { //│ │ │ throw new Error("non-exhaustive case expression"); //│ │ │ })()); //│ │ │ })()); //│ │ │ } //│ │ │ }); //│ │ │ } -//│ │ │ }; +//│ │ │ } +//│ │ │ const typing_unit1 = new TypingUnit1; //│ │ │ globalThis.EvalBase = typing_unit1.EvalBase; //│ │ └── Reply //│ │ [Function: EvalBase] @@ -160,11 +174,13 @@ mixin EvalBase { class Neg(expr: A) //│ class Neg[A](expr: A) //│ // Prelude -//│ let typing_unit2 = { -//│ cache: {}, +//│ class TypingUnit2 { +//│ #Neg; +//│ constructor() { +//│ } //│ get Neg() { -//│ const cache = this.cache; -//│ if (this.cache.Neg === undefined) { +//│ const outer = this; +//│ if (this.#Neg === undefined) { //│ class Neg { //│ #expr; //│ get expr() { return this.#expr; } @@ -172,22 +188,25 @@ class Neg(expr: A) //│ this.#expr = expr; //│ } //│ }; -//│ this.cache.Neg = ((expr) => new Neg(expr)); -//│ this.cache.Neg["class"] = Neg; +//│ this.#Neg = ((expr) => new Neg(expr)); +//│ this.#Neg.class = Neg; //│ } -//│ return this.cache.Neg; +//│ return this.#Neg; //│ } -//│ }; +//│ } +//│ const typing_unit2 = new TypingUnit2; //│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:160 +//│ ┌ Block at Mixin.mls:174 //│ ├─┬ Prelude //│ │ ├── Code -//│ │ │ let typing_unit2 = { -//│ │ │ cache: {}, +//│ │ │ class TypingUnit2 { +//│ │ │ #Neg; +//│ │ │ constructor() { +//│ │ │ } //│ │ │ get Neg() { -//│ │ │ const cache = this.cache; -//│ │ │ if (this.cache.Neg === undefined) { +//│ │ │ const outer = this; +//│ │ │ if (this.#Neg === undefined) { //│ │ │ class Neg { //│ │ │ #expr; //│ │ │ get expr() { return this.#expr; } @@ -195,12 +214,13 @@ class Neg(expr: A) //│ │ │ this.#expr = expr; //│ │ │ } //│ │ │ }; -//│ │ │ this.cache.Neg = ((expr) => new Neg(expr)); -//│ │ │ this.cache.Neg["class"] = Neg; +//│ │ │ this.#Neg = ((expr) => new Neg(expr)); +//│ │ │ this.#Neg.class = Neg; //│ │ │ } -//│ │ │ return this.cache.Neg; +//│ │ │ return this.#Neg; //│ │ │ } -//│ │ │ }; +//│ │ │ } +//│ │ │ const typing_unit2 = new TypingUnit2; //│ │ │ globalThis.Neg = typing_unit2.Neg; //│ │ └── Reply //│ │ [Function (anonymous)] { class: [class Neg] } @@ -219,9 +239,11 @@ mixin EvalNeg { //│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) //│ } //│ // Prelude -//│ let typing_unit3 = { -//│ cache: {}, +//│ class TypingUnit3 { +//│ constructor() { +//│ } //│ EvalNeg(base) { +//│ const outer = this; //│ return (class EvalNeg extends base { //│ constructor(...rest) { //│ super(...rest); @@ -229,20 +251,23 @@ mixin EvalNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ return e instanceof Neg.class ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit3 = new TypingUnit3; //│ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:211 +//│ ┌ Block at Mixin.mls:231 //│ ├─┬ Prelude //│ │ ├── Code -//│ │ │ let typing_unit3 = { -//│ │ │ cache: {}, +//│ │ │ class TypingUnit3 { +//│ │ │ constructor() { +//│ │ │ } //│ │ │ EvalNeg(base) { +//│ │ │ const outer = this; //│ │ │ return (class EvalNeg extends base { //│ │ │ constructor(...rest) { //│ │ │ super(...rest); @@ -250,12 +275,13 @@ mixin EvalNeg { //│ │ │ eval(e) { //│ │ │ const self = this; //│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); +//│ │ │ return e instanceof Neg.class ? ((d) => 0 - self.eval(d))(e.expr) : super.eval(e); //│ │ │ })()); //│ │ │ } //│ │ │ }); //│ │ │ } -//│ │ │ }; +//│ │ │ } +//│ │ │ const typing_unit3 = new TypingUnit3; //│ │ │ globalThis.EvalNeg = typing_unit3.EvalNeg; //│ │ └── Reply //│ │ [Function: EvalNeg] @@ -274,9 +300,11 @@ mixin EvalNegNeg { //│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b //│ } //│ // Prelude -//│ let typing_unit4 = { -//│ cache: {}, +//│ class TypingUnit4 { +//│ constructor() { +//│ } //│ EvalNegNeg(base) { +//│ const outer = this; //│ return (class EvalNegNeg extends base { //│ constructor(...rest) { //│ super(...rest); @@ -284,20 +312,23 @@ mixin EvalNegNeg { //│ eval(e) { //│ const self = this; //│ return ((() => { -//│ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ return e instanceof Neg.class ? ((tmp0) => tmp0 instanceof Neg.class ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); //│ })()); //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit4 = new TypingUnit4; //│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:266 +//│ ┌ Block at Mixin.mls:292 //│ ├─┬ Prelude //│ │ ├── Code -//│ │ │ let typing_unit4 = { -//│ │ │ cache: {}, +//│ │ │ class TypingUnit4 { +//│ │ │ constructor() { +//│ │ │ } //│ │ │ EvalNegNeg(base) { +//│ │ │ const outer = this; //│ │ │ return (class EvalNegNeg extends base { //│ │ │ constructor(...rest) { //│ │ │ super(...rest); @@ -305,12 +336,13 @@ mixin EvalNegNeg { //│ │ │ eval(e) { //│ │ │ const self = this; //│ │ │ return ((() => { -//│ │ │ return e instanceof Neg["class"] ? ((tmp0) => tmp0 instanceof Neg["class"] ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); +//│ │ │ return e instanceof Neg.class ? ((tmp0) => tmp0 instanceof Neg.class ? ((d) => self.eval(d))(tmp0.expr) : super.eval(e))(e.expr) : super.eval(e); //│ │ │ })()); //│ │ │ } //│ │ │ }); //│ │ │ } -//│ │ │ }; +//│ │ │ } +//│ │ │ const typing_unit4 = new TypingUnit4; //│ │ │ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; //│ │ └── Reply //│ │ [Function: EvalNegNeg] @@ -325,41 +357,49 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ where //│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] //│ // Prelude -//│ let typing_unit5 = { -//│ cache: {}, +//│ class TypingUnit5 { +//│ #TestLang; +//│ constructor() { +//│ } //│ get TestLang() { -//│ if (this.cache.TestLang === undefined) { +//│ const outer = this; +//│ if (this.#TestLang === undefined) { //│ class TestLang extends EvalNegNeg(EvalNeg(EvalBase(Object))) { //│ constructor() { //│ super(); //│ } //│ } -//│ this.cache.TestLang = new TestLang(); -//│ this.cache.TestLang["class"] = TestLang; +//│ this.#TestLang = new TestLang(); +//│ this.#TestLang.class = TestLang; //│ } -//│ return this.cache.TestLang; +//│ return this.#TestLang; //│ } -//│ }; +//│ } +//│ const typing_unit5 = new TypingUnit5; //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code -//│ ┌ Block at Mixin.mls:321 +//│ ┌ Block at Mixin.mls:353 //│ ├─┬ Prelude //│ │ ├── Code -//│ │ │ let typing_unit5 = { -//│ │ │ cache: {}, +//│ │ │ class TypingUnit5 { +//│ │ │ #TestLang; +//│ │ │ constructor() { +//│ │ │ } //│ │ │ get TestLang() { -//│ │ │ if (this.cache.TestLang === undefined) { +//│ │ │ const outer = this; +//│ │ │ if (this.#TestLang === undefined) { //│ │ │ class TestLang extends EvalNegNeg(EvalNeg(EvalBase(Object))) { //│ │ │ constructor() { //│ │ │ super(); //│ │ │ } //│ │ │ } -//│ │ │ this.cache.TestLang = new TestLang(); -//│ │ │ this.cache.TestLang["class"] = TestLang; +//│ │ │ this.#TestLang = new TestLang(); +//│ │ │ this.#TestLang.class = TestLang; //│ │ │ } -//│ │ │ return this.cache.TestLang; +//│ │ │ return this.#TestLang; //│ │ │ } -//│ │ │ }; +//│ │ │ } +//│ │ │ const typing_unit5 = new TypingUnit5; //│ │ │ globalThis.TestLang = typing_unit5.TestLang; //│ │ └── Reply //│ │ TestLang { class: [Function: TestLang] } @@ -377,7 +417,8 @@ TestLang.eval(mk(0)) //│ where //│ 'E :> Add['E] | Lit | Neg['E] //│ // Prelude -//│ let typing_unit6 = { cache: {} }; +//│ class TypingUnit6 {} +//│ const typing_unit6 = new TypingUnit6; //│ // Query 1 //│ globalThis.mk = function mk(n) { //│ return n == 0 === true ? Lit(0) : n == 1 === true ? Neg(mk(n)) : Add(mk(n), mk(n)); @@ -385,10 +426,11 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:370 +//│ ┌ Block at Mixin.mls:410 //│ ├─┬ Prelude //│ │ ├── Code -//│ │ │ let typing_unit6 = { cache: {} }; +//│ │ │ class TypingUnit6 {} +//│ │ │ const typing_unit6 = new TypingUnit6; //│ │ └── Reply //│ │ undefined //│ ├─┬ Query 1/2 @@ -416,7 +458,7 @@ class Foo(x: int) :e class Bar(x: int, y: int) extends Foo(x + y) //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.417: class Bar(x: int, y: int) extends Foo(x + y) +//│ ║ l.459: class Bar(x: int, y: int) extends Foo(x + y) //│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -445,9 +487,11 @@ mixin Fooo(x: int) { fun f = [x, this.x] } //│ fun f: (int, 'x,) //│ } //│ // Prelude -//│ let typing_unit14 = { -//│ cache: {}, +//│ class TypingUnit14 { +//│ constructor() { +//│ } //│ Fooo(base) { +//│ const outer = this; //│ return (class Fooo extends base { //│ #x; //│ get x() { return this.#x; } @@ -465,7 +509,8 @@ mixin Fooo(x: int) { fun f = [x, this.x] } //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit14 = new TypingUnit14; //│ globalThis.Fooo = typing_unit14.Fooo; //│ // End of generated code @@ -473,9 +518,11 @@ mixin Fooo(x: int) { fun f = [x, this.x] } mixin Bazz(y: int) //│ mixin Bazz(y: int) //│ // Prelude -//│ let typing_unit15 = { -//│ cache: {}, +//│ class TypingUnit15 { +//│ constructor() { +//│ } //│ Bazz(base) { +//│ const outer = this; //│ return (class Bazz extends base { //│ #y; //│ get y() { return this.#y; } @@ -485,7 +532,8 @@ mixin Bazz(y: int) //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit15 = new TypingUnit15; //│ globalThis.Bazz = typing_unit15.Bazz; //│ // End of generated code @@ -495,21 +543,25 @@ module Barr extends Fooo(0), Bazz(1) //│ fun f: (int, 0,) //│ } //│ // Prelude -//│ let typing_unit16 = { -//│ cache: {}, +//│ class TypingUnit16 { +//│ #Barr; +//│ constructor() { +//│ } //│ get Barr() { -//│ if (this.cache.Barr === undefined) { +//│ const outer = this; +//│ if (this.#Barr === undefined) { //│ class Barr extends Bazz(Fooo(Object)) { //│ constructor() { //│ super(1, 0); //│ } //│ } -//│ this.cache.Barr = new Barr(); -//│ this.cache.Barr["class"] = Barr; +//│ this.#Barr = new Barr(); +//│ this.#Barr.class = Barr; //│ } -//│ return this.cache.Barr; +//│ return this.#Barr; //│ } -//│ }; +//│ } +//│ const typing_unit16 = new TypingUnit16; //│ globalThis.Barr = typing_unit16.Barr; //│ // End of generated code @@ -529,7 +581,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.529: fun x = y +//│ ║ l.581: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error @@ -558,21 +610,25 @@ mixin MC(c: int) module MM extends MA(1), MB(2, 3), MC(4) //│ module MM() //│ // Prelude -//│ let typing_unit22 = { -//│ cache: {}, +//│ class TypingUnit22 { +//│ #MM; +//│ constructor() { +//│ } //│ get MM() { -//│ if (this.cache.MM === undefined) { +//│ const outer = this; +//│ if (this.#MM === undefined) { //│ class MM extends MC(MB(MA(Object))) { //│ constructor() { //│ super(4, 2, 3, 1); //│ } //│ } -//│ this.cache.MM = new MM(); -//│ this.cache.MM["class"] = MM; +//│ this.#MM = new MM(); +//│ this.#MM.class = MM; //│ } -//│ return this.cache.MM; +//│ return this.#MM; //│ } -//│ }; +//│ } +//│ const typing_unit22 = new TypingUnit22; //│ globalThis.MM = typing_unit22.MM; //│ // End of generated code diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls new file mode 100644 index 0000000000..c707d2d08e --- /dev/null +++ b/shared/src/test/diff/codegen/Nested.mls @@ -0,0 +1,1404 @@ +:NewParser +:NewDefs + +:js +module A { + let a = 42 + class B(x: int) { + fun b = x + 1 + } +} +//│ module A() { +//│ class B(x: int) { +//│ fun b: int +//│ } +//│ let a: 42 +//│ } +//│ // Prelude +//│ let res; +//│ class TypingUnit { +//│ #A; +//│ constructor() { +//│ } +//│ get A() { +//│ const outer = this; +//│ if (this.#A === undefined) { +//│ class A { +//│ #B; +//│ #a; +//│ get a() { return this.#a; } +//│ constructor() { +//│ this.#a = 42; +//│ const a = this.#a; +//│ } +//│ get B() { +//│ const outer1 = this; +//│ if (this.#B === undefined) { +//│ class B { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ get b() { +//│ const x = this.#x; +//│ return x + 1; +//│ } +//│ }; +//│ this.#B = ((x) => new B(x)); +//│ this.#B.class = B; +//│ } +//│ return this.#B; +//│ } +//│ } +//│ this.#A = new A(); +//│ this.#A.class = A; +//│ } +//│ return this.#A; +//│ } +//│ } +//│ const typing_unit = new TypingUnit; +//│ globalThis.A = typing_unit.A; +//│ // End of generated code + +:e +:js +let bb = A.B(A.a) +bb.b +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.66: let bb = A.B(A.a) +//│ ╙── ^^ +//│ let bb: error +//│ error +//│ // Prelude +//│ class TypingUnit1 {} +//│ const typing_unit1 = new TypingUnit1; +//│ // Query 1 +//│ globalThis.bb = A.B(A.a); +//│ // Query 2 +//│ res = bb.b; +//│ // End of generated code +//│ bb +//│ = B {} +//│ res +//│ = 43 + + +:e +class B(x: int) { + let outer = 42 + class C(y: int) { + let outer1 = outer + outer + } + class D(outer: int) +} +let b = B(1) +b.outer +let c = b.C(1) +c.outer1 +let d = b.D(1) +d.outer +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.97: let c = b.C(1) +//│ ╙── ^^ +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.99: let d = b.D(1) +//│ ╙── ^^ +//│ class B(x: int) { +//│ class C(y: int) { +//│ let outer1: int +//│ } +//│ class D(outer: int) +//│ let outer: 42 +//│ } +//│ let b: B +//│ let c: error +//│ let d: error +//│ error +//│ b +//│ = B {} +//│ res +//│ = 42 +//│ c +//│ = C {} +//│ res +//│ = 84 +//│ d +//│ = D {} +//│ res +//│ = 1 + +:js +mixin C() { + mixin D() { + mixin E() {} + } +} +//│ mixin C() { +//│ mixin D() { +//│ mixin E() +//│ } +//│ } +//│ // Prelude +//│ class TypingUnit3 { +//│ constructor() { +//│ } +//│ C(base) { +//│ const outer = this; +//│ return (class C extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ D(base) { +//│ const outer1 = this; +//│ return (class D extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ E(base) { +//│ const outer2 = this; +//│ return (class E extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ }); +//│ } +//│ }); +//│ } +//│ }); +//│ } +//│ } +//│ const typing_unit3 = new TypingUnit3; +//│ globalThis.C = typing_unit3.C; +//│ // End of generated code + +:js +module D { + class E(x: int) {} + fun createE(x: int) = E(x + 1) +} +//│ module D() { +//│ class E(x: int) +//│ fun createE: (x: int,) -> E +//│ } +//│ // Prelude +//│ class TypingUnit4 { +//│ #D; +//│ constructor() { +//│ } +//│ get D() { +//│ const outer = this; +//│ if (this.#D === undefined) { +//│ class D { +//│ #E; +//│ constructor() { +//│ } +//│ createE(x) { +//│ const self = this; +//│ return self.E(x + 1); +//│ } +//│ get E() { +//│ const outer1 = this; +//│ if (this.#E === undefined) { +//│ class E { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ }; +//│ this.#E = ((x) => new E(x)); +//│ this.#E.class = E; +//│ } +//│ return this.#E; +//│ } +//│ } +//│ this.#D = new D(); +//│ this.#D.class = D; +//│ } +//│ return this.#D; +//│ } +//│ } +//│ const typing_unit4 = new TypingUnit4; +//│ globalThis.D = typing_unit4.D; +//│ // End of generated code + +:js +let ee = D.createE(42) +ee.x +//│ let ee: E +//│ int +//│ // Prelude +//│ class TypingUnit5 {} +//│ const typing_unit5 = new TypingUnit5; +//│ // Query 1 +//│ globalThis.ee = D.createE(42); +//│ // Query 2 +//│ res = ee.x; +//│ // End of generated code +//│ ee +//│ = E {} +//│ res +//│ = 43 + +:js +class E(x: int) { + class F(y: int) { + fun sum = x + y + class G(z: int) { + fun sum = x + y + z + } + } +} +//│ class E(x: int) { +//│ class F(y: int) { +//│ class G(z: int) { +//│ fun sum: int +//│ } +//│ fun sum: int +//│ } +//│ } +//│ // Prelude +//│ class TypingUnit6 { +//│ #E; +//│ constructor() { +//│ } +//│ get E() { +//│ const outer = this; +//│ if (this.#E === undefined) { +//│ class E { +//│ #F; +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ get F() { +//│ const outer1 = this; +//│ if (this.#F === undefined) { +//│ class F { +//│ #G; +//│ #y; +//│ get y() { return this.#y; } +//│ constructor(y) { +//│ this.#y = y; +//│ } +//│ get sum() { +//│ const y = this.#y; +//│ return outer1.x + y; +//│ } +//│ get G() { +//│ const outer2 = this; +//│ if (this.#G === undefined) { +//│ class G { +//│ #z; +//│ get z() { return this.#z; } +//│ constructor(z) { +//│ this.#z = z; +//│ } +//│ get sum() { +//│ const z = this.#z; +//│ return outer1.x + outer2.y + z; +//│ } +//│ }; +//│ this.#G = ((z) => new G(z)); +//│ this.#G.class = G; +//│ } +//│ return this.#G; +//│ } +//│ }; +//│ this.#F = ((y) => new F(y)); +//│ this.#F.class = F; +//│ } +//│ return this.#F; +//│ } +//│ }; +//│ this.#E = ((x) => new E(x)); +//│ this.#E.class = E; +//│ } +//│ return this.#E; +//│ } +//│ } +//│ const typing_unit6 = new TypingUnit6; +//│ globalThis.E = typing_unit6.E; +//│ // End of generated code + +:e +:js +let es = E(1) +let fff = es.F(2) +let gg = fff.G(3) +gg.sum +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.329: let fff = es.F(2) +//│ ╙── ^^ +//│ let es: E +//│ let fff: error +//│ let gg: error +//│ error +//│ // Prelude +//│ class TypingUnit7 {} +//│ const typing_unit7 = new TypingUnit7; +//│ // Query 1 +//│ globalThis.es = E(1); +//│ // Query 2 +//│ globalThis.fff = es.F(2); +//│ // Query 3 +//│ globalThis.gg = fff.G(3); +//│ // Query 4 +//│ res = gg.sum; +//│ // End of generated code +//│ es +//│ = E {} +//│ fff +//│ = F {} +//│ gg +//│ = G {} +//│ res +//│ = 6 + +:js +class F() { + let x = 42 + class G() { + let x1 = x + 1 + } +} +//│ class F() { +//│ class G() { +//│ let x1: int +//│ } +//│ let x: 42 +//│ } +//│ // Prelude +//│ class TypingUnit8 { +//│ #F; +//│ constructor() { +//│ } +//│ get F() { +//│ const outer = this; +//│ if (this.#F === undefined) { +//│ class F { +//│ #G; +//│ #x; +//│ get x() { return this.#x; } +//│ constructor() { +//│ this.#x = 42; +//│ const x = this.#x; +//│ } +//│ get G() { +//│ const outer1 = this; +//│ if (this.#G === undefined) { +//│ class G { +//│ #x1; +//│ get x1() { return this.#x1; } +//│ constructor() { +//│ this.#x1 = outer1.x + 1; +//│ const x1 = this.#x1; +//│ } +//│ }; +//│ this.#G = (() => new G()); +//│ this.#G.class = G; +//│ } +//│ return this.#G; +//│ } +//│ }; +//│ this.#F = (() => new F()); +//│ this.#F.class = F; +//│ } +//│ return this.#F; +//│ } +//│ } +//│ const typing_unit8 = new TypingUnit8; +//│ globalThis.F = typing_unit8.F; +//│ // End of generated code + + +:js +module G { + class I(x: int) {} + module H { + fun i1(x: int) = I(x + 1) + class J(x: int) { + fun ii(a: int) = I(x + a) + } + } +} +//│ module G() { +//│ module H() { +//│ class J(x: int) { +//│ fun ii: (a: int,) -> I +//│ } +//│ fun i1: (x: int,) -> I +//│ } +//│ class I(x: int) +//│ } +//│ // Prelude +//│ class TypingUnit9 { +//│ #G; +//│ constructor() { +//│ } +//│ get G() { +//│ const outer = this; +//│ if (this.#G === undefined) { +//│ class G { +//│ #I; +//│ #H; +//│ constructor() { +//│ } +//│ get H() { +//│ const outer1 = this; +//│ if (this.#H === undefined) { +//│ class H { +//│ #J; +//│ constructor() { +//│ } +//│ i1(x) { +//│ return outer1.I(x + 1); +//│ } +//│ get J() { +//│ const outer2 = this; +//│ if (this.#J === undefined) { +//│ class J { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ ii(a) { +//│ const x = this.#x; +//│ return outer1.I(x + a); +//│ } +//│ }; +//│ this.#J = ((x) => new J(x)); +//│ this.#J.class = J; +//│ } +//│ return this.#J; +//│ } +//│ } +//│ this.#H = new H(); +//│ this.#H.class = H; +//│ } +//│ return this.#H; +//│ } +//│ get I() { +//│ const outer1 = this; +//│ if (this.#I === undefined) { +//│ class I { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ }; +//│ this.#I = ((x) => new I(x)); +//│ this.#I.class = I; +//│ } +//│ return this.#I; +//│ } +//│ } +//│ this.#G = new G(); +//│ this.#G.class = G; +//│ } +//│ return this.#G; +//│ } +//│ } +//│ const typing_unit9 = new TypingUnit9; +//│ globalThis.G = typing_unit9.G; +//│ // End of generated code + + +:e +:js +let jj = G.H.J(42) +let i = jj.ii(2) +i.x +//│ ╔══[ERROR] access to module member not yet supported +//│ ║ l.513: let jj = G.H.J(42) +//│ ╙── ^^ +//│ let jj: error +//│ let i: error +//│ error +//│ // Prelude +//│ class TypingUnit10 {} +//│ const typing_unit10 = new TypingUnit10; +//│ // Query 1 +//│ globalThis.jj = G.H.J(42); +//│ // Query 2 +//│ globalThis.i = jj.ii(2); +//│ // Query 3 +//│ res = i.x; +//│ // End of generated code +//│ jj +//│ = J {} +//│ i +//│ = I {} +//│ res +//│ = 44 + +:js +module H { + class I(x: int) + class J(x: int) { + let i = I(x + 1) + } +} +//│ module H() { +//│ class I(x: int) +//│ class J(x: int) { +//│ let i: I +//│ } +//│ } +//│ // Prelude +//│ class TypingUnit11 { +//│ #H; +//│ constructor() { +//│ } +//│ get H() { +//│ const outer = this; +//│ if (this.#H === undefined) { +//│ class H { +//│ #I; +//│ #J; +//│ constructor() { +//│ } +//│ get I() { +//│ const outer1 = this; +//│ if (this.#I === undefined) { +//│ class I { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ }; +//│ this.#I = ((x) => new I(x)); +//│ this.#I.class = I; +//│ } +//│ return this.#I; +//│ } +//│ get J() { +//│ const outer1 = this; +//│ if (this.#J === undefined) { +//│ class J { +//│ #x; +//│ #i; +//│ get x() { return this.#x; } +//│ get i() { return this.#i; } +//│ constructor(x) { +//│ this.#x = x; +//│ this.#i = outer1.I(x + 1); +//│ const i = this.#i; +//│ } +//│ }; +//│ this.#J = ((x) => new J(x)); +//│ this.#J.class = J; +//│ } +//│ return this.#J; +//│ } +//│ } +//│ this.#H = new H(); +//│ this.#H.class = H; +//│ } +//│ return this.#H; +//│ } +//│ } +//│ const typing_unit11 = new TypingUnit11; +//│ globalThis.H = typing_unit11.H; +//│ // End of generated code + + +:e +:js +let j = H.J(42) +j.i.x +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.613: let j = H.J(42) +//│ ╙── ^^ +//│ let j: error +//│ error +//│ // Prelude +//│ class TypingUnit12 {} +//│ const typing_unit12 = new TypingUnit12; +//│ // Query 1 +//│ globalThis.j = H.J(42); +//│ // Query 2 +//│ res = j.i.x; +//│ // End of generated code +//│ j +//│ = J {} +//│ res +//│ = 43 + +:js +:e +class I(x: int) { + let y = x + 1 + class J(x: int) { + let y = x + 2 + fun incY = y + 1 + } +} +let i = I(1) +let ij = i.J(0) +ij.incY +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.643: let ij = i.J(0) +//│ ╙── ^^ +//│ class I(x: int) { +//│ class J(x: int) { +//│ fun incY: int +//│ let y: int +//│ } +//│ let y: int +//│ } +//│ let i: I +//│ let ij: error +//│ error +//│ // Prelude +//│ class TypingUnit13 { +//│ #I; +//│ constructor() { +//│ } +//│ get I() { +//│ const outer = this; +//│ if (this.#I === undefined) { +//│ class I { +//│ #J; +//│ #x; +//│ #y; +//│ get x() { return this.#x; } +//│ get y() { return this.#y; } +//│ constructor(x) { +//│ this.#x = x; +//│ this.#y = x + 1; +//│ const y = this.#y; +//│ } +//│ get J() { +//│ const outer1 = this; +//│ if (this.#J === undefined) { +//│ class J { +//│ #x; +//│ #y; +//│ get x() { return this.#x; } +//│ get y() { return this.#y; } +//│ constructor(x) { +//│ this.#x = x; +//│ this.#y = x + 2; +//│ const y = this.#y; +//│ } +//│ get incY() { +//│ const x = this.#x; +//│ const self = this; +//│ return self.y + 1; +//│ } +//│ }; +//│ this.#J = ((x) => new J(x)); +//│ this.#J.class = J; +//│ } +//│ return this.#J; +//│ } +//│ }; +//│ this.#I = ((x) => new I(x)); +//│ this.#I.class = I; +//│ } +//│ return this.#I; +//│ } +//│ } +//│ const typing_unit13 = new TypingUnit13; +//│ globalThis.I = typing_unit13.I; +//│ // Query 1 +//│ globalThis.i1 = I(1); +//│ // Query 2 +//│ globalThis.ij = i1.J(0); +//│ // Query 3 +//│ res = ij.incY; +//│ // End of generated code +//│ i +//│ = I {} +//│ ij +//│ = J {} +//│ res +//│ = 3 + +:e +:js +module J { + class K(x: int) {} + mixin L() {} + class M() extends K(1) {} + class N(x: int) extends K(x + 2), L +} +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.729: class M() extends K(1) {} +//│ ╙── ^^^^ +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.730: class N(x: int) extends K(x + 2), L +//│ ╙── ^^^^^^^^ +//│ module J() { +//│ class K(x: int) +//│ mixin L() +//│ class M() +//│ class N(x: int) +//│ } +//│ // Prelude +//│ class TypingUnit14 { +//│ #J; +//│ constructor() { +//│ } +//│ get J() { +//│ const outer = this; +//│ if (this.#J === undefined) { +//│ class J { +//│ #K; +//│ #M; +//│ #N; +//│ constructor() { +//│ } +//│ L(base) { +//│ const outer1 = this; +//│ return (class L extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ }); +//│ } +//│ get K() { +//│ const outer1 = this; +//│ if (this.#K === undefined) { +//│ class K { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ }; +//│ this.#K = ((x) => new K(x)); +//│ this.#K.class = K; +//│ } +//│ return this.#K; +//│ } +//│ get M() { +//│ const outer1 = this; +//│ if (this.#M === undefined) { +//│ class M extends outer1.K.class { +//│ constructor() { +//│ super(1); +//│ } +//│ }; +//│ this.#M = (() => new M()); +//│ this.#M.class = M; +//│ } +//│ return this.#M; +//│ } +//│ get N() { +//│ const outer1 = this; +//│ if (this.#N === undefined) { +//│ class N extends outer1.L(outer1.K.class) { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ super(x + 2); +//│ this.#x = x; +//│ } +//│ }; +//│ this.#N = ((x) => new N(x)); +//│ this.#N.class = N; +//│ } +//│ return this.#N; +//│ } +//│ } +//│ this.#J = new J(); +//│ this.#J.class = J; +//│ } +//│ return this.#J; +//│ } +//│ } +//│ const typing_unit14 = new TypingUnit14; +//│ globalThis.J = typing_unit14.J; +//│ // End of generated code + +:e +:js +let m = J.M() +let n = J.N(2) +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.823: let m = J.M() +//│ ╙── ^^ +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.824: let n = J.N(2) +//│ ╙── ^^ +//│ let m: error +//│ let n: error +//│ // Prelude +//│ class TypingUnit15 {} +//│ const typing_unit15 = new TypingUnit15; +//│ // Query 1 +//│ globalThis.m = J.M(); +//│ // Query 2 +//│ globalThis.n = J.N(2); +//│ // End of generated code +//│ m +//│ = M {} +//│ n +//│ = N {} + + +module K { + let x = 1 + module L { + let x = 42 + class M() { + fun f = x + } + } +} +//│ module K() { +//│ module L() { +//│ class M() { +//│ fun f: 42 +//│ } +//│ let x: 42 +//│ } +//│ let x: 1 +//│ } + +:e +let m = K.L.M() +m.f +//│ ╔══[ERROR] access to module member not yet supported +//│ ║ l.867: let m = K.L.M() +//│ ╙── ^^ +//│ let m: error +//│ error +//│ m +//│ = M {} +//│ res +//│ = 42 + +:e +module L { + class M(x: int) {} + module N { + module O { + class P(y: int) extends M(y + 1) {} + } + } +} +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.884: class P(y: int) extends M(y + 1) {} +//│ ╙── ^^^^^^^^ +//│ module L() { +//│ class M(x: int) +//│ module N() { +//│ module O() { +//│ class P(y: int) +//│ } +//│ } +//│ } + +:e +let op = L.N.O.P(0) +op.x +//│ ╔══[ERROR] access to module member not yet supported +//│ ║ l.901: let op = L.N.O.P(0) +//│ ╙── ^^ +//│ let op: error +//│ error +//│ op +//│ = P {} +//│ res +//│ = 1 + +:js +:e +module M { + module N { + fun op(x) = if x is + O then 0 + P then 1 + _ then 2 + } + class O() + class P() + fun op(x) = if x is + O then 0 + P then 1 + _ then 2 +} +M.N.op(M.P()) +//│ ╔══[ERROR] access to module member not yet supported +//│ ║ l.929: M.N.op(M.P()) +//│ ╙── ^^ +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.929: M.N.op(M.P()) +//│ ╙── ^^ +//│ module M() { +//│ module N() { +//│ fun op: anything -> (0 | 1 | 2) +//│ } +//│ class O() +//│ class P() +//│ fun op: anything -> (0 | 1 | 2) +//│ } +//│ error +//│ // Prelude +//│ class TypingUnit20 { +//│ #M; +//│ constructor() { +//│ } +//│ get M() { +//│ const outer = this; +//│ if (this.#M === undefined) { +//│ class M { +//│ #O; +//│ #P; +//│ #N; +//│ constructor() { +//│ } +//│ op(x) { +//│ let a; +//│ const self = this; +//│ return a = x, a instanceof self.O.class ? 0 : a instanceof self.P.class ? 1 : 2; +//│ } +//│ get N() { +//│ const outer1 = this; +//│ if (this.#N === undefined) { +//│ class N { +//│ constructor() { +//│ } +//│ op(x) { +//│ let a; +//│ return a = x, a instanceof outer1.O.class ? 0 : a instanceof outer1.P.class ? 1 : 2; +//│ } +//│ } +//│ this.#N = new N(); +//│ this.#N.class = N; +//│ } +//│ return this.#N; +//│ } +//│ get O() { +//│ const outer1 = this; +//│ if (this.#O === undefined) { +//│ class O {}; +//│ this.#O = (() => new O()); +//│ this.#O.class = O; +//│ } +//│ return this.#O; +//│ } +//│ get P() { +//│ const outer1 = this; +//│ if (this.#P === undefined) { +//│ class P {}; +//│ this.#P = (() => new P()); +//│ this.#P.class = P; +//│ } +//│ return this.#P; +//│ } +//│ } +//│ this.#M = new M(); +//│ this.#M.class = M; +//│ } +//│ return this.#M; +//│ } +//│ } +//│ const typing_unit20 = new TypingUnit20; +//│ globalThis.M = typing_unit20.M; +//│ // Query 1 +//│ res = M.N.op(M.P()); +//│ // End of generated code +//│ res +//│ = 1 + +:e +:js +module N { + module O { + class P() extends Q + } + class Q() +} +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.1017: class P() extends Q +//│ ╙── ^ +//│ module N() { +//│ module O() { +//│ class P() +//│ } +//│ class Q() +//│ } +//│ // Prelude +//│ class TypingUnit21 { +//│ #N; +//│ constructor() { +//│ } +//│ get N() { +//│ const outer = this; +//│ if (this.#N === undefined) { +//│ class N { +//│ #Q; +//│ #O; +//│ constructor() { +//│ } +//│ get O() { +//│ const outer1 = this; +//│ if (this.#O === undefined) { +//│ class O { +//│ #P; +//│ constructor() { +//│ } +//│ get P() { +//│ const outer2 = this; +//│ if (this.#P === undefined) { +//│ class P extends outer1.Q.class { +//│ constructor() { +//│ super(); +//│ } +//│ }; +//│ this.#P = (() => new P()); +//│ this.#P.class = P; +//│ } +//│ return this.#P; +//│ } +//│ } +//│ this.#O = new O(); +//│ this.#O.class = O; +//│ } +//│ return this.#O; +//│ } +//│ get Q() { +//│ const outer1 = this; +//│ if (this.#Q === undefined) { +//│ class Q {}; +//│ this.#Q = (() => new Q()); +//│ this.#Q.class = Q; +//│ } +//│ return this.#Q; +//│ } +//│ } +//│ this.#N = new N(); +//│ this.#N.class = N; +//│ } +//│ return this.#N; +//│ } +//│ } +//│ const typing_unit21 = new TypingUnit21; +//│ globalThis.N = typing_unit21.N; +//│ // End of generated code + +:e +N.O.P() +//│ ╔══[ERROR] access to module member not yet supported +//│ ║ l.1090: N.O.P() +//│ ╙── ^^ +//│ error +//│ res +//│ = P {} + +:js +:e +class I(x: int) { + let y = x + 1 + class J(z: int) { + let a = [x, y, z] + } +} +I(1).J(3).a +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.1106: I(1).J(3).a +//│ ╙── ^^ +//│ class I(x: int) { +//│ class J(z: int) { +//│ let a: (int, int, int,) +//│ } +//│ let y: int +//│ } +//│ error +//│ // Prelude +//│ class TypingUnit23 { +//│ #I; +//│ constructor() { +//│ } +//│ get I() { +//│ const outer = this; +//│ if (this.#I === undefined) { +//│ class I { +//│ #J; +//│ #x; +//│ #y; +//│ get x() { return this.#x; } +//│ get y() { return this.#y; } +//│ constructor(x) { +//│ this.#x = x; +//│ this.#y = x + 1; +//│ const y = this.#y; +//│ } +//│ get J() { +//│ const outer1 = this; +//│ if (this.#J === undefined) { +//│ class J { +//│ #z; +//│ #a; +//│ get z() { return this.#z; } +//│ get a() { return this.#a; } +//│ constructor(z) { +//│ this.#z = z; +//│ this.#a = [ +//│ outer1.x, +//│ outer1.y, +//│ z +//│ ]; +//│ const a = this.#a; +//│ } +//│ }; +//│ this.#J = ((z) => new J(z)); +//│ this.#J.class = J; +//│ } +//│ return this.#J; +//│ } +//│ }; +//│ this.#I = ((x) => new I(x)); +//│ this.#I.class = I; +//│ } +//│ return this.#I; +//│ } +//│ } +//│ const typing_unit23 = new TypingUnit23; +//│ globalThis.I = typing_unit23.I; +//│ // Query 1 +//│ res = I(1).J(3).a; +//│ // End of generated code +//│ res +//│ = [ 1, 2, 3 ] + + +:js +fun main = + fun f(x: int): int = if x is + 0 then 1 + else g(x - 1) + fun g(x: int): int = f(x) + f +//│ fun main: (x: int,) -> int +//│ // Prelude +//│ class TypingUnit24 {} +//│ const typing_unit24 = new TypingUnit24; +//│ // Query 1 +//│ globalThis.main = function main() { +//│ return ((() => { +//│ let f = (x) => x == 0 === true ? 1 : g(x - 1); +//│ let g = (x) => f(x); +//│ return f; +//│ })()); +//│ }; +//│ // End of generated code + +:js +fun mian = + class A(x: int) + mixin B() + module C + A(42) +//│ fun mian: A +//│ // Prelude +//│ class TypingUnit25 {} +//│ const typing_unit25 = new TypingUnit25; +//│ // Query 1 +//│ globalThis.mian = function mian() { +//│ return ((() => { +//│ const A = (() => { +//│ class A { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ } +//│ let ctor; +//│ ctor = ((x) => new A(x)); +//│ ctor.class = A; +//│ return ctor; +//│ })(); +//│ const B = (base) => { +//│ return (class B extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ }); +//│ }; +//│ const C = (() => { +//│ class C {} +//│ let ins; +//│ ins = new C(); +//│ ins.class = C; +//│ return ins; +//│ })(); +//│ return A(42); +//│ })()); +//│ }; +//│ // End of generated code + +:js +fun mian = + mixin B() + class A(x: int) extends B + module C extends B + [A, C] +//│ fun mian: ((x: int,) -> A, C,) +//│ // Prelude +//│ class TypingUnit26 {} +//│ const typing_unit26 = new TypingUnit26; +//│ // Query 1 +//│ globalThis.mian1 = function mian1() { +//│ return ((() => { +//│ const B = (base) => { +//│ return (class B extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ }); +//│ }; +//│ const A = (() => { +//│ class A extends B(Object) { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ super(); +//│ this.#x = x; +//│ } +//│ } +//│ let ctor; +//│ ctor = ((x) => new A(x)); +//│ ctor.class = A; +//│ return ctor; +//│ })(); +//│ const C = (() => { +//│ class C extends B(Object) { +//│ constructor() { +//│ super(); +//│ } +//│ } +//│ let ins; +//│ ins = new C(); +//│ ins.class = C; +//│ return ins; +//│ })(); +//│ return ([ +//│ A, +//│ C +//│ ]); +//│ })()); +//│ }; +//│ // End of generated code + +:js +fun main(arg) = + let x = arg + 1 + fun foo(y) = x + y + class C(u: int) { fun z = [foo(u), bar] } + fun bar = x + C(123) +//│ fun main: int -> C +//│ // Prelude +//│ class TypingUnit27 {} +//│ const typing_unit27 = new TypingUnit27; +//│ // Query 1 +//│ globalThis.main1 = function main1(arg) { +//│ return ((() => { +//│ let x = arg + 1; +//│ let foo = (y) => x + y; +//│ const C = (() => { +//│ class C { +//│ #u; +//│ get u() { return this.#u; } +//│ constructor(u) { +//│ this.#u = u; +//│ } +//│ get z() { +//│ const u = this.#u; +//│ return ([ +//│ foo(u), +//│ bar +//│ ]); +//│ } +//│ } +//│ let ctor; +//│ ctor = ((u) => new C(u)); +//│ ctor.class = C; +//│ return ctor; +//│ })(); +//│ let bar = x; +//│ return C(123); +//│ })()); +//│ }; +//│ // End of generated code + +module Test { + log(0) + module Foo { log(2) } + log(1) + Foo + log(3) + Foo +} +//│ module Test() { +//│ module Foo() +//│ } + +:js +class Outer1(outer: int) { + log(outer) + class Outer2(x: int) { + let outer = x + 1 + } +} +//│ class Outer1(outer: int) { +//│ class Outer2(x: int) { +//│ let outer: int +//│ } +//│ } +//│ // Prelude +//│ class TypingUnit29 { +//│ #Outer1; +//│ constructor() { +//│ } +//│ get Outer1() { +//│ const outer = this; +//│ if (this.#Outer1 === undefined) { +//│ class Outer1 { +//│ #Outer2; +//│ #outer; +//│ get outer() { return this.#outer; } +//│ constructor(outer1) { +//│ this.#outer = outer1; +//│ log(outer1); +//│ } +//│ get Outer2() { +//│ const outer1 = this; +//│ if (this.#Outer2 === undefined) { +//│ class Outer2 { +//│ #x; +//│ #outer; +//│ get x() { return this.#x; } +//│ get outer() { return this.#outer; } +//│ constructor(x) { +//│ this.#x = x; +//│ this.#outer = x + 1; +//│ const outer2 = this.#outer; +//│ } +//│ }; +//│ this.#Outer2 = ((x) => new Outer2(x)); +//│ this.#Outer2.class = Outer2; +//│ } +//│ return this.#Outer2; +//│ } +//│ }; +//│ this.#Outer1 = ((outer) => new Outer1(outer)); +//│ this.#Outer1.class = Outer1; +//│ } +//│ return this.#Outer1; +//│ } +//│ } +//│ const typing_unit29 = new TypingUnit29; +//│ globalThis.Outer1 = typing_unit29.Outer1; +//│ // End of generated code diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index 5e44dc5c22..20d8d4a061 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -9,11 +9,13 @@ class Test(n: int) { //│ } //│ // Prelude //│ let res; -//│ let typing_unit = { -//│ cache: {}, +//│ class TypingUnit { +//│ #Test; +//│ constructor() { +//│ } //│ get Test() { -//│ const cache = this.cache; -//│ if (this.cache.Test === undefined) { +//│ const outer = this; +//│ if (this.#Test === undefined) { //│ class Test { //│ #n; //│ get n() { return this.#n; } @@ -21,17 +23,17 @@ class Test(n: int) { //│ this.#n = n; //│ } //│ get inc() { -//│ const Test = cache.Test; //│ const n = this.#n; -//│ return Test(n + 1); +//│ return outer.Test(n + 1); //│ } //│ }; -//│ this.cache.Test = ((n) => new Test(n)); -//│ this.cache.Test["class"] = Test; +//│ this.#Test = ((n) => new Test(n)); +//│ this.#Test.class = Test; //│ } -//│ return this.cache.Test; +//│ return this.#Test; //│ } -//│ }; +//│ } +//│ const typing_unit = new TypingUnit; //│ globalThis.Test = typing_unit.Test; //│ // End of generated code @@ -71,7 +73,7 @@ class C[A](n: A) { let a = C[int](42) a.f //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.71: let a = C[int](42) +//│ ║ l.73: let a = C[int](42) //│ ╙── ^^^^^^ //│ let a: error //│ error @@ -81,7 +83,6 @@ a.f //│ = 42 -// FIXME module Foo { fun f = C0() class C0() @@ -90,8 +91,6 @@ module Foo { //│ class C0() //│ fun f: C0 //│ } -//│ Code generation encountered an error: -//│ unresolved symbol C0 mixin M0(n: int) { @@ -137,17 +136,20 @@ module M2 { bar(10) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.136: fun bar(x) = x + y + this.m +//│ ║ l.135: fun bar(x) = x + y + this.m //│ ╙── ^^ //│ module M2() { //│ fun foo: int -> int //│ let m: 100 //│ } //│ // Prelude -//│ let typing_unit11 = { -//│ cache: {}, +//│ class TypingUnit11 { +//│ #M2; +//│ constructor() { +//│ } //│ get M2() { -//│ if (this.cache.M2 === undefined) { +//│ const outer = this; +//│ if (this.#M2 === undefined) { //│ class M2 { //│ #m; //│ get m() { return this.#m; } @@ -163,12 +165,13 @@ module M2 { //│ })()); //│ } //│ } -//│ this.cache.M2 = new M2(); -//│ this.cache.M2["class"] = M2; +//│ this.#M2 = new M2(); +//│ this.#M2.class = M2; //│ } -//│ return this.cache.M2; +//│ return this.#M2; //│ } -//│ }; +//│ } +//│ const typing_unit11 = new TypingUnit11; //│ globalThis.M2 = typing_unit11.M2; //│ // End of generated code diff --git a/shared/src/test/diff/codegen/NuFuns.mls b/shared/src/test/diff/codegen/NuFuns.mls index d5e902adf7..5734ec7342 100644 --- a/shared/src/test/diff/codegen/NuFuns.mls +++ b/shared/src/test/diff/codegen/NuFuns.mls @@ -8,7 +8,8 @@ fun foo = //│ fun foo: int //│ // Prelude //│ let res; -//│ let typing_unit = { cache: {} }; +//│ class TypingUnit {} +//│ const typing_unit = new TypingUnit; //│ // Query 1 //│ globalThis.foo = function foo() { //│ return ((() => { @@ -18,13 +19,22 @@ fun foo = //│ }; //│ // End of generated code - -// TODO fun foo = class C(a: int) { fun bar(x) = a + x + 1 } C(100).bar(10) +foo //│ fun foo: int -//│ Code generation encountered an error: -//│ unsupported definitions in blocks - +//│ int +//│ res +//│ = [Function: foo1] +fun main = + mixin B { log(1) } + log(0) + module M extends B + log(2) +main +//│ fun main: unit +//│ unit +//│ res +//│ = [Function: main] diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 9bb7a0f841..5cac01cd98 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -12,9 +12,11 @@ mixin Foo0 { //│ } //│ // Prelude //│ let res; -//│ let typing_unit = { -//│ cache: {}, +//│ class TypingUnit { +//│ constructor() { +//│ } //│ Foo0(base) { +//│ const outer = this; //│ return (class Foo0 extends base { //│ #foo0; //│ get foo0() { return this.#foo0; } @@ -25,7 +27,8 @@ mixin Foo0 { //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit = new TypingUnit; //│ globalThis.Foo0 = typing_unit.Foo0; //│ // End of generated code @@ -40,9 +43,11 @@ mixin Foo1 { //│ let foo1: 'foo0 //│ } //│ // Prelude -//│ let typing_unit1 = { -//│ cache: {}, +//│ class TypingUnit1 { +//│ constructor() { +//│ } //│ Foo1(base) { +//│ const outer = this; //│ return (class Foo1 extends base { //│ #foo0; //│ #foo1; @@ -57,7 +62,8 @@ mixin Foo1 { //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit1 = new TypingUnit1; //│ globalThis.Foo1 = typing_unit1.Foo1; //│ // End of generated code @@ -80,16 +86,18 @@ mixin Foo2 { fun foo2 = super } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.80: fun foo2 = super +//│ ║ l.86: fun foo2 = super //│ ╙── ^^^^^ //│ mixin Foo2() { //│ super: 'super //│ fun foo2: 'super //│ } //│ // Prelude -//│ let typing_unit4 = { -//│ cache: {}, +//│ class TypingUnit4 { +//│ constructor() { +//│ } //│ Foo2(base) { +//│ const outer = this; //│ return (class Foo2 extends base { //│ constructor(...rest) { //│ super(...rest); @@ -99,7 +107,8 @@ mixin Foo2 { //│ } //│ }); //│ } -//│ }; +//│ } +//│ const typing_unit4 = new TypingUnit4; //│ globalThis.Foo2 = typing_unit4.Foo2; //│ // End of generated code //│ Syntax error: @@ -112,21 +121,25 @@ module Test0 extends Foo2 //│ fun foo2: anything //│ } //│ // Prelude -//│ let typing_unit5 = { -//│ cache: {}, +//│ class TypingUnit5 { +//│ #Test0; +//│ constructor() { +//│ } //│ get Test0() { -//│ if (this.cache.Test0 === undefined) { +//│ const outer = this; +//│ if (this.#Test0 === undefined) { //│ class Test0 extends Foo2(Object) { //│ constructor() { //│ super(); //│ } //│ } -//│ this.cache.Test0 = new Test0(); -//│ this.cache.Test0["class"] = Test0; +//│ this.#Test0 = new Test0(); +//│ this.#Test0.class = Test0; //│ } -//│ return this.cache.Test0; +//│ return this.#Test0; //│ } -//│ }; +//│ } +//│ const typing_unit5 = new TypingUnit5; //│ globalThis.Test0 = typing_unit5.Test0; //│ // End of generated code //│ Runtime error: diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 2134a738bc..dfd98e1495 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -45,8 +45,7 @@ Lit(0).test //│ ╙── ^^^^^ //│ error //│ res -//│ Runtime error: -//│ ReferenceError: a is not defined +//│ = 0 fun f(p: Pair['a, 'b]) = p.lhs @@ -63,7 +62,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.64: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.63: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -76,10 +75,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.76: fun f(x: a) = x +//│ ║ l.75: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.77: f(l) +//│ ║ l.76: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 290c2983a3..9bc30a330b 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -213,8 +213,6 @@ class Annots(base: 0 | 1) { //│ class Annots(base: 0 | 1) { //│ fun a: 0 | 1 //│ } -//│ Code generation encountered an error: -//│ unexpected new class member a diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index 4a14085d05..da3ec4fb28 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -6,7 +6,8 @@ fun f(x) = x > 0 && f(x - 1) //│ fun f: int -> bool //│ // Prelude //│ let res; -//│ let typing_unit = { cache: {} }; +//│ class TypingUnit {} +//│ const typing_unit = new TypingUnit; //│ // Query 1 //│ globalThis.f = function f(x) { //│ return x > 0 && f(x - 1); @@ -22,7 +23,8 @@ f(12) let rec f(x) = x > 0 && f(x - 1) //│ let rec f: int -> bool //│ // Prelude -//│ let typing_unit2 = { cache: {} }; +//│ class TypingUnit2 {} +//│ const typing_unit2 = new TypingUnit2; //│ // Query 1 //│ globalThis.f1 = function f1(x) { //│ return x > 0 && f1(x - 1); @@ -41,7 +43,8 @@ let rec f() = f() //│ let rec f: () -> nothing //│ // Prelude -//│ let typing_unit4 = { cache: {} }; +//│ class TypingUnit4 {} +//│ const typing_unit4 = new TypingUnit4; //│ // Query 1 //│ globalThis.f2 = function f2() { //│ return ((() => { @@ -73,7 +76,8 @@ let rec f = f //│ nothing //│ // Prelude -//│ let typing_unit7 = { cache: {} }; +//│ class TypingUnit7 {} +//│ const typing_unit7 = new TypingUnit7; //│ // Query 1 //│ res = f3; //│ // End of generated code diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index 0b013ee43e..0c7a75bde0 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -20,7 +20,7 @@ c.NC0 //│ ╙── ^^^^ //│ error //│ res -//│ = undefined +//│ = [Function (anonymous)] { class: [class NC0] } module M0 { @@ -37,7 +37,7 @@ M0.NC0 //│ ╙── ^^^^ //│ error //│ res -//│ = undefined +//│ = [Function (anonymous)] { class: [class NC0] } module M1 { @@ -54,5 +54,5 @@ M1.NM1 //│ ╙── ^^^^ //│ error //│ res -//│ = undefined +//│ = NM1 { class: [class NM1] } diff --git a/shared/src/test/diff/nu/TypeSelections.mls b/shared/src/test/diff/nu/TypeSelections.mls index 7a007c27f5..2c29e565b8 100644 --- a/shared/src/test/diff/nu/TypeSelections.mls +++ b/shared/src/test/diff/nu/TypeSelections.mls @@ -1,7 +1,6 @@ :NewDefs -:ge // TODO module M { type T = int -> int class C(n: int) @@ -12,8 +11,6 @@ module M { //│ type T = int -> int //│ fun mkC: (n: int,) -> C //│ } -//│ Code generation encountered an error: -//│ unresolved symbol C let x: M.T = id //│ let x: int -> int @@ -23,18 +20,17 @@ let x: M.T = id fun foo(x: M.C) = x //│ fun foo: (x: C,) -> C -:re // TODO + foo(M.mkC(42)) //│ C //│ res -//│ Runtime error: -//│ ReferenceError: M is not defined +//│ = C {} :e 42 : M.mkC //│ ╔══[ERROR] Illegal selection of value member in type position -//│ ║ l.35: 42 : M.mkC +//│ ║ l.31: 42 : M.mkC //│ ╙── ^^^^ //│ error //│ res From a35790e61f9eebd6a2f5674c65255c0d6029bc42 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 11 Apr 2023 11:08:26 +0800 Subject: [PATCH 233/498] WIP Basic trait implementation placeholders --- .../src/main/scala/mlscript/NuTypeDefs.scala | 84 ++++++++++++++++--- shared/src/test/diff/nu/Interfaces.mls | 71 ++++++++++++++++ 2 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 shared/src/test/diff/nu/Interfaces.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 88eaf4bff1..662eb9b771 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -160,6 +160,40 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } + case class TypedNuTrt( + level: Level, td: NuTypeDef, ttu: TypedTypingUnit, + tparams: TyParams, + members: Map[Str, NuMember], + thisTy: ST, + sign: Opt[ST], + ) extends TypedNuTypeDef(Trt) with TypedNuTermDef + { + def decl: NuTypeDef = td + def kind: DeclKind = td.kind + def nme: TypeName = td.nme + def name: Str = nme.name + + def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil) + + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTrt = + TypedNuTrt(level, td, ttu, + tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), + members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, + f(pol.map(!_), thisTy), + sign.map(f(pol, _)) + ) + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTrt = + TypedNuTrt(level, td, ttu, + tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), + members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, + f(pol.contravar, thisTy), + sign.map(f(pol, _)) + ) + } + + case class TypedNuCls( level: Level, td: NuTypeDef, ttu: TypedTypingUnit, tparams: TyParams, params: Ls[Var -> FieldType], @@ -659,20 +693,22 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) - def inherit(parents: Ls[Term], superType: ST, members: Ls[NuMember]) + type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) + val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { + case v @ Var(nme) => + S(v, v, Nil) + case p @ App(v @ Var(nme), Tup(args)) => + S(p, v, args) + case p => + err(msg"Unsupported parent specification", p.toLoc) // TODO + N + } + + def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) : (ST, Ls[NuMember]) = parents match { - case p :: ps => + case (p, v @ Var(mxnNme), mxnArgs) :: ps => val newMembs = trace(s"${lvl}. Inheriting from $p") { - val (v @ Var(mxnNme), mxnArgs) = p match { - case v @ Var(nme) => - v -> Nil - case App(v @ Var(nme), Tup(args)) => - v -> args - case _ => - err(msg"Unsupported parent specification", p.toLoc) // TODO - return inherit(ps, superType, members) - } ctx.get(mxnNme) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { @@ -757,7 +793,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) val (thisType, baseMems) = - inherit(td.parents, baseType, tparamMems ++ paramMems) + inherit(parentSpecs, baseType, tparamMems ++ paramMems) ctx += "super" -> VarSymbol(thisType, Var("super")) @@ -770,6 +806,30 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val impltdMems = baseMems ++ clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers + + def computeInterface(parents: Ls[ParentSpec], annot: ST, members: Ls[NuMember]): (ST, Ls[NuMember]) = + parents match { + case (p, v @ Var(parNme), parArgs) :: ps => + // TODO find traits in `parents`; intersect their member types and self types + ctx.get(parNme) match { + case S(lti: LazyTypeInfo) => + val info = lti.complete() + // TODO substitute type parameters in info + info match { + case cls: TypedNuTrt => + ??? + case _ => computeInterface(ps, annot, members) + } + case N => + // err(msg"Could not find definition `${parNme}`", p.toLoc) + computeInterface(ps, annot, members) + } + case Nil => (annot, members) + } + val (ifaceAnnot, ifaceMembers) = computeInterface(parentSpecs, TopType, Nil) + // TODO check mems against interface stuff above + + TypedNuCls(outerCtx.lvl, td, ttu, tparams, typedParams, mems, // if (td.kind is Nms) TopType else thisTV diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls new file mode 100644 index 0000000000..57d42bcd1f --- /dev/null +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -0,0 +1,71 @@ +:NewDefs + + +// FIXME +trait Test[A] { fun foo: A } +//│ ╔══[ERROR] traits are not yet supported +//│ ║ l.5: trait Test[A] { fun foo: A } +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + +// FIXME +class C extends Test[int] +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.13: class C extends Test[int] +//│ ╙── ^^^^^^^^^ +//│ class C() +//│ Code generation encountered an error: +//│ unresolved symbol Test + + +// TODO +:e +class D extends Test[int], Test[bool] +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.24: class D extends Test[int], Test[bool] +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Unsupported parent specification +//│ ║ l.24: class D extends Test[int], Test[bool] +//│ ╙── ^^^^^^^^^^ +//│ class D() +//│ Code generation encountered an error: +//│ unresolved symbol Test + + +// FIXME +trait Base: A | B +class A +class B +//│ ╔══[ERROR] traits are not yet supported +//│ ║ l.37: trait Base: A | B +//│ ╙── ^^^^^^^^^^ +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + +// FIXME +let b: Base = A() +//│ ╔══[ERROR] trait Base cannot be used as a type +//│ ║ l.47: let b: Base = A() +//│ ╙── ^^^^ +//│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: Trt + +// FIXME +b: Base & (A | B) +//│ ╔══[ERROR] trait Base cannot be used as a type +//│ ║ l.47: let b: Base = A() +//│ ╙── ^^^^ +//│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: Trt + + +// FIXME +trait Base: Foo | Bar +class Foo[A] +class Bar[B] +//│ ╔══[ERROR] traits are not yet supported +//│ ║ l.62: trait Base: Foo | Bar +//│ ╙── ^^^^^^^^^^ +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + + From 57c57f6034cdc48b5a3078d410c226b515d52779 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Tue, 11 Apr 2023 18:44:30 +0800 Subject: [PATCH 234/498] rough sketch of trait --- .../src/main/scala/mlscript/NuTypeDefs.scala | 80 +++++++++- shared/src/main/scala/mlscript/TypeDefs.scala | 2 +- .../main/scala/mlscript/TypeSimplifier.scala | 1 + shared/src/main/scala/mlscript/Typer.scala | 10 ++ .../main/scala/mlscript/TyperHelpers.scala | 9 ++ shared/src/test/diff/nu/Interfaces.mls | 142 +++++++++++++----- 6 files changed, 200 insertions(+), 44 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 662eb9b771..4d9d9d53af 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -127,6 +127,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuAls(level, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), body.freshenAbove(lim, rigidify)) + case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign) => + TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, + thisTy.freshenAbove(lim, rigidify), + sign.map(_.freshenAbove(lim, rigidify)) // todo + ) } val td: NuTypeDef val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) @@ -641,8 +648,48 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (res, funMembers) = td.kind match { case Trt => - err(msg"traits are not yet supported" -> td.toLoc :: Nil) - ??? + ctx.nest.nextLevel { implicit ctx => + + type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) + val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { + case v @ Var(nme) => + S(v, v, Nil) + case p @ App(v @ Var(nme), Tup(args)) => + S(p, v, args) + case p => + err(msg"Unsupported parent specification", p.toLoc) // TODO + N + } + + ctx ++= paramSymbols + ctx += "this" -> VarSymbol(thisTV, Var("this")) + + def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) + : (ST, Ls[NuMember]) = + parents match { + case (p, v @ Var(trtName), mxnArgs) :: ps => + ctx.get(trtName) match { + case S(lti: LazyTypeInfo) => lti.complete().freshen match { + case trt: TypedNuTrt => + inherit(ps, superType & trt.thisTy, members ++ trt.members.values) + case _ => + err(msg"trait can only inherit traits", p.toLoc) + (superType, members) + } + case _ => (superType, members) + } + case Nil => (superType, members) + } + + val (thisType, baseMems) = + inherit(parentSpecs, TopType, Nil) + + val ttu = typeTypingUnit(td.body, topLevel = false) + val trtMems = baseMems // ? what is ttu ++ ttu.entities + val mems = typedSignatureMembers.toMap // ? ++ trtMems.map(d => d.name -> d).toMap + + TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, TopType, None) -> Nil + } case Als => @@ -739,6 +786,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val bodyMems = mxn.ttu.entities paramMems ++ bodyMems + + case trt: TypedNuTrt => + Nil case cls: TypedNuCls => err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO @@ -816,10 +866,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val info = lti.complete() // TODO substitute type parameters in info info match { - case cls: TypedNuTrt => - ??? + case trt: TypedNuTrt => + computeInterface(ps, annot & trt.thisTy, members ++ trt.members.values) // intersect members case _ => computeInterface(ps, annot, members) } + case S(_) => + err("i don't know", p.toLoc) + computeInterface(ps, annot, members) case N => // err(msg"Could not find definition `${parNme}`", p.toLoc) computeInterface(ps, annot, members) @@ -828,12 +881,23 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val (ifaceAnnot, ifaceMembers) = computeInterface(parentSpecs, TopType, Nil) // TODO check mems against interface stuff above - + + ifaceMembers.foreach { m => + impltdMems.find(x => x.name == m.name) match { + case S(mem: TypedNuTermDef) => + val memSign = mem.typeSignature + implicit val prov: TP = memSign.prov + constrain(memSign, m.asInstanceOf[TypedNuFun].typeSignature) + case S(_) => () + case N => + err(msg"Member ${m.name} is declared in parent trait but not implemented", td.toLoc) + } + } TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems, + tparams, typedParams, mems ++ ifaceMembers.map(d => d.name -> d).toMap, // if (td.kind is Nms) TopType else thisTV - TopType + ifaceAnnot // ? TopType ? not sure )(thisType) -> impltdMems } case Mxn => @@ -870,7 +934,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(mem: NuParam) => case S(_) => ??? // TODO case N => - if (!td.isDecl) + if (!td.isDecl && td.kind != Trt) err(msg"Member ${fd.nme.name} is declared but not defined", fd.nme.toLoc) } } diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 66d0975a2e..e77e5a1750 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -111,7 +111,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => Var(clsNme.name + "#" + tparamNme.name) def clsNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { - require((td.kind is Cls) || (td.kind is Nms), td.kind) + require((td.kind is Cls) || (td.kind is Nms) || (td.kind is Trt), td.kind) ClassTag(Var(td.nme.name), // ctx.allBaseClassesOf(td.nme.name) Set.single(TypeName("Eql")) // TODO superclasses diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 68a61898fd..2bea1c5fe7 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -4,6 +4,7 @@ import scala.collection.mutable.{Map => MutMap, Set => MutSet, LinkedHashMap, Li import scala.collection.immutable.{SortedMap, SortedSet} import scala.util.chaining._ import mlscript.utils._, shorthands._ +import scala.util.Try trait TypeSimplifier { self: Typer => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 027ac7b42b..fea5b60bd7 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1332,6 +1332,16 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign) => + ectx(tparams) |> { implicit ectx => + NuTypeDef(td.kind, td.nme, td.tparams, + Tup(Nil), + N,//TODO + Nil,//TODO + N,//TODO + Option.when(!(TopType <:< thisTy))(go(thisTy)), + mkTypingUnit(thisTy, members))(td.declareLoc) + } case tf @ TypedNuFun(level, fd, bodyTy) => NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc) case p: NuParam => diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 68f8dc34f1..74049a2cbb 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -790,6 +790,10 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.instanceType) + case cls: TypedNuTrt => + cls.tparams.iterator.map(pol.invar -> _._2) ++ + cls.members.valuesIterator.flatMap(childrenPolMem) ++ + S(pol.contravar -> cls.thisTy) } ents ::: tu.result.toList.map(pol -> _) }} @@ -1155,6 +1159,11 @@ abstract class TyperHelpers { Typer: Typer => members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign) => + tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) + members.valuesIterator.foreach(applyMem(pol)) + // thisTy.foreach(apply(pol.invar)(_)) + apply(pol.contravar)(thisTy) case TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 57d42bcd1f..62a45a550c 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -1,71 +1,143 @@ :NewDefs - +:NoJS + +trait Test { + fun foo: int + fun bar: bool -> bool +} +//│ trait Test() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } + +trait Oth extends Test { + fun cool : int -> bool +} +//│ trait Oth() { +//│ fun cool: int -> bool +//│ } + + +class C extends Test { + fun foo = 1 + fun bar(x) = x +} +//│ class C() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } + +class F extends Oth { + fun cool(x) = x == 1 + fun foo = 2 + fun bar(x) = x +} +//│ class F() { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun cool: int -> bool +//│ fun foo: 2 +//│ } + +let c = C() +c.foo +c.bar(true) +//│ let c: C +//│ bool // FIXME -trait Test[A] { fun foo: A } -//│ ╔══[ERROR] traits are not yet supported -//│ ║ l.5: trait Test[A] { fun foo: A } -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing - +c: Test +//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @1a8f3d9d) -// FIXME -class C extends Test[int] -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.13: class C extends Test[int] -//│ ╙── ^^^^^^^^^ -//│ class C() -//│ Code generation encountered an error: -//│ unresolved symbol Test +:e +class E1 extends Test { + fun foo = 2 +} +trait TE1 extends C +//│ ╔══[ERROR] Member bar is declared in parent trait but not implemented +//│ ║ l.52: class E1 extends Test { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.53: fun foo = 2 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.54: } +//│ ╙── ^ +//│ ╔══[ERROR] trait can only inherit traits +//│ ║ l.55: trait TE1 extends C +//│ ╙── ^ +//│ class E1() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } +//│ trait TE1() +:e +class E2 extends Test { + fun foo = true + fun bar(x) = x +} +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.74: fun foo = true +//│ ║ ^^^^^^^^^^ +//│ ╟── reference of type `true` is not an instance of type `int` +//│ ║ l.74: fun foo = true +//│ ║ ^^^^ +//│ ╟── but it flows into definition of method foo with expected type `int` +//│ ║ l.74: fun foo = true +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.5: fun foo: int +//│ ║ ^^^ +//│ ╟── from signature of member foo: +//│ ║ l.5: fun foo: int +//│ ╙── ^^^^^^^^ +//│ class E2() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } // TODO :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.24: class D extends Test[int], Test[bool] +//│ ║ l.99: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.24: class D extends Test[int], Test[bool] +//│ ║ l.99: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() -//│ Code generation encountered an error: -//│ unresolved symbol Test // FIXME trait Base: A | B class A class B -//│ ╔══[ERROR] traits are not yet supported -//│ ║ l.37: trait Base: A | B -//│ ╙── ^^^^^^^^^^ -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ trait Base() +//│ class A() +//│ class B() // FIXME let b: Base = A() -//│ ╔══[ERROR] trait Base cannot be used as a type -//│ ║ l.47: let b: Base = A() -//│ ╙── ^^^^ -//│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: Trt +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.119: let b: Base = A() +//│ ║ ^^^ +//│ ╟── application of type `A` is not an instance of type `Base` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.119: let b: Base = A() +//│ ╙── ^^^^ +//│ let b: Base // FIXME b: Base & (A | B) -//│ ╔══[ERROR] trait Base cannot be used as a type -//│ ║ l.47: let b: Base = A() -//│ ╙── ^^^^ -//│ /!!!\ Uncaught error: java.lang.IllegalArgumentException: requirement failed: Trt +//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @1a8f3d9d) // FIXME trait Base: Foo | Bar class Foo[A] class Bar[B] -//│ ╔══[ERROR] traits are not yet supported -//│ ║ l.62: trait Base: Foo | Bar -//│ ╙── ^^^^^^^^^^ -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ trait Base() +//│ class Foo[A]() +//│ class Bar[B]() From 6e369a63cb175b21b126bc5d9aadecaf29eb9761 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Tue, 11 Apr 2023 18:53:24 +0800 Subject: [PATCH 235/498] fix --- .../src/main/scala/mlscript/NuTypeDefs.scala | 8 ++- shared/src/test/diff/nu/Interfaces.mls | 55 +++++++++++-------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 4d9d9d53af..38b6216ac3 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -658,12 +658,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => S(p, v, args) case p => err(msg"Unsupported parent specification", p.toLoc) // TODO + // support type application N } ctx ++= paramSymbols ctx += "this" -> VarSymbol(thisTV, Var("this")) + // inherit traits def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) : (ST, Ls[NuMember]) = parents match { @@ -685,10 +687,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inherit(parentSpecs, TopType, Nil) val ttu = typeTypingUnit(td.body, topLevel = false) - val trtMems = baseMems // ? what is ttu ++ ttu.entities - val mems = typedSignatureMembers.toMap // ? ++ trtMems.map(d => d.name -> d).toMap + val trtMems = baseMems // ? [what is ttu] ++ ttu.entities + val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap - TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, TopType, None) -> Nil + TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None) -> Nil } case Als => diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 62a45a550c..c18573a4d7 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -14,7 +14,9 @@ trait Oth extends Test { fun cool : int -> bool } //│ trait Oth() { +//│ fun bar: bool -> bool //│ fun cool: int -> bool +//│ fun foo: int //│ } @@ -33,9 +35,9 @@ class F extends Oth { fun bar(x) = x } //│ class F() { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: bool -> bool //│ fun cool: int -> bool -//│ fun foo: 2 +//│ fun foo: int //│ } let c = C() @@ -45,28 +47,37 @@ c.bar(true) //│ bool // FIXME -c: Test -//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @1a8f3d9d) +let c1: Test = C() +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.50: let c1: Test = C() +//│ ║ ^^^ +//│ ╟── application of type `C` is not an instance of type `Test` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.50: let c1: Test = C() +//│ ╙── ^^^^ +//│ let c1: Test :e class E1 extends Test { fun foo = 2 } -trait TE1 extends C //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.52: class E1 extends Test { +//│ ║ l.61: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.53: fun foo = 2 +//│ ║ l.62: fun foo = 2 //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.54: } +//│ ║ l.63: } //│ ╙── ^ -//│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.55: trait TE1 extends C -//│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool //│ fun foo: int //│ } + +:e +trait TE1 extends C +//│ ╔══[ERROR] trait can only inherit traits +//│ ║ l.77: trait TE1 extends C +//│ ╙── ^ //│ trait TE1() :e @@ -75,13 +86,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.74: fun foo = true +//│ ║ l.85: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.74: fun foo = true +//│ ║ l.85: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.74: fun foo = true +//│ ║ l.85: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -98,15 +109,15 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.99: class D extends Test[int], Test[bool] -//│ ╙── ^^^^^^^^^ +//│ ║ l.110: class D extends Test[int], Test[bool] +//│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.99: class D extends Test[int], Test[bool] -//│ ╙── ^^^^^^^^^^ +//│ ║ l.110: class D extends Test[int], Test[bool] +//│ ╙── ^^^^^^^^^^ //│ class D() -// FIXME + trait Base: A | B class A class B @@ -118,17 +129,17 @@ class B // FIXME let b: Base = A() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.119: let b: Base = A() +//│ ║ l.130: let b: Base = A() //│ ║ ^^^ //│ ╟── application of type `A` is not an instance of type `Base` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.119: let b: Base = A() +//│ ║ l.130: let b: Base = A() //│ ╙── ^^^^ //│ let b: Base // FIXME b: Base & (A | B) -//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @1a8f3d9d) +//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @6d580313) // FIXME From dc62381d491eeaa07d5ba60ffe94146f160651d2 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 12 Apr 2023 20:22:03 +0800 Subject: [PATCH 236/498] sketch of intersecton of members --- .../src/main/scala/mlscript/NuTypeDefs.scala | 34 +++- shared/src/test/diff/nu/Interfaces.mls | 147 ++++++++++++++---- 2 files changed, 148 insertions(+), 33 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 38b6216ac3..3a5db20ace 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -367,6 +367,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )(provTODO) )(provTODO) ) + case Trt => + TraitTag(Var(td.nme.name))(provTODO) // case k => err case k => errType // FIXME } @@ -673,7 +675,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.get(trtName) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { case trt: TypedNuTrt => - inherit(ps, superType & trt.thisTy, members ++ trt.members.values) + // TODO check intersection of members + inherit(ps, superType & trt.thisTy, memberUn(members, trt.members.values.toList)) case _ => err(msg"trait can only inherit traits", p.toLoc) (superType, members) @@ -687,7 +690,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inherit(parentSpecs, TopType, Nil) val ttu = typeTypingUnit(td.body, topLevel = false) - val trtMems = baseMems // ? [what is ttu] ++ ttu.entities + val trtMems = baseMems ++ ttu.entities val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None) -> Nil @@ -858,7 +861,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val impltdMems = baseMems ++ clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers - def computeInterface(parents: Ls[ParentSpec], annot: ST, members: Ls[NuMember]): (ST, Ls[NuMember]) = parents match { case (p, v @ Var(parNme), parArgs) :: ps => @@ -869,7 +871,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO substitute type parameters in info info match { case trt: TypedNuTrt => - computeInterface(ps, annot & trt.thisTy, members ++ trt.members.values) // intersect members + // TODO also computer intersect + computeInterface(ps, annot & trt.thisTy, memberUn(members, trt.members.values.toList)) // intersect members case _ => computeInterface(ps, annot, members) } case S(_) => @@ -889,7 +892,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature implicit val prov: TP = memSign.prov - constrain(memSign, m.asInstanceOf[TypedNuFun].typeSignature) + constrain(memSign, m.asInstanceOf[TypedNuTermDef].typeSignature) case S(_) => () case N => err(msg"Member ${m.name} is declared in parent trait but not implemented", td.toLoc) @@ -972,7 +975,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - + def memberUn(l: Ls[NuMember], r: Ls[NuMember])(implicit raise: Raise): Ls[NuMember] = { + val nms = Set.from(l.map(_.name) ++ r.map(_.name)).toList + nms.map {n => + (l.find(x => x.name == n), r.find(x => x.name == n)) match { + case(S(a: TypedNuFun), S(b: TypedNuFun)) + if a.level == b.level + && a.fd.isLetRec == b.fd.isLetRec + && a.fd.nme == b.fd.nme + && a.fd.tparams == b.fd.tparams + // todo: check fd.rhs + => + TypedNuFun(a.level, a.fd, a.bodyType & b.bodyType) + case(S(a), N) => a + case(N, S(b)) => b + case _ => + err(msg"invalid $n", N) + ??? + } + } + } } diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index c18573a4d7..dbccd5ed2e 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -1,7 +1,7 @@ :NewDefs :NoJS -trait Test { +trait Test { fun foo: int fun bar: bool -> bool } @@ -11,14 +11,44 @@ trait Test { //│ } trait Oth extends Test { + let a : int fun cool : int -> bool } //│ trait Oth() { +//│ let a: int //│ fun bar: bool -> bool //│ fun cool: int -> bool //│ fun foo: int //│ } +trait Geo { + let v: 2 | 3 + fun get: int | bool + fun ter: int +} +trait Anemo { + let v: 1 | 2 + fun get: bool | string + fun ter: bool +} +//│ trait Geo() { +//│ fun get: bool | int +//│ fun ter: int +//│ let v: 2 | 3 +//│ } +//│ trait Anemo() { +//│ fun get: bool | string +//│ fun ter: bool +//│ let v: 1 | 2 +//│ } + +trait Mixed extends Geo, Anemo +//│ trait Mixed() { +//│ fun get: bool +//│ fun ter: nothing +//│ let v: 2 +//│ } + class C extends Test { fun foo = 1 @@ -29,15 +59,31 @@ class C extends Test { //│ fun foo: int //│ } -class F extends Oth { +mixin M { + fun m1 = 3 +} +//│ mixin M() { +//│ fun m1: 3 +//│ } + +class F extends Oth, M, Mixed { fun cool(x) = x == 1 fun foo = 2 fun bar(x) = x + fun get = true + fun ter = ter + let a = 3 + let v = 2 } //│ class F() { +//│ let a: int //│ fun bar: bool -> bool //│ fun cool: int -> bool //│ fun foo: int +//│ fun get: bool +//│ fun m1: 3 +//│ fun ter: nothing +//│ let v: 2 //│ } let c = C() @@ -46,28 +92,64 @@ c.bar(true) //│ let c: C //│ bool +// FIXME +c: Test +//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @3bf50bf8) + // FIXME let c1: Test = C() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.50: let c1: Test = C() -//│ ║ ^^^ +//│ ║ l.100: let c1: Test = C() +//│ ║ ^^^ //│ ╟── application of type `C` is not an instance of type `Test` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.50: let c1: Test = C() -//│ ╙── ^^^^ +//│ ║ l.100: let c1: Test = C() +//│ ╙── ^^^^ //│ let c1: Test +trait A1 { fun a1: 1 | 2 | 3} +trait A2 { fun a1: 2 | 3 | 4} +//│ trait A1() { +//│ fun a1: 1 | 2 | 3 +//│ } +//│ trait A2() { +//│ fun a1: 2 | 3 | 4 +//│ } + +:e +class Ea1 extends A1, A2 { + fun a1 = 4 +} +//│ ╔══[ERROR] Type mismatch in definition of method a1: +//│ ║ l.121: fun a1 = 4 +//│ ║ ^^^^^^ +//│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` +//│ ║ l.121: fun a1 = 4 +//│ ║ ^ +//│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` +//│ ║ l.121: fun a1 = 4 +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.110: trait A1 { fun a1: 1 | 2 | 3} +//│ ║ ^^^^^^^^^ +//│ ╟── from signature of member a1: +//│ ║ l.110: trait A1 { fun a1: 1 | 2 | 3} +//│ ╙── ^^^^^^^^^^^^^ +//│ class Ea1() { +//│ fun a1: 2 | 3 +//│ } + :e class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.61: class E1 extends Test { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.62: fun foo = 2 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.63: } -//│ ╙── ^ +//│ ║ l.143: class E1 extends Test { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.144: fun foo = 2 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.145: } +//│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool //│ fun foo: int @@ -75,10 +157,15 @@ class E1 extends Test { :e trait TE1 extends C +trait TE2 extends M, Test +//│ ╔══[ERROR] trait can only inherit traits +//│ ║ l.159: trait TE1 extends C +//│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.77: trait TE1 extends C -//│ ╙── ^ +//│ ║ l.160: trait TE2 extends M, Test +//│ ╙── ^ //│ trait TE1() +//│ trait TE2() :e class E2 extends Test { @@ -86,14 +173,14 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.85: fun foo = true -//│ ║ ^^^^^^^^^^ +//│ ║ l.172: fun foo = true +//│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.85: fun foo = true -//│ ║ ^^^^ +//│ ║ l.172: fun foo = true +//│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.85: fun foo = true -//│ ║ ^^^^^^^^^^ +//│ ║ l.172: fun foo = true +//│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int //│ ║ ^^^ @@ -109,10 +196,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.110: class D extends Test[int], Test[bool] +//│ ║ l.197: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.110: class D extends Test[int], Test[bool] +//│ ║ l.197: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -129,17 +216,17 @@ class B // FIXME let b: Base = A() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.130: let b: Base = A() +//│ ║ l.217: let b: Base = A() //│ ║ ^^^ //│ ╟── application of type `A` is not an instance of type `Base` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.130: let b: Base = A() +//│ ║ l.217: let b: Base = A() //│ ╙── ^^^^ //│ let b: Base // FIXME b: Base & (A | B) -//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @6d580313) +//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @3bf50bf8) // FIXME @@ -150,5 +237,11 @@ class Bar[B] //│ class Foo[A]() //│ class Bar[B]() - - +// FIXME +fun mt(x) = if x is Test then 1 else 0 +//│ ╔══[ERROR] Cannot find constructor `Test` in scope +//│ ║ l.241: fun mt(x) = if x is Test then 1 else 0 +//│ ╙── ^^^^ +//│ fun mt: anything -> error + //│ ╙── ^^^^ +//│ From 32b43d2b7d77fbba3451ae6d64b780244090ba29 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 14 Apr 2023 00:26:45 +0800 Subject: [PATCH 237/498] ? exploit `thisTy` --- .../src/main/scala/mlscript/NuTypeDefs.scala | 9 +- shared/src/main/scala/mlscript/TypeDefs.scala | 4 + .../main/scala/mlscript/TyperHelpers.scala | 26 +++ shared/src/test/diff/nu/Interfaces.mls | 154 ++++++++++++++---- 4 files changed, 161 insertions(+), 32 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 3a5db20ace..f107724e05 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -675,7 +675,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.get(trtName) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { case trt: TypedNuTrt => - // TODO check intersection of members inherit(ps, superType & trt.thisTy, memberUn(members, trt.members.values.toList)) case _ => err(msg"trait can only inherit traits", p.toLoc) @@ -687,7 +686,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val (thisType, baseMems) = - inherit(parentSpecs, TopType, Nil) + // ? is it really a good idea + inherit(parentSpecs, trtNameToNomTag(td)(noProv, ctx), Nil) val ttu = typeTypingUnit(td.body, topLevel = false) val trtMems = baseMems ++ ttu.entities @@ -884,7 +884,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case Nil => (annot, members) } - val (ifaceAnnot, ifaceMembers) = computeInterface(parentSpecs, TopType, Nil) + val (ifaceAnnot, ifaceMembers) = computeInterface(parentSpecs, thisType, Nil) // TODO check mems against interface stuff above ifaceMembers.foreach { m => @@ -902,7 +902,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuCls(outerCtx.lvl, td, ttu, tparams, typedParams, mems ++ ifaceMembers.map(d => d.name -> d).toMap, // if (td.kind is Nms) TopType else thisTV - ifaceAnnot // ? TopType ? not sure + TopType + // ifaceAnnot // ? TopType ? not sure )(thisType) -> impltdMems } case Mxn => diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index e77e5a1750..6392acb825 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -129,6 +129,10 @@ class TypeDefs extends NuTypeDefs { self: Typer => require(td.kind is Trt) TraitTag(Var(td.nme.name))(prov) } + def trtNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): TraitTag = { + require(td.kind is Trt) + TraitTag(Var(td.nme.name))(prov) + } def baseClassesOf(tyd: mlscript.TypeDef): Set[TypeName] = if (tyd.kind === Als) Set.empty else baseClassesOf(tyd.body) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 74049a2cbb..8c3f859a69 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -995,8 +995,34 @@ abstract class TyperHelpers { Typer: Typer => substSyntax(td.body)(td.tparams.lazyZip(targs).map { case (tp, ta) => SkolemTag(tp._2.level, tp._2)(noProv) -> ta }.toMap) + case S(td: TypedNuTrt) => + assert(td.tparams.size === targs.size) + td.thisTy & RecordType(info.tparams.lazyZip(targs).map { + case ((tn, tv, vi), ta) => // TODO use vi + val fldNme = td.nme.name + "#" + tn.name + Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) + })(provTODO) + case S(td: TypedNuCls) => + assert(td.tparams.size === targs.size) + td.thisTy & + clsNameToNomTag(td.decl)(provTODO, ctx) & + RecordType(info.tparams.lazyZip(targs).map { + case ((tn, tv, vi), ta) => // TODO use vi + val fldNme = td.nme.name + "#" + tn.name + Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) + })(provTODO) case _ => info.decl match { + case td: NuTypeDef if td.kind is Trt => ??? + // assert(td.tparams.size === targs.size) + // // TODO add parent tags + + // trtNameToNomTag(td)(provTODO, ctx) & + // RecordType(info.tparams.lazyZip(targs).map { + // case ((tn, tv, vi), ta) => // TODO use vi + // val fldNme = td.nme.name + "#" + tn.name + // Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) + // })(provTODO) case td: NuTypeDef if td.kind.isInstanceOf[ObjDefKind] => assert(td.tparams.size === targs.size) clsNameToNomTag(td)(provTODO, ctx) & diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index dbccd5ed2e..f721b7c1a2 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -6,6 +6,7 @@ trait Test { fun bar: bool -> bool } //│ trait Test() { +//│ this: #Test //│ fun bar: bool -> bool //│ fun foo: int //│ } @@ -15,6 +16,7 @@ trait Oth extends Test { fun cool : int -> bool } //│ trait Oth() { +//│ this: #Oth & #Test //│ let a: int //│ fun bar: bool -> bool //│ fun cool: int -> bool @@ -32,11 +34,13 @@ trait Anemo { fun ter: bool } //│ trait Geo() { +//│ this: #Geo //│ fun get: bool | int //│ fun ter: int //│ let v: 2 | 3 //│ } //│ trait Anemo() { +//│ this: #Anemo //│ fun get: bool | string //│ fun ter: bool //│ let v: 1 | 2 @@ -44,6 +48,7 @@ trait Anemo { trait Mixed extends Geo, Anemo //│ trait Mixed() { +//│ this: #Anemo & #Geo & #Mixed //│ fun get: bool //│ fun ter: nothing //│ let v: 2 @@ -94,25 +99,39 @@ c.bar(true) // FIXME c: Test -//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @3bf50bf8) +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.101: c: Test +//│ ║ ^ +//│ ╟── application of type `C` is not an instance of type `Test` +//│ ║ l.94: let c = C() +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `#Test` +//│ ║ l.101: c: Test +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.101: c: Test +//│ ╙── ^^^^ +//│ Test // FIXME let c1: Test = C() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.100: let c1: Test = C() +//│ ║ l.117: let c1: Test = C() //│ ║ ^^^ //│ ╟── application of type `C` is not an instance of type `Test` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.100: let c1: Test = C() +//│ ║ l.117: let c1: Test = C() //│ ╙── ^^^^ //│ let c1: Test -trait A1 { fun a1: 1 | 2 | 3} -trait A2 { fun a1: 2 | 3 | 4} +trait A1 { fun a1: 1 | 2 | 3 } +trait A2 { fun a1: 2 | 3 | 4 } //│ trait A1() { +//│ this: #A1 //│ fun a1: 1 | 2 | 3 //│ } //│ trait A2() { +//│ this: #A2 //│ fun a1: 2 | 3 | 4 //│ } @@ -121,34 +140,50 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.121: fun a1 = 4 +//│ ║ l.140: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.121: fun a1 = 4 +//│ ║ l.140: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.121: fun a1 = 4 +//│ ║ l.140: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.110: trait A1 { fun a1: 1 | 2 | 3} +//│ ║ l.127: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.110: trait A1 { fun a1: 1 | 2 | 3} +//│ ║ l.127: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 //│ } +trait Ele { + fun ce: Oth -> Test +} +//│ trait Ele() { +//│ this: #Ele +//│ fun ce: Oth -> Test +//│ } + +// FIXME +class CE extends Ele { + fun ce(x) = x +} +//│ class CE() { +//│ fun ce: Oth -> Test +//│ } + :e class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.143: class E1 extends Test { +//│ ║ l.178: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.144: fun foo = 2 +//│ ║ l.179: fun foo = 2 //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.145: } +//│ ║ l.180: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -159,13 +194,17 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.159: trait TE1 extends C +//│ ║ l.194: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.160: trait TE2 extends M, Test +//│ ║ l.195: trait TE2 extends M, Test //│ ╙── ^ -//│ trait TE1() -//│ trait TE2() +//│ trait TE1() { +//│ this: #TE1 +//│ } +//│ trait TE2() { +//│ this: #TE2 +//│ } :e class E2 extends Test { @@ -173,13 +212,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.172: fun foo = true +//│ ║ l.211: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.172: fun foo = true +//│ ║ l.211: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.172: fun foo = true +//│ ║ l.211: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -196,10 +235,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.197: class D extends Test[int], Test[bool] +//│ ║ l.236: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.197: class D extends Test[int], Test[bool] +//│ ║ l.236: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -208,7 +247,9 @@ class D extends Test[int], Test[bool] trait Base: A | B class A class B -//│ trait Base() +//│ trait Base() { +//│ this: #Base +//│ } //│ class A() //│ class B() @@ -216,32 +257,89 @@ class B // FIXME let b: Base = A() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.217: let b: Base = A() +//│ ║ l.258: let b: Base = A() //│ ║ ^^^ //│ ╟── application of type `A` is not an instance of type `Base` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.217: let b: Base = A() +//│ ║ l.258: let b: Base = A() //│ ╙── ^^^^ //│ let b: Base // FIXME b: Base & (A | B) -//│ /!!!\ Uncaught error: java.lang.ClassCastException: class mlscript.NuTypeDefs$TypedNuTrt cannot be cast to class mlscript.NuTypeDefs$TypedNuCls (mlscript.NuTypeDefs$TypedNuTrt and mlscript.NuTypeDefs$TypedNuCls are in unnamed module of loader sbt.internal.LayeredClassLoader @3bf50bf8) +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.269: b: Base & (A | B) +//│ ║ ^ +//│ ╟── type `#Base` does not match type `A | B` +//│ ║ l.258: let b: Base = A() +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `A | B` +//│ ║ l.269: b: Base & (A | B) +//│ ║ ^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.269: b: Base & (A | B) +//│ ║ ^^^^^^^ +//│ ╟── from intersection type: +//│ ║ l.269: b: Base & (A | B) +//│ ╙── ^^^^^^^^^^^^^^ +//│ A & Base | B & Base // FIXME trait Base: Foo | Bar class Foo[A] class Bar[B] -//│ trait Base() +//│ trait Base() { +//│ this: #Base +//│ } //│ class Foo[A]() //│ class Bar[B]() // FIXME fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.241: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.299: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error //│ ╙── ^^^^ //│ + +let ot : Oth +let tt : Test +//│ let ot: Oth +//│ let tt: Test + +fun fot(x: Oth): Test = x +ot : Test +//│ fun fot: (x: Oth,) -> Test +//│ Test + +:e +tt : Oth +fun fto(x: Test): Oth = x +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.319: fun fto(x: Test): Oth = x +//│ ║ ^ +//│ ╟── type `#Test` is not an instance of type `Oth` +//│ ║ l.319: fun fto(x: Test): Oth = x +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `#Oth` +//│ ║ l.319: fun fto(x: Test): Oth = x +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.319: fun fto(x: Test): Oth = x +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.318: tt : Oth +//│ ║ ^^ +//│ ╟── type `#Test` is not an instance of type `Oth` +//│ ║ l.308: let tt : Test +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `#Oth` +//│ ║ l.318: tt : Oth +//│ ║ ^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.318: tt : Oth +//│ ╙── ^^^ +//│ fun fto: (x: Test,) -> Oth +//│ Oth From 27d9e674b240405d7285475768ded8072206198a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 18 Apr 2023 00:28:27 +0800 Subject: [PATCH 238/498] Fix `compiler` subproject and update tests Co-authored-by: pca006132 --- .../scala/mlscript/compiler/ClassLifter.scala | 34 +++++---- .../mlscript/compiler/PrettyPrinter.scala | 6 +- compiler/shared/test/diff/LiftType.mls | 16 ++-- compiler/shared/test/diff/Lifter.mls | 73 ++++++++----------- compiler/shared/test/diff/LifterBlks.mls | 48 ++++++------ ts2mls/js/src/test/diff/Array.d.mls | 2 +- ts2mls/js/src/test/diff/BasicFunctions.d.mls | 6 +- ts2mls/js/src/test/diff/ClassMember.d.mls | 2 +- ts2mls/js/src/test/diff/Dec.d.mls | 2 +- ts2mls/js/src/test/diff/Enum.d.mls | 2 +- ts2mls/js/src/test/diff/Heritage.d.mls | 2 +- ts2mls/js/src/test/diff/InterfaceMember.d.mls | 2 +- ts2mls/js/src/test/diff/Intersection.d.mls | 2 +- ts2mls/js/src/test/diff/MultiFiles.d.mls | 2 +- ts2mls/js/src/test/diff/Namespace.d.mls | 2 +- ts2mls/js/src/test/diff/Optional.d.mls | 2 +- ts2mls/js/src/test/diff/Overload.d.mls | 2 +- ts2mls/js/src/test/diff/Tuple.d.mls | 2 +- ts2mls/js/src/test/diff/Type.d.mls | 2 +- ts2mls/js/src/test/diff/Union.d.mls | 2 +- ts2mls/js/src/test/diff/Variables.d.mls | 2 +- .../js/src/test/typescript/BasicFunctions.ts | 2 +- 22 files changed, 105 insertions(+), 110 deletions(-) diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index b7328e40b4..f4afa1aa8c 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -89,7 +89,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { private def getFields(etts: List[Statement]): Set[Var] = { etts.flatMap{ case NuFunDef(_, nm, _, _) => Some(nm) - case NuTypeDef(_, TypeName(nm), _, _, _, _) => Some(Var(nm)) + case nuty: NuTypeDef => Some(Var(nuty.name)) case Let(_, name, _, _) => Some(name) case _ => None }.toSet @@ -180,13 +180,13 @@ class ClassLifter(logDebugMsg: Boolean = false) { }.fold(emptyCtx)(_ ++ _) case TyApp(trm, tpLst) => getFreeVars(trm).addT(tpLst.flatMap(_.collectTypeNames.map(TypeName(_)))) - case NuTypeDef(_, nm, tps, param, pars, body) => + case NuTypeDef(_, nm, tps, param, _, pars, _, _, body) => val prmVs = getFreeVars(param)(using emptyCtx, Map(), None) val newVs = prmVs.vSet ++ getFields(body.entities) + Var(nm.name) - val nCtx = ctx.addV(newVs).addT(nm).addT(tps) + val nCtx = ctx.addV(newVs).addT(nm).addT(tps.map(_._2)) val parVs = pars.map(getFreeVars(_)(using nCtx)).fold(emptyCtx)(_ ++ _) val bodyVs = body.entities.map(getFreeVars(_)(using nCtx)).fold(emptyCtx)(_ ++ _) - (bodyVs ++ parVs -+ prmVs).extT(tps) + (bodyVs ++ parVs -+ prmVs).extT(tps.map(_._2)) case Blk(stmts) => val newVs = getFields(stmts) stmts.map(getFreeVars(_)(using ctx.addV(newVs))).fold(emptyCtx)(_ ++ _) @@ -197,7 +197,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { } private def collectClassInfo(cls: NuTypeDef, preClss: Set[TypeName])(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): ClassInfoCache = { - val NuTypeDef(_, nm, tps, param, pars, body) = cls + val NuTypeDef(_, nm, tps, param, _, pars, _, _, body) = cls log(s"grep context of ${cls.nme.name} under {\n$ctx\n$cache\n$outer\n}\n") val (clses, funcs, trms) = splitEntities(cls.body.entities) val (supNms, rcdFlds) = pars.map(getSupClsInfoByTerm).unzip @@ -209,7 +209,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { }.unzip log(s"par record: ${flds._2.flatten}") val fields = (param.fields.flatMap(tupleEntityToVar) ++ funcs.map(_.nme) ++ clses.map(x => Var(x.nme.name)) ++ trms.flatMap(grepFieldsInTrm) ++ flds._1).toSet - val nCtx = ctx.addV(fields).addV(flds._1).extT(tps) + val nCtx = ctx.addV(fields).addV(flds._1).extT(tps.map(_._2)) val tmpCtx = ((body.entities.map(getFreeVars(_)(using nCtx)) ++ pars.map(getFreeVars(_)(using nCtx))).fold(emptyCtx)(_ ++ _).moveT2V(preClss) ).addT(flds._2.flatten.toSet).extV(supNms.flatten.map(x => Var(x.name))) @@ -379,13 +379,14 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nTpNm = TypeName(genAnoName(t.name)) val cls = cache.get(t).get val supArgs = Tup(cls.body.params.fields.flatMap(tupleEntityToVar).map(toFldsEle)) - val anoCls = NuTypeDef(Cls, nTpNm, Nil, cls.body.params, List(App(Var(t.name), supArgs)), tu) + val anoCls = NuTypeDef(Cls, nTpNm, Nil, cls.body.params, None, + List(App(Var(t.name), supArgs)), None, None, tu)(None) val nSta = New(Some((nTpNm, prm)), TypingUnit(Nil)) val ret = liftEntities(List(anoCls, nSta)) (Blk(ret._1), ret._2) case New(None, tu) => val nTpNm = TypeName(genAnoName()) - val anoCls = NuTypeDef(Cls, nTpNm, Nil, Tup(Nil), Nil, tu) + val anoCls = NuTypeDef(Cls, nTpNm, Nil, Tup(Nil), None, Nil, None, None, tu)(None) val nSta = New(Some((nTpNm, Tup(Nil))), TypingUnit(Nil)) val ret = liftEntities(List(anoCls, nSta)) (Blk(ret._1), ret._2) @@ -464,7 +465,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nlhs = liftType(lb) val nrhs = liftType(ub) Bounds(nlhs._1, nrhs._1) -> (nlhs._2 ++ nrhs._2) - case Constrained(base, bounds, where) => + case Constrained(base: Type, bounds, where) => val (nTargs, nCtx) = bounds.map { case (tv, Bounds(lb, ub)) => val nlhs = liftType(lb) val nrhs = liftType(ub) @@ -478,6 +479,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (nBase, bCtx) = liftType(base) Constrained(nBase, nTargs, bounds2) -> ((nCtx ++ nCtx2).fold(emptyCtx)(_ ++ _) ++ bCtx) + case Constrained(_, _, _) => die case Function(lhs, rhs) => val nlhs = liftType(lhs) val nrhs = liftType(rhs) @@ -531,7 +533,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { case PolyType(targs, body) => val (body2, ctx) = liftType(body) PolyType(targs, body2) -> ctx - case Top | Bot | _: Literal | _: TypeTag | _: TypeVar => target -> emptyCtx + case Top | Bot | _: Literal | _: TypeTag | _: TypeVar => target.asInstanceOf[Type] -> emptyCtx } @@ -541,14 +543,14 @@ class ClassLifter(logDebugMsg: Boolean = false) { body match{ case Left(value) => val ret = liftTerm(value)(using ctx.addV(nm).addT(tpVs)) - (func.copy(rhs = Left(ret._1)), ret._2) + (func.copy(rhs = Left(ret._1))(None), ret._2) case Right(PolyType(targs, body)) => val nBody = liftType(body)(using ctx.addT(tpVs)) val nTargs = targs.map { case L(tp) => liftTypeName(tp)(using ctx.addT(tpVs)).mapFirst(Left.apply) case R(tv) => R(tv) -> emptyCtx }.unzip - (func.copy(rhs = Right(PolyType(nTargs._1, nBody._1))), nTargs._2.fold(nBody._2)(_ ++ _)) + (func.copy(rhs = Right(PolyType(nTargs._1, nBody._1)))(None), nTargs._2.fold(nBody._2)(_ ++ _)) } } @@ -624,14 +626,14 @@ class ClassLifter(logDebugMsg: Boolean = false) { ).flatten.toMap } log("lift type " + target.toString() + " with cache " + cache.toString()) - val NuTypeDef(kind, nme, tps, params, pars, body) = target + val NuTypeDef(kind, nme, tps, params, sig, pars, supAnn, thisAnn, body) = target val nOuter = cache.get(nme) val ClassInfoCache(_, nName, freeVs, flds, inners, sups, _, _, _) = nOuter.get val (clsList, funcList, termList) = splitEntities(body.entities) val innerNmsSet = clsList.map(_.nme).toSet val nCache = cache ++ inners ++ getAllInners(sups) - val nTps = (tps ++ (freeVs.tSet -- nCache.keySet).toList).distinct + val nTps = (tps.map(_._2) ++ (freeVs.tSet -- nCache.keySet).toList).distinct val nCtx = freeVs.addT(nTps) val nParams = outer.map(x => List(toFldsEle(Var(genParName(x.liftedNm.name))))).getOrElse(Nil) @@ -641,7 +643,9 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nFuncs = funcList.map(liftFunc(_)(using emptyCtx, nCache, nOuter)).unzip val nTerms = termList.map(liftTerm(_)(using emptyCtx, nCache, nOuter)).unzip clsList.foreach(x => liftTypeDefNew(x)(using nCache, nOuter)) - retSeq = retSeq.appended(NuTypeDef(kind, nName, nTps, Tup(nParams), nPars._1, TypingUnit(nFuncs._1 ++ nTerms._1))) + retSeq = retSeq.appended(NuTypeDef( + kind, nName, nTps.map((None, _)), Tup(nParams), None, nPars._1, + None, None, TypingUnit(nFuncs._1 ++ nTerms._1))(None)) } def liftTypingUnit(rawUnit: TypingUnit): TypingUnit = { diff --git a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala index f2a10bef01..8bdee95fcb 100644 --- a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala @@ -36,9 +36,9 @@ object PrettyPrinter: case Some(true) => "let'" } s"$st ${funDef.nme.name}" - + (if funDef.targs.isEmpty + + (if funDef.tparams.isEmpty then "" - else funDef.targs.map(_.name).mkString("[", ", ", "]")) + else funDef.tparams.map(_.name).mkString("[", ", ", "]")) + " = " + funDef.rhs.fold(_.toString, _.show) @@ -46,7 +46,7 @@ object PrettyPrinter: s"${tyDef.kind.str} ${tyDef.nme.name}" + (if tyDef.tparams.isEmpty then "" - else tyDef.tparams.map(_.name).mkString("[", ",", "]")) + else tyDef.tparams.map(_._2.name).mkString("[", ",", "]")) + "(" + tyDef.params + ")" + (if tyDef.parents.isEmpty then "" diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index 488e54e495..bda3a602a0 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -8,7 +8,7 @@ class CTX{ //│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |=>| |A|)|#:| |(|A| |=>| |A|)| |=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| //│ Parsed: {class CTX() {class A() {}; fun foo = (f: (A,) => A,) => f (new A() {},) : (A -> A) -> A}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit()), NuFunDef(None, foo, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),)), TypingUnit(List())))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),)), TypingUnit(List())))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2(par$CTX$1,) {} @@ -25,11 +25,11 @@ class CTX(x, y){ //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |(|A|,| |B|)|)|#:| |(|B|,| |A|)| |#=| |(|any|._2|,| |any|._1|)|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A() {fun foo = x}; class B(): A {fun foo = y}; fun foo = (any: '(' A, B, ')',) => '(' (any)._2, (any)._1, ')' : (B, A,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuFunDef(None, foo, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (Var(A)), TypingUnit(NuFunDef(None, foo, [], Var(y)))), NuFunDef(None, foo, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], Var(y)))), NuFunDef(None, foo, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2(par$CTX$1,) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3(par$CTX$1,): CTX$1_A$2 ((this).par$CTX$1,) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_B$3(par$CTX$1,) {fun foo = ((this).par$CTX$1).y} //│ class CTX$1(x, y,) { //│ fun foo = (any: '(' CTX$1_A$2, CTX$1_B$3, ')',) => '(' (any)._2, (any)._1, ')' : (CTX$1_B$3, CTX$1_A$2,) //│ } @@ -43,11 +43,11 @@ class CTX(x, y){ //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |{|p1|#:| |A|,| |p2|#:| |B|}|)|#:| |(|B|,| |A|)| |#=| |(|any|.p2|,| |any|.p1|)|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A() {fun foo = x}; class B(): A {fun foo = y}; fun foo = (any: '{' {p1: A, p2: B} '}',) => '(' (any).p2, (any).p1, ')' : (B, A,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuFunDef(None, foo, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (Var(A)), TypingUnit(NuFunDef(None, foo, [], Var(y)))), NuFunDef(None, foo, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], Var(y)))), NuFunDef(None, foo, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2(par$CTX$1,) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3(par$CTX$1,): CTX$1_A$2 ((this).par$CTX$1,) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_B$3(par$CTX$1,) {fun foo = ((this).par$CTX$1).y} //│ class CTX$1(x, y,) { //│ fun foo = (any: '{' {p1: CTX$1_A$2, p2: CTX$1_B$3} '}',) => '(' (any).p2, (any).p1, ')' : (CTX$1_B$3, CTX$1_A$2,) //│ } @@ -61,7 +61,7 @@ class CTX(x, y){ //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|‹|T|›| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |(|A|,| |B|‹|A|›|)|)|#:| |(|(|B|‹|A|›|,| |A|)|,| |A|)| |#=| |(|any|,| |any|._1|)|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A() {fun foo = x}; class B‹T›() {fun foo = y}; fun foo = (any: '(' A, B‹A›, ')',) => '(' any, (any)._1, ')' : ((B[A], A,), A,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuFunDef(None, foo, [], Var(x)))), NuTypeDef(class, B, (TypeName(T)), Tup(), (), TypingUnit(NuFunDef(None, foo, [], Var(y)))), NuFunDef(None, foo, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A)))))), Asc(Bra(rcd = false, Tup(_: Var(any), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], Var(y)))), NuFunDef(None, foo, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A)))))), Asc(Bra(rcd = false, Tup(_: Var(any), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2(par$CTX$1,) {fun foo = ((this).par$CTX$1).x} @@ -80,9 +80,9 @@ class CTX{ (new CTX).bar } //│ |#class| |CTX|{|→|#fun| |ctx|(|x|,|y|)| |#=| |→|#class| |A|{| |#fun| |foo| |#=| |x| |}|↵|#fun| |bar|‹|T|›|(|any|#:| |T|)|#:| |A| |#=| |→|#let| |x| |#=| |#new| |T|↵|#new| |A|←|↵|(|#new| |CTX|)|.bar|‹|CTX|›|←|←|↵|}| -//│ Parsed: {class CTX() {fun ctx = (x, y,) => {class A() {fun foo = x}; fun bar = (any: T,) => {let x = new T() {}; new A() {}} : A; ('(' new CTX() {}, ')').bar‹CTX›}}} +//│ Parsed: {class CTX() {fun ctx = (x, y,) => {class A() {fun foo = x}; fun bar = (any: T,) => {let x = new T() {}; new A() {}} : A; ('(' new CTX() {} ')').bar‹CTX›}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), TypingUnit(NuFunDef(None, ctx, [], Lam(Tup(_: Var(x), _: Var(y)), Blk(...)))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, ctx, [], Lam(Tup(_: Var(x), _: Var(y)), Blk(...)))))) //│ Lifted: //│ Lifting failed: mlscript.codegen.CodeGenError: Cannot find type T. Class values are not supported in lifter. diff --git a/compiler/shared/test/diff/Lifter.mls b/compiler/shared/test/diff/Lifter.mls index d1eb609d99..566d126969 100644 --- a/compiler/shared/test/diff/Lifter.mls +++ b/compiler/shared/test/diff/Lifter.mls @@ -28,7 +28,7 @@ class A(x) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getB1| |#=| |B1|(|y|)|↵|#class| |C|(|z|)| |{|→|#fun| |inc|(||)| |#=| |x| |+| |1|↵|#fun| |getY| |#=| |y|↵|#fun| |getA| |#=| |A|(|z|)|↵|#fun| |getB|(|w|)| |#=| |B|(|w|)|↵|#fun| |getC| |#=| |#new| |C|(|inc|(||)|)|↵|#fun| |getSelf| |#=| |this|←|↵|}|←|↵|}|↵|#class| |B1|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getY| |#=| |y|↵|#fun| |getB| |#=| |#new| |B|(|y|)|↵|#fun| |getB1| |#=| |#new| |B1|(|y|)|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|(|x|)|↵|#fun| |getB2|(|y|)| |#=| |B1|(|y|)|↵|#fun| |getB3|(|z|)| |#=| |getB2|(|z|)|↵|#fun| |getA| |#=| |A|(|x|)|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1 (y,); class C(z,) {fun inc = () => + (x,) (1,); fun getY = y; fun getA = A (z,); fun getB = (w,) => B (w,); fun getC = new C(inc (),) {}; fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = new B(y,) {}; fun getB1 = new B1(y,) {}}; fun getB = new B(x,) {}; fun getB2 = (y,) => B1 (y,); fun getB3 = (z,) => getB2 (z,); fun getA = A (x,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), TypingUnit(NuFunDef(None, getX, [], Var(x)), NuFunDef(None, getB1, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), TypingUnit(NuFunDef(None, inc, [], Lam(Tup(), App(App(Var(+), Tup(_: Var(x))), Tup(_: IntLit(1))))), NuFunDef(None, getY, [], Var(y)), NuFunDef(None, getA, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, [], New(Some((TypeName(C),inc (),)), TypingUnit(List()))), NuFunDef(None, getSelf, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), TypingUnit(NuFunDef(None, getX, [], Var(x)), NuFunDef(None, getY, [], Var(y)), NuFunDef(None, getB, [], New(Some((TypeName(B),y,)), TypingUnit(List()))), NuFunDef(None, getB1, [], New(Some((TypeName(B1),y,)), TypingUnit(List()))))), NuFunDef(None, getB, [], New(Some((TypeName(B),x,)), TypingUnit(List()))), NuFunDef(None, getB2, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, [], App(Var(A), Tup(_: Var(x))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, [], Var(x)), NuFunDef(None, getB1, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, [], Lam(Tup(), App(App(Var(+), Tup(_: Var(x))), Tup(_: IntLit(1))))), NuFunDef(None, getY, [], Var(y)), NuFunDef(None, getA, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, [], New(Some((TypeName(C),inc (),)), TypingUnit(List()))), NuFunDef(None, getSelf, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, [], Var(x)), NuFunDef(None, getY, [], Var(y)), NuFunDef(None, getB, [], New(Some((TypeName(B),y,)), TypingUnit(List()))), NuFunDef(None, getB1, [], New(Some((TypeName(B1),y,)), TypingUnit(List()))))), NuFunDef(None, getB, [], New(Some((TypeName(B),x,)), TypingUnit(List()))), NuFunDef(None, getB2, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, [], App(Var(A), Tup(_: Var(x))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2_C$4(par$A$1_B$2, z,) { @@ -67,7 +67,7 @@ class A(x) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#class| |C|(|z|)| |{|→|#fun| |sum| |#=| |x| |+| |y| |+| |z|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {class C(z,) {fun sum = + (+ (x,) (y,),) (z,)}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), TypingUnit(NuTypeDef(class, C, (), Tup(_: Var(z)), (), TypingUnit(NuFunDef(None, sum, [], App(App(Var(+), Tup(_: App(App(Var(+), Tup(_: Var(x))), Tup(_: Var(y))))), Tup(_: Var(z))))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, sum, [], App(App(Var(+), Tup(_: App(App(Var(+), Tup(_: Var(x))), Tup(_: Var(y))))), Tup(_: Var(z))))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2_C$3(par$A$1_B$2, z,) { @@ -106,18 +106,9 @@ new C{ //│ |#class| |A|(|x|)| |{|→|#class| |B|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |11|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |2|↵|#fun| |bar| |#=| |12|←|↵|}|↵|#fun| |bar| |#=| |13|←|↵|}|↵|#class| |C|#:| |A|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |3|↵|#fun| |bar| |#=| |14|←|↵|}|↵|#fun| |bar| |#=| |15|←|↵|}|↵|#new| |C|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |4|↵|#fun| |bar| |#=| |16|←|↵|}|↵|#fun| |bar| |#=| |17|←|↵|}| //│ Parsed: {class A(x,) {class B() {fun foo = 1; fun bar = 11}; fun getB = new B() {fun foo = 2; fun bar = 12}; fun bar = 13}; class C(): A {fun getB = new B() {fun foo = 3; fun bar = 14}; fun bar = 15}; new C() {fun getB = new B() {fun foo = 4; fun bar = 16}; fun bar = 17}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), TypingUnit(NuTypeDef(class, B, (), Tup(), (), TypingUnit(NuFunDef(None, foo, [], IntLit(1)), NuFunDef(None, bar, [], IntLit(11)))), NuFunDef(None, getB, [], New(Some((TypeName(B),)), TypingUnit(List(fun foo = 2, fun bar = 12)))), NuFunDef(None, bar, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (Var(A)), TypingUnit(NuFunDef(None, getB, [], New(Some((TypeName(B),)), TypingUnit(List(fun foo = 3, fun bar = 14)))), NuFunDef(None, bar, [], IntLit(15)))), New(Some((TypeName(C),)), TypingUnit(List(fun getB = new B() {fun foo = 4; fun bar = 16}, fun bar = 17)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], IntLit(1)), NuFunDef(None, bar, [], IntLit(11)))), NuFunDef(None, getB, [], New(Some((TypeName(B),)), TypingUnit(List(fun foo = 2, fun bar = 12)))), NuFunDef(None, bar, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, [], New(Some((TypeName(B),)), TypingUnit(List(fun foo = 3, fun bar = 14)))), NuFunDef(None, bar, [], IntLit(15)))), New(Some((TypeName(C),)), TypingUnit(List(fun getB = new B() {fun foo = 4; fun bar = 16}, fun bar = 17)))) //│ Lifted: -//│ TypingUnit { -//│ class A$1_B$1$4(par$A$1,): A$1_B$3 ((this).par$A$1,) {fun foo = 2; fun bar = 12} -//│ class A$1_B$3(par$A$1,) {fun foo = 1; fun bar = 11} -//│ class A$1(x,) {fun getB = {new A$1_B$1$4(this,) {}}; fun bar = 13} -//│ class C$2_B$2$5(par$C$2,): A$1_B$3 ((this).par$C$2,) {fun foo = 3; fun bar = 14} -//│ class C$2(): A$1 () {fun getB = {new C$2_B$2$5(this,) {}}; fun bar = 15} -//│ class C$3$6_B$4$7(par$C$3$6,): A$1_B$3 ((this).par$C$3$6,) {fun foo = 4; fun bar = 16} -//│ class C$3$6(): C$2 () {fun getB = {new C$3$6_B$4$7(this,) {}}; fun bar = 17} -//│ Code(List({new C$3$6() {}})) -//│ } +//│ Lifting failed: java.util.NoSuchElementException: None.get @@ -131,7 +122,7 @@ class Parent(x) { //│ |#class| |Parent|‹|T|,| |U|,| |V|›|(|x|)| |{| |→|#fun| |foo|(|x|#:| |Int|)|#:| |T| |#=| |x|+|1|↵|#class| |Inner|‹|W|›|(|y|#:| |Int|)|{|→|#fun| |bar|(|z|#:| |U|)| |#=| |foo|(|y|)|↵|#fun| |boo|(|z|#:| |W|)| |#=| |z|←|↵|}|←|↵|}| //│ Parsed: {class Parent‹T, U, V›(x,) {fun foo = (x: Int,) => + (x,) (1,) : T; class Inner‹W›(y: Int,) {fun bar = (z: U,) => foo (y,); fun boo = (z: W,) => z}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Parent, (TypeName(T), TypeName(U), TypeName(V)), Tup(_: Var(x)), (), TypingUnit(NuFunDef(None, foo, [], Lam(Tup(x: Var(Int)), Asc(App(App(Var(+), Tup(_: Var(x))), Tup(_: IntLit(1))), TypeName(T)))), NuTypeDef(class, Inner, (TypeName(W)), Tup(y: Var(Int)), (), TypingUnit(NuFunDef(None, bar, [], Lam(Tup(z: Var(U)), App(Var(foo), Tup(_: Var(y))))), NuFunDef(None, boo, [], Lam(Tup(z: Var(W)), Var(z)))))))) +//│ TypingUnit(NuTypeDef(class, Parent, ((None,TypeName(T)), (None,TypeName(U)), (None,TypeName(V))), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, [], Lam(Tup(x: Var(Int)), Asc(App(App(Var(+), Tup(_: Var(x))), Tup(_: IntLit(1))), TypeName(T)))), NuTypeDef(class, Inner, ((None,TypeName(W))), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, [], Lam(Tup(z: Var(U)), App(Var(foo), Tup(_: Var(y))))), NuFunDef(None, boo, [], Lam(Tup(z: Var(W)), Var(z)))))))) //│ Lifted: //│ TypingUnit { //│ class Parent$1_Inner$2[W,U](par$Parent$1, y: Int,) { @@ -151,31 +142,31 @@ class A(x: Int): {a1: Int} & B & D(x){ } } //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| -//│ Parsed: {class B‹T›() {}; class C() {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): & (& ('{' {a1: Int} '}',) (B‹T›,),) (D (x,),) {fun getA = () => new C() {fun foo = (x: T,) => x}}} +//│ Parsed: {class B‹T›() {}; class C() {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[(x,)] {fun getA = () => new C() {fun foo = (x: T,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, (TypeName(T)), Tup(), (), TypingUnit()), NuTypeDef(class, C, (), Tup(), (), TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), TypingUnit()), NuTypeDef(class, A, (TypeName(T), TypeName(U)), Tup(x: Var(Int)), (App(App(Var(&), Tup(_: App(App(Var(&), Tup(_: Bra(rcd = true, Rcd(Var(a1) = Var(Int))))), Tup(_: TyApp(Var(B), List(TypeName(T))))))), Tup(_: App(Var(D), Tup(_: Var(x)))))), TypingUnit(NuFunDef(None, getA, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = (x: T,) => x)))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = (x: T,) => x)))))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]() {} //│ class C$2() {} //│ class D$3(y: Int,) {} //│ class A$4_C$1$5[T](par$A$4,): C$2 () {fun foo = (x: T,) => x} -//│ class A$4[T,U](x: Int,): & (& ('{' {a1: Int} '}',) (B$1 ()‹T›,),) (D$3 ((this).x,),) {fun getA = () => {new A$4_C$1$5(this,) {}}} +//│ class A$4[T,U](x: Int,) {fun getA = () => {new A$4_C$1$5(this,) {}}} //│ } // │ TypingUnit(NuTypeDef(class, B, (TypeName(T)), Tup(), (), TypingUnit()), NuTypeDef(class, C, (), Tup(), (), TypingUnit()), NuTypeDef(class, A, (TypeName(T), TypeName(U)), Tup(x: Var(Int)), (App(App(Var(&), Tup(_: Bra(rcd = true, Rcd(Var(a1) = Var(Int)})))), Tup(_: TyApp(Var(B), List(TypeName(T)))))), TypingUnit(NuFunDef(None, getA, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = x: T, => x)))))))) class B {} class C {} class D(y: Int) {} -class A(x: Int): {a1: Int}, B, D(x){ +class A(x: Int) extends {a1: Int}, B, D(x){ fun getA() = new C{ fun foo(x) = x } } -//│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| +//│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)| |#extends| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| //│ Parsed: {class B‹T›() {}; class C() {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D (x,) {fun getA = () => new C() {fun foo = (x,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, (TypeName(T)), Tup(), (), TypingUnit()), NuTypeDef(class, C, (), Tup(), (), TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), TypingUnit()), NuTypeDef(class, A, (TypeName(T), TypeName(U)), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), TypingUnit(NuFunDef(None, getA, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = (x,) => x)))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = (x,) => x)))))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]() {} @@ -193,15 +184,15 @@ class Child(x): { age: T } & { name: String} { fun boo = new Inner } //│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| -//│ Parsed: {class Child‹T, U›(x,): & ('{' {age: T} '}',) ('{' {name: String} '}',) {class Inner() {fun foo = age}; fun bar = age; fun boo = new Inner() {}}} +//│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner() {fun foo = age}; fun bar = age; fun boo = new Inner() {}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Child, (TypeName(T), TypeName(U)), Tup(_: Var(x)), (App(App(Var(&), Tup(_: Bra(rcd = true, Rcd(Var(age) = Var(T))))), Tup(_: Bra(rcd = true, Rcd(Var(name) = Var(String)))))), TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), TypingUnit(NuFunDef(None, foo, [], Var(age)))), NuFunDef(None, bar, [], Var(age)), NuFunDef(None, boo, [], New(Some((TypeName(Inner),)), TypingUnit(List())))))) +//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], Var(age)))), NuFunDef(None, bar, [], Var(age)), NuFunDef(None, boo, [], New(Some((TypeName(Inner),)), TypingUnit(List())))))) //│ Lifted: //│ TypingUnit { -//│ class Child$1_Inner$2(par$Child$1,) {fun foo = ((this).par$Child$1).age} -//│ class Child$1[T,U](x,): & ('{' {age: T} '}',) ('{' {name: String} '}',) { -//│ fun bar = (this).age -//│ fun boo = new Child$1_Inner$2(this,) {} +//│ class Child$1_Inner$2(par$Child$1, age,) {fun foo = (this).age} +//│ class Child$1[T,U](x,) { +//│ fun bar = age +//│ fun boo = new Child$1_Inner$2(this, age,) {} //│ } //│ } @@ -217,7 +208,7 @@ new A(0) { //│ |#class| |A|(|x|#:| |Int|)| |{|→|#fun| |getA|#:| |Int| |#=| |0|↵|#fun| |getA1| |#=| |1|←|↵|}|↵|#new| |A|(|0|)| |{|→|#fun| |getA| |#=| |3|↵|#fun| |getA2| |#=| |2|←|↵|}| //│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; new A(0,) {fun getA = 3; fun getA2 = 2}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), TypingUnit(NuFunDef(None, getA, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, [], IntLit(1)))), New(Some((TypeName(A),0,)), TypingUnit(List(fun getA = 3, fun getA2 = 2)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, [], IntLit(1)))), New(Some((TypeName(A),0,)), TypingUnit(List(fun getA = 3, fun getA2 = 2)))) //│ Lifted: //│ TypingUnit { //│ class A$1(x: Int,) {fun getA = 0 : Int; fun getA1 = 1} @@ -237,7 +228,7 @@ new A(1) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{| |}|←|↵|}|↵|#new| |A|(|1|)| |{|→|#fun| |getB| |#=| |#new| |B|(|2|)|{|→|#fun| |getB| |#=| |#new| |B|(|3|)|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {}}; new A(1,) {fun getB = new B(2,) {fun getB = new B(3,) {}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), TypingUnit()))), New(Some((TypeName(A),1,)), TypingUnit(List(fun getB = new B(2,) {fun getB = new B(3,) {}})))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),1,)), TypingUnit(List(fun getB = new B(2,) {fun getB = new B(3,) {}})))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2(par$A$1, y,) {} @@ -269,11 +260,11 @@ new B{ //│ |#class| |A| |{|→|#fun| |getA| |#=| |0|↵|#fun| |funcA| |#=| |10|←|↵|}|↵|#class| |B|#:| |A|{|→|#fun| |getA| |#=| |1|↵|#fun| |funcB| |#=| |11|←|↵|}|↵|#new| |A|↵|#new| |B|↵|#fun| |f|(|x|)| |#=| |#if| |x| |is| |A| |#then| |0| |#else| |1|↵|f|(|#new| |A|{|→|#fun| |getA| |#=| |2|←|↵|}|)|↵|#new| |B|{|→|#fun| |getA| |#=| |funcB|←|↵|}| //│ Parsed: {class A() {fun getA = 0; fun funcA = 10}; class B(): A {fun getA = 1; fun funcB = 11}; new A() {}; new B() {}; fun f = (x,) => if (is (x,) (A,)) then 0 else 1; f (new A() {fun getA = 2},); new B() {fun getA = funcB}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuFunDef(None, getA, [], IntLit(0)), NuFunDef(None, funcA, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (Var(A)), TypingUnit(NuFunDef(None, getA, [], IntLit(1)), NuFunDef(None, funcB, [], IntLit(11)))), New(Some((TypeName(A),)), TypingUnit(List())), New(Some((TypeName(B),)), TypingUnit(List())), NuFunDef(None, f, [], Lam(Tup(_: Var(x)), If(IfThen(App(App(Var(is), Tup(_: Var(x))), Tup(_: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),)), TypingUnit(List(fun getA = 2))))), New(Some((TypeName(B),)), TypingUnit(List(fun getA = funcB)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, [], IntLit(0)), NuFunDef(None, funcA, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, [], IntLit(1)), NuFunDef(None, funcB, [], IntLit(11)))), New(Some((TypeName(A),)), TypingUnit(List())), New(Some((TypeName(B),)), TypingUnit(List())), NuFunDef(None, f, [], Lam(Tup(_: Var(x)), If(IfThen(App(App(Var(is), Tup(_: Var(x))), Tup(_: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),)), TypingUnit(List(fun getA = 2))))), New(Some((TypeName(B),)), TypingUnit(List(fun getA = funcB)))) //│ Lifted: //│ TypingUnit { //│ class A$1() {fun getA = 0; fun funcA = 10} -//│ class B$2(): A$1 () {fun getA = 1; fun funcB = 11} +//│ class B$2() {fun getA = 1; fun funcB = 11} //│ class A$1$3(): A$1 () {fun getA = 2} //│ class B$2$4(): B$2 () {fun getA = (this).funcB} //│ fun f = (x,) => if (is (x,) (A$1 (),)) then 0 else 1 @@ -309,13 +300,13 @@ class A{ //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A() {class B() {fun funB = 1; fun foo = 100}; class C(): B {fun funC = 2; fun foo = 1000}; class D() {fun funD = 3; fun foo = 10000; class E(): C {fun funE = 4; fun foo = 100000}; class F(): E {fun funF = 5; fun foo = 1000000}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuTypeDef(class, B, (), Tup(), (), TypingUnit(NuFunDef(None, funB, [], IntLit(1)), NuFunDef(None, foo, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (Var(B)), TypingUnit(NuFunDef(None, funC, [], IntLit(2)), NuFunDef(None, foo, [], IntLit(1000)))), NuTypeDef(class, D, (), Tup(), (), TypingUnit(NuFunDef(None, funD, [], IntLit(3)), NuFunDef(None, foo, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (Var(C)), TypingUnit(NuFunDef(None, funE, [], IntLit(4)), NuFunDef(None, foo, [], IntLit(100000)))), NuTypeDef(class, F, (), Tup(), (Var(E)), TypingUnit(NuFunDef(None, funF, [], IntLit(5)), NuFunDef(None, foo, [], IntLit(1000000))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, [], IntLit(1)), NuFunDef(None, foo, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, [], IntLit(2)), NuFunDef(None, foo, [], IntLit(1000)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, [], IntLit(3)), NuFunDef(None, foo, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, [], IntLit(4)), NuFunDef(None, foo, [], IntLit(100000)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, [], IntLit(5)), NuFunDef(None, foo, [], IntLit(1000000))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2(par$A$1,) {fun funB = 1; fun foo = 100} -//│ class A$1_C$3(par$A$1,): A$1_B$2 ((this).par$A$1,) {fun funC = 2; fun foo = 1000} -//│ class A$1_D$4_E$5(par$A$1_D$4,): A$1_C$3 (((this).par$A$1_D$4).par$A$1,) {fun funE = 4; fun foo = 100000} -//│ class A$1_D$4_F$6(par$A$1_D$4,): A$1_D$4_E$5 ((this).par$A$1_D$4,) {fun funF = 5; fun foo = 1000000} +//│ class A$1_C$3(par$A$1,) {fun funC = 2; fun foo = 1000} +//│ class A$1_D$4_E$5(par$A$1_D$4,) {fun funE = 4; fun foo = 100000} +//│ class A$1_D$4_F$6(par$A$1_D$4,) {fun funF = 5; fun foo = 1000000} //│ class A$1_D$4(par$A$1,) {fun funD = 3; fun foo = 10000} //│ class A$1() {} //│ } @@ -351,22 +342,22 @@ class A{ //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|↵|#fun| |getB| |#=| |#new| |B|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|↵|#fun| |getD| |#=| |#new| |D|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|↵|#fun| |getE| |#=| |#new| |E|{|→|#fun| |foo| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A() {class B() {fun funB = 1; fun foo = 100}; class C(): B {fun funC = 2; fun foo = 1000; fun getB = new B() {}}; class D() {fun funD = 3; fun foo = 10000; class E(): C {fun funE = 4; fun foo = 100000; fun getD = new D() {}}; class F(): E {fun funF = 5; fun foo = 1000000; fun getE = new E() {fun foo = 0}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuTypeDef(class, B, (), Tup(), (), TypingUnit(NuFunDef(None, funB, [], IntLit(1)), NuFunDef(None, foo, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (Var(B)), TypingUnit(NuFunDef(None, funC, [], IntLit(2)), NuFunDef(None, foo, [], IntLit(1000)), NuFunDef(None, getB, [], New(Some((TypeName(B),)), TypingUnit(List()))))), NuTypeDef(class, D, (), Tup(), (), TypingUnit(NuFunDef(None, funD, [], IntLit(3)), NuFunDef(None, foo, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (Var(C)), TypingUnit(NuFunDef(None, funE, [], IntLit(4)), NuFunDef(None, foo, [], IntLit(100000)), NuFunDef(None, getD, [], New(Some((TypeName(D),)), TypingUnit(List()))))), NuTypeDef(class, F, (), Tup(), (Var(E)), TypingUnit(NuFunDef(None, funF, [], IntLit(5)), NuFunDef(None, foo, [], IntLit(1000000)), NuFunDef(None, getE, [], New(Some((TypeName(E),)), TypingUnit(List(fun foo = 0))))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, [], IntLit(1)), NuFunDef(None, foo, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, [], IntLit(2)), NuFunDef(None, foo, [], IntLit(1000)), NuFunDef(None, getB, [], New(Some((TypeName(B),)), TypingUnit(List()))))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, [], IntLit(3)), NuFunDef(None, foo, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, [], IntLit(4)), NuFunDef(None, foo, [], IntLit(100000)), NuFunDef(None, getD, [], New(Some((TypeName(D),)), TypingUnit(List()))))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, [], IntLit(5)), NuFunDef(None, foo, [], IntLit(1000000)), NuFunDef(None, getE, [], New(Some((TypeName(E),)), TypingUnit(List(fun foo = 0))))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2(par$A$1,) {fun funB = 1; fun foo = 100} -//│ class A$1_C$3(par$A$1,): A$1_B$2 ((this).par$A$1,) { +//│ class A$1_C$3(par$A$1,) { //│ fun funC = 2 //│ fun foo = 1000 //│ fun getB = new A$1_B$2((this).par$A$1,) {} //│ } -//│ class A$1_D$4_E$5(par$A$1_D$4,): A$1_C$3 (((this).par$A$1_D$4).par$A$1,) { +//│ class A$1_D$4_E$5(par$A$1_D$4,) { //│ fun funE = 4 //│ fun foo = 100000 //│ fun getD = new A$1_D$4(((this).par$A$1_D$4).par$A$1,) {} //│ } //│ class A$1_D$4_F$6_E$1$7(par$A$1_D$4_F$6,): A$1_D$4_E$5 (((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = 0} -//│ class A$1_D$4_F$6(par$A$1_D$4,): A$1_D$4_E$5 ((this).par$A$1_D$4,) { +//│ class A$1_D$4_F$6(par$A$1_D$4,) { //│ fun funF = 5 //│ fun foo = 1000000 //│ fun getE = {new A$1_D$4_F$6_E$1$7(this,) {}} @@ -386,7 +377,7 @@ new A //│ |#class| |A|{|→|#class| |B|{|→|#fun| |foo| |#=| |1|←|↵|}|↵|#fun| |bar| |#=| |#new| |B|←|↵|}|↵|#new| |A| //│ Parsed: {class A() {class B() {fun foo = 1}; fun bar = new B() {}}; new A() {}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuTypeDef(class, B, (), Tup(), (), TypingUnit(NuFunDef(None, foo, [], IntLit(1)))), NuFunDef(None, bar, [], New(Some((TypeName(B),)), TypingUnit(List()))))), New(Some((TypeName(A),)), TypingUnit(List()))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, [], IntLit(1)))), NuFunDef(None, bar, [], New(Some((TypeName(B),)), TypingUnit(List()))))), New(Some((TypeName(A),)), TypingUnit(List()))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2(par$A$1,) {fun foo = 1} @@ -410,7 +401,7 @@ let x = new A{ //│ |#class| |A|(|x|)| |{|→|#fun| |foo| |#=| |0|↵|#fun| |bar| |#=| |x|←|↵|}|↵|#let| |x| |#=| |#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |newFun| |#=| |2|↵|#fun| |bar| |#=| |#new| |A|(|foo|)|{|→|#fun| |foo| |#=| |bar| |+| |1|↵|#fun| |bar2| |#=| |newFun| |+| |1|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A() {fun foo = 1; fun newFun = 2; fun bar = new A(foo,) {fun foo = + (bar,) (1,); fun bar2 = + (newFun,) (1,)}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), TypingUnit(NuFunDef(None, foo, [], IntLit(0)), NuFunDef(None, bar, [], Var(x)))), NuFunDef(Some(false), x, [], New(Some((TypeName(A),)), TypingUnit(List(fun foo = 1, fun newFun = 2, fun bar = new A(foo,) {fun foo = + (bar,) (1,); fun bar2 = + (newFun,) (1,)}))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, [], IntLit(0)), NuFunDef(None, bar, [], Var(x)))), NuFunDef(Some(false), x, [], New(Some((TypeName(A),)), TypingUnit(List(fun foo = 1, fun newFun = 2, fun bar = new A(foo,) {fun foo = + (bar,) (1,); fun bar2 = + (newFun,) (1,)}))))) //│ Lifted: //│ TypingUnit { //│ class A$1(x,) {fun foo = 0; fun bar = (this).x} @@ -446,7 +437,7 @@ new A{ //│ |#class| |A| |{||}|↵|#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |#new| |A|{|→|#fun| |foo1| |#=| |foo|↵|#fun| |bar1| |#=| |#new| |A|{|→|#fun| |foo2| |#=| |foo|↵|#fun| |bar2| |#=| |#new| |A|{|→|#fun| |foo3| |#=| |foo|↵|#fun| |bar3| |#=| |#new| |A|{|→|#fun| |foo4| |#=| |foo|↵|#fun| |bar4| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A() {}; new A() {fun foo = 1; fun bar = new A() {fun foo1 = foo; fun bar1 = new A() {fun foo2 = foo; fun bar2 = new A() {fun foo3 = foo; fun bar3 = new A() {fun foo4 = foo; fun bar4 = 0}}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit()), New(Some((TypeName(A),)), TypingUnit(List(fun foo = 1, fun bar = new A() {fun foo1 = foo; fun bar1 = new A() {fun foo2 = foo; fun bar2 = new A() {fun foo3 = foo; fun bar3 = new A() {fun foo4 = foo; fun bar4 = 0}}}})))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),)), TypingUnit(List(fun foo = 1, fun bar = new A() {fun foo1 = foo; fun bar1 = new A() {fun foo2 = foo; fun bar2 = new A() {fun foo3 = foo; fun bar3 = new A() {fun foo4 = foo; fun bar4 = 0}}}})))) //│ Lifted: //│ TypingUnit { //│ class A$1() {} diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index b4e8d2df0c..6089f19262 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -18,7 +18,7 @@ class A{ //│ |#class| |A|{|→|#class| |B| |{||}|↵|#fun| |foo|(|x|#:| |B|)| |#=| |(|x|#:|B|)|←|↵|}| //│ Parsed: {class A() {class B() {}; fun foo = (x: B,) => '(' x: B, ')'}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), TypingUnit(NuTypeDef(class, B, (), Tup(), (), TypingUnit()), NuFunDef(None, foo, [], Lam(Tup(x: Var(B)), Bra(rcd = false, Tup(x: Var(B)))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, [], Lam(Tup(x: Var(B)), Bra(rcd = false, Tup(x: Var(B)))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2(par$A$1,) {} @@ -37,13 +37,13 @@ fun foo = print of local of 0 + local of 1 fun tmp = 2 //│ |#fun| |foo| |#=|→|#fun| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| -//│ Parsed: {fun foo = {fun local = (x,) => {class Foo() {fun bar = + (x,) (1,)}; (Foo ()).bar}; print (+ (local (0,),) (local (1,),),); print (+ (local (0,),) (local (1,),),); fun tmp = 1; print (local (+ (0,) (local (1,),),),); fun tmp = 2}} +//│ Parsed: {fun foo = {fun local = (x,) => {class Foo() {fun bar = + (x,) (1,)}; (Foo ()).bar}; print (+ (local (0,),) (local (1,),),); print (+ ('(' local (0,) ')',) (local (1,),),); fun tmp = 1; print (local (+ (0,) (local (1,),),),); fun tmp = 2}} //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, [], Blk(...))) //│ Lifted: //│ TypingUnit { //│ class Foo$1(x,) {fun bar = + ((this).x,) (1,)} -//│ fun foo = {fun local = (x,) => {(Foo$1 (x,)).bar}; fun tmp = 1; fun tmp = 2; print (+ (local (0,),) (local (1,),),); print (+ (local (0,),) (local (1,),),); print (local (+ (0,) (local (1,),),),)} +//│ fun foo = {fun local = (x,) => {(Foo$1 (x,)).bar}; fun tmp = 1; fun tmp = 2; print (+ (local (0,),) (local (1,),),); print (+ ('(' local (0,) ')',) (local (1,),),); print (local (+ (0,) (local (1,),),),)} //│ } class A(y){} @@ -52,7 +52,7 @@ f(0) //│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| //│ Parsed: {class A(y,) {}; let f = (x,) => new A(0,) {fun bar = + (x,) (y,)}; f (0,)} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), TypingUnit()), NuFunDef(Some(false), f, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),0,)), TypingUnit(List(fun bar = + (x,) (y,)))))), App(Var(f), Tup(_: IntLit(0)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),0,)), TypingUnit(List(fun bar = + (x,) (y,)))))), App(Var(f), Tup(_: IntLit(0)))) //│ Lifted: //│ TypingUnit { //│ class A$1(y,) {} @@ -74,7 +74,7 @@ class A(x){ //│ |#class| |A|(|x|)|{|→|#fun| |w| |#=| |x|↵|#fun| |foo|(|y|)| |#=| |→|#class| |B|(|z|)|{|→|#fun| |bar| |#=| |x|+|y|+|z|←|↵|}|↵|#new| |B|(|0|)|{|→|#fun| |bar| |#=| |w|+|y|+|z|←|↵|}|←|←|↵|}| //│ Parsed: {class A(x,) {fun w = x; fun foo = (y,) => {class B(z,) {fun bar = + (+ (x,) (y,),) (z,)}; new B(0,) {fun bar = + (+ (w,) (y,),) (z,)}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), TypingUnit(NuFunDef(None, w, [], Var(x)), NuFunDef(None, foo, [], Lam(Tup(_: Var(y)), Blk(...)))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, w, [], Var(x)), NuFunDef(None, foo, [], Lam(Tup(_: Var(y)), Blk(...)))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2(par$A$1, z, y,) { @@ -98,10 +98,10 @@ fun f(x,y,z) = fun foo = new A fun bar2 = y } - class C: A,B{ + class C extends A, B { fun bar = bar1 + bar2 } -//│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#class| |C|#:| |A|,|B|{|→|#fun| |bar| |#=| |bar1| |+| |bar2|←|↵|}|←| +//│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#class| |C| |#extends| |A|,| |B| |{|→|#fun| |bar| |#=| |bar1| |+| |bar2|←|↵|}|←| //│ Parsed: {fun f = (x, y, z,) => {class A() {fun foo = new B() {}; fun bar1 = x}; class B() {fun foo = new A() {}; fun bar2 = y}; class C(): A, B {fun bar = + (bar1,) (bar2,)}}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) @@ -132,7 +132,7 @@ fun f(x,y,z) = fun boo = (new A).bar1 + B().bar2 + z } //│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |C|{|→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#fun| |boo| |#=| |(|#new| |A|)|.bar1| |+| |B|(||)|.bar2| |+| |z|←|↵|}|←| -//│ Parsed: {fun f = (x, y, z,) => {class C() {class A() {fun foo = new B() {}; fun bar1 = x}; class B() {fun foo = new A() {}; fun bar2 = y}; fun boo = + (+ (('(' new A() {}, ')').bar1,) ((B ()).bar2,),) (z,)}}} +//│ Parsed: {fun f = (x, y, z,) => {class C() {class A() {fun foo = new B() {}; fun bar1 = x}; class B() {fun foo = new A() {}; fun bar2 = y}; fun boo = + (+ (('(' new A() {} ')').bar1,) ((B ()).bar2,),) (z,)}}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) //│ Lifted: @@ -146,7 +146,7 @@ fun f(x,y,z) = //│ fun bar2 = ((this).par$C$1).y //│ } //│ class C$1(x, y, z,) { -//│ fun boo = + (+ (('(' new C$1_A$2(this,) {}, ')').bar1,) ((C$1_B$3 (this,)).bar2,),) ((this).z,) +//│ fun boo = + (+ (('(' new C$1_A$2(this,) {} ')').bar1,) ((C$1_B$3 (this,)).bar2,),) ((this).z,) //│ } //│ fun f = (x, y, z,) => {} //│ } @@ -185,22 +185,22 @@ fun f(x) = //│ fun f = (x,) => {let g = (x,) => {let h = (x,) => + (x,) (2,); (Foo$1 (h (x,), x, g,)).bar}; (Foo$1 (x, x, g,)).bar} //│ } -class Foo(x, y): Bar(y, x), Baz(x + y) -//│ |#class| |Foo|(|x|,| |y|)|#:| |Bar|(|y|,| |x|)|,| |Baz|(|x| |+| |y|)| +class Foo(x, y) extends Bar(y, x), Baz(x + y) +//│ |#class| |Foo|(|x|,| |y|)| |#extends| |Bar|(|y|,| |x|)|,| |Baz|(|x| |+| |y|)| //│ Parsed: {class Foo(x, y,): Bar (y, x,), Baz (+ (x,) (y,),) {}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(_: Var(x), _: Var(y)), (App(Var(Bar), Tup(_: Var(y), _: Var(x))), App(Var(Baz), Tup(_: App(App(Var(+), Tup(_: Var(x))), Tup(_: Var(y)))))), TypingUnit())) +//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(_: Var(x), _: Var(y)), (App(Var(Bar), Tup(_: Var(y), _: Var(x))), App(Var(Baz), Tup(_: App(App(Var(+), Tup(_: Var(x))), Tup(_: Var(y)))))), None, None, TypingUnit())) //│ Lifted: //│ TypingUnit { //│ class Foo$1(x, y,): Bar ((this).y, (this).x,), Baz (+ ((this).x,) ((this).y,),) {} //│ } fun foo(x: T): string = - class A(y): B, C(y: U) { + class A(y) extends B, C(y: U) { fun bar = this } "rua" -//│ |#fun| |foo|‹|T|,| |U|›|(|x|#:| |T|)|#:| |string| |#=| |→|#class| |A|(|y|)|#:| |B|‹|T|›|,| |C|(|y|#:| |U|)| |{|→|#fun| |bar| |#=| |this|←|↵|}|↵|"rua"|←| +//│ |#fun| |foo|‹|T|,| |U|›|(|x|#:| |T|)|#:| |string| |#=| |→|#class| |A|(|y|)| |#extends| |B|‹|T|›|,| |C|(|y|#:| |U|)| |{|→|#fun| |bar| |#=| |this|←|↵|}|↵|"rua"|←| //│ Parsed: {fun foo = (x: T,) => {class A(y,): B‹T›, C (y: U,) {fun bar = this}; "rua"} : string} //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, [TypeName(T), TypeName(U)], Lam(Tup(x: Var(T)), Asc(Blk(...), TypeName(string))))) @@ -219,7 +219,7 @@ class A{ //│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f|#:| |T| |=>| |B| |=>| |T| |#=| |x| |=>| |y| |=>| |x|↵|#fun| |g|#:| |T| |=>| |B| |=>| |T|←|↵|}|←|↵|}| //│ Parsed: {class A‹T›() {class B() {fun f = (x,) => (y,) => x : T -> B -> T; fun g: T -> B -> T}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (TypeName(T)), Tup(), (), TypingUnit(NuTypeDef(class, B, (), Tup(), (), TypingUnit(NuFunDef(None, f, [], Asc(Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x))), Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T))))), NuFunDef(None, g, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) +//│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, [], Asc(Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x))), Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T))))), NuFunDef(None, g, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2[T](par$A$1,) { @@ -235,14 +235,14 @@ class Foo{ class Bar: {any: RectangleBox => StackedRectangleBoxes} } //│ |#class| |Foo|‹|T|›|{|→|#class| |RectangleBox|#:| |Box|‹|T|›| |&| |{| |breadth|#:| |T| |}|↵|#class| |StackedRectangleBoxes|‹|N|›| |#:| |RectangleBox|‹|T|›| |&| |{| |size|#:| |N| |}|↵|#class| |Bar|#:| |{|any|#:| |RectangleBox| |=>| |StackedRectangleBoxes|}|←|↵|}| -//│ Parsed: {class Foo‹T›() {class RectangleBox(): & (Box‹T›,) ('{' {breadth: T} '}',) {}; class StackedRectangleBoxes‹N›(): & (RectangleBox‹T›,) ('{' {size: N} '}',) {}; class Bar(): '{' {any: (RectangleBox,) => StackedRectangleBoxes} '}' {}}} +//│ Parsed: {class Foo‹T›() {class RectangleBox(): Box[T] & {breadth: T} {}; class StackedRectangleBoxes‹N›(): RectangleBox[T] & {size: N} {}; class Bar(): {any: RectangleBox -> StackedRectangleBoxes} {}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, (TypeName(T)), Tup(), (), TypingUnit(NuTypeDef(class, RectangleBox, (), Tup(), (App(App(Var(&), Tup(_: TyApp(Var(Box), List(TypeName(T))))), Tup(_: Bra(rcd = true, Rcd(Var(breadth) = Var(T)))))), TypingUnit()), NuTypeDef(class, StackedRectangleBoxes, (TypeName(N)), Tup(), (App(App(Var(&), Tup(_: TyApp(Var(RectangleBox), List(TypeName(T))))), Tup(_: Bra(rcd = true, Rcd(Var(size) = Var(N)))))), TypingUnit()), NuTypeDef(class, Bar, (), Tup(), (Bra(rcd = true, Rcd(Var(any) = Lam(Tup(_: Var(RectangleBox)), Var(StackedRectangleBoxes))))), TypingUnit())))) +//│ TypingUnit(NuTypeDef(class, Foo, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, RectangleBox, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, StackedRectangleBoxes, ((None,TypeName(N))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, Bar, (), Tup(), (), None, None, TypingUnit())))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1_RectangleBox$2[T](par$Foo$1,): & (Box‹T›,) ('{' {breadth: T} '}',) {} -//│ class Foo$1_StackedRectangleBoxes$3[N,T](par$Foo$1,): & (Foo$1_RectangleBox$2 ((this).par$Foo$1,)‹T›,) ('{' {size: N} '}',) {} -//│ class Foo$1_Bar$4(par$Foo$1,): '{' {any: (Foo$1_RectangleBox$2,) => Foo$1_StackedRectangleBoxes$3} '}' {} +//│ class Foo$1_RectangleBox$2(par$Foo$1,) {} +//│ class Foo$1_StackedRectangleBoxes$3[N](par$Foo$1,) {} +//│ class Foo$1_Bar$4(par$Foo$1,) {} //│ class Foo$1[T]() {} //│ } @@ -257,14 +257,14 @@ fun ctx(a,b) = fun apply(x) = a+x }, b) //│ |#class| |Func|‹|T|,| |U|›| |{|→|#fun| |apply|#:| |T| |=>| |U|←|↵|}|↵|#class| |Lambda|‹|T|,| |U|›| |#:| |Func|‹|T|,| |U|›| |{||}|↵|#fun| |ctx|(|a|,|b|)| |#=|→|#fun| |foo|(|f|#:| |Func|,| |x|)| |#=| |→|f|.apply|(|x|)|←|↵|foo|(|#new| |Lambda|{|→|#fun| |apply|(|x|)| |#=| |a|+|x|←|↵|}|,| |b|)|←| -//│ Parsed: {class Func‹T, U›() {fun apply: T -> U}; class Lambda‹T, U›(): Func‹T, U› {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply (x,)}; foo (new Lambda() {fun apply = (x,) => + (a,) (x,)}, b,)}} +//│ Parsed: {class Func‹T, U›() {fun apply: T -> U}; class Lambda‹T, U›(): Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply (x,)}; foo (new Lambda() {fun apply = (x,) => + (a,) (x,)}, b,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Func, (TypeName(T), TypeName(U)), Tup(), (), TypingUnit(NuFunDef(None, apply, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),TypeName(U)))))), NuTypeDef(class, Lambda, (TypeName(T), TypeName(U)), Tup(), (TyApp(Var(Func), List(TypeName(T), TypeName(U)))), TypingUnit()), NuFunDef(None, ctx, [], Lam(Tup(_: Var(a), _: Var(b)), Blk(...)))) +//│ TypingUnit(NuTypeDef(class, Func, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),TypeName(U)))))), NuTypeDef(class, Lambda, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit()), NuFunDef(None, ctx, [], Lam(Tup(_: Var(a), _: Var(b)), Blk(...)))) //│ Lifted: //│ TypingUnit { //│ class Func$1[T,U]() {fun apply = T -> U} -//│ class Lambda$2[T,U](): Func$1 ()‹T, U› {} -//│ class Lambda$1$3[T,U](a,): Lambda$2 () {fun apply = (x,) => + ((this).a,) (x,)} +//│ class Lambda$2[T,U]() {} +//│ class Lambda$1$3(a,): Lambda$2 () {fun apply = (x,) => + ((this).a,) (x,)} //│ fun ctx = (a, b,) => {fun foo = (f: Func$1, x,) => {(f).apply (x,)}; foo ({new Lambda$1$3(a,) {}}, b,)} //│ } diff --git a/ts2mls/js/src/test/diff/Array.d.mls b/ts2mls/js/src/test/diff/Array.d.mls index 5fd86917fc..63668598c2 100644 --- a/ts2mls/js/src/test/diff/Array.d.mls +++ b/ts2mls/js/src/test/diff/Array.d.mls @@ -20,4 +20,4 @@ class Temp() { fun ta(ts: MutArray>): MutArray> fun tat(ts: MutArray>): MutArray> //│ |#fun| |first|(|x|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |getZero3|(||)|#:| |MutArray|‹|number|›|↵|#fun| |first2|(|fs|#:| |MutArray|‹|(|number|)| |=>| |number|›|)|#:| |(|number|)| |=>| |number|↵|#fun| |doEs|(|e|#:| |MutArray|‹|int|›|)|#:| |MutArray|‹|int|›|↵|#class| |C|(||)| |{||}|↵|#trait| |I|(||)| |{|→|#let| |i|#:| |number|←|↵|}|↵|#fun| |doCs|(|c|#:| |MutArray|‹|C|›|)|#:| |MutArray|‹|C|›|↵|#fun| |doIs|(|i|#:| |MutArray|‹|I|›|)|#:| |MutArray|‹|I|›|↵|#fun| |inter|‹|U|,| |T|›|(|x|#:| |MutArray|‹|(|U|)| |&| |(|T|)|›|)|#:| |MutArray|‹|(|U|)| |&| |(|T|)|›|↵|#fun| |clean|(|x|#:| |MutArray|‹|(|string|,| |number|,| |)|›|)|#:| |MutArray|‹|(|string|,| |number|,| |)|›|↵|#fun| |translate|‹|T|,| |U|›|(|x|#:| |MutArray|‹|T|›|)|#:| |MutArray|‹|U|›|↵|#fun| |uu|(|x|#:| |MutArray|‹|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|›|)|#:| |MutArray|‹|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|›|↵|#class| |Temp|‹|T|›|(||)| |{|→|#let| |x|#:| |T|←|↵|}|↵|#fun| |ta|(|ts|#:| |MutArray|‹|Temp|‹|(|false|)| ||| |(|true|)|›|›|)|#:| |MutArray|‹|Temp|‹|(|false|)| ||| |(|true|)|›|›|↵|#fun| |tat|‹|T|›|(|ts|#:| |MutArray|‹|Temp|‹|T|›|›|)|#:| |MutArray|‹|Temp|‹|T|›|›| -//│ Parsed: {fun first: (x: MutArray[string],) -> string; fun getZero3: () -> MutArray[number]; fun first2: (fs: MutArray[number -> number],) -> number -> number; fun doEs: (e: MutArray[int],) -> MutArray[int]; class C() {}; trait I() {let i: number}; fun doCs: (c: MutArray[C],) -> MutArray[C]; fun doIs: (i: MutArray[I],) -> MutArray[I]; fun inter: (x: MutArray[(U,) & (T,)],) -> MutArray[(U,) & (T,)]; fun clean: (x: MutArray[(string, number,)],) -> MutArray[(string, number,)]; fun translate: (x: MutArray[T],) -> MutArray[U]; fun uu: (x: MutArray[((number,) | (false,),) | (true,)],) -> MutArray[((number,) | (false,),) | (true,)]; class Temp‹T›() {let x: T}; fun ta: (ts: MutArray[Temp[(false,) | (true,)]],) -> MutArray[Temp[(false,) | (true,)]]; fun tat: (ts: MutArray[Temp[T]],) -> MutArray[Temp[T]]} +//│ Parsed: {fun first: (x: MutArray[string],) -> string; fun getZero3: () -> MutArray[number]; fun first2: (fs: MutArray[number -> number],) -> number -> number; fun doEs: (e: MutArray[int],) -> MutArray[int]; class C() {}; trait I() {let i: number}; fun doCs: (c: MutArray[C],) -> MutArray[C]; fun doIs: (i: MutArray[I],) -> MutArray[I]; fun inter: (x: MutArray[U & T],) -> MutArray[U & T]; fun clean: (x: MutArray[(string, number,)],) -> MutArray[(string, number,)]; fun translate: (x: MutArray[T],) -> MutArray[U]; fun uu: (x: MutArray[number | false | true],) -> MutArray[number | false | true]; class Temp‹T›() {let x: T}; fun ta: (ts: MutArray[Temp[bool]],) -> MutArray[Temp[bool]]; fun tat: (ts: MutArray[Temp[T]],) -> MutArray[Temp[T]]} diff --git a/ts2mls/js/src/test/diff/BasicFunctions.d.mls b/ts2mls/js/src/test/diff/BasicFunctions.d.mls index 2c68fdee09..791152e8b4 100644 --- a/ts2mls/js/src/test/diff/BasicFunctions.d.mls +++ b/ts2mls/js/src/test/diff/BasicFunctions.d.mls @@ -18,11 +18,11 @@ class Foooooo() { let ooooooo: number } fun inn(f: Foooooo): unit -fun out(): Foooooo +fun out1(): Foooooo trait Barrrrrrrrr() { let rrrrrrr: number } fun inn2(b: Barrrrrrrrr): unit fun out2(): Barrrrrrrrr -//│ |#fun| |hello|(||)|#:| |unit|↵|#fun| |add|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |sub|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |foo|(||)|#:| |number|↵|#fun| |id|(|x|#:| |anything|)|#:| |anything|↵|#fun| |odd|(|x|#:| |number|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |isnull|(|x|#:| |anything|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |bar|(||)|#:| |anything|↵|#fun| |nu|(|n|#:| |null|)|#:| |null|↵|#fun| |un|(|n|#:| |undefined|)|#:| |undefined|↵|#fun| |fail|(||)|#:| |nothing|↵|#fun| |create|(||)|#:| |object|↵|#fun| |pa|(|x|#:| |number|)|#:| |number|↵|#fun| |wtf|(|x|#:| |anything|)|#:| |unit|↵|#class| |Foooooo|(||)| |{|→|#let| |ooooooo|#:| |number|←|↵|}|↵|#fun| |inn|(|f|#:| |Foooooo|)|#:| |unit|↵|#fun| |out|(||)|#:| |Foooooo|↵|#trait| |Barrrrrrrrr|(||)| |{|→|#let| |rrrrrrr|#:| |number|←|↵|}|↵|#fun| |inn2|(|b|#:| |Barrrrrrrrr|)|#:| |unit|↵|#fun| |out2|(||)|#:| |Barrrrrrrrr| -//│ Parsed: {fun hello: () -> unit; fun add: (x: number, y: number,) -> number; fun sub: (x: number, y: number,) -> number; fun foo: () -> number; fun id: (x: anything,) -> anything; fun odd: (x: number,) -> ((false,) | (true,)); fun isnull: (x: anything,) -> ((false,) | (true,)); fun bar: () -> anything; fun nu: (n: null,) -> null; fun un: (n: undefined,) -> undefined; fun fail: () -> nothing; fun create: () -> object; fun pa: (x: number,) -> number; fun wtf: (x: anything,) -> unit; class Foooooo() {let ooooooo: number}; fun inn: (f: Foooooo,) -> unit; fun out: () -> Foooooo; trait Barrrrrrrrr() {let rrrrrrr: number}; fun inn2: (b: Barrrrrrrrr,) -> unit; fun out2: () -> Barrrrrrrrr} +//│ |#fun| |hello|(||)|#:| |unit|↵|#fun| |add|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |sub|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |foo|(||)|#:| |number|↵|#fun| |id|(|x|#:| |anything|)|#:| |anything|↵|#fun| |odd|(|x|#:| |number|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |isnull|(|x|#:| |anything|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |bar|(||)|#:| |anything|↵|#fun| |nu|(|n|#:| |null|)|#:| |null|↵|#fun| |un|(|n|#:| |undefined|)|#:| |undefined|↵|#fun| |fail|(||)|#:| |nothing|↵|#fun| |create|(||)|#:| |object|↵|#fun| |pa|(|x|#:| |number|)|#:| |number|↵|#fun| |wtf|(|x|#:| |anything|)|#:| |unit|↵|#class| |Foooooo|(||)| |{|→|#let| |ooooooo|#:| |number|←|↵|}|↵|#fun| |inn|(|f|#:| |Foooooo|)|#:| |unit|↵|#fun| |out1|(||)|#:| |Foooooo|↵|#trait| |Barrrrrrrrr|(||)| |{|→|#let| |rrrrrrr|#:| |number|←|↵|}|↵|#fun| |inn2|(|b|#:| |Barrrrrrrrr|)|#:| |unit|↵|#fun| |out2|(||)|#:| |Barrrrrrrrr| +//│ Parsed: {fun hello: () -> unit; fun add: (x: number, y: number,) -> number; fun sub: (x: number, y: number,) -> number; fun foo: () -> number; fun id: (x: anything,) -> anything; fun odd: (x: number,) -> bool; fun isnull: (x: anything,) -> bool; fun bar: () -> anything; fun nu: (n: null,) -> null; fun un: (n: undefined,) -> undefined; fun fail: () -> nothing; fun create: () -> object; fun pa: (x: number,) -> number; fun wtf: (x: anything,) -> unit; class Foooooo() {let ooooooo: number}; fun inn: (f: Foooooo,) -> unit; fun out1: () -> Foooooo; trait Barrrrrrrrr() {let rrrrrrr: number}; fun inn2: (b: Barrrrrrrrr,) -> unit; fun out2: () -> Barrrrrrrrr} diff --git a/ts2mls/js/src/test/diff/ClassMember.d.mls b/ts2mls/js/src/test/diff/ClassMember.d.mls index 06a8f40a81..f76a852948 100644 --- a/ts2mls/js/src/test/diff/ClassMember.d.mls +++ b/ts2mls/js/src/test/diff/ClassMember.d.mls @@ -22,4 +22,4 @@ class TTT() { fun ttt2(x: T): T } //│ |#class| |Student|(|s|#:| |string|,| |age|#:| |number|)| |{|→|#let| |name|#:| |string|↵|#fun| |isFriend|(|other|#:| |Student|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |addScore|(|sub|#:| |string|,| |score|#:| |number|)|#:| |unit|↵|#fun| |getID|(||)|#:| |number|←|↵|}|↵|#class| |Foo|‹|T|›|(||)| |{|→|#fun| |bar|(|x|#:| |T|)|#:| |unit|←|↵|}|↵|#class| |EZ|(||)| |{|→|#fun| |inc|(|x|#:| |number|)|#:| |number|←|↵|}|↵|#class| |Outer|(||)| |{|→|#class| |Inner|(||)| |{|→|#let| |a|#:| |number|←|↵|}|←|↵|}|↵|#class| |TTT|‹|T|›|(||)| |{|→|#fun| |ttt|(|x|#:| |T|)|#:| |T|↵|#fun| |ttt2|(|x|#:| |T|)|#:| |T|←|↵|}| -//│ Parsed: {class Student(s: string, age: number,) {let name: string; fun isFriend: (other: Student,) -> ((false,) | (true,)); fun addScore: (sub: string, score: number,) -> unit; fun getID: () -> number}; class Foo‹T›() {fun bar: (x: T,) -> unit}; class EZ() {fun inc: (x: number,) -> number}; class Outer() {class Inner() {let a: number}}; class TTT‹T›() {fun ttt: (x: T,) -> T; fun ttt2: (x: T,) -> T}} +//│ Parsed: {class Student(s: string, age: number,) {let name: string; fun isFriend: (other: Student,) -> bool; fun addScore: (sub: string, score: number,) -> unit; fun getID: () -> number}; class Foo‹T›() {fun bar: (x: T,) -> unit}; class EZ() {fun inc: (x: number,) -> number}; class Outer() {class Inner() {let a: number}}; class TTT‹T›() {fun ttt: (x: T,) -> T; fun ttt2: (x: T,) -> T}} diff --git a/ts2mls/js/src/test/diff/Dec.d.mls b/ts2mls/js/src/test/diff/Dec.d.mls index d6f9857c19..2506d31958 100644 --- a/ts2mls/js/src/test/diff/Dec.d.mls +++ b/ts2mls/js/src/test/diff/Dec.d.mls @@ -11,4 +11,4 @@ class Person(name: string, age: number) { namespace OOO { } //│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |=>| |unit|)| ||| |(|undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#namespace| |OOO| |{|↵|}| -//│ Parsed: {fun getName: (id: (string,) | (number,),) -> string; fun render: (callback: (unit -> unit,) | (undefined,),) -> string; trait Get() {fun __call: (id: string,) -> string}; class Person(name: string, age: number,) {fun getName: (id: number,) -> string}; namespace OOO() {}} +//│ Parsed: {fun getName: (id: string | number,) -> string; fun render: (callback: unit -> unit | undefined,) -> string; trait Get() {fun __call: (id: string,) -> string}; class Person(name: string, age: number,) {fun getName: (id: number,) -> string}; module OOO() {}} diff --git a/ts2mls/js/src/test/diff/Enum.d.mls b/ts2mls/js/src/test/diff/Enum.d.mls index 639bf9aaed..2915b85cc7 100644 --- a/ts2mls/js/src/test/diff/Enum.d.mls +++ b/ts2mls/js/src/test/diff/Enum.d.mls @@ -4,4 +4,4 @@ fun pass(c: int): (false) | (true) fun stop(): int fun g(x: int): int //│ |#fun| |pass|(|c|#:| |int|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |stop|(||)|#:| |int|↵|#fun| |g|(|x|#:| |int|)|#:| |int| -//│ Parsed: {fun pass: (c: int,) -> ((false,) | (true,)); fun stop: () -> int; fun g: (x: int,) -> int} +//│ Parsed: {fun pass: (c: int,) -> bool; fun stop: () -> int; fun g: (x: int,) -> int} diff --git a/ts2mls/js/src/test/diff/Heritage.d.mls b/ts2mls/js/src/test/diff/Heritage.d.mls index 34b56a6b61..68dba08a1a 100644 --- a/ts2mls/js/src/test/diff/Heritage.d.mls +++ b/ts2mls/js/src/test/diff/Heritage.d.mls @@ -41,4 +41,4 @@ namespace Five { } class Y(): Five.ROTK {} //│ |#class| |A|(||)| |{|→|#fun| |foo|(||)|#:| |unit|←|↵|}|↵|#class| |B|(||)|#:| |A| |{||}|↵|#class| |C|‹|T|›|(||)| |{|→|#fun| |set|(|x|#:| |T|)|#:| |unit|↵|#fun| |get|(||)|#:| |T|←|↵|}|↵|#class| |D|(||)|#:| |C|‹|number|›| |{||}|↵|#trait| |Wu|(||)| |{|→|#let| |x|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#class| |WuWu|(||)|#:| |Wu| |{|→|#let| |y|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |WuWuWu|(||)|#:| |WuWu| |{|→|#let| |z|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |Never|(||)|#:| |WuWuWu| |{|→|#fun| |w|(||)|#:| |nothing|←|↵|}|↵|#class| |VG|‹|T|›|(||)| |{|→|#let| |x|#:| |T|←|↵|}|↵|#class| |Home|‹|T|›|(||)|#:| |VG|‹|string|›| |{|→|#let| |y|#:| |T|←|↵|}|↵|#trait| |O|‹|I|›|(||)| |{|→|#fun| |xx|(|x|#:| |I|)|#:| |I|←|↵|}|↵|#class| |OR|‹|R|›|(||)|#:| |O|‹|R|›| |{|→|#fun| |xx|(|x|#:| |R|)|#:| |R|←|↵|}|↵|#namespace| |Five| |{|→|#class| |ROTK|(||)| |{|→|#let| |wu|#:| |string|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}| -//│ Parsed: {class A() {fun foo: () -> unit}; class B(): A {}; class C‹T›() {fun set: (x: T,) -> unit; fun get: () -> T}; class D(): C‹number› {}; trait Wu() {let x: (false,) | (true,)}; class WuWu(): Wu {let y: (false,) | (true,)}; trait WuWuWu(): WuWu {let z: (false,) | (true,)}; trait Never(): WuWuWu {fun w: () -> nothing}; class VG‹T›() {let x: T}; class Home‹T›(): VG‹string› {let y: T}; trait O‹I›() {fun xx: (x: I,) -> I}; class OR‹R›(): O‹R› {fun xx: (x: R,) -> R}; namespace Five() {class ROTK() {let wu: string}; class Y(): (Five).ROTK {}}; class Y(): (Five).ROTK {}} +//│ Parsed: {class A() {fun foo: () -> unit}; class B(): A {}; class C‹T›() {fun set: (x: T,) -> unit; fun get: () -> T}; class D(): C[number] {}; trait Wu() {let x: bool}; class WuWu(): Wu {let y: bool}; trait WuWuWu(): WuWu {let z: bool}; trait Never(): WuWuWu {fun w: () -> nothing}; class VG‹T›() {let x: T}; class Home‹T›(): VG[string] {let y: T}; trait O‹I›() {fun xx: (x: I,) -> I}; class OR‹R›(): O[R] {fun xx: (x: R,) -> R}; module Five() {class ROTK() {let wu: string}; class Y(): Five.ROTK {}}; class Y(): Five.ROTK {}} diff --git a/ts2mls/js/src/test/diff/InterfaceMember.d.mls b/ts2mls/js/src/test/diff/InterfaceMember.d.mls index 252b3f0e93..5eda9179e0 100644 --- a/ts2mls/js/src/test/diff/InterfaceMember.d.mls +++ b/ts2mls/js/src/test/diff/InterfaceMember.d.mls @@ -37,4 +37,4 @@ trait TTT() { fun ttt(x: T): T } //│ |#trait| |IFoo|(||)| |{|→|#let| |a|#:| |string|↵|#fun| |b|(|x|#:| |number|)|#:| |number|↵|#fun| |c|(||)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |d|(|x|#:| |string|)|#:| |unit|←|↵|}|↵|#trait| |II|‹|T|›|(||)| |{|→|#fun| |test|(|x|#:| |T|)|#:| |number|←|↵|}|↵|#fun| |create|(||)|#:| |{|v|#:| |number|,|}|↵|#fun| |get|(|x|#:| |{|t|#:| |string|,|}|)|#:| |string|↵|#trait| |IEvent|(||)| |{|→|#fun| |callback|(||)|#:| |(|number|)| |=>| |unit|←|↵|}|↵|#trait| |SearchFunc|(||)| |{|→|#fun| |__call|(|source|#:| |string|,| |subString|#:| |string|)|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |StringArray|(||)| |{|→|#fun| |__index|(|index|#:| |number|)|#:| |string|←|↵|}|↵|#trait| |Counter|(||)| |{|→|#fun| |__call|(|start|#:| |number|)|#:| |string|↵|#let| |interval|#:| |number|↵|#fun| |reset|(||)|#:| |unit|←|↵|}|↵|#trait| |Simple|(||)| |{|→|#let| |a|#:| |number|↵|#fun| |b|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |string|←|↵|}|↵|#trait| |Simple2|‹|T|›|(||)| |{|→|#let| |abc|#:| |T|←|↵|}|↵|#trait| |Next|(||)|#:| |Simple| |{||}|↵|#trait| |TTT|‹|T|›|(||)| |{|→|#fun| |ttt|(|x|#:| |T|)|#:| |T|←|↵|}| -//│ Parsed: {trait IFoo() {let a: string; fun b: (x: number,) -> number; fun c: () -> ((false,) | (true,)); fun d: (x: string,) -> unit}; trait II‹T›() {fun test: (x: T,) -> number}; fun create: () -> {v: number}; fun get: (x: {t: string},) -> string; trait IEvent() {fun callback: () -> number -> unit}; trait SearchFunc() {fun __call: (source: string, subString: string,) -> ((false,) | (true,))}; trait StringArray() {fun __index: (index: number,) -> string}; trait Counter() {fun __call: (start: number,) -> string; let interval: number; fun reset: () -> unit}; trait Simple() {let a: number; fun b: (x: (false,) | (true,),) -> string}; trait Simple2‹T›() {let abc: T}; trait Next(): Simple {}; trait TTT‹T›() {fun ttt: (x: T,) -> T}} +//│ Parsed: {trait IFoo() {let a: string; fun b: (x: number,) -> number; fun c: () -> bool; fun d: (x: string,) -> unit}; trait II‹T›() {fun test: (x: T,) -> number}; fun create: () -> {v: number}; fun get: (x: {t: string},) -> string; trait IEvent() {fun callback: () -> number -> unit}; trait SearchFunc() {fun __call: (source: string, subString: string,) -> bool}; trait StringArray() {fun __index: (index: number,) -> string}; trait Counter() {fun __call: (start: number,) -> string; let interval: number; fun reset: () -> unit}; trait Simple() {let a: number; fun b: (x: bool,) -> string}; trait Simple2‹T›() {let abc: T}; trait Next(): Simple {}; trait TTT‹T›() {fun ttt: (x: T,) -> T}} diff --git a/ts2mls/js/src/test/diff/Intersection.d.mls b/ts2mls/js/src/test/diff/Intersection.d.mls index b9e532b6b1..033f4ff1e6 100644 --- a/ts2mls/js/src/test/diff/Intersection.d.mls +++ b/ts2mls/js/src/test/diff/Intersection.d.mls @@ -18,4 +18,4 @@ class A() {} class B() {} fun inter(c: (A) & (B)): (A) & (B) //│ |#fun| |extend|‹|T|,| |U|›|(|first|#:| |T|,| |second|#:| |U|)|#:| |(|T|)| |&| |(|U|)|↵|#fun| |foo|‹|T|,| |U|›|(|x|#:| |(|T|)| |&| |(|U|)|)|#:| |unit|↵|#fun| |over|(|f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|)|#:| |string|↵|#trait| |IA|(||)| |{|→|#let| |x|#:| |number|←|↵|}|↵|#trait| |IB|(||)| |{|→|#let| |y|#:| |number|←|↵|}|↵|#fun| |iii|(|x|#:| |(|IA|)| |&| |(|IB|)|)|#:| |(|IA|)| |&| |(|IB|)|↵|#fun| |uu|‹|U|,| |V|,| |T|,| |P|›|(|x|#:| |(|(|(|(|U|)| |&| |(|T|)|)| ||| |(|(|U|)| |&| |(|P|)|)|)| ||| |(|(|V|)| |&| |(|T|)|)|)| ||| |(|(|V|)| |&| |(|P|)|)|)|#:| |(|(|(|(|U|)| |&| |(|T|)|)| ||| |(|(|U|)| |&| |(|P|)|)|)| ||| |(|(|V|)| |&| |(|T|)|)|)| ||| |(|(|V|)| |&| |(|P|)|)|↵|#fun| |iiii|‹|U|,| |T|,| |V|›|(|x|#:| |(|(|U|)| |&| |(|T|)|)| |&| |(|V|)|)|#:| |(|(|U|)| |&| |(|T|)|)| |&| |(|V|)|↵|#fun| |arr|‹|U|,| |T|›|(|a|#:| |(|MutArray|‹|U|›|)| |&| |(|MutArray|‹|T|›|)|)|#:| |(|MutArray|‹|U|›|)| |&| |(|MutArray|‹|T|›|)|↵|#fun| |tt|‹|U|,| |T|,| |V|›|(|x|#:| |(|(|U|,| |T|,| |)|)| |&| |(|(|V|,| |V|,| |)|)|)|#:| |(|(|U|,| |T|,| |)|)| |&| |(|(|V|,| |V|,| |)|)|↵|#class| |A|(||)| |{||}|↵|#class| |B|(||)| |{||}|↵|#fun| |inter|(|c|#:| |(|A|)| |&| |(|B|)|)|#:| |(|A|)| |&| |(|B|)| -//│ Parsed: {fun extend: (first: T, second: U,) -> ((T,) & (U,)); fun foo: (x: (T,) & (U,),) -> unit; fun over: (f: (number -> string,) & (object -> string,),) -> string; trait IA() {let x: number}; trait IB() {let y: number}; fun iii: (x: (IA,) & (IB,),) -> ((IA,) & (IB,)); fun uu: (x: ((((U,) & (T,),) | ((U,) & (P,),),) | ((V,) & (T,),),) | ((V,) & (P,),),) -> (((((U,) & (T,),) | ((U,) & (P,),),) | ((V,) & (T,),),) | ((V,) & (P,),)); fun iiii: (x: ((U,) & (T,),) & (V,),) -> (((U,) & (T,),) & (V,)); fun arr: (a: (MutArray[U],) & (MutArray[T],),) -> ((MutArray[U],) & (MutArray[T],)); fun tt: (x: ((U, T,),) & ((V, V,),),) -> (((U, T,),) & ((V, V,),)); class A() {}; class B() {}; fun inter: (c: (A,) & (B,),) -> ((A,) & (B,))} +//│ Parsed: {fun extend: (first: T, second: U,) -> (T & U); fun foo: (x: T & U,) -> unit; fun over: (f: number -> string & object -> string,) -> string; trait IA() {let x: number}; trait IB() {let y: number}; fun iii: (x: IA & IB,) -> (IA & IB); fun uu: (x: U & T | U & P | V & T | V & P,) -> (U & T | U & P | V & T | V & P); fun iiii: (x: U & T & V,) -> (U & T & V); fun arr: (a: MutArray[U] & MutArray[T],) -> (MutArray[U] & MutArray[T]); fun tt: (x: (U, T,) & (V, V,),) -> ((U, T,) & (V, V,)); class A() {}; class B() {}; fun inter: (c: A & B,) -> (A & B)} diff --git a/ts2mls/js/src/test/diff/MultiFiles.d.mls b/ts2mls/js/src/test/diff/MultiFiles.d.mls index e2d44c0bbc..21007ede73 100644 --- a/ts2mls/js/src/test/diff/MultiFiles.d.mls +++ b/ts2mls/js/src/test/diff/MultiFiles.d.mls @@ -19,4 +19,4 @@ trait Base() { class AnotherFoo(): AnotherBase {} fun multi5(): unit //│ |#fun| |multi1|(|x|#:| |number|)|#:| |number|↵|#fun| |multi3|(||)|#:| |unit|↵|#class| |Foo|(||)|#:| |Base| |{||}|↵|#trait| |AnotherBase|(||)| |{|→|#let| |y|#:| |string|←|↵|}|↵|#namespace| |N| |{|→|#fun| |f|(||)|#:| |unit|↵|#fun| |g|(||)|#:| |unit|↵|#fun| |h|(||)|#:| |unit|←|↵|}|↵|#fun| |multi2|(|x|#:| |string|)|#:| |string|↵|#fun| |multi4|(||)|#:| |unit|↵|#trait| |Base|(||)| |{|→|#let| |a|#:| |number|←|↵|}|↵|#class| |AnotherFoo|(||)|#:| |AnotherBase| |{||}|↵|#fun| |multi5|(||)|#:| |unit| -//│ Parsed: {fun multi1: (x: number,) -> number; fun multi3: () -> unit; class Foo(): Base {}; trait AnotherBase() {let y: string}; namespace N() {fun f: () -> unit; fun g: () -> unit; fun h: () -> unit}; fun multi2: (x: string,) -> string; fun multi4: () -> unit; trait Base() {let a: number}; class AnotherFoo(): AnotherBase {}; fun multi5: () -> unit} +//│ Parsed: {fun multi1: (x: number,) -> number; fun multi3: () -> unit; class Foo(): Base {}; trait AnotherBase() {let y: string}; module N() {fun f: () -> unit; fun g: () -> unit; fun h: () -> unit}; fun multi2: (x: string,) -> string; fun multi4: () -> unit; trait Base() {let a: number}; class AnotherFoo(): AnotherBase {}; fun multi5: () -> unit} diff --git a/ts2mls/js/src/test/diff/Namespace.d.mls b/ts2mls/js/src/test/diff/Namespace.d.mls index 04d4d81763..1f0901ea63 100644 --- a/ts2mls/js/src/test/diff/Namespace.d.mls +++ b/ts2mls/js/src/test/diff/Namespace.d.mls @@ -29,4 +29,4 @@ namespace AA { fun f1(x: N1.C): N1.C fun f2(x: AA.C): AA.C //│ |#namespace| |N1| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |number|↵|#fun| |ff|(|y|#:| |anything|)|#:| |number|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#namespace| |N2| |{|→|#fun| |fff|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |number|↵|#fun| |gg|(|c|#:| |N1|.C|)|#:| |N1|.C|↵|#class| |BBB|(||)|#:| |N1|.C| |{||}|←|↵|}|←|↵|}|↵|#namespace| |AA| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |string|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#namespace| |N2| |{|↵|}|←|↵|}|↵|#fun| |f1|(|x|#:| |N1|.C|)|#:| |N1|.C|↵|#fun| |f2|(|x|#:| |AA|.C|)|#:| |AA|.C| -//│ Parsed: {namespace N1() {fun f: (x: anything,) -> number; fun ff: (y: anything,) -> number; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; namespace N2() {fun fff: (x: (false,) | (true,),) -> number; fun gg: (c: N1.C,) -> N1.C; class BBB(): (N1).C {}}}; namespace AA() {fun f: (x: anything,) -> string; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; namespace N2() {}}; fun f1: (x: N1.C,) -> N1.C; fun f2: (x: AA.C,) -> AA.C} +//│ Parsed: {module N1() {fun f: (x: anything,) -> number; fun ff: (y: anything,) -> number; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2() {fun fff: (x: bool,) -> number; fun gg: (c: N1.C,) -> N1.C; class BBB(): N1.C {}}}; module AA() {fun f: (x: anything,) -> string; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2() {}}; fun f1: (x: N1.C,) -> N1.C; fun f2: (x: AA.C,) -> AA.C} diff --git a/ts2mls/js/src/test/diff/Optional.d.mls b/ts2mls/js/src/test/diff/Optional.d.mls index dbcf0d2a11..07ea8fa40d 100644 --- a/ts2mls/js/src/test/diff/Optional.d.mls +++ b/ts2mls/js/src/test/diff/Optional.d.mls @@ -21,4 +21,4 @@ class B() { } fun boom(b: (B) | (undefined)): anything //│ |#fun| |buildName|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|undefined|)|)|#:| |string|↵|#fun| |buildName2|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|undefined|)|)|#:| |string|↵|#fun| |buildName3|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |buildName4|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|anything|›|)|#:| |string|↵|#trait| |SquareConfig|(||)| |{|→|#let| |color|#:| |(|string|)| ||| |(|undefined|)|↵|#let| |width|#:| |(|number|)| ||| |(|undefined|)|←|↵|}|↵|#fun| |did|(|x|#:| |number|,| |f|#:| |(|(|number|)| |=>| |number|)| ||| |(|undefined|)|)|#:| |number|↵|#fun| |getOrElse|(|arr|#:| |(|MutArray|‹|object|›|)| ||| |(|undefined|)|)|#:| |object|↵|#class| |ABC|(||)| |{||}|↵|#fun| |testABC|(|abc|#:| |(|ABC|)| ||| |(|undefined|)|)|#:| |unit|↵|#fun| |testSquareConfig|(|conf|#:| |(|SquareConfig|)| ||| |(|undefined|)|)|#:| |unit|↵|#fun| |err|(|msg|#:| |(|(|number|,| |string|,| |)|)| ||| |(|undefined|)|)|#:| |unit|↵|#fun| |toStr|(|x|#:| |(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| ||| |(|undefined|)|)|#:| |string|↵|#fun| |boo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|)| ||| |(|undefined|)|)|#:| |unit|↵|#class| |B|‹|T|›|(||)| |{|→|#let| |b|#:| |T|←|↵|}|↵|#fun| |boom|(|b|#:| |(|B|‹|nothing|›|)| ||| |(|undefined|)|)|#:| |anything| -//│ Parsed: {fun buildName: (firstName: string, lastName: (string,) | (undefined,),) -> string; fun buildName2: (firstName: string, lastName: (string,) | (undefined,),) -> string; fun buildName3: (firstName: string, lastName: MutArray[string],) -> string; fun buildName4: (firstName: string, lastName: MutArray[anything],) -> string; trait SquareConfig() {let color: (string,) | (undefined,); let width: (number,) | (undefined,)}; fun did: (x: number, f: (number -> number,) | (undefined,),) -> number; fun getOrElse: (arr: (MutArray[object],) | (undefined,),) -> object; class ABC() {}; fun testABC: (abc: (ABC,) | (undefined,),) -> unit; fun testSquareConfig: (conf: (SquareConfig,) | (undefined,),) -> unit; fun err: (msg: ((number, string,),) | (undefined,),) -> unit; fun toStr: (x: (((number,) | (false,),) | (true,),) | (undefined,),) -> string; fun boo: (x: ((T,) & (U,),) | (undefined,),) -> unit; class B‹T›() {let b: T}; fun boom: (b: (B[nothing],) | (undefined,),) -> anything} +//│ Parsed: {fun buildName: (firstName: string, lastName: string | undefined,) -> string; fun buildName2: (firstName: string, lastName: string | undefined,) -> string; fun buildName3: (firstName: string, lastName: MutArray[string],) -> string; fun buildName4: (firstName: string, lastName: MutArray[anything],) -> string; trait SquareConfig() {let color: string | undefined; let width: number | undefined}; fun did: (x: number, f: number -> number | undefined,) -> number; fun getOrElse: (arr: MutArray[object] | undefined,) -> object; class ABC() {}; fun testABC: (abc: ABC | undefined,) -> unit; fun testSquareConfig: (conf: SquareConfig | undefined,) -> unit; fun err: (msg: (number, string,) | undefined,) -> unit; fun toStr: (x: number | false | true | undefined,) -> string; fun boo: (x: T & U | undefined,) -> unit; class B‹T›() {let b: T}; fun boom: (b: B[nothing] | undefined,) -> anything} diff --git a/ts2mls/js/src/test/diff/Overload.d.mls b/ts2mls/js/src/test/diff/Overload.d.mls index 0e89921fd3..c68fd67169 100644 --- a/ts2mls/js/src/test/diff/Overload.d.mls +++ b/ts2mls/js/src/test/diff/Overload.d.mls @@ -23,4 +23,4 @@ class WWW() { } fun baz(): anything /* warning: the overload of function baz is not supported yet. */ //│ |#fun| |f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |=>| |unit|)| |=>| |(|number|)| |=>| |unit|)| |&| |(|(|(|string|)| |=>| |unit|)| |=>| |(|string|)| |=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |=>| |unit|)| |&| |(|(|N|)| |=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |=>| |(|(|number|)| ||| |(|undefined|)|)| |=>| |unit|)| |&| |(|(|number|)| |=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|undefined|)|)| |=>| |unit|)|↵|#fun| |swap|#:| |(|(|(|number|,| |string|,| |)|)| |=>| |(|number|,| |string|,| |)|)| |&| |(|(|(|string|,| |number|,| |)|)| |=>| |(|number|,| |string|,| |)|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#namespace| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| -//│ Parsed: {fun f: (number -> string,) & (string -> string,); class M() {let foo: (number -> string,) & (string -> string,)}; fun app: ((string -> unit) -> number -> unit,) & ((string -> unit) -> string -> unit,); fun create: (number -> unit -> ((false,) | (true,)),) & (((false,) | (true,)) -> unit -> ((false,) | (true,)),); fun g0: (MutArray[string] -> string,) & (MutArray[object] -> string,); fun db: (number -> MutArray[number],) & (object -> MutArray[number],); class N() {}; fun id: (M -> unit,) & (N -> unit,); fun tst: ({z: number} -> {y: string},) & ({z: (false,) | (true,)} -> {y: string},); fun op: (number -> ((number,) | (undefined,)) -> unit,) & (number -> (((false,) | (true,),) | (undefined,)) -> unit,); fun swap: ((number, string,) -> (number, string,),) & ((string, number,) -> (number, string,),); fun u: ((((number,) | (false,),) | (true,)) -> string,) & (object -> string,); fun doSome: (x: anything,) -> unit; namespace XX() {fun f: (x: T, n: anything,) -> string}; class WWW() {fun F: (x: T,) -> anything}; fun baz: () -> anything} +//│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | undefined) -> unit & number -> (false | true | undefined) -> unit; fun swap: (number, string,) -> (number, string,) & (string, number,) -> (number, string,); fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything,) -> unit; module XX() {fun f: (x: T, n: anything,) -> string}; class WWW() {fun F: (x: T,) -> anything}; fun baz: () -> anything} diff --git a/ts2mls/js/src/test/diff/Tuple.d.mls b/ts2mls/js/src/test/diff/Tuple.d.mls index 551620feb3..9153102040 100644 --- a/ts2mls/js/src/test/diff/Tuple.d.mls +++ b/ts2mls/js/src/test/diff/Tuple.d.mls @@ -17,4 +17,4 @@ class A() { class B() {} fun swap(x: (A, B, )): (B, A, ) //│ |#fun| |key|(|x|#:| |(|string|,| |(|false|)| ||| |(|true|)|,| |)|)|#:| |string|↵|#fun| |value|(|x|#:| |(|string|,| |(|false|)| ||| |(|true|)|,| |)|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |third|(|x|#:| |(|number|,| |number|,| |number|,| |)|)|#:| |number|↵|#fun| |vec2|(|x|#:| |number|,| |y|#:| |number|)|#:| |(|number|,| |number|,| |)|↵|#fun| |twoFunctions|(|ff|#:| |(|(|number|)| |=>| |number|,| |(|number|)| |=>| |number|,| |)|,| |x|#:| |number|)|#:| |number|↵|#fun| |tupleIt|(|x|#:| |string|)|#:| |(|unit| |=>| |string|,| |)|↵|#fun| |s|(|flag|#:| |(|false|)| ||| |(|true|)|)|#:| |(|(|string|)| ||| |(|number|)|,| |(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|,| |)|↵|#fun| |s2|(|t|#:| |(|(|false|)| ||| |(|true|)|,| |(|string|)| ||| |(|number|)|,| |)|)|#:| |(|string|)| ||| |(|number|)|↵|#fun| |ex|‹|T|,| |U|›|(|x|#:| |T|,| |y|#:| |U|)|#:| |(|T|,| |U|,| |(|T|)| |&| |(|U|)|,| |)|↵|#fun| |foo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|,| |)|)|#:| |unit|↵|#fun| |conv|(|x|#:| |{|y|#:| |number|,|}|)|#:| |(|{|y|#:| |number|,|}|,| |{|z|#:| |string|,|}|,| |)|↵|#class| |A|(||)| |{|→|#let| |x|#:| |number|←|↵|}|↵|#class| |B|(||)| |{||}|↵|#fun| |swap|(|x|#:| |(|A|,| |B|,| |)|)|#:| |(|B|,| |A|,| |)| -//│ Parsed: {fun key: (x: (string, (false,) | (true,),),) -> string; fun value: (x: (string, (false,) | (true,),),) -> ((false,) | (true,)); fun third: (x: (number, number, number,),) -> number; fun vec2: (x: number, y: number,) -> (number, number,); fun twoFunctions: (ff: (number -> number, number -> number,), x: number,) -> number; fun tupleIt: (x: string,) -> (unit -> string,); fun s: (flag: (false,) | (true,),) -> ((string,) | (number,), ((number,) | (false,),) | (true,),); fun s2: (t: ((false,) | (true,), (string,) | (number,),),) -> ((string,) | (number,)); fun ex: (x: T, y: U,) -> (T, U, (T,) & (U,),); fun foo: (x: ((T,) & (U,),),) -> unit; fun conv: (x: {y: number},) -> ({y: number}, {z: string},); class A() {let x: number}; class B() {}; fun swap: (x: (A, B,),) -> (B, A,)} +//│ Parsed: {fun key: (x: (string, bool,),) -> string; fun value: (x: (string, bool,),) -> bool; fun third: (x: (number, number, number,),) -> number; fun vec2: (x: number, y: number,) -> (number, number,); fun twoFunctions: (ff: (number -> number, number -> number,), x: number,) -> number; fun tupleIt: (x: string,) -> unit -> string; fun s: (flag: bool,) -> (string | number, number | false | true,); fun s2: (t: (bool, string | number,),) -> (string | number); fun ex: (x: T, y: U,) -> (T, U, T & U,); fun foo: (x: T & U,) -> unit; fun conv: (x: {y: number},) -> ({y: number}, {z: string},); class A() {let x: number}; class B() {}; fun swap: (x: (A, B,),) -> (B, A,)} diff --git a/ts2mls/js/src/test/diff/Type.d.mls b/ts2mls/js/src/test/diff/Type.d.mls index c1f448a0bc..de7bc27730 100644 --- a/ts2mls/js/src/test/diff/Type.d.mls +++ b/ts2mls/js/src/test/diff/Type.d.mls @@ -29,4 +29,4 @@ type G = ABC let none: {_tag: "None",} fun some(a: A): (None) | (Some) //│ |#trait| |None|(||)| |{|→|#let| |_tag|#:| |"None"|←|↵|}|↵|#trait| |Some|‹|A|›|(||)| |{|→|#let| |_tag|#:| |"Some"|↵|#let| |value|#:| |A|←|↵|}|↵|#type| |Option|‹|A|›| |#=| |(|None|)| ||| |(|Some|‹|A|›|)|↵|#type| |Func| |#=| |(|number|)| |=>| |number|↵|#type| |S2| |#=| |(|string|,| |string|,| |)|↵|#trait| |I1|(||)| |{||}|↵|#trait| |I2|(||)| |{||}|↵|#type| |I3| |#=| |(|I1|)| |&| |(|I2|)|↵|#type| |StringArray| |#=| |Array|‹|string|›|↵|#type| |SomeInterface| |#=| |{|x|#:| |number|,|y|#:| |number|,|}|↵|#class| |ABC|(||)| |{||}|↵|#type| |DEF| |#=| |ABC|↵|#type| |TP|‹|A|,| |B|,| |C|›| |#=| |(|A|,| |B|,| |C|,| |)|↵|#namespace| |NA| |{|→|#fun| |fb|(|b|#:| |string|)|#:| |unit|↵|#type| |B| |#=| |string|←|↵|}|↵|#class| |NC|(||)| |{|→|#let| |b|#:| |string|←|↵|}|↵|#type| |G| |#=| |ABC|↵|#let| |none|#:| |{|_tag|#:| |"None"|,|}|↵|#fun| |some|‹|A|›|(|a|#:| |A|)|#:| |(|None|)| ||| |(|Some|‹|A|›|)| -//│ Parsed: {trait None() {let _tag: "None"}; trait Some‹A›() {let _tag: "Some"; let value: A}; type alias Option‹A›() = | (None,) (Some‹A›,) {}; type alias Func() = (number,) => number {}; type alias S2() = '(' string, string, ')' {}; trait I1() {}; trait I2() {}; type alias I3() = & (I1,) (I2,) {}; type alias StringArray() = Array‹string› {}; type alias SomeInterface() = '{' {x: number, y: number} '}' {}; class ABC() {}; type alias DEF() = ABC {}; type alias TP‹A, B, C›() = '(' A, B, C, ')' {}; namespace NA() {fun fb: (b: string,) -> unit; type alias B() = string {}}; class NC() {let b: string}; type alias G() = ABC {}; let none: {_tag: "None"}; fun some: (a: A,) -> ((None,) | (Some[A],))} +//│ Parsed: {trait None() {let _tag: "None"}; trait Some‹A›() {let _tag: "Some"; let value: A}; type alias Option‹A›(): None | Some[A] {}; type alias Func(): number -> number {}; type alias S2(): (string, string,) {}; trait I1() {}; trait I2() {}; type alias I3(): I1 & I2 {}; type alias StringArray(): Array[string] {}; type alias SomeInterface(): {x: number, y: number} {}; class ABC() {}; type alias DEF(): ABC {}; type alias TP‹A, B, C›(): (A, B, C,) {}; module NA() {fun fb: (b: string,) -> unit; type alias B(): string {}}; class NC() {let b: string}; type alias G(): ABC {}; let none: {_tag: "None"}; fun some: (a: A,) -> (None | Some[A])} diff --git a/ts2mls/js/src/test/diff/Union.d.mls b/ts2mls/js/src/test/diff/Union.d.mls index 1124713fa7..511d213132 100644 --- a/ts2mls/js/src/test/diff/Union.d.mls +++ b/ts2mls/js/src/test/diff/Union.d.mls @@ -8,4 +8,4 @@ fun get2(t: ((string, string, )) | ((number, string, ))): string fun typeVar(x: (T) | (U)): (T) | (U) fun uuuu(x: (((string) | (number)) | (false)) | (true)): (((string) | (number)) | (false)) | (true) //│ |#fun| |getString|(|x|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)|)|#:| |string|↵|#fun| |test|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |(|string|)| ||| |(|number|)|↵|#fun| |run|(|f|#:| |(|(|number|)| |=>| |number|)| ||| |(|(|number|)| |=>| |string|)|)|#:| |anything|↵|#fun| |get|(|arr|#:| |(|MutArray|‹|number|›|)| ||| |(|MutArray|‹|string|›|)|)|#:| |unit|↵|#fun| |get2|(|t|#:| |(|(|string|,| |string|,| |)|)| ||| |(|(|number|,| |string|,| |)|)|)|#:| |string|↵|#fun| |typeVar|‹|T|,| |U|›|(|x|#:| |(|T|)| ||| |(|U|)|)|#:| |(|T|)| ||| |(|U|)|↵|#fun| |uuuu|(|x|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)|)|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)| -//│ Parsed: {fun getString: (x: (((string,) | (number,),) | (false,),) | (true,),) -> string; fun test: (x: (false,) | (true,),) -> ((string,) | (number,)); fun run: (f: (number -> number,) | (number -> string,),) -> anything; fun get: (arr: (MutArray[number],) | (MutArray[string],),) -> unit; fun get2: (t: ((string, string,),) | ((number, string,),),) -> string; fun typeVar: (x: (T,) | (U,),) -> ((T,) | (U,)); fun uuuu: (x: (((string,) | (number,),) | (false,),) | (true,),) -> ((((string,) | (number,),) | (false,),) | (true,))} +//│ Parsed: {fun getString: (x: string | number | false | true,) -> string; fun test: (x: bool,) -> (string | number); fun run: (f: number -> number | number -> string,) -> anything; fun get: (arr: MutArray[number] | MutArray[string],) -> unit; fun get2: (t: (string, string,) | (number, string,),) -> string; fun typeVar: (x: T | U,) -> (T | U); fun uuuu: (x: string | number | false | true,) -> (string | number | false | true)} diff --git a/ts2mls/js/src/test/diff/Variables.d.mls b/ts2mls/js/src/test/diff/Variables.d.mls index 178e8f1e15..fbe763c783 100644 --- a/ts2mls/js/src/test/diff/Variables.d.mls +++ b/ts2mls/js/src/test/diff/Variables.d.mls @@ -15,4 +15,4 @@ namespace DD { let bar: number } //│ |#let| |URI|#:| |string|↵|#let| |URI2|#:| |string|↵|#let| |foo|#:| |number|↵|#let| |bar|#:| |false|↵|#class| |FooBar|(||)| |{||}|↵|#let| |fb|#:| |FooBar|↵|#namespace| |ABC| |{|→|#class| |DEF|(||)| |{||}|←|↵|}|↵|#let| |d|#:| |ABC|.DEF|↵|#namespace| |DD| |{|→|#let| |foo|#:| |number|↵|#let| |bar|#:| |number|←|↵|}| -//│ Parsed: {let URI: string; let URI2: string; let foo: number; let bar: false; class FooBar() {}; let fb: FooBar; namespace ABC() {class DEF() {}}; let d: ABC.DEF; namespace DD() {let foo: number; let bar: number}} +//│ Parsed: {let URI: string; let URI2: string; let foo: number; let bar: false; class FooBar() {}; let fb: FooBar; module ABC() {class DEF() {}}; let d: ABC.DEF; module DD() {let foo: number; let bar: number}} diff --git a/ts2mls/js/src/test/typescript/BasicFunctions.ts b/ts2mls/js/src/test/typescript/BasicFunctions.ts index 27ae2c2562..ef0b915cab 100644 --- a/ts2mls/js/src/test/typescript/BasicFunctions.ts +++ b/ts2mls/js/src/test/typescript/BasicFunctions.ts @@ -60,7 +60,7 @@ function inn(f: Foooooo) { console.log(f.ooooooo) } -function out(): Foooooo { +function out1(): Foooooo { return new Foooooo(); } From 99d688be0ab78e541b7675a60d5ef4971491a8df Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 18 Apr 2023 23:29:05 +0800 Subject: [PATCH 239/498] Add val, undefined, null, and some tests --- .../scala/mlscript/ConstraintSolver.scala | 6 +- shared/src/main/scala/mlscript/NewLexer.scala | 4 + .../src/main/scala/mlscript/NewParser.scala | 7 +- shared/src/main/scala/mlscript/Typer.scala | 9 ++- .../main/scala/mlscript/codegen/Scope.scala | 1 + shared/src/test/diff/nu/Declarations.mls | 79 ++++++++++++++++--- shared/src/test/diff/nu/MethodSignatures.mls | 39 +++++++++ shared/src/test/diff/nu/Numbers.mls | 23 ++++++ shared/src/test/diff/ucs/SimpleUCS.mls | 6 +- ts2mls/js/src/test/diff/BasicFunctions.d.mls | 2 +- ts2mls/js/src/test/diff/Dec.d.mls | 2 +- ts2mls/js/src/test/diff/Optional.d.mls | 2 +- ts2mls/js/src/test/diff/Overload.d.mls | 2 +- 13 files changed, 153 insertions(+), 29 deletions(-) create mode 100644 shared/src/test/diff/nu/MethodSignatures.mls create mode 100644 shared/src/test/diff/nu/Numbers.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 8441794ea4..f22e06ffd8 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -31,7 +31,7 @@ class ConstraintSolver extends NormalForms { self: Typer => (implicit ctx: Ctx, raise: Raise) : Either[Diagnostic, NuMember] = { - val info = ctx.tyDefs2(clsNme) + val info = ctx.tyDefs2.getOrElse(clsNme, die/*TODO*/) if (info.isComputing) { @@ -54,7 +54,7 @@ class ConstraintSolver extends NormalForms { self: Typer => (implicit ctx: Ctx, raise: Raise) : FieldType = { - val info = ctx.tyDefs2(clsNme) + val info = ctx.tyDefs2.getOrElse(clsNme, die/*TODO*/) // require(!info.isComputing) // TODO intersect with found signature! @@ -165,7 +165,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // (implicit raise: Raise, cctx: ConCtx, ctx: Ctx, shadows: Shadows) (implicit ctx: Ctx, raise: Raise) : TypedNuCls = { - val info = ctx.tyDefs2(clsNme) + val info = ctx.tyDefs2.getOrElse(clsNme, die/*TODO*/) info.complete() match { case td: TypedNuCls => diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 07f4629160..1fce939aa9 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -250,6 +250,8 @@ object NewLexer { "then", "else", "fun", + "val", + "var", // "is", // "as", "of", @@ -278,6 +280,8 @@ object NewLexer { "exists", "in", "out", + "null", + "undefined", ) def printToken(tl: TokLoc): Str = tl match { diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 286f983122..579084badb 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -277,7 +277,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D yeetSpaces go(acc.copy(acc.mods + ("declare" -> l0))) case _ if acc.mods.isEmpty => acc - case (KEYWORD("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module" | "fun"), l0) :: _ => + case (KEYWORD("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module" | "fun" | "val"), l0) :: _ => acc case (tok, loc) :: _ => // TODO support indented blocks of modified declarations... @@ -373,7 +373,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body)(isDecl) R(res.withLoc(S(l0 ++ res.getLoc))) - case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "let")), l0) :: c) => // TODO support rec? + case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "val" | "let")), l0) :: c) => // TODO support rec? consume val (isDecl, mods2) = mods.handle("declare") mods2.done @@ -520,6 +520,9 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (LITVAL(lit), l0) :: _ => consume exprCont(lit.withLoc(S(l0)), prec, allowNewlines = false) + case (KEYWORD(kwStr @ ("undefined" | "null")), l0) :: _ => + consume + exprCont(UnitLit(kwStr === "undefined").withLoc(S(l0)), prec, allowNewlines = false) case (IDENT(nme, false), l0) :: _ => consume exprCont(Var(nme).withLoc(S(l0)), prec, allowNewlines = false) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 027ac7b42b..493d518d41 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -66,7 +66,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) lvl: Int, inPattern: Bool, tyDefs: Map[Str, TypeDef], - // tyDefs2: MutMap[Str, NuTypeDef], tyDefs2: MutMap[Str, DelayedTypeInfo], inRecursiveDef: Opt[Var], // TODO rm extrCtx: ExtrCtx, @@ -259,6 +258,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Map( "true" -> TrueType, "false" -> FalseType, + "NaN" -> DecType, "document" -> BotType, "window" -> BotType, "typeof" -> fun(singleTup(TopType), StrType)(noProv), @@ -430,9 +430,10 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case Literal(lit) => ClassTag(lit, lit.baseClasses)(tyTp(ty.toLoc, "literal type")) case TypeName("this") => - ctx.env.getOrElse("this", err(msg"undeclared this" -> ty.toLoc :: Nil)) match { - case AbstractConstructor(_, _) => die - case VarSymbol(t: SimpleType, _) => t + ctx.env.get("this") match { + case S(AbstractConstructor(_, _)) => die + case S(VarSymbol(t: SimpleType, _)) => t + case N => err(msg"undeclared this" -> ty.toLoc :: Nil) } case tn @ TypeTag(name) => rec(TypeName(name.decapitalize)) // TODO rm this hack // case tn @ TypeTag(name) => rec(TypeName(name)) diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 3f2f222e0e..bd2e0297f7 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -34,6 +34,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { Ls( "true", "false", + "NaN", "id", "emptyArray", "succ", diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index a5a960892c..a1d2d0b249 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -2,15 +2,19 @@ -declare fun console: nothing -//│ fun console: nothing - -console.error("hello") +declare fun btoa: nothing +declare fun atob: nothing +//│ fun btoa: nothing +//│ fun atob: nothing + +let str = btoa("hello") +atob(str) +//│ let str: nothing //│ nothing +//│ str +//│ = 'aGVsbG8=' //│ res -//│ = undefined -//│ // Output -//│ hello +//│ = 'hello' declare module console { @@ -30,13 +34,14 @@ console.error("hello") :e console.log("hello") //│ ╔══[ERROR] Module `console` does not contain member `log` -//│ ║ l.31: console.log("hello") +//│ ║ l.35: console.log("hello") //│ ╙── ^^^^ //│ error //│ res //│ = undefined + declare module Foo { fun foo: int } @@ -52,7 +57,7 @@ Foo.foo //│ ReferenceError: Foo is not defined -declare type A = int +declare type A = int //│ type A = int 42 : A @@ -62,14 +67,62 @@ declare type A = int +declare class Sanitizer { + fun sanitizeFor(element: string, input: string): string +} +//│ class Sanitizer() { +//│ fun sanitizeFor: (element: string, input: string,) -> string +//│ } + +:re +let s = Sanitizer() +//│ let s: Sanitizer +//│ s +//│ Runtime error: +//│ ReferenceError: Sanitizer is not defined + + + +// * TODO allow Buffer2 to be named Buffer... +// :d +declare module Buffer { + class Buffer2 { + val length: int + } + fun bar: int + fun from(a: Array[int]): Buffer2 = from(a) + // fun from1(a: Array[int]): this.Buffer2 = from1(a) // FIXME + // fun from2(a: Array[int]): Buffer.Buffer2 = from2(a) // FIXME +} +//│ module Buffer() { +//│ class Buffer2() { +//│ let length: int +//│ } +//│ fun bar: int +//│ fun from: (a: Array[int],) -> Buffer2 +//│ } + +let b = Buffer.from([0, 1, 2]) +//│ let b: Buffer2 +//│ b +//│ = + +b.length +//│ int +//│ res +//│ = 3 + + + + :pe declare 42 //│ ╔══[PARSE ERROR] Unexpected literal token after modifier -//│ ║ l.66: declare 42 -//│ ╙── ^^ +//│ ║ l.119: declare 42 +//│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected literal token after modifier -//│ ║ l.66: declare 42 -//│ ╙── ^^ +//│ ║ l.119: declare 42 +//│ ╙── ^^ //│ 42 //│ res //│ = 42 diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls new file mode 100644 index 0000000000..3fada7539e --- /dev/null +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -0,0 +1,39 @@ +:NewDefs + + +// FIXME currently type signatures are typed too early (not in the context where the other defns live) +// We need to move all the typing unit setup to lazy type info prelude +// :d +module M { + class A + fun a: A + fun a = 1 +} +//│ ╔══[ERROR] type identifier not found: A +//│ ║ l.9: fun a: A +//│ ╙── ^ +//│ module M() { +//│ class A() +//│ fun a: error +//│ } + +// FIXME similar +module M { + class A + fun a: this.A + fun a = 1 +} +//│ ╔══[ERROR] undeclared this +//│ ║ l.23: fun a: this.A +//│ ╙── ^^^^ +//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached and unexpected state. + +// FIXME similar +module M { + class A + fun a: M.A + fun a = 1 +} +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + diff --git a/shared/src/test/diff/nu/Numbers.mls b/shared/src/test/diff/nu/Numbers.mls new file mode 100644 index 0000000000..abeaf04369 --- /dev/null +++ b/shared/src/test/diff/nu/Numbers.mls @@ -0,0 +1,23 @@ +:NewDefs + + +let x = NaN +//│ let x: number +//│ x +//│ = NaN + +// TODO polymorphic number operations +x + 1 +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.10: x + 1 +//│ ║ ^^^ +//│ ╟── reference of type `number` is not an instance of type `int` +//│ ║ l.4: let x = NaN +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `int` +//│ ║ l.10: x + 1 +//│ ╙── ^ +//│ error | int +//│ res +//│ = NaN + diff --git a/shared/src/test/diff/ucs/SimpleUCS.mls b/shared/src/test/diff/ucs/SimpleUCS.mls index 929d3111e4..0155bffbed 100644 --- a/shared/src/test/diff/ucs/SimpleUCS.mls +++ b/shared/src/test/diff/ucs/SimpleUCS.mls @@ -315,7 +315,7 @@ class Var(name) class ValBase class IntVal(value): ValBase class BoolVal(value): ValBase -class Lit(val) +class Lit(value) //│ Defined class Var //│ Defined class ValBase //│ Defined class IntVal @@ -329,7 +329,7 @@ class Lit(val) //│ = [Function: IntVal1] //│ BoolVal: 'value -> (BoolVal & {value: 'value}) //│ = [Function: BoolVal1] -//│ Lit: 'val -> (Lit & {val: 'val}) +//│ Lit: 'value -> (Lit & {value: 'value}) //│ = [Function: Lit1] fun p(e, context) = @@ -339,7 +339,7 @@ fun p(e, context) = Some(BoolVal(v)) then Right(v) Lit(IntVal(v)) then Left(v) Lit(BoolVal(v)) then Right(v) -//│ p: (Lit & {val: BoolVal & {value: 'value} | IntVal & {value: 'value0}} | Var & {name: 'name}, {get: 'name -> (Some & {value: BoolVal & {value: 'value} | IntVal & {value: 'value0}})},) -> (Left & {leftValue: 'value0} | Right & {rightValue: 'value}) +//│ p: (Lit & {value: BoolVal & {value: 'value} | IntVal & {value: 'value0}} | Var & {name: 'name}, {get: 'name -> (Some & {value: BoolVal & {value: 'value} | IntVal & {value: 'value0}})},) -> (Left & {leftValue: 'value0} | Right & {rightValue: 'value}) //│ = [Function: p1] class Nil() diff --git a/ts2mls/js/src/test/diff/BasicFunctions.d.mls b/ts2mls/js/src/test/diff/BasicFunctions.d.mls index 791152e8b4..9e8752a4ca 100644 --- a/ts2mls/js/src/test/diff/BasicFunctions.d.mls +++ b/ts2mls/js/src/test/diff/BasicFunctions.d.mls @@ -24,5 +24,5 @@ trait Barrrrrrrrr() { } fun inn2(b: Barrrrrrrrr): unit fun out2(): Barrrrrrrrr -//│ |#fun| |hello|(||)|#:| |unit|↵|#fun| |add|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |sub|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |foo|(||)|#:| |number|↵|#fun| |id|(|x|#:| |anything|)|#:| |anything|↵|#fun| |odd|(|x|#:| |number|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |isnull|(|x|#:| |anything|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |bar|(||)|#:| |anything|↵|#fun| |nu|(|n|#:| |null|)|#:| |null|↵|#fun| |un|(|n|#:| |undefined|)|#:| |undefined|↵|#fun| |fail|(||)|#:| |nothing|↵|#fun| |create|(||)|#:| |object|↵|#fun| |pa|(|x|#:| |number|)|#:| |number|↵|#fun| |wtf|(|x|#:| |anything|)|#:| |unit|↵|#class| |Foooooo|(||)| |{|→|#let| |ooooooo|#:| |number|←|↵|}|↵|#fun| |inn|(|f|#:| |Foooooo|)|#:| |unit|↵|#fun| |out1|(||)|#:| |Foooooo|↵|#trait| |Barrrrrrrrr|(||)| |{|→|#let| |rrrrrrr|#:| |number|←|↵|}|↵|#fun| |inn2|(|b|#:| |Barrrrrrrrr|)|#:| |unit|↵|#fun| |out2|(||)|#:| |Barrrrrrrrr| +//│ |#fun| |hello|(||)|#:| |unit|↵|#fun| |add|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |sub|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |foo|(||)|#:| |number|↵|#fun| |id|(|x|#:| |anything|)|#:| |anything|↵|#fun| |odd|(|x|#:| |number|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |isnull|(|x|#:| |anything|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |bar|(||)|#:| |anything|↵|#fun| |nu|(|n|#:| |#null|)|#:| |#null|↵|#fun| |un|(|n|#:| |#undefined|)|#:| |#undefined|↵|#fun| |fail|(||)|#:| |nothing|↵|#fun| |create|(||)|#:| |object|↵|#fun| |pa|(|x|#:| |number|)|#:| |number|↵|#fun| |wtf|(|x|#:| |anything|)|#:| |unit|↵|#class| |Foooooo|(||)| |{|→|#let| |ooooooo|#:| |number|←|↵|}|↵|#fun| |inn|(|f|#:| |Foooooo|)|#:| |unit|↵|#fun| |out1|(||)|#:| |Foooooo|↵|#trait| |Barrrrrrrrr|(||)| |{|→|#let| |rrrrrrr|#:| |number|←|↵|}|↵|#fun| |inn2|(|b|#:| |Barrrrrrrrr|)|#:| |unit|↵|#fun| |out2|(||)|#:| |Barrrrrrrrr| //│ Parsed: {fun hello: () -> unit; fun add: (x: number, y: number,) -> number; fun sub: (x: number, y: number,) -> number; fun foo: () -> number; fun id: (x: anything,) -> anything; fun odd: (x: number,) -> bool; fun isnull: (x: anything,) -> bool; fun bar: () -> anything; fun nu: (n: null,) -> null; fun un: (n: undefined,) -> undefined; fun fail: () -> nothing; fun create: () -> object; fun pa: (x: number,) -> number; fun wtf: (x: anything,) -> unit; class Foooooo() {let ooooooo: number}; fun inn: (f: Foooooo,) -> unit; fun out1: () -> Foooooo; trait Barrrrrrrrr() {let rrrrrrr: number}; fun inn2: (b: Barrrrrrrrr,) -> unit; fun out2: () -> Barrrrrrrrr} diff --git a/ts2mls/js/src/test/diff/Dec.d.mls b/ts2mls/js/src/test/diff/Dec.d.mls index 2506d31958..1527f227f4 100644 --- a/ts2mls/js/src/test/diff/Dec.d.mls +++ b/ts2mls/js/src/test/diff/Dec.d.mls @@ -10,5 +10,5 @@ class Person(name: string, age: number) { } namespace OOO { } -//│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |=>| |unit|)| ||| |(|undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#namespace| |OOO| |{|↵|}| +//│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |=>| |unit|)| ||| |(|#undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#namespace| |OOO| |{|↵|}| //│ Parsed: {fun getName: (id: string | number,) -> string; fun render: (callback: unit -> unit | undefined,) -> string; trait Get() {fun __call: (id: string,) -> string}; class Person(name: string, age: number,) {fun getName: (id: number,) -> string}; module OOO() {}} diff --git a/ts2mls/js/src/test/diff/Optional.d.mls b/ts2mls/js/src/test/diff/Optional.d.mls index 07ea8fa40d..72be7897d5 100644 --- a/ts2mls/js/src/test/diff/Optional.d.mls +++ b/ts2mls/js/src/test/diff/Optional.d.mls @@ -20,5 +20,5 @@ class B() { let b: T } fun boom(b: (B) | (undefined)): anything -//│ |#fun| |buildName|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|undefined|)|)|#:| |string|↵|#fun| |buildName2|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|undefined|)|)|#:| |string|↵|#fun| |buildName3|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |buildName4|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|anything|›|)|#:| |string|↵|#trait| |SquareConfig|(||)| |{|→|#let| |color|#:| |(|string|)| ||| |(|undefined|)|↵|#let| |width|#:| |(|number|)| ||| |(|undefined|)|←|↵|}|↵|#fun| |did|(|x|#:| |number|,| |f|#:| |(|(|number|)| |=>| |number|)| ||| |(|undefined|)|)|#:| |number|↵|#fun| |getOrElse|(|arr|#:| |(|MutArray|‹|object|›|)| ||| |(|undefined|)|)|#:| |object|↵|#class| |ABC|(||)| |{||}|↵|#fun| |testABC|(|abc|#:| |(|ABC|)| ||| |(|undefined|)|)|#:| |unit|↵|#fun| |testSquareConfig|(|conf|#:| |(|SquareConfig|)| ||| |(|undefined|)|)|#:| |unit|↵|#fun| |err|(|msg|#:| |(|(|number|,| |string|,| |)|)| ||| |(|undefined|)|)|#:| |unit|↵|#fun| |toStr|(|x|#:| |(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| ||| |(|undefined|)|)|#:| |string|↵|#fun| |boo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|)| ||| |(|undefined|)|)|#:| |unit|↵|#class| |B|‹|T|›|(||)| |{|→|#let| |b|#:| |T|←|↵|}|↵|#fun| |boom|(|b|#:| |(|B|‹|nothing|›|)| ||| |(|undefined|)|)|#:| |anything| +//│ |#fun| |buildName|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName2|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName3|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |buildName4|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|anything|›|)|#:| |string|↵|#trait| |SquareConfig|(||)| |{|→|#let| |color|#:| |(|string|)| ||| |(|#undefined|)|↵|#let| |width|#:| |(|number|)| ||| |(|#undefined|)|←|↵|}|↵|#fun| |did|(|x|#:| |number|,| |f|#:| |(|(|number|)| |=>| |number|)| ||| |(|#undefined|)|)|#:| |number|↵|#fun| |getOrElse|(|arr|#:| |(|MutArray|‹|object|›|)| ||| |(|#undefined|)|)|#:| |object|↵|#class| |ABC|(||)| |{||}|↵|#fun| |testABC|(|abc|#:| |(|ABC|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |testSquareConfig|(|conf|#:| |(|SquareConfig|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |err|(|msg|#:| |(|(|number|,| |string|,| |)|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |toStr|(|x|#:| |(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |boo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|)| ||| |(|#undefined|)|)|#:| |unit|↵|#class| |B|‹|T|›|(||)| |{|→|#let| |b|#:| |T|←|↵|}|↵|#fun| |boom|(|b|#:| |(|B|‹|nothing|›|)| ||| |(|#undefined|)|)|#:| |anything| //│ Parsed: {fun buildName: (firstName: string, lastName: string | undefined,) -> string; fun buildName2: (firstName: string, lastName: string | undefined,) -> string; fun buildName3: (firstName: string, lastName: MutArray[string],) -> string; fun buildName4: (firstName: string, lastName: MutArray[anything],) -> string; trait SquareConfig() {let color: string | undefined; let width: number | undefined}; fun did: (x: number, f: number -> number | undefined,) -> number; fun getOrElse: (arr: MutArray[object] | undefined,) -> object; class ABC() {}; fun testABC: (abc: ABC | undefined,) -> unit; fun testSquareConfig: (conf: SquareConfig | undefined,) -> unit; fun err: (msg: (number, string,) | undefined,) -> unit; fun toStr: (x: number | false | true | undefined,) -> string; fun boo: (x: T & U | undefined,) -> unit; class B‹T›() {let b: T}; fun boom: (b: B[nothing] | undefined,) -> anything} diff --git a/ts2mls/js/src/test/diff/Overload.d.mls b/ts2mls/js/src/test/diff/Overload.d.mls index c68fd67169..c3ef1b83fb 100644 --- a/ts2mls/js/src/test/diff/Overload.d.mls +++ b/ts2mls/js/src/test/diff/Overload.d.mls @@ -22,5 +22,5 @@ class WWW() { fun F(x: T): anything /* warning: the overload of function F is not supported yet. */ } fun baz(): anything /* warning: the overload of function baz is not supported yet. */ -//│ |#fun| |f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |=>| |unit|)| |=>| |(|number|)| |=>| |unit|)| |&| |(|(|(|string|)| |=>| |unit|)| |=>| |(|string|)| |=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |=>| |unit|)| |&| |(|(|N|)| |=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |=>| |(|(|number|)| ||| |(|undefined|)|)| |=>| |unit|)| |&| |(|(|number|)| |=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|undefined|)|)| |=>| |unit|)|↵|#fun| |swap|#:| |(|(|(|number|,| |string|,| |)|)| |=>| |(|number|,| |string|,| |)|)| |&| |(|(|(|string|,| |number|,| |)|)| |=>| |(|number|,| |string|,| |)|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#namespace| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| +//│ |#fun| |f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |=>| |unit|)| |=>| |(|number|)| |=>| |unit|)| |&| |(|(|(|string|)| |=>| |unit|)| |=>| |(|string|)| |=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |=>| |unit|)| |&| |(|(|N|)| |=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |=>| |(|(|number|)| ||| |(|#undefined|)|)| |=>| |unit|)| |&| |(|(|number|)| |=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|#undefined|)|)| |=>| |unit|)|↵|#fun| |swap|#:| |(|(|(|number|,| |string|,| |)|)| |=>| |(|number|,| |string|,| |)|)| |&| |(|(|(|string|,| |number|,| |)|)| |=>| |(|number|,| |string|,| |)|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#namespace| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| //│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | undefined) -> unit & number -> (false | true | undefined) -> unit; fun swap: (number, string,) -> (number, string,) & (string, number,) -> (number, string,); fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything,) -> unit; module XX() {fun f: (x: T, n: anything,) -> string}; class WWW() {fun F: (x: T,) -> anything}; fun baz: () -> anything} From 8f4452849cb20107eb31ac1e9470e3d4bca2033d Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 19 Apr 2023 16:34:05 +0800 Subject: [PATCH 240/498] tags --- .../scala/mlscript/ConstraintSolver.scala | 15 + .../src/main/scala/mlscript/NuTypeDefs.scala | 57 ++-- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperHelpers.scala | 21 +- shared/src/test/diff/nu/Interfaces.mls | 290 ++++++++++++------ 5 files changed, 246 insertions(+), 141 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 8441794ea4..8d28ff41c3 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -95,6 +95,21 @@ class ConstraintSolver extends NormalForms { self: Typer => case N => S(nope) } } + + case trt: TypedNuTrt => + trt.members.get(fld.name) match { + case S(d: TypedNuFun) => + S(d.typeSignature.toUpper(provTODO)) + case S(p: NuParam) => + S(p.ty) + case S(m) => + S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) + case N => + fromRft match { + case S(fty) => N + case N => S(nope) + } + } case _ => ??? // TODO } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index f107724e05..e162b16499 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -116,24 +116,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) - case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => + case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags) => TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), + tags.freshenAbove(lim, rigidify), )(cls.instanceType.freshenAbove(lim, rigidify)) case cls @ TypedNuAls(level, td, tparams, body) => TypedNuAls(level, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), body.freshenAbove(lim, rigidify)) - case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign) => + case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags) => TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), - sign.map(_.freshenAbove(lim, rigidify)) // todo - ) + sign.map(_.freshenAbove(lim, rigidify)), // todo + tags.freshenAbove(lim, rigidify) + ) } val td: NuTypeDef val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) @@ -173,6 +175,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members: Map[Str, NuMember], thisTy: ST, sign: Opt[ST], + tags: ST ) extends TypedNuTypeDef(Trt) with TypedNuTermDef { def decl: NuTypeDef = td @@ -180,7 +183,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil) + def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, tags) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -188,7 +191,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), - sign.map(f(pol, _)) + sign.map(f(pol, _)), + tags ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -196,7 +200,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), - sign.map(f(pol, _)) + sign.map(f(pol, _)), + tags ) } @@ -205,6 +210,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => level: Level, td: NuTypeDef, ttu: TypedTypingUnit, tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, + tags: ST, )(val instanceType: ST, // * only meant to be used in `force` and `variances` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { @@ -213,7 +219,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, params) + def typeSignature: ST = typeSignatureOf(td, level, tparams, params, tags) // TODO @@ -269,6 +275,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), + tags )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -277,6 +284,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), + tags )(f(pol, instanceType)) } @@ -348,7 +356,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params): ST = td.kind match { + def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, tags: ST = TopType): ST = td.kind match { case Nms => ClassTag(Var(td.nme.name), // TODO base classes @@ -361,14 +369,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ClassTag(Var(td.nme.name), // TODO base classes Set.single(TypeName("Eql")) - )(provTODO) & RecordType.mk( + )(provTODO) & tags & RecordType.mk( tparams.map { case (tn, tv, vi) => // TODO use vi Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } )(provTODO) )(provTODO) ) - case Trt => - TraitTag(Var(td.nme.name))(provTODO) // case k => err case k => errType // FIXME } @@ -668,32 +674,32 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "this" -> VarSymbol(thisTV, Var("this")) // inherit traits - def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) - : (ST, Ls[NuMember]) = + def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember]) + : (ST, ST, Ls[NuMember]) = parents match { case (p, v @ Var(trtName), mxnArgs) :: ps => ctx.get(trtName) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { case trt: TypedNuTrt => - inherit(ps, superType & trt.thisTy, memberUn(members, trt.members.values.toList)) + inherit(ps, superType & trt.thisTy, tags & trt.tags, memberUn(members, trt.members.values.toList)) case _ => err(msg"trait can only inherit traits", p.toLoc) - (superType, members) + (superType, tags, members) } - case _ => (superType, members) + case _ => (superType, tags, members) } - case Nil => (superType, members) + case Nil => (superType, tags, members) } - val (thisType, baseMems) = + val (thisType, tags, baseMems) = // ? is it really a good idea - inherit(parentSpecs, trtNameToNomTag(td)(noProv, ctx), Nil) + inherit(parentSpecs, TopType, trtNameToNomTag(td)(noProv, ctx), Nil) val ttu = typeTypingUnit(td.body, topLevel = false) val trtMems = baseMems ++ ttu.entities val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap - TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None) -> Nil + TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, tags) -> Nil } case Als => @@ -872,7 +878,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => info match { case trt: TypedNuTrt => // TODO also computer intersect - computeInterface(ps, annot & trt.thisTy, memberUn(members, trt.members.values.toList)) // intersect members + computeInterface(ps, annot & trt.tags, memberUn(members, trt.members.values.toList)) // intersect members case _ => computeInterface(ps, annot, members) } case S(_) => @@ -884,7 +890,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case Nil => (annot, members) } - val (ifaceAnnot, ifaceMembers) = computeInterface(parentSpecs, thisType, Nil) + val thisTag = TopType //clsNameToNomTag(td)(provTODO, ctx) + val (ifaceAnnot, ifaceMembers) = computeInterface(parentSpecs, thisTag, Nil) // TODO check mems against interface stuff above ifaceMembers.foreach { m => @@ -902,8 +909,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuCls(outerCtx.lvl, td, ttu, tparams, typedParams, mems ++ ifaceMembers.map(d => d.name -> d).toMap, // if (td.kind is Nms) TopType else thisTV - TopType - // ifaceAnnot // ? TopType ? not sure + TopType, + ifaceAnnot, )(thisType) -> impltdMems } case Mxn => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index fea5b60bd7..59e95655e7 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1322,7 +1322,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), @@ -1332,7 +1332,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 8c3f859a69..08d8f380ca 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -997,32 +997,21 @@ abstract class TyperHelpers { Typer: Typer => }.toMap) case S(td: TypedNuTrt) => assert(td.tparams.size === targs.size) - td.thisTy & RecordType(info.tparams.lazyZip(targs).map { + td.tags & RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.nme.name + "#" + tn.name Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) })(provTODO) case S(td: TypedNuCls) => assert(td.tparams.size === targs.size) - td.thisTy & - clsNameToNomTag(td.decl)(provTODO, ctx) & - RecordType(info.tparams.lazyZip(targs).map { + clsNameToNomTag(td.decl)(provTODO, ctx) & + td.tags & RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.nme.name + "#" + tn.name Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) })(provTODO) case _ => info.decl match { - case td: NuTypeDef if td.kind is Trt => ??? - // assert(td.tparams.size === targs.size) - // // TODO add parent tags - - // trtNameToNomTag(td)(provTODO, ctx) & - // RecordType(info.tparams.lazyZip(targs).map { - // case ((tn, tv, vi), ta) => // TODO use vi - // val fldNme = td.nme.name + "#" + tn.name - // Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) - // })(provTODO) case td: NuTypeDef if td.kind.isInstanceOf[ObjDefKind] => assert(td.tparams.size === targs.size) clsNameToNomTag(td)(provTODO, ctx) & @@ -1179,13 +1168,13 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index f721b7c1a2..90ef80187a 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -6,17 +6,28 @@ trait Test { fun bar: bool -> bool } //│ trait Test() { -//│ this: #Test //│ fun bar: bool -> bool //│ fun foo: int //│ } +// FIXME +fun ts(x: Test) = x.foo +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.14: fun ts(x: Test) = x.foo +//│ ║ ^^^^^ +//│ ╟── type `Test` does not have field 'foo' +//│ ║ l.14: fun ts(x: Test) = x.foo +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `{foo: ?foo}` +//│ ║ l.14: fun ts(x: Test) = x.foo +//│ ╙── ^ +//│ fun ts: (x: Test,) -> error + trait Oth extends Test { let a : int fun cool : int -> bool } //│ trait Oth() { -//│ this: #Oth & #Test //│ let a: int //│ fun bar: bool -> bool //│ fun cool: int -> bool @@ -34,13 +45,11 @@ trait Anemo { fun ter: bool } //│ trait Geo() { -//│ this: #Geo //│ fun get: bool | int //│ fun ter: int //│ let v: 2 | 3 //│ } //│ trait Anemo() { -//│ this: #Anemo //│ fun get: bool | string //│ fun ter: bool //│ let v: 1 | 2 @@ -48,7 +57,6 @@ trait Anemo { trait Mixed extends Geo, Anemo //│ trait Mixed() { -//│ this: #Anemo & #Geo & #Mixed //│ fun get: bool //│ fun ter: nothing //│ let v: 2 @@ -92,46 +100,109 @@ class F extends Oth, M, Mixed { //│ } let c = C() +//│ let c: C & #Test + c.foo +//│ int + c.bar(true) -//│ let c: C //│ bool -// FIXME c: Test -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.101: c: Test -//│ ║ ^ -//│ ╟── application of type `C` is not an instance of type `Test` -//│ ║ l.94: let c = C() -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `#Test` -//│ ║ l.101: c: Test -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.101: c: Test -//│ ╙── ^^^^ +let c1: Test = C() +//│ let c1: Test +//│ Test + +:d +fun fcc(x: C) = x.foo +//│ 0. Typing TypingUnit(List(fun fcc = (x: C,) => (x).foo)) +//│ | 0. Created lazy type info for fun fcc = (x: C,) => (x).foo +//│ | Completing fun fcc = (x: C,) => (x).foo +//│ | | UNSTASHING... (out) +//│ | | Type params +//│ | | UNSTASHING... (out) +//│ | | Params +//│ | | 1. Typing term (x: C,) => (x).foo +//│ | | | 1. Typing pattern x: C, +//│ | | | | 1. Typing pattern x : C +//│ | | | | | Typing type TypeName(C) +//│ | | | | | | vars=Map() newDefsInfo=Map() +//│ | | | | | | 1. type TypeName(C) +//│ | | | | | | => C +//│ | | | | | => C ——— +//│ | | | | 1. : C +//│ | | | 1. : (x: C,) +//│ | | | 1. Typing term (x).foo +//│ | | | | 1. Typing term x +//│ | | | | 1. : C +//│ | | | | CONSTRAIN C {}∧#Test) {}∧#Test <: DNF(1, {foo: foo76'}) +//│ | | | | | | Possible: List({foo: foo76'}) +//│ | | | | | | 1. A C{}∧#Test % List() {}∧#Test % List() {}∧#Test % List() foo76') +//│ | | UNSTASHING... (out) +//│ | | CONSTRAIN ((x: C,) -> foo76') Int +//│ | | 1. C ((x: C,) -> foo76') foo76')› where +//│ | foo76' :> Int +//│ fun fcc: (x: C,) -> int + +fun fc(x: Test) = x +//│ fun fc: (x: Test,) -> Test + +fc(c) //│ Test +fun fts['a](x: 'a & Test) = x.foo +fts(c) +//│ fun fts: forall 'foo. (x: Test & {foo: 'foo} | Test & ~#Test,) -> 'foo +//│ int + // FIXME -let c1: Test = C() -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.117: let c1: Test = C() -//│ ║ ^^^ -//│ ╟── application of type `C` is not an instance of type `Test` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.117: let c1: Test = C() -//│ ╙── ^^^^ -//│ let c1: Test +fts(c1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.233: fts(c1) +//│ ║ ^^^^^^^ +//│ ╟── type `#Test` does not match type `{foo: ?foo} | ~#Test` +//│ ║ l.163: let c1: Test = C() +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `{foo: ?foo} | ~#Test` +//│ ║ l.233: fts(c1) +//│ ║ ^^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.227: fun fts['a](x: 'a & Test) = x.foo +//│ ║ ^^^^^ +//│ ╟── from intersection type: +//│ ║ l.227: fun fts['a](x: 'a & Test) = x.foo +//│ ╙── ^^^^^^^^^ +//│ error trait A1 { fun a1: 1 | 2 | 3 } trait A2 { fun a1: 2 | 3 | 4 } //│ trait A1() { -//│ this: #A1 //│ fun a1: 1 | 2 | 3 //│ } //│ trait A2() { -//│ this: #A2 //│ fun a1: 2 | 3 | 4 //│ } @@ -140,19 +211,19 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.140: fun a1 = 4 +//│ ║ l.262: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.140: fun a1 = 4 +//│ ║ l.262: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.140: fun a1 = 4 +//│ ║ l.262: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.127: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.251: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.127: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.251: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 @@ -162,7 +233,6 @@ trait Ele { fun ce: Oth -> Test } //│ trait Ele() { -//│ this: #Ele //│ fun ce: Oth -> Test //│ } @@ -179,11 +249,11 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.178: class E1 extends Test { +//│ ║ l.299: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.179: fun foo = 2 +//│ ║ l.300: fun foo = 2 //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.180: } +//│ ║ l.301: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -194,17 +264,13 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.194: trait TE1 extends C +//│ ║ l.315: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.195: trait TE2 extends M, Test +//│ ║ l.316: trait TE2 extends M, Test //│ ╙── ^ -//│ trait TE1() { -//│ this: #TE1 -//│ } -//│ trait TE2() { -//│ this: #TE2 -//│ } +//│ trait TE1() +//│ trait TE2() :e class E2 extends Test { @@ -212,13 +278,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.211: fun foo = true +//│ ║ l.328: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.211: fun foo = true +//│ ║ l.328: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.211: fun foo = true +//│ ║ l.328: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -235,10 +301,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.236: class D extends Test[int], Test[bool] +//│ ║ l.353: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.236: class D extends Test[int], Test[bool] +//│ ║ l.353: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -247,9 +313,7 @@ class D extends Test[int], Test[bool] trait Base: A | B class A class B -//│ trait Base() { -//│ this: #Base -//│ } +//│ trait Base() //│ class A() //│ class B() @@ -257,30 +321,30 @@ class B // FIXME let b: Base = A() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.258: let b: Base = A() +//│ ║ l.373: let b: Base = A() //│ ║ ^^^ //│ ╟── application of type `A` is not an instance of type `Base` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.258: let b: Base = A() +//│ ║ l.373: let b: Base = A() //│ ╙── ^^^^ //│ let b: Base // FIXME b: Base & (A | B) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.269: b: Base & (A | B) +//│ ║ l.384: b: Base & (A | B) //│ ║ ^ //│ ╟── type `#Base` does not match type `A | B` -//│ ║ l.258: let b: Base = A() +//│ ║ l.373: let b: Base = A() //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `A | B` -//│ ║ l.269: b: Base & (A | B) +//│ ║ l.384: b: Base & (A | B) //│ ║ ^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.269: b: Base & (A | B) +//│ ║ l.384: b: Base & (A | B) //│ ║ ^^^^^^^ //│ ╟── from intersection type: -//│ ║ l.269: b: Base & (A | B) +//│ ║ l.384: b: Base & (A | B) //│ ╙── ^^^^^^^^^^^^^^ //│ A & Base | B & Base @@ -289,57 +353,87 @@ b: Base & (A | B) trait Base: Foo | Bar class Foo[A] class Bar[B] -//│ trait Base() { -//│ this: #Base -//│ } +//│ trait Base() //│ class Foo[A]() //│ class Bar[B]() // FIXME fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.299: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.412: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error //│ ╙── ^^^^ //│ -let ot : Oth -let tt : Test -//│ let ot: Oth -//│ let tt: Test +trait Geo +trait ZL extends Geo +trait GL extends Geo +trait WP extends ZL, GL +trait EM extends WP, Geo +//│ trait Geo() +//│ trait ZL() +//│ trait GL() +//│ trait WP() +//│ trait EM() -fun fot(x: Oth): Test = x -ot : Test -//│ fun fot: (x: Oth,) -> Test -//│ Test +let g: Geo +let z: ZL +let w: WP +let e: EM +//│ let g: Geo +//│ let z: ZL +//│ let w: WP +//│ let e: EM + +fun fot(x: EM): Geo = x +fun fit(x: EM): WP = x +w: Geo +z: Geo +e: WP +//│ fun fot: (x: EM,) -> Geo +//│ fun fit: (x: EM,) -> WP +//│ WP :e -tt : Oth -fun fto(x: Test): Oth = x +fun fto(w: WP): EM = w +z: WP +g: ZL +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.450: fun fto(w: WP): EM = w +//│ ║ ^ +//│ ╟── type `#GL & #Geo & #WP & #ZL` is not an instance of type `EM` +//│ ║ l.450: fun fto(w: WP): EM = w +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `#EM` +//│ ║ l.450: fun fto(w: WP): EM = w +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.450: fun fto(w: WP): EM = w +//│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.319: fun fto(x: Test): Oth = x -//│ ║ ^ -//│ ╟── type `#Test` is not an instance of type `Oth` -//│ ║ l.319: fun fto(x: Test): Oth = x -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `#Oth` -//│ ║ l.319: fun fto(x: Test): Oth = x -//│ ║ ^ +//│ ║ l.451: z: WP +//│ ║ ^ +//│ ╟── type `#Geo & #ZL` is not an instance of type `WP` +//│ ║ l.432: let z: ZL +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `#WP` +//│ ║ l.451: z: WP +//│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.319: fun fto(x: Test): Oth = x -//│ ╙── ^^^ +//│ ║ l.451: z: WP +//│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.318: tt : Oth -//│ ║ ^^ -//│ ╟── type `#Test` is not an instance of type `Oth` -//│ ║ l.308: let tt : Test -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `#Oth` -//│ ║ l.318: tt : Oth -//│ ║ ^^ +//│ ║ l.452: g: ZL +//│ ║ ^ +//│ ╟── type `#Geo` is not an instance of type `ZL` +//│ ║ l.431: let g: Geo +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `#ZL` +//│ ║ l.452: g: ZL +//│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.318: tt : Oth -//│ ╙── ^^^ -//│ fun fto: (x: Test,) -> Oth -//│ Oth +//│ ║ l.452: g: ZL +//│ ╙── ^^ +//│ fun fto: (w: WP,) -> EM +//│ ZL From ed223a1dae869a30d19fc74db1f5f90d3ae46fac Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 19 Apr 2023 17:18:03 +0800 Subject: [PATCH 241/498] WIP Fix trait member resolution (tests broken) --- .../scala/mlscript/ConstraintSolver.scala | 223 ++++++++------- .../src/main/scala/mlscript/NuTypeDefs.scala | 8 +- shared/src/test/diff/nu/Interfaces.mls | 268 +++++++----------- 3 files changed, 231 insertions(+), 268 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 8d28ff41c3..c026ffde12 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -50,127 +50,149 @@ class ConstraintSolver extends NormalForms { self: Typer => } } - def lookupField(clsNme: Str, rfnt: Var => Opt[FieldType], fld: Var) + def lookupField(clsNme: Opt[Str], rfnt: Var => Opt[FieldType], tags: SortedSet[AbstractTag], fld: Var) (implicit ctx: Ctx, raise: Raise) : FieldType = { - val info = ctx.tyDefs2(clsNme) + + // val info = ctx.tyDefs2(clsNme) // require(!info.isComputing) // TODO intersect with found signature! val fromRft = rfnt(fld) - def nope = - err(noSuchMember(info, fld)).toUpper(noProv) - - // * The raw type of this member, with original references to the class' type variables/type parameters - val raw = if (info.isComputing) { + def getFieldType(info: DelayedTypeInfo): FieldType = { - info.typedFields.get(fld) match { - case S(fty) => S(fty) - case N => - fromRft match { - case S(fty) => - N - case N => - if (info.allFields.contains(fld)) - S(err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv)) - else - S(nope) - } - } + def nope = + err(noSuchMember(info, fld)).toUpper(noProv) - } else info.complete() match { - case cls: TypedNuCls => - cls.members.get(fld.name) match { - case S(d: TypedNuFun) => - S(d.typeSignature.toUpper(provTODO)) - case S(p: NuParam) => - S(p.ty) - case S(m) => - S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) - case N => - fromRft match { - case S(fty) => N - case N => S(nope) - } - } - - case trt: TypedNuTrt => - trt.members.get(fld.name) match { - case S(d: TypedNuFun) => - S(d.typeSignature.toUpper(provTODO)) - case S(p: NuParam) => - S(p.ty) - case S(m) => - S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) + // * The raw type of this member, with original references to the class' type variables/type parameters + val raw = if (info.isComputing) { + + info.typedFields.get(fld) match { + case S(fty) => S(fty) case N => fromRft match { - case S(fty) => N - case N => S(nope) + case S(fty) => + N + case N => + if (info.allFields.contains(fld)) + S(err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv)) + else + S(nope) } } - case _ => ??? // TODO - } - - println(s"Lookup ${info.decl.name}.${fld.name} : $raw where ${raw.fold("")(_.ub.showBounds)}") - - - val freshenedRaw = raw.fold(TopType.toUpper(noProv)) { raw => - - // TODO dedup with below logic from `lookupNuTypeDef` + } else info.complete() match { + case cls: TypedNuCls => + cls.members.get(fld.name) match { + case S(d: TypedNuFun) => + S(d.typeSignature.toUpper(provTODO)) + case S(p: NuParam) => + S(p.ty) + case S(m) => + S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) + case N => + fromRft match { + case S(fty) => N + case N => S(nope) + } + } + + case trt: TypedNuTrt => + trt.members.get(fld.name) match { + case S(d: TypedNuFun) => + S(d.typeSignature.toUpper(provTODO)) + case S(p: NuParam) => + S(p.ty) + case S(m) => + S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) + case N => + fromRft match { + case S(fty) => N + case N => S(nope) + } + } + + case _ => ??? // TODO + } - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - info.tparams.foreach { case (tn, _tv, vi) => - val targ = rfnt(Var(info.decl.name + "#" + tn.name)) match { - case S(fty) => - TypeBounds.mk( - fty.lb.getOrElse(BotType), - fty.ub, - ) - case N => - // FIXME type bounds are kind of wrong for this - TypeBounds( - // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), - // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), - _tv.lowerBounds.foldLeft( - Extruded(false, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST - // ^ TODO provide extrusion reason? - )(_ | _), - _tv.upperBounds.foldLeft( - Extruded(true, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST - // ^ TODO provide extrusion reason? - )(_ & _), - )(_tv.prov) - } + println(s"Lookup ${info.decl.name}.${fld.name} : $raw where ${raw.fold("")(_.ub.showBounds)}") + + + val freshenedRaw = raw.fold(TopType.toUpper(noProv)) { raw => + + // TODO dedup with below logic from `lookupNuTypeDef` - freshened += _tv -> (targ match { - case tv: TypeVarOrRigidVar => tv - case _ => - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - tv - }) + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + info.tparams.foreach { case (tn, _tv, vi) => + val targ = rfnt(Var(info.decl.name + "#" + tn.name)) match { + case S(fty) => + TypeBounds.mk( + fty.lb.getOrElse(BotType), + fty.ub, + ) + case N => + // FIXME type bounds are kind of wrong for this + TypeBounds( + // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), + // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), + _tv.lowerBounds.foldLeft( + Extruded(false, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ | _), + _tv.upperBounds.foldLeft( + Extruded(true, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST + // ^ TODO provide extrusion reason? + )(_ & _), + )(_tv.prov) + } + + freshened += _tv -> (targ match { + case tv: TypeVarOrRigidVar => tv + case _ => + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) + + } + + raw.freshenAbove(info.level, rigidify = false) } - raw.freshenAbove(info.level, rigidify = false) + println(s"Fresh ${info.decl.name}.${fld.name} : $freshenedRaw where ${freshenedRaw.ub.showBounds}") + + freshenedRaw + } + + val fromCls = clsNme.map(clsNme => getFieldType(ctx.tyDefs2(clsNme))) + + val fromTrts = tags.toList.collect { + case TraitTag(nme) => + getFieldType(ctx.tyDefs2(nme.name)) } - println(s"Fresh ${info.decl.name}.${fld.name} : $freshenedRaw where ${freshenedRaw.ub.showBounds}") + val fields = fromRft.toList ::: fromCls.toList ::: fromTrts println(s" & ${fromRft} (from refinement)") - fromRft.foldRight(freshenedRaw)(_ && _) + // fromRft.foldRight(freshenedRaw)(_ && _) + + fields match { + case x :: xs => + xs.foldRight(x)(_ && _) + case Nil => ??? // TODO + } } @@ -634,7 +656,7 @@ class ConstraintSolver extends NormalForms { self: Typer => if ctx.tyDefs2.contains(nme) => if (newDefs && fldNme.name === "Eql#A") { val info = ctx.tyDefs2(nme) info.typedParams.foreach { p => - val fty = lookupField(nme, r.fields.toMap.get, p._1) + val fty = lookupField(S(nme), r.fields.toMap.get, ts, p._1) rec(fldTy.lb.get, RecordType(p._1 -> TypeRef(TypeName("Eql"), fty.ub // FIXME check mutable? :: Nil @@ -646,7 +668,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? // else { // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) - val fty = lookupField(nme, r.fields.toMap.get, fldNme) + val fty = lookupField(S(nme), r.fields.toMap.get, ts, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) // } @@ -659,7 +681,12 @@ class ConstraintSolver extends NormalForms { self: Typer => case (lr @ LhsRefined(bo, ts, r, _), rf @ RhsField(n, t2)) => // Reuse the case implemented below: (this shortcut adds a few more annoying calls in stats) annoying(Nil, lr, Nil, RhsBases(Nil, S(R(rf)), SortedMap.empty)) + case (LhsRefined(N, ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) => + val fty = lookupField(N, r.fields.toMap.get, ts, fldNme) + rec(fty.ub, fldTy.ub, false) + recLb(fldTy, fty) case (LhsRefined(bo, ts, r, _), RhsBases(ots, S(R(RhsField(n, t2))), trs)) => + // TODO simplify - merge with above? r.fields.find(_._1 === n) match { case S(nt1) => recLb(t2, nt1._2) @@ -876,7 +903,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case (fldNme @ Var("Eql#A"), fldTy) => goToWork(lhs, RecordType(fldNme -> fldTy :: Nil)(noProv)) case (fldNme, fldTy) => - val fty = lookupField(nme, _ => N, fldNme) + val fty = lookupField(S(nme), _ => N, SortedSet.empty, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index e162b16499..560b9ab504 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -192,7 +192,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), sign.map(f(pol, _)), - tags + f(pol, tags), ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -201,7 +201,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), sign.map(f(pol, _)), - tags + f(pol, tags), ) } @@ -356,7 +356,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, tags: ST = TopType): ST = td.kind match { + def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, tags: ST): ST = td.kind match { case Nms => ClassTag(Var(td.nme.name), // TODO base classes @@ -975,7 +975,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => die } case td: NuTypeDef => - typeSignatureOf(td, level, tparams, typedParams) + typeSignatureOf(td, level, tparams, typedParams, TopType) } override def toString: String = diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 90ef80187a..cf02fc6ab5 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -2,30 +2,44 @@ :NoJS trait Test { - fun foo: int - fun bar: bool -> bool + fun foo: int + fun bar: bool -> bool } //│ trait Test() { //│ fun bar: bool -> bool //│ fun foo: int //│ } -// FIXME fun ts(x: Test) = x.foo -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.14: fun ts(x: Test) = x.foo -//│ ║ ^^^^^ -//│ ╟── type `Test` does not have field 'foo' -//│ ║ l.14: fun ts(x: Test) = x.foo -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `{foo: ?foo}` -//│ ║ l.14: fun ts(x: Test) = x.foo -//│ ╙── ^ -//│ fun ts: (x: Test,) -> error +//│ fun ts: (x: Test,) -> int + + +module M extends Test { + fun foo = 0 + fun bar = not +} +//│ module M() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } + +// TODO for modules +ts(M) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.27: ts(M) +//│ ║ ^^^^^ +//│ ╟── reference of type `M` is not an instance of type `Test` +//│ ║ l.27: ts(M) +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.13: fun ts(x: Test) = x.foo +//│ ╙── ^^^^ +//│ error | int + trait Oth extends Test { - let a : int - fun cool : int -> bool + let a : int + fun cool : int -> bool } //│ trait Oth() { //│ let a: int @@ -35,14 +49,14 @@ trait Oth extends Test { //│ } trait Geo { - let v: 2 | 3 - fun get: int | bool - fun ter: int + let v: 2 | 3 + fun get: int | bool + fun ter: int } trait Anemo { - let v: 1 | 2 - fun get: bool | string - fun ter: bool + let v: 1 | 2 + fun get: bool | string + fun ter: bool } //│ trait Geo() { //│ fun get: bool | int @@ -64,8 +78,8 @@ trait Mixed extends Geo, Anemo class C extends Test { - fun foo = 1 - fun bar(x) = x + fun foo = 1 + fun bar(x) = x } //│ class C() { //│ fun bar: bool -> bool @@ -73,20 +87,20 @@ class C extends Test { //│ } mixin M { - fun m1 = 3 + fun m1 = 3 } //│ mixin M() { //│ fun m1: 3 //│ } class F extends Oth, M, Mixed { - fun cool(x) = x == 1 - fun foo = 2 - fun bar(x) = x - fun get = true - fun ter = ter - let a = 3 - let v = 2 + fun cool(x) = x == 1 + fun foo = 2 + fun bar(x) = x + fun get = true + fun ter = ter + let a = 3 + let v = 2 } //│ class F() { //│ let a: int @@ -113,58 +127,8 @@ let c1: Test = C() //│ let c1: Test //│ Test -:d +// :d fun fcc(x: C) = x.foo -//│ 0. Typing TypingUnit(List(fun fcc = (x: C,) => (x).foo)) -//│ | 0. Created lazy type info for fun fcc = (x: C,) => (x).foo -//│ | Completing fun fcc = (x: C,) => (x).foo -//│ | | UNSTASHING... (out) -//│ | | Type params -//│ | | UNSTASHING... (out) -//│ | | Params -//│ | | 1. Typing term (x: C,) => (x).foo -//│ | | | 1. Typing pattern x: C, -//│ | | | | 1. Typing pattern x : C -//│ | | | | | Typing type TypeName(C) -//│ | | | | | | vars=Map() newDefsInfo=Map() -//│ | | | | | | 1. type TypeName(C) -//│ | | | | | | => C -//│ | | | | | => C ——— -//│ | | | | 1. : C -//│ | | | 1. : (x: C,) -//│ | | | 1. Typing term (x).foo -//│ | | | | 1. Typing term x -//│ | | | | 1. : C -//│ | | | | CONSTRAIN C {}∧#Test) {}∧#Test <: DNF(1, {foo: foo76'}) -//│ | | | | | | Possible: List({foo: foo76'}) -//│ | | | | | | 1. A C{}∧#Test % List() {}∧#Test % List() {}∧#Test % List() foo76') -//│ | | UNSTASHING... (out) -//│ | | CONSTRAIN ((x: C,) -> foo76') Int -//│ | | 1. C ((x: C,) -> foo76') foo76')› where -//│ | foo76' :> Int //│ fun fcc: (x: C,) -> int fun fc(x: Test) = x @@ -178,24 +142,8 @@ fts(c) //│ fun fts: forall 'foo. (x: Test & {foo: 'foo} | Test & ~#Test,) -> 'foo //│ int -// FIXME fts(c1) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.233: fts(c1) -//│ ║ ^^^^^^^ -//│ ╟── type `#Test` does not match type `{foo: ?foo} | ~#Test` -//│ ║ l.163: let c1: Test = C() -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `{foo: ?foo} | ~#Test` -//│ ║ l.233: fts(c1) -//│ ║ ^^ -//│ ╟── Note: constraint arises from field selection: -//│ ║ l.227: fun fts['a](x: 'a & Test) = x.foo -//│ ║ ^^^^^ -//│ ╟── from intersection type: -//│ ║ l.227: fun fts['a](x: 'a & Test) = x.foo -//│ ╙── ^^^^^^^^^ -//│ error +//│ int trait A1 { fun a1: 1 | 2 | 3 } trait A2 { fun a1: 2 | 3 | 4 } @@ -208,37 +156,36 @@ trait A2 { fun a1: 2 | 3 | 4 } :e class Ea1 extends A1, A2 { - fun a1 = 4 + fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.262: fun a1 = 4 -//│ ║ ^^^^^^ +//│ ║ l.159: fun a1 = 4 +//│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.262: fun a1 = 4 -//│ ║ ^ +//│ ║ l.159: fun a1 = 4 +//│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.262: fun a1 = 4 -//│ ║ ^^^^^^ +//│ ║ l.159: fun a1 = 4 +//│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.251: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.148: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.251: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.148: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 //│ } trait Ele { - fun ce: Oth -> Test + fun ce: Oth -> Test } //│ trait Ele() { //│ fun ce: Oth -> Test //│ } -// FIXME class CE extends Ele { - fun ce(x) = x + fun ce(x) = x } //│ class CE() { //│ fun ce: Oth -> Test @@ -246,14 +193,14 @@ class CE extends Ele { :e class E1 extends Test { - fun foo = 2 + fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.299: class E1 extends Test { +//│ ║ l.195: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.300: fun foo = 2 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.301: } +//│ ║ l.196: fun foo = 2 +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.197: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -264,34 +211,34 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.315: trait TE1 extends C +//│ ║ l.211: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.316: trait TE2 extends M, Test +//│ ║ l.212: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() //│ trait TE2() :e class E2 extends Test { - fun foo = true - fun bar(x) = x + fun foo = true + fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.328: fun foo = true -//│ ║ ^^^^^^^^^^ +//│ ║ l.224: fun foo = true +//│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.328: fun foo = true -//│ ║ ^^^^ +//│ ║ l.224: fun foo = true +//│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.328: fun foo = true -//│ ║ ^^^^^^^^^^ +//│ ║ l.224: fun foo = true +//│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: fun foo: int -//│ ║ ^^^ +//│ ║ l.5: fun foo: int +//│ ║ ^^^ //│ ╟── from signature of member foo: -//│ ║ l.5: fun foo: int -//│ ╙── ^^^^^^^^ +//│ ║ l.5: fun foo: int +//│ ╙── ^^^^^^^^ //│ class E2() { //│ fun bar: bool -> bool //│ fun foo: int @@ -301,70 +248,59 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.353: class D extends Test[int], Test[bool] +//│ ║ l.249: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.353: class D extends Test[int], Test[bool] +//│ ║ l.249: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() trait Base: A | B -class A -class B +class A extends Base +class B extends Base //│ trait Base() //│ class A() //│ class B() -// FIXME let b: Base = A() -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.373: let b: Base = A() -//│ ║ ^^^ -//│ ╟── application of type `A` is not an instance of type `Base` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.373: let b: Base = A() -//│ ╙── ^^^^ //│ let b: Base // FIXME b: Base & (A | B) //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.384: b: Base & (A | B) +//│ ║ l.272: b: Base & (A | B) //│ ║ ^ //│ ╟── type `#Base` does not match type `A | B` -//│ ║ l.373: let b: Base = A() +//│ ║ l.268: let b: Base = A() //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `A | B` -//│ ║ l.384: b: Base & (A | B) +//│ ║ l.272: b: Base & (A | B) //│ ║ ^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.384: b: Base & (A | B) +//│ ║ l.272: b: Base & (A | B) //│ ║ ^^^^^^^ //│ ╟── from intersection type: -//│ ║ l.384: b: Base & (A | B) +//│ ║ l.272: b: Base & (A | B) //│ ╙── ^^^^^^^^^^^^^^ //│ A & Base | B & Base -// FIXME trait Base: Foo | Bar -class Foo[A] -class Bar[B] +class Foo[A] extends Base +class Bar[B] extends Base //│ trait Base() //│ class Foo[A]() //│ class Bar[B]() -// FIXME +// TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.412: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.299: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error - //│ ╙── ^^^^ -//│ trait Geo trait ZL extends Geo @@ -400,40 +336,40 @@ fun fto(w: WP): EM = w z: WP g: ZL //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.450: fun fto(w: WP): EM = w +//│ ║ l.335: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#GL & #Geo & #WP & #ZL` is not an instance of type `EM` -//│ ║ l.450: fun fto(w: WP): EM = w +//│ ║ l.335: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.450: fun fto(w: WP): EM = w +//│ ║ l.335: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.450: fun fto(w: WP): EM = w +//│ ║ l.335: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.451: z: WP +//│ ║ l.336: z: WP //│ ║ ^ //│ ╟── type `#Geo & #ZL` is not an instance of type `WP` -//│ ║ l.432: let z: ZL +//│ ║ l.317: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.451: z: WP +//│ ║ l.336: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.451: z: WP +//│ ║ l.336: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.452: g: ZL +//│ ║ l.337: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.431: let g: Geo +//│ ║ l.316: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.452: g: ZL +//│ ║ l.337: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.452: g: ZL +//│ ║ l.337: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ ZL From e1eb718093f065b6b97af71012d80ddee1c73207 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 19 Apr 2023 17:49:11 +0800 Subject: [PATCH 242/498] WIP --- .../scala/mlscript/ConstraintSolver.scala | 2 + .../src/main/scala/mlscript/NuTypeDefs.scala | 42 ++- shared/src/main/scala/mlscript/TypeDefs.scala | 1 + .../main/scala/mlscript/TyperHelpers.scala | 7 +- shared/src/test/diff/nu/Interfaces.mls | 270 ++++++++++++++---- 5 files changed, 258 insertions(+), 64 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index c026ffde12..15739c3f89 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1165,6 +1165,8 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(ov.approximatePos, rhs, true) case (_: NegType | _: Without, _) | (_, _: NegType | _: Without) => goToWork(lhs, rhs) + case (_: ClassTag | _: TraitTag, _: TraitTag) => + goToWork(lhs, rhs) case _ => reportError() }} }}() diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 560b9ab504..a62f5e1c52 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -175,7 +175,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members: Map[Str, NuMember], thisTy: ST, sign: Opt[ST], - tags: ST + selfTy: ST ) extends TypedNuTypeDef(Trt) with TypedNuTermDef { def decl: NuTypeDef = td @@ -183,7 +183,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, tags) + def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -192,7 +192,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), sign.map(f(pol, _)), - f(pol, tags), + f(pol, selfTy), ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -201,7 +201,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), sign.map(f(pol, _)), - f(pol, tags), + f(pol, selfTy), ) } @@ -275,7 +275,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), - tags + f(pol, tags), )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -284,7 +284,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), - tags + f(pol, tags), )(f(pol, instanceType)) } @@ -477,6 +477,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => println(s"${ctx.lvl}. Created lazy type info for $decl") + // YTODO: + // Add here thes ecomputations: + // type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) + // val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { + // and derive from these the full set of transitively inherited tags + lazy val tparams: TyParams = ctx.nest.nextLevel { implicit ctx => decl match { case td: NuTypeDef => @@ -672,7 +678,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx ++= paramSymbols ctx += "this" -> VarSymbol(thisTV, Var("this")) - + + val sig_ty = typeType(td.sig.getOrElse(Top)) + // td.sig match { + // case S(sig) => + // case N => () + // } + // inherit traits def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember]) : (ST, ST, Ls[NuMember]) = @@ -681,7 +693,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.get(trtName) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { case trt: TypedNuTrt => - inherit(ps, superType & trt.thisTy, tags & trt.tags, memberUn(members, trt.members.values.toList)) + inherit(ps, superType & trt.thisTy, tags & trt.selfTy, memberUn(members, trt.members.values.toList)) case _ => err(msg"trait can only inherit traits", p.toLoc) (superType, tags, members) @@ -693,13 +705,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (thisType, tags, baseMems) = // ? is it really a good idea - inherit(parentSpecs, TopType, trtNameToNomTag(td)(noProv, ctx), Nil) - + inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil) + + // val selfType = tags & sig_ty + val selfType = sig_ty + val ttu = typeTypingUnit(td.body, topLevel = false) val trtMems = baseMems ++ ttu.entities val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap - TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, tags) -> Nil + TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType) -> Nil } case Als => @@ -878,7 +893,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => info match { case trt: TypedNuTrt => // TODO also computer intersect - computeInterface(ps, annot & trt.tags, memberUn(members, trt.members.values.toList)) // intersect members + computeInterface(ps, annot & trt.selfTy, memberUn(members, trt.members.values.toList)) // intersect members case _ => computeInterface(ps, annot, members) } case S(_) => @@ -910,7 +925,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams, typedParams, mems ++ ifaceMembers.map(d => d.name -> d).toMap, // if (td.kind is Nms) TopType else thisTV TopType, - ifaceAnnot, + // ifaceAnnot, + TopType, // TODO use signature )(thisType) -> impltdMems } case Mxn => diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 6392acb825..f6d103b9ad 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -112,6 +112,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => def clsNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { require((td.kind is Cls) || (td.kind is Nms) || (td.kind is Trt), td.kind) + // YTODO: use ctx.tyDefs2 to get the lazy type info and the iags ClassTag(Var(td.nme.name), // ctx.allBaseClassesOf(td.nme.name) Set.single(TypeName("Eql")) // TODO superclasses diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 08d8f380ca..282c339b9c 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -997,7 +997,9 @@ abstract class TyperHelpers { Typer: Typer => }.toMap) case S(td: TypedNuTrt) => assert(td.tparams.size === targs.size) - td.tags & RecordType(info.tparams.lazyZip(targs).map { + td.selfTy & + trtNameToNomTag(td.decl)(provTODO, ctx) & + RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.nme.name + "#" + tn.name Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) @@ -1005,7 +1007,8 @@ abstract class TyperHelpers { Typer: Typer => case S(td: TypedNuCls) => assert(td.tparams.size === targs.size) clsNameToNomTag(td.decl)(provTODO, ctx) & - td.tags & RecordType(info.tparams.lazyZip(targs).map { + td.tags & + RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.nme.name + "#" + tn.name Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index cf02fc6ab5..1e28ade25f 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -114,7 +114,7 @@ class F extends Oth, M, Mixed { //│ } let c = C() -//│ let c: C & #Test +//│ let c: C c.foo //│ int @@ -123,9 +123,90 @@ c.bar(true) //│ bool c: Test +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.125: c: Test +//│ ║ ^ +//│ ╟── application of type `C` is not an instance of type `Test` +//│ ║ l.116: let c = C() +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `#Test` +//│ ║ l.125: c: Test +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.125: c: Test +//│ ╙── ^^^^ +//│ Test + +:d let c1: Test = C() +//│ 0. Typing TypingUnit(List(let c1 = C () : Test)) +//│ | 0. Created lazy type info for let c1 = C () : Test +//│ | Completing let c1 = C () : Test +//│ | | UNSTASHING... (out) +//│ | | Type params +//│ | | UNSTASHING... (out) +//│ | | Params +//│ | | 0. Typing term C () : Test +//│ | | | 0. Typing term C () +//│ | | | | 0. Typing term C +//│ | | | | 0. : (() -> C) +//│ | | | | CONSTRAIN (() -> C) α80) +//│ | | | | where +//│ | | | | 0. C (() -> C) α80) (0) +//│ | | | | | 0. C () Test +//│ | | | => Test ——— +//│ | | | CONSTRAIN α80 C +//│ | | | 0. C α80 {}) {} <: DNF(0, {}∧#Test) +//│ | | | | | | | Possible: List({}∧#Test) +//│ | | | | | | | 0. A C{} % List() {} % List() <: #Test +//│ | | | | | | | | | | allVarPols: +//│ | | | | | | | | | | normLike[+] C +//│ | | | | | | | | | | | norm[+] C +//│ | | | | | | | | | | | | DNF: DNF(0, C{}) +//│ | | | | | | | | | | | | rcd2 {} +//│ | | | | | | | | | | | | typeRef C +//│ | | | | | | | | | | | | clsFields +//│ | | | | | | | | | | | ~> C +//│ | | | | | | | | | | CONSTRAIN error<> 'foo -//│ int +//│ error | int fts(c1) //│ int @@ -159,19 +255,19 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.159: fun a1 = 4 +//│ ║ l.255: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.159: fun a1 = 4 +//│ ║ l.255: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.159: fun a1 = 4 +//│ ║ l.255: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.148: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.244: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.148: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.244: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 @@ -187,6 +283,18 @@ trait Ele { class CE extends Ele { fun ce(x) = x } +//│ ╔══[ERROR] Type mismatch in definition of method ce: +//│ ║ l.284: fun ce(x) = x +//│ ║ ^^^^^^^^^ +//│ ╟── type `#Oth` is not an instance of type `Test` +//│ ║ l.277: fun ce: Oth -> Test +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `#Test` +//│ ║ l.284: fun ce(x) = x +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.277: fun ce: Oth -> Test +//│ ╙── ^^^^ //│ class CE() { //│ fun ce: Oth -> Test //│ } @@ -196,11 +304,11 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.195: class E1 extends Test { +//│ ║ l.303: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.196: fun foo = 2 +//│ ║ l.304: fun foo = 2 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.197: } +//│ ║ l.305: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -211,10 +319,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.211: trait TE1 extends C +//│ ║ l.319: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.212: trait TE2 extends M, Test +//│ ║ l.320: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() //│ trait TE2() @@ -225,13 +333,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.224: fun foo = true +//│ ║ l.332: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.224: fun foo = true +//│ ║ l.332: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.224: fun foo = true +//│ ║ l.332: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -248,10 +356,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.249: class D extends Test[int], Test[bool] +//│ ║ l.357: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.249: class D extends Test[int], Test[bool] +//│ ║ l.357: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -266,31 +374,33 @@ class B extends Base let b: Base = A() +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.376: let b: Base = A() +//│ ║ ^^^ +//│ ╟── application of type `A` is not an instance of type `Base` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.376: let b: Base = A() +//│ ╙── ^^^^ //│ let b: Base -// FIXME b: Base & (A | B) -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.272: b: Base & (A | B) -//│ ║ ^ -//│ ╟── type `#Base` does not match type `A | B` -//│ ║ l.268: let b: Base = A() -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `A | B` -//│ ║ l.272: b: Base & (A | B) -//│ ║ ^ -//│ ╟── Note: constraint arises from union type: -//│ ║ l.272: b: Base & (A | B) -//│ ║ ^^^^^^^ -//│ ╟── from intersection type: -//│ ║ l.272: b: Base & (A | B) -//│ ╙── ^^^^^^^^^^^^^^ //│ A & Base | B & Base +if b is + A then 0 + B then 1 +//│ 0 | 1 + trait Base: Foo | Bar class Foo[A] extends Base class Bar[B] extends Base +//│ ╔══[ERROR] Type Foo takes parameters +//│ ║ l.395: trait Base: Foo | Bar +//│ ╙── ^^^ +//│ ╔══[ERROR] Type Bar takes parameters +//│ ║ l.395: trait Base: Foo | Bar +//│ ╙── ^^^ //│ trait Base() //│ class Foo[A]() //│ class Bar[B]() @@ -298,7 +408,7 @@ class Bar[B] extends Base // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.299: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.409: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -327,6 +437,66 @@ fun fit(x: EM): WP = x w: Geo z: Geo e: WP +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ║ ^ +//│ ╟── type `#EM` is not an instance of type `Geo` +//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `#Geo` +//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.436: fun fit(x: EM): WP = x +//│ ║ ^ +//│ ╟── type `#EM` is not an instance of type `WP` +//│ ║ l.436: fun fit(x: EM): WP = x +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `#WP` +//│ ║ l.436: fun fit(x: EM): WP = x +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.436: fun fit(x: EM): WP = x +//│ ╙── ^^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.437: w: Geo +//│ ║ ^ +//│ ╟── type `#WP` is not an instance of type `Geo` +//│ ║ l.428: let w: WP +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `#Geo` +//│ ║ l.437: w: Geo +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.437: w: Geo +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.438: z: Geo +//│ ║ ^ +//│ ╟── type `#ZL` is not an instance of type `Geo` +//│ ║ l.427: let z: ZL +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `#Geo` +//│ ║ l.438: z: Geo +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.438: z: Geo +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.439: e: WP +//│ ║ ^ +//│ ╟── type `#EM` is not an instance of type `WP` +//│ ║ l.429: let e: EM +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `#WP` +//│ ║ l.439: e: WP +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.439: e: WP +//│ ╙── ^^ //│ fun fot: (x: EM,) -> Geo //│ fun fit: (x: EM,) -> WP //│ WP @@ -336,40 +506,42 @@ fun fto(w: WP): EM = w z: WP g: ZL //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.335: fun fto(w: WP): EM = w +//│ ║ l.505: fun fto(w: WP): EM = w //│ ║ ^ -//│ ╟── type `#GL & #Geo & #WP & #ZL` is not an instance of type `EM` -//│ ║ l.335: fun fto(w: WP): EM = w +//│ ╟── type `#WP` is not an instance of type `EM` +//│ ║ l.505: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.335: fun fto(w: WP): EM = w +//│ ║ l.505: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.335: fun fto(w: WP): EM = w +//│ ║ l.505: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.336: z: WP +//│ ║ l.506: z: WP //│ ║ ^ -//│ ╟── type `#Geo & #ZL` is not an instance of type `WP` -//│ ║ l.317: let z: ZL +//│ ╟── type `#ZL` is not an instance of type `WP` +//│ ║ l.427: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.336: z: WP +//│ ║ l.506: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.336: z: WP +//│ ║ l.506: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.337: g: ZL +//│ ║ l.507: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.316: let g: Geo +//│ ║ l.426: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.337: g: ZL +//│ ║ l.507: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.337: g: ZL +//│ ║ l.507: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ ZL + + From 3bfdeea9996b565b44d4774f0ec71eff687d74fd Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 19 Apr 2023 20:43:48 +0800 Subject: [PATCH 243/498] try fix --- .../scala/mlscript/ConstraintSolver.scala | 2 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 54 ++++---- shared/src/test/diff/nu/Interfaces.mls | 121 +++++++++--------- .../test/diff/nu/PolymorphicVariants_Alt.mls | 52 +++++--- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 4 +- 5 files changed, 122 insertions(+), 111 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 15739c3f89..df448292eb 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -681,7 +681,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case (lr @ LhsRefined(bo, ts, r, _), rf @ RhsField(n, t2)) => // Reuse the case implemented below: (this shortcut adds a few more annoying calls in stats) annoying(Nil, lr, Nil, RhsBases(Nil, S(R(rf)), SortedMap.empty)) - case (LhsRefined(N, ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) => + case (LhsRefined(N, ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if newDefs => val fty = lookupField(N, r.fields.toMap.get, ts, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index c05c6bb0fe..841ae4ddb6 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -105,8 +105,8 @@ module Test1 extends EvalVar, EvalLambda //│ <: 'a //│ 'l :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} //│ <: 'a -//│ 'A6 :> 'A3 & 'A7 | 'A5 & 'A8 | 'A4 | ('x, 'n,) -//│ <: ('A2 | 'A7) & ('A4 | 'A8) & 'A5 +//│ 'A6 :> 'A7 & 'A3 | 'A8 & 'A5 | 'A4 | ('x, 'n,) +//│ <: ('A7 | 'A2) & ('A8 | 'A4) & 'A5 //│ 'A8 := in 'A4 out 'A5 //│ 'k :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} //│ <: 'o @@ -115,21 +115,21 @@ module Test1 extends EvalVar, EvalLambda //│ 'p :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} | Cons['A9] | Nil //│ <: #Cons & {Cons#A <: 'A10} | #Nil & ~#Cons //│ 'A9 := out 'A10 -//│ 'A10 :> 'A3 & 'A11 | 'A5 & 'A12 +//│ 'A10 :> 'A11 & 'A3 | 'A12 & 'A5 //│ <: 'head -//│ 'head :> 'A3 & 'A11 | 'A5 & 'A12 +//│ 'head :> 'A11 & 'A3 | 'A12 & 'A5 //│ <: {_2: 'q} & {_1: 'r} //│ 'A12 := in 'A4 out 'A5 //│ 'A11 := in 'A2 out 'A3 -//│ 'A5 :> 'A3 & 'A7 | 'A4 | ('x0, 'u,) +//│ 'A5 :> 'A7 & 'A3 | 'A4 | ('x0, 'u,) //│ <: 'A2 & {_1: 'r} & {_2: 'q} -//│ 'A2 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | ('x, 'n,) & {_2: 'n, _1: 'x} | ('x1, 'v,) | 'A3 & 'A7 +//│ 'A2 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | ('x, 'n,) & {_2: 'n, _1: 'x} | ('x1, 'v,) | 'A7 & 'A3 //│ <: 'A4 & {_1: 'r} & {_2: 'q} +//│ 'A7 := in 'A2 out 'A3 //│ 'A3 :> 'A2 | ('x1, 'v,) //│ <: 'A4 & {_1: 'r} & {_2: 'q} -//│ 'A4 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | 'A3 & 'A7 | ('x1, 'v,) | ('x, 'n,) & {_2: 'n, _1: 'x} -//│ <: ('A2 | 'A7) & 'A2 & {_1: 'r} & {_2: 'q} -//│ 'A7 := in 'A2 out 'A3 +//│ 'A4 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | 'A7 & 'A3 | ('x1, 'v,) | ('x, 'n,) & {_2: 'n, _1: 'x} +//│ <: ('A7 | 'A2) & 'A2 & {_1: 'r} & {_2: 'q} //│ 'n :> #Var //│ <: 'u //│ 'x :> string @@ -285,8 +285,8 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ <: 'a //│ 'h :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} //│ <: 'a -//│ 'A3 :> 'A0 & 'A4 | 'A2 & 'A5 | 'A1 | ('x, 'j,) -//│ <: ('A | 'A4) & ('A1 | 'A5) & 'A2 +//│ 'A3 :> 'A4 & 'A0 | 'A5 & 'A2 | 'A1 | ('x, 'j,) +//│ <: ('A4 | 'A) & ('A5 | 'A1) & 'A2 //│ 'A5 := in 'A1 out 'A2 //│ 'g :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} //│ <: 'k @@ -301,21 +301,21 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ 'p :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} | Cons['A6] | Nil //│ <: #Cons & {Cons#A <: 'A7} | #Nil & ~#Cons //│ 'A6 := out 'A7 -//│ 'A7 :> 'A0 & 'A8 | 'A2 & 'A9 +//│ 'A7 :> 'A8 & 'A0 | 'A9 & 'A2 //│ <: 'head -//│ 'head :> 'A0 & 'A8 | 'A2 & 'A9 +//│ 'head :> 'A8 & 'A0 | 'A9 & 'A2 //│ <: {_2: 'q} & {_1: 'u} //│ 'A9 := in 'A1 out 'A2 //│ 'A8 := in 'A out 'A0 -//│ 'A2 :> 'A0 & 'A4 | 'A1 | ('x0, 'v,) +//│ 'A2 :> 'A4 & 'A0 | 'A1 | ('x0, 'v,) //│ <: 'A & {_1: 'u} & {_2: 'q} -//│ 'A :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | ('x, 'j,) & {_2: 'j, _1: 'x} | ('x1, 'w,) | 'A0 & 'A4 +//│ 'A :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | ('x, 'j,) & {_2: 'j, _1: 'x} | ('x1, 'w,) | 'A4 & 'A0 //│ <: 'A1 & {_1: 'u} & {_2: 'q} +//│ 'A4 := in 'A out 'A0 //│ 'A0 :> 'A | ('x1, 'w,) //│ <: 'A1 & {_1: 'u} & {_2: 'q} -//│ 'A1 :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | 'A0 & 'A4 | ('x1, 'w,) | ('x, 'j,) & {_2: 'j, _1: 'x} -//│ <: ('A | 'A4) & 'A & {_1: 'u} & {_2: 'q} -//│ 'A4 := in 'A out 'A0 +//│ 'A1 :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | 'A4 & 'A0 | ('x1, 'w,) | ('x, 'j,) & {_2: 'j, _1: 'x} +//│ <: ('A4 | 'A) & 'A & {_1: 'u} & {_2: 'q} //│ 'j :> #Var //│ <: 'v //│ 'x :> string @@ -428,8 +428,8 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr //│ <: 'a //│ 'j :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} //│ <: 'a -//│ 'A3 :> 'A0 & 'A4 | 'A2 & 'A5 | 'A1 | ('x, 'm,) -//│ <: ('A | 'A4) & ('A1 | 'A5) & 'A2 +//│ 'A3 :> 'A4 & 'A0 | 'A5 & 'A2 | 'A1 | ('x, 'm,) +//│ <: ('A4 | 'A) & ('A5 | 'A1) & 'A2 //│ 'A5 := in 'A1 out 'A2 //│ 'i :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} //│ <: 'n @@ -438,21 +438,21 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr //│ 'o :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} | Cons['A6] | Nil //│ <: #Cons & {Cons#A <: 'A7} | #Nil & ~#Cons //│ 'A6 := out 'A7 -//│ 'A7 :> 'A0 & 'A8 | 'A2 & 'A9 +//│ 'A7 :> 'A8 & 'A0 | 'A9 & 'A2 //│ <: 'head -//│ 'head :> 'A0 & 'A8 | 'A2 & 'A9 +//│ 'head :> 'A8 & 'A0 | 'A9 & 'A2 //│ <: {_2: 'p} & {_1: 'q} //│ 'A9 := in 'A1 out 'A2 //│ 'A8 := in 'A out 'A0 -//│ 'A2 :> 'A0 & 'A4 | 'A1 | ('x0, 's,) +//│ 'A2 :> 'A4 & 'A0 | 'A1 | ('x0, 's,) //│ <: 'A & {_1: 'q} & {_2: 'p} -//│ 'A :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | ('x, 'm,) & {_2: 'm, _1: 'x} | ('x1, 't,) | 'A0 & 'A4 +//│ 'A :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | ('x, 'm,) & {_2: 'm, _1: 'x} | ('x1, 't,) | 'A4 & 'A0 //│ <: 'A1 & {_1: 'q} & {_2: 'p} +//│ 'A4 := in 'A out 'A0 //│ 'A0 :> 'A | ('x1, 't,) //│ <: 'A1 & {_1: 'q} & {_2: 'p} -//│ 'A1 :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | 'A0 & 'A4 | ('x1, 't,) | ('x, 'm,) & {_2: 'm, _1: 'x} -//│ <: ('A | 'A4) & 'A & {_1: 'q} & {_2: 'p} -//│ 'A4 := in 'A out 'A0 +//│ 'A1 :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | 'A4 & 'A0 | ('x1, 't,) | ('x, 'm,) & {_2: 'm, _1: 'x} +//│ <: ('A4 | 'A) & 'A & {_1: 'q} & {_2: 'p} //│ 'm :> #Var //│ <: 's //│ 'x :> string diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 1e28ade25f..03de7a6e87 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -175,7 +175,6 @@ let c1: Test = C() //│ | | | | | | | Possible: List({}∧#Test) //│ | | | | | | | 0. A C{} % List() {} % List() <: #Test //│ | | | | | | | | | | allVarPols: @@ -221,19 +220,19 @@ fc(c) fun fts['a](x: 'a & Test) = x.foo fts(c) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.222: fts(c) +//│ ║ l.221: fts(c) //│ ║ ^^^^^^ //│ ╟── application of type `C` is not an instance of type `Test` //│ ║ l.116: let c = C() //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#Test` -//│ ║ l.222: fts(c) +//│ ║ l.221: fts(c) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.221: fun fts['a](x: 'a & Test) = x.foo +//│ ║ l.220: fun fts['a](x: 'a & Test) = x.foo //│ ║ ^^^^ //│ ╟── from intersection type: -//│ ║ l.221: fun fts['a](x: 'a & Test) = x.foo +//│ ║ l.220: fun fts['a](x: 'a & Test) = x.foo //│ ╙── ^^^^^^^^^ //│ fun fts: forall 'foo. (x: Test & {foo: 'foo} | Test & ~#Test,) -> 'foo //│ error | int @@ -255,19 +254,19 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.255: fun a1 = 4 +//│ ║ l.254: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.255: fun a1 = 4 +//│ ║ l.254: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.255: fun a1 = 4 +//│ ║ l.254: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.244: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.243: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.244: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.243: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 @@ -284,16 +283,16 @@ class CE extends Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method ce: -//│ ║ l.284: fun ce(x) = x +//│ ║ l.283: fun ce(x) = x //│ ║ ^^^^^^^^^ //│ ╟── type `#Oth` is not an instance of type `Test` -//│ ║ l.277: fun ce: Oth -> Test +//│ ║ l.276: fun ce: Oth -> Test //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#Test` -//│ ║ l.284: fun ce(x) = x +//│ ║ l.283: fun ce(x) = x //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.277: fun ce: Oth -> Test +//│ ║ l.276: fun ce: Oth -> Test //│ ╙── ^^^^ //│ class CE() { //│ fun ce: Oth -> Test @@ -304,11 +303,11 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.303: class E1 extends Test { +//│ ║ l.302: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.304: fun foo = 2 +//│ ║ l.303: fun foo = 2 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.305: } +//│ ║ l.304: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -319,10 +318,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.319: trait TE1 extends C +//│ ║ l.318: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.320: trait TE2 extends M, Test +//│ ║ l.319: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() //│ trait TE2() @@ -333,13 +332,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.332: fun foo = true +//│ ║ l.331: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.332: fun foo = true +//│ ║ l.331: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.332: fun foo = true +//│ ║ l.331: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -356,10 +355,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ l.356: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ l.356: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -375,11 +374,11 @@ class B extends Base let b: Base = A() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.376: let b: Base = A() +//│ ║ l.375: let b: Base = A() //│ ║ ^^^ //│ ╟── application of type `A` is not an instance of type `Base` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.376: let b: Base = A() +//│ ║ l.375: let b: Base = A() //│ ╙── ^^^^ //│ let b: Base @@ -396,10 +395,10 @@ trait Base: Foo | Bar class Foo[A] extends Base class Bar[B] extends Base //│ ╔══[ERROR] Type Foo takes parameters -//│ ║ l.395: trait Base: Foo | Bar +//│ ║ l.394: trait Base: Foo | Bar //│ ╙── ^^^ //│ ╔══[ERROR] Type Bar takes parameters -//│ ║ l.395: trait Base: Foo | Bar +//│ ║ l.394: trait Base: Foo | Bar //│ ╙── ^^^ //│ trait Base() //│ class Foo[A]() @@ -408,7 +407,7 @@ class Bar[B] extends Base // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.409: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.408: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -438,64 +437,64 @@ w: Geo z: Geo e: WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ║ l.434: fun fot(x: EM): Geo = x //│ ║ ^ //│ ╟── type `#EM` is not an instance of type `Geo` -//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ║ l.434: fun fot(x: EM): Geo = x //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ║ l.434: fun fot(x: EM): Geo = x //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.435: fun fot(x: EM): Geo = x +//│ ║ l.434: fun fot(x: EM): Geo = x //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.436: fun fit(x: EM): WP = x +//│ ║ l.435: fun fit(x: EM): WP = x //│ ║ ^ //│ ╟── type `#EM` is not an instance of type `WP` -//│ ║ l.436: fun fit(x: EM): WP = x +//│ ║ l.435: fun fit(x: EM): WP = x //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.436: fun fit(x: EM): WP = x +//│ ║ l.435: fun fit(x: EM): WP = x //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.436: fun fit(x: EM): WP = x +//│ ║ l.435: fun fit(x: EM): WP = x //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.437: w: Geo +//│ ║ l.436: w: Geo //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `Geo` -//│ ║ l.428: let w: WP +//│ ║ l.427: let w: WP //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.437: w: Geo +//│ ║ l.436: w: Geo //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.437: w: Geo +//│ ║ l.436: w: Geo //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.438: z: Geo +//│ ║ l.437: z: Geo //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `Geo` -//│ ║ l.427: let z: ZL +//│ ║ l.426: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.438: z: Geo +//│ ║ l.437: z: Geo //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.438: z: Geo +//│ ║ l.437: z: Geo //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.439: e: WP +//│ ║ l.438: e: WP //│ ║ ^ //│ ╟── type `#EM` is not an instance of type `WP` -//│ ║ l.429: let e: EM +//│ ║ l.428: let e: EM //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.439: e: WP +//│ ║ l.438: e: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.439: e: WP +//│ ║ l.438: e: WP //│ ╙── ^^ //│ fun fot: (x: EM,) -> Geo //│ fun fit: (x: EM,) -> WP @@ -506,40 +505,40 @@ fun fto(w: WP): EM = w z: WP g: ZL //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.505: fun fto(w: WP): EM = w +//│ ║ l.504: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.505: fun fto(w: WP): EM = w +//│ ║ l.504: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.505: fun fto(w: WP): EM = w +//│ ║ l.504: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.505: fun fto(w: WP): EM = w +//│ ║ l.504: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.506: z: WP +//│ ║ l.505: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.427: let z: ZL +//│ ║ l.426: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.506: z: WP +//│ ║ l.505: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.506: z: WP +//│ ║ l.505: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.507: g: ZL +//│ ║ l.506: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.426: let g: Geo +//│ ║ l.425: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.507: g: ZL +//│ ║ l.506: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.507: g: ZL +//│ ║ l.506: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ ZL diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index f510799a12..0572bd0f09 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -112,24 +112,32 @@ module Test1 extends EvalVar, EvalLambda //│ 'b :> App['b] | Abs['b] | Var Test1.eval(Nil(), Var("a")) -//│ 'a -//│ where -//│ 'a :> Abs['a] | Var | App['a] +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) +//│ ║ l.114: Test1.eval(Nil(), Var("a")) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ error Test1.eval(Nil(), Abs("b", Var("a"))) -//│ 'a -//│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) +//│ ║ l.121: Test1.eval(Nil(), Abs("b", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ error Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ 'a -//│ where -//│ 'a :> Abs['a] | Var | App['a] +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) +//│ ║ l.128: Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ error Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ 'a -//│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) +//│ ║ l.135: Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ error class Num(n: int) class Add(l: A, r: A) @@ -144,7 +152,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) +//│ fun map_expr: forall 'A 'l 'A0 'l0. ('l -> 'A0 & 'l0 -> 'A, Add['l] | Mul['l0] | Num | Var,) -> (Add['A0] | Mul['A] | Num | Var) mixin EvalExpr { fun eval(sub, v) = @@ -187,20 +195,24 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> 'b //│ } //│ where -//│ 'b :> Num | Var | 'c | App['b] | Abs['b] +//│ 'b :> App['b] | Abs['b] | Num | Var | 'c //│ 'c <: Add['d] | Mul['d] | Num | Var //│ 'd <: 'a //│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | 'c & ~#Abs & ~#App Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ 'a -//│ where -//│ 'a :> Abs[Var] | Var | Num | App['a] | Abs['a] +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) +//│ ║ l.203: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ error Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) -//│ 'a -//│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var | Add[Num | Var] | Num +//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) +//│ ║ l.210: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── Note: use flag `:ex` to see internal error info. +//│ error module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index 11cd86598a..44d16861fd 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -55,8 +55,8 @@ TestLang.eval(mk(0)) //│ error | int //│ res //│ = 0 -//│ constrain calls : 242 +//│ constrain calls : 239 //│ annoying calls : 116 -//│ subtyping calls : 4071 +//│ subtyping calls : 3975 From 410e86b51770a9c021f1fabe4c024c12d0f0e227 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 19 Apr 2023 23:22:34 +0800 Subject: [PATCH 244/498] WIP Allow references to raw types and access to type param fields --- .../scala/mlscript/ConstraintSolver.scala | 79 +++--- .../src/main/scala/mlscript/NuTypeDefs.scala | 64 +++-- shared/src/main/scala/mlscript/Typer.scala | 15 +- .../src/test/diff/codegen/ConstructorStmt.mls | 4 +- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 18 +- shared/src/test/diff/gadt/Exp1.mls | 13 +- shared/src/test/diff/nu/BadClasses.mls | 2 +- shared/src/test/diff/nu/BasicClasses.mls | 2 +- shared/src/test/diff/nu/Declarations.mls | 2 +- shared/src/test/diff/nu/FieldRefinement.mls | 2 +- shared/src/test/diff/nu/GenericClasses.mls | 2 +- shared/src/test/diff/nu/Interfaces.mls | 244 +++++++++--------- .../src/test/diff/nu/ThisRefinedClasses.mls | 12 +- 13 files changed, 229 insertions(+), 230 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index df448292eb..82a7045253 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -50,21 +50,18 @@ class ConstraintSolver extends NormalForms { self: Typer => } } - def lookupField(clsNme: Opt[Str], rfnt: Var => Opt[FieldType], tags: SortedSet[AbstractTag], fld: Var) + + /** Note: `mkType` is just for reporting errors. */ + def lookupField(mkType: () => ST, clsNme: Opt[Str], rfnt: Var => Opt[FieldType], tags: SortedSet[AbstractTag], fld: Var) (implicit ctx: Ctx, raise: Raise) : FieldType = { - // val info = ctx.tyDefs2(clsNme) - // require(!info.isComputing) - - // TODO intersect with found signature! val fromRft = rfnt(fld) - def getFieldType(info: DelayedTypeInfo): FieldType = { - - def nope = - err(noSuchMember(info, fld)).toUpper(noProv) + var foundRec: Opt[Diagnostic] = N + + def getFieldType(info: DelayedTypeInfo): Opt[FieldType] = { // * The raw type of this member, with original references to the class' type variables/type parameters val raw = if (info.isComputing) { @@ -72,57 +69,47 @@ class ConstraintSolver extends NormalForms { self: Typer => info.typedFields.get(fld) match { case S(fty) => S(fty) case N => - fromRft match { - case S(fty) => - N - case N => - if (info.allFields.contains(fld)) - S(err(msg"Indirectly-recursive member should have type annotation", fld.toLoc).toUpper(noProv)) - else - S(nope) - } + if (info.allFields.contains(fld)) // TODO don't report this if the field can be found somewhere else! + foundRec = S(ErrorReport(msg"Indirectly-recursive member should have type annotation" -> fld.toLoc :: Nil)) + N } } else info.complete() match { + case cls: TypedNuCls => - cls.members.get(fld.name) match { + cls.virtualMembers.get(fld.name) match { case S(d: TypedNuFun) => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => S(p.ty) + case S(p: NuTypeParam) => + S(p.ty) case S(m) => S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) - case N => - fromRft match { - case S(fty) => N - case N => S(nope) - } + case N => N } + // TODO factor code with above!! case trt: TypedNuTrt => trt.members.get(fld.name) match { case S(d: TypedNuFun) => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => S(p.ty) + case S(p: NuTypeParam) => + S(p.ty) case S(m) => S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) - case N => - fromRft match { - case S(fty) => N - case N => S(nope) - } + case N => N } case _ => ??? // TODO } - println(s"Lookup ${info.decl.name}.${fld.name} : $raw where ${raw.fold("")(_.ub.showBounds)}") - - val freshenedRaw = raw.fold(TopType.toUpper(noProv)) { raw => - + val freshenedRaw = raw.map { raw => + // TODO dedup with below logic from `lookupNuTypeDef` implicit val freshened: MutMap[TV, ST] = MutMap.empty @@ -170,28 +157,32 @@ class ConstraintSolver extends NormalForms { self: Typer => raw.freshenAbove(info.level, rigidify = false) } - println(s"Fresh ${info.decl.name}.${fld.name} : $freshenedRaw where ${freshenedRaw.ub.showBounds}") + println(s"Fresh ${info.decl.name}.${fld.name} : $freshenedRaw where ${freshenedRaw.map(_.ub.showBounds)}") freshenedRaw } - val fromCls = clsNme.map(clsNme => getFieldType(ctx.tyDefs2(clsNme))) + val fromCls = clsNme.flatMap(clsNme => getFieldType(ctx.tyDefs2(clsNme))) val fromTrts = tags.toList.collect { case TraitTag(nme) => getFieldType(ctx.tyDefs2(nme.name)) - } + }.flatten val fields = fromRft.toList ::: fromCls.toList ::: fromTrts println(s" & ${fromRft} (from refinement)") - // fromRft.foldRight(freshenedRaw)(_ && _) - fields match { case x :: xs => xs.foldRight(x)(_ && _) - case Nil => ??? // TODO + case Nil => + foundRec match { + case S(d) => err(d).toUpper(noProv) + case N => + err(msg"Type `${mkType().expPos}` does not contain member `${fld.name}`" -> + fld.toLoc :: Nil).toUpper(noProv) + } } } @@ -656,7 +647,7 @@ class ConstraintSolver extends NormalForms { self: Typer => if ctx.tyDefs2.contains(nme) => if (newDefs && fldNme.name === "Eql#A") { val info = ctx.tyDefs2(nme) info.typedParams.foreach { p => - val fty = lookupField(S(nme), r.fields.toMap.get, ts, p._1) + val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, p._1) rec(fldTy.lb.get, RecordType(p._1 -> TypeRef(TypeName("Eql"), fty.ub // FIXME check mutable? :: Nil @@ -668,7 +659,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? // else { // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) - val fty = lookupField(S(nme), r.fields.toMap.get, ts, fldNme) + val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) // } @@ -682,7 +673,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // Reuse the case implemented below: (this shortcut adds a few more annoying calls in stats) annoying(Nil, lr, Nil, RhsBases(Nil, S(R(rf)), SortedMap.empty)) case (LhsRefined(N, ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if newDefs => - val fty = lookupField(N, r.fields.toMap.get, ts, fldNme) + val fty = lookupField(() => done_ls.toType(sort = true), N, r.fields.toMap.get, ts, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) case (LhsRefined(bo, ts, r, _), RhsBases(ots, S(R(RhsField(n, t2))), trs)) => @@ -725,6 +716,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } }() + /* def lookupNuTypeDefField(cls: TypedNuCls, fld: Var): FieldType = { // println(fld.name, cls.members) // println(s"Looking up $fld in ${cls.td.nme}") @@ -742,6 +734,7 @@ class ConstraintSolver extends NormalForms { self: Typer => println(s"Lookup ${cls.td.nme.name}.${fld.name} : $res where ${res.ub.showBounds}") res } + */ /** Helper function to constrain Field lower bounds. */ def recLb(lhs: FieldType, rhs: FieldType) @@ -903,7 +896,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case (fldNme @ Var("Eql#A"), fldTy) => goToWork(lhs, RecordType(fldNme -> fldTy :: Nil)(noProv)) case (fldNme, fldTy) => - val fty = lookupField(S(nme), _ => N, SortedSet.empty, fldNme) + val fty = lookupField(() => lhs, S(nme), _ => N, SortedSet.empty, fldNme) rec(fty.ub, fldTy.ub, false) recLb(fldTy, fty) } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index a62f5e1c52..b7d0c43aff 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -25,9 +25,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed trait NuMember { def name: Str def kind: DeclKind + def level: Level /** Used in inheritance processing, for parent types. */ - def freshen(implicit ctx: Ctx): NuMember + def freshen(implicit ctx: Ctx): NuMember = { + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + ctx.copy(lvl = level + 1) |> { implicit ctx => + freshenAbove(level, rigidify = false) + } + } def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) @@ -45,49 +52,50 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - case class NuParam(nme: Var, ty: FieldType, isType: Bool) extends NuMember { + case class NuParam(nme: Var, ty: FieldType, isType: Bool)(val level: Level) extends NuMember { def name: Str = nme.name def kind: DeclKind = Val def typeSignature: ST = ty.ub - def freshen(implicit ctx: Ctx): NuMember = this - def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuParam = - NuParam(nme, ty.freshenAbove(lim, rigidify), isType) + NuParam(nme, ty.freshenAbove(lim, rigidify), isType)(level) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember = - NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)), isType) + NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)), isType)(level) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember = - NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)), isType) + NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)), isType)(level) } // TODO: - // case class NuTypeParam(nme: TN, ty: FieldType) extends NuMember { - // def name: Str = nme.name - // - // def freshenAbove(lim: Int, rigidify: Bool) - // (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - // : NuParam = - // NuParam(nme, ty.freshenAbove(lim, rigidify)) - // } + case class NuTypeParam(nme: TN, ty: FieldType)(val level: Level) extends NuMember { + def name: Str = nme.name + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + : NuTypeParam = + NuTypeParam(nme, ty.freshenAbove(lim, rigidify))(level) + + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember = + NuTypeParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)))(level) + + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): NuMember = + NuTypeParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)))(level) + + def kind: DeclKind = Als // FIXME? + } sealed trait TypedNuDecl extends NuMember { def name: Str def level: Level - def freshen(implicit ctx: Ctx): NuMember = { - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - ctx.copy(lvl = level + 1) |> { implicit ctx => - freshenAbove(level, rigidify = false) - } - } def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) @@ -221,6 +229,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def typeSignature: ST = typeSignatureOf(td, level, tparams, params, tags) + /** Includes class-name-coded type parameter fields. */ + lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { + case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuTypeParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } // TODO // def checkVariances @@ -760,7 +772,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi val fldNme = td.nme.name + "#" + tp.name - NuParam(Var(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isType = true) + NuParam(Var(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isType = true)(lvl) } val tparamFields = tparamMems.map(p => p.nme -> p.ty) assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) @@ -805,7 +817,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val a_ty = typeTerm(a) p.lb.foreach(constrain(_, a_ty)) constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false)(lvl) } // TODO check overriding @@ -866,7 +878,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val baseType = RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) - val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)(lvl)) val (thisType, baseMems) = inherit(parentSpecs, baseType, tparamMems ++ paramMems) @@ -934,7 +946,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols - val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)) + val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)(lvl)) implicit val vars: Map[Str, SimpleType] = outerVars ++ Map.empty // TODO type params val thisTV = freshVar(provTODO, N, S("this")) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 59e95655e7..c59992bbc7 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -442,9 +442,18 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) vars.getOrElse(name, { typeNamed(tyLoc, name) match { case R((_, tpnum)) => - if (tpnum =/= 0) { - err(msg"Type $name takes parameters", tyLoc)(raise) - } else TypeRef(tn, Nil)(tpr) + if (tpnum === 0) TypeRef(tn, Nil)(tpr) + else ctx.tyDefs2.get(name) match { + case S(lti) => + lti.decl match { + case NuTypeDef(Cls | Nms, _, _, _, _, _, _, _, _) => + clsNameToNomTag(ctx.tyDefs2(name).decl.asInstanceOf[NuTypeDef])(tyTp(tyLoc, "class tag"), ctx) + case NuTypeDef(Trt, _, _, _, _, _, _, _, _) => + trtNameToNomTag(ctx.tyDefs2(name).decl.asInstanceOf[NuTypeDef])(tyTp(tyLoc, "class tag"), ctx) + case _ => die // TODO + } + case _ => err(msg"Type $name takes parameters", tyLoc)(raise) + } case L(e) => if (name.isEmpty || !name.head.isLower) e() else (typeNamed(tyLoc, name.capitalize), ctx.tyDefs.get(name.capitalize)) match { diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index b910fd2931..f9df9e858a 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -135,7 +135,7 @@ let ab = A(0) class Foo { this: { x: int } } -//│ ╔══[ERROR] Class `Foo` does not contain member `x` +//│ ╔══[ERROR] Type `#Foo` does not contain member `x` //│ ║ l.136: this: { x: int } //│ ╙── ^ //│ class Foo() @@ -166,7 +166,7 @@ class Bar { //│ ╔══[ERROR] Illegal use of `super` //│ ║ l.164: super: { x: int } //│ ╙── ^^^^^ -//│ ╔══[ERROR] Class `Bar` does not contain member `x` +//│ ╔══[ERROR] Type `#Bar` does not contain member `x` //│ ║ l.164: super: { x: int } //│ ╙── ^ //│ class Bar() diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 0e42519908..7296b2a7e2 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -186,16 +186,16 @@ mixin Text { :e module SizeText extends Text -//│ ╔══[ERROR] Module `SizeText` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` //│ ║ l.180: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Module `SizeText` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` //│ ║ l.179: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Module `SizeText` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` //│ ║ l.178: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Module `SizeText` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` //│ ║ l.177: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText() { @@ -324,19 +324,19 @@ module TestElim extends Eliminate //│ } //│ where //│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~#Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'b :> Outside['b] | Union['b] | Intersect['b] | Translate['b] | Scale['b] +//│ 'b :> Intersect['b] | Translate['b] | Scale['b] | Outside['b] | Union['b] TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where -//│ 'a :> Intersect['a] | Translate['a] | Scale['a] | Univ | Outside['a] | Union['a] +//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Univ //│ res //│ = Univ {} TestElim.eliminate(circles) //│ 'a //│ where -//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Circle +//│ 'a :> Circle | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] //│ res //│ = Union {} @@ -354,7 +354,7 @@ fun mk(n) = if n is TestElim.eliminate(mk(100)) //│ 'a //│ where -//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ 'a :> Intersect['a] | Translate['a] | Scale['a] | Outside['a] | Union['a] //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -377,7 +377,7 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~#Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'c :> Translate['c] | Scale['c] | Outside['c] | Union['c] | Intersect['c] +//│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] // TODO investigate diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index dfd98e1495..3696d40f9d 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -10,9 +10,6 @@ class Exp[A]: Pair | Lit { // TODO enable class inheritance class Lit(n: int) extends Exp[int] class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╔══[ERROR] Type Pair takes parameters -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ╙── ^^^^ //│ ╔══[ERROR] type signatures not yet supported for classes //│ ║ l.5: class Exp[A]: Pair | Lit { //│ ╙── ^^^^^^^^^^ @@ -40,8 +37,8 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] :e // TODO Lit(0).test -//│ ╔══[ERROR] Class `Lit` does not contain member `test` -//│ ║ l.42: Lit(0).test +//│ ╔══[ERROR] Type `Lit` does not contain member `test` +//│ ║ l.39: Lit(0).test //│ ╙── ^^^^^ //│ error //│ res @@ -62,7 +59,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.63: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.60: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -75,10 +72,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.75: fun f(x: a) = x +//│ ║ l.72: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.76: f(l) +//│ ║ l.73: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index f758d40b27..16ad8c119c 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -96,7 +96,7 @@ class Foo[A] { 42: A } :e class C1 { fun oops = this.x } -//│ ╔══[ERROR] Class `C1` does not contain member `x` +//│ ╔══[ERROR] Type `#C1` does not contain member `x` //│ ║ l.98: class C1 { fun oops = this.x } //│ ╙── ^^ //│ class C1() { diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 9bc30a330b..b61c639778 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -167,7 +167,7 @@ b.me :e b.getBaseTypo -//│ ╔══[ERROR] Class `Base1` does not contain member `getBaseTypo` +//│ ╔══[ERROR] Type `Base1` does not contain member `getBaseTypo` //│ ║ l.169: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index a5a960892c..cbc3677d45 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -29,7 +29,7 @@ console.error("hello") :e console.log("hello") -//│ ╔══[ERROR] Module `console` does not contain member `log` +//│ ╔══[ERROR] Type `console` does not contain member `log` //│ ║ l.31: console.log("hello") //│ ╙── ^^^^ //│ error diff --git a/shared/src/test/diff/nu/FieldRefinement.mls b/shared/src/test/diff/nu/FieldRefinement.mls index ed653aef73..6c5dee5364 100644 --- a/shared/src/test/diff/nu/FieldRefinement.mls +++ b/shared/src/test/diff/nu/FieldRefinement.mls @@ -28,7 +28,7 @@ foo.y :e foo.z -//│ ╔══[ERROR] Class `Foo` does not contain member `z` +//│ ╔══[ERROR] Type `Foo & {y: bool, bar: 0 | 1, baz: 0 | 1, x: 0 | 1}` does not contain member `z` //│ ║ l.30: foo.z //│ ╙── ^^ //│ error diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 513d081580..6024ab15d7 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -392,7 +392,7 @@ not(w.x.n) :e not(w.x.a) -//│ ╔══[ERROR] Class `C` does not contain member `a` +//│ ╔══[ERROR] Type `C['a]` does not contain member `a` //│ ║ l.394: not(w.x.a) //│ ╙── ^^ //│ bool diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 03de7a6e87..020af89099 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -137,57 +137,8 @@ c: Test //│ ╙── ^^^^ //│ Test -:d +// :d let c1: Test = C() -//│ 0. Typing TypingUnit(List(let c1 = C () : Test)) -//│ | 0. Created lazy type info for let c1 = C () : Test -//│ | Completing let c1 = C () : Test -//│ | | UNSTASHING... (out) -//│ | | Type params -//│ | | UNSTASHING... (out) -//│ | | Params -//│ | | 0. Typing term C () : Test -//│ | | | 0. Typing term C () -//│ | | | | 0. Typing term C -//│ | | | | 0. : (() -> C) -//│ | | | | CONSTRAIN (() -> C) α80) -//│ | | | | where -//│ | | | | 0. C (() -> C) α80) (0) -//│ | | | | | 0. C () Test -//│ | | | => Test ——— -//│ | | | CONSTRAIN α80 C -//│ | | | 0. C α80 {}) {} <: DNF(0, {}∧#Test) -//│ | | | | | | | Possible: List({}∧#Test) -//│ | | | | | | | 0. A C{} % List() {} % List() <: #Test -//│ | | | | | | | | | | allVarPols: -//│ | | | | | | | | | | normLike[+] C -//│ | | | | | | | | | | | norm[+] C -//│ | | | | | | | | | | | | DNF: DNF(0, C{}) -//│ | | | | | | | | | | | | rcd2 {} -//│ | | | | | | | | | | | | typeRef C -//│ | | | | | | | | | | | | clsFields -//│ | | | | | | | | | | | ~> C -//│ | | | | | | | | | | CONSTRAIN error<> 'foo //│ error | int @@ -254,19 +195,19 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.254: fun a1 = 4 +//│ ║ l.195: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.254: fun a1 = 4 +//│ ║ l.195: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.254: fun a1 = 4 +//│ ║ l.195: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.243: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.184: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.243: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.184: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 @@ -283,16 +224,16 @@ class CE extends Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method ce: -//│ ║ l.283: fun ce(x) = x +//│ ║ l.224: fun ce(x) = x //│ ║ ^^^^^^^^^ //│ ╟── type `#Oth` is not an instance of type `Test` -//│ ║ l.276: fun ce: Oth -> Test +//│ ║ l.217: fun ce: Oth -> Test //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#Test` -//│ ║ l.283: fun ce(x) = x +//│ ║ l.224: fun ce(x) = x //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.276: fun ce: Oth -> Test +//│ ║ l.217: fun ce: Oth -> Test //│ ╙── ^^^^ //│ class CE() { //│ fun ce: Oth -> Test @@ -303,11 +244,11 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.302: class E1 extends Test { +//│ ║ l.243: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.303: fun foo = 2 +//│ ║ l.244: fun foo = 2 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.304: } +//│ ║ l.245: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -318,10 +259,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.318: trait TE1 extends C +//│ ║ l.259: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.319: trait TE2 extends M, Test +//│ ║ l.260: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() //│ trait TE2() @@ -332,13 +273,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.331: fun foo = true +//│ ║ l.272: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.331: fun foo = true +//│ ║ l.272: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.331: fun foo = true +//│ ║ l.272: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -355,10 +296,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.356: class D extends Test[int], Test[bool] +//│ ║ l.297: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.356: class D extends Test[int], Test[bool] +//│ ║ l.297: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -374,11 +315,11 @@ class B extends Base let b: Base = A() //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.375: let b: Base = A() +//│ ║ l.316: let b: Base = A() //│ ║ ^^^ //│ ╟── application of type `A` is not an instance of type `Base` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.375: let b: Base = A() +//│ ║ l.316: let b: Base = A() //│ ╙── ^^^^ //│ let b: Base @@ -392,22 +333,68 @@ if b is trait Base: Foo | Bar -class Foo[A] extends Base -class Bar[B] extends Base -//│ ╔══[ERROR] Type Foo takes parameters -//│ ║ l.394: trait Base: Foo | Bar -//│ ╙── ^^^ -//│ ╔══[ERROR] Type Bar takes parameters -//│ ║ l.394: trait Base: Foo | Bar -//│ ╙── ^^^ +class Foo[A](aa: (A, A)) extends Base +class Bar[B](f: B => B) extends Base //│ trait Base() -//│ class Foo[A]() -//│ class Bar[B]() +//│ class Foo[A](aa: (A, A,)) +//│ class Bar[B](f: B -> B) + +let f: Foo = Foo((1, 2)) +//│ let f: Foo[anything] + +f.aa +//│ (??A, ??A,) + +// FIXME +let b: Base = f +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.349: let b: Base = f +//│ ║ ^ +//│ ╟── type `Foo[anything]` is not an instance of type `Base` +//│ ║ l.342: let f: Foo = Foo((1, 2)) +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `#Base` +//│ ║ l.349: let b: Base = f +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.349: let b: Base = f +//│ ╙── ^^^^ +//│ let b: Base + +if b is Foo(a) then a else 0 +//│ (??A, ??A,) | 0 + +// FIXME? why does it happen in this case and not above? +if b is Bar(f) then f else 0 +//│ ╔══[ERROR] Type error in `case` expression +//│ ║ l.368: if b is Bar(f) then f else 0 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `B` leaks out of its scope +//│ ║ l.337: class Bar[B](f: B => B) extends Base +//│ ╙── ^ +//│ (??B & 'B) -> ('B | ??B0) | 0 + +// FIXME? +if b is + Foo(a) then a + Bar(f) then f +//│ ╔══[ERROR] Type error in `case` expression +//│ ║ l.378: if b is +//│ ║ ^^^^ +//│ ║ l.379: Foo(a) then a +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.380: Bar(f) then f +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── type variable `B` leaks out of its scope +//│ ║ l.337: class Bar[B](f: B => B) extends Base +//│ ╙── ^ +//│ anything + // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.408: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.395: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -437,64 +424,64 @@ w: Geo z: Geo e: WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.434: fun fot(x: EM): Geo = x +//│ ║ l.421: fun fot(x: EM): Geo = x //│ ║ ^ //│ ╟── type `#EM` is not an instance of type `Geo` -//│ ║ l.434: fun fot(x: EM): Geo = x +//│ ║ l.421: fun fot(x: EM): Geo = x //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.434: fun fot(x: EM): Geo = x +//│ ║ l.421: fun fot(x: EM): Geo = x //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.434: fun fot(x: EM): Geo = x +//│ ║ l.421: fun fot(x: EM): Geo = x //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.435: fun fit(x: EM): WP = x +//│ ║ l.422: fun fit(x: EM): WP = x //│ ║ ^ //│ ╟── type `#EM` is not an instance of type `WP` -//│ ║ l.435: fun fit(x: EM): WP = x +//│ ║ l.422: fun fit(x: EM): WP = x //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.435: fun fit(x: EM): WP = x +//│ ║ l.422: fun fit(x: EM): WP = x //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.435: fun fit(x: EM): WP = x +//│ ║ l.422: fun fit(x: EM): WP = x //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.436: w: Geo +//│ ║ l.423: w: Geo //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `Geo` -//│ ║ l.427: let w: WP +//│ ║ l.414: let w: WP //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.436: w: Geo +//│ ║ l.423: w: Geo //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.436: w: Geo +//│ ║ l.423: w: Geo //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.437: z: Geo +//│ ║ l.424: z: Geo //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `Geo` -//│ ║ l.426: let z: ZL +//│ ║ l.413: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.437: z: Geo +//│ ║ l.424: z: Geo //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.437: z: Geo +//│ ║ l.424: z: Geo //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.438: e: WP +//│ ║ l.425: e: WP //│ ║ ^ //│ ╟── type `#EM` is not an instance of type `WP` -//│ ║ l.428: let e: EM +//│ ║ l.415: let e: EM //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.438: e: WP +//│ ║ l.425: e: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.438: e: WP +//│ ║ l.425: e: WP //│ ╙── ^^ //│ fun fot: (x: EM,) -> Geo //│ fun fit: (x: EM,) -> WP @@ -505,42 +492,43 @@ fun fto(w: WP): EM = w z: WP g: ZL //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.504: fun fto(w: WP): EM = w +//│ ║ l.491: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.504: fun fto(w: WP): EM = w +//│ ║ l.491: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.504: fun fto(w: WP): EM = w +//│ ║ l.491: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.504: fun fto(w: WP): EM = w +//│ ║ l.491: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.505: z: WP +//│ ║ l.492: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.426: let z: ZL +//│ ║ l.413: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.505: z: WP +//│ ║ l.492: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.505: z: WP +//│ ║ l.492: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.506: g: ZL +//│ ║ l.493: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.425: let g: Geo +//│ ║ l.412: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.506: g: ZL +//│ ║ l.493: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.506: g: ZL +//│ ║ l.493: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ ZL + diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 19cb4e3dca..5589db513b 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -9,7 +9,7 @@ :e class Foo { fun test = this.x } -//│ ╔══[ERROR] Class `Foo` does not contain member `x` +//│ ╔══[ERROR] Type `#Foo` does not contain member `x` //│ ║ l.11: class Foo { fun test = this.x } //│ ╙── ^^ //│ class Foo() { @@ -19,7 +19,7 @@ class Foo { fun test = this.x } :e class Foo(n: int) { fun test = this.x } -//│ ╔══[ERROR] Class `Foo` does not contain member `x` +//│ ╔══[ERROR] Type `#Foo & {n: int}` does not contain member `x` //│ ║ l.21: class Foo(n: int) { fun test = this.x } //│ ╙── ^^ //│ class Foo(n: int) { @@ -29,7 +29,7 @@ class Foo(n: int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } -//│ ╔══[ERROR] Class `Foo` does not contain member `x` +//│ ╔══[ERROR] Type `#Foo & {Foo#A = ?A, n: A}` does not contain member `x` //│ ║ l.31: class Foo(n: A) { fun test = this.x } //│ ╙── ^^ //│ class Foo[A](n: A) { @@ -43,7 +43,7 @@ class Foo { this: { x: 'a } // fun test = this.x } -//│ ╔══[ERROR] Class `Foo` does not contain member `x` +//│ ╔══[ERROR] Type `#Foo` does not contain member `x` //│ ║ l.43: this: { x: 'a } //│ ╙── ^ //│ class Foo() @@ -52,10 +52,10 @@ class Foo { // TODO // * All on one line: class Test { this: { x: int}; fun test = this.x } -//│ ╔══[ERROR] Class `Test` does not contain member `x` +//│ ╔══[ERROR] Type `#Test` does not contain member `x` //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^^ -//│ ╔══[ERROR] Class `Test` does not contain member `x` +//│ ╔══[ERROR] Type `#Test` does not contain member `x` //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^ //│ class Test() { From 7899cc9eb9622f01c732ad6fb109e5f681b8b228 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 21 Apr 2023 00:28:10 +0800 Subject: [PATCH 245/498] try fixing trait subtyping --- .../scala/mlscript/ConstraintSolver.scala | 17 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 90 +++-- shared/src/main/scala/mlscript/TypeDefs.scala | 9 +- .../main/scala/mlscript/TypeSimplifier.scala | 4 +- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- .../main/scala/mlscript/TyperHelpers.scala | 4 +- shared/src/test/diff/gadt/Exp1.mls | 6 +- .../src/test/diff/mlscript/StressTraits.mls | 20 +- shared/src/test/diff/nu/Interfaces.mls | 310 +++++++++--------- 10 files changed, 245 insertions(+), 221 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 82a7045253..c5d29de35d 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -165,7 +165,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val fromCls = clsNme.flatMap(clsNme => getFieldType(ctx.tyDefs2(clsNme))) val fromTrts = tags.toList.collect { - case TraitTag(nme) => + case TraitTag(nme, iht) => getFieldType(ctx.tyDefs2(nme.name)) }.flatten @@ -665,6 +665,8 @@ class ConstraintSolver extends NormalForms { self: Typer => // } } case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => + // TODO: inherited trait tags + // println(s"!!! TODO !!! ${pt.parentsST} $pts") if (pts.contains(pt) || pts.exists(p => pt.parentsST.contains(p.id))) println(s"OK $pt <: ${pts.mkString(" | ")}") // else f.fold(reportError())(f => annoying(Nil, done_ls, Nil, f)) @@ -690,8 +692,17 @@ class ConstraintSolver extends NormalForms { self: Typer => case _ => reportError() } } - case (LhsRefined(N, ts, r, _), RhsBases(pts, N | S(L(_: FunctionType | _: ArrayBase)), _)) => - reportError() + case (LhsRefined(N, ts, r, trs), RhsBases(pts, N, trs2)) => + // TODO inherited trait tags + // println(s"!!! TODO !!! ${ts} ${pts}") + if (pts.exists(p => ts.toList.collect { + case TraitTag(n, h) => n :: h.toList.map(n => Var(n.name)) + }.flatten.contains(p.id))) + println(s"OK $ts <: $pts") + else + reportError() + case (LhsRefined(N, ts, r, _), RhsBases(pts, S(L(_: FunctionType | _: ArrayBase)), _)) => + reportError() case (LhsRefined(S(b: TupleType), ts, r, _), RhsBases(pts, S(L(ty: TupleType)), _)) if b.fields.size === ty.fields.size => (b.fields.unzip._2 lazyZip ty.fields.unzip._2).foreach { (l, r) => diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index b7d0c43aff..79a4910c9c 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -124,25 +124,27 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) - case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags) => + case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags) => TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), tags.freshenAbove(lim, rigidify), + inheritedTags )(cls.instanceType.freshenAbove(lim, rigidify)) case cls @ TypedNuAls(level, td, tparams, body) => TypedNuAls(level, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), body.freshenAbove(lim, rigidify)) - case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags) => + case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags) => TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), sign.map(_.freshenAbove(lim, rigidify)), // todo - tags.freshenAbove(lim, rigidify) + tags.freshenAbove(lim, rigidify), + inheritedTags ) } val td: NuTypeDef @@ -183,7 +185,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members: Map[Str, NuMember], thisTy: ST, sign: Opt[ST], - selfTy: ST + selfTy: ST, + inheritedTags: Set[TypeName] ) extends TypedNuTypeDef(Trt) with TypedNuTermDef { def decl: NuTypeDef = td @@ -191,7 +194,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy) + def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy, inheritedTags) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -201,6 +204,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.map(!_), thisTy), sign.map(f(pol, _)), f(pol, selfTy), + inheritedTags ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -210,6 +214,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.contravar, thisTy), sign.map(f(pol, _)), f(pol, selfTy), + inheritedTags ) } @@ -219,6 +224,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, tags: ST, + inheritedTags: Set[TypeName] )(val instanceType: ST, // * only meant to be used in `force` and `variances` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { @@ -227,7 +233,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, params, tags) + def typeSignature: ST = typeSignatureOf(td, level, tparams, params, tags, inheritedTags) /** Includes class-name-coded type parameter fields. */ lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { @@ -288,6 +294,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), f(pol, tags), + inheritedTags )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -297,6 +304,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), f(pol, tags), + inheritedTags )(f(pol, instanceType)) } @@ -368,7 +376,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, tags: ST): ST = td.kind match { + def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, tags: ST, ihtags: Set[TypeName]): ST = td.kind match { case Nms => ClassTag(Var(td.nme.name), // TODO base classes @@ -380,7 +388,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TupleType(params.mapKeys(some))(provTODO), ClassTag(Var(td.nme.name), // TODO base classes - Set.single(TypeName("Eql")) + Set.single(TypeName("Eql")) union ihtags )(provTODO) & tags & RecordType.mk( tparams.map { case (tn, tv, vi) => // TODO use vi Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } @@ -494,6 +502,42 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) // val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { // and derive from these the full set of transitively inherited tags + + type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) + val parentSpecs: Ls[ParentSpec] = + decl match { + case td: NuTypeDef if td.kind == Trt || td.kind == Cls || td.kind == Nms => + td.parents.flatMap { + case v @ Var(nme) => + S(v, v, Nil) + case p @ App(v @ Var(nme), Tup(args)) => + S(p, v, args) + case p => + err(msg"Unsupported parent specification", p.toLoc) // TODO + // support type application + N + } + case _ => Nil + } + + def lookupTags(parents: Ls[ParentSpec], tags: Set[TypeName]): Set[TypeName] = { + parents match { + case Nil => tags + case (p, Var(nm), _) :: ps => + ctx.get(nm) match { + case S(lti: DelayedTypeInfo) if lti.kind == Trt => + lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) + case S(lti: CompletedTypeInfo) if lti.kind == Trt => + lookupTags(ps, + Set.single(TypeName(nm)) union + lti.member.asInstanceOf[TypedNuTrt].inheritedTags union + tags) + case _ => lookupTags(ps, tags) + } + } + } + + lazy val inheritedTags = lookupTags(parentSpecs, Set.empty) lazy val tparams: TyParams = ctx.nest.nextLevel { implicit ctx => decl match { @@ -675,19 +719,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Trt => ctx.nest.nextLevel { implicit ctx => - - type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) - val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { - case v @ Var(nme) => - S(v, v, Nil) - case p @ App(v @ Var(nme), Tup(args)) => - S(p, v, args) - case p => - err(msg"Unsupported parent specification", p.toLoc) // TODO - // support type application - N - } - ctx ++= paramSymbols ctx += "this" -> VarSymbol(thisTV, Var("this")) @@ -726,7 +757,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val trtMems = baseMems ++ ttu.entities val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap - TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType) -> Nil + TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags) -> Nil } case Als => @@ -777,18 +808,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val tparamFields = tparamMems.map(p => p.nme -> p.ty) assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) - - type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) - val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { - case v @ Var(nme) => - S(v, v, Nil) - case p @ App(v @ Var(nme), Tup(args)) => - S(p, v, args) - case p => - err(msg"Unsupported parent specification", p.toLoc) // TODO - N - } - def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) : (ST, Ls[NuMember]) = parents match { @@ -939,6 +958,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TopType, // ifaceAnnot, TopType, // TODO use signature + inheritedTags )(thisType) -> impltdMems } case Mxn => @@ -1003,7 +1023,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => die } case td: NuTypeDef => - typeSignatureOf(td, level, tparams, typedParams, TopType) + typeSignatureOf(td, level, tparams, typedParams, TopType, inheritedTags) } override def toString: String = diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index f6d103b9ad..6d2d8d255f 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -116,6 +116,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => ClassTag(Var(td.nme.name), // ctx.allBaseClassesOf(td.nme.name) Set.single(TypeName("Eql")) // TODO superclasses + union ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) )(prov) } def clsNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { @@ -128,11 +129,11 @@ class TypeDefs extends NuTypeDefs { self: Typer => } def trtNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): TraitTag = { require(td.kind is Trt) - TraitTag(Var(td.nme.name))(prov) + TraitTag(Var(td.nme.name), Set.empty)(prov) } def trtNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): TraitTag = { require(td.kind is Trt) - TraitTag(Var(td.nme.name))(prov) + TraitTag(Var(td.nme.name), ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty))(prov) } def baseClassesOf(tyd: mlscript.TypeDef): Set[TypeName] = @@ -533,7 +534,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => case _ => Nil } def go(md: MethodDef[_ <: Term \/ Type]): (Str, MethodType) = { - val thisTag = TraitTag(Var("this"))(noProv) // or Skolem?! + val thisTag = TraitTag(Var("this"), Set.empty)(noProv) // or Skolem?! // val thisTag = SkolemTag(thisCtx.lvl/*TODO correct?*/, Var("this"))(noProv) val thisTy = thisTag & tr thisCtx += "this" -> VarSymbol(thisTy, Var("this")) @@ -567,7 +568,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => } rhs.fold(_ => defined, _ => declared) += nme.name -> nme.toLoc val dummyTargs2 = tparams.map(p => - TraitTag(Var(p.name))(originProv(p.toLoc, "method type parameter", p.name))) // FIXME or Skolem?! + TraitTag(Var(p.name), Set.empty)(originProv(p.toLoc, "method type parameter", p.name))) // FIXME or Skolem?! val targsMap2 = targsMap ++ tparams.iterator.map(_.name).zip(dummyTargs2).toMap val reverseRigid2 = reverseRigid ++ dummyTargs2.map(t => t -> freshVar(t.prov, N, S(t.id.idStr))(thisCtx.lvl + 1)) + diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 2bea1c5fe7..acb8540922 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -211,7 +211,7 @@ trait TypeSimplifier { self: Typer => } val traitPrefixes = - tts.iterator.collect{ case TraitTag(Var(tagNme)) => tagNme.capitalize }.toSet + tts.iterator.collect{ case TraitTag(Var(tagNme), _) => tagNme.capitalize }.toSet bo match { case S(cls @ ClassTag(Var(tagNme), ps)) @@ -1179,7 +1179,7 @@ trait TypeSimplifier { self: Typer => (fields1.size === fields2.size || nope) && fields1.map(_._2).lazyZip(fields2.map(_._2)).forall(unifyF) case (FunctionType(lhs1, rhs1), FunctionType(lhs2, rhs2)) => unify(lhs1, lhs2) && unify(rhs1, rhs2) case (Without(base1, names1), Without(base2, names2)) => unify(base1, base2) && (names1 === names2 || nope) - case (TraitTag(id1), TraitTag(id2)) => id1 === id2 || nope + case (TraitTag(id1, _), TraitTag(id2, _)) => id1 === id2 || nope case (SkolemTag(l1, id1), SkolemTag(l2, id2)) => l1 === l2 && id1 === id2 || nope case (ExtrType(pol1), ExtrType(pol2)) => pol1 === pol2 || nope case (TypeBounds(lb1, ub1), TypeBounds(lb2, ub2)) => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index c59992bbc7..82ae28070f 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1331,7 +1331,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), @@ -1341,7 +1341,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index dac3240f55..0c27c2bbcf 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -418,7 +418,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => sealed abstract class AbstractTag extends BaseTypeOrTag with TypeTag with Factorizable - case class TraitTag(id: Var)(val prov: TypeProvenance) extends AbstractTag with ObjectTag { + case class TraitTag(id: Var, parents: Set[TypeName])(val prov: TypeProvenance) extends AbstractTag with ObjectTag { def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = MinLevel def level: Level = MinLevel } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 282c339b9c..8da7588104 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1171,13 +1171,13 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 3696d40f9d..72d3938e73 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -10,15 +10,15 @@ class Exp[A]: Pair | Lit { // TODO enable class inheritance class Lit(n: int) extends Exp[int] class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification //│ ║ l.11: class Lit(n: int) extends Exp[int] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification //│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ╙── ^^^^^^ +//│ ╔══[ERROR] type signatures not yet supported for classes +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.6: fun test = if this is //│ ║ ^^^^^^^ diff --git a/shared/src/test/diff/mlscript/StressTraits.mls b/shared/src/test/diff/mlscript/StressTraits.mls index db60a314f4..c752de1117 100644 --- a/shared/src/test/diff/mlscript/StressTraits.mls +++ b/shared/src/test/diff/mlscript/StressTraits.mls @@ -83,7 +83,7 @@ foo arg //│ res: error | int //│ constrain calls : 71 //│ annoying calls : 90 -//│ subtyping calls : 4279 +//│ subtyping calls : 4291 :stats :e @@ -103,7 +103,7 @@ foo arg //│ res: error //│ constrain calls : 94 //│ annoying calls : 216 -//│ subtyping calls : 17114 +//│ subtyping calls : 17284 // ====== 2 ====== // @@ -160,7 +160,7 @@ foo arg //│ res: error | int //│ constrain calls : 82 //│ annoying calls : 90 -//│ subtyping calls : 2903 +//│ subtyping calls : 2915 // ====== 4 ====== // @@ -190,7 +190,7 @@ foo arg //│ res: error //│ constrain calls : 102 //│ annoying calls : 131 -//│ subtyping calls : 3945 +//│ subtyping calls : 3957 :stats :e @@ -208,7 +208,7 @@ foo (arg with { x = 1} with { y = 2 }) //│ res: error //│ constrain calls : 77 //│ annoying calls : 128 -//│ subtyping calls : 3358 +//│ subtyping calls : 3370 :stats :e @@ -226,7 +226,7 @@ foo (arg with { x = 1; y = 2; z = 3 }) //│ res: error //│ constrain calls : 77 //│ annoying calls : 128 -//│ subtyping calls : 3346 +//│ subtyping calls : 3358 // ====== 5 ====== // @@ -257,7 +257,7 @@ foo arg //│ res: error //│ constrain calls : 106 //│ annoying calls : 131 -//│ subtyping calls : 4376 +//│ subtyping calls : 4388 // ====== 6 ====== // @@ -289,7 +289,7 @@ foo arg //│ res: error //│ constrain calls : 110 //│ annoying calls : 131 -//│ subtyping calls : 4941 +//│ subtyping calls : 4953 // ====== 7 ====== // @@ -322,7 +322,7 @@ foo arg //│ res: error //│ constrain calls : 114 //│ annoying calls : 131 -//│ subtyping calls : 5661 +//│ subtyping calls : 5673 def foo_manual: ({fA: 'a} & a | {fB: 'a} & b & ~a | {fC: 'a} & c & ~a & ~b | {fD: 'a} & d & ~a & ~b & ~c | {fE: 'a} & e & ~a & ~b & ~c & ~d | {fF: 'a} & f & ~a & ~b & ~c & ~d & ~e | {fG: 'a} & g & ~a & ~b & ~c & ~d & ~e & ~f) -> 'a //│ foo_manual: ({fA: 'a} & #A | ~#A & ({fB: 'a} & #B | ~#B & ({fC: 'a} & #C | ~#C & ({fD: 'a} & #D | ~#D & ({fE: 'a} & #E | ~#E & ({fF: 'a} & #F | {fG: 'a} & #G & ~#F)))))) -> 'a @@ -388,6 +388,6 @@ foo arg //│ res: error //│ constrain calls : 118 //│ annoying calls : 131 -//│ subtyping calls : 6557 +//│ subtyping calls : 6569 diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 020af89099..09f2d8e221 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -48,6 +48,43 @@ trait Oth extends Test { //│ fun foo: int //│ } +let oth1: Oth +//│ let oth1: Oth + +oth1.bar(true) +//│ bool + +:d +oth1: Test +//│ 0. Typing TypingUnit(List(oth1 : Test)) +//│ | Typing unit statements +//│ | | 0. Typing term oth1 : Test +//│ | | | 0. Typing term oth1 +//│ | | | 0. : ‹∀ 0. Oth› +//│ | | | Typing type TypeName(Test) +//│ | | | | vars=Map() newDefsInfo=Map() +//│ | | | | 0. type TypeName(Test) +//│ | | | | => Test +//│ | | | => Test ——— +//│ | | | CONSTRAIN ‹∀ 0. Oth› +//│ Eql[C] + +let ct: Test = c +//│ let ct: Test + c.foo //│ int c.bar(true) //│ bool +// :d c: Test +//│ Test + +:e +c: Oth //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.125: c: Test +//│ ║ l.207: c: Oth //│ ║ ^ -//│ ╟── application of type `C` is not an instance of type `Test` -//│ ║ l.116: let c = C() +//│ ╟── application of type `C` is not an instance of type `Oth` +//│ ║ l.187: let c = C() //│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `#Test` -//│ ║ l.125: c: Test +//│ ╟── but it flows into reference with expected type `#Oth` +//│ ║ l.207: c: Oth //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.125: c: Test -//│ ╙── ^^^^ -//│ Test +//│ ║ l.207: c: Oth +//│ ╙── ^^^ +//│ Oth // :d let c1: Test = C() -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.141: let c1: Test = C() -//│ ║ ^^^ -//│ ╟── application of type `C` is not an instance of type `Test` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.141: let c1: Test = C() -//│ ╙── ^^^^ //│ let c1: Test // :d @@ -153,30 +228,36 @@ fun fcc(x: C) = x.foo //│ fun fcc: (x: C,) -> int fun fc(x: Test) = x +fun ffm(x: F) = x.get //│ fun fc: (x: Test,) -> Test +//│ fun ffm: (x: F,) -> bool + +:e +fun fee(x: Test) = x: Oth +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.236: fun fee(x: Test) = x: Oth +//│ ║ ^ +//│ ╟── type `#Test` is not an instance of type `Oth` +//│ ║ l.236: fun fee(x: Test) = x: Oth +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `#Oth` +//│ ║ l.236: fun fee(x: Test) = x: Oth +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.236: fun fee(x: Test) = x: Oth +//│ ╙── ^^^ +//│ fun fee: (x: Test,) -> Oth fc(c) //│ Test fun fts['a](x: 'a & Test) = x.foo fts(c) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.162: fts(c) -//│ ║ ^^^^^^ -//│ ╟── application of type `C` is not an instance of type `Test` -//│ ║ l.116: let c = C() -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `#Test` -//│ ║ l.162: fts(c) -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.161: fun fts['a](x: 'a & Test) = x.foo -//│ ║ ^^^^ -//│ ╟── from intersection type: -//│ ║ l.161: fun fts['a](x: 'a & Test) = x.foo -//│ ╙── ^^^^^^^^^ //│ fun fts: forall 'foo. (x: Test & {foo: 'foo} | Test & ~#Test,) -> 'foo -//│ error | int +//│ int + +fts(oth1) +//│ int fts(c1) //│ int @@ -195,19 +276,19 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.195: fun a1 = 4 +//│ ║ l.276: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.195: fun a1 = 4 +//│ ║ l.276: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.195: fun a1 = 4 +//│ ║ l.276: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.184: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.265: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.184: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.265: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 @@ -223,18 +304,6 @@ trait Ele { class CE extends Ele { fun ce(x) = x } -//│ ╔══[ERROR] Type mismatch in definition of method ce: -//│ ║ l.224: fun ce(x) = x -//│ ║ ^^^^^^^^^ -//│ ╟── type `#Oth` is not an instance of type `Test` -//│ ║ l.217: fun ce: Oth -> Test -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `#Test` -//│ ║ l.224: fun ce(x) = x -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.217: fun ce: Oth -> Test -//│ ╙── ^^^^ //│ class CE() { //│ fun ce: Oth -> Test //│ } @@ -244,11 +313,11 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.243: class E1 extends Test { +//│ ║ l.312: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.244: fun foo = 2 +//│ ║ l.313: fun foo = 2 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.245: } +//│ ║ l.314: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -259,10 +328,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.259: trait TE1 extends C +//│ ║ l.328: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.260: trait TE2 extends M, Test +//│ ║ l.329: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() //│ trait TE2() @@ -273,13 +342,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.272: fun foo = true +//│ ║ l.341: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.272: fun foo = true +//│ ║ l.341: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.272: fun foo = true +//│ ║ l.341: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -296,10 +365,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.297: class D extends Test[int], Test[bool] +//│ ║ l.366: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.297: class D extends Test[int], Test[bool] +//│ ║ l.366: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -314,13 +383,6 @@ class B extends Base let b: Base = A() -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.316: let b: Base = A() -//│ ║ ^^^ -//│ ╟── application of type `A` is not an instance of type `Base` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.316: let b: Base = A() -//│ ╙── ^^^^ //│ let b: Base b: Base & (A | B) @@ -345,20 +407,7 @@ let f: Foo = Foo((1, 2)) f.aa //│ (??A, ??A,) -// FIXME let b: Base = f -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.349: let b: Base = f -//│ ║ ^ -//│ ╟── type `Foo[anything]` is not an instance of type `Base` -//│ ║ l.342: let f: Foo = Foo((1, 2)) -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `#Base` -//│ ║ l.349: let b: Base = f -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.349: let b: Base = f -//│ ╙── ^^^^ //│ let b: Base if b is Foo(a) then a else 0 @@ -367,10 +416,10 @@ if b is Foo(a) then a else 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.368: if b is Bar(f) then f else 0 +//│ ║ l.417: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.337: class Bar[B](f: B => B) extends Base +//│ ║ l.399: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -379,14 +428,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.378: if b is +//│ ║ l.427: if b is //│ ║ ^^^^ -//│ ║ l.379: Foo(a) then a +//│ ║ l.428: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.380: Bar(f) then f +//│ ║ l.429: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.337: class Bar[B](f: B => B) extends Base +//│ ║ l.399: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything @@ -394,7 +443,7 @@ if b is // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.395: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.444: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -423,112 +472,55 @@ fun fit(x: EM): WP = x w: Geo z: Geo e: WP -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.421: fun fot(x: EM): Geo = x -//│ ║ ^ -//│ ╟── type `#EM` is not an instance of type `Geo` -//│ ║ l.421: fun fot(x: EM): Geo = x -//│ ║ ^^ -//│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.421: fun fot(x: EM): Geo = x -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.421: fun fot(x: EM): Geo = x -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.422: fun fit(x: EM): WP = x -//│ ║ ^ -//│ ╟── type `#EM` is not an instance of type `WP` -//│ ║ l.422: fun fit(x: EM): WP = x -//│ ║ ^^ -//│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.422: fun fit(x: EM): WP = x -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.422: fun fit(x: EM): WP = x -//│ ╙── ^^ -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.423: w: Geo -//│ ║ ^ -//│ ╟── type `#WP` is not an instance of type `Geo` -//│ ║ l.414: let w: WP -//│ ║ ^^ -//│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.423: w: Geo -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.423: w: Geo -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.424: z: Geo -//│ ║ ^ -//│ ╟── type `#ZL` is not an instance of type `Geo` -//│ ║ l.413: let z: ZL -//│ ║ ^^ -//│ ╟── but it flows into reference with expected type `#Geo` -//│ ║ l.424: z: Geo -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.424: z: Geo -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.425: e: WP -//│ ║ ^ -//│ ╟── type `#EM` is not an instance of type `WP` -//│ ║ l.415: let e: EM -//│ ║ ^^ -//│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.425: e: WP -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.425: e: WP -//│ ╙── ^^ +w: ZL & GL +e: ZL & Geo //│ fun fot: (x: EM,) -> Geo //│ fun fit: (x: EM,) -> WP -//│ WP +//│ Geo & ZL :e fun fto(w: WP): EM = w z: WP g: ZL +e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.491: fun fto(w: WP): EM = w +//│ ║ l.482: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.491: fun fto(w: WP): EM = w +//│ ║ l.482: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.491: fun fto(w: WP): EM = w +//│ ║ l.482: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.491: fun fto(w: WP): EM = w +//│ ║ l.482: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.492: z: WP +//│ ║ l.483: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.413: let z: ZL +//│ ║ l.462: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.492: z: WP +//│ ║ l.483: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.492: z: WP +//│ ║ l.483: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.493: g: ZL +//│ ║ l.484: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.412: let g: Geo +//│ ║ l.461: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.493: g: ZL +//│ ║ l.484: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.493: g: ZL +//│ ║ l.484: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM -//│ ZL +//│ WP & ZL From ad3e08542c226bbe662d8766f4317ab9cf792d1d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 21 Apr 2023 01:20:31 +0800 Subject: [PATCH 246/498] Small omission? --- shared/src/main/scala/mlscript/TypeDefs.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 6d2d8d255f..1338542d89 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -116,7 +116,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => ClassTag(Var(td.nme.name), // ctx.allBaseClassesOf(td.nme.name) Set.single(TypeName("Eql")) // TODO superclasses - union ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) + | ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) )(prov) } def clsNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { @@ -124,6 +124,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => if (newDefs && td.kind.str.isCapitalized) ClassTag(Var(td.nme.name), // ctx.allBaseClassesOf(td.nme.name))(prov) Set.single(TypeName("Eql")) // TODO superclasses + | ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) )(prov) else ClassTag(Var(td.nme.name), ctx.allBaseClassesOf(td.nme.name))(prov) } From c258721595e5938ae2abd03444f9474c3570b537 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 21 Apr 2023 01:40:08 +0800 Subject: [PATCH 247/498] trait for modules --- .../scala/mlscript/ConstraintSolver.scala | 9 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- shared/src/test/diff/nu/Interfaces.mls | 160 ++++++++---------- 3 files changed, 80 insertions(+), 91 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index c5d29de35d..5d4bfa55c7 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -666,7 +666,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => // TODO: inherited trait tags - // println(s"!!! TODO !!! ${pt.parentsST} $pts") + println(s"class checking $pt $pts") if (pts.contains(pt) || pts.exists(p => pt.parentsST.contains(p.id))) println(s"OK $pt <: ${pts.mkString(" | ")}") // else f.fold(reportError())(f => annoying(Nil, done_ls, Nil, f)) @@ -694,10 +694,11 @@ class ConstraintSolver extends NormalForms { self: Typer => } case (LhsRefined(N, ts, r, trs), RhsBases(pts, N, trs2)) => // TODO inherited trait tags - // println(s"!!! TODO !!! ${ts} ${pts}") - if (pts.exists(p => ts.toList.collect { + println(s"tag checking ${ts} ${pts}") + if (pts.exists(p => ts.toList.flatMap { case TraitTag(n, h) => n :: h.toList.map(n => Var(n.name)) - }.flatten.contains(p.id))) + case _ => Nil + }.contains(p.id))) println(s"OK $ts <: $pts") else reportError() diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 79a4910c9c..0dcdc1fedf 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -380,7 +380,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nms => ClassTag(Var(td.nme.name), // TODO base classes - Set.single(TN("Eql")) + Set.single(TN("Eql")) union ihtags )(provTODO) case Cls => PolymorphicType.mk(level, diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 09f2d8e221..62325ee454 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -23,19 +23,11 @@ module M extends Test { //│ fun foo: int //│ } -// TODO for modules -ts(M) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.27: ts(M) -//│ ║ ^^^^^ -//│ ╟── reference of type `M` is not an instance of type `Test` -//│ ║ l.27: ts(M) -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.13: fun ts(x: Test) = x.foo -//│ ╙── ^^^^ -//│ error | int +M: Test +//│ Test +ts(M) +//│ int trait Oth extends Test { let a : int @@ -54,37 +46,33 @@ let oth1: Oth oth1.bar(true) //│ bool -:d oth1: Test -//│ 0. Typing TypingUnit(List(oth1 : Test)) -//│ | Typing unit statements -//│ | | 0. Typing term oth1 : Test -//│ | | | 0. Typing term oth1 -//│ | | | 0. : ‹∀ 0. Oth› -//│ | | | Typing type TypeName(Test) -//│ | | | | vars=Map() newDefsInfo=Map() -//│ | | | | 0. type TypeName(Test) -//│ | | | | => Test -//│ | | | => Test ——— -//│ | | | CONSTRAIN ‹∀ 0. Oth› Oth @@ -276,19 +264,19 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.276: fun a1 = 4 +//│ ║ l.264: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.276: fun a1 = 4 +//│ ║ l.264: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.276: fun a1 = 4 +//│ ║ l.264: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.265: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.253: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member a1: -//│ ║ l.265: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.253: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { //│ fun a1: 2 | 3 @@ -313,11 +301,11 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.312: class E1 extends Test { +//│ ║ l.300: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.313: fun foo = 2 +//│ ║ l.301: fun foo = 2 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.314: } +//│ ║ l.302: } //│ ╙── ^ //│ class E1() { //│ fun bar: bool -> bool @@ -328,10 +316,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.328: trait TE1 extends C +//│ ║ l.316: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.329: trait TE2 extends M, Test +//│ ║ l.317: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() //│ trait TE2() @@ -342,13 +330,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.341: fun foo = true +//│ ║ l.329: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.341: fun foo = true +//│ ║ l.329: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.341: fun foo = true +//│ ║ l.329: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -365,10 +353,10 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.366: class D extends Test[int], Test[bool] +//│ ║ l.354: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.366: class D extends Test[int], Test[bool] +//│ ║ l.354: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^ //│ class D() @@ -416,10 +404,10 @@ if b is Foo(a) then a else 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.417: if b is Bar(f) then f else 0 +//│ ║ l.405: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.399: class Bar[B](f: B => B) extends Base +//│ ║ l.387: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -428,14 +416,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.427: if b is +//│ ║ l.415: if b is //│ ║ ^^^^ -//│ ║ l.428: Foo(a) then a +//│ ║ l.416: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.429: Bar(f) then f +//│ ║ l.417: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.399: class Bar[B](f: B => B) extends Base +//│ ║ l.387: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything @@ -443,7 +431,7 @@ if b is // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.444: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.432: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -484,40 +472,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.482: fun fto(w: WP): EM = w +//│ ║ l.470: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.482: fun fto(w: WP): EM = w +//│ ║ l.470: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.482: fun fto(w: WP): EM = w +//│ ║ l.470: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.482: fun fto(w: WP): EM = w +//│ ║ l.470: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.483: z: WP +//│ ║ l.471: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.462: let z: ZL +//│ ║ l.450: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.483: z: WP +//│ ║ l.471: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.483: z: WP +//│ ║ l.471: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.484: g: ZL +//│ ║ l.472: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.461: let g: Geo +//│ ║ l.449: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.484: g: ZL +//│ ║ l.472: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.484: g: ZL +//│ ║ l.472: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL From 44ff359bcc785556c046e5e30a4e90692095eec1 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 21 Apr 2023 19:55:23 +0800 Subject: [PATCH 248/498] WIP: class inheritance, TODO: overriding check --- .../src/main/scala/mlscript/NuTypeDefs.scala | 64 ++++++--- shared/src/test/diff/codegen/Mixin.mls | 7 +- shared/src/test/diff/codegen/Nested.mls | 32 ++--- .../test/diff/nu/BasicClassInheritance.mls | 9 +- shared/src/test/diff/nu/Interfaces.mls | 123 ++++++++++++++++++ shared/src/test/diff/nu/ParamPassing.mls | 5 +- 6 files changed, 184 insertions(+), 56 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 0dcdc1fedf..012294f17a 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -525,13 +525,21 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => tags case (p, Var(nm), _) :: ps => ctx.get(nm) match { - case S(lti: DelayedTypeInfo) if lti.kind == Trt => - lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) - case S(lti: CompletedTypeInfo) if lti.kind == Trt => - lookupTags(ps, + case S(lti: DelayedTypeInfo) => lti.kind match { + case Trt | Cls | Nms => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) + case _ => lookupTags(ps, tags) + } + case S(lti: CompletedTypeInfo) => lti.kind match { + case Trt => lookupTags(ps, Set.single(TypeName(nm)) union lti.member.asInstanceOf[TypedNuTrt].inheritedTags union tags) + case Cls | Nms => lookupTags(ps, + Set.single(TypeName(nm)) union + lti.member.asInstanceOf[TypedNuCls].inheritedTags union + tags) + case _ => lookupTags(ps, tags) + } case _ => lookupTags(ps, tags) } } @@ -808,11 +816,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val tparamFields = tparamMems.map(p => p.nme -> p.ty) assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) - def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) + def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember], baseClass: Opt[Str]) : (ST, Ls[NuMember]) = parents match { case (p, v @ Var(mxnNme), mxnArgs) :: ps => - val newMembs = trace(s"${lvl}. Inheriting from $p") { + val (newMembs, bc) = trace(s"${lvl}. Inheriting from $p") { ctx.get(mxnNme) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { @@ -842,32 +850,53 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO check overriding val bodyMems = mxn.ttu.entities - paramMems ++ bodyMems + (paramMems ++ bodyMems, N) case trt: TypedNuTrt => - Nil + Nil -> N case cls: TypedNuCls => - err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO - Nil + // err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO + + if (baseClass.isDefined) { + err(msg"cannot inherit from more than one base class: ${baseClass.get} and ${mxnNme}", v.toLoc) + } + + if (mxnArgs.sizeCompare(cls.params) =/= 0) + err(msg"class $mxnNme expects ${ + cls.params.size.toString} parameters; got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) + + val paramMems = cls.params.lazyZip(mxnArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false)(lvl) + } + + // TODO check overriding + val bodyMems = cls.ttu.entities + + (paramMems ++ bodyMems, S(mxnNme)) + case als: TypedNuAls => // TODO dealias first? err(msg"Cannot inherit from a type alias", p.toLoc) - Nil + Nil -> N case als: NuParam => // TODO first-class mixins/classes... err(msg"Cannot inherit from a parameter", p.toLoc) - Nil + Nil -> N case cls: TypedNuFun => err(msg"Cannot inherit from this", p.toLoc) - Nil + Nil -> N } case S(_) => err(msg"Cannot inherit from this", p.toLoc) - Nil + Nil -> N case N => err(msg"Could not find definition `${mxnNme}`", p.toLoc) - Nil + Nil -> N } }() val newSuperType = WithType( @@ -879,7 +908,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } )(provTODO) )(provTODO) - inherit(ps, newSuperType, members ++ newMembs) + inherit(ps, newSuperType, members ++ newMembs, bc) case Nil => val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & @@ -900,7 +929,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)(lvl)) val (thisType, baseMems) = - inherit(parentSpecs, baseType, tparamMems ++ paramMems) + inherit(parentSpecs, baseType, tparamMems ++ paramMems, N) ctx += "super" -> VarSymbol(thisType, Var("super")) @@ -923,7 +952,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO substitute type parameters in info info match { case trt: TypedNuTrt => - // TODO also computer intersect computeInterface(ps, annot & trt.selfTy, memberUn(members, trt.members.values.toList)) // intersect members case _ => computeInterface(ps, annot, members) } diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index b72e833b59..5956e8c2fa 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -455,11 +455,8 @@ class Foo(x: int) //│ class Foo(x: int) -:e + class Bar(x: int, y: int) extends Foo(x + y) -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.459: class Bar(x: int, y: int) extends Foo(x + y) -//│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) @@ -581,7 +578,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.581: fun x = y +//│ ║ l.578: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index c707d2d08e..e965538fc5 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -721,7 +721,7 @@ ij.incY //│ res //│ = 3 -:e + :js module J { class K(x: int) {} @@ -729,12 +729,6 @@ module J { class M() extends K(1) {} class N(x: int) extends K(x + 2), L } -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.729: class M() extends K(1) {} -//│ ╙── ^^^^ -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.730: class N(x: int) extends K(x + 2), L -//│ ╙── ^^^^^^^^ //│ module J() { //│ class K(x: int) //│ mixin L() @@ -823,10 +817,10 @@ module J { let m = J.M() let n = J.N(2) //│ ╔══[ERROR] access to class member not yet supported -//│ ║ l.823: let m = J.M() +//│ ║ l.817: let m = J.M() //│ ╙── ^^ //│ ╔══[ERROR] access to class member not yet supported -//│ ║ l.824: let n = J.N(2) +//│ ║ l.818: let n = J.N(2) //│ ╙── ^^ //│ let m: error //│ let n: error @@ -867,7 +861,7 @@ module K { let m = K.L.M() m.f //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.867: let m = K.L.M() +//│ ║ l.861: let m = K.L.M() //│ ╙── ^^ //│ let m: error //│ error @@ -876,7 +870,6 @@ m.f //│ res //│ = 42 -:e module L { class M(x: int) {} module N { @@ -885,9 +878,6 @@ module L { } } } -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.884: class P(y: int) extends M(y + 1) {} -//│ ╙── ^^^^^^^^ //│ module L() { //│ class M(x: int) //│ module N() { @@ -901,7 +891,7 @@ module L { let op = L.N.O.P(0) op.x //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.901: let op = L.N.O.P(0) +//│ ║ l.891: let op = L.N.O.P(0) //│ ╙── ^^ //│ let op: error //│ error @@ -928,10 +918,10 @@ module M { } M.N.op(M.P()) //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.929: M.N.op(M.P()) +//│ ║ l.919: M.N.op(M.P()) //│ ╙── ^^ //│ ╔══[ERROR] access to class member not yet supported -//│ ║ l.929: M.N.op(M.P()) +//│ ║ l.919: M.N.op(M.P()) //│ ╙── ^^ //│ module M() { //│ module N() { @@ -1010,7 +1000,6 @@ M.N.op(M.P()) //│ res //│ = 1 -:e :js module N { module O { @@ -1018,9 +1007,6 @@ module N { } class Q() } -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.1017: class P() extends Q -//│ ╙── ^ //│ module N() { //│ module O() { //│ class P() @@ -1089,7 +1075,7 @@ module N { :e N.O.P() //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.1090: N.O.P() +//│ ║ l.1076: N.O.P() //│ ╙── ^^ //│ error //│ res @@ -1105,7 +1091,7 @@ class I(x: int) { } I(1).J(3).a //│ ╔══[ERROR] access to class member not yet supported -//│ ║ l.1106: I(1).J(3).a +//│ ║ l.1092: I(1).J(3).a //│ ╙── ^^ //│ class I(x: int) { //│ class J(z: int) { diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 330b8b6a45..5f4b4d2c4f 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -6,9 +6,6 @@ class A // TODO class B(m: int) extends A -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.8: class B(m: int) extends A -//│ ╙── ^ //│ class B(m: int) @@ -17,9 +14,9 @@ class A(n: int) // TODO class B(m: int) extends A(n + 1) -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.19: class B(m: int) extends A(n + 1) -//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] identifier not found: n +//│ ║ l.16: class B(m: int) extends A(n + 1) +//│ ╙── ^ //│ class B(m: int) //│ Code generation encountered an error: //│ unresolved symbol n diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 62325ee454..271eef726a 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -510,5 +510,128 @@ e: ZL & WP //│ fun fto: (w: WP,) -> EM //│ WP & ZL +class Bs(a: bool) { + fun foo(x) = x + 1 +} +//│ class Bs(a: bool) { +//│ fun foo: int -> int +//│ } + +class Ih extends Bs(false) { + fun bar(x) = x + fun foo(x) = 1 +} +//│ class Ih() { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun foo: anything -> 1 +//│ } + +let ih1 = Ih() +//│ let ih1: Ih + +ih1.foo(1) +//│ 1 + +ih1: Bs +//│ Bs + +ih1.a +//│ false + +// FIXME +class Eh2 extends Bs(true), Ele { + fun foo(x) = x && true + fun ce(x) = x +} +//│ class Eh2() { +//│ fun ce: Oth -> Test +//│ fun foo: bool -> bool +//│ } + +:e +class Eh extends Bs(1) +class Eh1 extends Bs +class Eh3 extends Bs(false), Test +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.552: class Eh extends Bs(1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── integer literal of type `1` is not an instance of type `bool` +//│ ║ l.552: class Eh extends Bs(1) +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.513: class Bs(a: bool) { +//│ ╙── ^^^^ +//│ ╔══[ERROR] class Bs expects 1 parameters; got 0 +//│ ║ l.553: class Eh1 extends Bs +//│ ╙── ^^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.514: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── function of type `?a -> ?b` is not an instance of type `int` +//│ ║ l.514: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^ +//│ ╟── but it flows into definition of method foo with expected type `int` +//│ ║ l.514: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.5: fun foo: int +//│ ║ ^^^ +//│ ╟── from signature of member foo: +//│ ║ l.5: fun foo: int +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Member bar is declared in parent trait but not implemented +//│ ║ l.554: class Eh3 extends Bs(false), Test +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ class Eh() { +//│ fun foo: int -> int +//│ } +//│ class Eh1() { +//│ fun foo: int -> int +//│ } +//│ class Eh3() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } +class Ca(a: int) extends Oth { + fun foo = 1 + fun cool(x) = false + fun bar(x) = x +} +//│ class Ca(a: int) { +//│ let a: int +//│ fun bar: bool -> bool +//│ fun cool: int -> bool +//│ fun foo: int +//│ } + +class Cx(a: 1 | 2, b: bool) extends Ca(a) +//│ class Cx(a: 1 | 2, b: bool) { +//│ fun bar: 'a -> 'a +//│ fun cool: anything -> false +//│ fun foo: 1 +//│ } + +let cx1 = Cx(2, true) +//│ let cx1: Cx + +cx1.bar(cx1.b) +//│ bool + +cx1: Test +//│ Test +cx1: Ca +//│ Ca + +class Bc1(foo: int) +class Bc2(bar: bool) +//│ class Bc1(foo: int) +//│ class Bc2(bar: bool) + +:e +class Bc12 extends Bc1(1), Bc2(true) +//│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 +//│ ║ l.633: class Bc12 extends Bc1(1), Bc2(true) +//│ ╙── ^^^ +//│ class Bc12() diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 4f890426d7..db8a960ca2 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -5,11 +5,8 @@ class Foo(x: int) //│ class Foo(x: int) -:e + class Bar(x: int, y: int) extends Foo(x + y) -//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.9: class Bar(x: int, y: int) extends Foo(x + y) -//│ ╙── ^^^^^^^^^^ //│ class Bar(x: int, y: int) From 65f4feb240b3aa37b431167f26358fbe258b7762 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 21 Apr 2023 23:34:43 +0800 Subject: [PATCH 249/498] WIP overriding check --- .../src/main/scala/mlscript/NuTypeDefs.scala | 104 +++++++---- shared/src/test/diff/codegen/Mixin.mls | 3 +- shared/src/test/diff/nu/Interfaces.mls | 176 ++++++++++++++++-- 3 files changed, 231 insertions(+), 52 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 012294f17a..1781ba7c3d 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -816,11 +816,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val tparamFields = tparamMems.map(p => p.nme -> p.ty) assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) - def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember], baseClass: Opt[Str]) + def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) : (ST, Ls[NuMember]) = parents match { case (p, v @ Var(mxnNme), mxnArgs) :: ps => - val (newMembs, bc) = trace(s"${lvl}. Inheriting from $p") { + val newMembs = trace(s"${lvl}. Inheriting from $p") { ctx.get(mxnNme) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { @@ -850,53 +850,32 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO check overriding val bodyMems = mxn.ttu.entities - (paramMems ++ bodyMems, N) + paramMems ++ bodyMems case trt: TypedNuTrt => - Nil -> N + Nil case cls: TypedNuCls => - // err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) // TODO - - if (baseClass.isDefined) { - err(msg"cannot inherit from more than one base class: ${baseClass.get} and ${mxnNme}", v.toLoc) - } - - if (mxnArgs.sizeCompare(cls.params) =/= 0) - err(msg"class $mxnNme expects ${ - cls.params.size.toString} parameters; got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) - - val paramMems = cls.params.lazyZip(mxnArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false)(lvl) - } - - // TODO check overriding - val bodyMems = cls.ttu.entities - - (paramMems ++ bodyMems, S(mxnNme)) - + // err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) + Nil case als: TypedNuAls => // TODO dealias first? err(msg"Cannot inherit from a type alias", p.toLoc) - Nil -> N + Nil case als: NuParam => // TODO first-class mixins/classes... err(msg"Cannot inherit from a parameter", p.toLoc) - Nil -> N + Nil case cls: TypedNuFun => err(msg"Cannot inherit from this", p.toLoc) - Nil -> N + Nil } case S(_) => err(msg"Cannot inherit from this", p.toLoc) - Nil -> N + Nil case N => err(msg"Could not find definition `${mxnNme}`", p.toLoc) - Nil -> N + Nil } }() val newSuperType = WithType( @@ -908,7 +887,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } )(provTODO) )(provTODO) - inherit(ps, newSuperType, members ++ newMembs, bc) + inherit(ps, newSuperType, members ++ newMembs) case Nil => val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & @@ -929,7 +908,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)(lvl)) val (thisType, baseMems) = - inherit(parentSpecs, baseType, tparamMems ++ paramMems, N) + inherit(parentSpecs, baseType, tparamMems ++ paramMems) ctx += "super" -> VarSymbol(thisType, Var("super")) @@ -937,7 +916,54 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO report non-unit result/statements? // TODO check overriding - val clsMems = ttu.entities + def computeBaseClass(parents: Ls[ParentSpec], members: Ls[NuMember], baseClass: Opt[Str]): Ls[NuMember] = + parents match { + case (p, v @ Var(parNme), parArgs) :: ps => + ctx.get(parNme) match { + case S(lti: LazyTypeInfo) => + val info = lti.complete() + info match { + case cls: TypedNuCls => + if (baseClass.isDefined) { + err(msg"cannot inherit from more than one base class: ${baseClass.get} and ${parNme}", v.toLoc) + } + + if (parArgs.sizeCompare(cls.params) =/= 0) + err(msg"class $parNme expects ${ + cls.params.size.toString} parameters; got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) + + val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false)(lvl) + } + val numem = paramMems ++ cls.members.values.toList + val res = members ++ numem.flatMap { m => + members.find(x => x.name == m.name) match { + case S(mem: TypedNuTermDef) => + val memSign = mem.typeSignature + // TODO fix here + val parSign = m.asInstanceOf[TypedNuTermDef].typeSignature + println(s"checking overriding: $memSign <: $parSign") + implicit val prov: TP = memSign.prov + constrain(memSign, parSign) + Nil + case _ => m :: Nil + } + } + + computeBaseClass(ps, res , S(parNme)) + + case _ => computeBaseClass(ps, members, baseClass) + } + case _ => computeBaseClass(ps, members, baseClass) + } + case Nil => members + } + + val clsMems = computeBaseClass(parentSpecs, ttu.entities, N) val impltdMems = baseMems ++ clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers @@ -965,7 +991,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => (annot, members) } val thisTag = TopType //clsNameToNomTag(td)(provTODO, ctx) - val (ifaceAnnot, ifaceMembers) = computeInterface(parentSpecs, thisTag, Nil) + val (_, ifaceMembers) = computeInterface(parentSpecs, thisTag, Nil) // TODO check mems against interface stuff above ifaceMembers.foreach { m => @@ -1071,6 +1097,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // todo: check fd.rhs => TypedNuFun(a.level, a.fd, a.bodyType & b.bodyType) + // case (S(a: NuParam), S(b: NuParam)) + // if a.level == b.level + // && a.nme.name == b.nme.name + // && a.isType == b.isType + // => + // NuParam(a.nme, a.ty && b.ty, a.isType)(a.level) case(S(a), N) => a case(N, S(b)) => b case _ => diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 5956e8c2fa..cb3bbe6df7 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -455,7 +455,6 @@ class Foo(x: int) //│ class Foo(x: int) - class Bar(x: int, y: int) extends Foo(x + y) //│ class Bar(x: int, y: int) @@ -578,7 +577,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.578: fun x = y +//│ ║ l.577: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 271eef726a..21c593620c 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -103,7 +103,7 @@ trait Mixed extends Geo, Anemo class C extends Test { - fun foo = 1 + fun foo: 1 = 1 fun bar(x) = x } //│ class C() { @@ -517,12 +517,143 @@ class Bs(a: bool) { //│ fun foo: int -> int //│ } +:d class Ih extends Bs(false) { fun bar(x) = x fun foo(x) = 1 } +//│ 0. Typing TypingUnit(List(class Ih(): Bs (false,) {fun bar = (x,) => x; fun foo = (x,) => 1})) +//│ | 0. Created lazy type info for class Ih(): Bs (false,) {fun bar = (x,) => x; fun foo = (x,) => 1} +//│ | Completing class Ih(): Bs (false,) {fun bar = (x,) => x; fun foo = (x,) => 1} +//│ | | UNSTASHING... (out) +//│ | | Type params +//│ | | UNSTASHING... (out) +//│ | | Params +//│ | | UNSTASHING... (out) +//│ | | Typing type Top +//│ | | | vars=Map() newDefsInfo=Map() +//│ | | | 1. type Top +//│ | | | => ⊤ +//│ | | => ⊤ ——— +//│ | | 1. Inheriting from Bs (false,) +//│ | | 1. Finalizing inheritance with ({} w/ {} w/ {} & Ih) <: ih223' +//│ | | | CONSTRAIN ({} w/ {} w/ {} & Ih) ) x, fun foo = (x,) => 1)) +//│ | | | 1. Created lazy type info for fun bar = (x,) => x +//│ | | | 1. Created lazy type info for fun foo = (x,) => 1 +//│ | | | Completing fun bar = (x,) => x +//│ | | | | UNSTASHING... (out) +//│ | | | | Type params +//│ | | | | UNSTASHING... (out) +//│ | | | | Params +//│ | | | | 2. Typing term (x,) => x +//│ | | | | | 2. Typing pattern x, +//│ | | | | | | 2. Typing pattern x +//│ | | | | | | 2. : x226'' +//│ | | | | | 2. : (x226'',) +//│ | | | | | 2. Typing term x +//│ | | | | | 2. : x226'' +//│ | | | | 2. : (x226'' -> x226'') +//│ | | | | UNSTASHING... (out) +//│ | | | | CONSTRAIN (x226'' -> x226'') x226'') 1 +//│ | | | | UNSTASHING... (out) +//│ | | | | Type params +//│ | | | | UNSTASHING... (out) +//│ | | | | Params +//│ | | | | 2. Typing term (x,) => 1 +//│ | | | | | 2. Typing pattern x, +//│ | | | | | | 2. Typing pattern x +//│ | | | | | | 2. : x228'' +//│ | | | | | 2. : (x228'',) +//│ | | | | | 2. Typing term 1 +//│ | | | | | 2. : 1 +//│ | | | | 2. : (x228'' -> 1) +//│ | | | | UNSTASHING... (out) +//│ | | | | CONSTRAIN (x228'' -> 1) 1) +//│ | | CONSTRAIN false 1)› <: ‹∀ 1. (α217'' -> α219'')› +//│ | | CONSTRAIN ‹∀ 1. (x228'' -> 1)› α219'')› +//│ | | where +//│ α217'' <: int +//│ α219'' :> int +//│ | | 1. C ‹∀ 1. (x228'' -> 1)› α219'')› (0) +//│ | | | New skolem: α217'' ~> ‘_230'' +//│ | | | α217_231'' :> List(‘_230'') +//│ | | | α217_231'' <: List((‘_230'' | int)) +//│ | | | New skolem: α219'' ~> ‘_232'' +//│ | | | α219_233'' :> List((‘_232'' & int)) +//│ | | | α219_233'' <: List(‘_232'') +//│ | | | BUMP TO LEVEL 2 --> (α217_231'' -> α219_233'') +//│ | | | where +//│ α217_231'' :> ‘_230'' <: (‘_230'' | int) +//│ α219_233'' :> (‘_232'' & int) <: ‘_232'' +//│ | | | 2. C ‹∀ 1. (x228'' -> 1)› α219_233'') (2) +//│ | | | | 2. C ‹∀ 1. (x228'' -> 1)› α219_233'') (2) +//│ | | | | | could be distribbed: Set() +//│ | | | | | INST [1] ‹∀ 1. (x228'' -> 1)› +//│ | | | | | where +//│ | | | | | TO [2] ~> (x228_234'' -> 1) +//│ | | | | | where +//│ | | | | | 2. C (x228_234'' -> 1) α219_233'') (5) +//│ | | | | | | 2. C (α217_231'',) <: ‘_232'' +//│ | | | | | | | | allVarPols: -_232'' +//│ | | | | | | | | normLike[-] ‘_232'' +//│ | | | | | | | | | norm[-] ‘_232'' +//│ | | | | | | | | | | DNF: DNF(2, {}∧‘_232'') +//│ | | | | | | | | | ~> ‘_232'' +//│ | | | | | | | | allVarPols: +//│ | | | | | | | | normLike[+] 1 +//│ | | | | | | | | | norm[+] 1 +//│ | | | | | | | | | | DNF: DNF(0, 1{}) +//│ | | | | | | | | | ~> 1 +//│ ╔══[ERROR] Type mismatch in function: +//│ ║ l.523: fun foo(x) = 1 +//│ ║ ^^^^^^^ +//│ ╟── integer literal of type `1` does not match type `?_` +//│ ║ l.523: fun foo(x) = 1 +//│ ║ ^ +//│ ╟── Note: constraint arises from operator application: +//│ ║ l.514: fun foo(x) = x + 1 +//│ ╙── ^^^^^ +//│ | | | UNSTASHING... +//│ | | | UNSTASHING... (out) +//│ | | UNSTASHING... (out) +//│ | | UNSTASHING... (out) +//│ | Typing unit statements +//│ | : None +//│ ======== TYPED ======== +//│ class Ih +//│ this: ⊤ +//│ fun bar: ‹∀ 1. (x226'' -> x226'')› where +//│ fun foo: ‹∀ 1. (x228'' -> 1)› where //│ class Ih() { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: forall 'x. 'x -> 'x //│ fun foo: anything -> 1 //│ } @@ -536,13 +667,29 @@ ih1: Bs //│ Bs ih1.a -//│ false +//│ bool -// FIXME +:e class Eh2 extends Bs(true), Ele { - fun foo(x) = x && true + fun foo(x) = x && false fun ce(x) = x } +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.674: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── variable of type `?_` is not an instance of type `bool` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.674: fun foo(x) = x && false +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.674: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── operator application of type `bool` does not match type `?_` +//│ ║ l.674: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from operator application: +//│ ║ l.514: fun foo(x) = x + 1 +//│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: Oth -> Test //│ fun foo: bool -> bool @@ -553,21 +700,21 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.552: class Eh extends Bs(1) +//│ ║ l.699: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.552: class Eh extends Bs(1) +//│ ║ l.699: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.513: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameters; got 0 -//│ ║ l.553: class Eh1 extends Bs +//│ ║ l.700: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.514: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> ?b` is not an instance of type `int` +//│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` //│ ║ l.514: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` @@ -580,7 +727,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.554: class Eh3 extends Bs(false), Test +//│ ║ l.701: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -607,9 +754,10 @@ class Ca(a: int) extends Oth { class Cx(a: 1 | 2, b: bool) extends Ca(a) //│ class Cx(a: 1 | 2, b: bool) { -//│ fun bar: 'a -> 'a -//│ fun cool: anything -> false -//│ fun foo: 1 +//│ let a: int +//│ fun bar: bool -> bool +//│ fun cool: int -> bool +//│ fun foo: int //│ } let cx1 = Cx(2, true) @@ -632,6 +780,6 @@ class Bc2(bar: bool) :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.633: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.781: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() From f91e9341dd550abe2cc8c4886f5fd288dba23614 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 21 Apr 2023 23:45:16 +0800 Subject: [PATCH 250/498] Fix skolem bounds computation --- .../scala/mlscript/ConstraintSolver.scala | 4 +- shared/src/test/diff/mlscript/BadMethods.mls | 4 +- shared/src/test/diff/nu/Interfaces.mls | 155 ++---------------- 3 files changed, 16 insertions(+), 147 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 5d4bfa55c7..6ad8f81157 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1640,9 +1640,9 @@ class ConstraintSolver extends NormalForms { self: Typer => // where rv is the rigidified variables. // Now, since there may be recursive bounds, we do the same // but through the indirection of a type variable tv2: - tv2.lowerBounds ::= tv.lowerBounds.map(freshen).foldLeft(rv: ST)(_ & _) + tv2.lowerBounds ::= tv.upperBounds.map(freshen).foldLeft(rv: ST)(_ & _) println(s"$tv2 :> ${tv2.lowerBounds}") - tv2.upperBounds ::= tv.upperBounds.map(freshen).foldLeft(rv: ST)(_ | _) + tv2.upperBounds ::= tv.lowerBounds.map(freshen).foldLeft(rv: ST)(_ | _) println(s"$tv2 <: ${tv2.upperBounds}") tv2 } else { diff --git a/shared/src/test/diff/mlscript/BadMethods.mls b/shared/src/test/diff/mlscript/BadMethods.mls index 5aebf8c5ab..1abe0af7f2 100644 --- a/shared/src/test/diff/mlscript/BadMethods.mls +++ b/shared/src/test/diff/mlscript/BadMethods.mls @@ -823,10 +823,10 @@ class Test9B: Test9A[int] //│ ╔══[ERROR] Type mismatch in method declaration: //│ ║ l.815: method Mth9A : Test9A[int] -> int //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `Test9A[int] -> int` does not match type `?x` +//│ ╟── type `Test9A[int] -> int` does not match type `int | ?x` //│ ║ l.815: method Mth9A : Test9A[int] -> int //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into method declaration with expected type `?x` +//│ ╟── but it flows into method declaration with expected type `int | ?x` //│ ║ l.815: method Mth9A : Test9A[int] -> int //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from field selection: diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 21c593620c..56b3735d63 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -517,143 +517,12 @@ class Bs(a: bool) { //│ fun foo: int -> int //│ } -:d class Ih extends Bs(false) { fun bar(x) = x fun foo(x) = 1 } -//│ 0. Typing TypingUnit(List(class Ih(): Bs (false,) {fun bar = (x,) => x; fun foo = (x,) => 1})) -//│ | 0. Created lazy type info for class Ih(): Bs (false,) {fun bar = (x,) => x; fun foo = (x,) => 1} -//│ | Completing class Ih(): Bs (false,) {fun bar = (x,) => x; fun foo = (x,) => 1} -//│ | | UNSTASHING... (out) -//│ | | Type params -//│ | | UNSTASHING... (out) -//│ | | Params -//│ | | UNSTASHING... (out) -//│ | | Typing type Top -//│ | | | vars=Map() newDefsInfo=Map() -//│ | | | 1. type Top -//│ | | | => ⊤ -//│ | | => ⊤ ——— -//│ | | 1. Inheriting from Bs (false,) -//│ | | 1. Finalizing inheritance with ({} w/ {} w/ {} & Ih) <: ih223' -//│ | | | CONSTRAIN ({} w/ {} w/ {} & Ih) ) x, fun foo = (x,) => 1)) -//│ | | | 1. Created lazy type info for fun bar = (x,) => x -//│ | | | 1. Created lazy type info for fun foo = (x,) => 1 -//│ | | | Completing fun bar = (x,) => x -//│ | | | | UNSTASHING... (out) -//│ | | | | Type params -//│ | | | | UNSTASHING... (out) -//│ | | | | Params -//│ | | | | 2. Typing term (x,) => x -//│ | | | | | 2. Typing pattern x, -//│ | | | | | | 2. Typing pattern x -//│ | | | | | | 2. : x226'' -//│ | | | | | 2. : (x226'',) -//│ | | | | | 2. Typing term x -//│ | | | | | 2. : x226'' -//│ | | | | 2. : (x226'' -> x226'') -//│ | | | | UNSTASHING... (out) -//│ | | | | CONSTRAIN (x226'' -> x226'') x226'') 1 -//│ | | | | UNSTASHING... (out) -//│ | | | | Type params -//│ | | | | UNSTASHING... (out) -//│ | | | | Params -//│ | | | | 2. Typing term (x,) => 1 -//│ | | | | | 2. Typing pattern x, -//│ | | | | | | 2. Typing pattern x -//│ | | | | | | 2. : x228'' -//│ | | | | | 2. : (x228'',) -//│ | | | | | 2. Typing term 1 -//│ | | | | | 2. : 1 -//│ | | | | 2. : (x228'' -> 1) -//│ | | | | UNSTASHING... (out) -//│ | | | | CONSTRAIN (x228'' -> 1) 1) -//│ | | CONSTRAIN false 1)› <: ‹∀ 1. (α217'' -> α219'')› -//│ | | CONSTRAIN ‹∀ 1. (x228'' -> 1)› α219'')› -//│ | | where -//│ α217'' <: int -//│ α219'' :> int -//│ | | 1. C ‹∀ 1. (x228'' -> 1)› α219'')› (0) -//│ | | | New skolem: α217'' ~> ‘_230'' -//│ | | | α217_231'' :> List(‘_230'') -//│ | | | α217_231'' <: List((‘_230'' | int)) -//│ | | | New skolem: α219'' ~> ‘_232'' -//│ | | | α219_233'' :> List((‘_232'' & int)) -//│ | | | α219_233'' <: List(‘_232'') -//│ | | | BUMP TO LEVEL 2 --> (α217_231'' -> α219_233'') -//│ | | | where -//│ α217_231'' :> ‘_230'' <: (‘_230'' | int) -//│ α219_233'' :> (‘_232'' & int) <: ‘_232'' -//│ | | | 2. C ‹∀ 1. (x228'' -> 1)› α219_233'') (2) -//│ | | | | 2. C ‹∀ 1. (x228'' -> 1)› α219_233'') (2) -//│ | | | | | could be distribbed: Set() -//│ | | | | | INST [1] ‹∀ 1. (x228'' -> 1)› -//│ | | | | | where -//│ | | | | | TO [2] ~> (x228_234'' -> 1) -//│ | | | | | where -//│ | | | | | 2. C (x228_234'' -> 1) α219_233'') (5) -//│ | | | | | | 2. C (α217_231'',) <: ‘_232'' -//│ | | | | | | | | allVarPols: -_232'' -//│ | | | | | | | | normLike[-] ‘_232'' -//│ | | | | | | | | | norm[-] ‘_232'' -//│ | | | | | | | | | | DNF: DNF(2, {}∧‘_232'') -//│ | | | | | | | | | ~> ‘_232'' -//│ | | | | | | | | allVarPols: -//│ | | | | | | | | normLike[+] 1 -//│ | | | | | | | | | norm[+] 1 -//│ | | | | | | | | | | DNF: DNF(0, 1{}) -//│ | | | | | | | | | ~> 1 -//│ ╔══[ERROR] Type mismatch in function: -//│ ║ l.523: fun foo(x) = 1 -//│ ║ ^^^^^^^ -//│ ╟── integer literal of type `1` does not match type `?_` -//│ ║ l.523: fun foo(x) = 1 -//│ ║ ^ -//│ ╟── Note: constraint arises from operator application: -//│ ║ l.514: fun foo(x) = x + 1 -//│ ╙── ^^^^^ -//│ | | | UNSTASHING... -//│ | | | UNSTASHING... (out) -//│ | | UNSTASHING... (out) -//│ | | UNSTASHING... (out) -//│ | Typing unit statements -//│ | : None -//│ ======== TYPED ======== -//│ class Ih -//│ this: ⊤ -//│ fun bar: ‹∀ 1. (x226'' -> x226'')› where -//│ fun foo: ‹∀ 1. (x228'' -> 1)› where //│ class Ih() { -//│ fun bar: forall 'x. 'x -> 'x +//│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 1 //│ } @@ -675,17 +544,17 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.674: fun foo(x) = x && false +//│ ║ l.543: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── variable of type `?_` is not an instance of type `bool` +//│ ╟── expression of type `int & ?_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.674: fun foo(x) = x && false +//│ ║ l.543: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.674: fun foo(x) = x && false +//│ ║ l.543: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `?_` -//│ ║ l.674: fun foo(x) = x && false +//│ ╟── operator application of type `bool` does not match type `int | ?_` +//│ ║ l.543: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: //│ ║ l.514: fun foo(x) = x + 1 @@ -700,16 +569,16 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.699: class Eh extends Bs(1) +//│ ║ l.568: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.699: class Eh extends Bs(1) +//│ ║ l.568: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.513: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameters; got 0 -//│ ║ l.700: class Eh1 extends Bs +//│ ║ l.569: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.514: fun foo(x) = x + 1 @@ -727,7 +596,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.701: class Eh3 extends Bs(false), Test +//│ ║ l.570: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -780,6 +649,6 @@ class Bc2(bar: bool) :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.781: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.650: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() From 5cf2db75e85aecedece6936bf56e1f7b800d34a0 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 21 Apr 2023 23:53:37 +0800 Subject: [PATCH 251/498] Minor --- .../scala/mlscript/ConstraintSolver.scala | 4 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 47 +++++--- shared/src/test/diff/gadt/Exp1.mls | 100 +++++++++++++++--- shared/src/test/diff/nu/GADTMono.mls | 7 +- shared/src/test/diff/nu/Interfaces.mls | 91 +++++++++------- 5 files changed, 176 insertions(+), 73 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 6ad8f81157..a097f06a9d 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1625,9 +1625,9 @@ class ConstraintSolver extends NormalForms { self: Typer => case Some(tv) => tv case None if rigidify && tv.level <= below => // * Rigid type variables (ie, skolems) are encoded as SkolemTag-s - val rv = SkolemTag(lvl, freshVar(noProv, N, tv.nameHint.orElse(S("_"))))(tv.prov) + val rv = SkolemTag(lvl, freshVar(noProv, S(tv), tv.nameHint.orElse(S("_"))))(tv.prov) println(s"New skolem: $tv ~> $rv") - if (tv.lowerBounds.nonEmpty || tv.upperBounds.nonEmpty) { + if (tv.lowerBounds.nonEmpty || tv.upperBounds.nonEmpty) { // TODO just add bounds to skolems! should lead to simpler constraints // The bounds of `tv` may be recursive (refer to `tv` itself), // so here we create a fresh variabe that will be able to tie the presumed recursive knot // (if there is no recursion, it will just be a useless type variable) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 1781ba7c3d..85731b6ac1 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -503,27 +503,30 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { // and derive from these the full set of transitively inherited tags - type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) + type ParentSpec = (Term, Var, Ls[Type], Ls[Opt[Var] -> Fld]) val parentSpecs: Ls[ParentSpec] = decl match { case td: NuTypeDef if td.kind == Trt || td.kind == Cls || td.kind == Nms => td.parents.flatMap { case v @ Var(nme) => - S(v, v, Nil) - case p @ App(v @ Var(nme), Tup(args)) => - S(p, v, args) - case p => - err(msg"Unsupported parent specification", p.toLoc) // TODO - // support type application - N - } + S(v, v, Nil, Nil) + case p @ App(v @ Var(nme), Tup(args)) => + S(p, v, Nil, args) + case TyApp(v @ Var(nme), targs) => + S(v, v, targs, Nil) + case p @ App(TyApp(v @ Var(nme), targs), Tup(args)) => + S(p, v, targs, args) + case p => + err(msg"Unsupported parent specification", p.toLoc) // TODO + N + } case _ => Nil } def lookupTags(parents: Ls[ParentSpec], tags: Set[TypeName]): Set[TypeName] = { parents match { case Nil => tags - case (p, Var(nm), _) :: ps => + case (p, Var(nm), _, _) :: ps => ctx.get(nm) match { case S(lti: DelayedTypeInfo) => lti.kind match { case Trt | Cls | Nms => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) @@ -740,7 +743,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember]) : (ST, ST, Ls[NuMember]) = parents match { - case (p, v @ Var(trtName), mxnArgs) :: ps => + case (p, v @ Var(trtName), targs, args) :: ps => + if (targs.nonEmpty) err(msg"trait type arguments not yet supported", p.toLoc) + if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) ctx.get(trtName) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { case trt: TypedNuTrt => @@ -819,10 +824,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) : (ST, Ls[NuMember]) = parents match { - case (p, v @ Var(mxnNme), mxnArgs) :: ps => + case (p, v @ Var(mxnNme), mxnTargs, mxnArgs) :: ps => + if (mxnTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) val newMembs = trace(s"${lvl}. Inheriting from $p") { ctx.get(mxnNme) match { case S(lti: LazyTypeInfo) => + lti.complete().freshen match { case mxn: TypedNuMxn => @@ -866,8 +873,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO first-class mixins/classes... err(msg"Cannot inherit from a parameter", p.toLoc) Nil + case als: NuTypeParam => + err(msg"Cannot inherit from a type parameter", p.toLoc) + Nil case cls: TypedNuFun => - err(msg"Cannot inherit from this", p.toLoc) + err(msg"Cannot inherit from a function", p.toLoc) Nil } case S(_) => @@ -918,20 +928,21 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO check overriding def computeBaseClass(parents: Ls[ParentSpec], members: Ls[NuMember], baseClass: Opt[Str]): Ls[NuMember] = parents match { - case (p, v @ Var(parNme), parArgs) :: ps => + case (p, v @ Var(parNme), parTargs, parArgs) :: ps => ctx.get(parNme) match { case S(lti: LazyTypeInfo) => val info = lti.complete() info match { case cls: TypedNuCls => + if (parTargs.nonEmpty) err(msg"class type arguments not yet supported", p.toLoc) if (baseClass.isDefined) { err(msg"cannot inherit from more than one base class: ${baseClass.get} and ${parNme}", v.toLoc) } - + if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ cls.params.size.toString} parameters; got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - + val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec implicit val genLambdas: GenLambdas = true val a_ty = typeTerm(a) @@ -970,7 +981,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def computeInterface(parents: Ls[ParentSpec], annot: ST, members: Ls[NuMember]): (ST, Ls[NuMember]) = parents match { - case (p, v @ Var(parNme), parArgs) :: ps => + case (p, v @ Var(parNme), parTargs, parArgs) :: ps => // TODO find traits in `parents`; intersect their member types and self types ctx.get(parNme) match { case S(lti: LazyTypeInfo) => @@ -978,6 +989,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO substitute type parameters in info info match { case trt: TypedNuTrt => + if (parTargs.nonEmpty) err(msg"trait type arguments not yet supported", p.toLoc) + if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) computeInterface(ps, annot & trt.selfTy, memberUn(members, trt.members.values.toList)) // intersect members case _ => computeInterface(ps, annot, members) } diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 72d3938e73..fa400f2ddc 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -10,15 +10,87 @@ class Exp[A]: Pair | Lit { // TODO enable class inheritance class Lit(n: int) extends Exp[int] class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.11: class Lit(n: int) extends Exp[int] -//│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Unsupported parent specification -//│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╙── ^^^^^^ //│ ╔══[ERROR] type signatures not yet supported for classes //│ ║ l.5: class Exp[A]: Pair | Lit { //│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] mixin type arguments not yet supported +//│ ║ l.11: class Lit(n: int) extends Exp[int] +//│ ╙── ^^^ +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.6: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.7: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.8: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.9: } +//│ ╙── ^ +//│ ╔══[ERROR] Cannot inherit from a function +//│ ║ l.11: class Lit(n: int) extends Exp[int] +//│ ╙── ^^^ +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.6: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.7: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.8: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.9: } +//│ ╙── ^ +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.6: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.7: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.8: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.9: } +//│ ╙── ^ +//│ ╔══[ERROR] mixin type arguments not yet supported +//│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] +//│ ╙── ^^^ +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.6: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.7: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.8: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.9: } +//│ ╙── ^ +//│ ╔══[ERROR] Cannot inherit from a function +//│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] +//│ ╙── ^^^ +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.6: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.7: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.8: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.9: } +//│ ╙── ^ +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.5: class Exp[A]: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.6: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.7: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.8: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.9: } +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.6: fun test = if this is //│ ║ ^^^^^^^ @@ -38,8 +110,8 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] :e // TODO Lit(0).test //│ ╔══[ERROR] Type `Lit` does not contain member `test` -//│ ║ l.39: Lit(0).test -//│ ╙── ^^^^^ +//│ ║ l.111: Lit(0).test +//│ ╙── ^^^^^ //│ error //│ res //│ = 0 @@ -59,8 +131,8 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.60: Pair['a, 'b](l, r) then [l, r] -//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ ║ l.132: Pair['a, 'b](l, r) then [l, r] +//│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared @@ -72,11 +144,11 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.72: fun f(x: a) = x -//│ ╙── ^ +//│ ║ l.144: fun f(x: a) = x +//│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.73: f(l) -//│ ╙── ^ +//│ ║ l.145: f(l) +//│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: //│ unresolved symbol l diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index ba71213812..85064cb0e2 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -10,9 +10,12 @@ class Exp[type A] // TODO class Lit(n: int) extends Exp[int] -//│ ╔══[ERROR] Unsupported parent specification +//│ ╔══[ERROR] mixin type arguments not yet supported //│ ║ l.12: class Lit(n: int) extends Exp[int] -//│ ╙── ^^^^^^^^ +//│ ╙── ^^^ +//│ ╔══[ERROR] class type arguments not yet supported +//│ ║ l.12: class Lit(n: int) extends Exp[int] +//│ ╙── ^^^ //│ class Lit(n: int) diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 56b3735d63..da4e6449ee 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -352,13 +352,28 @@ class E2 extends Test { // TODO :e class D extends Test[int], Test[bool] -//│ ╔══[ERROR] Unsupported parent specification +//│ ╔══[ERROR] mixin type arguments not yet supported //│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Unsupported parent specification +//│ ╙── ^^^^ +//│ ╔══[ERROR] mixin type arguments not yet supported //│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^^^^^^^ -//│ class D() +//│ ╙── ^^^^ +//│ ╔══[ERROR] trait type arguments not yet supported +//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ╙── ^^^^ +//│ ╔══[ERROR] trait type arguments not yet supported +//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ╙── ^^^^ +//│ ╔══[ERROR] Member foo is declared in parent trait but not implemented +//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member bar is declared in parent trait but not implemented +//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ class D() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } @@ -404,10 +419,10 @@ if b is Foo(a) then a else 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.405: if b is Bar(f) then f else 0 +//│ ║ l.420: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.387: class Bar[B](f: B => B) extends Base +//│ ║ l.402: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -416,14 +431,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.415: if b is +//│ ║ l.430: if b is //│ ║ ^^^^ -//│ ║ l.416: Foo(a) then a +//│ ║ l.431: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.417: Bar(f) then f +//│ ║ l.432: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.387: class Bar[B](f: B => B) extends Base +//│ ║ l.402: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything @@ -431,7 +446,7 @@ if b is // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.432: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.447: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -472,40 +487,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.470: fun fto(w: WP): EM = w +//│ ║ l.485: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.470: fun fto(w: WP): EM = w +//│ ║ l.485: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.470: fun fto(w: WP): EM = w +//│ ║ l.485: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.470: fun fto(w: WP): EM = w +//│ ║ l.485: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.471: z: WP +//│ ║ l.486: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.450: let z: ZL +//│ ║ l.465: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.471: z: WP +//│ ║ l.486: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.471: z: WP +//│ ║ l.486: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.472: g: ZL +//│ ║ l.487: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.449: let g: Geo +//│ ║ l.464: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.472: g: ZL +//│ ║ l.487: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.472: g: ZL +//│ ║ l.487: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -544,20 +559,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.543: fun foo(x) = x && false +//│ ║ l.558: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ?_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.543: fun foo(x) = x && false +//│ ║ l.558: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.543: fun foo(x) = x && false +//│ ║ l.558: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ?_` -//│ ║ l.543: fun foo(x) = x && false +//│ ║ l.558: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.514: fun foo(x) = x + 1 +//│ ║ l.529: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: Oth -> Test @@ -569,25 +584,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.568: class Eh extends Bs(1) +//│ ║ l.583: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.568: class Eh extends Bs(1) +//│ ║ l.583: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.513: class Bs(a: bool) { +//│ ║ l.528: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameters; got 0 -//│ ║ l.569: class Eh1 extends Bs +//│ ║ l.584: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.514: fun foo(x) = x + 1 +//│ ║ l.529: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.514: fun foo(x) = x + 1 +//│ ║ l.529: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.514: fun foo(x) = x + 1 +//│ ║ l.529: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -596,7 +611,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.570: class Eh3 extends Bs(false), Test +//│ ║ l.585: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -649,6 +664,6 @@ class Bc2(bar: bool) :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.650: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.665: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() From bd133a214dac84d15d81aa6c67f7f3ee045f9205 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 22 Apr 2023 00:26:47 +0800 Subject: [PATCH 252/498] WIP Implement type argument in trait parents of classes (TODO factor out and generalize) --- .../src/main/scala/mlscript/NuTypeDefs.scala | 42 ++++- shared/src/test/diff/gadt/Exp1.mls | 14 +- shared/src/test/diff/nu/BadClasses.mls | 4 +- shared/src/test/diff/nu/GADTMono.mls | 3 - shared/src/test/diff/nu/Interfaces.mls | 144 ++++++++++++------ 5 files changed, 143 insertions(+), 64 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 85731b6ac1..f4f61f7760 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -825,13 +825,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => : (ST, Ls[NuMember]) = parents match { case (p, v @ Var(mxnNme), mxnTargs, mxnArgs) :: ps => - if (mxnTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) val newMembs = trace(s"${lvl}. Inheriting from $p") { ctx.get(mxnNme) match { case S(lti: LazyTypeInfo) => lti.complete().freshen match { case mxn: TypedNuMxn => + if (mxnTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) println(s"Fresh $mxn") @@ -844,7 +844,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if (mxnArgs.sizeCompare(mxn.params) =/= 0) err(msg"mixin $mxnNme expects ${ - mxn.params.size.toString} parameters; got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) + mxn.params.size.toString} parameter(s); got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) val paramMems = mxn.params.lazyZip(mxnArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec implicit val genLambdas: GenLambdas = true @@ -941,7 +941,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ - cls.params.size.toString} parameters; got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) + cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec implicit val genLambdas: GenLambdas = true @@ -988,10 +988,42 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val info = lti.complete() // TODO substitute type parameters in info info match { - case trt: TypedNuTrt => - if (parTargs.nonEmpty) err(msg"trait type arguments not yet supported", p.toLoc) + case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) + + + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + + if (rawTrt.tparams.sizeCompare(parTargs.size) =/= 0) + err(msg"trait $parNme expects ${ + rawTrt.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) + + rawTrt.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => + + val targ = typeType(targTy) + + freshened += _tv -> (targ match { + case tv: TypeVarOrRigidVar => tv + case _ => + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) + + } + + val trt = rawTrt.freshenAbove(info.level, rigidify = false) + .asInstanceOf[TypedNuTrt] // FIXME + computeInterface(ps, annot & trt.selfTy, memberUn(members, trt.members.values.toList)) // intersect members + case _ => computeInterface(ps, annot, members) } case S(_) => diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index fa400f2ddc..afcc61f38d 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -13,9 +13,6 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ╔══[ERROR] type signatures not yet supported for classes //│ ║ l.5: class Exp[A]: Pair | Lit { //│ ╙── ^^^^^^^^^^ -//│ ╔══[ERROR] mixin type arguments not yet supported -//│ ║ l.11: class Lit(n: int) extends Exp[int] -//│ ╙── ^^^ //│ ╔══[ERROR] Unhandled cyclic definition //│ ║ l.5: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,9 +49,6 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.9: } //│ ╙── ^ -//│ ╔══[ERROR] mixin type arguments not yet supported -//│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╙── ^^^ //│ ╔══[ERROR] Unhandled cyclic definition //│ ║ l.5: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +104,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] :e // TODO Lit(0).test //│ ╔══[ERROR] Type `Lit` does not contain member `test` -//│ ║ l.111: Lit(0).test +//│ ║ l.105: Lit(0).test //│ ╙── ^^^^^ //│ error //│ res @@ -131,7 +125,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.132: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.126: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -144,10 +138,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.144: fun f(x: a) = x +//│ ║ l.138: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.145: f(l) +//│ ║ l.139: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 16ad8c119c..3537677663 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -7,14 +7,14 @@ mixin M0(x: int) :e class C0 extends M0 -//│ ╔══[ERROR] mixin M0 expects 1 parameters; got 0 +//│ ╔══[ERROR] mixin M0 expects 1 parameter(s); got 0 //│ ║ l.9: class C0 extends M0 //│ ╙── ^^ //│ class C0() :e class C0 extends M0(1, 2) -//│ ╔══[ERROR] mixin M0 expects 1 parameters; got 2 +//│ ╔══[ERROR] mixin M0 expects 1 parameter(s); got 2 //│ ║ l.16: class C0 extends M0(1, 2) //│ ╙── ^^^^^^^ //│ class C0() diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 85064cb0e2..278492696b 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -10,9 +10,6 @@ class Exp[type A] // TODO class Lit(n: int) extends Exp[int] -//│ ╔══[ERROR] mixin type arguments not yet supported -//│ ║ l.12: class Lit(n: int) extends Exp[int] -//│ ╙── ^^^ //│ ╔══[ERROR] class type arguments not yet supported //│ ║ l.12: class Lit(n: int) extends Exp[int] //│ ╙── ^^^ diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index da4e6449ee..c2bf7e95d3 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -352,18 +352,12 @@ class E2 extends Test { // TODO :e class D extends Test[int], Test[bool] -//│ ╔══[ERROR] mixin type arguments not yet supported +//│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 //│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^ -//│ ╔══[ERROR] mixin type arguments not yet supported +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 //│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^ -//│ ╔══[ERROR] trait type arguments not yet supported -//│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^ -//│ ╔══[ERROR] trait type arguments not yet supported -//│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^ +//│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member foo is declared in parent trait but not implemented //│ ║ l.354: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -419,10 +413,10 @@ if b is Foo(a) then a else 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.420: if b is Bar(f) then f else 0 +//│ ║ l.414: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.402: class Bar[B](f: B => B) extends Base +//│ ║ l.396: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -431,14 +425,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.430: if b is +//│ ║ l.424: if b is //│ ║ ^^^^ -//│ ║ l.431: Foo(a) then a +//│ ║ l.425: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.432: Bar(f) then f +//│ ║ l.426: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.402: class Bar[B](f: B => B) extends Base +//│ ║ l.396: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything @@ -446,7 +440,7 @@ if b is // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.447: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.441: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -487,40 +481,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.485: fun fto(w: WP): EM = w +//│ ║ l.479: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.485: fun fto(w: WP): EM = w +//│ ║ l.479: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.485: fun fto(w: WP): EM = w +//│ ║ l.479: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.485: fun fto(w: WP): EM = w +//│ ║ l.479: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.486: z: WP +//│ ║ l.480: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.465: let z: ZL +//│ ║ l.459: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.486: z: WP +//│ ║ l.480: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.486: z: WP +//│ ║ l.480: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.487: g: ZL +//│ ║ l.481: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.464: let g: Geo +//│ ║ l.458: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.487: g: ZL +//│ ║ l.481: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.487: g: ZL +//│ ║ l.481: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -559,20 +553,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.558: fun foo(x) = x && false +//│ ║ l.552: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ?_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.558: fun foo(x) = x && false +//│ ║ l.552: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.558: fun foo(x) = x && false +//│ ║ l.552: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ?_` -//│ ║ l.558: fun foo(x) = x && false +//│ ║ l.552: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.529: fun foo(x) = x + 1 +//│ ║ l.523: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: Oth -> Test @@ -584,25 +578,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.583: class Eh extends Bs(1) +//│ ║ l.577: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.583: class Eh extends Bs(1) +//│ ║ l.577: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.528: class Bs(a: bool) { +//│ ║ l.522: class Bs(a: bool) { //│ ╙── ^^^^ -//│ ╔══[ERROR] class Bs expects 1 parameters; got 0 -//│ ║ l.584: class Eh1 extends Bs +//│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 +//│ ║ l.578: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.529: fun foo(x) = x + 1 +//│ ║ l.523: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.529: fun foo(x) = x + 1 +//│ ║ l.523: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.529: fun foo(x) = x + 1 +//│ ║ l.523: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -611,7 +605,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.585: class Eh3 extends Bs(false), Test +//│ ║ l.579: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -664,6 +658,68 @@ class Bc2(bar: bool) :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.665: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.659: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() + + + +trait Base[A] { fun f: A -> A } +//│ trait Base[A]() { +//│ fun f: A -> A +//│ } + +class Der1 extends Base[int] { fun f(x) = x + 1 } +//│ class Der1() { +//│ fun f: int -> int +//│ } + +class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } +//│ class Der2[A, B]() { +//│ fun f: (A, B,) -> (A, B,) +//│ } + + +:e +class DerBad1 extends Base[int, int] +//│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 +//│ ║ l.684: class DerBad1 extends Base[int, int] +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member f is declared in parent trait but not implemented +//│ ║ l.684: class DerBad1 extends Base[int, int] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ class DerBad1() { +//│ fun f: int -> int +//│ } + +:e +class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ╔══[ERROR] Type mismatch in definition of method f: +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── reference of type `B` does not match type `A` +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ +//│ ╟── Note: constraint arises from type parameter: +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ +//│ ╟── Note: type parameter B is defined at: +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method f: +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── reference of type `A` does not match type `B` +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ +//│ ╟── Note: constraint arises from type parameter: +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ╙── ^ +//│ class Der2[A, B]() { +//│ fun f: (A, B,) -> (A, B,) +//│ } + + From 5382d1c5f3de1834b7b7c8783a1adff79da7f075 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Tue, 25 Apr 2023 12:03:19 +0800 Subject: [PATCH 253/498] FIXED: DiffTest output, taits as class params WIP: trait type arguments, factor out the code --- .../src/main/scala/mlscript/NuTypeDefs.scala | 47 ++++- shared/src/main/scala/mlscript/Typer.scala | 4 +- shared/src/test/diff/nu/GADTMono.mls | 26 +-- shared/src/test/diff/nu/Interfaces.mls | 161 +++++++++++++----- .../src/test/scala/mlscript/DiffTests.scala | 6 + 5 files changed, 174 insertions(+), 70 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index f4f61f7760..2a278aa884 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -743,14 +743,47 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember]) : (ST, ST, Ls[NuMember]) = parents match { - case (p, v @ Var(trtName), targs, args) :: ps => - if (targs.nonEmpty) err(msg"trait type arguments not yet supported", p.toLoc) + case (p, v @ Var(trtName), parTargs, args) :: ps => + // if (parTargs.nonEmpty) err(msg"trait type arguments not yet supported", p.toLoc) if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) ctx.get(trtName) match { - case S(lti: LazyTypeInfo) => lti.complete().freshen match { - case trt: TypedNuTrt => - inherit(ps, superType & trt.thisTy, tags & trt.selfTy, memberUn(members, trt.members.values.toList)) - case _ => + case S(lti: LazyTypeInfo) => + val info = lti.complete().freshen + info match { + case rawTrt: TypedNuTrt => + + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + + if (rawTrt.tparams.sizeCompare(parTargs.size) =/= 0) + err(msg"trait $trtName expects ${ + rawTrt.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) + + rawTrt.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => + + val targ = typeType(targTy) + + freshened += _tv -> (targ match { + case tv: TypeVarOrRigidVar => tv + case _ => + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) + + } + + val trt = rawTrt.freshenAbove(info.level, rigidify = false) + .asInstanceOf[TypedNuTrt] // FIXME + + inherit(ps, superType & trt.thisTy, tags & trt.selfTy, memberUn(members, trt.members.values.toList)) + case _ => err(msg"trait can only inherit traits", p.toLoc) (superType, tags, members) } @@ -955,7 +988,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.find(x => x.name == m.name) match { case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature - // TODO fix here val parSign = m.asInstanceOf[TypedNuTermDef].typeSignature println(s"checking overriding: $memSign <: $parSign") implicit val prov: TP = memSign.prov @@ -991,7 +1023,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 82ae28070f..e6cbf25e93 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -357,9 +357,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case CompletedTypeInfo(mem: TypedNuTypeDef) => S(mem.td.kind, mem.tparams.size) case ti: DelayedTypeInfo => ti.decl match { - case NuTypeDef(k @ (Cls | Nms | Als), _, tps, _, _, _, _, _, _) => + case NuTypeDef(k @ (Cls | Nms | Als | Trt), _, tps, _, _, _, _, _, _) => S(k, tps.size) - case NuTypeDef(k @ (Mxn | Trt), nme, tps, _, _, _, _, _, _) => + case NuTypeDef(k @ (Mxn /* | Trt */), nme, tps, _, _, _, _, _, _) => err(msg"${k.str} ${nme.name} cannot be used as a type", loc) S(k, tps.size) case fd: NuFunDef => diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 278492696b..af290976bc 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -1,18 +1,10 @@ :NewDefs - - -// TODO -class Exp[type A] -//│ ╔══[PARSE ERROR] Unexpected 'type' keyword here -//│ ║ l.5: class Exp[type A] -//│ ╙── ^^^^ -//│ class Exp() - -// TODO -class Lit(n: int) extends Exp[int] -//│ ╔══[ERROR] class type arguments not yet supported -//│ ║ l.12: class Lit(n: int) extends Exp[int] -//│ ╙── ^^^ -//│ class Lit(n: int) - - +:NoJS + +// FIXME +trait Expr[A]: LitInt | LitBool | Add | Cond +class LitInt(n: int) extends Expr[int] +class LitBool(b: bool) extends Expr[bool] +class Add(x: Expr[int], y: Expr[int]) extends Expr[int] +class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) extends Expr[T] +//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: ‘T36' was not a type variable diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index c2bf7e95d3..4129e8672d 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -391,6 +391,11 @@ if b is //│ 0 | 1 +fun f(x: Base) = if x is + A then 0 + B then 1 +//│ fun f: (x: Base,) -> (0 | 1) + trait Base: Foo | Bar class Foo[A](aa: (A, A)) extends Base class Bar[B](f: B => B) extends Base @@ -413,10 +418,10 @@ if b is Foo(a) then a else 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.414: if b is Bar(f) then f else 0 +//│ ║ l.419: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.396: class Bar[B](f: B => B) extends Base +//│ ║ l.401: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -425,14 +430,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.424: if b is +//│ ║ l.429: if b is //│ ║ ^^^^ -//│ ║ l.425: Foo(a) then a +//│ ║ l.430: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.426: Bar(f) then f +//│ ║ l.431: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.396: class Bar[B](f: B => B) extends Base +//│ ║ l.401: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything @@ -440,7 +445,7 @@ if b is // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.441: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.446: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -481,40 +486,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.479: fun fto(w: WP): EM = w +//│ ║ l.484: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.479: fun fto(w: WP): EM = w +//│ ║ l.484: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.479: fun fto(w: WP): EM = w +//│ ║ l.484: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.479: fun fto(w: WP): EM = w +//│ ║ l.484: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.480: z: WP +//│ ║ l.485: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.459: let z: ZL +//│ ║ l.464: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.480: z: WP +//│ ║ l.485: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.480: z: WP +//│ ║ l.485: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.481: g: ZL +//│ ║ l.486: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.458: let g: Geo +//│ ║ l.463: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.481: g: ZL +//│ ║ l.486: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.481: g: ZL +//│ ║ l.486: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -553,20 +558,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.552: fun foo(x) = x && false +//│ ║ l.557: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ?_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.552: fun foo(x) = x && false +//│ ║ l.557: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.552: fun foo(x) = x && false +//│ ║ l.557: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ?_` -//│ ║ l.552: fun foo(x) = x && false +//│ ║ l.557: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.523: fun foo(x) = x + 1 +//│ ║ l.528: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: Oth -> Test @@ -578,25 +583,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.577: class Eh extends Bs(1) +//│ ║ l.582: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.577: class Eh extends Bs(1) +//│ ║ l.582: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.522: class Bs(a: bool) { +//│ ║ l.527: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.578: class Eh1 extends Bs +//│ ║ l.583: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.523: fun foo(x) = x + 1 +//│ ║ l.528: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.523: fun foo(x) = x + 1 +//│ ║ l.528: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.523: fun foo(x) = x + 1 +//│ ║ l.528: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -605,7 +610,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.579: class Eh3 extends Bs(false), Test +//│ ║ l.584: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -658,7 +663,7 @@ class Bc2(bar: bool) :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.659: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.664: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() @@ -679,14 +684,60 @@ class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ fun f: (A, B,) -> (A, B,) //│ } +trait BInt extends Base[int] +//│ trait BInt() { +//│ fun f: int -> int +//│ } + +trait BPar[T] extends Base[(int,T)] +//│ trait BPar[T]() { +//│ fun f: (int, T,) -> (int, T,) +//│ } + +let bi: BInt +let bp: BPar[bool] +//│ let bi: BInt +//│ let bp: BPar[bool] + +// TODO +bp: Base[(int, bool)] +//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` +//│ ║ l.672: trait Base[A] { fun f: A -> A } +//│ ╙── ^ +//│ Base[(int, bool,)] + +bi.f(1) +//│ int + +bp.f +//│ ((int, bool,) & 'A) -> ((int, bool,) | 'A) + +fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) +//│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) + +// TODO +fb(bp, false) +//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` +//│ ║ l.672: trait Base[A] { fun f: A -> A } +//│ ╙── ^ +//│ (int, false,) | error + +:e +trait BErr1 extends Base +//│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 +//│ ║ l.726: trait BErr1 extends Base +//│ ╙── ^^^^ +//│ trait BErr1() { +//│ fun f: 'A -> 'A +//│ } :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.684: class DerBad1 extends Base[int, int] +//│ ║ l.735: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.684: class DerBad1 extends Base[int, int] +//│ ║ l.735: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() { //│ fun f: int -> int @@ -695,31 +746,55 @@ class DerBad1 extends Base[int, int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.696: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (A, B,) -> (A, B,) //│ } +trait Ta[T] { + let p: bool + let g: T +} +class K[A](k: Ta[A]) +//│ trait Ta[T]() { +//│ let g: T +//│ let p: bool +//│ } +//│ class K[A](k: Ta[A]) + +let ta1: Ta[int] +//│ let ta1: Ta[int] + +let k1 = K(ta1) +//│ let k1: K[int] + +k1.k : Ta[int] +//│ Ta[int] +k1.k.g +//│ int + +k1.k.p +//│ bool diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 3f60095f59..738a2acbe7 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -502,10 +502,16 @@ class DiffTests val indStr = " " * ind // ttu.entities.map(_.complete()(raise)).foreach { ttu.entities.foreach { + case p: typer.NuTypeParam => + output(s"${indStr}${p.name}: ${p.ty}") case p: typer.NuParam => output(s"${indStr}${p.name}: ${p.ty}") case tc: typer.TypedNuAls => output(s"${indStr}type ${tc.name} = ${tc.body}") + case tt: typer.TypedNuTrt => + output(s"${indStr}trait ${tt.name}") + output(s"${indStr} this: ${tt.thisTy} ${tt.thisTy.showBounds + .indentNewLines(indStr+" |")}") case tc: typer.TypedNuCls => output(s"${indStr}class ${tc.name}") output(s"${indStr} this: ${tc.thisTy} ${tc.thisTy.showBounds From 16c217fb21c5f2c9908b2461426b55e2aca0cade Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Tue, 25 Apr 2023 14:17:43 +0800 Subject: [PATCH 254/498] WIP: parent trait type members --- .../scala/mlscript/ConstraintSolver.scala | 2 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 45 +++++++++----- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/TyperHelpers.scala | 4 +- shared/src/test/diff/nu/GADTMono.mls | 7 ++- shared/src/test/diff/nu/Interfaces.mls | 60 +++++++++++-------- 6 files changed, 75 insertions(+), 45 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index a097f06a9d..60ce6601cb 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -91,7 +91,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // TODO factor code with above!! case trt: TypedNuTrt => - trt.members.get(fld.name) match { + trt.virtualMembers.get(fld.name) match { case S(d: TypedNuFun) => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 2a278aa884..5461d3164d 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -137,14 +137,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuAls(level, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), body.freshenAbove(lim, rigidify)) - case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags) => + case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags, typeMembers) => TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), sign.map(_.freshenAbove(lim, rigidify)), // todo tags.freshenAbove(lim, rigidify), - inheritedTags + inheritedTags, + typeMembers.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ) } val td: NuTypeDef @@ -186,7 +187,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => thisTy: ST, sign: Opt[ST], selfTy: ST, - inheritedTags: Set[TypeName] + inheritedTags: Set[TypeName], + typeMembers: Map[Str, NuMember] ) extends TypedNuTypeDef(Trt) with TypedNuTermDef { def decl: NuTypeDef = td @@ -195,6 +197,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def name: Str = nme.name def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy, inheritedTags) + + def virtualMembers: Map[Str, NuMember] = members ++ typeMembers def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -204,7 +208,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.map(!_), thisTy), sign.map(f(pol, _)), f(pol, selfTy), - inheritedTags + inheritedTags, + typeMembers.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -214,7 +219,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.contravar, thisTy), sign.map(f(pol, _)), f(pol, selfTy), - inheritedTags + inheritedTags, + typeMembers.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ) } @@ -224,7 +230,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, tags: ST, - inheritedTags: Set[TypeName] + inheritedTags: Set[TypeName], )(val instanceType: ST, // * only meant to be used in `force` and `variances` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { @@ -740,8 +746,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } // inherit traits - def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember]) - : (ST, ST, Ls[NuMember]) = + def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember], vMembers: Map[Str, NuMember]) + : (ST, ST, Ls[NuMember], Map[Str, NuMember]) = parents match { case (p, v @ Var(trtName), parTargs, args) :: ps => // if (parTargs.nonEmpty) err(msg"trait type arguments not yet supported", p.toLoc) @@ -782,19 +788,24 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val trt = rawTrt.freshenAbove(info.level, rigidify = false) .asInstanceOf[TypedNuTrt] // FIXME - inherit(ps, superType & trt.thisTy, tags & trt.selfTy, memberUn(members, trt.members.values.toList)) + inherit(ps, + superType & trt.thisTy, + tags & trt.selfTy, + memberUn(members, trt.members.values.toList), + vMembers ++ trt.typeMembers + ) case _ => err(msg"trait can only inherit traits", p.toLoc) - (superType, tags, members) + (superType, tags, members, vMembers) } - case _ => (superType, tags, members) + case _ => (superType, tags, members, vMembers) } - case Nil => (superType, tags, members) + case Nil => (superType, tags, members, vMembers) } - val (thisType, tags, baseMems) = + val (thisType, tags, baseMems, baseVMems) = // ? is it really a good idea - inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil) + inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) // val selfType = tags & sig_ty val selfType = sig_ty @@ -802,8 +813,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val ttu = typeTypingUnit(td.body, topLevel = false) val trtMems = baseMems ++ ttu.entities val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap + val vmems = baseVMems ++ tparams.map { + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuTypeParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } - TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags) -> Nil + TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags, vmems) -> Nil } case Als => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index e6cbf25e93..8763490a05 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1341,7 +1341,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, _ /* TODO */) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 8da7588104..505d4b0d72 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -745,6 +745,7 @@ abstract class TyperHelpers { Typer: Typer => case NuParam(nme, ty, isType) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable case TypedNuFun(level, fd, ty) => pol -> ty :: Nil case td: TypedNuDecl => TypedTypingUnit(td :: Nil, N).childrenPol(pol: PolMap) // TODO refactor + case NuTypeParam(nme, ty) => childrenPolField(PolMap.pos)(ty) } this match { case tv @ AssignedVariable(ty) => @@ -1177,7 +1178,7 @@ abstract class TyperHelpers { Typer: Typer => members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, tms) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) @@ -1190,6 +1191,7 @@ abstract class TyperHelpers { Typer: Typer => apply(pol.contravar)(superTV) case NuParam(nme, ty, isType) => applyField(pol)(ty) case TypedNuFun(level, fd, ty) => apply(pol)(ty) + case NuTypeParam(nme, ty) => applyField(pol)(ty) } def apply(pol: PolMap)(st: ST): Unit = st match { case tv @ AssignedVariable(ty) => apply(pol)(ty) diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index af290976bc..61339c9a6c 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -1,10 +1,13 @@ :NewDefs :NoJS -// FIXME -trait Expr[A]: LitInt | LitBool | Add | Cond +// TODO +trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd class LitInt(n: int) extends Expr[int] class LitBool(b: bool) extends Expr[bool] class Add(x: Expr[int], y: Expr[int]) extends Expr[int] class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) extends Expr[T] +class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr[(S, T)] +class Fst[S, T](p: Expr[(S, T)]) extends Expr[S] +class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] //│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: ‘T36' was not a type variable diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 4129e8672d..7feff0ffd5 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -684,10 +684,11 @@ class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ fun f: (A, B,) -> (A, B,) //│ } -trait BInt extends Base[int] -//│ trait BInt() { -//│ fun f: int -> int -//│ } +// TODO +trait BInt extends Base[int] { + fun f = error +} +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A341# trait BPar[T] extends Base[(int,T)] //│ trait BPar[T]() { @@ -699,15 +700,11 @@ let bp: BPar[bool] //│ let bi: BInt //│ let bp: BPar[bool] -// TODO bp: Base[(int, bool)] -//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.672: trait Base[A] { fun f: A -> A } -//│ ╙── ^ //│ Base[(int, bool,)] bi.f(1) -//│ int +//│ nothing bp.f //│ ((int, bool,) & 'A) -> ((int, bool,) | 'A) @@ -715,17 +712,13 @@ bp.f fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) //│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) -// TODO fb(bp, false) -//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.672: trait Base[A] { fun f: A -> A } -//│ ╙── ^ -//│ (int, false,) | error +//│ (int, bool,) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.726: trait BErr1 extends Base +//│ ║ l.719: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -734,10 +727,10 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.735: class DerBad1 extends Base[int, int] +//│ ║ l.728: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.735: class DerBad1 extends Base[int, int] +//│ ║ l.728: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() { //│ fun f: int -> int @@ -746,28 +739,28 @@ class DerBad1 extends Base[int, int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.747: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (A, B,) -> (A, B,) @@ -798,3 +791,20 @@ k1.k.g k1.k.p //│ bool + +trait Tb extends Ta[int] { + let p = false +} +//│ trait Tb() { +//│ let g: int +//│ let p: false +//│ } + +class Ctb extends Tb { + let p = false + let g = 2 +} +//│ class Ctb() { +//│ let g: int +//│ let p: false +//│ } From c0872d9b6ed8868d2be587013d4ae3a8565f2823 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Tue, 25 Apr 2023 14:34:37 +0800 Subject: [PATCH 255/498] parent trait type members for classes --- .../src/main/scala/mlscript/NuTypeDefs.scala | 40 +++++++++++-------- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/TyperHelpers.scala | 2 +- shared/src/test/diff/nu/Interfaces.mls | 35 +++++++++++----- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 5461d3164d..46935b4e99 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -124,14 +124,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) - case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags) => + case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags, typeMembers) => TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), tags.freshenAbove(lim, rigidify), - inheritedTags + inheritedTags, + typeMembers )(cls.instanceType.freshenAbove(lim, rigidify)) case cls @ TypedNuAls(level, td, tparams, body) => TypedNuAls(level, td, @@ -231,6 +232,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, tags: ST, inheritedTags: Set[TypeName], + typeMembers: Map[Str, NuMember] )(val instanceType: ST, // * only meant to be used in `force` and `variances` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef { @@ -242,9 +244,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def typeSignature: ST = typeSignatureOf(td, level, tparams, params, tags, inheritedTags) /** Includes class-name-coded type parameter fields. */ - lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { - case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuTypeParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } + lazy val virtualMembers: Map[Str, NuMember] = members ++ typeMembers // TODO // def checkVariances @@ -300,7 +300,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), f(pol, tags), - inheritedTags + inheritedTags, + typeMembers.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -310,7 +311,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), f(pol, tags), - inheritedTags + inheritedTags, + typeMembers.mapValuesIter(_.mapPolMap(pol)(f)).toMap, )(f(pol, instanceType)) } @@ -1026,7 +1028,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val impltdMems = baseMems ++ clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers - def computeInterface(parents: Ls[ParentSpec], annot: ST, members: Ls[NuMember]): (ST, Ls[NuMember]) = + def computeInterface(parents: Ls[ParentSpec], annot: ST, members: Ls[NuMember], tMem: Map[Str, NuMember]): (ST, Ls[NuMember], Map[Str, NuMember]) = parents match { case (p, v @ Var(parNme), parTargs, parArgs) :: ps => // TODO find traits in `parents`; intersect their member types and self types @@ -1068,22 +1070,27 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val trt = rawTrt.freshenAbove(info.level, rigidify = false) .asInstanceOf[TypedNuTrt] // FIXME - computeInterface(ps, annot & trt.selfTy, memberUn(members, trt.members.values.toList)) // intersect members + computeInterface(ps, annot & trt.selfTy, memberUn(members, trt.members.values.toList), tMem ++ trt.typeMembers) // intersect members - case _ => computeInterface(ps, annot, members) + case _ => computeInterface(ps, annot, members, tMem) } case S(_) => err("i don't know", p.toLoc) - computeInterface(ps, annot, members) + computeInterface(ps, annot, members, tMem) case N => // err(msg"Could not find definition `${parNme}`", p.toLoc) - computeInterface(ps, annot, members) + computeInterface(ps, annot, members, tMem) } - case Nil => (annot, members) + case Nil => (annot, members, tMem) } val thisTag = TopType //clsNameToNomTag(td)(provTODO, ctx) - val (_, ifaceMembers) = computeInterface(parentSpecs, thisTag, Nil) - // TODO check mems against interface stuff above + val (_, ifaceMembers, ifaceTmem) = computeInterface(parentSpecs, thisTag, Nil, Map.empty) + + // TODO type members of parent class + val tyMem = ifaceTmem ++ tparams.map { + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuTypeParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } ifaceMembers.foreach { m => impltdMems.find(x => x.name == m.name) match { @@ -1103,7 +1110,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TopType, // ifaceAnnot, TopType, // TODO use signature - inheritedTags + inheritedTags, + tyMem )(thisType) -> impltdMems } case Mxn => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 8763490a05..edc8b32d41 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1331,7 +1331,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, _) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 505d4b0d72..ce80d09b00 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1172,7 +1172,7 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, tms) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 7feff0ffd5..6906fafcf1 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -715,10 +715,23 @@ fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) fb(bp, false) //│ (int, bool,) +class CP extends BPar[int] { + fun f(x) = (x._2, x._1) +} +//│ class CP() { +//│ fun f: ((int, int,) & 'A) -> ((int, int,) | 'A) +//│ } + +let cp1 = CP() +//│ let cp1: CP + +fb(cp1, 2) +//│ (int, int,) + :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.719: trait BErr1 extends Base +//│ ║ l.732: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -727,10 +740,10 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.728: class DerBad1 extends Base[int, int] +//│ ║ l.741: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.728: class DerBad1 extends Base[int, int] +//│ ║ l.741: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() { //│ fun f: int -> int @@ -739,28 +752,28 @@ class DerBad1 extends Base[int, int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.740: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (A, B,) -> (A, B,) From a32c67fdf8f138459ae429781b06628871c23f0e Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Tue, 25 Apr 2023 14:37:04 +0800 Subject: [PATCH 256/498] simple factor out --- .../scala/mlscript/ConstraintSolver.scala | 27 +++++++------------ shared/src/test/diff/nu/Interfaces.mls | 13 +++++++++ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 60ce6601cb..3f69b972e3 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -74,24 +74,10 @@ class ConstraintSolver extends NormalForms { self: Typer => N } - } else info.complete() match { - - case cls: TypedNuCls => - cls.virtualMembers.get(fld.name) match { - case S(d: TypedNuFun) => - S(d.typeSignature.toUpper(provTODO)) - case S(p: NuParam) => - S(p.ty) - case S(p: NuTypeParam) => - S(p.ty) - case S(m) => - S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) - case N => N - } + } else { - // TODO factor code with above!! - case trt: TypedNuTrt => - trt.virtualMembers.get(fld.name) match { + def handle(virtualMembers: Map[Str, NuMember]): Opt[FieldType] = + virtualMembers.get(fld.name) match { case S(d: TypedNuFun) => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => @@ -102,9 +88,14 @@ class ConstraintSolver extends NormalForms { self: Typer => S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) case N => N } - + + info.complete() match { + + case cls: TypedNuCls => handle(cls.virtualMembers) + case trt: TypedNuTrt => handle(trt.virtualMembers) case _ => ??? // TODO } + } println(s"Lookup ${info.decl.name}.${fld.name} : $raw where ${raw.fold("")(_.ub.showBounds)}") diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 6906fafcf1..413270931b 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -821,3 +821,16 @@ class Ctb extends Tb { //│ let g: int //│ let p: false //│ } + +class G1[A](x: A) +//│ class G1[A](x: A) + +// TODO +class GI(x: int) extends G1[int] +//│ ╔══[ERROR] class type arguments not yet supported +//│ ║ l.829: class GI(x: int) extends G1[int] +//│ ╙── ^^ +//│ ╔══[ERROR] class G1 expects 1 parameter(s); got 0 +//│ ║ l.829: class GI(x: int) extends G1[int] +//│ ╙── ^^ +//│ class GI(x: int) From b7a7cd55cbdeb4b707e8a8dbda59eecc1664d253 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 26 Apr 2023 22:33:44 +0800 Subject: [PATCH 257/498] Support negative integers --- shared/src/main/scala/mlscript/NewLexer.scala | 19 ++++++++++++------- shared/src/test/diff/parser/NuParser.mls | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 shared/src/test/diff/parser/NuParser.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index fd278f7eb0..bdfc5fb336 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -163,14 +163,19 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { // go(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n))) lex(j, ind, next(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n)))) case _ if isOpChar(c) => - val (n, j) = takeWhile(i)(isOpChar) - if (n === "." && j < length && isIdentFirstChar(bytes(j))) { - val (name, k) = takeWhile(j)(isIdentChar) - // go(k, SELECT(name)) - lex(k, ind, next(k, SELECT(name))) + if (c === '-' && isDigit(bytes(i + 1))) { + val (str, j) = takeWhile(i + 1)(isDigit) + lex(j, ind, next(j, LITVAL(IntLit(-BigInt(str))))) + } else { + val (n, j) = takeWhile(i)(isOpChar) + if (n === "." && j < length && isIdentFirstChar(bytes(j))) { + val (name, k) = takeWhile(j)(isIdentChar) + // go(k, SELECT(name)) + lex(k, ind, next(k, SELECT(name))) + } + // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) + else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) } - // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) - else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) case _ if isDigit(c) => val (str, j) = takeWhile(i)(isDigit) // go(j, LITVAL(IntLit(BigInt(str)))) diff --git a/shared/src/test/diff/parser/NuParser.mls b/shared/src/test/diff/parser/NuParser.mls new file mode 100644 index 0000000000..79c8446d84 --- /dev/null +++ b/shared/src/test/diff/parser/NuParser.mls @@ -0,0 +1,14 @@ +:NewParser +:ParseOnly + +type MinusOne = -1 +//│ |#type| |MinusOne| |#=| |-1| +//│ Parsed: {type alias MinusOne(): -1 {}} + +fun f(x: MinusOne) = x +//│ |#fun| |f|(|x|#:| |MinusOne|)| |#=| |x| +//│ Parsed: {fun f = (x: MinusOne,) => x} + +f(-1) +//│ |f|(|-1|)| +//│ Parsed: {f (-1,)} From a16b7ff0eae8bb2621b99f839d96dd2df3e9e61a Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 26 Apr 2023 23:28:29 +0800 Subject: [PATCH 258/498] small refactor for `computeInterface` --- .../src/main/scala/mlscript/NuTypeDefs.scala | 80 +++++++------------ shared/src/test/diff/gadt/Exp1.mls | 32 ++------ 2 files changed, 34 insertions(+), 78 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 46935b4e99..5266d66032 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -909,12 +909,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => paramMems ++ bodyMems - case trt: TypedNuTrt => - Nil - - case cls: TypedNuCls => - // err(msg"Class inheritance is not supported yet (use mixins)", p.toLoc) - Nil + case trt: TypedNuTrt => Nil // handled in computeBaseClass + case cls: TypedNuCls => Nil // handled in computeBaseClass case als: TypedNuAls => // TODO dealias first? err(msg"Cannot inherit from a type alias", p.toLoc) @@ -976,17 +972,21 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO report non-unit result/statements? // TODO check overriding - def computeBaseClass(parents: Ls[ParentSpec], members: Ls[NuMember], baseClass: Opt[Str]): Ls[NuMember] = + + case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], trtMem: Ls[NuMember], trtTyMem: Map[Str, NuMember]) + + // compute base class and interfaces + def computeBaseClass(parents: Ls[ParentSpec], pack: Pack): Pack = parents match { case (p, v @ Var(parNme), parTargs, parArgs) :: ps => ctx.get(parNme) match { case S(lti: LazyTypeInfo) => val info = lti.complete() - info match { + info match { case cls: TypedNuCls => if (parTargs.nonEmpty) err(msg"class type arguments not yet supported", p.toLoc) - if (baseClass.isDefined) { - err(msg"cannot inherit from more than one base class: ${baseClass.get} and ${parNme}", v.toLoc) + if (pack.bsCls.isDefined) { + err(msg"cannot inherit from more than one base class: ${pack.bsCls.get} and ${parNme}", v.toLoc) } if (parArgs.sizeCompare(cls.params) =/= 0) @@ -1001,8 +1001,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false)(lvl) } val numem = paramMems ++ cls.members.values.toList - val res = members ++ numem.flatMap { m => - members.find(x => x.name == m.name) match { + val res = pack.clsMem ++ numem.flatMap { m => + pack.clsMem.find(x => x.name == m.name) match { case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature val parSign = m.asInstanceOf[TypedNuTermDef].typeSignature @@ -1014,29 +1014,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - computeBaseClass(ps, res , S(parNme)) + computeBaseClass(ps, pack.copy(clsMem = res, bsCls = S(parNme))) - case _ => computeBaseClass(ps, members, baseClass) - } - case _ => computeBaseClass(ps, members, baseClass) - } - case Nil => members - } - - val clsMems = computeBaseClass(parentSpecs, ttu.entities, N) - - val impltdMems = baseMems ++ clsMems - val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers - - def computeInterface(parents: Ls[ParentSpec], annot: ST, members: Ls[NuMember], tMem: Map[Str, NuMember]): (ST, Ls[NuMember], Map[Str, NuMember]) = - parents match { - case (p, v @ Var(parNme), parTargs, parArgs) :: ps => - // TODO find traits in `parents`; intersect their member types and self types - ctx.get(parNme) match { - case S(lti: LazyTypeInfo) => - val info = lti.complete() - // TODO substitute type parameters in info - info match { case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) @@ -1048,9 +1027,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => rawTrt.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) rawTrt.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => - val targ = typeType(targTy) - freshened += _tv -> (targ match { case tv: TypeVarOrRigidVar => tv case _ => @@ -1064,27 +1041,28 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // println(s"Assigned ${tv.assignedTo}") tv }) - } val trt = rawTrt.freshenAbove(info.level, rigidify = false) .asInstanceOf[TypedNuTrt] // FIXME - - computeInterface(ps, annot & trt.selfTy, memberUn(members, trt.members.values.toList), tMem ++ trt.typeMembers) // intersect members - - case _ => computeInterface(ps, annot, members, tMem) + + computeBaseClass(ps, pack.copy( + trtMem = memberUn(pack.trtMem, trt.members.values.toList), + trtTyMem = pack.trtTyMem ++ trt.typeMembers) + ) + + case _ => computeBaseClass(ps, pack) } - case S(_) => - err("i don't know", p.toLoc) - computeInterface(ps, annot, members, tMem) - case N => - // err(msg"Could not find definition `${parNme}`", p.toLoc) - computeInterface(ps, annot, members, tMem) + case _ => computeBaseClass(ps, pack) } - case Nil => (annot, members, tMem) - } - val thisTag = TopType //clsNameToNomTag(td)(provTODO, ctx) - val (_, ifaceMembers, ifaceTmem) = computeInterface(parentSpecs, thisTag, Nil, Map.empty) + case Nil => pack + } + + val Pack(clsMems, _, ifaceMembers, ifaceTmem) = + computeBaseClass(parentSpecs, Pack(ttu.entities, N, Nil, Map.empty)) + + val impltdMems = baseMems ++ clsMems + val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers // TODO type members of parent class val tyMem = ifaceTmem ++ tparams.map { diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index afcc61f38d..908e269460 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -49,17 +49,6 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.9: } //│ ╙── ^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.6: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.7: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.8: Pair then 1 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.9: } -//│ ╙── ^ //│ ╔══[ERROR] Cannot inherit from a function //│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ╙── ^^^ @@ -74,17 +63,6 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.9: } //│ ╙── ^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.6: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.7: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.8: Pair then 1 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.9: } -//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.6: fun test = if this is //│ ║ ^^^^^^^ @@ -104,8 +82,8 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] :e // TODO Lit(0).test //│ ╔══[ERROR] Type `Lit` does not contain member `test` -//│ ║ l.105: Lit(0).test -//│ ╙── ^^^^^ +//│ ║ l.83: Lit(0).test +//│ ╙── ^^^^^ //│ error //│ res //│ = 0 @@ -125,7 +103,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.126: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.104: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -138,10 +116,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.138: fun f(x: a) = x +//│ ║ l.116: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.139: f(l) +//│ ║ l.117: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: From d8f55058c2d9ff2c92b5000d59783a5fa20e6313 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Thu, 27 Apr 2023 13:32:20 +0800 Subject: [PATCH 259/498] FIXED some overriding issue: member overriding param, param overriding member --- .../src/main/scala/mlscript/NuTypeDefs.scala | 16 +++- shared/src/test/diff/nu/Interfaces.mls | 86 +++++++++++++++---- 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 5266d66032..8536ec25b4 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1002,14 +1002,24 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val numem = paramMems ++ cls.members.values.toList val res = pack.clsMem ++ numem.flatMap { m => + lazy val parSign = m match { + case nt: TypedNuTermDef => nt.typeSignature + case np: NuParam => np.typeSignature + case _ => ??? // probably no other cases + } pack.clsMem.find(x => x.name == m.name) match { case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature - val parSign = m.asInstanceOf[TypedNuTermDef].typeSignature println(s"checking overriding: $memSign <: $parSign") implicit val prov: TP = memSign.prov constrain(memSign, parSign) Nil + case S(pm: NuParam) => + val pmSign = pm.typeSignature + println(s"checking overriding: $pmSign <: $parSign") + implicit val prov: TP = pmSign.prov + constrain(pmSign, parSign) + Nil case _ => m :: Nil } } @@ -1059,9 +1069,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val Pack(clsMems, _, ifaceMembers, ifaceTmem) = - computeBaseClass(parentSpecs, Pack(ttu.entities, N, Nil, Map.empty)) + computeBaseClass(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil, Map.empty)) - val impltdMems = baseMems ++ clsMems + val impltdMems = clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers // TODO type members of parent class diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 413270931b..1391bbdc96 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -637,7 +637,6 @@ class Ca(a: int) extends Oth { class Cx(a: 1 | 2, b: bool) extends Ca(a) //│ class Cx(a: 1 | 2, b: bool) { -//│ let a: int //│ fun bar: bool -> bool //│ fun cool: int -> bool //│ fun foo: int @@ -657,16 +656,64 @@ cx1: Ca class Bc1(foo: int) class Bc2(bar: bool) +class Bc3 { + let baz : int +} //│ class Bc1(foo: int) //│ class Bc2(bar: bool) +//│ class Bc3() { +//│ let baz: int +//│ } :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.664: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.669: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() +class Bc02 extends Bc1(1:int) { + let foo = 2 +} +//│ class Bc02() { +//│ let foo: 2 +//│ } + +Bc02().foo +//│ 2 + +:e +class Bc31(baz: bool) extends Bc3 +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.686: class Bc31(baz: bool) extends Bc3 +//│ ║ ^^^^ +//│ ╟── type `bool` is not an instance of type `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.660: let baz : int +//│ ╙── ^^^ +//│ class Bc31(baz: bool) + +:e +class Bc11 extends Bc1(1) { + let foo = true +} +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.698: let foo = true +//│ ║ ^^^^ +//│ ╟── reference of type `true` does not match type `1` +//│ ╟── Note: constraint arises from integer literal: +//│ ║ l.697: class Bc11 extends Bc1(1) { +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.698: let foo = true +//│ ║ ^^^^ +//│ ╟── reference of type `true` is not an instance of type `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.657: class Bc1(foo: int) +//│ ╙── ^^^ +//│ class Bc11() { +//│ let foo: true +//│ } trait Base[A] { fun f: A -> A } @@ -688,7 +735,7 @@ class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } trait BInt extends Base[int] { fun f = error } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A341# +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A351# trait BPar[T] extends Base[(int,T)] //│ trait BPar[T]() { @@ -731,7 +778,7 @@ fb(cp1, 2) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.732: trait BErr1 extends Base +//│ ║ l.779: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -740,10 +787,10 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.741: class DerBad1 extends Base[int, int] +//│ ║ l.788: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.741: class DerBad1 extends Base[int, int] +//│ ║ l.788: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() { //│ fun f: int -> int @@ -752,28 +799,28 @@ class DerBad1 extends Base[int, int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.753: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (A, B,) -> (A, B,) @@ -828,9 +875,16 @@ class G1[A](x: A) // TODO class GI(x: int) extends G1[int] //│ ╔══[ERROR] class type arguments not yet supported -//│ ║ l.829: class GI(x: int) extends G1[int] +//│ ║ l.876: class GI(x: int) extends G1[int] //│ ╙── ^^ //│ ╔══[ERROR] class G1 expects 1 parameter(s); got 0 -//│ ║ l.829: class GI(x: int) extends G1[int] +//│ ║ l.876: class GI(x: int) extends G1[int] //│ ╙── ^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.876: class GI(x: int) extends G1[int] +//│ ║ ^^^ +//│ ╟── type `int` does not match type `A` +//│ ╟── Note: constraint arises from type parameter: +//│ ║ l.872: class G1[A](x: A) +//│ ╙── ^ //│ class GI(x: int) From 3f857e2c3bd513e968638da79afa70633c7dd1ba Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Thu, 27 Apr 2023 19:34:37 +0800 Subject: [PATCH 260/498] WIP: handling class params for interfaces --- .../src/main/scala/mlscript/NuTypeDefs.scala | 23 +- shared/src/test/diff/nu/InterfaceMono.mls | 197 ++++++++++++ shared/src/test/diff/nu/Interfaces.mls | 297 +++++++++++------- 3 files changed, 392 insertions(+), 125 deletions(-) create mode 100644 shared/src/test/diff/nu/InterfaceMono.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8536ec25b4..3ac9271a48 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -759,7 +759,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val info = lti.complete().freshen info match { case rawTrt: TypedNuTrt => - implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty @@ -797,16 +796,17 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => vMembers ++ trt.typeMembers ) case _ => - err(msg"trait can only inherit traits", p.toLoc) - (superType, tags, members, vMembers) + err(msg"trait can only inherit traits", p.toLoc) + (superType, tags, members, vMembers) } - case _ => (superType, tags, members, vMembers) + case _ => + err(msg"Could not find definition `${trtName}`", p.toLoc) + (superType, tags, members, vMembers) } case Nil => (superType, tags, members, vMembers) } val (thisType, tags, baseMems, baseVMems) = - // ? is it really a good idea inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) // val selfType = tags & sig_ty @@ -1063,7 +1063,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => computeBaseClass(ps, pack) } - case _ => computeBaseClass(ps, pack) + case _ => + err(msg"Could not find definition ${parNme}", p.toLoc) + computeBaseClass(ps, pack) } case Nil => pack } @@ -1085,15 +1087,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature implicit val prov: TP = memSign.prov + // println(s"checking interface mamber `${m.name}`") constrain(memSign, m.asInstanceOf[TypedNuTermDef].typeSignature) - case S(_) => () + case S(pm: NuParam) => + val pmSign = pm.typeSignature + implicit val prov: TP = pmSign.prov + constrain(pmSign, m.asInstanceOf[TypedNuTermDef].typeSignature) + case S(_) => Nil case N => err(msg"Member ${m.name} is declared in parent trait but not implemented", td.toLoc) } } TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems ++ ifaceMembers.map(d => d.name -> d).toMap, + tparams, typedParams, mems /* ++ ifaceMembers.map(d => d.name -> d).toMap */, // if (td.kind is Nms) TopType else thisTV TopType, // ifaceAnnot, diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls new file mode 100644 index 0000000000..fe41d517e9 --- /dev/null +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -0,0 +1,197 @@ +:NewDefs +:NoJS + +trait Showable { + fun toString: string +} +//│ trait Showable() { +//│ fun toString: string +//│ } + +:e +trait What0 extends woooo +//│ ╔══[ERROR] Could not find definition `woooo` +//│ ║ l.12: trait What0 extends woooo +//│ ╙── ^^^^^ +//│ trait What0() + +class Point(x: int, y: int) extends Showable { + fun mlen = x + y + fun toString = "I'm a point" +} +//│ class Point(x: int, y: int) { +//│ fun mlen: int +//│ fun toString: "I'm a point" +//│ } + +class What1(toString: string) extends Showable +//│ class What1(toString: string) + +:e +trait NoShow extends What1("hi") +//│ ╔══[ERROR] trait arguments not yet supported +//│ ║ l.31: trait NoShow extends What1("hi") +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] trait can only inherit traits +//│ ║ l.31: trait NoShow extends What1("hi") +//│ ╙── ^^^^^^^^^^^ +//│ trait NoShow() + +:e +class ErrC1 extends Showable +class ErrC2 extends Showable { + fun toString = 114 +} +//│ ╔══[ERROR] Member toString is declared in parent trait but not implemented +//│ ║ l.41: class ErrC1 extends Showable +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in definition of method toString: +//│ ║ l.43: fun toString = 114 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── integer literal of type `114` is not an instance of type `string` +//│ ║ l.43: fun toString = 114 +//│ ║ ^^^ +//│ ╟── but it flows into definition of method toString with expected type `string` +//│ ║ l.43: fun toString = 114 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.5: fun toString: string +//│ ║ ^^^^^^ +//│ ╟── from signature of member toString: +//│ ║ l.5: fun toString: string +//│ ╙── ^^^^^^^^^^^^^^^^ +//│ class ErrC1() +//│ class ErrC2() { +//│ fun toString: 114 +//│ } + +trait Stadt { + let name: string +} +//│ trait Stadt() { +//│ let name: string +//│ } + +trait RefinedStadt extends Stadt { + let size: int + fun foo: bool -> int +} +//│ trait RefinedStadt() { +//│ fun foo: bool -> int +//│ let name: string +//│ let size: int +//│ } + +trait SizedStadt extends RefinedStadt { + let size: 1 | 2 | 3 + fun bar: int -> int +} +//│ trait SizedStadt() { +//│ fun bar: int -> int +//│ fun foo: bool -> int +//│ let name: string +//│ let size: 1 | 2 | 3 +//│ } + +class Goodstatt(size: 1 | 2) extends RefinedStadt { + let name = "good" + fun bar(x) = x + fun foo(t) = if t && true then this.size else 0 +} +//│ class Goodstatt(size: 1 | 2) { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun foo: bool -> (0 | 1 | 2) +//│ let name: "good" +//│ } + +:e +class Errcity(size: int) extends SizedStadt { + fun bar = "hahaha" +} +//│ ╔══[ERROR] Type mismatch in definition of method bar: +//│ ║ l.109: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── string literal of type `"hahaha"` is not a function +//│ ║ l.109: fun bar = "hahaha" +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into definition of method bar with expected type `int -> int` +//│ ║ l.109: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.87: fun bar: int -> int +//│ ║ ^^^^^^^^^^ +//│ ╟── from signature of member bar: +//│ ║ l.87: fun bar: int -> int +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member foo is declared in parent trait but not implemented +//│ ║ l.108: class Errcity(size: int) extends SizedStadt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.109: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.110: } +//│ ╙── ^ +//│ ╔══[ERROR] Member name is declared in parent trait but not implemented +//│ ║ l.108: class Errcity(size: int) extends SizedStadt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.109: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.110: } +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.108: class Errcity(size: int) extends SizedStadt { +//│ ║ ^^^ +//│ ╟── type `int` does not match type `1 | 2 | 3` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.86: let size: 1 | 2 | 3 +//│ ╙── ^^^^^^^^^ +//│ class Errcity(size: int) { +//│ fun bar: "hahaha" +//│ } + +module Omg extends Stadt { + fun name = "omg!!!" + fun cool(x) = x + x +} +//│ module Omg() { +//│ fun cool: int -> int +//│ fun name: "omg!!!" +//│ } + +mixin More { + fun more(x) = x == 1 + fun size = 1 + fun bar(x) = x +} +//│ mixin More() { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun more: number -> bool +//│ fun size: 1 +//│ } + +mixin Fooo { + fun foo(x) = 0 +} +//│ mixin Fooo() { +//│ fun foo: anything -> 0 +//│ } + +// FIXME +class Dirtberg extends More, SizedStadt, Fooo { + let name = "dirt" + fun size = 4 +} +//│ class Dirtberg() { +//│ fun bar: int -> int +//│ fun foo: anything -> 0 +//│ fun more: number -> bool +//│ let name: "dirt" +//│ fun size: 4 +//│ } + +class Iceburg(name: string) extends RefinedStadt, More, Fooo +//│ class Iceburg(name: string) { +//│ fun bar: 'a -> 'a +//│ fun foo: anything -> 0 +//│ fun more: number -> bool +//│ fun size: 1 +//│ } diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 1391bbdc96..944c7f9642 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -20,7 +20,7 @@ module M extends Test { } //│ module M() { //│ fun bar: bool -> bool -//│ fun foo: int +//│ fun foo: 0 //│ } M: Test @@ -107,8 +107,8 @@ class C extends Test { fun bar(x) = x } //│ class C() { -//│ fun bar: bool -> bool -//│ fun foo: int +//│ fun bar: forall 'a. 'a -> 'a +//│ fun foo: 1 //│ } mixin M { @@ -128,11 +128,11 @@ class F extends Oth, M, Mixed { let v = 2 } //│ class F() { -//│ let a: int -//│ fun bar: bool -> bool -//│ fun cool: int -> bool -//│ fun foo: int -//│ fun get: bool +//│ let a: 3 +//│ fun bar: forall 'a. 'a -> 'a +//│ fun cool: number -> bool +//│ fun foo: 2 +//│ fun get: true //│ fun m1: 3 //│ fun ter: nothing //│ let v: 2 @@ -145,7 +145,7 @@ fi : Oth & Geo //│ Geo & Oth fi.get -//│ bool +//│ true fi: Test & Anemo //│ Anemo & Test @@ -182,10 +182,10 @@ let ct: Test = c //│ let ct: Test c.foo -//│ int +//│ 1 c.bar(true) -//│ bool +//│ true // :d c: Test @@ -213,12 +213,12 @@ let c1: Test = C() // :d fun fcc(x: C) = x.foo -//│ fun fcc: (x: C,) -> int +//│ fun fcc: (x: C,) -> 1 fun fc(x: Test) = x fun ffm(x: F) = x.get //│ fun fc: (x: Test,) -> Test -//│ fun ffm: (x: F,) -> bool +//│ fun ffm: (x: F,) -> true :e fun fee(x: Test) = x: Oth @@ -242,7 +242,7 @@ fc(c) fun fts['a](x: 'a & Test) = x.foo fts(c) //│ fun fts: forall 'foo. (x: Test & {foo: 'foo} | Test & ~#Test,) -> 'foo -//│ int +//│ 1 fts(oth1) //│ int @@ -279,7 +279,7 @@ class Ea1 extends A1, A2 { //│ ║ l.253: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1() { -//│ fun a1: 2 | 3 +//│ fun a1: 4 //│ } trait Ele { @@ -293,7 +293,7 @@ class CE extends Ele { fun ce(x) = x } //│ class CE() { -//│ fun ce: Oth -> Test +//│ fun ce: forall 'a. 'a -> 'a //│ } :e @@ -308,18 +308,17 @@ class E1 extends Test { //│ ║ l.302: } //│ ╙── ^ //│ class E1() { -//│ fun bar: bool -> bool -//│ fun foo: int +//│ fun foo: 2 //│ } :e trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.316: trait TE1 extends C +//│ ║ l.315: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] trait can only inherit traits -//│ ║ l.317: trait TE2 extends M, Test +//│ ║ l.316: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() //│ trait TE2() @@ -330,13 +329,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.329: fun foo = true +//│ ║ l.328: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.329: fun foo = true +//│ ║ l.328: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.329: fun foo = true +//│ ║ l.328: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -345,29 +344,26 @@ class E2 extends Test { //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ class E2() { -//│ fun bar: bool -> bool -//│ fun foo: int +//│ fun bar: forall 'a. 'a -> 'a +//│ fun foo: true //│ } // TODO :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ║ l.353: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ║ l.353: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member foo is declared in parent trait but not implemented -//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ║ l.353: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ║ l.353: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ class D() { -//│ fun bar: bool -> bool -//│ fun foo: int -//│ } +//│ class D() @@ -418,10 +414,10 @@ if b is Foo(a) then a else 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.419: if b is Bar(f) then f else 0 +//│ ║ l.415: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.401: class Bar[B](f: B => B) extends Base +//│ ║ l.397: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -430,14 +426,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.429: if b is +//│ ║ l.425: if b is //│ ║ ^^^^ -//│ ║ l.430: Foo(a) then a +//│ ║ l.426: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.431: Bar(f) then f +//│ ║ l.427: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.401: class Bar[B](f: B => B) extends Base +//│ ║ l.397: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything @@ -445,7 +441,7 @@ if b is // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.446: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.442: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -486,40 +482,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.484: fun fto(w: WP): EM = w +//│ ║ l.480: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.484: fun fto(w: WP): EM = w +//│ ║ l.480: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.484: fun fto(w: WP): EM = w +//│ ║ l.480: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.484: fun fto(w: WP): EM = w +//│ ║ l.480: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.485: z: WP +//│ ║ l.481: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.464: let z: ZL +//│ ║ l.460: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.485: z: WP +//│ ║ l.481: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.485: z: WP +//│ ║ l.481: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.486: g: ZL +//│ ║ l.482: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.463: let g: Geo +//│ ║ l.459: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.486: g: ZL +//│ ║ l.482: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.486: g: ZL +//│ ║ l.482: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -558,23 +554,23 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.557: fun foo(x) = x && false +//│ ║ l.553: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ?_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.557: fun foo(x) = x && false +//│ ║ l.553: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.557: fun foo(x) = x && false +//│ ║ l.553: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ?_` -//│ ║ l.557: fun foo(x) = x && false +//│ ║ l.553: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.528: fun foo(x) = x + 1 +//│ ║ l.524: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2() { -//│ fun ce: Oth -> Test +//│ fun ce: forall 'a. 'a -> 'a //│ fun foo: bool -> bool //│ } @@ -583,25 +579,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.582: class Eh extends Bs(1) +//│ ║ l.578: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.582: class Eh extends Bs(1) +//│ ║ l.578: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.527: class Bs(a: bool) { +//│ ║ l.523: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.583: class Eh1 extends Bs +//│ ║ l.579: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.528: fun foo(x) = x + 1 +//│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.528: fun foo(x) = x + 1 +//│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.528: fun foo(x) = x + 1 +//│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -610,7 +606,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.584: class Eh3 extends Bs(false), Test +//│ ║ l.580: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -619,8 +615,7 @@ class Eh3 extends Bs(false), Test //│ fun foo: int -> int //│ } //│ class Eh3() { -//│ fun bar: bool -> bool -//│ fun foo: int +//│ fun foo: int -> int //│ } class Ca(a: int) extends Oth { @@ -629,17 +624,16 @@ class Ca(a: int) extends Oth { fun bar(x) = x } //│ class Ca(a: int) { -//│ let a: int -//│ fun bar: bool -> bool -//│ fun cool: int -> bool -//│ fun foo: int +//│ fun bar: forall 'a. 'a -> 'a +//│ fun cool: anything -> false +//│ fun foo: 1 //│ } class Cx(a: 1 | 2, b: bool) extends Ca(a) //│ class Cx(a: 1 | 2, b: bool) { -//│ fun bar: bool -> bool -//│ fun cool: int -> bool -//│ fun foo: int +//│ fun bar: forall 'a. 'a -> 'a +//│ fun cool: anything -> false +//│ fun foo: 1 //│ } let cx1 = Cx(2, true) @@ -668,7 +662,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.669: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.663: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() @@ -685,11 +679,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.686: class Bc31(baz: bool) extends Bc3 +//│ ║ l.680: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.660: let baz : int +//│ ║ l.654: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -698,18 +692,18 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.698: let foo = true +//│ ║ l.692: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.697: class Bc11 extends Bc1(1) { +//│ ║ l.691: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.698: let foo = true +//│ ║ l.692: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.657: class Bc1(foo: int) +//│ ║ l.651: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -722,20 +716,36 @@ trait Base[A] { fun f: A -> A } //│ } class Der1 extends Base[int] { fun f(x) = x + 1 } -//│ class Der1() { -//│ fun f: int -> int -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A353# +//│ at: scala.collection.MapOps.default(Map.scala:274) +//│ at: scala.collection.MapOps.default$(Map.scala:273) +//│ at: scala.collection.AbstractMap.default(Map.scala:405) +//│ at: scala.collection.MapOps.apply(Map.scala:176) +//│ at: scala.collection.MapOps.apply$(Map.scala:175) +//│ at: scala.collection.AbstractMap.apply(Map.scala:405) +//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) +//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) +//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) +//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } -//│ class Der2[A, B]() { -//│ fun f: (A, B,) -> (A, B,) -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A367'# +//│ at: scala.collection.MapOps.default(Map.scala:274) +//│ at: scala.collection.MapOps.default$(Map.scala:273) +//│ at: scala.collection.AbstractMap.default(Map.scala:405) +//│ at: scala.collection.MapOps.apply(Map.scala:176) +//│ at: scala.collection.MapOps.apply$(Map.scala:175) +//│ at: scala.collection.AbstractMap.apply(Map.scala:405) +//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) +//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) +//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) +//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) // TODO trait BInt extends Base[int] { fun f = error } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A351# +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A377# trait BPar[T] extends Base[(int,T)] //│ trait BPar[T]() { @@ -765,9 +775,17 @@ fb(bp, false) class CP extends BPar[int] { fun f(x) = (x._2, x._1) } -//│ class CP() { -//│ fun f: ((int, int,) & 'A) -> ((int, int,) | 'A) -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A383_431'# +//│ at: scala.collection.MapOps.default(Map.scala:274) +//│ at: scala.collection.MapOps.default$(Map.scala:273) +//│ at: scala.collection.AbstractMap.default(Map.scala:405) +//│ at: scala.collection.MapOps.apply(Map.scala:176) +//│ at: scala.collection.MapOps.apply$(Map.scala:175) +//│ at: scala.collection.AbstractMap.apply(Map.scala:405) +//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) +//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) +//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) +//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) let cp1 = CP() //│ let cp1: CP @@ -778,7 +796,7 @@ fb(cp1, 2) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.779: trait BErr1 extends Base +//│ ║ l.797: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -787,44 +805,60 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.788: class DerBad1 extends Base[int, int] +//│ ║ l.806: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.788: class DerBad1 extends Base[int, int] +//│ ║ l.806: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ class DerBad1() { -//│ fun f: int -> int -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A458# +//│ at: scala.collection.MapOps.default(Map.scala:274) +//│ at: scala.collection.MapOps.default$(Map.scala:273) +//│ at: scala.collection.AbstractMap.default(Map.scala:405) +//│ at: scala.collection.MapOps.apply(Map.scala:176) +//│ at: scala.collection.MapOps.apply$(Map.scala:175) +//│ at: scala.collection.AbstractMap.apply(Map.scala:405) +//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) +//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) +//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) +//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.800: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ -//│ class Der2[A, B]() { -//│ fun f: (A, B,) -> (A, B,) -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A467'# +//│ at: scala.collection.MapOps.default(Map.scala:274) +//│ at: scala.collection.MapOps.default$(Map.scala:273) +//│ at: scala.collection.AbstractMap.default(Map.scala:405) +//│ at: scala.collection.MapOps.apply(Map.scala:176) +//│ at: scala.collection.MapOps.apply$(Map.scala:175) +//│ at: scala.collection.AbstractMap.apply(Map.scala:405) +//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) +//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) +//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) +//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) trait Ta[T] { let p: bool @@ -864,10 +898,17 @@ class Ctb extends Tb { let p = false let g = 2 } -//│ class Ctb() { -//│ let g: int -//│ let p: false -//│ } +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: T508# +//│ at: scala.collection.MapOps.default(Map.scala:274) +//│ at: scala.collection.MapOps.default$(Map.scala:273) +//│ at: scala.collection.AbstractMap.default(Map.scala:405) +//│ at: scala.collection.MapOps.apply(Map.scala:176) +//│ at: scala.collection.MapOps.apply$(Map.scala:175) +//│ at: scala.collection.AbstractMap.apply(Map.scala:405) +//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) +//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) +//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) +//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) class G1[A](x: A) //│ class G1[A](x: A) @@ -875,16 +916,38 @@ class G1[A](x: A) // TODO class GI(x: int) extends G1[int] //│ ╔══[ERROR] class type arguments not yet supported -//│ ║ l.876: class GI(x: int) extends G1[int] +//│ ║ l.917: class GI(x: int) extends G1[int] //│ ╙── ^^ //│ ╔══[ERROR] class G1 expects 1 parameter(s); got 0 -//│ ║ l.876: class GI(x: int) extends G1[int] +//│ ║ l.917: class GI(x: int) extends G1[int] //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.876: class GI(x: int) extends G1[int] +//│ ║ l.917: class GI(x: int) extends G1[int] //│ ║ ^^^ //│ ╟── type `int` does not match type `A` //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.872: class G1[A](x: A) +//│ ║ l.913: class G1[A](x: A) //│ ╙── ^ //│ class GI(x: int) + +trait Oz { + let age: int +} +//│ trait Oz() { +//│ let age: int +//│ } + +:e +class Fischl(age: bool) extends Oz +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.941: class Fischl(age: bool) extends Oz +//│ ║ ^^^^ +//│ ╟── type `bool` is not an instance of type `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.934: let age: int +//│ ╙── ^^^ +//│ class Fischl(age: bool) + +// TODO +class Klee(age: 1 | 2 | 3) extends Oz +//│ class Klee(age: 1 | 2 | 3) From d60d48b9647afe5b95d81b9576b018623264376c Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Thu, 27 Apr 2023 19:39:37 +0800 Subject: [PATCH 261/498] up --- .../src/main/scala/mlscript/NuTypeDefs.scala | 1 - shared/src/test/diff/nu/InterfaceMono.mls | 40 ++++++++++++------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 3ac9271a48..ac7e48a0f9 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1064,7 +1064,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => computeBaseClass(ps, pack) } case _ => - err(msg"Could not find definition ${parNme}", p.toLoc) computeBaseClass(ps, pack) } case Nil => pack diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index fe41d517e9..4e7cacaf9b 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -42,6 +42,7 @@ class ErrC1 extends Showable class ErrC2 extends Showable { fun toString = 114 } +class ErrC3(toString: string -> string) extends Showable //│ ╔══[ERROR] Member toString is declared in parent trait but not implemented //│ ║ l.41: class ErrC1 extends Showable //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,10 +61,21 @@ class ErrC2 extends Showable { //│ ╟── from signature of member toString: //│ ║ l.5: fun toString: string //│ ╙── ^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in function type: +//│ ║ l.45: class ErrC3(toString: string -> string) extends Showable +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── type `string -> string` is not an instance of type `string` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.5: fun toString: string +//│ ║ ^^^^^^ +//│ ╟── from signature of member toString: +//│ ║ l.5: fun toString: string +//│ ╙── ^^^^^^^^^^^^^^^^ //│ class ErrC1() //│ class ErrC2() { //│ fun toString: 114 //│ } +//│ class ErrC3(toString: string -> string) trait Stadt { let name: string @@ -109,40 +121,40 @@ class Errcity(size: int) extends SizedStadt { fun bar = "hahaha" } //│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.109: fun bar = "hahaha" +//│ ║ l.121: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── string literal of type `"hahaha"` is not a function -//│ ║ l.109: fun bar = "hahaha" +//│ ║ l.121: fun bar = "hahaha" //│ ║ ^^^^^^^^ //│ ╟── but it flows into definition of method bar with expected type `int -> int` -//│ ║ l.109: fun bar = "hahaha" +//│ ║ l.121: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.87: fun bar: int -> int +//│ ║ l.99: fun bar: int -> int //│ ║ ^^^^^^^^^^ //│ ╟── from signature of member bar: -//│ ║ l.87: fun bar: int -> int +//│ ║ l.99: fun bar: int -> int //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member foo is declared in parent trait but not implemented -//│ ║ l.108: class Errcity(size: int) extends SizedStadt { +//│ ║ l.120: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.109: fun bar = "hahaha" +//│ ║ l.121: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.110: } +//│ ║ l.122: } //│ ╙── ^ //│ ╔══[ERROR] Member name is declared in parent trait but not implemented -//│ ║ l.108: class Errcity(size: int) extends SizedStadt { +//│ ║ l.120: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.109: fun bar = "hahaha" +//│ ║ l.121: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.110: } +//│ ║ l.122: } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.108: class Errcity(size: int) extends SizedStadt { +//│ ║ l.120: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^ //│ ╟── type `int` does not match type `1 | 2 | 3` //│ ╟── Note: constraint arises from union type: -//│ ║ l.86: let size: 1 | 2 | 3 +//│ ║ l.98: let size: 1 | 2 | 3 //│ ╙── ^^^^^^^^^ //│ class Errcity(size: int) { //│ fun bar: "hahaha" @@ -178,7 +190,7 @@ mixin Fooo { // FIXME class Dirtberg extends More, SizedStadt, Fooo { let name = "dirt" - fun size = 4 + fun size = 4 // this should not check } //│ class Dirtberg() { //│ fun bar: int -> int From 88df416d1918dd1c97eedcb69179de030661d434 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Thu, 27 Apr 2023 23:21:42 +0800 Subject: [PATCH 262/498] Override Fields Created in Ctor (#160) --- .../main/scala/mlscript/codegen/Codegen.scala | 8 +- .../src/test/diff/codegen/ConstructorStmt.mls | 2 +- .../src/test/diff/codegen/FieldOverride.mls | 131 ++++++++++++++++++ shared/src/test/diff/codegen/Mixin.mls | 4 +- shared/src/test/diff/codegen/Nested.mls | 12 +- shared/src/test/diff/codegen/Super.mls | 2 +- 6 files changed, 145 insertions(+), 14 deletions(-) create mode 100644 shared/src/test/diff/codegen/FieldOverride.mls diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index def01ddca8..437187ceb3 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -854,10 +854,10 @@ final case class JSClassNewDecl( if (s.isEmpty) s"${p._1}" else s"${p._1}, $s") nestedTypes.foreach(t => buffer += s" #$t;") - if (!privateMem.isEmpty) { - privateMem.foreach(f => buffer += s" #${f};") - privateMem.foreach(f => buffer += s" get ${f}() { return this.#${f}; }") - } + privateMem.distinct.foreach(f => { + buffer += s" #${f};" + buffer += s" get ${f}() { return this.#${f}; }" + }) buffer += s" constructor($params) {" if (`extends`.isDefined) { val sf = superFields.iterator.zipWithIndex.foldLeft("")((res, p) => diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index b910fd2931..527ea98f11 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -212,8 +212,8 @@ class Baz { //│ if (this.#Baz === undefined) { //│ class Baz { //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor() { //│ this.#x = 123; diff --git a/shared/src/test/diff/codegen/FieldOverride.mls b/shared/src/test/diff/codegen/FieldOverride.mls new file mode 100644 index 0000000000..4de74414b0 --- /dev/null +++ b/shared/src/test/diff/codegen/FieldOverride.mls @@ -0,0 +1,131 @@ +:NewParser +:NewDefs + +:js +class C(a: int) { let a = 1 } +//│ class C(a: int) { +//│ let a: 1 +//│ } +//│ // Prelude +//│ let res; +//│ class TypingUnit { +//│ #C; +//│ constructor() { +//│ } +//│ get C() { +//│ const outer = this; +//│ if (this.#C === undefined) { +//│ class C { +//│ #a; +//│ get a() { return this.#a; } +//│ constructor(a) { +//│ this.#a = a; +//│ this.#a = 1; +//│ const a1 = this.#a; +//│ } +//│ }; +//│ this.#C = ((a) => new C(a)); +//│ this.#C.class = C; +//│ } +//│ return this.#C; +//│ } +//│ } +//│ const typing_unit = new TypingUnit; +//│ globalThis.C = typing_unit.C; +//│ // End of generated code + +// should return 1 +let a = C(2) +a.a +//│ let a: C +//│ 1 +//│ a +//│ = C {} +//│ res +//│ = 1 + +:js +class C2(a: int, b: int) { + let a = b + 1 + let b = a + 1 +} +//│ class C2(a: int, b: int) { +//│ let a: int +//│ let b: int +//│ } +//│ // Prelude +//│ class TypingUnit2 { +//│ #C2; +//│ constructor() { +//│ } +//│ get C2() { +//│ const outer = this; +//│ if (this.#C2 === undefined) { +//│ class C2 { +//│ #a; +//│ get a() { return this.#a; } +//│ #b; +//│ get b() { return this.#b; } +//│ constructor(a, b) { +//│ this.#a = a; +//│ this.#b = b; +//│ this.#a = b + 1; +//│ const a1 = this.#a; +//│ this.#b = a1 + 1; +//│ const b1 = this.#b; +//│ } +//│ }; +//│ this.#C2 = ((a, b) => new C2(a, b)); +//│ this.#C2.class = C2; +//│ } +//│ return this.#C2; +//│ } +//│ } +//│ const typing_unit2 = new TypingUnit2; +//│ globalThis.C2 = typing_unit2.C2; +//│ // End of generated code + +let c2 = C2(1, 2) +c2.a +c2.b +//│ let c2: C2 +//│ int +//│ c2 +//│ = C2 {} +//│ res +//│ = 3 +//│ res +//│ = 4 + +class C3(a: int) { + let a = 42 + class C4(a: int) { + let a = 44 + } +} +//│ class C3(a: int) { +//│ class C4(a: int) { +//│ let a: 44 +//│ } +//│ let a: 42 +//│ } + +:e +let c3 = C3(1) +let c4 = c3.C4(2) +c3.a +c4.a +//│ ╔══[ERROR] access to class member not yet supported +//│ ║ l.115: let c4 = c3.C4(2) +//│ ╙── ^^^ +//│ let c3: C3 +//│ let c4: error +//│ error +//│ c3 +//│ = C3 {} +//│ c4 +//│ = C4 {} +//│ res +//│ = 42 +//│ res +//│ = 44 diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index b72e833b59..e51cb76fd5 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -19,8 +19,8 @@ class Lit(n: int) //│ if (this.#Add === undefined) { //│ class Add { //│ #lhs; -//│ #rhs; //│ get lhs() { return this.#lhs; } +//│ #rhs; //│ get rhs() { return this.#rhs; } //│ constructor(lhs, rhs) { //│ this.#lhs = lhs; @@ -66,8 +66,8 @@ class Lit(n: int) //│ │ │ if (this.#Add === undefined) { //│ │ │ class Add { //│ │ │ #lhs; -//│ │ │ #rhs; //│ │ │ get lhs() { return this.#lhs; } +//│ │ │ #rhs; //│ │ │ get rhs() { return this.#rhs; } //│ │ │ constructor(lhs, rhs) { //│ │ │ this.#lhs = lhs; diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index c707d2d08e..b47e15c78c 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -582,8 +582,8 @@ module H { //│ if (this.#J === undefined) { //│ class J { //│ #x; -//│ #i; //│ get x() { return this.#x; } +//│ #i; //│ get i() { return this.#i; } //│ constructor(x) { //│ this.#x = x; @@ -666,8 +666,8 @@ ij.incY //│ class I { //│ #J; //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor(x) { //│ this.#x = x; @@ -679,8 +679,8 @@ ij.incY //│ if (this.#J === undefined) { //│ class J { //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor(x) { //│ this.#x = x; @@ -1125,8 +1125,8 @@ I(1).J(3).a //│ class I { //│ #J; //│ #x; -//│ #y; //│ get x() { return this.#x; } +//│ #y; //│ get y() { return this.#y; } //│ constructor(x) { //│ this.#x = x; @@ -1138,8 +1138,8 @@ I(1).J(3).a //│ if (this.#J === undefined) { //│ class J { //│ #z; -//│ #a; //│ get z() { return this.#z; } +//│ #a; //│ get a() { return this.#a; } //│ constructor(z) { //│ this.#z = z; @@ -1378,8 +1378,8 @@ class Outer1(outer: int) { //│ if (this.#Outer2 === undefined) { //│ class Outer2 { //│ #x; -//│ #outer; //│ get x() { return this.#x; } +//│ #outer; //│ get outer() { return this.#outer; } //│ constructor(x) { //│ this.#x = x; diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 5cac01cd98..aa500a3b7b 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -50,8 +50,8 @@ mixin Foo1 { //│ const outer = this; //│ return (class Foo1 extends base { //│ #foo0; -//│ #foo1; //│ get foo0() { return this.#foo0; } +//│ #foo1; //│ get foo1() { return this.#foo1; } //│ constructor(...rest) { //│ super(...rest); From 52b8c240ff2f846fcb2a26801789bef6a90e2119 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 27 Apr 2023 16:45:29 +0800 Subject: [PATCH 263/498] Add some tests and remove an apparently redundant definition --- .../scala/mlscript/ConstraintSolver.scala | 4 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 21 ++-- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/test/diff/nu/InterfaceMono.mls | 91 ++++++++++++++ shared/src/test/diff/nu/Interfaces.mls | 119 ++++++------------ shared/src/test/diff/nu/NuScratch.mls | 78 ++++++++++++ .../src/test/scala/mlscript/DiffTests.scala | 4 +- 7 files changed, 224 insertions(+), 99 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 3f69b972e3..4b9169d1a7 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -82,8 +82,8 @@ class ConstraintSolver extends NormalForms { self: Typer => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => S(p.ty) - case S(p: NuTypeParam) => - S(p.ty) + // case S(p: NuTypeParam) => + // S(p.ty) case S(m) => S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) case N => N diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index ac7e48a0f9..e9b28fc54e 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -54,7 +54,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class NuParam(nme: Var, ty: FieldType, isType: Bool)(val level: Level) extends NuMember { def name: Str = nme.name - def kind: DeclKind = Val + def kind: DeclKind = + if (isType) Als // FIXME? + else Val def typeSignature: ST = ty.ub def freshenAbove(lim: Int, rigidify: Bool) @@ -71,6 +73,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } + /* // TODO: case class NuTypeParam(nme: TN, ty: FieldType)(val level: Level) extends NuMember { def name: Str = nme.name @@ -90,7 +93,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = Als // FIXME? } - + */ sealed trait TypedNuDecl extends NuMember { def name: Str @@ -756,7 +759,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) ctx.get(trtName) match { case S(lti: LazyTypeInfo) => - val info = lti.complete().freshen + val info = lti.complete() info match { case rawTrt: TypedNuTrt => implicit val freshened: MutMap[TV, ST] = MutMap.empty @@ -817,7 +820,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap val vmems = baseVMems ++ tparams.map { case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuTypeParam(nme, FieldType(S(tv), tv)(provTODO))(level) + td.nme.name+"#"+name -> NuParam(nme.toVar, FieldType(S(tv), tv)(provTODO), true)(level) } TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags, vmems) -> Nil @@ -919,9 +922,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO first-class mixins/classes... err(msg"Cannot inherit from a parameter", p.toLoc) Nil - case als: NuTypeParam => - err(msg"Cannot inherit from a type parameter", p.toLoc) - Nil + // case als: NuTypeParam => + // err(msg"Cannot inherit from a type parameter", p.toLoc) + // Nil case cls: TypedNuFun => err(msg"Cannot inherit from a function", p.toLoc) Nil @@ -976,7 +979,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], trtMem: Ls[NuMember], trtTyMem: Map[Str, NuMember]) // compute base class and interfaces - def computeBaseClass(parents: Ls[ParentSpec], pack: Pack): Pack = + def computeBaseClass(parents: Ls[ParentSpec], pack: Pack): Pack = // TODO rename parents match { case (p, v @ Var(parNme), parTargs, parArgs) :: ps => ctx.get(parNme) match { @@ -1078,7 +1081,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO type members of parent class val tyMem = ifaceTmem ++ tparams.map { case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuTypeParam(nme, FieldType(S(tv), tv)(provTODO))(level) + td.nme.name+"#"+name -> NuParam(nme.toVar, FieldType(S(tv), tv)(provTODO), true)(level) } ifaceMembers.foreach { m => diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index ce80d09b00..9e76c29f15 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -745,7 +745,7 @@ abstract class TyperHelpers { Typer: Typer => case NuParam(nme, ty, isType) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable case TypedNuFun(level, fd, ty) => pol -> ty :: Nil case td: TypedNuDecl => TypedTypingUnit(td :: Nil, N).childrenPol(pol: PolMap) // TODO refactor - case NuTypeParam(nme, ty) => childrenPolField(PolMap.pos)(ty) + // case NuTypeParam(nme, ty) => childrenPolField(PolMap.pos)(ty) } this match { case tv @ AssignedVariable(ty) => @@ -789,6 +789,7 @@ abstract class TyperHelpers { Typer: Typer => // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ + cls.typeMembers.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.instanceType) case cls: TypedNuTrt => @@ -881,6 +882,7 @@ abstract class TyperHelpers { Typer: Typer => // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil) ++ cls.members.valuesIterator.flatMap(childrenMem) ++ + cls.typeMembers.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.instanceType) } @@ -1191,7 +1193,7 @@ abstract class TyperHelpers { Typer: Typer => apply(pol.contravar)(superTV) case NuParam(nme, ty, isType) => applyField(pol)(ty) case TypedNuFun(level, fd, ty) => apply(pol)(ty) - case NuTypeParam(nme, ty) => applyField(pol)(ty) + // case NuTypeParam(nme, ty) => applyField(pol)(ty) } def apply(pol: PolMap)(st: ST): Unit = st match { case tv @ AssignedVariable(ty) => apply(pol)(ty) diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 4e7cacaf9b..a431f90299 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -207,3 +207,94 @@ class Iceburg(name: string) extends RefinedStadt, More, Fooo //│ fun more: number -> bool //│ fun size: 1 //│ } + +class A { fun x: int = 1 } +//│ class A() { +//│ fun x: int +//│ } + +class B extends A { fun x = "A" } +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.216: class B extends A { fun x = "A" } +//│ ║ ^^^^^^^ +//│ ╟── string literal of type `"A"` is not an instance of type `int` +//│ ║ l.216: class B extends A { fun x = "A" } +//│ ║ ^^^ +//│ ╟── but it flows into definition of method x with expected type `int` +//│ ║ l.216: class B extends A { fun x = "A" } +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.211: class A { fun x: int = 1 } +//│ ║ ^^^ +//│ ╟── from definition of method x: +//│ ║ l.211: class A { fun x: int = 1 } +//│ ╙── ^^^^^^^^^^ +//│ class B() { +//│ fun x: "A" +//│ } + +class C1[A] { fun a: A = a } +//│ class C1[A]() { +//│ fun a: A +//│ } + +// TODO +class C2 extends C1[int] { fun a = 1 } +//│ ╔══[ERROR] class type arguments not yet supported +//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } +//│ ╙── ^^ +//│ ╔══[ERROR] Type mismatch in definition of method a: +//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } +//│ ║ ^^^^^ +//│ ╟── integer literal of type `1` does not match type `A` +//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } +//│ ║ ^ +//│ ╟── but it flows into definition of method a with expected type `A` +//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from definition of method a: +//│ ║ l.236: class C1[A] { fun a: A = a } +//│ ╙── ^^^^^^^^ +//│ class C2() { +//│ fun a: 1 +//│ } + +// trait MyTrait[A] { type MyTrait#A = A; fun a: A = a } +// freshen/subst +// trait MyTrait[int] { type MyTrait#A = int; fun a: int = a } + +trait MyTrait[A] { fun a: A = a } +//│ trait MyTrait[A]() { +//│ fun a: A +//│ } + +// :ns +// :d +// :ds +class C extends MyTrait[int] { fun a = 1 } +//│ class C() { +//│ fun a: 1 +//│ } + +:e +class C extends MyTrait[int] { fun a = false } +//│ ╔══[ERROR] Type mismatch in definition of method a: +//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ ^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `int` +//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ ^^^^^ +//│ ╟── but it flows into definition of method a with expected type `int` +//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ ^^^ +//│ ╟── from definition of method a: +//│ ║ l.266: trait MyTrait[A] { fun a: A = a } +//│ ╙── ^^^^^^^^ +//│ class C() { +//│ fun a: false +//│ } + + diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 944c7f9642..9e3df12567 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -716,36 +716,20 @@ trait Base[A] { fun f: A -> A } //│ } class Der1 extends Base[int] { fun f(x) = x + 1 } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A353# -//│ at: scala.collection.MapOps.default(Map.scala:274) -//│ at: scala.collection.MapOps.default$(Map.scala:273) -//│ at: scala.collection.AbstractMap.default(Map.scala:405) -//│ at: scala.collection.MapOps.apply(Map.scala:176) -//│ at: scala.collection.MapOps.apply$(Map.scala:175) -//│ at: scala.collection.AbstractMap.apply(Map.scala:405) -//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) -//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) -//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) -//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) +//│ class Der1() { +//│ fun f: int -> int +//│ } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A367'# -//│ at: scala.collection.MapOps.default(Map.scala:274) -//│ at: scala.collection.MapOps.default$(Map.scala:273) -//│ at: scala.collection.AbstractMap.default(Map.scala:405) -//│ at: scala.collection.MapOps.apply(Map.scala:176) -//│ at: scala.collection.MapOps.apply$(Map.scala:175) -//│ at: scala.collection.AbstractMap.apply(Map.scala:405) -//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) -//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) -//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) -//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) +//│ class Der2[A, B]() { +//│ fun f: forall 'a 'b. ('a, 'b,) -> ('a, 'b,) +//│ } // TODO trait BInt extends Base[int] { fun f = error } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A377# +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A385# trait BPar[T] extends Base[(int,T)] //│ trait BPar[T]() { @@ -775,17 +759,9 @@ fb(bp, false) class CP extends BPar[int] { fun f(x) = (x._2, x._1) } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A383_431'# -//│ at: scala.collection.MapOps.default(Map.scala:274) -//│ at: scala.collection.MapOps.default$(Map.scala:273) -//│ at: scala.collection.AbstractMap.default(Map.scala:405) -//│ at: scala.collection.MapOps.apply(Map.scala:176) -//│ at: scala.collection.MapOps.apply$(Map.scala:175) -//│ at: scala.collection.AbstractMap.apply(Map.scala:405) -//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) -//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) -//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) -//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) +//│ class CP() { +//│ fun f: forall 'a 'b. {_1: 'a, _2: 'b} -> ('b, 'a,) +//│ } let cp1 = CP() //│ let cp1: CP @@ -796,7 +772,7 @@ fb(cp1, 2) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.797: trait BErr1 extends Base +//│ ║ l.773: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -805,60 +781,42 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.806: class DerBad1 extends Base[int, int] +//│ ║ l.782: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.806: class DerBad1 extends Base[int, int] +//│ ║ l.782: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A458# -//│ at: scala.collection.MapOps.default(Map.scala:274) -//│ at: scala.collection.MapOps.default$(Map.scala:273) -//│ at: scala.collection.AbstractMap.default(Map.scala:405) -//│ at: scala.collection.MapOps.apply(Map.scala:176) -//│ at: scala.collection.MapOps.apply$(Map.scala:175) -//│ at: scala.collection.AbstractMap.apply(Map.scala:405) -//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) -//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) -//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) -//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) +//│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.826: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A467'# -//│ at: scala.collection.MapOps.default(Map.scala:274) -//│ at: scala.collection.MapOps.default$(Map.scala:273) -//│ at: scala.collection.AbstractMap.default(Map.scala:405) -//│ at: scala.collection.MapOps.apply(Map.scala:176) -//│ at: scala.collection.MapOps.apply$(Map.scala:175) -//│ at: scala.collection.AbstractMap.apply(Map.scala:405) -//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) -//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) -//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) -//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) +//│ class Der2[A, B]() { +//│ fun f: forall 'a 'b. ('a, 'b,) -> ('b, 'a,) +//│ } trait Ta[T] { let p: bool @@ -898,17 +856,10 @@ class Ctb extends Tb { let p = false let g = 2 } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: T508# -//│ at: scala.collection.MapOps.default(Map.scala:274) -//│ at: scala.collection.MapOps.default$(Map.scala:273) -//│ at: scala.collection.AbstractMap.default(Map.scala:405) -//│ at: scala.collection.MapOps.apply(Map.scala:176) -//│ at: scala.collection.MapOps.apply$(Map.scala:175) -//│ at: scala.collection.AbstractMap.apply(Map.scala:405) -//│ at: mlscript.TypeSimplifier.process$1(TypeSimplifier.scala:59) -//│ at: mlscript.TypeSimplifier.$anonfun$removeIrrelevantBounds$5(TypeSimplifier.scala:39) -//│ at: mlscript.NuTypeDefs$NuMember.$anonfun$map$1(NuTypeDefs.scala:44) -//│ at: mlscript.NuTypeDefs$NuTypeParam.$anonfun$mapPol$4(NuTypeDefs.scala:85) +//│ class Ctb() { +//│ let g: 2 +//│ let p: false +//│ } class G1[A](x: A) //│ class G1[A](x: A) @@ -916,17 +867,17 @@ class G1[A](x: A) // TODO class GI(x: int) extends G1[int] //│ ╔══[ERROR] class type arguments not yet supported -//│ ║ l.917: class GI(x: int) extends G1[int] +//│ ║ l.868: class GI(x: int) extends G1[int] //│ ╙── ^^ //│ ╔══[ERROR] class G1 expects 1 parameter(s); got 0 -//│ ║ l.917: class GI(x: int) extends G1[int] +//│ ║ l.868: class GI(x: int) extends G1[int] //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.917: class GI(x: int) extends G1[int] +//│ ║ l.868: class GI(x: int) extends G1[int] //│ ║ ^^^ //│ ╟── type `int` does not match type `A` //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.913: class G1[A](x: A) +//│ ║ l.864: class G1[A](x: A) //│ ╙── ^ //│ class GI(x: int) @@ -940,11 +891,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.941: class Fischl(age: bool) extends Oz +//│ ║ l.892: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.934: let age: int +//│ ║ l.885: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index db2ada0199..660e1ee9bc 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,2 +1,80 @@ :NewDefs +1 +//│ 1 +//│ res +//│ = 1 + +mixin T { fun a = "hi" } +//│ mixin T() { +//│ fun a: "hi" +//│ } + +class C(a: int) extends T +//│ class C(a: int) { +//│ fun a: "hi" +//│ } + +class B { let a = "hi" } +//│ class B() { +//│ let a: "hi" +//│ } + +class C(a: int) extends B +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.23: class C(a: int) extends B +//│ ║ ^^^ +//│ ╟── type `int` does not match type `"hi"` +//│ ╟── Note: constraint arises from string literal: +//│ ║ l.18: class B { let a = "hi" } +//│ ╙── ^^^^ +//│ class C(a: int) + + +mixin M { let b = "hi" } +//│ mixin M() { +//│ let b: "hi" +//│ } + +class B { let a = 1 : int } +//│ class B() { +//│ let a: int +//│ } + +class C(a: int, b: int) extends B, M +//│ class C(a: int, b: int) { +//│ let b: "hi" +//│ } + +let c = C(2, 3) +(c.a, c.b) +//│ let c: C +//│ (int, "hi",) +//│ c +//│ = C {} +//│ res +//│ = [ 2, 3 ] + +// class C(a: int, b: int) extends B, M { let b = "hi" } + + + +// FIXME +class C(a: int) { let a = 1 } +//│ class C(a: int) { +//│ let a: 1 +//│ } +//│ Syntax error: +//│ Identifier '#a' has already been declared + +class C(a: int) { fun a = 1 } +//│ class C(a: int) { +//│ fun a: 1 +//│ } + +class C(a: int) { fun a = a } +//│ class C(a: int) { +//│ fun a: nothing +//│ } + + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 738a2acbe7..45527907df 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -502,8 +502,8 @@ class DiffTests val indStr = " " * ind // ttu.entities.map(_.complete()(raise)).foreach { ttu.entities.foreach { - case p: typer.NuTypeParam => - output(s"${indStr}${p.name}: ${p.ty}") + // case p: typer.NuTypeParam => + // output(s"${indStr}${p.name}: ${p.ty}") case p: typer.NuParam => output(s"${indStr}${p.name}: ${p.ty}") case tc: typer.TypedNuAls => From 339e9b7a4a53fff722997f17caa4644e5eb1f2ca Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 28 Apr 2023 10:59:26 +0800 Subject: [PATCH 264/498] Simplify NuParam --- .../src/main/scala/mlscript/NuTypeDefs.scala | 27 ++++++++++--------- .../main/scala/mlscript/TyperHelpers.scala | 6 ++--- shared/src/main/scala/mlscript/helpers.scala | 1 + shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/nu/InterfaceMono.mls | 8 +++--- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index e9b28fc54e..0b7f96bc83 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -52,8 +52,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - case class NuParam(nme: Var, ty: FieldType, isType: Bool)(val level: Level) extends NuMember { + case class NuParam(nme: NameRef, ty: FieldType)(val level: Level) extends NuMember { def name: Str = nme.name + def isType: Bool = nme.isInstanceOf[TypeName] def kind: DeclKind = if (isType) Als // FIXME? else Val @@ -62,14 +63,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuParam = - NuParam(nme, ty.freshenAbove(lim, rigidify), isType)(level) + NuParam(nme, ty.freshenAbove(lim, rigidify))(level) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember = - NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)), isType)(level) + NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)))(level) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember = - NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)), isType)(level) + NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)))(level) } @@ -820,7 +821,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap val vmems = baseVMems ++ tparams.map { case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme.toVar, FieldType(S(tv), tv)(provTODO), true)(level) + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) } TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags, vmems) -> Nil @@ -869,9 +870,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi val fldNme = td.nme.name + "#" + tp.name - NuParam(Var(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isType = true)(lvl) + NuParam(TypeName(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov))(lvl) } - val tparamFields = tparamMems.map(p => p.nme -> p.ty) + val tparamFields = tparamMems.map(p => p.nme.toVar -> p.ty) assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) @@ -904,7 +905,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val a_ty = typeTerm(a) p.lb.foreach(constrain(_, a_ty)) constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false)(lvl) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } // TODO check overriding @@ -941,7 +942,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => superType, RecordType( newMembs.collect{ - case m: NuParam => m.nme -> m.ty + case m: NuParam => m.nme.toVar -> m.ty case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) } )(provTODO) @@ -964,7 +965,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val baseType = RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) - val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)(lvl)) + val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) val (thisType, baseMems) = inherit(parentSpecs, baseType, tparamMems ++ paramMems) @@ -1001,7 +1002,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val a_ty = typeTerm(a) p.lb.foreach(constrain(_, a_ty)) constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO), isType = false)(lvl) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } val numem = paramMems ++ cls.members.values.toList val res = pack.clsMem ++ numem.flatMap { m => @@ -1081,7 +1082,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO type members of parent class val tyMem = ifaceTmem ++ tparams.map { case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme.toVar, FieldType(S(tv), tv)(provTODO), true)(level) + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) } ifaceMembers.foreach { m => @@ -1116,7 +1117,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols - val paramMems = typedParams.map(f => NuParam(f._1, f._2, isType = false)(lvl)) + val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) implicit val vars: Map[Str, SimpleType] = outerVars ++ Map.empty // TODO type params val thisTV = freshVar(provTODO, N, S("this")) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 9e76c29f15..8e066950c4 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -742,7 +742,7 @@ abstract class TyperHelpers { Typer: Typer => def childrenPolField(pol: PolMap)(fld: FieldType): List[PolMap -> SimpleType] = fld.lb.map(pol.contravar -> _).toList ::: pol.covar -> fld.ub :: Nil def childrenPolMem(m: NuMember): List[PolMap -> SimpleType] = m match { - case NuParam(nme, ty, isType) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable + case NuParam(nme, ty) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable case TypedNuFun(level, fd, ty) => pol -> ty :: Nil case td: TypedNuDecl => TypedTypingUnit(td :: Nil, N).childrenPol(pol: PolMap) // TODO refactor // case NuTypeParam(nme, ty) => childrenPolField(PolMap.pos)(ty) @@ -842,7 +842,7 @@ abstract class TyperHelpers { Typer: Typer => } private def childrenMem(m: NuMember): List[ST] = m match { - case NuParam(nme, ty, isType) => ty.lb.toList ::: ty.ub :: Nil + case NuParam(nme, ty) => ty.lb.toList ::: ty.ub :: Nil case TypedNuFun(level, fd, ty) => ty :: Nil } def children(includeBounds: Bool): List[SimpleType] = this match { @@ -1191,7 +1191,7 @@ abstract class TyperHelpers { Typer: Typer => members.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTV) apply(pol.contravar)(superTV) - case NuParam(nme, ty, isType) => applyField(pol)(ty) + case NuParam(nme, ty) => applyField(pol)(ty) case TypedNuFun(level, fd, ty) => apply(pol)(ty) // case NuTypeParam(nme, ty) => applyField(pol)(ty) } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 02cd4c9f00..661f4eea04 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -627,6 +627,7 @@ trait LitImpl { self: Lit => trait VarImpl { self: Var => def isPatVar: Bool = (name.head.isLetter && name.head.isLower || name.head === '_' || name.head === '$') && name =/= "true" && name =/= "false" + def toVar: Var = this var uid: Opt[Int] = N } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index fba2e39ded..0c797ecd1c 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -43,7 +43,7 @@ final case class MethodDef[RHS <: Term \/ Type]( val children: Ls[Located] = nme :: body :: Nil } -sealed trait NameRef extends Located { val name: Str } +sealed trait NameRef extends Located { val name: Str; def toVar: Var } sealed abstract class DeclKind(val str: Str) case object Val extends DeclKind("value") diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index a431f90299..0bb3971fd4 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -279,16 +279,16 @@ class C extends MyTrait[int] { fun a = 1 } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ l.280: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ l.280: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ l.280: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.412: class C extends MyTrait[int] { fun a = false } +//│ ║ l.280: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ //│ ╟── from definition of method a: //│ ║ l.266: trait MyTrait[A] { fun a: A = a } From 09239cc3db059b6269f9427f621b4fa2ccb78bf7 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 28 Apr 2023 13:16:40 +0800 Subject: [PATCH 265/498] WIP: refactor and more tests --- .../src/main/scala/mlscript/NuTypeDefs.scala | 196 ++++++++---------- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/test/diff/nu/GADTMono.mls | 9 +- .../test/diff/nu/GenericClassInheritance.mls | 16 ++ shared/src/test/diff/nu/InterfaceGeneric.mls | 51 +++++ shared/src/test/diff/nu/InterfaceMono.mls | 81 +++----- shared/src/test/diff/nu/Interfaces.mls | 102 ++++----- shared/src/test/diff/nu/NuScratch.mls | 3 +- 9 files changed, 241 insertions(+), 227 deletions(-) create mode 100644 shared/src/test/diff/nu/GenericClassInheritance.mls create mode 100644 shared/src/test/diff/nu/InterfaceGeneric.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 0b7f96bc83..ee5175ee37 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -128,29 +128,27 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) - case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags, typeMembers) => + case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags) => TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), tags.freshenAbove(lim, rigidify), - inheritedTags, - typeMembers + inheritedTags )(cls.instanceType.freshenAbove(lim, rigidify)) case cls @ TypedNuAls(level, td, tparams, body) => TypedNuAls(level, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), body.freshenAbove(lim, rigidify)) - case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags, typeMembers) => + case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags) => TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), sign.map(_.freshenAbove(lim, rigidify)), // todo tags.freshenAbove(lim, rigidify), - inheritedTags, - typeMembers.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, + inheritedTags ) } val td: NuTypeDef @@ -183,6 +181,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol, body) ) } + + sealed trait PolyNuDecl extends TypedNuDecl { + def tparams: TyParams + } case class TypedNuTrt( @@ -192,9 +194,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => thisTy: ST, sign: Opt[ST], selfTy: ST, - inheritedTags: Set[TypeName], - typeMembers: Map[Str, NuMember] - ) extends TypedNuTypeDef(Trt) with TypedNuTermDef + inheritedTags: Set[TypeName] + ) extends TypedNuTypeDef(Trt) with TypedNuTermDef with PolyNuDecl { def decl: NuTypeDef = td def kind: DeclKind = td.kind @@ -203,7 +204,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy, inheritedTags) - def virtualMembers: Map[Str, NuMember] = members ++ typeMembers + def virtualMembers: Map[Str, NuMember] = members ++ tparams.map { + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -213,8 +217,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.map(!_), thisTy), sign.map(f(pol, _)), f(pol, selfTy), - inheritedTags, - typeMembers.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, + inheritedTags ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -224,8 +227,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.contravar, thisTy), sign.map(f(pol, _)), f(pol, selfTy), - inheritedTags, - typeMembers.mapValuesIter(_.mapPolMap(pol)(f)).toMap, + inheritedTags ) } @@ -235,10 +237,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, tags: ST, - inheritedTags: Set[TypeName], - typeMembers: Map[Str, NuMember] + inheritedTags: Set[TypeName] )(val instanceType: ST, // * only meant to be used in `force` and `variances` - ) extends TypedNuTypeDef(Cls) with TypedNuTermDef + ) extends TypedNuTypeDef(Cls) with TypedNuTermDef with PolyNuDecl { def decl: NuTypeDef = td def kind: DeclKind = td.kind @@ -248,7 +249,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def typeSignature: ST = typeSignatureOf(td, level, tparams, params, tags, inheritedTags) /** Includes class-name-coded type parameter fields. */ - lazy val virtualMembers: Map[Str, NuMember] = members ++ typeMembers + lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } // TODO // def checkVariances @@ -304,8 +308,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), f(pol, tags), - inheritedTags, - typeMembers.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, + inheritedTags )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -315,8 +318,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), f(pol, tags), - inheritedTags, - typeMembers.mapValuesIter(_.mapPolMap(pol)(f)).toMap, + inheritedTags )(f(pol, instanceType)) } @@ -667,6 +669,41 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => private lazy val thisTV: TV = freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) + + def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : T = { + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + + val raw = info.asInstanceOf[T] + val rawName = v.name + + if (raw.tparams.sizeCompare(parTargs.size) =/= 0) + err(msg"${if (raw.isInstanceOf[TypedNuTrt]) "trait" else "class"} $rawName expects ${ + raw.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) + + raw.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => + val targ = typeType(targTy) + freshened += _tv -> (targ match { + case tv: TV => + // TODO + println(s"Passing ${_tv} <=< ${tv}") + tv + case _ => + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) + + } + + raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] // FIXME + } def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { @@ -752,66 +789,36 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } // inherit traits - def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember], vMembers: Map[Str, NuMember]) - : (ST, ST, Ls[NuMember], Map[Str, NuMember]) = + def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember]) + : (ST, ST, Ls[NuMember]) = parents match { case (p, v @ Var(trtName), parTargs, args) :: ps => - // if (parTargs.nonEmpty) err(msg"trait type arguments not yet supported", p.toLoc) - if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) ctx.get(trtName) match { case S(lti: LazyTypeInfo) => val info = lti.complete() info match { case rawTrt: TypedNuTrt => - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - - if (rawTrt.tparams.sizeCompare(parTargs.size) =/= 0) - err(msg"trait $trtName expects ${ - rawTrt.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) - - rawTrt.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => - - val targ = typeType(targTy) - - freshened += _tv -> (targ match { - case tv: TypeVarOrRigidVar => tv - case _ => - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - tv - }) - - } - - val trt = rawTrt.freshenAbove(info.level, rigidify = false) - .asInstanceOf[TypedNuTrt] // FIXME + if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) + val trt = refreshGen[TypedNuTrt](info, v , parTargs)// FIXME inherit(ps, superType & trt.thisTy, tags & trt.selfTy, - memberUn(members, trt.members.values.toList), - vMembers ++ trt.typeMembers + memberUn(members, trt.members.values.toList) ) case _ => err(msg"trait can only inherit traits", p.toLoc) - (superType, tags, members, vMembers) + (superType, tags, members) } case _ => err(msg"Could not find definition `${trtName}`", p.toLoc) - (superType, tags, members, vMembers) + (superType, tags, members) } - case Nil => (superType, tags, members, vMembers) + case Nil => (superType, tags, members) } - val (thisType, tags, baseMems, baseVMems) = - inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) + val (thisType, tags, baseMems) = + inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil) // val selfType = tags & sig_ty val selfType = sig_ty @@ -819,12 +826,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val ttu = typeTypingUnit(td.body, topLevel = false) val trtMems = baseMems ++ ttu.entities val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap - val vmems = baseVMems ++ tparams.map { - case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } - TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags, vmems) -> Nil + TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags) -> Nil } case Als => @@ -977,7 +980,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO report non-unit result/statements? // TODO check overriding - case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], trtMem: Ls[NuMember], trtTyMem: Map[Str, NuMember]) + case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], trtMem: Ls[NuMember]) // compute base class and interfaces def computeBaseClass(parents: Ls[ParentSpec], pack: Pack): Pack = // TODO rename @@ -987,11 +990,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(lti: LazyTypeInfo) => val info = lti.complete() info match { - case cls: TypedNuCls => - if (parTargs.nonEmpty) err(msg"class type arguments not yet supported", p.toLoc) - if (pack.bsCls.isDefined) { - err(msg"cannot inherit from more than one base class: ${pack.bsCls.get} and ${parNme}", v.toLoc) - } + case rawCls: TypedNuCls => + // if (parTargs.nonEmpty) err(msg"class type arguments not yet supported", p.toLoc) + if (pack.bsCls.isDefined) + err(msg"cannot inherit from more than one base class: ${ + pack.bsCls.get} and ${parNme}", v.toLoc) + + // val cls = rawCls + val cls = refreshGen[TypedNuCls](info, v, parTargs) if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ @@ -1032,38 +1038,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - - if (rawTrt.tparams.sizeCompare(parTargs.size) =/= 0) - err(msg"trait $parNme expects ${ - rawTrt.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) - - rawTrt.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => - val targ = typeType(targTy) - freshened += _tv -> (targ match { - case tv: TypeVarOrRigidVar => tv - case _ => - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - tv - }) - } - - val trt = rawTrt.freshenAbove(info.level, rigidify = false) - .asInstanceOf[TypedNuTrt] // FIXME + val trt = refreshGen[TypedNuTrt](info, v, parTargs) // FIXME computeBaseClass(ps, pack.copy( - trtMem = memberUn(pack.trtMem, trt.members.values.toList), - trtTyMem = pack.trtTyMem ++ trt.typeMembers) - ) + trtMem = memberUn(pack.trtMem, trt.members.values.toList) + )) case _ => computeBaseClass(ps, pack) } @@ -1073,17 +1052,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => pack } - val Pack(clsMems, _, ifaceMembers, ifaceTmem) = - computeBaseClass(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil, Map.empty)) + val Pack(clsMems, _, ifaceMembers) = + computeBaseClass(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil)) val impltdMems = clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers // TODO type members of parent class - val tyMem = ifaceTmem ++ tparams.map { - case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } ifaceMembers.foreach { m => impltdMems.find(x => x.name == m.name) match { @@ -1108,8 +1083,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TopType, // ifaceAnnot, TopType, // TODO use signature - inheritedTags, - tyMem + inheritedTags )(thisType) -> impltdMems } case Mxn => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index edc8b32d41..e6cbf25e93 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1331,7 +1331,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, _) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), @@ -1341,7 +1341,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, _ /* TODO */) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 8e066950c4..4952190362 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -789,7 +789,6 @@ abstract class TyperHelpers { Typer: Typer => // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ - cls.typeMembers.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.instanceType) case cls: TypedNuTrt => @@ -882,7 +881,6 @@ abstract class TyperHelpers { Typer: Typer => // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil) ++ cls.members.valuesIterator.flatMap(childrenMem) ++ - cls.typeMembers.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.instanceType) } @@ -1174,13 +1172,13 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, tms) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, tms) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 61339c9a6c..af35e85053 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -10,4 +10,11 @@ class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) extends Expr[T] class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr[(S, T)] class Fst[S, T](p: Expr[(S, T)]) extends Expr[S] class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] -//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: ‘T36' was not a type variable +//│ trait Expr[A]() +//│ class LitInt(n: int) +//│ class LitBool(b: bool) +//│ class Add(x: Expr[int], y: Expr[int]) +//│ class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) +//│ class Pair[S, T](a: Expr[S], b: Expr[T]) +//│ class Fst[S, T](p: Expr[(S, T,)]) +//│ class Snd[S, T](p: Expr[(S, T,)]) diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls new file mode 100644 index 0000000000..8f3a85dfe8 --- /dev/null +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -0,0 +1,16 @@ +:NewDefs +:NoJS + +class Room[A](name: string) { + fun foo(x: A) = x +} +//│ class Room[A](name: string) { +//│ fun foo: (x: A,) -> A +//│ } + +class BigRoom extends Room[bool]("big") +//│ class BigRoom() { +//│ fun foo: (x: 'A,) -> 'A +//│ } +//│ where +//│ 'A := bool diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls new file mode 100644 index 0000000000..21e7a38d90 --- /dev/null +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -0,0 +1,51 @@ +:NewDefs +:NoJS + +trait Into[T] { + fun into: T +} +//│ trait Into[T]() { +//│ fun into: T +//│ } + +trait Nat extends Into[int] +//│ trait Nat() { +//│ fun into: int +//│ } + +trait Product[A, B] extends Into[A] { + let pair: (A, B) +} +//│ trait Product[A, B]() { +//│ fun into: A +//│ let pair: (A, B,) +//│ } + +class Int2(pair: (int, int)) extends Product[int, int] { + fun into = pair._1 + pair._2 +} +//│ class Int2(pair: (int, int,)) { +//│ fun into: int +//│ } + +let i2 = Int2((1,2)) +//│ let i2: Int2 + +i2: Product[int, int] +//│ ╔══[ERROR] Type `Int2` does not contain member `Product#A` +//│ ║ l.16: trait Product[A, B] extends Into[A] { +//│ ╙── ^ +//│ Product[int, int] + +i2: Into[int] +//│ ╔══[ERROR] Type `Int2` does not contain member `Into#T` +//│ ║ l.4: trait Into[T] { +//│ ╙── ^ +//│ Into[int] + +i2.pair +//│ (int, int,) + +i2.into +//│ int + diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 0bb3971fd4..4761a8c29d 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -29,9 +29,6 @@ class What1(toString: string) extends Showable :e trait NoShow extends What1("hi") -//│ ╔══[ERROR] trait arguments not yet supported -//│ ║ l.31: trait NoShow extends What1("hi") -//│ ╙── ^^^^^^^^^^^ //│ ╔══[ERROR] trait can only inherit traits //│ ║ l.31: trait NoShow extends What1("hi") //│ ╙── ^^^^^^^^^^^ @@ -44,16 +41,16 @@ class ErrC2 extends Showable { } class ErrC3(toString: string -> string) extends Showable //│ ╔══[ERROR] Member toString is declared in parent trait but not implemented -//│ ║ l.41: class ErrC1 extends Showable +//│ ║ l.38: class ErrC1 extends Showable //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method toString: -//│ ║ l.43: fun toString = 114 +//│ ║ l.40: fun toString = 114 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── integer literal of type `114` is not an instance of type `string` -//│ ║ l.43: fun toString = 114 +//│ ║ l.40: fun toString = 114 //│ ║ ^^^ //│ ╟── but it flows into definition of method toString with expected type `string` -//│ ║ l.43: fun toString = 114 +//│ ║ l.40: fun toString = 114 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun toString: string @@ -62,7 +59,7 @@ class ErrC3(toString: string -> string) extends Showable //│ ║ l.5: fun toString: string //│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in function type: -//│ ║ l.45: class ErrC3(toString: string -> string) extends Showable +//│ ║ l.42: class ErrC3(toString: string -> string) extends Showable //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── type `string -> string` is not an instance of type `string` //│ ╟── Note: constraint arises from type reference: @@ -121,40 +118,40 @@ class Errcity(size: int) extends SizedStadt { fun bar = "hahaha" } //│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.121: fun bar = "hahaha" +//│ ║ l.118: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── string literal of type `"hahaha"` is not a function -//│ ║ l.121: fun bar = "hahaha" +//│ ║ l.118: fun bar = "hahaha" //│ ║ ^^^^^^^^ //│ ╟── but it flows into definition of method bar with expected type `int -> int` -//│ ║ l.121: fun bar = "hahaha" +//│ ║ l.118: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.99: fun bar: int -> int +//│ ║ l.96: fun bar: int -> int //│ ║ ^^^^^^^^^^ //│ ╟── from signature of member bar: -//│ ║ l.99: fun bar: int -> int +//│ ║ l.96: fun bar: int -> int //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member foo is declared in parent trait but not implemented -//│ ║ l.120: class Errcity(size: int) extends SizedStadt { +//│ ║ l.117: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.121: fun bar = "hahaha" +//│ ║ l.118: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.122: } +//│ ║ l.119: } //│ ╙── ^ //│ ╔══[ERROR] Member name is declared in parent trait but not implemented -//│ ║ l.120: class Errcity(size: int) extends SizedStadt { +//│ ║ l.117: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.121: fun bar = "hahaha" +//│ ║ l.118: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.122: } +//│ ║ l.119: } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.120: class Errcity(size: int) extends SizedStadt { +//│ ║ l.117: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^ //│ ╟── type `int` does not match type `1 | 2 | 3` //│ ╟── Note: constraint arises from union type: -//│ ║ l.98: let size: 1 | 2 | 3 +//│ ║ l.95: let size: 1 | 2 | 3 //│ ╙── ^^^^^^^^^ //│ class Errcity(size: int) { //│ fun bar: "hahaha" @@ -213,21 +210,22 @@ class A { fun x: int = 1 } //│ fun x: int //│ } +:e class B extends A { fun x = "A" } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.216: class B extends A { fun x = "A" } +//│ ║ l.214: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── string literal of type `"A"` is not an instance of type `int` -//│ ║ l.216: class B extends A { fun x = "A" } +//│ ║ l.214: class B extends A { fun x = "A" } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `int` -//│ ║ l.216: class B extends A { fun x = "A" } +//│ ║ l.214: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.211: class A { fun x: int = 1 } +//│ ║ l.208: class A { fun x: int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.211: class A { fun x: int = 1 } +//│ ║ l.208: class A { fun x: int = 1 } //│ ╙── ^^^^^^^^^^ //│ class B() { //│ fun x: "A" @@ -240,21 +238,6 @@ class C1[A] { fun a: A = a } // TODO class C2 extends C1[int] { fun a = 1 } -//│ ╔══[ERROR] class type arguments not yet supported -//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } -//│ ╙── ^^ -//│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } -//│ ║ ^^^^^ -//│ ╟── integer literal of type `1` does not match type `A` -//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } -//│ ║ ^ -//│ ╟── but it flows into definition of method a with expected type `A` -//│ ║ l.242: class C2 extends C1[int] { fun a = 1 } -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from definition of method a: -//│ ║ l.236: class C1[A] { fun a: A = a } -//│ ╙── ^^^^^^^^ //│ class C2() { //│ fun a: 1 //│ } @@ -263,7 +246,7 @@ class C2 extends C1[int] { fun a = 1 } // freshen/subst // trait MyTrait[int] { type MyTrait#A = int; fun a: int = a } -trait MyTrait[A] { fun a: A = a } +trait MyTrait[A] { fun a: A } //│ trait MyTrait[A]() { //│ fun a: A //│ } @@ -279,20 +262,20 @@ class C extends MyTrait[int] { fun a = 1 } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.280: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.280: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.280: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.280: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ -//│ ╟── from definition of method a: -//│ ║ l.266: trait MyTrait[A] { fun a: A = a } -//│ ╙── ^^^^^^^^ +//│ ╟── from signature of member a: +//│ ║ l.249: trait MyTrait[A] { fun a: A } +//│ ╙── ^^^^ //│ class C() { //│ fun a: false //│ } diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 9e3df12567..b80fd60b7f 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -553,22 +553,6 @@ class Eh2 extends Bs(true), Ele { fun foo(x) = x && false fun ce(x) = x } -//│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.553: fun foo(x) = x && false -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ?_` is not an instance of type `bool` -//│ ╟── Note: constraint arises from reference: -//│ ║ l.553: fun foo(x) = x && false -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.553: fun foo(x) = x && false -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ?_` -//│ ║ l.553: fun foo(x) = x && false -//│ ║ ^^^^^^^^^^ -//│ ╟── Note: constraint arises from operator application: -//│ ║ l.524: fun foo(x) = x + 1 -//│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: forall 'a. 'a -> 'a //│ fun foo: bool -> bool @@ -579,21 +563,21 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.578: class Eh extends Bs(1) +//│ ║ l.562: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.578: class Eh extends Bs(1) +//│ ║ l.562: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.523: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.579: class Eh1 extends Bs +//│ ║ l.563: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` +//│ ╟── function of type `?a -> ?b` is not an instance of type `int` //│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` @@ -606,7 +590,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.580: class Eh3 extends Bs(false), Test +//│ ║ l.564: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -631,7 +615,7 @@ class Ca(a: int) extends Oth { class Cx(a: 1 | 2, b: bool) extends Ca(a) //│ class Cx(a: 1 | 2, b: bool) { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: 'a -> 'a //│ fun cool: anything -> false //│ fun foo: 1 //│ } @@ -662,7 +646,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.663: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.647: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() @@ -679,11 +663,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.680: class Bc31(baz: bool) extends Bc3 +//│ ║ l.664: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.654: let baz : int +//│ ║ l.638: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -692,18 +676,18 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.692: let foo = true +//│ ║ l.676: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.691: class Bc11 extends Bc1(1) { +//│ ║ l.675: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.692: let foo = true +//│ ║ l.676: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.651: class Bc1(foo: int) +//│ ║ l.635: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -722,14 +706,15 @@ class Der1 extends Base[int] { fun f(x) = x + 1 } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ class Der2[A, B]() { -//│ fun f: forall 'a 'b. ('a, 'b,) -> ('a, 'b,) +//│ fun f: forall 'a 'b. ('b, 'a,) -> ('b, 'a,) //│ } -// TODO trait BInt extends Base[int] { fun f = error } -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A385# +//│ trait BInt() { +//│ fun f: nothing +//│ } trait BPar[T] extends Base[(int,T)] //│ trait BPar[T]() { @@ -742,19 +727,25 @@ let bp: BPar[bool] //│ let bp: BPar[bool] bp: Base[(int, bool)] +//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` +//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ╙── ^ //│ Base[(int, bool,)] bi.f(1) //│ nothing bp.f -//│ ((int, bool,) & 'A) -> ((int, bool,) | 'A) +//│ forall 'T. (int, 'T,) -> (int, 'T,) fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) //│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) fb(bp, false) -//│ (int, bool,) +//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` +//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ╙── ^ +//│ (int, false,) | error class CP extends BPar[int] { fun f(x) = (x._2, x._1) @@ -767,12 +758,15 @@ let cp1 = CP() //│ let cp1: CP fb(cp1, 2) -//│ (int, int,) +//│ ╔══[ERROR] Type `CP` does not contain member `Base#A` +//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ╙── ^ +//│ (int, 2,) | error :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.773: trait BErr1 extends Base +//│ ║ l.767: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -781,38 +775,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.782: class DerBad1 extends Base[int, int] +//│ ║ l.776: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.782: class DerBad1 extends Base[int, int] +//│ ║ l.776: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.792: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: forall 'a 'b. ('a, 'b,) -> ('b, 'a,) @@ -866,19 +860,9 @@ class G1[A](x: A) // TODO class GI(x: int) extends G1[int] -//│ ╔══[ERROR] class type arguments not yet supported -//│ ║ l.868: class GI(x: int) extends G1[int] -//│ ╙── ^^ //│ ╔══[ERROR] class G1 expects 1 parameter(s); got 0 -//│ ║ l.868: class GI(x: int) extends G1[int] +//│ ║ l.862: class GI(x: int) extends G1[int] //│ ╙── ^^ -//│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.868: class GI(x: int) extends G1[int] -//│ ║ ^^^ -//│ ╟── type `int` does not match type `A` -//│ ╟── Note: constraint arises from type parameter: -//│ ║ l.864: class G1[A](x: A) -//│ ╙── ^ //│ class GI(x: int) trait Oz { @@ -891,11 +875,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.892: class Fischl(age: bool) extends Oz +//│ ║ l.876: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.885: let age: int +//│ ║ l.869: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index 660e1ee9bc..bd2b97d4de 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -20,9 +20,10 @@ class B { let a = "hi" } //│ let a: "hi" //│ } +:e class C(a: int) extends B //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.23: class C(a: int) extends B +//│ ║ l.24: class C(a: int) extends B //│ ║ ^^^ //│ ╟── type `int` does not match type `"hi"` //│ ╟── Note: constraint arises from string literal: From 34c2c4723ebf2de06eb625afb29db87e8176bb06 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 28 Apr 2023 13:20:02 +0800 Subject: [PATCH 266/498] rename computeBaseClass --- .../src/main/scala/mlscript/NuTypeDefs.scala | 17 ++-- .../test/diff/nu/GenericClassInheritance.mls | 2 - shared/src/test/diff/nu/InterfaceMono.mls | 22 +++-- shared/src/test/diff/nu/Interfaces.mls | 85 ++++++++++++------- 4 files changed, 80 insertions(+), 46 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index ee5175ee37..6f8bb75497 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -983,7 +983,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], trtMem: Ls[NuMember]) // compute base class and interfaces - def computeBaseClass(parents: Ls[ParentSpec], pack: Pack): Pack = // TODO rename + def computeBaseClassTrait(parents: Ls[ParentSpec], pack: Pack): Pack = parents match { case (p, v @ Var(parNme), parTargs, parArgs) :: ps => ctx.get(parNme) match { @@ -996,8 +996,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"cannot inherit from more than one base class: ${ pack.bsCls.get} and ${parNme}", v.toLoc) - // val cls = rawCls - val cls = refreshGen[TypedNuCls](info, v, parTargs) + val cls = rawCls + // TODO: refreshing breaks overriding check + // val cls = refreshGen[TypedNuCls](info, v, parTargs) if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ @@ -1034,26 +1035,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - computeBaseClass(ps, pack.copy(clsMem = res, bsCls = S(parNme))) + computeBaseClassTrait(ps, pack.copy(clsMem = res, bsCls = S(parNme))) case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) val trt = refreshGen[TypedNuTrt](info, v, parTargs) // FIXME - computeBaseClass(ps, pack.copy( + computeBaseClassTrait(ps, pack.copy( trtMem = memberUn(pack.trtMem, trt.members.values.toList) )) - case _ => computeBaseClass(ps, pack) + case _ => computeBaseClassTrait(ps, pack) } case _ => - computeBaseClass(ps, pack) + computeBaseClassTrait(ps, pack) } case Nil => pack } val Pack(clsMems, _, ifaceMembers) = - computeBaseClass(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil)) + computeBaseClassTrait(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil)) val impltdMems = clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 8f3a85dfe8..953fc8481b 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -12,5 +12,3 @@ class BigRoom extends Room[bool]("big") //│ class BigRoom() { //│ fun foo: (x: 'A,) -> 'A //│ } -//│ where -//│ 'A := bool diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 4761a8c29d..c08281dad2 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -238,6 +238,18 @@ class C1[A] { fun a: A = a } // TODO class C2 extends C1[int] { fun a = 1 } +//│ ╔══[ERROR] Type mismatch in definition of method a: +//│ ║ l.240: class C2 extends C1[int] { fun a = 1 } +//│ ║ ^^^^^ +//│ ╟── integer literal of type `1` does not match type `A` +//│ ║ l.240: class C2 extends C1[int] { fun a = 1 } +//│ ║ ^ +//│ ╟── but it flows into definition of method a with expected type `A` +//│ ║ l.240: class C2 extends C1[int] { fun a = 1 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from definition of method a: +//│ ║ l.234: class C1[A] { fun a: A = a } +//│ ╙── ^^^^^^^^ //│ class C2() { //│ fun a: 1 //│ } @@ -262,19 +274,19 @@ class C extends MyTrait[int] { fun a = 1 } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.275: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.275: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.275: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.275: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ //│ ╟── from signature of member a: -//│ ║ l.249: trait MyTrait[A] { fun a: A } +//│ ║ l.261: trait MyTrait[A] { fun a: A } //│ ╙── ^^^^ //│ class C() { //│ fun a: false diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index b80fd60b7f..2804c68f00 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -553,6 +553,22 @@ class Eh2 extends Bs(true), Ele { fun foo(x) = x && false fun ce(x) = x } +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.553: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `int & ?_` is not an instance of type `bool` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.553: fun foo(x) = x && false +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.553: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── operator application of type `bool` does not match type `int | ?_` +//│ ║ l.553: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from operator application: +//│ ║ l.524: fun foo(x) = x + 1 +//│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: forall 'a. 'a -> 'a //│ fun foo: bool -> bool @@ -563,21 +579,21 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.562: class Eh extends Bs(1) +//│ ║ l.578: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.562: class Eh extends Bs(1) +//│ ║ l.578: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.523: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.563: class Eh1 extends Bs +//│ ║ l.579: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> ?b` is not an instance of type `int` +//│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` //│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` @@ -590,7 +606,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.564: class Eh3 extends Bs(false), Test +//│ ║ l.580: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -615,7 +631,7 @@ class Ca(a: int) extends Oth { class Cx(a: 1 | 2, b: bool) extends Ca(a) //│ class Cx(a: 1 | 2, b: bool) { -//│ fun bar: 'a -> 'a +//│ fun bar: forall 'a. 'a -> 'a //│ fun cool: anything -> false //│ fun foo: 1 //│ } @@ -646,7 +662,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.647: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.663: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() @@ -663,11 +679,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.664: class Bc31(baz: bool) extends Bc3 +//│ ║ l.680: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.638: let baz : int +//│ ║ l.654: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -676,18 +692,18 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.676: let foo = true +//│ ║ l.692: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.675: class Bc11 extends Bc1(1) { +//│ ║ l.691: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.676: let foo = true +//│ ║ l.692: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.635: class Bc1(foo: int) +//│ ║ l.651: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -706,7 +722,7 @@ class Der1 extends Base[int] { fun f(x) = x + 1 } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ class Der2[A, B]() { -//│ fun f: forall 'a 'b. ('b, 'a,) -> ('b, 'a,) +//│ fun f: forall 'a 'b. ('a, 'b,) -> ('a, 'b,) //│ } trait BInt extends Base[int] { @@ -728,7 +744,7 @@ let bp: BPar[bool] bp: Base[(int, bool)] //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ║ l.713: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ Base[(int, bool,)] @@ -743,7 +759,7 @@ fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) fb(bp, false) //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ║ l.713: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ (int, false,) | error @@ -759,14 +775,14 @@ let cp1 = CP() fb(cp1, 2) //│ ╔══[ERROR] Type `CP` does not contain member `Base#A` -//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ║ l.713: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ (int, 2,) | error :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.767: trait BErr1 extends Base +//│ ║ l.783: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -775,38 +791,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.776: class DerBad1 extends Base[int, int] +//│ ║ l.792: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.776: class DerBad1 extends Base[int, int] +//│ ║ l.792: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: forall 'a 'b. ('a, 'b,) -> ('b, 'a,) @@ -861,8 +877,15 @@ class G1[A](x: A) // TODO class GI(x: int) extends G1[int] //│ ╔══[ERROR] class G1 expects 1 parameter(s); got 0 -//│ ║ l.862: class GI(x: int) extends G1[int] +//│ ║ l.878: class GI(x: int) extends G1[int] //│ ╙── ^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.878: class GI(x: int) extends G1[int] +//│ ║ ^^^ +//│ ╟── type `int` does not match type `A` +//│ ╟── Note: constraint arises from type parameter: +//│ ║ l.874: class G1[A](x: A) +//│ ╙── ^ //│ class GI(x: int) trait Oz { @@ -875,11 +898,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.876: class Fischl(age: bool) extends Oz +//│ ║ l.899: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.869: let age: int +//│ ║ l.892: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) From 70783db6106d1ba61bdb3520e98cfef248490544 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 28 Apr 2023 13:56:50 +0800 Subject: [PATCH 267/498] WIP: broken overriding check of parent class --- .../src/main/scala/mlscript/NuTypeDefs.scala | 46 +++---- .../test/diff/nu/GenericClassInheritance.mls | 31 +++++ shared/src/test/diff/nu/InterfaceGeneric.mls | 12 +- shared/src/test/diff/nu/InterfaceMono.mls | 22 +--- shared/src/test/diff/nu/Interfaces.mls | 115 ++++++++---------- 5 files changed, 110 insertions(+), 116 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 6f8bb75497..ab73281c27 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -980,7 +980,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO report non-unit result/statements? // TODO check overriding - case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], trtMem: Ls[NuMember]) + case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], bsMem: Ls[NuMember], trtMem: Ls[NuMember]) // compute base class and interfaces def computeBaseClassTrait(parents: Ls[ParentSpec], pack: Pack): Pack = @@ -996,9 +996,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"cannot inherit from more than one base class: ${ pack.bsCls.get} and ${parNme}", v.toLoc) - val cls = rawCls - // TODO: refreshing breaks overriding check - // val cls = refreshGen[TypedNuCls](info, v, parTargs) + val cls = refreshGen[TypedNuCls](info, v, parTargs) if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ @@ -1012,30 +1010,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } val numem = paramMems ++ cls.members.values.toList + val res = pack.clsMem ++ numem.flatMap { m => - lazy val parSign = m match { - case nt: TypedNuTermDef => nt.typeSignature - case np: NuParam => np.typeSignature - case _ => ??? // probably no other cases - } pack.clsMem.find(x => x.name == m.name) match { - case S(mem: TypedNuTermDef) => - val memSign = mem.typeSignature - println(s"checking overriding: $memSign <: $parSign") - implicit val prov: TP = memSign.prov - constrain(memSign, parSign) - Nil - case S(pm: NuParam) => - val pmSign = pm.typeSignature - println(s"checking overriding: $pmSign <: $parSign") - implicit val prov: TP = pmSign.prov - constrain(pmSign, parSign) - Nil + case S(mem: TypedNuTermDef) => Nil + case S(pm: NuParam) => Nil case _ => m :: Nil } } - computeBaseClassTrait(ps, pack.copy(clsMem = res, bsCls = S(parNme))) + computeBaseClassTrait(ps, pack.copy(clsMem = res, bsCls = S(parNme), bsMem = cls.members.values.toList)) case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) @@ -1053,25 +1037,29 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => pack } - val Pack(clsMems, _, ifaceMembers) = - computeBaseClassTrait(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil)) + val Pack(clsMems, _, bsMembers, ifaceMembers) = + computeBaseClassTrait(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil, Nil)) val impltdMems = clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers - // TODO type members of parent class - - ifaceMembers.foreach { m => + // TODO: overriding check of parent class doesn't seem working + (bsMembers ++ ifaceMembers).foreach { m => + lazy val parSign = m match { + case nt: TypedNuTermDef => nt.typeSignature + case np: NuParam => np.typeSignature + case _ => ??? // probably no other cases + } impltdMems.find(x => x.name == m.name) match { case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature implicit val prov: TP = memSign.prov // println(s"checking interface mamber `${m.name}`") - constrain(memSign, m.asInstanceOf[TypedNuTermDef].typeSignature) + constrain(memSign, parSign) case S(pm: NuParam) => val pmSign = pm.typeSignature implicit val prov: TP = pmSign.prov - constrain(pmSign, m.asInstanceOf[TypedNuTermDef].typeSignature) + constrain(pmSign, parSign) case S(_) => Nil case N => err(msg"Member ${m.name} is declared in parent trait but not implemented", td.toLoc) diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 953fc8481b..0b001d2239 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -12,3 +12,34 @@ class BigRoom extends Room[bool]("big") //│ class BigRoom() { //│ fun foo: (x: 'A,) -> 'A //│ } +//│ where +//│ 'A := bool + +:e +class WrongRoom extends Room[bool]("wrong") { + fun foo(x) = x + 1 +} +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.20: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type `bool` is not an instance of type `int` +//│ ║ l.19: class WrongRoom extends Room[bool]("wrong") { +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.20: fun foo(x) = x + 1 +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.20: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── operator application of type `int` is not an instance of type `bool` +//│ ║ l.20: fun foo(x) = x + 1 +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.19: class WrongRoom extends Room[bool]("wrong") { +//│ ║ ^^^^ +//│ ╟── from reference: +//│ ║ l.5: fun foo(x: A) = x +//│ ╙── ^ +//│ class WrongRoom() { +//│ fun foo: int -> int +//│ } diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index 21e7a38d90..e71e73249a 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -21,24 +21,24 @@ trait Product[A, B] extends Into[A] { //│ let pair: (A, B,) //│ } -class Int2(pair: (int, int)) extends Product[int, int] { +class TwoInts(pair: (int, int)) extends Product[int, int] { fun into = pair._1 + pair._2 } -//│ class Int2(pair: (int, int,)) { +//│ class TwoInts(pair: (int, int,)) { //│ fun into: int //│ } -let i2 = Int2((1,2)) -//│ let i2: Int2 +let i2 = TwoInts((1,2)) +//│ let i2: TwoInts i2: Product[int, int] -//│ ╔══[ERROR] Type `Int2` does not contain member `Product#A` +//│ ╔══[ERROR] Type `TwoInts` does not contain member `Product#A` //│ ║ l.16: trait Product[A, B] extends Into[A] { //│ ╙── ^ //│ Product[int, int] i2: Into[int] -//│ ╔══[ERROR] Type `Int2` does not contain member `Into#T` +//│ ╔══[ERROR] Type `TwoInts` does not contain member `Into#T` //│ ║ l.4: trait Into[T] { //│ ╙── ^ //│ Into[int] diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index c08281dad2..4761a8c29d 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -238,18 +238,6 @@ class C1[A] { fun a: A = a } // TODO class C2 extends C1[int] { fun a = 1 } -//│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.240: class C2 extends C1[int] { fun a = 1 } -//│ ║ ^^^^^ -//│ ╟── integer literal of type `1` does not match type `A` -//│ ║ l.240: class C2 extends C1[int] { fun a = 1 } -//│ ║ ^ -//│ ╟── but it flows into definition of method a with expected type `A` -//│ ║ l.240: class C2 extends C1[int] { fun a = 1 } -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from definition of method a: -//│ ║ l.234: class C1[A] { fun a: A = a } -//│ ╙── ^^^^^^^^ //│ class C2() { //│ fun a: 1 //│ } @@ -274,19 +262,19 @@ class C extends MyTrait[int] { fun a = 1 } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.275: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.275: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.275: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.275: class C extends MyTrait[int] { fun a = false } +//│ ║ l.263: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ //│ ╟── from signature of member a: -//│ ║ l.261: trait MyTrait[A] { fun a: A } +//│ ║ l.249: trait MyTrait[A] { fun a: A } //│ ╙── ^^^^ //│ class C() { //│ fun a: false diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 2804c68f00..efc5b8f906 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -553,22 +553,6 @@ class Eh2 extends Bs(true), Ele { fun foo(x) = x && false fun ce(x) = x } -//│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.553: fun foo(x) = x && false -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ?_` is not an instance of type `bool` -//│ ╟── Note: constraint arises from reference: -//│ ║ l.553: fun foo(x) = x && false -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.553: fun foo(x) = x && false -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ?_` -//│ ║ l.553: fun foo(x) = x && false -//│ ║ ^^^^^^^^^^ -//│ ╟── Note: constraint arises from operator application: -//│ ║ l.524: fun foo(x) = x + 1 -//│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: forall 'a. 'a -> 'a //│ fun foo: bool -> bool @@ -579,21 +563,28 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.578: class Eh extends Bs(1) +//│ ║ l.562: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.578: class Eh extends Bs(1) +//│ ║ l.562: class Eh extends Bs(1) +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.523: class Bs(a: bool) { +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in integer literal: +//│ ║ l.562: class Eh extends Bs(1) //│ ║ ^ +//│ ╟── integer literal of type `1` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: //│ ║ l.523: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.579: class Eh1 extends Bs +//│ ║ l.563: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` +//│ ╟── function of type `?a -> ?b` is not an instance of type `int` //│ ║ l.524: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` @@ -606,7 +597,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.580: class Eh3 extends Bs(false), Test +//│ ║ l.564: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -631,7 +622,7 @@ class Ca(a: int) extends Oth { class Cx(a: 1 | 2, b: bool) extends Ca(a) //│ class Cx(a: 1 | 2, b: bool) { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: 'a -> 'a //│ fun cool: anything -> false //│ fun foo: 1 //│ } @@ -662,7 +653,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.663: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.654: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() @@ -679,11 +670,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.680: class Bc31(baz: bool) extends Bc3 +//│ ║ l.671: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.654: let baz : int +//│ ║ l.645: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -692,18 +683,11 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.692: let foo = true -//│ ║ ^^^^ -//│ ╟── reference of type `true` does not match type `1` -//│ ╟── Note: constraint arises from integer literal: -//│ ║ l.691: class Bc11 extends Bc1(1) { -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.692: let foo = true +//│ ║ l.683: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.651: class Bc1(foo: int) +//│ ║ l.642: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -722,7 +706,7 @@ class Der1 extends Base[int] { fun f(x) = x + 1 } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ class Der2[A, B]() { -//│ fun f: forall 'a 'b. ('a, 'b,) -> ('a, 'b,) +//│ fun f: forall 'a 'b. ('b, 'a,) -> ('b, 'a,) //│ } trait BInt extends Base[int] { @@ -744,7 +728,7 @@ let bp: BPar[bool] bp: Base[(int, bool)] //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.713: trait Base[A] { fun f: A -> A } +//│ ║ l.697: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ Base[(int, bool,)] @@ -759,7 +743,7 @@ fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) fb(bp, false) //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.713: trait Base[A] { fun f: A -> A } +//│ ║ l.697: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ (int, false,) | error @@ -775,14 +759,14 @@ let cp1 = CP() fb(cp1, 2) //│ ╔══[ERROR] Type `CP` does not contain member `Base#A` -//│ ║ l.713: trait Base[A] { fun f: A -> A } +//│ ║ l.697: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ (int, 2,) | error :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.783: trait BErr1 extends Base +//│ ║ l.767: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -791,38 +775,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.792: class DerBad1 extends Base[int, int] +//│ ║ l.776: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.792: class DerBad1 extends Base[int, int] +//│ ║ l.776: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.802: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: forall 'a 'b. ('a, 'b,) -> ('b, 'a,) @@ -874,18 +858,7 @@ class Ctb extends Tb { class G1[A](x: A) //│ class G1[A](x: A) -// TODO -class GI(x: int) extends G1[int] -//│ ╔══[ERROR] class G1 expects 1 parameter(s); got 0 -//│ ║ l.878: class GI(x: int) extends G1[int] -//│ ╙── ^^ -//│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.878: class GI(x: int) extends G1[int] -//│ ║ ^^^ -//│ ╟── type `int` does not match type `A` -//│ ╟── Note: constraint arises from type parameter: -//│ ║ l.874: class G1[A](x: A) -//│ ╙── ^ +class GI(x: int) extends G1[int](x) //│ class GI(x: int) trait Oz { @@ -898,14 +871,28 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.899: class Fischl(age: bool) extends Oz +//│ ║ l.872: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.892: let age: int +//│ ║ l.865: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) -// TODO class Klee(age: 1 | 2 | 3) extends Oz //│ class Klee(age: 1 | 2 | 3) + +class Fate { + fun foo(x) = x + 1 +} +//│ class Fate() { +//│ fun foo: int -> int +//│ } + +:e +class Go extends Fate { + fun foo(x) = x && true +} +//│ class Go() { +//│ fun foo: bool -> bool +//│ } From d168eb5768d8ca6d7a0b1b354686405ed4ecd02b Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sun, 30 Apr 2023 16:16:14 +0800 Subject: [PATCH 268/498] Add some examples of unhygienic let bindings --- shared/src/test/diff/ucs/HygienicBindings.mls | 164 ++++++++++++++++++ shared/src/test/diff/ucs/Wildcard.mls | 26 +++ 2 files changed, 190 insertions(+) create mode 100644 shared/src/test/diff/ucs/HygienicBindings.mls diff --git a/shared/src/test/diff/ucs/HygienicBindings.mls b/shared/src/test/diff/ucs/HygienicBindings.mls new file mode 100644 index 0000000000..6684e39d20 --- /dev/null +++ b/shared/src/test/diff/ucs/HygienicBindings.mls @@ -0,0 +1,164 @@ +:NewDefs + +type Option[out T] = None | Some[T] +module None +class Some[out T](value: T) +//│ type Option[T] = Some[T] | None +//│ module None() +//│ class Some[T](value: T) + +type Either[A, B] = Left[A] | Right[B] +class Left[A](leftValue: A) +class Right[B](rightValue: B) +//│ type Either[A, B] = Left[A] | Right[B] +//│ class Left[A](leftValue: A) +//│ class Right[B](rightValue: B) + +type List[out A] = Nil | Cons[A] +module Nil +class Cons[out A](head: A, tail: List[A]) +//│ type List[A] = Cons[A] | Nil +//│ module Nil() +//│ class Cons[A](head: A, tail: List[A]) + +fun h0(a) = + if + a is Some(Left(y)) then y + a is Some(Right(z)) then z + a is None then 0 +//│ fun h0: forall 'leftValue. (None | Some[Left['leftValue] | Right['leftValue]]) -> (0 | 'leftValue) + +// FIXME: Precise scrutinee identification (easy) +// This seems fine. But the subtrees are not merged. +fun h1(a) = + if + a is Some(x) and x is Left(y) then y + a is Some(y) and y is Right(z) then z + a is None then 0 +//│ fun h1: forall 'leftValue. (None | Some[Right['leftValue]]) -> (0 | 'leftValue) + +// FIXME: This is the desugared version of the test case above. +fun h1'(a) = + if a is + Some then + let x = a.value + let y = a.value + if x is + Left then + let y = x.leftValue + y + _ then + if y is + Right then + let z = y.rightValue + z + None then 0 +//│ fun h1': forall 'leftValue. (None | Some[Right['leftValue]]) -> (0 | 'leftValue) + +// FIXME This seems fine but the desugared term does not merge the cases. +// See the example below. +fun h1''(a) = + if + a is Some(x) and x is Left(y) then y + a is Some(x) and x is Right(z) then z + a is None then 0 +//│ fun h1'': forall 'leftValue. (None | Some[Left['leftValue] | Right['leftValue]]) -> (0 | 'leftValue) + +// FIXME +h1(Some(Left(0))) +h1'(Some(Left(0))) +h1''(Some(Left(0))) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.68: h1(Some(Left(0))) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Left[?A]` is not an instance of type `Right` +//│ ║ l.68: h1(Some(Left(0))) +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from class pattern: +//│ ║ l.36: a is Some(y) and y is Right(z) then z +//│ ║ ^^^^^ +//│ ╟── from reference: +//│ ║ l.35: a is Some(x) and x is Left(y) then y +//│ ║ ^ +//│ ╟── Note: type parameter T is defined at: +//│ ║ l.5: class Some[out T](value: T) +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.69: h1'(Some(Left(0))) +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Left[?A]` is not an instance of type `Right` +//│ ║ l.69: h1'(Some(Left(0))) +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from class pattern: +//│ ║ l.52: Right then +//│ ║ ^^^^^ +//│ ╟── from field selection: +//│ ║ l.45: let y = a.value +//│ ║ ^^^^^^^ +//│ ╟── Note: type parameter T is defined at: +//│ ║ l.5: class Some[out T](value: T) +//│ ╙── ^ +//│ 0 +//│ res +//│ = 0 +//│ res +//│ = 0 +//│ res +//│ = 0 + +// FIXME: Precise scrutinee identification (hard) +fun h2(a) = + if + a is Some(x) and x is x' and x' is Left(y) then y + a is Some(y) and + let y' = y + y' is Right(z) then z + a is None then 0 +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.114: let y' = y +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.114: let y' = y +//│ ╙── ^ +//│ fun h2: forall 'leftValue. (None | Some[Left['leftValue] | ~Left[anything]]) -> (0 | error | 'leftValue) +//│ Code generation encountered an error: +//│ unresolved symbol y + +// FIXME +fun h3(x, y, f, p) = + if x is + _ and f(x) is y and p(x) then y + None then y + _ then "anyway" +h3("anything", "not me", _ => "should be me", _ => true) +h3(None, "should be me", _ => "not me", _ => false) +h3("anything", "anything", _ => "not me", _ => false) +//│ fun h3: forall 'a 'b. (None | 'a & ~#None, 'b, (None | 'a) -> anything, (None | 'a) -> anything,) -> ("anyway" | 'b) +//│ "anything" | "anyway" +//│ res +//│ = [Function: h3] +//│ res +//│ = 'not me' +//│ res +//│ = 'should be me' + +// FIXME +fun h4(x, y, p) = + if x is + y and p(x) then y + None then y + _ then "default" +h4("should be me", "not me", _ => true) // WRONG! +h4(None, "not me", _ => true) // WRONG! +h4(None, "should be me", _ => false) +h4("anything", "not me", _ => false) +//│ fun h4: forall 'a 'b. (None | 'a & ~#None, 'b, (None | 'a) -> anything,) -> ("default" | 'b) +//│ "default" | "not me" +//│ res +//│ = [Function: h4] +//│ res +//│ = 'not me' +//│ res +//│ = 'not me' +//│ res +//│ = 'should be me' diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index 6b3b38b8f7..15cc780cab 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -235,3 +235,29 @@ w6("42", "42") //│ = 0 //│ res //│ = '42' + +// FIXME +// Should report warnings. +fun w7(x, f) = + if x is + _ and f(x) is + Some(v) then v + None then x + Left(x) then x + 1 + Right(x) then x + 2 +//│ fun w7: forall 'a 'value. (Left[int] | Right[int] | 'a & ~#Left & ~#Right, 'a -> (None | Some['value]),) -> (int | 'value | 'a) + +// The results are wrong: +w7(Left(99), _ => Some(0)) // => 0 +w7(Left(99), _ => None) // => Left(99) +w7(Right(99), _ => Some(0)) // => 0 +w7(Right(99), _ => None) // => Right(99) +//│ int +//│ res +//│ = 100 +//│ res +//│ = 100 +//│ res +//│ = 101 +//│ res +//│ = 101 From 2ff4c7b86f931c96a7808bf7622a9fa1c0493ffa Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Fri, 5 May 2023 14:58:51 +0800 Subject: [PATCH 269/498] Fix `undefined` is a keyword --- shared/src/test/diff/ucs/zipWith.mls | 127 ++++++--------------------- 1 file changed, 26 insertions(+), 101 deletions(-) diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index 6f02146f8a..61edd35e1b 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -3,20 +3,17 @@ :escape -let undefined: nothing -//│ ╔══[PARSE ERROR] Expected a function name; found 'undefined' keyword instead -//│ ║ l.6: let undefined: nothing -//│ ╙── ^^^^^^^^^ -//│ let : nothing -//│ +let nothing: nothing +//│ let nothing: nothing +//│ nothing //│ = module None { - fun value = undefined + fun value = nothing } class Some[out A](value: A) //│ module None() { -//│ fun value: undefined +//│ fun value: nothing //│ } //│ class Some[A](value: A) @@ -49,29 +46,29 @@ fun zipWith_wrong(f, xs, ys) = then Some(Cons(f(x, y), tail)) else None //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application followed by newline instead -//│ ║ l.46: if xs is Cons(x, xs) +//│ ║ l.43: if xs is Cons(x, xs) //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.47: and ys is Cons(y, ys) +//│ ║ l.44: and ys is Cons(y, ys) //│ ║ ^^ //│ ╟── Note: 'if' expression started here: -//│ ║ l.46: if xs is Cons(x, xs) +//│ ║ l.43: if xs is Cons(x, xs) //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.47: and ys is Cons(y, ys) +//│ ║ l.44: and ys is Cons(y, ys) //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.48: and zipWith_wrong(f, xs, ys) is Some(tail) +//│ ║ l.45: and zipWith_wrong(f, xs, ys) is Some(tail) //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.46: if xs is Cons(x, xs) +//│ ║ l.43: if xs is Cons(x, xs) //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.47: and ys is Cons(y, ys) +//│ ║ l.44: and ys is Cons(y, ys) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.48: and zipWith_wrong(f, xs, ys) is Some(tail) +//│ ║ l.45: and zipWith_wrong(f, xs, ys) is Some(tail) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.49: then Some(Cons(f(x, y), tail)) +//│ ║ l.46: then Some(Cons(f(x, y), tail)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.50: else None +//│ ║ l.47: else None //│ ╙── ^^^^^^^^^^^ //│ fun zipWith_wrong: (anything, anything, anything,) -> undefined @@ -83,9 +80,9 @@ fun zipWith_wrong(f, xs, ys) = and zipWith_wrong(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) else None //│ ╔══[ERROR] illegal pattern -//│ ║ l.81: if xs is Cons(x, xs) +//│ ║ l.78: if xs is Cons(x, xs) //│ ║ ^^^^^^^^^^^ -//│ ║ l.82: and ys is Cons(y, ys) +//│ ║ l.79: and ys is Cons(y, ys) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun zipWith_wrong: (anything, anything, anything,) -> error //│ Code generation encountered an error: @@ -114,16 +111,7 @@ fun zipWith(f, xs, ys) = //│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.116: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.116: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ = [ [ 0, '0' ], [] ] @@ -136,16 +124,7 @@ fun zipWith(f, xs, ys) = //│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.138: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.138: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ = [ [ 0, '0' ], [] ] @@ -157,16 +136,7 @@ fun zipWith(f, xs, ys) = //│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.159: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.159: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ = [ [ 0, '0' ], [] ] @@ -180,16 +150,7 @@ fun zipWith(f, xs, ys) = //│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.182: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.182: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ = [ [ 0, '0' ], [] ] @@ -208,60 +169,24 @@ fun zipWith(f, xs, ys) = //│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Nil, Cons['head0] | Nil,) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Nil, Nil).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.210: zipWith(pairup, Nil, Nil).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.210: zipWith(pairup, Nil, Nil).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ = [] :re zipWith(pairup, Nil, Cons(0, Nil)).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.225: zipWith(pairup, Nil, Cons(0, Nil)).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.225: zipWith(pairup, Nil, Cons(0, Nil)).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ Runtime error: -//│ TypeError: Cannot read properties of undefined (reading 'toArray') +//│ ReferenceError: nothing is not defined zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.240: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.240: zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ = [ [ 0, '0' ], [] ] zipWith(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))).value.toArray -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.254: zipWith(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))).value.toArray -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` does not have field 'toArray' -//│ ║ l.15: fun value = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `{toArray: ?toArray}` -//│ ║ l.254: zipWith(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))).value.toArray -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Array[anything] | error +//│ Array[anything] //│ res //│ = [ [ 0, '0' ], [ [ 1, '1' ], [] ] ] From 7a6d03cc5f31f01d77a7fb388fbc80b2c5cb7330 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Sat, 6 May 2023 21:19:33 +0800 Subject: [PATCH 270/498] add tests for inheritance --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 2 + shared/src/test/diff/nu/Interfaces.mls | 53 +++++++++++++------ 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index ab73281c27..89b9e97715 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1054,7 +1054,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature implicit val prov: TP = memSign.prov - // println(s"checking interface mamber `${m.name}`") + println(s"checking overriding `${m.name}`") constrain(memSign, parSign) case S(pm: NuParam) => val pmSign = pm.typeSignature diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index e71e73249a..34666e34d3 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -31,12 +31,14 @@ class TwoInts(pair: (int, int)) extends Product[int, int] { let i2 = TwoInts((1,2)) //│ let i2: TwoInts +// FIXME i2: Product[int, int] //│ ╔══[ERROR] Type `TwoInts` does not contain member `Product#A` //│ ║ l.16: trait Product[A, B] extends Into[A] { //│ ╙── ^ //│ Product[int, int] +// FIXME i2: Into[int] //│ ╔══[ERROR] Type `TwoInts` does not contain member `Into#T` //│ ║ l.4: trait Into[T] { diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index efc5b8f906..024aecc2b7 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -548,7 +548,7 @@ ih1: Bs ih1.a //│ bool -:e +// FIXME class Eh2 extends Bs(true), Ele { fun foo(x) = x && false fun ce(x) = x @@ -726,6 +726,8 @@ let bp: BPar[bool] //│ let bi: BInt //│ let bp: BPar[bool] + +// FIXME bp: Base[(int, bool)] //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` //│ ║ l.697: trait Base[A] { fun f: A -> A } @@ -741,6 +743,7 @@ bp.f fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) //│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) +// FIXME fb(bp, false) //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` //│ ║ l.697: trait Base[A] { fun f: A -> A } @@ -757,6 +760,7 @@ class CP extends BPar[int] { let cp1 = CP() //│ let cp1: CP +// FIXME fb(cp1, 2) //│ ╔══[ERROR] Type `CP` does not contain member `Base#A` //│ ║ l.697: trait Base[A] { fun f: A -> A } @@ -766,7 +770,7 @@ fb(cp1, 2) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.767: trait BErr1 extends Base +//│ ║ l.771: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -775,38 +779,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.776: class DerBad1 extends Base[int, int] +//│ ║ l.780: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.776: class DerBad1 extends Base[int, int] +//│ ║ l.780: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.786: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: forall 'a 'b. ('a, 'b,) -> ('b, 'a,) @@ -871,11 +875,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.872: class Fischl(age: bool) extends Oz +//│ ║ l.876: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.865: let age: int +//│ ║ l.869: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -889,10 +893,29 @@ class Fate { //│ fun foo: int -> int //│ } -:e +// FIXME class Go extends Fate { fun foo(x) = x && true } //│ class Go() { //│ fun foo: bool -> bool //│ } + +class Ha { let x: int = 1 } +//│ class Ha() { +//│ let x: int +//│ } + +class Haha(x: 1 | 2) extends Ha +//│ class Haha(x: 1 | 2) + +:e +class Ohhh(x: bool) extends Ha +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.913: class Ohhh(x: bool) extends Ha +//│ ║ ^^^^ +//│ ╟── type `bool` is not an instance of `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.904: class Ha { let x: int = 1 } +//│ ╙── ^^^ +//│ class Ohhh(x: bool) From fabe0d3cd31d42bc5eb08f243e7fb8e3c2224253 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 8 May 2023 16:06:06 +0800 Subject: [PATCH 271/498] Add abstract keyword --- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 9 +++++++-- shared/src/main/scala/mlscript/Typer.scala | 7 ++++--- shared/src/main/scala/mlscript/helpers.scala | 2 ++ shared/src/main/scala/mlscript/syntax.scala | 3 ++- shared/src/test/diff/nu/Abstract.mls | 19 +++++++++++++++++++ 6 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 shared/src/test/diff/nu/Abstract.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 1fce939aa9..ea52c54eca 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -282,6 +282,7 @@ object NewLexer { "out", "null", "undefined", + "abstract" ) def printToken(tl: TokLoc): Str = tl match { diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 579084badb..8d1c4b87ed 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -276,6 +276,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D consume yeetSpaces go(acc.copy(acc.mods + ("declare" -> l0))) + case (KEYWORD("abstract"), l0) :: c => + consume + yeetSpaces + go(acc.copy(acc.mods + ("abstract" -> l0))) case _ if acc.mods.isEmpty => acc case (KEYWORD("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module" | "fun" | "val"), l0) :: _ => acc @@ -300,7 +304,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c) => consume val (isDecl, mods2) = mods.handle("declare") - mods2.done + val (isAbs, mods3) = mods2.handle("abstract") + mods3.done val kind = k match { case "class" => Cls case "trait" => Trt @@ -370,7 +375,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => Nil } val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body)(isDecl) + val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body)(isDecl, isAbs) R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "val" | "let")), l0) :: c) => // TODO support rec? diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 493d518d41..66e81028a4 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1311,7 +1311,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => - NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))(td.declareLoc) + NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))( + td.declareLoc, td.abstractLoc) } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => ectx(tparams) |> { implicit ectx => @@ -1321,7 +1322,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc) + mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) } case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => ectx(tparams) |> { implicit ectx => @@ -1331,7 +1332,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc) + mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) } case tf @ TypedNuFun(level, fd, bodyTy) => NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 02cd4c9f00..9ef052a97b 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -388,7 +388,9 @@ trait NuDeclImpl extends Located { self: NuDecl => val body: Located def kind: DeclKind val declareLoc: Opt[Loc] + val abstractLoc: Opt[Loc] def isDecl: Bool = declareLoc.nonEmpty + def isAbstract: Bool = abstractLoc.nonEmpty def declStr: Str = if (isDecl) "declare " else "" val nameVar: Var = self match { case td: NuTypeDef => td.nme.toVar diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index fba2e39ded..c810eba5de 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -186,7 +186,7 @@ final case class NuTypeDef( superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit -)(val declareLoc: Opt[Loc]) extends NuDecl with Statement +)(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc]) extends NuDecl with Statement final case class NuFunDef( isLetRec: Opt[Bool], // None means it's a `fun`, which is always recursive; Some means it's a `let` @@ -196,6 +196,7 @@ final case class NuFunDef( )(val declareLoc: Opt[Loc]) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) def kind: DeclKind = Val + val abstractLoc: Opt[Loc] = None } diff --git a/shared/src/test/diff/nu/Abstract.mls b/shared/src/test/diff/nu/Abstract.mls new file mode 100644 index 0000000000..7a797236b9 --- /dev/null +++ b/shared/src/test/diff/nu/Abstract.mls @@ -0,0 +1,19 @@ +:NewDefs + +abstract class Foo(x: int) { + fun f(y: int) = x + y +} +//│ class Foo(x: int) { +//│ fun f: (y: int,) -> int +//│ } + +let foo = new Foo(42) +//│ let foo: Foo +//│ foo +//│ = Foo {} + +// TODO: reject +let bar = Foo(42) +//│ let bar: Foo +//│ bar +//│ = Foo {} From d335b3f87d92713b7fa9671305da52b9074c525c Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 8 May 2023 16:14:16 +0800 Subject: [PATCH 272/498] Add :e for the rejected test case --- shared/src/main/scala/mlscript/syntax.scala | 3 ++- shared/src/test/diff/nu/Abstract.mls | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index c810eba5de..648316c75a 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -186,7 +186,8 @@ final case class NuTypeDef( superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit -)(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc]) extends NuDecl with Statement +)(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc]) + extends NuDecl with Statement final case class NuFunDef( isLetRec: Opt[Bool], // None means it's a `fun`, which is always recursive; Some means it's a `let` diff --git a/shared/src/test/diff/nu/Abstract.mls b/shared/src/test/diff/nu/Abstract.mls index 7a797236b9..39da2934b9 100644 --- a/shared/src/test/diff/nu/Abstract.mls +++ b/shared/src/test/diff/nu/Abstract.mls @@ -12,7 +12,8 @@ let foo = new Foo(42) //│ foo //│ = Foo {} -// TODO: reject +// TODO reject +// :e let bar = Foo(42) //│ let bar: Foo //│ bar From bad401396644d744a0360e13e31ae4bfc35b0c53 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 8 May 2023 21:20:30 +0800 Subject: [PATCH 273/498] WIP: Try to fix new keyword generation in backend --- shared/src/main/scala/mlscript/JSBackend.scala | 7 +++++-- shared/src/main/scala/mlscript/codegen/Symbol.scala | 6 +++++- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/test/diff/nu/Abstract.mls | 7 +++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 86a51002c7..d08b8552bb 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -111,7 +111,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: NuTypeSymbol with RuntimeSymbol) => - translateNuTypeSymbol(sym) + if (sym.isAbstract) + JSNew(translateNuTypeSymbol(sym)) + else + translateNuTypeSymbol(sym) case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") scope.resolveValue("this") match { @@ -924,7 +927,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) val sym = - NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) + NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested, td.isAbstract).tap(scope.register) if (!td.isDecl) classes += sym } case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index b2ef4b5811..14f9738115 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -33,6 +33,7 @@ sealed trait NuTypeSymbol { val ctor: Ls[Statement] // statements in the constructor val nested: Ls[NuTypeDef] // nested class/mixin/module val superParameters: Ls[Term] // parameters that need to be passed to the `super()` + val isAbstract: Bool // does instantiation needs `new` keyword } sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol { @@ -118,7 +119,8 @@ final case class NewClassSymbol( ctor: Ls[Statement], superParameters: Ls[Term], nested: Ls[NuTypeDef], - isNested: Bool + isNested: Bool, + isAbstract: Bool ) extends TypeSymbol with RuntimeSymbol with NuTypeSymbol { override def toString: Str = s"new class $lexicalName" @@ -145,6 +147,7 @@ final case class MixinSymbol( // Mixins should pass `...rest` to the `super()` // But the variable name is not sure when we create the symbol object override val superParameters: Ls[Term] = Nil + override val isAbstract: Bool = false } final case class ModuleSymbol( @@ -162,6 +165,7 @@ final case class ModuleSymbol( // Modules should have fixed names determined by users override def runtimeName: Str = lexicalName + override val isAbstract: Bool = false } // capture runtime symbols in the outside module/class/mixin diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 9ef052a97b..2a0671f260 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -389,7 +389,7 @@ trait NuDeclImpl extends Located { self: NuDecl => def kind: DeclKind val declareLoc: Opt[Loc] val abstractLoc: Opt[Loc] - def isDecl: Bool = declareLoc.nonEmpty + def isDecl: Bool = declareLoc.nonEmpty || isAbstract def isAbstract: Bool = abstractLoc.nonEmpty def declStr: Str = if (isDecl) "declare " else "" val nameVar: Var = self match { diff --git a/shared/src/test/diff/nu/Abstract.mls b/shared/src/test/diff/nu/Abstract.mls index 39da2934b9..bce3fb79ed 100644 --- a/shared/src/test/diff/nu/Abstract.mls +++ b/shared/src/test/diff/nu/Abstract.mls @@ -7,14 +7,17 @@ abstract class Foo(x: int) { //│ fun f: (y: int,) -> int //│ } +:re let foo = new Foo(42) //│ let foo: Foo //│ foo -//│ = Foo {} +//│ Runtime error: +//│ ReferenceError: Foo is not defined // TODO reject // :e let bar = Foo(42) //│ let bar: Foo //│ bar -//│ = Foo {} +//│ Runtime error: +//│ ReferenceError: Foo is not defined From cd2a52d77bed2985eee752b5f7ad62676da51801 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 10 May 2023 09:18:11 +0800 Subject: [PATCH 274/498] WIP: Update test cases --- .../src/test/diff/codegen/OptionalParam.mls | 88 +++++++++++++++++++ shared/src/test/diff/nu/Abstract.mls | 23 ----- 2 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 shared/src/test/diff/codegen/OptionalParam.mls delete mode 100644 shared/src/test/diff/nu/Abstract.mls diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls new file mode 100644 index 0000000000..d8e067e33d --- /dev/null +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -0,0 +1,88 @@ +:NewParser +:NewDefs + +:js +class A(x: int) {} +//│ class A(x: int) +//│ // Prelude +//│ let res; +//│ class TypingUnit { +//│ #A; +//│ constructor() { +//│ } +//│ get A() { +//│ const outer = this; +//│ if (this.#A === undefined) { +//│ class A { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ }; +//│ this.#A = ((x) => new A(x)); +//│ this.#A.class = A; +//│ } +//│ return this.#A; +//│ } +//│ } +//│ const typing_unit = new TypingUnit; +//│ globalThis.A = typing_unit.A; +//│ // End of generated code + +:js +class B {} +//│ class B() +//│ // Prelude +//│ class TypingUnit1 { +//│ #B; +//│ constructor() { +//│ } +//│ get B() { +//│ const outer = this; +//│ if (this.#B === undefined) { +//│ class B {}; +//│ this.#B = (() => new B()); +//│ this.#B.class = B; +//│ } +//│ return this.#B; +//│ } +//│ } +//│ const typing_unit1 = new TypingUnit1; +//│ globalThis.B = typing_unit1.B; +//│ // End of generated code + +// TODO: +:js +class C { + constructor(x: int) +} +//│ ╔══[ERROR] identifier not found: constructor +//│ ║ l.58: constructor(x: int) +//│ ╙── ^^^^^^^^^^^ +//│ class C() +//│ Code generation encountered an error: +//│ unresolved symbol constructor + +// TODO: +:e +class D(x: int) { + constructor(y: int) +} +//│ ╔══[ERROR] identifier not found: constructor +//│ ║ l.70: constructor(y: int) +//│ ╙── ^^^^^^^^^^^ +//│ class D(x: int) +//│ Code generation encountered an error: +//│ unresolved symbol constructor + +// TODO: +:e +constructor(x: int) +//│ ╔══[ERROR] identifier not found: constructor +//│ ║ l.75: constructor(x: int) +//│ ╙── ^^^^^^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol constructor + diff --git a/shared/src/test/diff/nu/Abstract.mls b/shared/src/test/diff/nu/Abstract.mls deleted file mode 100644 index bce3fb79ed..0000000000 --- a/shared/src/test/diff/nu/Abstract.mls +++ /dev/null @@ -1,23 +0,0 @@ -:NewDefs - -abstract class Foo(x: int) { - fun f(y: int) = x + y -} -//│ class Foo(x: int) { -//│ fun f: (y: int,) -> int -//│ } - -:re -let foo = new Foo(42) -//│ let foo: Foo -//│ foo -//│ Runtime error: -//│ ReferenceError: Foo is not defined - -// TODO reject -// :e -let bar = Foo(42) -//│ let bar: Foo -//│ bar -//│ Runtime error: -//│ ReferenceError: Foo is not defined From 9734d911483c94020e3936d51f7d814bc348b65f Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 10 May 2023 09:47:34 +0800 Subject: [PATCH 275/498] WIP: Undo changes for abstract --- shared/src/main/scala/mlscript/JSBackend.scala | 7 ++----- shared/src/main/scala/mlscript/NewLexer.scala | 3 +-- shared/src/main/scala/mlscript/NewParser.scala | 9 ++------- shared/src/main/scala/mlscript/Typer.scala | 7 +++---- shared/src/main/scala/mlscript/codegen/Symbol.scala | 6 +----- shared/src/main/scala/mlscript/helpers.scala | 4 +--- shared/src/main/scala/mlscript/syntax.scala | 3 +-- shared/src/test/diff/codegen/OptionalParam.mls | 8 ++++---- 8 files changed, 15 insertions(+), 32 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index d08b8552bb..86a51002c7 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -111,10 +111,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: NuTypeSymbol with RuntimeSymbol) => - if (sym.isAbstract) - JSNew(translateNuTypeSymbol(sym)) - else - translateNuTypeSymbol(sym) + translateNuTypeSymbol(sym) case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") scope.resolveValue("this") match { @@ -927,7 +924,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) val sym = - NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested, td.isAbstract).tap(scope.register) + NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) if (!td.isDecl) classes += sym } case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index ea52c54eca..857b77895f 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -281,8 +281,7 @@ object NewLexer { "in", "out", "null", - "undefined", - "abstract" + "undefined" ) def printToken(tl: TokLoc): Str = tl match { diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 8d1c4b87ed..579084badb 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -276,10 +276,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D consume yeetSpaces go(acc.copy(acc.mods + ("declare" -> l0))) - case (KEYWORD("abstract"), l0) :: c => - consume - yeetSpaces - go(acc.copy(acc.mods + ("abstract" -> l0))) case _ if acc.mods.isEmpty => acc case (KEYWORD("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module" | "fun" | "val"), l0) :: _ => acc @@ -304,8 +300,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c) => consume val (isDecl, mods2) = mods.handle("declare") - val (isAbs, mods3) = mods2.handle("abstract") - mods3.done + mods2.done val kind = k match { case "class" => Cls case "trait" => Trt @@ -375,7 +370,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => Nil } val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body)(isDecl, isAbs) + val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body)(isDecl) R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "val" | "let")), l0) :: c) => // TODO support rec? diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 66e81028a4..493d518d41 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1311,8 +1311,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => - NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))( - td.declareLoc, td.abstractLoc) + NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))(td.declareLoc) } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => ectx(tparams) |> { implicit ectx => @@ -1322,7 +1321,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) + mkTypingUnit(thisTy, members))(td.declareLoc) } case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => ectx(tparams) |> { implicit ectx => @@ -1332,7 +1331,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) + mkTypingUnit(thisTy, members))(td.declareLoc) } case tf @ TypedNuFun(level, fd, bodyTy) => NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc) diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index 14f9738115..b2ef4b5811 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -33,7 +33,6 @@ sealed trait NuTypeSymbol { val ctor: Ls[Statement] // statements in the constructor val nested: Ls[NuTypeDef] // nested class/mixin/module val superParameters: Ls[Term] // parameters that need to be passed to the `super()` - val isAbstract: Bool // does instantiation needs `new` keyword } sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol { @@ -119,8 +118,7 @@ final case class NewClassSymbol( ctor: Ls[Statement], superParameters: Ls[Term], nested: Ls[NuTypeDef], - isNested: Bool, - isAbstract: Bool + isNested: Bool ) extends TypeSymbol with RuntimeSymbol with NuTypeSymbol { override def toString: Str = s"new class $lexicalName" @@ -147,7 +145,6 @@ final case class MixinSymbol( // Mixins should pass `...rest` to the `super()` // But the variable name is not sure when we create the symbol object override val superParameters: Ls[Term] = Nil - override val isAbstract: Bool = false } final case class ModuleSymbol( @@ -165,7 +162,6 @@ final case class ModuleSymbol( // Modules should have fixed names determined by users override def runtimeName: Str = lexicalName - override val isAbstract: Bool = false } // capture runtime symbols in the outside module/class/mixin diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 2a0671f260..02cd4c9f00 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -388,9 +388,7 @@ trait NuDeclImpl extends Located { self: NuDecl => val body: Located def kind: DeclKind val declareLoc: Opt[Loc] - val abstractLoc: Opt[Loc] - def isDecl: Bool = declareLoc.nonEmpty || isAbstract - def isAbstract: Bool = abstractLoc.nonEmpty + def isDecl: Bool = declareLoc.nonEmpty def declStr: Str = if (isDecl) "declare " else "" val nameVar: Var = self match { case td: NuTypeDef => td.nme.toVar diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 648316c75a..2761b54550 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -186,7 +186,7 @@ final case class NuTypeDef( superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit -)(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc]) +)(val declareLoc: Opt[Loc]) extends NuDecl with Statement final case class NuFunDef( @@ -197,7 +197,6 @@ final case class NuFunDef( )(val declareLoc: Opt[Loc]) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) def kind: DeclKind = Val - val abstractLoc: Opt[Loc] = None } diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index d8e067e33d..5541648461 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -52,7 +52,7 @@ class B {} //│ globalThis.B = typing_unit1.B; //│ // End of generated code -// TODO: +// TODO :js class C { constructor(x: int) @@ -64,7 +64,7 @@ class C { //│ Code generation encountered an error: //│ unresolved symbol constructor -// TODO: +// TODO :e class D(x: int) { constructor(y: int) @@ -76,11 +76,11 @@ class D(x: int) { //│ Code generation encountered an error: //│ unresolved symbol constructor -// TODO: +// TODO :e constructor(x: int) //│ ╔══[ERROR] identifier not found: constructor -//│ ║ l.75: constructor(x: int) +//│ ║ l.81: constructor(x: int) //│ ╙── ^^^^^^^^^^^ //│ error //│ Code generation encountered an error: From f4328ae2efe4828a4a10afd41707cf43a309e930 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 10 May 2023 11:48:51 +0800 Subject: [PATCH 276/498] WIP: Try to add abstract and optional parameters(not ready) --- .../src/main/scala/mlscript/JSBackend.scala | 26 ++++-- shared/src/main/scala/mlscript/NewLexer.scala | 4 +- .../src/main/scala/mlscript/NewParser.scala | 49 +++++++++-- shared/src/main/scala/mlscript/Typer.scala | 7 +- .../main/scala/mlscript/codegen/Symbol.scala | 6 +- shared/src/main/scala/mlscript/helpers.scala | 9 ++ shared/src/main/scala/mlscript/syntax.scala | 5 +- .../src/test/diff/codegen/OptionalParam.mls | 86 ++++++++++++++----- shared/src/test/diff/nu/Abstract.mls | 8 ++ shared/src/test/diff/nu/BasicMixins.mls | 2 - shared/src/test/diff/nu/ClassesInMixins.mls | 4 +- shared/src/test/diff/nu/Declarations.mls | 3 + 12 files changed, 162 insertions(+), 47 deletions(-) create mode 100644 shared/src/test/diff/nu/Abstract.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 86a51002c7..28fcf96aaa 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -111,7 +111,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: NuTypeSymbol with RuntimeSymbol) => - translateNuTypeSymbol(sym) + if (sym.needNew) JSNew(translateNuTypeSymbol(sym)) + else translateNuTypeSymbol(sym) case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") scope.resolveValue("this") match { @@ -648,13 +649,21 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val privateIdent = JSIdent(s"this.#${classSymbol.lexicalName}") val outerStmt = JSConstDecl(outerSymbol.runtimeName, JSIdent("this")) + val initList = + if (classSymbol.needNew) + Ls( + JSExprStmt(JSClassExpr(classBody)), + JSExprStmt(JSAssignExpr(privateIdent, JSIdent(classSymbol.lexicalName))) + ) + else + Ls( + JSExprStmt(JSClassExpr(classBody)), + JSExprStmt(JSAssignExpr(privateIdent, + JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), + JSExprStmt(JSAssignExpr(privateIdent.member("class"), JSIdent(classSymbol.lexicalName))) + ) JSClassGetter(classSymbol.lexicalName, R(outerStmt :: Ls( - JSIfStmt(JSBinary("===", privateIdent, JSIdent("undefined")), Ls( - JSExprStmt(JSClassExpr(classBody)), - JSExprStmt(JSAssignExpr(privateIdent, - JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), - JSExprStmt(JSAssignExpr(privateIdent.member("class"), JSIdent(classSymbol.lexicalName))) - )), + JSIfStmt(JSBinary("===", privateIdent, JSIdent("undefined")), initList), JSReturnStmt(S(privateIdent)) ))) } @@ -924,7 +933,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) val sym = - NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) + NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested, td.hasExtraCtor).tap(scope.register) if (!td.isDecl) classes += sym } case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { @@ -1254,6 +1263,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { private def generateNewDef(pgrm: Pgrm)(implicit scope: Scope, allowEscape: Bool): JSTestBackend.TestCode = { val (typeDefs, otherStmts) = pgrm.tops.partitionMap { + case _: Constructor => throw CodeGenError("unexpected constructor.") case ot: Terms => R(ot) case fd: NuFunDef => R(fd) case nd: NuTypeDef => L(nd) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 857b77895f..6ec931e4bd 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -281,7 +281,9 @@ object NewLexer { "in", "out", "null", - "undefined" + "undefined", + "abstract", + "constructor" ) def printToken(tl: TokLoc): Str = tl match { diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 579084badb..1bebf86a45 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -223,6 +223,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D errExpr case R(d: NuDecl) => d case R(e: Term) => e + case R(c: Constructor) => c case _ => ??? } TypingUnit(es) @@ -276,7 +277,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D consume yeetSpaces go(acc.copy(acc.mods + ("declare" -> l0))) + case (KEYWORD("abstract"), l0) :: c => + consume + yeetSpaces + go(acc.copy(acc.mods + ("abstract" -> l0))) case _ if acc.mods.isEmpty => acc + case (KEYWORD("constructor"), l0) :: _ => + acc case (KEYWORD("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module" | "fun" | "val"), l0) :: _ => acc case (tok, loc) :: _ => @@ -297,10 +304,23 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (SPACE, _) :: _ => consume; block case c => val t = c match { + case ModifierSet(mods, (KEYWORD("constructor"), l0) :: c) => + consume + val res = yeetSpaces match { + case (br @ BRACKETS(Round, toks), loc) :: _ => + consume + val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO + Constructor(Tup(as).withLoc(S(loc))) + case _ => + err(msg"Expect parameter list for the constructor" -> S(l0) :: Nil) + Constructor(Tup(Nil)) + } + R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c) => consume val (isDecl, mods2) = mods.handle("declare") - mods2.done + val (isAbs, mods3) = mods2.handle("abstract") + mods3.done val kind = k match { case "class" => Cls case "trait" => Trt @@ -338,12 +358,12 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D rec(toks, S(br.innerLoc), br.describe).concludeWith(_.maybeIndented((p, _) => p.typeParams)) case _ => Nil } - val params = yeetSpaces match { + val (params, has_params) = yeetSpaces match { case (br @ BRACKETS(Round, toks), loc) :: _ => consume val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO - Tup(as).withLoc(S(loc)) - case _ => Tup(Nil) + (Tup(as).withLoc(S(loc)), true) + case _ => (Tup(Nil), false) } def otherParents: Ls[Term] = yeetSpaces match { case (COMMA, _) :: _ => @@ -369,8 +389,25 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D expr(0) :: otherParents case _ => Nil } - val body = curlyTypingUnit - val res = NuTypeDef(kind, tn, tparams, params, sig, ps, N, N, body)(isDecl) + val tu = curlyTypingUnit + val (ctor, body) = tu.entities.partition { + case _: Constructor => true + case _ => false + } + + val (real_params, ctorLoc) = + if (ctor.length > 1) { + err(msg"more than one constructor" -> S(l0) :: Nil) + (Tup(Nil), N) + } + else ctor.headOption match { + case Some(ctor @ Constructor(tup)) => + if (has_params) err(msg"more than one constructor" -> S(l0) :: Nil) + (tup, ctor.toLoc) + case _ => (params, N) + } + + val res = NuTypeDef(kind, tn, tparams, real_params, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs, ctorLoc) R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "val" | "let")), l0) :: c) => // TODO support rec? diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 493d518d41..988788e148 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1311,7 +1311,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => - NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))(td.declareLoc) + NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))( + td.declareLoc, td.abstractLoc, td.ctorLoc) } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => ectx(tparams) |> { implicit ectx => @@ -1321,7 +1322,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc) + mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc, td.ctorLoc) } case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => ectx(tparams) |> { implicit ectx => @@ -1331,7 +1332,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc) + mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc, td.ctorLoc) } case tf @ TypedNuFun(level, fd, bodyTy) => NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc) diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index b2ef4b5811..d8cacf4d4c 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -33,6 +33,7 @@ sealed trait NuTypeSymbol { val ctor: Ls[Statement] // statements in the constructor val nested: Ls[NuTypeDef] // nested class/mixin/module val superParameters: Ls[Term] // parameters that need to be passed to the `super()` + val needNew: Bool } sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol { @@ -118,7 +119,8 @@ final case class NewClassSymbol( ctor: Ls[Statement], superParameters: Ls[Term], nested: Ls[NuTypeDef], - isNested: Bool + isNested: Bool, + needNew: Bool ) extends TypeSymbol with RuntimeSymbol with NuTypeSymbol { override def toString: Str = s"new class $lexicalName" @@ -145,6 +147,7 @@ final case class MixinSymbol( // Mixins should pass `...rest` to the `super()` // But the variable name is not sure when we create the symbol object override val superParameters: Ls[Term] = Nil + val needNew: Bool = false } final case class ModuleSymbol( @@ -162,6 +165,7 @@ final case class ModuleSymbol( // Modules should have fixed names determined by users override def runtimeName: Str = lexicalName + val needNew: Bool = false } // capture runtime symbols in the outside module/class/mixin diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 02cd4c9f00..46a9727715 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -388,7 +388,11 @@ trait NuDeclImpl extends Located { self: NuDecl => val body: Located def kind: DeclKind val declareLoc: Opt[Loc] + val abstractLoc: Opt[Loc] + val ctorLoc: Opt[Loc] def isDecl: Bool = declareLoc.nonEmpty + def isAbstract: Bool = abstractLoc.nonEmpty + def hasExtraCtor: Bool = ctorLoc.nonEmpty def declStr: Str = if (isDecl) "declare " else "" val nameVar: Var = self match { case td: NuTypeDef => td.nme.toVar @@ -710,6 +714,9 @@ trait StatementImpl extends Located { self: Statement => lazy val desugared = doDesugar private def doDesugar: Ls[Diagnostic] -> Ls[DesugaredStatement] = this match { + case ctor: Constructor => + import Message._ + (ErrorReport(msg"constructor must be in a class." -> ctor.toLoc :: Nil) :: Nil) -> Nil case l @ LetS(isrec, pat, rhs) => val (diags, v, args) = desugDefnPattern(pat, Nil) diags -> (Def(isrec, v, L(args.foldRight(rhs)(Lam(_, _))), false).withLocOf(l) :: Nil) // TODO use v, not v.name @@ -871,6 +878,7 @@ trait StatementImpl extends Located { self: Statement => case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil case Super() => Nil + case Constructor(lst) => lst :: Nil case NuTypeDef(k, nme, tps, ps, sig, pars, sup, ths, bod) => nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil } @@ -880,6 +888,7 @@ trait StatementImpl extends Located { self: Statement => case LetS(isRec, name, rhs) => s"let${if (isRec) " rec" else ""} $name = $rhs" case DatatypeDefn(head, body) => s"data type $head of $body" case DataDefn(head) => s"data $head" + case Constructor(lst) => s"constructor($lst)" case _: Term => super.toString case d: Decl => d.showDbg case d: NuDecl => d.showDbg diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 2761b54550..949ecf6e18 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -112,6 +112,7 @@ sealed trait Statement extends StatementImpl final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement final case class DataDefn(body: Term) extends Statement final case class DatatypeDefn(head: Term, body: Term) extends Statement +final case class Constructor(lst: Tup) extends Statement sealed trait DesugaredStatement extends Statement with DesugaredStatementImpl @@ -186,7 +187,7 @@ final case class NuTypeDef( superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit -)(val declareLoc: Opt[Loc]) +)(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc], val ctorLoc: Opt[Loc]) extends NuDecl with Statement final case class NuFunDef( @@ -197,6 +198,8 @@ final case class NuFunDef( )(val declareLoc: Opt[Loc]) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) def kind: DeclKind = Val + val abstractLoc: Opt[Loc] = None + val ctorLoc: Opt[Loc] = None } diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 5541648461..08db69bebc 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -52,37 +52,79 @@ class B {} //│ globalThis.B = typing_unit1.B; //│ // End of generated code -// TODO :js class C { constructor(x: int) + fun f = x + 1 } -//│ ╔══[ERROR] identifier not found: constructor -//│ ║ l.58: constructor(x: int) -//│ ╙── ^^^^^^^^^^^ -//│ class C() -//│ Code generation encountered an error: -//│ unresolved symbol constructor +//│ class C(x: int) { +//│ fun f: int +//│ } +//│ // Prelude +//│ class TypingUnit2 { +//│ #C; +//│ constructor() { +//│ } +//│ get C() { +//│ const outer = this; +//│ if (this.#C === undefined) { +//│ class C { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ get f() { +//│ const x = this.#x; +//│ return x + 1; +//│ } +//│ }; +//│ this.#C = C; +//│ } +//│ return this.#C; +//│ } +//│ } +//│ const typing_unit2 = new TypingUnit2; +//│ globalThis.C = typing_unit2.C; +//│ // End of generated code -// TODO -:e +let c = new C(1) +c.x +c.f +//│ let c: C +//│ int +//│ c +//│ = C {} +//│ res +//│ = 1 +//│ res +//│ = 2 + +:pe class D(x: int) { constructor(y: int) } -//│ ╔══[ERROR] identifier not found: constructor -//│ ║ l.70: constructor(y: int) -//│ ╙── ^^^^^^^^^^^ -//│ class D(x: int) -//│ Code generation encountered an error: -//│ unresolved symbol constructor +//│ ╔══[PARSE ERROR] more than one constructor +//│ ║ l.104: class D(x: int) { +//│ ╙── ^^^^^ +//│ class D(y: int) + +:pe +class E { + constructor(x: int) + constructor(y: int) +} +//│ ╔══[PARSE ERROR] more than one constructor +//│ ║ l.113: class E { +//│ ╙── ^^^^^ +//│ class E() -// TODO +// TODO: better check? :e constructor(x: int) -//│ ╔══[ERROR] identifier not found: constructor -//│ ║ l.81: constructor(x: int) -//│ ╙── ^^^^^^^^^^^ -//│ error +//│ ╔══[ERROR] constructor must be in a class. +//│ ║ l.124: constructor(x: int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ () //│ Code generation encountered an error: -//│ unresolved symbol constructor - +//│ unexpected constructor. diff --git a/shared/src/test/diff/nu/Abstract.mls b/shared/src/test/diff/nu/Abstract.mls new file mode 100644 index 0000000000..e1173b64ac --- /dev/null +++ b/shared/src/test/diff/nu/Abstract.mls @@ -0,0 +1,8 @@ +:NewDefs + +abstract class Foo(x: int) { + fun f(y: int) = x + y +} +//│ class Foo(x: int) { +//│ fun f: (y: int,) -> int +//│ } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 159ca3893a..5f09e8758b 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -43,8 +43,6 @@ class Base1(base: int) extends BaseTest { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.39: fun test2 = [base, this.base] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.40: } -//│ ║ ^ //│ ╟── Object of type `anything` does not have field 'base' //│ ║ l.38: class Base1(base: int) extends BaseTest { //│ ║ ^ diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 5dd8012c96..c1af29bb86 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -71,9 +71,7 @@ mixin Test { //│ ║ l.64: class Add(lhs: A, rhs: A) { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.65: let cached = size(this) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.66: } -//│ ╙── ^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Illegal pattern `Add` //│ ║ l.68: Add(l, r) then this.size(l) + this.size(r) //│ ╙── ^^^ diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index a1d2d0b249..4ef374b00e 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -123,6 +123,9 @@ declare 42 //│ ╔══[PARSE ERROR] Unexpected literal token after modifier //│ ║ l.119: declare 42 //│ ╙── ^^ +//│ ╔══[PARSE ERROR] Unexpected literal token after modifier +//│ ║ l.119: declare 42 +//│ ╙── ^^ //│ 42 //│ res //│ = 42 From eea3c1efb7851217e19850ab008854c0daf9240f Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 10 May 2023 12:03:34 +0800 Subject: [PATCH 277/498] WIP: Freeze object before returning(not ready) --- .../src/main/scala/mlscript/JSBackend.scala | 13 +++-- .../src/test/diff/codegen/ConstructorStmt.mls | 12 ++--- .../src/test/diff/codegen/FieldOverride.mls | 4 +- shared/src/test/diff/codegen/Mixin.mls | 12 ++--- shared/src/test/diff/codegen/Nested.mls | 48 +++++++++---------- shared/src/test/diff/codegen/NuClasses.mls | 2 +- .../src/test/diff/codegen/OptionalParam.mls | 4 +- shared/src/test/diff/nu/BasicMixins.mls | 32 ++++++------- 8 files changed, 63 insertions(+), 64 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 28fcf96aaa..2049e44d24 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -651,19 +651,18 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val outerStmt = JSConstDecl(outerSymbol.runtimeName, JSIdent("this")) val initList = if (classSymbol.needNew) - Ls( - JSExprStmt(JSClassExpr(classBody)), - JSExprStmt(JSAssignExpr(privateIdent, JSIdent(classSymbol.lexicalName))) - ) + Ls(JSExprStmt(JSAssignExpr(privateIdent, JSIdent(classSymbol.lexicalName)))) else Ls( - JSExprStmt(JSClassExpr(classBody)), JSExprStmt(JSAssignExpr(privateIdent, - JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))))), + JSArrowFn(constructor, L( + JSInvoke(JSIdent("Object").member("freeze"), Ls(JSInvoke(JSNew(JSIdent(classSymbol.lexicalName)), params))) + )))), JSExprStmt(JSAssignExpr(privateIdent.member("class"), JSIdent(classSymbol.lexicalName))) ) JSClassGetter(classSymbol.lexicalName, R(outerStmt :: Ls( - JSIfStmt(JSBinary("===", privateIdent, JSIdent("undefined")), initList), + JSIfStmt(JSBinary("===", privateIdent, JSIdent("undefined")), + JSExprStmt(JSClassExpr(classBody)) :: initList), JSReturnStmt(S(privateIdent)) ))) } diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 527ea98f11..dddd99e418 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -80,7 +80,7 @@ class A(a: int) { //│ log(a); //│ } //│ }; -//│ this.#A = ((a) => new A(a)); +//│ this.#A = ((a) => Object.freeze(new A(a))); //│ this.#A.class = A; //│ } //│ return this.#A; @@ -148,7 +148,7 @@ class Foo { //│ const outer = this; //│ if (this.#Foo === undefined) { //│ class Foo {}; -//│ this.#Foo = (() => new Foo()); +//│ this.#Foo = (() => Object.freeze(new Foo())); //│ this.#Foo.class = Foo; //│ } //│ return this.#Foo; @@ -179,7 +179,7 @@ class Bar { //│ const outer = this; //│ if (this.#Bar === undefined) { //│ class Bar {}; -//│ this.#Bar = (() => new Bar()); +//│ this.#Bar = (() => Object.freeze(new Bar())); //│ this.#Bar.class = Bar; //│ } //│ return this.#Bar; @@ -236,7 +236,7 @@ class Baz { //│ ]); //│ } //│ }; -//│ this.#Baz = (() => new Baz()); +//│ this.#Baz = (() => Object.freeze(new Baz())); //│ this.#Baz.class = Baz; //│ } //│ return this.#Baz; @@ -294,7 +294,7 @@ class Q() { //│ })()); //│ } //│ }; -//│ this.#Q = (() => new Q()); +//│ this.#Q = (() => Object.freeze(new Q())); //│ this.#Q.class = Q; //│ } //│ return this.#Q; @@ -342,7 +342,7 @@ class W() { //│ return self.x + self1; //│ } //│ }; -//│ this.#W = (() => new W()); +//│ this.#W = (() => Object.freeze(new W())); //│ this.#W.class = W; //│ } //│ return this.#W; diff --git a/shared/src/test/diff/codegen/FieldOverride.mls b/shared/src/test/diff/codegen/FieldOverride.mls index 4de74414b0..b7323e3da3 100644 --- a/shared/src/test/diff/codegen/FieldOverride.mls +++ b/shared/src/test/diff/codegen/FieldOverride.mls @@ -24,7 +24,7 @@ class C(a: int) { let a = 1 } //│ const a1 = this.#a; //│ } //│ }; -//│ this.#C = ((a) => new C(a)); +//│ this.#C = ((a) => Object.freeze(new C(a))); //│ this.#C.class = C; //│ } //│ return this.#C; @@ -75,7 +75,7 @@ class C2(a: int, b: int) { //│ const b1 = this.#b; //│ } //│ }; -//│ this.#C2 = ((a, b) => new C2(a, b)); +//│ this.#C2 = ((a, b) => Object.freeze(new C2(a, b))); //│ this.#C2.class = C2; //│ } //│ return this.#C2; diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index e51cb76fd5..3c3e2e76af 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -27,7 +27,7 @@ class Lit(n: int) //│ this.#rhs = rhs; //│ } //│ }; -//│ this.#Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ this.#Add = ((lhs, rhs) => Object.freeze(new Add(lhs, rhs))); //│ this.#Add.class = Add; //│ } //│ return this.#Add; @@ -42,7 +42,7 @@ class Lit(n: int) //│ this.#n = n; //│ } //│ }; -//│ this.#Lit = ((n) => new Lit(n)); +//│ this.#Lit = ((n) => Object.freeze(new Lit(n))); //│ this.#Lit.class = Lit; //│ } //│ return this.#Lit; @@ -74,7 +74,7 @@ class Lit(n: int) //│ │ │ this.#rhs = rhs; //│ │ │ } //│ │ │ }; -//│ │ │ this.#Add = ((lhs, rhs) => new Add(lhs, rhs)); +//│ │ │ this.#Add = ((lhs, rhs) => Object.freeze(new Add(lhs, rhs))); //│ │ │ this.#Add.class = Add; //│ │ │ } //│ │ │ return this.#Add; @@ -89,7 +89,7 @@ class Lit(n: int) //│ │ │ this.#n = n; //│ │ │ } //│ │ │ }; -//│ │ │ this.#Lit = ((n) => new Lit(n)); +//│ │ │ this.#Lit = ((n) => Object.freeze(new Lit(n))); //│ │ │ this.#Lit.class = Lit; //│ │ │ } //│ │ │ return this.#Lit; @@ -188,7 +188,7 @@ class Neg(expr: A) //│ this.#expr = expr; //│ } //│ }; -//│ this.#Neg = ((expr) => new Neg(expr)); +//│ this.#Neg = ((expr) => Object.freeze(new Neg(expr))); //│ this.#Neg.class = Neg; //│ } //│ return this.#Neg; @@ -214,7 +214,7 @@ class Neg(expr: A) //│ │ │ this.#expr = expr; //│ │ │ } //│ │ │ }; -//│ │ │ this.#Neg = ((expr) => new Neg(expr)); +//│ │ │ this.#Neg = ((expr) => Object.freeze(new Neg(expr))); //│ │ │ this.#Neg.class = Neg; //│ │ │ } //│ │ │ return this.#Neg; diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index b47e15c78c..560e8b2766 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -45,7 +45,7 @@ module A { //│ return x + 1; //│ } //│ }; -//│ this.#B = ((x) => new B(x)); +//│ this.#B = ((x) => Object.freeze(new B(x))); //│ this.#B.class = B; //│ } //│ return this.#B; @@ -207,7 +207,7 @@ module D { //│ this.#x = x; //│ } //│ }; -//│ this.#E = ((x) => new E(x)); +//│ this.#E = ((x) => Object.freeze(new E(x))); //│ this.#E.class = E; //│ } //│ return this.#E; @@ -301,19 +301,19 @@ class E(x: int) { //│ return outer1.x + outer2.y + z; //│ } //│ }; -//│ this.#G = ((z) => new G(z)); +//│ this.#G = ((z) => Object.freeze(new G(z))); //│ this.#G.class = G; //│ } //│ return this.#G; //│ } //│ }; -//│ this.#F = ((y) => new F(y)); +//│ this.#F = ((y) => Object.freeze(new F(y))); //│ this.#F.class = F; //│ } //│ return this.#F; //│ } //│ }; -//│ this.#E = ((x) => new E(x)); +//│ this.#E = ((x) => Object.freeze(new E(x))); //│ this.#E.class = E; //│ } //│ return this.#E; @@ -397,13 +397,13 @@ class F() { //│ const x1 = this.#x1; //│ } //│ }; -//│ this.#G = (() => new G()); +//│ this.#G = (() => Object.freeze(new G())); //│ this.#G.class = G; //│ } //│ return this.#G; //│ } //│ }; -//│ this.#F = (() => new F()); +//│ this.#F = (() => Object.freeze(new F())); //│ this.#F.class = F; //│ } //│ return this.#F; @@ -470,7 +470,7 @@ module G { //│ return outer1.I(x + a); //│ } //│ }; -//│ this.#J = ((x) => new J(x)); +//│ this.#J = ((x) => Object.freeze(new J(x))); //│ this.#J.class = J; //│ } //│ return this.#J; @@ -491,7 +491,7 @@ module G { //│ this.#x = x; //│ } //│ }; -//│ this.#I = ((x) => new I(x)); +//│ this.#I = ((x) => Object.freeze(new I(x))); //│ this.#I.class = I; //│ } //│ return this.#I; @@ -572,7 +572,7 @@ module H { //│ this.#x = x; //│ } //│ }; -//│ this.#I = ((x) => new I(x)); +//│ this.#I = ((x) => Object.freeze(new I(x))); //│ this.#I.class = I; //│ } //│ return this.#I; @@ -591,7 +591,7 @@ module H { //│ const i = this.#i; //│ } //│ }; -//│ this.#J = ((x) => new J(x)); +//│ this.#J = ((x) => Object.freeze(new J(x))); //│ this.#J.class = J; //│ } //│ return this.#J; @@ -693,13 +693,13 @@ ij.incY //│ return self.y + 1; //│ } //│ }; -//│ this.#J = ((x) => new J(x)); +//│ this.#J = ((x) => Object.freeze(new J(x))); //│ this.#J.class = J; //│ } //│ return this.#J; //│ } //│ }; -//│ this.#I = ((x) => new I(x)); +//│ this.#I = ((x) => Object.freeze(new I(x))); //│ this.#I.class = I; //│ } //│ return this.#I; @@ -773,7 +773,7 @@ module J { //│ this.#x = x; //│ } //│ }; -//│ this.#K = ((x) => new K(x)); +//│ this.#K = ((x) => Object.freeze(new K(x))); //│ this.#K.class = K; //│ } //│ return this.#K; @@ -786,7 +786,7 @@ module J { //│ super(1); //│ } //│ }; -//│ this.#M = (() => new M()); +//│ this.#M = (() => Object.freeze(new M())); //│ this.#M.class = M; //│ } //│ return this.#M; @@ -802,7 +802,7 @@ module J { //│ this.#x = x; //│ } //│ }; -//│ this.#N = ((x) => new N(x)); +//│ this.#N = ((x) => Object.freeze(new N(x))); //│ this.#N.class = N; //│ } //│ return this.#N; @@ -981,7 +981,7 @@ M.N.op(M.P()) //│ const outer1 = this; //│ if (this.#O === undefined) { //│ class O {}; -//│ this.#O = (() => new O()); +//│ this.#O = (() => Object.freeze(new O())); //│ this.#O.class = O; //│ } //│ return this.#O; @@ -990,7 +990,7 @@ M.N.op(M.P()) //│ const outer1 = this; //│ if (this.#P === undefined) { //│ class P {}; -//│ this.#P = (() => new P()); +//│ this.#P = (() => Object.freeze(new P())); //│ this.#P.class = P; //│ } //│ return this.#P; @@ -1055,7 +1055,7 @@ module N { //│ super(); //│ } //│ }; -//│ this.#P = (() => new P()); +//│ this.#P = (() => Object.freeze(new P())); //│ this.#P.class = P; //│ } //│ return this.#P; @@ -1070,7 +1070,7 @@ module N { //│ const outer1 = this; //│ if (this.#Q === undefined) { //│ class Q {}; -//│ this.#Q = (() => new Q()); +//│ this.#Q = (() => Object.freeze(new Q())); //│ this.#Q.class = Q; //│ } //│ return this.#Q; @@ -1151,13 +1151,13 @@ I(1).J(3).a //│ const a = this.#a; //│ } //│ }; -//│ this.#J = ((z) => new J(z)); +//│ this.#J = ((z) => Object.freeze(new J(z))); //│ this.#J.class = J; //│ } //│ return this.#J; //│ } //│ }; -//│ this.#I = ((x) => new I(x)); +//│ this.#I = ((x) => Object.freeze(new I(x))); //│ this.#I.class = I; //│ } //│ return this.#I; @@ -1387,13 +1387,13 @@ class Outer1(outer: int) { //│ const outer2 = this.#outer; //│ } //│ }; -//│ this.#Outer2 = ((x) => new Outer2(x)); +//│ this.#Outer2 = ((x) => Object.freeze(new Outer2(x))); //│ this.#Outer2.class = Outer2; //│ } //│ return this.#Outer2; //│ } //│ }; -//│ this.#Outer1 = ((outer) => new Outer1(outer)); +//│ this.#Outer1 = ((outer) => Object.freeze(new Outer1(outer))); //│ this.#Outer1.class = Outer1; //│ } //│ return this.#Outer1; diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index 20d8d4a061..e040b20353 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -27,7 +27,7 @@ class Test(n: int) { //│ return outer.Test(n + 1); //│ } //│ }; -//│ this.#Test = ((n) => new Test(n)); +//│ this.#Test = ((n) => Object.freeze(new Test(n))); //│ this.#Test.class = Test; //│ } //│ return this.#Test; diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 08db69bebc..7c48ae651e 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -20,7 +20,7 @@ class A(x: int) {} //│ this.#x = x; //│ } //│ }; -//│ this.#A = ((x) => new A(x)); +//│ this.#A = ((x) => Object.freeze(new A(x))); //│ this.#A.class = A; //│ } //│ return this.#A; @@ -42,7 +42,7 @@ class B {} //│ const outer = this; //│ if (this.#B === undefined) { //│ class B {}; -//│ this.#B = (() => new B()); +//│ this.#B = (() => Object.freeze(new B())); //│ this.#B.class = B; //│ } //│ return this.#B; diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 5f09e8758b..f464c974c5 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -113,7 +113,7 @@ Base2(11).test2 // TODO class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.116: class Base2(x) extends BaseOf(x + 1), BaseTest +//│ ║ l.114: class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╙── ^ //│ class Base2(x: error) { //│ fun original: int @@ -123,10 +123,10 @@ class Base2(x) extends BaseOf(x + 1), BaseTest :e class Base1(x): BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.126: class Base1(x): BaseTest +//│ ║ l.124: class Base1(x): BaseTest //│ ╙── ^ //│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.126: class Base1(x): BaseTest +//│ ║ l.124: class Base1(x): BaseTest //│ ╙── ^^^^^^^^ //│ class Base1(x: error) @@ -148,31 +148,31 @@ mixin Foo { :e module Base1(base: int, misc: string) extends Foo //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.149: module Base1(base: int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.149: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'misc' -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.149: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.141: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.141: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.149: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.149: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.141: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.141: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ module Base1(base: int, misc: string) { //│ fun test: (int & 'a) -> (int, 'a, nothing,) @@ -255,16 +255,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.258: WrapBase1.wrapA("ok") +//│ ║ l.256: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.258: WrapBase1.wrapA("ok") +//│ ║ l.256: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.192: fun wrapA(x: int) = x : int +//│ ║ l.190: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.202: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.200: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error //│ res From 75d1470b011a22cacc135f126670127b58a0fbbe Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 10 May 2023 18:39:23 +0800 Subject: [PATCH 278/498] Fix freshening of type definitions/methods and do not generalize method types unless annotated --- .../scala/mlscript/compiler/ClassLifter.scala | 4 +- .../scala/mlscript/ConstraintSolver.scala | 2 +- .../src/main/scala/mlscript/NewParser.scala | 6 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 118 ++-- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/codegen/Mixin.mls | 8 +- .../test/diff/ecoop23/ExpressionProblem.mls | 42 +- shared/src/test/diff/ecoop23/Intro.mls | 4 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 622 +++++++++--------- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 190 ++++-- shared/src/test/diff/nu/BasicClasses.mls | 4 +- shared/src/test/diff/nu/BasicMixins.mls | 8 +- shared/src/test/diff/nu/EvalNegNeg.mls | 29 +- .../test/diff/nu/ExpressionProblem_repro.mls | 26 +- .../test/diff/nu/ExpressionProblem_small.mls | 10 +- shared/src/test/diff/nu/FunPoly.mls | 2 +- shared/src/test/diff/nu/GenericClasses.mls | 12 +- shared/src/test/diff/nu/GenericMethods.mls | 2 +- shared/src/test/diff/nu/GenericModules.mls | 6 +- shared/src/test/diff/nu/InterfaceMono.mls | 8 +- shared/src/test/diff/nu/Interfaces.mls | 180 +++-- shared/src/test/diff/nu/MemberConfusion.mls | 75 +++ shared/src/test/diff/nu/MetaWrap.mls | 34 +- shared/src/test/diff/nu/MethodSignatures.mls | 145 +++- shared/src/test/diff/nu/NuScratch.mls | 77 --- .../test/diff/nu/PolymorphicVariants_Alt.mls | 111 ++-- shared/src/test/diff/nu/SelfAppMethods.mls | 66 ++ shared/src/test/diff/nu/repro_EvalNegNeg.mls | 26 +- .../diff/nu/repro_PolymorphicVariants.mls | 7 +- 31 files changed, 1075 insertions(+), 755 deletions(-) create mode 100644 shared/src/test/diff/nu/MemberConfusion.mls create mode 100644 shared/src/test/diff/nu/SelfAppMethods.mls diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index f4afa1aa8c..88ef254eef 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -543,14 +543,14 @@ class ClassLifter(logDebugMsg: Boolean = false) { body match{ case Left(value) => val ret = liftTerm(value)(using ctx.addV(nm).addT(tpVs)) - (func.copy(rhs = Left(ret._1))(None), ret._2) + (func.copy(rhs = Left(ret._1))(func.declareLoc, func.signature), ret._2) case Right(PolyType(targs, body)) => val nBody = liftType(body)(using ctx.addT(tpVs)) val nTargs = targs.map { case L(tp) => liftTypeName(tp)(using ctx.addT(tpVs)).mapFirst(Left.apply) case R(tv) => R(tv) -> emptyCtx }.unzip - (func.copy(rhs = Right(PolyType(nTargs._1, nBody._1)))(None), nTargs._2.fold(nBody._2)(_ ++ _)) + (func.copy(rhs = Right(PolyType(nTargs._1, nBody._1)))(func.declareLoc, func.signature), nTargs._2.fold(nBody._2)(_ ++ _)) } } diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index ce3693d2ba..a6d84c5e32 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1616,7 +1616,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case Some(tv) => tv case None if rigidify && tv.level <= below => // * Rigid type variables (ie, skolems) are encoded as SkolemTag-s - val rv = SkolemTag(lvl, freshVar(noProv, S(tv), tv.nameHint.orElse(S("_"))))(tv.prov) + val rv = SkolemTag(lvl, freshVar(noProv, S(tv), tv.nameHint/* .orElse(S("_"))*/))(tv.prov) println(s"New skolem: $tv ~> $rv") if (tv.lowerBounds.nonEmpty || tv.upperBounds.nonEmpty) { // TODO just add bounds to skolems! should lead to simpler constraints // The bounds of `tv` may be recursive (refer to `tv` itself), diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 579084badb..9a62883355 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -439,7 +439,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D val body = expr(0) val newBody = transformBody.fold(body)(_(body)) val annotatedBody = asc.fold(newBody)(ty => Asc(newBody, ty)) - R(NuFunDef(isLetRec, v, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))))(isDecl)) + R(NuFunDef(isLetRec, v, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))))(isDecl, N)) case c => asc match { case S(ty) => @@ -447,14 +447,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D R(NuFunDef(isLetRec, v, tparams, R(PolyType(Nil, ps.foldRight(ty)((p, r) => Function(p.toType match { case L(diag) => raise(diag); Top // TODO better case R(tp) => tp - }, r)))))(isDecl)) // TODO rm PolyType after FCP is merged + }, r)))))(isDecl, N)) // TODO rm PolyType after FCP is merged case N => // TODO dedup: val (tkstr, loc) = c.headOption.fold(("end of input", lastLoc))(_.mapFirst(_.describe).mapSecond(some)) err(( msg"Expected ':' or '=' followed by a function body or signature; found ${tkstr} instead" -> loc :: Nil)) consume - R(NuFunDef(isLetRec, v, Nil, L(ps.foldRight(errExpr: Term)((i, acc) => Lam(i, acc))))(isDecl)) + R(NuFunDef(isLetRec, v, Nil, L(ps.foldRight(errExpr: Term)((i, acc) => Lam(i, acc))))(isDecl, N)) } } } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 89b9e97715..4286107d7b 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -27,11 +27,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind def level: Level + protected def withLevel[R](k: Ctx => R)(implicit ctx: Ctx): R = k(ctx.copy(lvl = level + 1)) + /** Used in inheritance processing, for parent types. */ def freshen(implicit ctx: Ctx): NuMember = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty - ctx.copy(lvl = level + 1) |> { implicit ctx => + withLevel { implicit ctx => freshenAbove(level, rigidify = false) } } @@ -118,7 +120,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def decl: NuTypeDef def tparams: TyParams - override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = + override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = withLevel { implicit ctx => this match { case m @ TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => TypedNuMxn(td, @@ -151,6 +153,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inheritedTags ) } + } val td: NuTypeDef val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) val level: Level @@ -358,10 +361,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - : TypedNuFun = this match { + : TypedNuFun = withLevel { implicit ctx => this match { case TypedNuFun(level, fd, ty) => TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) - } + }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -434,12 +437,31 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case decl: NuDecl => L(decl) case s => R(s) } + val funSigs = MutMap.empty[Str, NuFunDef] val implems = if (topLevel) decls else decls.filter { - case NuFunDef(N, nme, tparams, R(rhs)) => false // There will already be typed in DelayedTypeInfo + case fd @ NuFunDef(N, nme, tparams, R(rhs)) => + funSigs.updateWith(nme.name) { + case S(s) => + err(s"A type signature for '$nme' has already been given", fd.toLoc) + S(s) + case N => S(fd) + } + false // There will already be typed in DelayedTypeInfo case _ => true } val infos = implems.map { - case decl: NuDecl => + case _decl: NuDecl => + val decl = _decl match { + case fd: NuFunDef => + assert(fd.signature.isEmpty) + funSigs.get(fd.nme.name) match { + case S(sig) => + fd.copy()(fd.declareLoc, S(sig)) + case _ => + fd + } + case _ => _decl + } val lti = new DelayedTypeInfo(decl, implicitly) decl match { case td: NuTypeDef => @@ -448,7 +470,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } named.updateWith(decl.name) { case sv @ S(v) => - // * TODO allow defining a previously given signature decl match { case NuFunDef(S(_), _, _, _) => () case _ => @@ -670,47 +691,47 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => private lazy val thisTV: TV = freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) - def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : T = { - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty + def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : T = { + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty - val raw = info.asInstanceOf[T] - val rawName = v.name + val raw = info.asInstanceOf[T] + val rawName = v.name - if (raw.tparams.sizeCompare(parTargs.size) =/= 0) - err(msg"${if (raw.isInstanceOf[TypedNuTrt]) "trait" else "class"} $rawName expects ${ - raw.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) + if (raw.tparams.sizeCompare(parTargs.size) =/= 0) + err(msg"${if (raw.isInstanceOf[TypedNuTrt]) "trait" else "class"} $rawName expects ${ + raw.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) - raw.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => - val targ = typeType(targTy) - freshened += _tv -> (targ match { - case tv: TV => - // TODO - println(s"Passing ${_tv} <=< ${tv}") - tv - case _ => - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - tv - }) - - } + raw.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => + val targ = typeType(targTy) + freshened += _tv -> (targ match { + case tv: TV => + // TODO + println(s"Passing ${_tv} <=< ${tv}") + tv + case _ => + println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) - raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] // FIXME } + raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] // FIXME + } + def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { if (isComputing) { val ty = err(msg"Unhandled cyclic definition", decl.toLoc) // * Hacky: return a dummy decl to avoid possible infinite completion recursions - TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top))(N), ty) + TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top))(N, N), ty) } else trace(s"Completing ${decl.showDbg}") { println(s"Type params ${tparams.mkString(" ")}") @@ -722,7 +743,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case fd: NuFunDef => def checkNoTyParams() = if (fd.tparams.nonEmpty) - err(msg"Type parameters here are not yet supported in this position", + err(msg"Type parameters are not yet supported in this position", fd.tparams.head.toLoc) val res_ty = fd.rhs match { case R(PolyType(tps, ty)) => @@ -752,6 +773,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * In the future, we should type each mutual-recursion-component independently // * and polymorphically wrt to external uses of them. implicit val gl: GenLambdas = false + val outer_ctx = ctx val body_ty = ctx.nextLevel { implicit ctx: Ctx => // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods // * in the current typing unit are quantified together. @@ -760,7 +782,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => originName = S(tn.name), isType = true), N, S(tn.name)) } |> { implicit vars => - typeTerm(body) + // * Only type methods polymorphically if they're at the top level or if + // * they're annotated with a type signature. + // * Otherwise, we get too much extrusion and cycle check failures + // * especially in the context of open recursion and mixins. + if (ctx.lvl === 1 || fd.signature.nonEmpty) + typeTerm(body) + else outer_ctx |> { + println(s"Not typing polymorphicall (cf. not top level or not annotated)") + println(typedSignatureMembers) + implicit ctx: Ctx => typeTerm(body) } } }.withProv(TypeProvenance(fd.toLoc, s"definition of method ${fd.nme.name}")) TypedNuFun(ctx.lvl, fd, body_ty) @@ -890,7 +921,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case mxn: TypedNuMxn => if (mxnTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) - println(s"Fresh $mxn") + // println(s"Fresh $mxn") assert(finalType.level === lvl) assert(mxn.superTV.level === lvl) @@ -995,8 +1026,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if (pack.bsCls.isDefined) err(msg"cannot inherit from more than one base class: ${ pack.bsCls.get} and ${parNme}", v.toLoc) - + + // println(s"Raw $rawCls") val cls = refreshGen[TypedNuCls](info, v, parTargs) + // println(s"Fresh $cls") if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ @@ -1023,8 +1056,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) + // println(s"Raw $rawTrt") val trt = refreshGen[TypedNuTrt](info, v, parTargs) // FIXME - + // println(s"Fresh $trt") computeBaseClassTrait(ps, pack.copy( trtMem = memberUn(pack.trtMem, trt.members.values.toList) )) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 9686115c8d..cb5b4bfaf4 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1353,7 +1353,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) mkTypingUnit(thisTy, members))(td.declareLoc) } case tf @ TypedNuFun(level, fd, bodyTy) => - NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc) + NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc, fd.signature) case p: NuParam => ??? // TODO } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 0c27c2bbcf..1e1937351b 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -551,7 +551,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => override def toString: String = (trueOriginal match { case S(to) => - assert(to.nameHint === nameHint) + assert(to.nameHint === nameHint, (to.nameHint, nameHint)) to.mkStr + "_" + uid + showLevel(level) case N => showProvOver(false)(mkStr + showLevel(level)) diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 0c797ecd1c..be9cd29ab1 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -193,7 +193,7 @@ final case class NuFunDef( nme: Var, tparams: Ls[TypeName], rhs: Term \/ Type, -)(val declareLoc: Opt[Loc]) extends NuDecl with DesugaredStatement { +)(val declareLoc: Opt[Loc], val signature: Opt[NuFunDef]) extends NuDecl with DesugaredStatement { val body: Located = rhs.fold(identity, identity) def kind: DeclKind = Val } diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index cd5598694c..38f613ced2 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -295,9 +295,9 @@ mixin EvalNegNeg { else super.eval(e) } //│ mixin EvalNegNeg() { -//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b //│ } //│ // Prelude //│ class TypingUnit4 { @@ -352,10 +352,10 @@ mixin EvalNegNeg { :ShowRepl module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { -//│ fun eval: 'A -> int +//│ fun eval: 'a -> int //│ } //│ where -//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] +//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] //│ // Prelude //│ class TypingUnit5 { //│ #TestLang; diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index 09623fe14a..ca55b796a6 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -37,15 +37,15 @@ mixin EvalBase { module TestLang extends EvalBase //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where -//│ 'a <: Add['a] | Lit +//│ 'E <: Add['E] | Lit TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit) -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'E <: Add['E] | Lit //│ res //│ = [Function: eval] @@ -75,15 +75,15 @@ module TestLang extends EvalNothing, EvalAddLit //│ fun eval: (Add['lhs] | Lit | 'a & ~#Add & ~#Lit) -> (int | 'b) //│ } //│ module TestLang() { -//│ fun eval: 'c -> int +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where -//│ 'c <: Add['c] | Lit +//│ 'E <: Add['E] | Lit TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit) -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'E <: Add['E] | Lit //│ res //│ = [Function: eval] @@ -116,15 +116,17 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'expr <: Neg['expr] | 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit TestLang.eval -//│ 'a -> int +//│ (Neg['expr] | 'a & ~#Neg) -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'expr <: Neg['expr] | 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit //│ res //│ = [Function: eval] @@ -174,9 +176,9 @@ mixin EvalNegNeg_0 { // else super.eval(e) } //│ mixin EvalNegNeg_0() { -//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b //│ } // * Concise alternative, usign syntax sugar: @@ -184,17 +186,17 @@ mixin EvalNegNeg { fun eval(override Neg(Neg(d))) = this.eval(d) } //│ mixin EvalNegNeg() { -//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b //│ } module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { -//│ fun eval: 'A -> int +//│ fun eval: 'a -> int //│ } //│ where -//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] +//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] fun mk(n) = if n is 0 then Lit(0) @@ -205,9 +207,9 @@ fun mk(n) = if n is //│ 'E :> Add['E] | Lit | Neg['E] TestLang.eval -//│ 'A -> int +//│ 'a -> int //│ where -//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] +//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] //│ res //│ = [Function: eval] diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index b659ebde50..a3e07bc467 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -17,7 +17,7 @@ mixin ComparePoint { (lhs.x === rhs.x) && (lhs.y === rhs.y) } //│ mixin ComparePoint() { -//│ fun compare: forall 'a 'b. ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b},) -> bool +//│ fun compare: ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b},) -> bool //│ } @@ -40,7 +40,7 @@ mixin CompareColored { } //│ mixin CompareColored() { //│ super: {compare: ('a, 'b,) -> bool} -//│ fun compare: forall 'color. ({color: {equals: 'color -> bool}} & 'a, {color: 'color} & 'b,) -> bool +//│ fun compare: ({color: {equals: 'color -> bool}} & 'a, {color: 'color} & 'b,) -> bool //│ } diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 841ae4ddb6..6d95c90181 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -41,7 +41,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: forall 'result. (Cons[{_1: string, _2: 'result}] | Nil, Var,) -> (Var | 'result) +//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, Var,) -> (Var | 'result) //│ } class Abs[A](x: string, t: A) @@ -73,123 +73,120 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b,) -> 'c} -//│ this: {eval: ('a, 's,) -> ('d & 'e) & (Cons[(string, 'e,)], 't,) -> 'c & (Cons[(string, Var,) | 'A], 't0,) -> 'f} -//│ fun eval: ('a & (Cons['A] | Nil), Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['f] | App['d | 'e] | 'c) +//│ this: {eval: ('a, 's,) -> ('A & 'd) & (Cons[(string, 'd,)], 't,) -> 'c & (Cons[(string, Var,) | 'A0], 't0,) -> 'A1} +//│ fun eval: ('a & (Cons['A0] | Nil), Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['A1] | App['A] | 'c) //│ } // FIXME type simplification :ns module Test1 extends EvalVar, EvalLambda //│ module Test1() { -//│ fun eval: ('a, 'b,) -> ('c | 'd | 'e | 'f) +//│ fun eval: forall 'A 'A0 'a 'b 'c. ('d, 'a,) -> ('e | 'c | 'b | 'f) //│ } //│ where -//│ 'b <: #App & {App#A <: 'A} | (#Abs & {Abs#A <: 'A0} | 'g & ~#Abs) & ~#App -//│ 'g <: 'h -//│ 'h <: 'i -//│ 'i <: #Var -//│ 'A0 <: 't -//│ 't <: 't0 -//│ 't0 <: 'b -//│ 'A <: 't1 & 's -//│ 's <: (#Abs & {Abs#A <: 'A1} | 'j & ~#Abs) & 's0 -//│ 's0 <: 'b -//│ 'A1 <: 't2 -//│ 't2 <: 't3 -//│ 't3 <: 'b -//│ 't1 <: 't4 -//│ 't4 <: 'b -//│ 'a :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} -//│ <: 'k & (Cons['A6] | Nil) & 'l & 'm -//│ 'm :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} -//│ <: 'a -//│ 'l :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} -//│ <: 'a -//│ 'A6 :> 'A7 & 'A3 | 'A8 & 'A5 | 'A4 | ('x, 'n,) -//│ <: ('A7 | 'A2) & ('A8 | 'A4) & 'A5 -//│ 'A8 := in 'A4 out 'A5 -//│ 'k :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} +//│ 'b :> #Abs & {Abs#A = 'A1} +//│ 'c :> #App & {App#A = 'A2} +//│ 'a <: #App & {App#A <: 'A0} | (#Abs & {Abs#A <: 'A} | 'g & ~#Abs) & ~#App +//│ 'A <: 't +//│ 'A0 <: 't0 & 's +//│ 't0 <: 'h +//│ 'h <: #App & {App#A <: 'A3} | (#Abs & {Abs#A <: 'A4} | 'g & ~#Abs) & ~#App +//│ 'A4 <: 't +//│ 'A3 <: 't0 & 's +//│ 's <: 'i & (#Abs & {Abs#A <: 'A5} | 'j & ~#Abs) +//│ 'A5 <: 't1 +//│ 't1 <: 'k +//│ 'k <: #App & {App#A <: 'A6} | (#Abs & {Abs#A <: 'A7} | 'g & ~#Abs) & ~#App +//│ 'A7 <: 't +//│ 'A6 <: 't0 & 's +//│ 'i <: #App & {App#A <: 'A8} | (#Abs & {Abs#A <: 'A9} | 'g & ~#Abs) & ~#App +//│ 'A9 <: 't +//│ 't <: 'l +//│ 'l <: #App & {App#A <: 'A10} | (#Abs & {Abs#A <: 'A11} | 'g & ~#Abs) & ~#App +//│ 'g <: 'm +//│ 'm <: #Var +//│ 'A11 <: 't +//│ 'A10 <: 't0 & 's +//│ 'A8 <: 't0 & 's +//│ 'd :> #Cons & {Cons#A = 'A12} | #Cons & {Cons#A = 'A13} +//│ <: 'n & (Cons['A13] | Nil) +//│ 'n :> #Cons & {Cons#A = 'A12} | #Cons & {Cons#A = 'A13} //│ <: 'o -//│ 'o :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} -//│ <: 'p -//│ 'p :> #Cons & {Cons#A :> 'A2 <: 'A3} | #Cons & {Cons#A :> 'A4 <: 'A5} | Cons['A9] | Nil -//│ <: #Cons & {Cons#A <: 'A10} | #Nil & ~#Cons -//│ 'A9 := out 'A10 -//│ 'A10 :> 'A11 & 'A3 | 'A12 & 'A5 +//│ 'o :> #Cons & {Cons#A = 'A12} | #Cons & {Cons#A = 'A13} | Cons['A14] | Nil +//│ <: #Cons & {Cons#A <: 'A15} | #Nil & ~#Cons +//│ 'A14 := out 'A15 +//│ 'A12 :> ('x, 'p,) | ('x0, 'q,) +//│ <: 'A13 & 'A15 +//│ 'A13 :> ('x, 'p,) | ('x0, 'q,) +//│ <: 'A12 & 'A15 +//│ 'A15 :> ('x0, 'q,) | ('x, 'p,) //│ <: 'head -//│ 'head :> 'A11 & 'A3 | 'A12 & 'A5 -//│ <: {_2: 'q} & {_1: 'r} -//│ 'A12 := in 'A4 out 'A5 -//│ 'A11 := in 'A2 out 'A3 -//│ 'A5 :> 'A7 & 'A3 | 'A4 | ('x0, 'u,) -//│ <: 'A2 & {_1: 'r} & {_2: 'q} -//│ 'A2 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | ('x, 'n,) & {_2: 'n, _1: 'x} | ('x1, 'v,) | 'A7 & 'A3 -//│ <: 'A4 & {_1: 'r} & {_2: 'q} -//│ 'A7 := in 'A2 out 'A3 -//│ 'A3 :> 'A2 | ('x1, 'v,) -//│ <: 'A4 & {_1: 'r} & {_2: 'q} -//│ 'A4 :> ('x1, 'v,) & {_2: 'v, _1: 'x1} | ('x0, 'u,) & {_2: 'u, _1: 'x0} | ('x0, 'u,) | 'A7 & 'A3 | ('x1, 'v,) | ('x, 'n,) & {_2: 'n, _1: 'x} -//│ <: ('A7 | 'A2) & 'A2 & {_1: 'r} & {_2: 'q} -//│ 'n :> #Var -//│ <: 'u -//│ 'x :> string -//│ <: 'x0 -//│ 'u :> #Var -//│ <: 'q +//│ 'head :> ('x0, 'q,) | ('x, 'p,) +//│ <: {_2: 'r} & {_1: 'u} +//│ 'q :> forall 'v 'w. 'e | 'v | 'w | 'f +//│ <: 'r & 'A2 //│ 'x0 :> string -//│ <: 'r -//│ 'v :> 'w -//│ <: 'q -//│ 'w :> 'c | 'd | 'e | 'f -//│ <: 'q -//│ 'q :> 'c | 'd | 'e | 'f | #Var -//│ <: 'A13 -//│ 'A13 :> 'c | 'd | 'e | 'f | #Var -//│ <: 'A14 -//│ 'A14 :> 'c | 'd | 'e | 'f | #Var +//│ <: 'u +//│ 'p :> #Var +//│ <: 'r +//│ 'r :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var +//│ <: 'A16 +//│ 'A16 :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var +//│ <: 'A17 +//│ 'A17 :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var //│ <: 'result -//│ 'c :> 'y -//│ 'y :> 'c | 'd | 'e | 'f -//│ 'd :> #App & {App#A = 'A15} -//│ 'A15 :> 'w | 'z -//│ 'z :> 'c | 'd | 'e | 'f -//│ 'e :> #Abs & {Abs#A = 'A16} -//│ 'A16 :> 'a1 -//│ 'a1 :> 'c | 'd | 'e | 'f -//│ 'f :> 'b1 -//│ 'b1 :> #Var | 'result -//│ 'result :> 'c | 'd | 'e | 'f | #Var -//│ 'x1 :> string -//│ <: 'r -//│ 'r :> string -//│ <: 'c1 -//│ 'c1 := string +//│ 'e :> forall 'y 'z. 'e | 'y | 'z | 'f +//│ 'z :> #Abs & {Abs#A = 'A1} +//│ 'y :> #App & {App#A = 'A2} +//│ 'A2 :> (forall 'a1 'b1. 'e | 'a1 | 'b1 | 'f) | (forall 'v 'w. 'e | 'v | 'w | 'f) +//│ 'b1 :> #Abs & {Abs#A = 'A1} +//│ 'A1 :> forall 'c1 'd1. 'e | 'c1 | 'd1 | 'f +//│ 'f :> #Var | 'result +//│ 'result :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var +//│ 'w :> #Abs & {Abs#A = 'A1} +//│ 'v :> #App & {App#A = 'A2} +//│ 'd1 :> #Abs & {Abs#A = 'A1} +//│ 'c1 :> #App & {App#A = 'A2} +//│ 'a1 :> #App & {App#A = 'A2} +//│ 'x :> string +//│ <: 'u +//│ 'u :> string +//│ <: 'e1 +//│ 'e1 := string Test1.eval(Nil, Var("a")) -//│ 'a +//│ forall 'a. 'b | 'a | 'c //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> forall 'a. Var | 'b | 'a //│ res //│ = Var {} Test1.eval(Nil, Abs("b", Var("a"))) -//│ 'a +//│ forall 'a. 'b | 'a | 'c //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> forall 'a. Var | 'b | 'a //│ res //│ = Abs {} Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) -//│ 'a +//│ forall 'a. 'b | 'a | 'c //│ where -//│ 'a :> App['a] | Abs['a] | Var +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> forall 'a. Var | 'b | 'a //│ res //│ = Var {} Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) -//│ 'a +//│ forall 'a. 'b | 'a | 'c //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> forall 'a. Abs[Var] | Var | 'b | 'a //│ res //│ = Var {} @@ -206,7 +203,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'A 'l 'A0 'l0. ('l -> 'A0 & 'l0 -> 'A, Add['l] | Mul['l0] | Num | Var,) -> (Add['A0] | Mul['A] | Num | Var) +//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) mixin EvalExpr { fun eval(sub, v) = @@ -221,16 +218,15 @@ mixin EvalExpr { //│ mixin EvalExpr() { //│ super: {eval: ('a, Var,) -> 'b} //│ this: {eval: ('a, 'c,) -> anything} -//│ fun eval: forall 'd. ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) +//│ fun eval: ('a, 'b & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'b) //│ } module Test2 extends EvalVar, EvalExpr //│ module Test2() { -//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> (Num | Var | 'result | 'a) +//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'result}] | Nil, 'a & (Add['b] | Mul['b] | Num | Var),) -> (Num | Var | 'result | 'a) //│ } //│ where -//│ 'a <: Add['b] | Mul['b] | Num | Var -//│ 'b <: 'a +//│ 'b <: Add['b] | Mul['b] | Num | Var Test2.eval(Nil, Var("a")) //│ Num | Var @@ -251,16 +247,16 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.252: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.248: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.252: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.248: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.204: if v is +//│ ║ l.201: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.214: let vv = map_expr(eta, v) +//│ ║ l.211: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -276,135 +272,118 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) :ns module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: ('a, 'b,) -> ('c | 'd | 'e | 'f) +//│ fun eval: forall 'A 'A0 'a 'b 'c. ('d, 'a,) -> ('e | 'b | 'c | 'f) //│ } //│ where -//│ 'a :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'g & (Cons['A3] | Nil) & 'h & 'i -//│ 'i :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'a -//│ 'h :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'a -//│ 'A3 :> 'A4 & 'A0 | 'A5 & 'A2 | 'A1 | ('x, 'j,) -//│ <: ('A4 | 'A) & ('A5 | 'A1) & 'A2 -//│ 'A5 := in 'A1 out 'A2 -//│ 'g :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'k -//│ 'k :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'm & 'n -//│ 'n :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'a -//│ 'm :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'o -//│ 'o :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'p -//│ 'p :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} | Cons['A6] | Nil -//│ <: #Cons & {Cons#A <: 'A7} | #Nil & ~#Cons -//│ 'A6 := out 'A7 -//│ 'A7 :> 'A8 & 'A0 | 'A9 & 'A2 +//│ 'c :> #Abs & {Abs#A = 'A1} +//│ 'b :> #App & {App#A = 'A2} +//│ 'a <: #App & {App#A <: 'A0} | (#Abs & {Abs#A <: 'A} | 'g & ~#Abs) & ~#App +//│ 'A <: 't +//│ 'A0 <: 't0 & 's +//│ 'd :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} +//│ <: 'h & (Cons['A4] | Nil) +//│ 'h :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} +//│ <: 'd & 'i +//│ 'i :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} +//│ <: 'j +//│ 'j :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} | Cons['A5] | Nil +//│ <: #Cons & {Cons#A <: 'A6} | #Nil & ~#Cons +//│ 'A5 := out 'A6 +//│ 'A3 :> ('x, 'k,) | ('x0, 'm,) +//│ <: 'A4 & 'A6 +//│ 'A4 :> ('x, 'k,) | ('x0, 'm,) +//│ <: 'A3 & 'A6 +//│ 'A6 :> ('x0, 'm,) | ('x, 'k,) //│ <: 'head -//│ 'head :> 'A8 & 'A0 | 'A9 & 'A2 -//│ <: {_2: 'q} & {_1: 'u} -//│ 'A9 := in 'A1 out 'A2 -//│ 'A8 := in 'A out 'A0 -//│ 'A2 :> 'A4 & 'A0 | 'A1 | ('x0, 'v,) -//│ <: 'A & {_1: 'u} & {_2: 'q} -//│ 'A :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | ('x, 'j,) & {_2: 'j, _1: 'x} | ('x1, 'w,) | 'A4 & 'A0 -//│ <: 'A1 & {_1: 'u} & {_2: 'q} -//│ 'A4 := in 'A out 'A0 -//│ 'A0 :> 'A | ('x1, 'w,) -//│ <: 'A1 & {_1: 'u} & {_2: 'q} -//│ 'A1 :> ('x1, 'w,) & {_2: 'w, _1: 'x1} | ('x0, 'v,) & {_2: 'v, _1: 'x0} | ('x0, 'v,) | 'A4 & 'A0 | ('x1, 'w,) | ('x, 'j,) & {_2: 'j, _1: 'x} -//│ <: ('A4 | 'A) & 'A & {_1: 'u} & {_2: 'q} -//│ 'j :> #Var -//│ <: 'v -//│ 'x :> string -//│ <: 'x0 -//│ 'v :> #Var -//│ <: 'q +//│ 'head :> ('x0, 'm,) | ('x, 'k,) +//│ <: {_2: 'n} & {_1: 'o} +//│ 'm :> forall 'p 'q. 'e | 'p | 'q | 'f +//│ <: 'n & 'A2 //│ 'x0 :> string -//│ <: 'u -//│ 'w :> 'y -//│ <: 'q -//│ 'y :> 'c | 'd | 'e | 'f -//│ <: 'q -//│ 'q :> 'c | 'd | 'e | 'f | #Var -//│ <: 'A10 -//│ 'A10 :> 'c | 'd | 'e | 'f | #Var -//│ <: 'A11 -//│ 'A11 :> 'c | 'd | 'e | 'f | #Var -//│ <: 'result -//│ 'c :> 'z -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'z :> 'c | 'd | 'e | 'f -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'd :> #App & {App#A = 'A12} -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'A12 :> 'y | 'e1 -//│ 'e1 :> 'c | 'd | 'e | 'f -//│ 'e :> #Abs & {Abs#A = 'A13} -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'A13 :> 'f1 -//│ 'f1 :> 'c | 'd | 'e | 'f -//│ 'f :> 'g1 -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'g1 :> 'h1 | 'i1 | 'j1 | 'k1 -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'k1 :> #Num -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'j1 <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) & 'l1 -//│ 'l1 <: #Var | (#Num | (#Add & {Add#A <: 'A14} | #Mul & {Mul#A <: 'A15} & ~#Add) & ~#Num) & ~#Var -//│ 'A15 <: 'r & 'l -//│ 'l <: 'm1 -//│ 'r <: 'm1 -//│ 'A14 <: 'r0 & 'l0 -//│ 'l0 <: 'm1 -//│ 'r0 <: 'm1 -//│ 'm1 <: 'n1 -//│ 'n1 <: 'b -//│ 'b <: #App & {App#A <: 'A16} | (#Abs & {Abs#A <: 'A17} | 'o1 & ~#Abs) & ~#App -//│ 'o1 <: 'p1 -//│ 'p1 <: 'j1 +//│ <: 'o +//│ 'k :> #Var +//│ <: 'n +//│ 'n :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var +//│ <: 'A7 +//│ 'A7 :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var +//│ <: 'A8 +//│ 'A8 :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var +//│ <: 'result +//│ 'e :> forall 'u 'v. 'e | 'u | 'v | 'f +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'v :> #Abs & {Abs#A = 'A1} +//│ 'u :> #App & {App#A = 'A2} +//│ 'A2 :> (forall 'b1 'c1. 'e | 'b1 | 'c1 | 'f) | (forall 'p 'q. 'e | 'p | 'q | 'f) +//│ 'c1 :> #Abs & {Abs#A = 'A1} +//│ 'A1 :> forall 'd1 'e1. 'e | 'd1 | 'e1 | 'f +//│ 'f :> forall 'f1 'g1. 'h1 | 'f1 | 'i1 | 'g1 +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'g1 :> #Num +//│ 'i1 <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & 'j1 +//│ 'j1 <: #Var | (#Num | (#Add & {Add#A <: 'A9} | #Mul & {Mul#A <: 'A10} & ~#Add) & ~#Num) & ~#Var +//│ 'A10 <: 'r & 'l +//│ 'l <: 'k1 +//│ 'r <: 'k1 +//│ 'A9 <: 'r0 & 'l0 +//│ 'l0 <: 'k1 +//│ 'r0 <: 'k1 +//│ 'k1 <: 'l1 +//│ 'l1 <: #App & {App#A <: 'A11} | (#Abs & {Abs#A <: 'A12} | 'g & ~#Abs) & ~#App +//│ 'A12 <: 't +//│ 'A11 <: 't0 & 's +//│ 't0 <: 'm1 +//│ 'm1 <: #App & {App#A <: 'A13} | (#Abs & {Abs#A <: 'A14} | 'g & ~#Abs) & ~#App +//│ 'A14 <: 't +//│ 'A13 <: 't0 & 's +//│ 's <: 'n1 & (#Abs & {Abs#A <: 'A15} | 'o1 & ~#Abs) +//│ 'A15 <: 't1 +//│ 't1 <: 'p1 +//│ 'p1 <: #App & {App#A <: 'A16} | (#Abs & {Abs#A <: 'A17} | 'g & ~#Abs) & ~#App //│ 'A17 <: 't -//│ 't <: 't0 -//│ 't0 <: 'b -//│ 'A16 <: 't1 & 's -//│ 's <: (#Abs & {Abs#A <: 'A18} | 'q1 & ~#Abs) & 's0 -//│ 's0 <: 'b -//│ 'A18 <: 't2 -//│ 't2 <: 't3 -//│ 't3 <: 'b -//│ 't1 <: 't4 -//│ 't4 <: 'b -//│ 'i1 :> #Num -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'h1 :> 'r1 -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'r1 :> #Var | 'result -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'result :> 'c | 'd | 'e | 'f | #Var -//│ <: (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & (#Num | 'c1 & ~#Num) & (#Num | 'd1 & ~#Num) -//│ 'd1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} -//│ 'c1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} -//│ 'b1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} -//│ 'a1 :> #Var | #Abs & {Abs#A = 'A13} | #App & {App#A = 'A12} -//│ 'x1 :> string -//│ <: 'u -//│ 'u :> string -//│ <: 's1 -//│ 's1 := string +//│ 'A16 <: 't0 & 's +//│ 'n1 <: #App & {App#A <: 'A18} | (#Abs & {Abs#A <: 'A19} | 'g & ~#Abs) & ~#App +//│ 'A19 <: 't +//│ 't <: 'q1 +//│ 'q1 <: #App & {App#A <: 'A20} | (#Abs & {Abs#A <: 'A21} | 'g & ~#Abs) & ~#App +//│ 'g <: 'i1 +//│ 'A21 <: 't +//│ 'A20 <: 't0 & 's +//│ 'A18 <: 't0 & 's +//│ 'f1 :> #Num +//│ 'h1 :> #Var | 'result +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'result :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var +//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) +//│ 'a1 :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} +//│ 'z :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} +//│ 'y :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} +//│ 'w :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} +//│ 'q :> #Abs & {Abs#A = 'A1} +//│ 'p :> #App & {App#A = 'A2} +//│ 'e1 :> #Abs & {Abs#A = 'A1} +//│ 'd1 :> #App & {App#A = 'A2} +//│ 'b1 :> #App & {App#A = 'A2} +//│ 'x :> string +//│ <: 'o +//│ 'o :> string +//│ <: 'r1 +//│ 'r1 := string Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) -//│ 'a +//│ forall 'a. 'b | 'a | 'c //│ where -//│ 'a :> Abs['a] | Abs[Var] | Num | Var | App['a] +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> Abs[Var] | Num | Var | 'b //│ res //│ = Abs {} Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) -//│ 'a +//│ forall 'a. 'b | 'a | 'c //│ where -//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Num | Var] | Num | Var +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> Abs[Var] | Add[Num | Var] | Num | Var | 'b //│ res //│ = Var {} @@ -413,129 +392,138 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: ('a, 'b,) -> ('c | 'd | 'b | 'e) +//│ fun eval: forall 'a 'r 'b 'r0 'c 'l 'd 'A 'A0 'l0. ('e, 'd,) -> ('f | 'c | 'd | 'b) //│ } //│ where -//│ 'a :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'f & 'g -//│ 'g :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'a -//│ 'f :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} +//│ 'b :> #Num +//│ 'c :> #Num +//│ 'd <: 'a +//│ 'a <: #Var | (#Num | (#Add & {Add#A <: 'A0} | #Mul & {Mul#A <: 'A} & ~#Add) & ~#Num) & ~#Var +//│ 'A <: 'r & 'l0 +//│ 'l0 <: 'g +//│ 'r <: 'g +//│ 'A0 <: 'r0 & 'l +//│ 'l <: 'g +//│ 'r0 <: 'g +//│ 'e :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} //│ <: 'h -//│ 'h :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'i & (Cons['A3] | Nil) & 'j & 'k -//│ 'k :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'a -//│ 'j :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'a -//│ 'A3 :> 'A4 & 'A0 | 'A5 & 'A2 | 'A1 | ('x, 'm,) -//│ <: ('A4 | 'A) & ('A5 | 'A1) & 'A2 -//│ 'A5 := in 'A1 out 'A2 -//│ 'i :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'n -//│ 'n :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} -//│ <: 'o -//│ 'o :> #Cons & {Cons#A :> 'A <: 'A0} | #Cons & {Cons#A :> 'A1 <: 'A2} | Cons['A6] | Nil -//│ <: #Cons & {Cons#A <: 'A7} | #Nil & ~#Cons -//│ 'A6 := out 'A7 -//│ 'A7 :> 'A8 & 'A0 | 'A9 & 'A2 +//│ 'h :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} +//│ <: 'e & 'i & (Cons['A2] | Nil) +//│ 'i :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} +//│ <: 'j +//│ 'j :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} | Cons['A3] | Nil +//│ <: #Cons & {Cons#A <: 'A4} | #Nil & ~#Cons +//│ 'A3 := out 'A4 +//│ 'A1 :> ('x, 'k,) | ('x0, 'm,) +//│ <: 'A2 & 'A4 +//│ 'A2 :> ('x, 'k,) | ('x0, 'm,) +//│ <: 'A1 & 'A4 +//│ 'A4 :> ('x0, 'm,) | ('x, 'k,) //│ <: 'head -//│ 'head :> 'A8 & 'A0 | 'A9 & 'A2 -//│ <: {_2: 'p} & {_1: 'q} -//│ 'A9 := in 'A1 out 'A2 -//│ 'A8 := in 'A out 'A0 -//│ 'A2 :> 'A4 & 'A0 | 'A1 | ('x0, 's,) -//│ <: 'A & {_1: 'q} & {_2: 'p} -//│ 'A :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | ('x, 'm,) & {_2: 'm, _1: 'x} | ('x1, 't,) | 'A4 & 'A0 -//│ <: 'A1 & {_1: 'q} & {_2: 'p} -//│ 'A4 := in 'A out 'A0 -//│ 'A0 :> 'A | ('x1, 't,) -//│ <: 'A1 & {_1: 'q} & {_2: 'p} -//│ 'A1 :> ('x1, 't,) & {_2: 't, _1: 'x1} | ('x0, 's,) & {_2: 's, _1: 'x0} | ('x0, 's,) | 'A4 & 'A0 | ('x1, 't,) | ('x, 'm,) & {_2: 'm, _1: 'x} -//│ <: ('A4 | 'A) & 'A & {_1: 'q} & {_2: 'p} -//│ 'm :> #Var -//│ <: 's -//│ 'x :> string -//│ <: 'x0 -//│ 's :> #Var -//│ <: 'p +//│ 'head :> ('x0, 'm,) | ('x, 'k,) +//│ <: {_2: 'n} & {_1: 'o} +//│ 'm :> forall 'p 'q. 'f | 'p | 's | 'q +//│ <: 'n & 'A5 //│ 'x0 :> string -//│ <: 'q -//│ 't :> 'u -//│ <: 'p -//│ 'u :> 'c | 'd | 'b | 'e -//│ <: 'p -//│ 'p :> 'c | 'd | 'b | 'e | #Var -//│ <: 'A10 -//│ 'A10 :> 'c | 'd | 'b | 'e | #Var -//│ <: 'A11 -//│ 'A11 :> 'c | 'd | 'b | 'e | #Var -//│ <: 'result -//│ 'c :> 'v -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'v :> 'b1 | 'c1 | 'd1 | 'e1 -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'e1 :> 'f1 -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'f1 :> #Var | 'result -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'result :> 'c | 'd | 'b | 'e | #Var -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'd1 :> #Abs & {Abs#A = 'A12} -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'c1 :> #App & {App#A = 'A13} -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'b1 :> 'g1 -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'g1 :> 'c | 'd | 'b | 'e -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'd :> #Num -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'w :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} -//│ 'A12 :> 'h1 -//│ 'h1 :> 'c | 'd | 'b | 'e -//│ 'b <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & 'i1 -//│ 'i1 <: #Var | (#Num | (#Add & {Add#A <: 'A14} | #Mul & {Mul#A <: 'A15} & ~#Add) & ~#Num) & ~#Var -//│ 'A15 <: 'r & 'l -//│ 'l <: 'j1 -//│ 'r <: 'j1 -//│ 'A14 <: 'r0 & 'l0 -//│ 'l0 <: 'j1 -//│ 'r0 <: 'j1 -//│ 'j1 <: 'k1 -//│ 'k1 <: 'b -//│ 'y :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} -//│ 'A13 :> 'u | 'l1 -//│ 'l1 :> 'c | 'd | 'b | 'e -//│ 'e :> #Num -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'a1 :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} -//│ 'z :> #Var | #Abs & {Abs#A = 'A12} | #App & {App#A = 'A13} -//│ 'x1 :> string -//│ <: 'q -//│ 'q :> string -//│ <: 'm1 -//│ 'm1 := string +//│ <: 'o +//│ 'k :> #Var +//│ <: 'n +//│ 'n :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var +//│ <: 'A6 +//│ 'A6 :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var +//│ <: 'A7 +//│ 'A7 :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var +//│ <: 'result +//│ 'f :> forall 't 'u. 'v | 't | 'u | 'w +//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) +//│ 'w :> #Var | 'result +//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) +//│ 'result :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var +//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) +//│ 'u :> #Abs & {Abs#A = 'A8} +//│ 't :> #App & {App#A = 'A5} +//│ 'v :> forall 'c1 'd1. 'f | 'c1 | 'e1 | 'd1 +//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) +//│ 'd1 :> #Num +//│ 'e1 <: (#Num | 'b1 & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'y & ~#Num) & 'f1 +//│ 'f1 <: #Var | (#Num | (#Add & {Add#A <: 'A9} | #Mul & {Mul#A <: 'A10} & ~#Add) & ~#Num) & ~#Var +//│ 'A10 <: 'r1 & 'l1 +//│ 'l1 <: 'g +//│ 'r1 <: 'g +//│ 'A9 <: 'r2 & 'l2 +//│ 'l2 <: 'g +//│ 'r2 <: 'g +//│ 'b1 :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} +//│ 'A8 :> forall 'g1 'h1. 'f | 'g1 | 'i1 | 'h1 +//│ 'h1 :> #Num +//│ 'i1 <: 'j1 +//│ 'j1 <: #Var | (#Num | (#Add & {Add#A <: 'A11} | #Mul & {Mul#A <: 'A12} & ~#Add) & ~#Num) & ~#Var +//│ 'A12 <: 'r3 & 'l3 +//│ 'l3 <: 'g +//│ 'r3 <: 'g +//│ 'A11 <: 'r4 & 'l4 +//│ 'l4 <: 'g +//│ 'r4 <: 'g +//│ 'g <: 'k1 +//│ 'k1 <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & 'l1 +//│ 'l1 <: #Var | (#Num | (#Add & {Add#A <: 'A13} | #Mul & {Mul#A <: 'A14} & ~#Add) & ~#Num) & ~#Var +//│ 'A14 <: 'r5 & 'l5 +//│ 'l5 <: 'g +//│ 'r5 <: 'g +//│ 'A13 <: 'r6 & 'l6 +//│ 'l6 <: 'g +//│ 'r6 <: 'g +//│ 'y :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} +//│ 'A5 :> (forall 'm1 'n1. 'f | 'm1 | 'o1 | 'n1) | (forall 'p 'q. 'f | 'p | 's | 'q) +//│ 'q :> #Num +//│ 's <: (#Num | 'b1 & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'y & ~#Num) & 'p1 +//│ 'p1 <: #Var | (#Num | (#Add & {Add#A <: 'A15} | #Mul & {Mul#A <: 'A16} & ~#Add) & ~#Num) & ~#Var +//│ 'A16 <: 'r7 & 'l7 +//│ 'l7 <: 'g +//│ 'r7 <: 'g +//│ 'A15 <: 'r8 & 'l8 +//│ 'l8 <: 'g +//│ 'r8 <: 'g +//│ 'z :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} +//│ 'a1 :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} +//│ 'p :> #Num +//│ 'n1 :> #Num +//│ 'o1 <: 'q1 +//│ 'q1 <: #Var | (#Num | (#Add & {Add#A <: 'A17} | #Mul & {Mul#A <: 'A18} & ~#Add) & ~#Num) & ~#Var +//│ 'A18 <: 'r9 & 'l9 +//│ 'l9 <: 'g +//│ 'r9 <: 'g +//│ 'A17 <: 'r10 & 'l10 +//│ 'l10 <: 'g +//│ 'r10 <: 'g +//│ 'm1 :> #Num +//│ 'g1 :> #Num +//│ 'c1 :> #Num +//│ 'x :> string +//│ <: 'o +//│ 'o :> string +//│ <: 'r1 +//│ 'r1 := string // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.523: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.511: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.523: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.511: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.204: if v is +//│ ║ l.201: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.214: let vv = map_expr(eta, v) +//│ ║ l.211: let vv = map_expr(eta, v) //│ ╙── ^ -//│ error | 'a +//│ Abs[Var] | error | 'a //│ where -//│ 'a :> Abs['a] | App['a] | Var | Abs[Var] | Num +//│ 'a :> Abs[Num | 'a] | App[Num | 'a] | Num | Var //│ res //│ Runtime error: //│ Error: non-exhaustive case expression diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 7296b2a7e2..d25a8e8981 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -82,10 +82,11 @@ mixin SizeExt { module TestSize extends SizeBase, SizeExt //│ module TestSize() { -//│ fun size: 'a -> int +//│ fun size: (Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ) -> int //│ } //│ where -//│ 'a <: Circle | Empty | Intersect['a] | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ +//│ 'a <: Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ +//│ 'b <: Circle | Intersect[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] // TODO investigate :re @@ -134,10 +135,13 @@ mixin Contains { module TestContains extends Contains //│ module TestContains() { -//│ fun contains: ('a, {x: int, y: int},) -> bool +//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: int, y: int},) -> bool //│ } //│ where -//│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] +//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] // TODO investigate :re @@ -180,23 +184,23 @@ mixin Text { Translate then concat("a translated region of size ", toString(this.size(e))) } //│ mixin Text() { -//│ this: {size: (Intersect['Region] | Translate['Region0] | Union['Region1] | 'a) -> int} -//│ fun text: (Circle | Intersect['Region] | Outside['a] | Translate['Region0] | Union['Region1]) -> string +//│ this: {size: (Intersect[nothing] | Translate['Region] | Union[nothing] | 'a) -> int} +//│ fun text: (Circle | Intersect[anything] | Outside['a] | Translate['Region] | Union[anything]) -> string //│ } :e module SizeText extends Text -//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.180: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?a -> (?d | ?e | ?c | ?b | ?f)}` does not contain member `size` +//│ ║ l.184: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.179: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?a | ?f | ?b | ?d | ?c)}` does not contain member `size` +//│ ║ l.183: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.178: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?a | ?b | ?c | ?f | ?d)}` does not contain member `size` +//│ ║ l.182: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` -//│ ║ l.177: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?c -> (?f | ?e | ?d | ?a | ?b)}` does not contain member `size` +//│ ║ l.181: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText() { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -205,15 +209,14 @@ module SizeText extends Text // * Note: this inferred type got *much worse* after this commit (field access type refinement) module SizeText extends SizeBase, Text //│ module SizeText() { -//│ fun size: 'a -> int -//│ fun text: (Circle | Intersect[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]] | Outside['a] | Translate[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]] | Union[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]]) -> string +//│ fun size: (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]) -> int +//│ fun text: (Circle | Intersect[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Outside[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Translate[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Union[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]]) -> string //│ } //│ where -//│ 'a <: Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2] -//│ 'Region2 <: 'a -//│ 'Region1 <: 'a -//│ 'Region0 <: 'a -//│ 'Region <: 'a +//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] SizeText.text(circles) //│ string @@ -269,36 +272,52 @@ mixin IsEmpty { module IsUnivIsEmpty extends IsUniv, IsEmpty //│ module IsUnivIsEmpty() { -//│ fun isEmpty: 'a -> bool -//│ fun isUniv: 'b -> bool +//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) //│ } //│ where -//│ 'a <: Intersect['a] | Outside['b] | Scale['a] | Translate['a] | Union['a] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'b <: Intersect['b] | Outside['a] | Scale['b] | Translate['b] | Union['b] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region1 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a3 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a4 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region2 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a2 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a1 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ module IsUnivIsEmpty extends IsEmpty, IsUniv //│ module IsUnivIsEmpty() { -//│ fun isEmpty: 'a -> bool -//│ fun isUniv: 'b -> bool +//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) //│ } //│ where -//│ 'a <: Intersect['a] | Outside['b] | Scale['a] | Translate['a] | Union['a] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'b <: Intersect['b] | Outside['a] | Scale['b] | Translate['b] | Union['b] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region0 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region2 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a3 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a4 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region1 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a2 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a0 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a1 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ IsUnivIsEmpty.isUniv(circles) -//│ bool +//│ bool | 'a //│ res //│ = false IsUnivIsEmpty.isEmpty(circles) -//│ bool +//│ bool | 'a //│ res //│ = false class Foo IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) //│ class Foo() -//│ bool +//│ bool | 'a //│ res //│ = false @@ -314,29 +333,37 @@ mixin Eliminate { else e } //│ mixin Eliminate() { -//│ this: {eliminate: 'a -> 'b & 'a0 -> 'c & 'a1 -> 'd & 'a2 -> 'e & 'a3 -> 'f & 'a4 -> 'g} -//│ fun eliminate: forall 'h. (Intersect['a2] | Outside['a0 & (Outside['a] | ~#Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> (Intersect['e] | Outside['c] | Scale['g] | Translate['f] | Union['d] | 'b | 'h) +//│ this: {eliminate: 'a -> 'b & 'a0 -> 'Region & 'a1 -> 'Region0 & 'a2 -> 'Region1 & 'a3 -> 'Region2 & 'a4 -> 'Region3} +//│ fun eliminate: (Intersect['a2] | Outside['a0 & (Outside['a] | ~#Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> (Intersect['Region1] | Outside['Region] | Scale['Region3] | Translate['Region2] | Union['Region0] | 'b) //│ } module TestElim extends Eliminate //│ module TestElim() { -//│ fun eliminate: 'a -> 'b +//│ fun eliminate: forall 'Region 'b 'Region0 'c. (Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> ('d | 'b | 'c) //│ } //│ where -//│ 'a <: Intersect['a] | Outside['a & (Outside['a] | ~#Outside)] | Scale['a] | Translate['a] | Union['a] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'b :> Intersect['b] | Translate['b] | Scale['b] | Outside['b] | Union['b] +//│ 'd :> 'b | 'e +//│ 'b :> Outside['d | 'b | 'f] | Union['d | 'b | 'g | 'h] | Intersect['d | 'b | 'i | 'j] | Translate['d | 'b | 'k] | Scale['d | 'b | 'l] +//│ 'Region <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a0 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a1 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a2 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'k & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'Region0 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'g & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union TestElim.eliminate(Outside(Outside(Univ()))) -//│ 'a +//│ forall 'a. 'b | 'a //│ where -//│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] | Univ +//│ 'b :> forall 'a. Univ | 'a +//│ 'a :> Outside[forall 'a. Univ | 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] | Scale[forall 'a. 'b | 'a] //│ res //│ = Univ {} TestElim.eliminate(circles) -//│ 'a +//│ forall 'a. Circle | 'b | 'a //│ where -//│ 'a :> Circle | Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] +//│ 'b :> forall 'a. 'a +//│ 'a :> Outside[forall 'a. 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. Circle | 'b | 'a] | Scale[forall 'a. 'b | 'a] //│ res //│ = Union {} @@ -352,9 +379,10 @@ fun mk(n) = if n is :re TestElim.eliminate(mk(100)) -//│ 'a +//│ forall 'a. 'b | 'a //│ where -//│ 'a :> Intersect['a] | Translate['a] | Scale['a] | Outside['a] | Union['a] +//│ 'b :> forall 'a. 'a +//│ 'a :> Outside[forall 'a. 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] | Scale[forall 'a. 'b | 'a] //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -363,22 +391,38 @@ TestElim.eliminate(mk(100)) module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate //│ module Lang() { -//│ fun contains: ('a, {x: int, y: int},) -> bool -//│ fun eliminate: 'b -> 'c -//│ fun isEmpty: 'd -> bool -//│ fun isUniv: 'e -> bool -//│ fun size: 'f -> int -//│ fun text: (Circle | Intersect[Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ] | Outside['f] | Translate[Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ]) -> string +//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: int, y: int},) -> bool +//│ fun eliminate: forall 'b 'Region1 'c 'Region2. (Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> ('d | 'c | 'b) +//│ fun isEmpty: forall 'Region3 'Region4. (Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'e) +//│ fun isUniv: forall 'Region5 'Region6. (Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'e) +//│ fun size: (Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ) -> int +//│ fun text: (Circle | Intersect[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ]) -> string //│ } //│ where -//│ 'f <: Empty | Scale['Region] | Univ | 'g & ~#Empty & ~#Scale & ~#Univ -//│ 'g <: Circle | Intersect['f] | Outside['f] | Translate['f] | Union['f] -//│ 'Region <: 'f -//│ 'd <: Intersect['d] | Outside['e] | Scale['d] | Translate['d] | Union['d] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'e <: Intersect['e] | Outside['d] | Scale['e] | Translate['e] | Union['e] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'b <: Intersect['b] | Outside['b & (Outside['b] | ~#Outside)] | Scale['b] | Translate['b] | Union['b] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'c :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] -//│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] +//│ 'a11 <: Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ +//│ 'f <: Circle | Intersect[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] +//│ 'Region4 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a5 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region6 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a9 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a10 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region5 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a8 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a6 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a7 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region3 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'd :> 'c | 'g +//│ 'c :> Outside['d | 'c | 'h] | Union['d | 'c | 'i | 'j] | Intersect['d | 'c | 'k | 'l] | Translate['d | 'c | 'm] | Scale['d | 'c | 'n] +//│ 'Region1 <: Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'k & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a1 <: Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a2 <: Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'g & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a3 <: Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'n & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a4 <: Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'm & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'Region2 <: Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] // TODO investigate :re @@ -405,12 +449,12 @@ Lang.text(circles) //│ Error: non-exhaustive case expression Lang.isUniv(circles) -//│ bool +//│ bool | 'a //│ res //│ = false Lang.isEmpty(circles) -//│ bool +//│ bool | 'a //│ res //│ = false @@ -433,18 +477,18 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.434: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.478: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.375: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.434: Lang.contains(mk(100), Vector(0, 0)) -//│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.123: if a is -//│ ╙── ^ -//│ error | bool +//│ ║ l.124: if a is +//│ ║ ^ +//│ ╟── Note: type parameter Region is defined at: +//│ ║ l.17: class Translate[Region](v: Vector, a: Region) +//│ ╙── ^^^^^^ +//│ error //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -453,16 +497,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.454: Lang.text(mk(100)) +//│ ║ l.498: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.375: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.454: Lang.text(mk(100)) +//│ ║ l.498: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.175: if e is +//│ ║ l.179: if e is //│ ╙── ^ //│ error | string //│ res @@ -471,14 +515,14 @@ Lang.text(mk(100)) :re Lang.isUniv(mk(100)) -//│ bool +//│ bool | 'a //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded :re Lang.isEmpty(mk(100)) -//│ bool +//│ bool | 'a //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index b61c639778..efc126d732 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -61,8 +61,8 @@ class C { fun const(x) = id } //│ class C() { -//│ fun const: forall 'a. anything -> 'a -> 'a -//│ fun id: forall 'a. 'a -> 'a +//│ fun const: anything -> 'a -> 'a +//│ fun id: 'a -> 'a //│ } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 159ca3893a..62b5a1d014 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -144,7 +144,7 @@ mixin Foo { } //│ mixin Foo() { //│ super: {base: int, misc: 'misc} -//│ fun test: forall 'a. (int & 'a) -> (int, 'a, 'misc,) +//│ fun test: (int & 'a) -> (int, 'a, 'misc,) //│ } :e @@ -177,11 +177,11 @@ module Base1(base: int, misc: string) extends Foo //│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ module Base1(base: int, misc: string) { -//│ fun test: (int & 'a) -> (int, 'a, nothing,) +//│ fun test: forall 'a. (int & 'a) -> (int, 'a, nothing,) //│ } Base1.test -//│ (int & 'a) -> (int, 'a, nothing,) +//│ forall 'a. (int & 'a) -> (int, 'a, nothing,) //│ res //│ = [Function: test] @@ -193,7 +193,7 @@ mixin WrapBase { fun wrap(x) = x } //│ mixin WrapBase() { -//│ fun wrap: forall 'a. 'a -> 'a +//│ fun wrap: 'a -> 'a //│ fun wrapA: (x: int,) -> int //│ } diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index a62b491cd3..4f3103294e 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -41,28 +41,35 @@ mixin EvalNegNeg { else super.eval(e) } //│ mixin EvalNegNeg() { -//│ super: {eval: (Neg['A] | 'a) -> 'b} +//│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg['A & (~#Neg | Neg['expr])] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b //│ } module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang() { -//│ fun eval: 'A -> int +//│ fun eval: 'a -> int //│ } //│ where -//│ 'A <: Add['A] | Lit | Neg['A & (~#Neg | Neg['A])] +//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] fun mk(n) = if n is - 0 then Lit(0) - 1 then Neg(mk(n)) - _ then Add(mk(n), mk(n)) + 0 then Lit(3) + 1 then Neg(mk(n - 1)) + _ then Add(mk(n - 1), mk(n - 1)) +//│ fun mk: forall 'E. int -> 'E +//│ where +//│ 'E :> Add['E] | Lit | Neg['E] + TestLang.eval(mk(0)) -//│ fun mk: forall 'E. number -> 'E //│ int -//│ where -//│ 'E :> Add['E] | Lit | Neg['E] //│ res -//│ = [Function: mk] +//│ = 3 + +TestLang.eval(mk(11)) +//│ int +//│ res +//│ = -3072 + diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index 240b86972d..1cf40b8e57 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -57,15 +57,15 @@ mixin EvalAdd { module TestLang extends EvalAdd //│ module TestLang() { -//│ fun eval: 'a -> nothing +//│ fun eval: Add['lhs] -> nothing //│ } //│ where -//│ 'a <: Add['a] +//│ 'lhs <: Add['lhs] TestLang.eval -//│ 'a -> nothing +//│ Add['lhs] -> nothing //│ where -//│ 'a <: Add['a] +//│ 'lhs <: Add['lhs] @@ -83,15 +83,15 @@ mixin EvalBase { module TestLang extends EvalBase //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: (Add['E] | Lit) -> int //│ } //│ where -//│ 'a <: Add['a] | Lit +//│ 'E <: Add['E] | Lit TestLang.eval -//│ 'a -> int +//│ (Add['E] | Lit) -> int //│ where -//│ 'a <: Add['a] | Lit +//│ 'E <: Add['E] | Lit @@ -133,15 +133,17 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'expr <: Neg['expr] | 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit TestLang.eval -//│ 'a -> int +//│ (Neg['expr] | 'a & ~#Neg) -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'expr <: Neg['expr] | 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/ExpressionProblem_small.mls b/shared/src/test/diff/nu/ExpressionProblem_small.mls index ea0cee1c4b..fd38045a92 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_small.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_small.mls @@ -45,14 +45,16 @@ mixin EvalNeg { module TestLang extends EvalNothing, EvalAddLit, EvalNeg //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'expr <: Neg['expr] | 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit TestLang.eval -//│ 'a -> int +//│ (Neg['expr] | 'a & ~#Neg) -> int //│ where -//│ 'a <: Add['a] | Lit | Neg['a] +//│ 'expr <: Neg['expr] | 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit diff --git a/shared/src/test/diff/nu/FunPoly.mls b/shared/src/test/diff/nu/FunPoly.mls index 76eada40c3..12e7dc7112 100644 --- a/shared/src/test/diff/nu/FunPoly.mls +++ b/shared/src/test/diff/nu/FunPoly.mls @@ -61,7 +61,7 @@ module Helper { } //│ fun test: (1, true,) //│ module Helper() { -//│ fun id: forall 'a. 'a -> 'a +//│ fun id: 'a -> 'a //│ } diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 6024ab15d7..8a7c0d32e5 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -51,8 +51,8 @@ class Some(value: A) { } //│ class Some[A](value: A) { //│ fun get: A -//│ fun map: forall 'A. (A -> 'A) -> Some['A] -//│ fun map_A: forall 'A0. (A -> 'A0) -> Some['A0] +//│ fun map: (A -> 'A) -> Some['A] +//│ fun map_A: (A -> 'A0) -> Some['A0] //│ fun toArray: (A,) //│ } @@ -80,7 +80,7 @@ s.toArray s.map -//│ forall 'A. (1 -> 'A) -> Some['A] +//│ (1 -> 'A) -> Some['A] //│ res //│ = [Function: map] @@ -91,7 +91,7 @@ s.map(succ) s.map_A -//│ forall 'A. (1 -> 'A) -> Some['A] +//│ (1 -> 'A) -> Some['A] //│ res //│ = [Function: map_A] @@ -244,7 +244,7 @@ class Test(n: A) { //│ class Test[A](n: A) { //│ fun foo: A //│ fun foo1: (x: A,) -> A -//│ fun id: forall 'a. 'a -> 'a +//│ fun id: 'a -> 'a //│ } Test(1) @@ -280,7 +280,7 @@ t : Test<'a> //│ = Test {} t.id -//│ forall 'a. 'a -> 'a +//│ 'a -> 'a //│ res //│ = [Function: id] diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 2ed49e0fe0..c6621ab5d5 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -60,7 +60,7 @@ fun bar: forall 'A; 'A => 'A :e fun bar : A => A -//│ ╔══[ERROR] Type parameters here are not yet supported in this position +//│ ╔══[ERROR] Type parameters are not yet supported in this position //│ ║ l.62: fun bar : A => A //│ ╙── ^ //│ ╔══[ERROR] type identifier not found: A diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 5e74d9bf43..5a33006eb5 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -25,7 +25,7 @@ module Test { //│ fun foo: A -> A //│ fun poly0: forall 'a. 'a -> 'a //│ fun poly1: forall 'a0. 'a0 -> 'a0 -//│ fun poly2: forall 'a1. 'a1 -> 'a1 +//│ fun poly2: 'a1 -> 'a1 //│ } Test.foo @@ -54,7 +54,7 @@ Test.poly1 //│ = undefined Test.poly2 -//│ forall 'a. 'a -> 'a +//│ 'a -> 'a //│ res //│ = [Function: id] @@ -129,7 +129,7 @@ Test: Test<'a> fun test(x) = if x is Test then x.foo -//│ fun test: forall 'A. Test['A] -> 'A -> 'A +//│ fun test: forall 'A 'A0. Test[in 'A | 'A0 out 'A] -> 'A0 -> ('A | 'A0) :e test(Test) diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 4761a8c29d..a47c5b61cc 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -108,7 +108,7 @@ class Goodstatt(size: 1 | 2) extends RefinedStadt { fun foo(t) = if t && true then this.size else 0 } //│ class Goodstatt(size: 1 | 2) { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: 'a -> 'a //│ fun foo: bool -> (0 | 1 | 2) //│ let name: "good" //│ } @@ -172,7 +172,7 @@ mixin More { fun bar(x) = x } //│ mixin More() { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: 'a -> 'a //│ fun more: number -> bool //│ fun size: 1 //│ } @@ -190,7 +190,7 @@ class Dirtberg extends More, SizedStadt, Fooo { fun size = 4 // this should not check } //│ class Dirtberg() { -//│ fun bar: int -> int +//│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 //│ fun more: number -> bool //│ let name: "dirt" @@ -199,7 +199,7 @@ class Dirtberg extends More, SizedStadt, Fooo { class Iceburg(name: string) extends RefinedStadt, More, Fooo //│ class Iceburg(name: string) { -//│ fun bar: 'a -> 'a +//│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 //│ fun more: number -> bool //│ fun size: 1 diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 024aecc2b7..c79f25acc2 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -107,7 +107,7 @@ class C extends Test { fun bar(x) = x } //│ class C() { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: bool -> bool //│ fun foo: 1 //│ } @@ -129,7 +129,7 @@ class F extends Oth, M, Mixed { } //│ class F() { //│ let a: 3 -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: bool -> bool //│ fun cool: number -> bool //│ fun foo: 2 //│ fun get: true @@ -185,7 +185,7 @@ c.foo //│ 1 c.bar(true) -//│ true +//│ bool // :d c: Test @@ -293,7 +293,7 @@ class CE extends Ele { fun ce(x) = x } //│ class CE() { -//│ fun ce: forall 'a. 'a -> 'a +//│ fun ce: (Test & 'a) -> (Oth | 'a) //│ } :e @@ -344,7 +344,7 @@ class E2 extends Test { //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ class E2() { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: bool -> bool //│ fun foo: true //│ } @@ -408,13 +408,22 @@ f.aa let b: Base = f //│ let b: Base +// Not sure why this one started failing when it used to extrude in peace +:e if b is Foo(a) then a else 0 +//│ ╔══[ERROR] Type error in `case` expression +//│ ║ l.413: if b is Foo(a) then a else 0 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.396: class Foo[A](aa: (A, A)) extends Base +//│ ║ ^ +//│ ╙── into type `nothing` //│ (??A, ??A,) | 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.415: if b is Bar(f) then f else 0 +//│ ║ l.424: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope //│ ║ l.397: class Bar[B](f: B => B) extends Base @@ -426,22 +435,23 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.425: if b is +//│ ║ l.434: if b is //│ ║ ^^^^ -//│ ║ l.426: Foo(a) then a +//│ ║ l.435: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.427: Bar(f) then f +//│ ║ l.436: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── type variable `B` leaks out of its scope -//│ ║ l.397: class Bar[B](f: B => B) extends Base -//│ ╙── ^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.396: class Foo[A](aa: (A, A)) extends Base +//│ ║ ^ +//│ ╙── into type `nothing` //│ anything // TODO report proper error fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.442: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.452: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -482,40 +492,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.480: fun fto(w: WP): EM = w +//│ ║ l.490: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.480: fun fto(w: WP): EM = w +//│ ║ l.490: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.480: fun fto(w: WP): EM = w +//│ ║ l.490: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.480: fun fto(w: WP): EM = w +//│ ║ l.490: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.481: z: WP +//│ ║ l.491: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.460: let z: ZL +//│ ║ l.470: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.481: z: WP +//│ ║ l.491: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.481: z: WP +//│ ║ l.491: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.482: g: ZL +//│ ║ l.492: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.459: let g: Geo +//│ ║ l.469: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.482: g: ZL +//│ ║ l.492: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.482: g: ZL +//│ ║ l.492: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -532,7 +542,7 @@ class Ih extends Bs(false) { fun foo(x) = 1 } //│ class Ih() { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: 'a -> 'a //│ fun foo: anything -> 1 //│ } @@ -548,13 +558,29 @@ ih1: Bs ih1.a //│ bool -// FIXME +:e class Eh2 extends Bs(true), Ele { fun foo(x) = x && false fun ce(x) = x } +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.563: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `int & ??_` is not an instance of type `bool` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.563: fun foo(x) = x && false +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.563: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── operator application of type `bool` does not match type `int | ??_` +//│ ║ l.563: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from operator application: +//│ ║ l.534: fun foo(x) = x + 1 +//│ ╙── ^^^^^ //│ class Eh2() { -//│ fun ce: forall 'a. 'a -> 'a +//│ fun ce: (Test & 'a) -> (Oth | 'a) //│ fun foo: bool -> bool //│ } @@ -563,32 +589,32 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.562: class Eh extends Bs(1) +//│ ║ l.588: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.562: class Eh extends Bs(1) +//│ ║ l.588: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.523: class Bs(a: bool) { +//│ ║ l.533: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in integer literal: -//│ ║ l.562: class Eh extends Bs(1) +//│ ║ l.588: class Eh extends Bs(1) //│ ║ ^ //│ ╟── integer literal of type `1` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.523: class Bs(a: bool) { +//│ ║ l.533: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.563: class Eh1 extends Bs +//│ ║ l.589: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.524: fun foo(x) = x + 1 +//│ ║ l.534: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> ?b` is not an instance of type `int` -//│ ║ l.524: fun foo(x) = x + 1 +//│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` +//│ ║ l.534: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.524: fun foo(x) = x + 1 +//│ ║ l.534: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -597,7 +623,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.564: class Eh3 extends Bs(false), Test +//│ ║ l.590: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -615,14 +641,14 @@ class Ca(a: int) extends Oth { fun bar(x) = x } //│ class Ca(a: int) { -//│ fun bar: forall 'a. 'a -> 'a +//│ fun bar: bool -> bool //│ fun cool: anything -> false //│ fun foo: 1 //│ } class Cx(a: 1 | 2, b: bool) extends Ca(a) //│ class Cx(a: 1 | 2, b: bool) { -//│ fun bar: 'a -> 'a +//│ fun bar: bool -> bool //│ fun cool: anything -> false //│ fun foo: 1 //│ } @@ -653,7 +679,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.654: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.680: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() @@ -670,11 +696,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.671: class Bc31(baz: bool) extends Bc3 +//│ ║ l.697: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.645: let baz : int +//│ ║ l.671: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -683,11 +709,11 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.683: let foo = true +//│ ║ l.709: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.642: class Bc1(foo: int) +//│ ║ l.668: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -706,7 +732,7 @@ class Der1 extends Base[int] { fun f(x) = x + 1 } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ class Der2[A, B]() { -//│ fun f: forall 'a 'b. ('b, 'a,) -> ('b, 'a,) +//│ fun f: (A, B,) -> (A, B,) //│ } trait BInt extends Base[int] { @@ -730,7 +756,7 @@ let bp: BPar[bool] // FIXME bp: Base[(int, bool)] //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ║ l.723: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ Base[(int, bool,)] @@ -738,7 +764,7 @@ bi.f(1) //│ nothing bp.f -//│ forall 'T. (int, 'T,) -> (int, 'T,) +//│ ((int, bool,) & 'A) -> ((int, bool,) | 'A) fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) //│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) @@ -746,7 +772,7 @@ fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) // FIXME fb(bp, false) //│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ║ l.723: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ (int, false,) | error @@ -754,7 +780,7 @@ class CP extends BPar[int] { fun f(x) = (x._2, x._1) } //│ class CP() { -//│ fun f: forall 'a 'b. {_1: 'a, _2: 'b} -> ('b, 'a,) +//│ fun f: {_1: int, _2: int} -> (int, int,) //│ } let cp1 = CP() @@ -763,14 +789,14 @@ let cp1 = CP() // FIXME fb(cp1, 2) //│ ╔══[ERROR] Type `CP` does not contain member `Base#A` -//│ ║ l.697: trait Base[A] { fun f: A -> A } +//│ ║ l.723: trait Base[A] { fun f: A -> A } //│ ╙── ^ //│ (int, 2,) | error :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.771: trait BErr1 extends Base +//│ ║ l.797: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -779,41 +805,41 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.780: class DerBad1 extends Base[int, int] +//│ ║ l.806: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.780: class DerBad1 extends Base[int, int] +//│ ║ l.806: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.790: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { -//│ fun f: forall 'a 'b. ('a, 'b,) -> ('b, 'a,) +//│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) //│ } trait Ta[T] { @@ -875,11 +901,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.876: class Fischl(age: bool) extends Oz +//│ ║ l.902: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.869: let age: int +//│ ║ l.895: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -893,10 +919,26 @@ class Fate { //│ fun foo: int -> int //│ } -// FIXME +:e class Go extends Fate { fun foo(x) = x && true } +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.924: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `int & ??_` is not an instance of type `bool` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.924: fun foo(x) = x && true +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.924: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── operator application of type `bool` does not match type `int | ??_` +//│ ║ l.924: fun foo(x) = x && true +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from operator application: +//│ ║ l.916: fun foo(x) = x + 1 +//│ ╙── ^^^^^ //│ class Go() { //│ fun foo: bool -> bool //│ } @@ -912,10 +954,10 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.913: class Ohhh(x: bool) extends Ha +//│ ║ l.955: class Ohhh(x: bool) extends Ha //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.904: class Ha { let x: int = 1 } +//│ ║ l.946: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) diff --git a/shared/src/test/diff/nu/MemberConfusion.mls b/shared/src/test/diff/nu/MemberConfusion.mls new file mode 100644 index 0000000000..b6f8ff7dcc --- /dev/null +++ b/shared/src/test/diff/nu/MemberConfusion.mls @@ -0,0 +1,75 @@ +:NewDefs + + +mixin T { fun a = "hi" } +//│ mixin T() { +//│ fun a: "hi" +//│ } + +class C(a: int) extends T +//│ class C(a: int) { +//│ fun a: "hi" +//│ } + +class B { let a = "hi" } +//│ class B() { +//│ let a: "hi" +//│ } + +:e +class C(a: int) extends B +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.20: class C(a: int) extends B +//│ ║ ^^^ +//│ ╟── type `int` does not match type `"hi"` +//│ ╟── Note: constraint arises from string literal: +//│ ║ l.14: class B { let a = "hi" } +//│ ╙── ^^^^ +//│ class C(a: int) + + +mixin M { let b = "hi" } +//│ mixin M() { +//│ let b: "hi" +//│ } + +class B { let a = 1 : int } +//│ class B() { +//│ let a: int +//│ } + +class C(a: int, b: int) extends B, M +//│ class C(a: int, b: int) { +//│ let b: "hi" +//│ } + +let c = C(2, 3) +(c.a, c.b) +//│ let c: C +//│ (int, "hi",) +//│ c +//│ = C {} +//│ res +//│ = [ 2, 3 ] + +class C(a: int) { let a = 1 } +//│ class C(a: int) { +//│ let a: 1 +//│ } + +class C(a: int) { fun a = 1 } +//│ class C(a: int) { +//│ fun a: 1 +//│ } + +class C(a: int) { fun a = a } +//│ class C(a: int) { +//│ fun a: nothing +//│ } + +class C(a: int, b: int) extends B, M { let b = "hi" } +//│ class C(a: int, b: int) { +//│ let b: "hi" +//│ } + + diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index e8b3adcaa1..88d3a6f5f1 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -9,8 +9,8 @@ mixin Base { fun rewrap(x, f) = f(x) } //│ mixin Base() { -//│ fun rewrap: forall 'a 'b. ('a, 'a -> 'b,) -> 'b -//│ fun unwrap: forall 'c. 'c -> 'c +//│ fun rewrap: ('a, 'a -> 'b,) -> 'b +//│ fun unwrap: 'c -> 'c //│ } @@ -55,29 +55,29 @@ mixin WithType { module Test0 extends Base, WithUid //│ module Test0() { -//│ fun getUid: {uid: 'uid, underlying: 'underlying} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying0} -//│ fun setUid: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying0} -//│ fun unwrap: {uid: 'uid, underlying: 'underlying} -> 'underlying +//│ fun getUid: {uid: 'uid} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: 'underlying}, 'underlying -> 'a,) -> {uid: 'uid0, underlying: 'a} +//│ fun setUid: ({underlying: 'underlying0}, uid: int,) -> {uid: int, underlying: 'underlying0} +//│ fun unwrap: {underlying: 'underlying1} -> 'underlying1 //│ } module Test0 extends Base, WithUid, WithUid //│ module Test0() { -//│ fun getUid: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {uid: int | 'uid1, underlying: 'underlying0}} -//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying2 | {uid: int | 'uid1, underlying: 'underlying0}} -//│ fun unwrap: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'underlying +//│ fun getUid: {underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, 'underlying1 -> 'underlying0,) -> {uid: 'uid0, underlying: {uid: int | 'uid1, underlying: 'underlying0}} +//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, uid: int,) -> {uid: 'uid0, underlying: {uid: int | 'uid1, underlying: 'underlying0}} +//│ fun unwrap: {underlying: {uid: 'uid, underlying: 'underlying}} -> 'underlying //│ } module Test1 extends Base, WithUid, WithType //│ module Test1() { -//│ fun getType: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty -//│ fun getUid: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, ty: Type,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun setUid: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun unwrap: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying +//│ fun getType: {underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty +//│ fun getUid: {uid: 'uid} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1}}, 'underlying1 -> 'underlying0,) -> {uid: 'uid0, underlying: {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1}}, ty: Type,) -> {uid: 'uid0, underlying: {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun setUid: ({underlying: 'underlying2}, uid: int,) -> {uid: int, underlying: 'underlying2} +//│ fun unwrap: {underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying //│ } let uid = 0 @@ -123,7 +123,7 @@ a.underlying.ty.name //│ = 'A' let b = Test1.setType(a, Type("B")) -//│ let b: {uid: int, underlying: {ty: Type, underlying: 42}} +//│ let b: {uid: 0, underlying: {ty: Type, underlying: 42}} //│ b //│ = { underlying: { underlying: 42, ty: Type {} }, uid: 0 } diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 3fada7539e..46755c880e 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -1,6 +1,127 @@ :NewDefs + +module Oops { + fun a : int + fun a = 2 +} +//│ module Oops() { +//│ fun a: int +//│ } + +:e +module Oops { + fun a : int +} +//│ ╔══[ERROR] Member a is declared but not defined +//│ ║ l.15: fun a : int +//│ ╙── ^ +//│ module Oops() { +//│ fun a: int +//│ } + +:e +module Oops { + fun a : int + fun a : string + fun a = a +} +//│ ╔══[ERROR] A type signature for 'a' has already been given +//│ ║ l.27: fun a : string +//│ ╙── ^^^^^^^^^^ +//│ module Oops() { +//│ fun a: string +//│ } + +:e +module Oops { + fun a : int + fun a = false +} +//│ ╔══[ERROR] Type mismatch in definition of method a: +//│ ║ l.40: fun a = false +//│ ║ ^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `int` +//│ ║ l.40: fun a = false +//│ ║ ^^^^^ +//│ ╟── but it flows into definition of method a with expected type `int` +//│ ║ l.40: fun a = false +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.39: fun a : int +//│ ║ ^^^ +//│ ╟── from signature of member a: +//│ ║ l.39: fun a : int +//│ ╙── ^^^^^^^ +//│ module Oops() { +//│ fun a: int +//│ } + +:e +module Oops { + fun a = 1 + fun a = 2 +} +//│ ╔══[ERROR] Refininition of a +//│ ║ l.64: fun a = 2 +//│ ╙── ^^^^^ +//│ module Oops() { +//│ fun a: 2 +//│ } + + + +// * Without a type signature, the method's inferred type is not generalized +module A { + fun i(x) = x +} +//│ module A() { +//│ fun i: 'a -> 'a +//│ } + +// * With a type signature, it is generalized and checked against the signature +module A { + + fun i: forall 'a; 'a -> 'a + fun i(x) = x + + fun j: 'b -> 'b + fun j(x) = x + +} +//│ module A() { +//│ fun i: forall 'a. 'a -> 'a +//│ fun j: forall 'b. 'b -> 'b +//│ } + + +:e +module A { + fun i : 'a + fun i(x) = x +} +//│ ╔══[ERROR] Type mismatch in definition of method i: +//│ ║ l.102: fun i(x) = x +//│ ║ ^^^^^^^^ +//│ ╟── function of type `?a -> ?a` does not match type `'a` +//│ ║ l.102: fun i(x) = x +//│ ║ ^^^^^^^ +//│ ╟── but it flows into definition of method i with expected type `'a` +//│ ║ l.102: fun i(x) = x +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from type variable: +//│ ║ l.101: fun i : 'a +//│ ║ ^^ +//│ ╟── from signature of member i: +//│ ║ l.101: fun i : 'a +//│ ╙── ^^^^^^ +//│ module A() { +//│ fun i: nothing +//│ } + + + // FIXME currently type signatures are typed too early (not in the context where the other defns live) // We need to move all the typing unit setup to lazy type info prelude // :d @@ -9,12 +130,24 @@ module M { fun a: A fun a = 1 } -//│ ╔══[ERROR] type identifier not found: A -//│ ║ l.9: fun a: A -//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method a: +//│ ║ l.131: fun a = 1 +//│ ║ ^^^^^ +//│ ╟── integer literal of type `1` is not an instance of type `A` +//│ ║ l.131: fun a = 1 +//│ ║ ^ +//│ ╟── but it flows into definition of method a with expected type `A` +//│ ║ l.131: fun a = 1 +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.130: fun a: A +//│ ║ ^ +//│ ╟── from signature of member a: +//│ ║ l.130: fun a: A +//│ ╙── ^^^^ //│ module M() { //│ class A() -//│ fun a: error +//│ fun a: A //│ } // FIXME similar @@ -24,8 +157,8 @@ module M { fun a = 1 } //│ ╔══[ERROR] undeclared this -//│ ║ l.23: fun a: this.A -//│ ╙── ^^^^ +//│ ║ l.156: fun a: this.A +//│ ╙── ^^^^ //│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached and unexpected state. // FIXME similar diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index 9353feacb1..db2ada0199 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,79 +1,2 @@ :NewDefs -1 -//│ 1 -//│ res -//│ = 1 - -mixin T { fun a = "hi" } -//│ mixin T() { -//│ fun a: "hi" -//│ } - -class C(a: int) extends T -//│ class C(a: int) { -//│ fun a: "hi" -//│ } - -class B { let a = "hi" } -//│ class B() { -//│ let a: "hi" -//│ } - -:e -class C(a: int) extends B -//│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.24: class C(a: int) extends B -//│ ║ ^^^ -//│ ╟── type `int` does not match type `"hi"` -//│ ╟── Note: constraint arises from string literal: -//│ ║ l.18: class B { let a = "hi" } -//│ ╙── ^^^^ -//│ class C(a: int) - - -mixin M { let b = "hi" } -//│ mixin M() { -//│ let b: "hi" -//│ } - -class B { let a = 1 : int } -//│ class B() { -//│ let a: int -//│ } - -class C(a: int, b: int) extends B, M -//│ class C(a: int, b: int) { -//│ let b: "hi" -//│ } - -let c = C(2, 3) -(c.a, c.b) -//│ let c: C -//│ (int, "hi",) -//│ c -//│ = C {} -//│ res -//│ = [ 2, 3 ] - -// class C(a: int, b: int) extends B, M { let b = "hi" } - - - -// FIXME -class C(a: int) { let a = 1 } -//│ class C(a: int) { -//│ let a: 1 -//│ } - -class C(a: int) { fun a = 1 } -//│ class C(a: int) { -//│ fun a: 1 -//│ } - -class C(a: int) { fun a = a } -//│ class C(a: int) { -//│ fun a: nothing -//│ } - - diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 0572bd0f09..649e3c1ffd 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -61,7 +61,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: forall 'b. (List[{_1: string, _2: 'b}], Var,) -> ('b | Var) +//│ fun eval: (List[{_1: string, _2: 'b}], Var,) -> ('b | Var) //│ } class Abs(x: string, t: A) @@ -96,48 +96,51 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c,) -> 'd} -//│ this: {eval: ('b, 's,) -> ('e & 'f) & (List[in 'a out 'a | (string, 'f,)], 't,) -> 'd & (List[in 'a0 out 'a0 | 'a1 | (string, Var,)], 't0,) -> 'g} -//│ fun eval: forall 'a2. (List['a2] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['g] | App['e | 'f] | 'd) +//│ this: {eval: ('b, 's,) -> ('A & 'e) & (List[in 'a out 'a | (string, 'e,)], 't,) -> 'd & (List['a0], 't0,) -> 'A0} +//│ fun eval: (List['a0] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['A0] | App['A] | 'd) //│ } //│ where -//│ 'a2 :> 'a0 | (string, Var,) -//│ <: 'a1 +//│ 'a0 :> (string, Var,) module Test1 extends EvalVar, EvalLambda //│ module Test1() { -//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> 'b +//│ fun eval: forall 'a. (List[{_1: string, _2: 'b}], Abs['t] | App['A] | Var,) -> ('c | 'a) //│ } //│ where -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | Var -//│ 'b :> App['b] | Abs['b] | Var +//│ 't <: Abs['t] | App['A] | Var +//│ 'A <: Abs['t & (Abs['t] | App['A] | Var)] | Abs['t] & ~#Abs | App['A] | Var +//│ 'b :> Var | 'd +//│ 'd :> 'c | 'a +//│ 'c :> 'b | Var | 'a +//│ 'a :> App['d | 'c | 'a] | Abs['c | 'a] Test1.eval(Nil(), Var("a")) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) -//│ ║ l.114: Test1.eval(Nil(), Var("a")) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. -//│ error +//│ forall 'a. 'b | 'a | 'c +//│ where +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> (forall 'a. Var | 'b | 'a) | Var Test1.eval(Nil(), Abs("b", Var("a"))) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) -//│ ║ l.121: Test1.eval(Nil(), Abs("b", Var("a"))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. -//│ error +//│ forall 'a. 'b | 'a | 'c +//│ where +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> (forall 'a. Var | 'b | 'a) | Var Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) -//│ ║ l.128: Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. -//│ error +//│ forall 'a. 'b | 'a | 'c +//│ where +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> (forall 'a. Var | 'b | 'a) | Var Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) -//│ ║ l.135: Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. -//│ error +//│ forall 'a. 'b | 'a | 'c +//│ where +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Var class Num(n: int) class Add(l: A, r: A) @@ -152,7 +155,7 @@ fun map_expr(f, v) = Num then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'A 'l 'A0 'l0. ('l -> 'A0 & 'l0 -> 'A, Add['l] | Mul['l0] | Num | Var,) -> (Add['A0] | Mul['A] | Num | Var) +//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) mixin EvalExpr { fun eval(sub, v) = @@ -167,16 +170,15 @@ mixin EvalExpr { //│ mixin EvalExpr() { //│ super: {eval: ('a, Var,) -> 'b} //│ this: {eval: ('a, 'c,) -> anything} -//│ fun eval: forall 'd. ('a, 'd & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'd | 'b) +//│ fun eval: ('a, 'b & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'b) //│ } module Test2 extends EvalVar, EvalExpr //│ module Test2() { -//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> ('b | Num | Var | 'a) +//│ fun eval: forall 'a. (List[{_1: string, _2: 'b}], 'a & (Add['c] | Mul['c] | Num | Var),) -> ('b | Num | Var | 'a) //│ } //│ where -//│ 'a <: Add['c] | Mul['c] | Num | Var -//│ 'c <: 'a +//│ 'c <: Add['c] | Mul['c] | Num | Var Test2.eval(Nil(), Var("a")) //│ Num | Var @@ -192,34 +194,39 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> 'b +//│ fun eval: forall 'A 'a. (List[{_1: string, _2: 'b}], Abs['t] | App['A] | 'c & ~#Abs & ~#App,) -> ('d | 'a) //│ } //│ where -//│ 'b :> App['b] | Abs['b] | Num | Var | 'c -//│ 'c <: Add['d] | Mul['d] | Num | Var -//│ 'd <: 'a -//│ 'a <: Abs['a] | App['a & (Abs['a] | ~#Abs)] | 'c & ~#Abs & ~#App +//│ 'b :> Var | 'e +//│ 'e :> 'd | 'a +//│ 'd :> 'b | Num | Var | 'c | 'a +//│ 'a :> App['e | 'd | 'a] | Abs['d | 'a] +//│ 'c <: Add['f] | Mul['f] | Num | Var +//│ 'f <: Abs['t] | App['A] | 'c & ~#Abs & ~#App +//│ 't <: Abs['t] | App['A] | 'c & ~#Abs & ~#App +//│ 'A <: Abs['t & (Abs['t] | App['A] | 'c & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | 'c & ~#Abs & ~#App Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) -//│ ║ l.203: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. -//│ error +//│ forall 'a. 'b | 'a | 'c +//│ where +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Num | Var Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) -//│ ╔══[ERROR] Subtyping constraint of the form `?eval <: (?a, ?b,) -> ?c` took too many steps and ran out of fuel (5000) -//│ ║ l.210: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── Note: use flag `:ex` to see internal error info. -//│ error +//│ forall 'a. 'b | 'a | 'c +//│ where +//│ 'b :> forall 'a. 'a | 'c +//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Num | Var] | Num | Var module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> ('a | 'b) +//│ fun eval: forall 'a. (List[{_1: string, _2: 'b}], 'a & (Add['c] | Mul['c] | Num | Var),) -> ('a | 'd) //│ } //│ where -//│ 'b :> Abs['b] | App['b] | Var | Num | 'a -//│ 'a <: Add['c] | Mul['c] | Num | Var -//│ 'c <: 'a +//│ 'c <: Add['c] | Mul['c] | Num | Var +//│ 'b :> Var | 'e +//│ 'e :> 'd +//│ 'd :> 'b | Abs[Num | 'd] | App[Num | 'e | 'd] | Num | Var diff --git a/shared/src/test/diff/nu/SelfAppMethods.mls b/shared/src/test/diff/nu/SelfAppMethods.mls new file mode 100644 index 0000000000..bce149cf32 --- /dev/null +++ b/shared/src/test/diff/nu/SelfAppMethods.mls @@ -0,0 +1,66 @@ +:NewDefs + + +class A { + + fun f = f(f) + + fun g : A + fun g = g(g) // * FIXME not using the signature + +} +//│ class A() { +//│ fun f: nothing +//│ fun g: A +//│ } + +module A { + fun i(x) = x + fun f = f(f) + fun g(x) = x(x) + fun h = g(g) +} +//│ module A() { +//│ fun f: nothing +//│ fun g: 'a -> 'b +//│ fun h: 'b +//│ fun i: 'c -> 'c +//│ } +//│ where +//│ 'a := 'a -> 'b + +:ns +A.i +//│ 'i +//│ where +//│ 'i :> 'a -> 'a +//│ res +//│ = [Function: i] + +:re +:ns +A.f +//│ 'f +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:ns +A.g +//│ 'g +//│ where +//│ 'g :> 'a -> 'b +//│ 'a := 'a -> 'b +//│ 'b <: 'c +//│ res +//│ = [Function: g] + +:ns +:re +A.h +//│ 'h +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + + diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index 44d16861fd..eb0b964613 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -19,17 +19,18 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ this: {eval: nothing -> 'a & 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit | Neg[nothing]) -> (int | 'a) +//│ this: {eval: 'expr -> 'a & ('A | 'lhs) -> int} +//│ fun eval: (Add['lhs] | Lit | Neg['A & (~#Neg | Neg['expr])]) -> (int | 'a) //│ } // module TestLang extends EvalBase, EvalNeg module TestLang extends EvalBase //│ module TestLang() { -//│ fun eval: 'a -> int +//│ fun eval: forall 'E. (Add['E] | Lit | Neg['A]) -> int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg[nothing] +//│ 'E <: Add['E] | Lit | Neg['A] +//│ 'A <: Add['E] | Lit | Neg['A & (Add['E] | Lit | Neg['A])] | Neg['A] & ~#Neg fun mk(n) = if n is @@ -43,20 +44,11 @@ fun mk(n) = if n is // TODO support this in UCS :stats TestLang.eval(mk(0)) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.45: TestLang.eval(mk(0)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Lit` does not match type `nothing` -//│ ║ l.36: 0 then Lit(0) -//│ ║ ^^^^^^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.6: class Neg(expr: A) -//│ ╙── ^ -//│ error | int +//│ int //│ res //│ = 0 -//│ constrain calls : 239 -//│ annoying calls : 116 -//│ subtyping calls : 3975 +//│ constrain calls : 289 +//│ annoying calls : 163 +//│ subtyping calls : 2353 diff --git a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls index b995026755..d504913c5b 100644 --- a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls +++ b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls @@ -25,8 +25,11 @@ mixin EvalLambda { //│ fun eval: (Cons['A] | Nil, Abs[anything],) -> nothing //│ } -// FIXME type simplification bug: analyze2 does not traverse TVs witht he correct PolMap +// Note: this used to crash becayse of a current type simplification bug: analyze2 does not traverse TVs witht he correct PolMap +// The original unreduced version in PolymorphicVariants.mls still crashes... // :ds module Test1 extends EvalLambda -//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed: x46_115' has no occurrences... +//│ module Test1() { +//│ fun eval: (Cons[anything] | Nil, Abs[anything],) -> nothing +//│ } From 9cda2531812534144d3a3ce33715fc667605f527 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 10 May 2023 20:20:46 +0800 Subject: [PATCH 279/498] FIXED type members of parent trait --- .../src/main/scala/mlscript/NuTypeDefs.scala | 150 +++++++++++------- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperHelpers.scala | 12 +- shared/src/test/diff/nu/GADTMono.mls | 82 +++++++++- shared/src/test/diff/nu/InterfaceGeneric.mls | 45 ++++-- shared/src/test/diff/nu/Interfaces.mls | 101 +++++++----- 6 files changed, 283 insertions(+), 111 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 4286107d7b..18144b6017 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -130,27 +130,29 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify)) - case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags) => + case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags, pvms) => TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), tags.freshenAbove(lim, rigidify), - inheritedTags + inheritedTags, + pvms.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap )(cls.instanceType.freshenAbove(lim, rigidify)) case cls @ TypedNuAls(level, td, tparams, body) => TypedNuAls(level, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), body.freshenAbove(lim, rigidify)) - case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags) => + case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags, pvms) => TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), sign.map(_.freshenAbove(lim, rigidify)), // todo tags.freshenAbove(lim, rigidify), - inheritedTags + inheritedTags, + pvms.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap ) } } @@ -197,7 +199,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => thisTy: ST, sign: Opt[ST], selfTy: ST, - inheritedTags: Set[TypeName] + inheritedTags: Set[TypeName], + parentTP: Map[Str, NuMember] ) extends TypedNuTypeDef(Trt) with TypedNuTermDef with PolyNuDecl { def decl: NuTypeDef = td @@ -207,10 +210,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy, inheritedTags) - def virtualMembers: Map[Str, NuMember] = members ++ tparams.map { + lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } + } ++ parentTP def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -220,7 +223,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.map(!_), thisTy), sign.map(f(pol, _)), f(pol, selfTy), - inheritedTags + inheritedTags, + parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -230,7 +234,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol.contravar, thisTy), sign.map(f(pol, _)), f(pol, selfTy), - inheritedTags + inheritedTags, + parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap ) } @@ -240,7 +245,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, tags: ST, - inheritedTags: Set[TypeName] + inheritedTags: Set[TypeName], + parentTP: Map[Str, NuMember] )(val instanceType: ST, // * only meant to be used in `force` and `variances` ) extends TypedNuTypeDef(Cls) with TypedNuTermDef with PolyNuDecl { @@ -255,7 +261,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } + } ++ parentTP // TODO // def checkVariances @@ -311,7 +317,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), f(pol, tags), - inheritedTags + inheritedTags, + parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -321,7 +328,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), f(pol, tags), - inheritedTags + inheritedTags, + parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap, )(f(pol, instanceType)) } @@ -691,7 +699,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => private lazy val thisTV: TV = freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) - def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : T = { + def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : (T, Map[Str, NuMember]) = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty @@ -702,28 +710,37 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"${if (raw.isInstanceOf[TypedNuTrt]) "trait" else "class"} $rawName expects ${ raw.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) - raw.tparams.lazyZip(parTargs).foreach { case ((tn, _tv, vi), targTy) => - val targ = typeType(targTy) - freshened += _tv -> (targ match { - case tv: TV => - // TODO - println(s"Passing ${_tv} <=< ${tv}") - tv - case _ => - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - tv - }) + val parTP = raw.tparams.lazyZip(parTargs).map { case ((tn, _tv, vi), targTy) => + val targ = typeType(targTy) + val tv = (targ match { + case tv: TV => + // TODO + println(s"Passing ${tn.name} :: ${_tv} <=< ${tv}") + tv + case _ => + println(s"Assigning ${tn.name} :: ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) + freshened += _tv -> tv + tn -> tv + } + + println(s"collected ${parTP}") - } + raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] -> + parTP.map { + case (nme, tv) => rawName+"#"+nme.name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + }.toMap + // } - raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] // FIXME + // raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] // FIXME } @@ -820,8 +837,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } // inherit traits - def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember]) - : (ST, ST, Ls[NuMember]) = + def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) + : (ST, ST, Ls[NuMember], Map[Str, NuMember]) = parents match { case (p, v @ Var(trtName), parTargs, args) :: ps => ctx.get(trtName) match { @@ -830,26 +847,27 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => info match { case rawTrt: TypedNuTrt => if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) - val trt = refreshGen[TypedNuTrt](info, v , parTargs)// FIXME + val (trt, vm) = refreshGen[TypedNuTrt](info, v , parTargs)// FIXME inherit(ps, superType & trt.thisTy, tags & trt.selfTy, - memberUn(members, trt.members.values.toList) + memberUn(members, trt.members.values.toList), + vms ++ vm ++ trt.parentTP ) case _ => err(msg"trait can only inherit traits", p.toLoc) - (superType, tags, members) + (superType, tags, members, vms) } case _ => err(msg"Could not find definition `${trtName}`", p.toLoc) - (superType, tags, members) + (superType, tags, members, vms) } - case Nil => (superType, tags, members) + case Nil => (superType, tags, members, vms) } - val (thisType, tags, baseMems) = - inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil) + val (thisType, tags, baseMems, vms) = + inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) // val selfType = tags & sig_ty val selfType = sig_ty @@ -858,7 +876,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val trtMems = baseMems ++ ttu.entities val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap - TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, thisType, None, selfType, inheritedTags) -> Nil + TypedNuTrt(outerCtx.lvl, td, ttu, + tparams, + mems, + thisType, + None, + selfType, + inheritedTags, + vms + ) -> Nil } case Als => @@ -1011,7 +1037,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO report non-unit result/statements? // TODO check overriding - case class Pack(clsMem: Ls[NuMember], bsCls: Opt[Str], bsMem: Ls[NuMember], trtMem: Ls[NuMember]) + case class Pack( + clsMem: Ls[NuMember], + bsCls: Opt[Str], + bsMem: Ls[NuMember], + trtMem: Ls[NuMember], + pTP: Map[Str, NuMember] + ) // compute base class and interfaces def computeBaseClassTrait(parents: Ls[ParentSpec], pack: Pack): Pack = @@ -1026,10 +1058,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if (pack.bsCls.isDefined) err(msg"cannot inherit from more than one base class: ${ pack.bsCls.get} and ${parNme}", v.toLoc) - - // println(s"Raw $rawCls") - val cls = refreshGen[TypedNuCls](info, v, parTargs) - // println(s"Fresh $cls") + + val (cls, ptp) = refreshGen[TypedNuCls](info, v, parTargs) if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ @@ -1052,15 +1082,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - computeBaseClassTrait(ps, pack.copy(clsMem = res, bsCls = S(parNme), bsMem = cls.members.values.toList)) + computeBaseClassTrait(ps, pack.copy( + clsMem = res, + bsCls = S(parNme), + bsMem = cls.members.values.toList, + pTP = pack.pTP ++ ptp ++ cls.parentTP + )) case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - // println(s"Raw $rawTrt") - val trt = refreshGen[TypedNuTrt](info, v, parTargs) // FIXME - // println(s"Fresh $trt") + val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) // FIXME + computeBaseClassTrait(ps, pack.copy( - trtMem = memberUn(pack.trtMem, trt.members.values.toList) + trtMem = memberUn(pack.trtMem, trt.members.values.toList), + pTP = pack.pTP ++ ptp ++ trt.parentTP )) case _ => computeBaseClassTrait(ps, pack) @@ -1071,8 +1106,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => pack } - val Pack(clsMems, _, bsMembers, ifaceMembers) = - computeBaseClassTrait(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil, Nil)) + val Pack(clsMems, _, bsMembers, ifaceMembers, ptps) = + computeBaseClassTrait(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil, Nil, Map.empty)) val impltdMems = clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers @@ -1106,7 +1141,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TopType, // ifaceAnnot, TopType, // TODO use signature - inheritedTags + inheritedTags, + ptps )(thisType) -> impltdMems } case Mxn => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index cb5b4bfaf4..2c676972f0 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1332,7 +1332,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, vms) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), @@ -1342,7 +1342,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, vms) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 4952190362..0ab58931db 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -790,11 +790,13 @@ abstract class TyperHelpers { Typer: Typer => cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ - S(pol.covar -> cls.instanceType) + S(pol.covar -> cls.instanceType) ++ + cls.parentTP.valuesIterator.flatMap(childrenPolMem) case cls: TypedNuTrt => cls.tparams.iterator.map(pol.invar -> _._2) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ - S(pol.contravar -> cls.thisTy) + S(pol.contravar -> cls.thisTy) ++ + cls.parentTP.valuesIterator.flatMap(childrenPolMem) } ents ::: tu.result.toList.map(pol -> _) }} @@ -1172,16 +1174,18 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, pvms) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) + pvms.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, pvms) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) + pvms.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTy) case TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index af35e85053..836a229ecc 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -1,7 +1,6 @@ :NewDefs :NoJS -// TODO trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd class LitInt(n: int) extends Expr[int] class LitBool(b: bool) extends Expr[bool] @@ -18,3 +17,84 @@ class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] //│ class Pair[S, T](a: Expr[S], b: Expr[T]) //│ class Fst[S, T](p: Expr[(S, T,)]) //│ class Snd[S, T](p: Expr[(S, T,)]) + +let l1 = LitInt(1) +//│ let l1: LitInt + +l1: Expr[int] +//│ Expr[int] + +:e +l1: Expr[bool] +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.28: l1: Expr[bool] +//│ ║ ^^ +//│ ╟── type `int` is not an instance of `bool` +//│ ║ l.5: class LitInt(n: int) extends Expr[int] +//│ ║ ^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.28: l1: Expr[bool] +//│ ╙── ^^^^ +//│ Expr[bool] + +// FIXME +fun eval[A](e: Expr[A]): A = + if + e is LitInt(n) then n + e is LitBool(b) then b + e is Add(x, y) then eval(x) + eval(y) +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.43: e is LitInt(n) then n +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.44: e is LitBool(b) then b +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.45: e is Add(x, y) then eval(x) + eval(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `#Expr & (Add & {Expr#A = ?A} | Cond[?] & {Expr#A = ?A} | Fst[?, ?] & {Expr#A = ?A} | LitBool & {Expr#A = ?A} | LitInt & {Expr#A = ?A} | Pair[?, ?] & {Expr#A = ?A} | Snd[?, ?] & {Expr#A = ?A})` does not match type `Add | LitBool | LitInt` +//│ ║ l.41: fun eval[A](e: Expr[A]): A = +//│ ║ ^^^^^^^ +//│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt` +//│ ║ l.43: e is LitInt(n) then n +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.41: fun eval[A](e: Expr[A]): A = +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.42: if +//│ ║ ^^^^^^^ +//│ ║ l.43: e is LitInt(n) then n +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.44: e is LitBool(b) then b +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.45: e is Add(x, y) then eval(x) + eval(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `bool` is not an instance of `int` +//│ ║ l.6: class LitBool(b: bool) extends Expr[bool] +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `int` +//│ ║ l.43: e is LitInt(n) then n +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.7: class Add(x: Expr[int], y: Expr[int]) extends Expr[int] +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.41: fun eval[A](e: Expr[A]): A = +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.42: if +//│ ║ ^^^^^^^ +//│ ║ l.43: e is LitInt(n) then n +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.44: e is LitBool(b) then b +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.45: e is Add(x, y) then eval(x) + eval(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `bool` is not an instance of type `int` +//│ ║ l.6: class LitBool(b: bool) extends Expr[bool] +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `int` +//│ ║ l.43: e is LitInt(n) then n +//│ ║ ^ +//│ ╟── Note: constraint arises from application: +//│ ║ l.45: e is Add(x, y) then eval(x) + eval(y) +//│ ╙── ^^^^^^^ +//│ fun eval: (e: Expr[out bool | int],) -> (bool | int) + diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index 34666e34d3..7e4b788b01 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -10,16 +10,20 @@ trait Into[T] { trait Nat extends Into[int] //│ trait Nat() { -//│ fun into: int +//│ fun into: 'T //│ } +//│ where +//│ 'T := int trait Product[A, B] extends Into[A] { let pair: (A, B) } //│ trait Product[A, B]() { -//│ fun into: A +//│ fun into: 'T //│ let pair: (A, B,) //│ } +//│ where +//│ 'T := A class TwoInts(pair: (int, int)) extends Product[int, int] { fun into = pair._1 + pair._2 @@ -31,18 +35,10 @@ class TwoInts(pair: (int, int)) extends Product[int, int] { let i2 = TwoInts((1,2)) //│ let i2: TwoInts -// FIXME i2: Product[int, int] -//│ ╔══[ERROR] Type `TwoInts` does not contain member `Product#A` -//│ ║ l.16: trait Product[A, B] extends Into[A] { -//│ ╙── ^ //│ Product[int, int] -// FIXME i2: Into[int] -//│ ╔══[ERROR] Type `TwoInts` does not contain member `Into#T` -//│ ║ l.4: trait Into[T] { -//│ ╙── ^ //│ Into[int] i2.pair @@ -51,3 +47,32 @@ i2.pair i2.into //│ int +let p1: Product[int, int] +//│ let p1: Product[int, int] + +:e +p1: Product[bool, int] +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.54: p1: Product[bool, int] +//│ ║ ^^ +//│ ╟── expression of type `int & ?A` is not an instance of type `bool` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.54: p1: Product[bool, int] +//│ ╙── ^^^^ +//│ Product[bool, int] + +p1: Into[int] +//│ Into[int] + +:e +p1: Into[bool] +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.68: p1: Into[bool] +//│ ║ ^^ +//│ ╟── type `int` is not an instance of type `bool` +//│ ║ l.50: let p1: Product[int, int] +//│ ║ ^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.68: p1: Into[bool] +//│ ╙── ^^^^ +//│ Into[bool] diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index c79f25acc2..4038c1673f 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -744,22 +744,32 @@ trait BInt extends Base[int] { trait BPar[T] extends Base[(int,T)] //│ trait BPar[T]() { -//│ fun f: (int, T,) -> (int, T,) +//│ fun f: 'A -> 'A //│ } +//│ where +//│ 'A := (int, T,) let bi: BInt let bp: BPar[bool] //│ let bi: BInt //│ let bp: BPar[bool] - -// FIXME bp: Base[(int, bool)] -//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.723: trait Base[A] { fun f: A -> A } -//│ ╙── ^ //│ Base[(int, bool,)] +:e +bp: Base[(int, int)] +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.761: bp: Base[(int, int)] +//│ ║ ^^ +//│ ╟── type `bool` is not an instance of type `int` +//│ ║ l.753: let bp: BPar[bool] +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.761: bp: Base[(int, int)] +//│ ╙── ^^^ +//│ Base[(int, int,)] + bi.f(1) //│ nothing @@ -769,12 +779,8 @@ bp.f fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) //│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) -// FIXME fb(bp, false) -//│ ╔══[ERROR] Type `#BPar` does not contain member `Base#A` -//│ ║ l.723: trait Base[A] { fun f: A -> A } -//│ ╙── ^ -//│ (int, false,) | error +//│ (int, bool,) class CP extends BPar[int] { fun f(x) = (x._2, x._1) @@ -786,17 +792,13 @@ class CP extends BPar[int] { let cp1 = CP() //│ let cp1: CP -// FIXME fb(cp1, 2) -//│ ╔══[ERROR] Type `CP` does not contain member `Base#A` -//│ ║ l.723: trait Base[A] { fun f: A -> A } -//│ ╙── ^ -//│ (int, 2,) | error +//│ (int, int,) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.797: trait BErr1 extends Base +//│ ║ l.799: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -805,38 +807,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.806: class DerBad1 extends Base[int, int] +//│ ║ l.808: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.806: class DerBad1 extends Base[int, int] +//│ ║ l.808: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.816: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -872,9 +874,11 @@ trait Tb extends Ta[int] { let p = false } //│ trait Tb() { -//│ let g: int +//│ let g: 'T //│ let p: false //│ } +//│ where +//│ 'T := int class Ctb extends Tb { let p = false @@ -901,11 +905,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.902: class Fischl(age: bool) extends Oz +//│ ║ l.906: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.895: let age: int +//│ ║ l.899: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -924,20 +928,20 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.924: fun foo(x) = x && true +//│ ║ l.928: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.924: fun foo(x) = x && true +//│ ║ l.928: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.924: fun foo(x) = x && true +//│ ║ l.928: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.924: fun foo(x) = x && true +//│ ║ l.928: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.916: fun foo(x) = x + 1 +//│ ║ l.920: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go() { //│ fun foo: bool -> bool @@ -954,10 +958,33 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.955: class Ohhh(x: bool) extends Ha +//│ ║ l.959: class Ohhh(x: bool) extends Ha //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.946: class Ha { let x: int = 1 } +//│ ║ l.950: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) + +trait TA[A] { let a : A } +//│ trait TA[A]() { +//│ let a: A +//│ } + +class G1[A, B](a: A, b: B) extends TA[A] +//│ class G1[A, B](a: A, b: B) + +class G2[T](x: T) extends G1[T, int](x, 1) +//│ class G2[T](x: T) + +let g21 = G2(false) +//│ let g21: G2[false] + +g21: G1[bool, int] +//│ G1[bool, int] + +g21.a +//│ bool + +g21: TA[bool] +//│ TA[bool] From b2c5592682212e7c1a2a193e952f15475efbf2ec Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 11 May 2023 10:10:54 +0800 Subject: [PATCH 280/498] WIP: Support extend and pattern matching(not ready) --- .../src/main/scala/mlscript/JSBackend.scala | 45 +++- .../src/main/scala/mlscript/NewParser.scala | 4 +- .../src/test/diff/codegen/ConstructorStmt.mls | 13 +- .../src/test/diff/codegen/OptionalParam.mls | 249 +++++++++++++++++- shared/src/test/diff/nu/ClassField.mls | 2 +- shared/src/test/diff/nu/Dates.mls | 18 ++ shared/src/test/diff/nu/NestedClasses.mls | 4 +- 7 files changed, 305 insertions(+), 30 deletions(-) create mode 100644 shared/src/test/diff/nu/Dates.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 2049e44d24..5767b275ce 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -111,7 +111,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: NuTypeSymbol with RuntimeSymbol) => - if (sym.needNew) JSNew(translateNuTypeSymbol(sym)) + if (sym.needNew && isCallee) JSNew(translateNuTypeSymbol(sym)) else translateNuTypeSymbol(sym) case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") @@ -324,11 +324,17 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSBinary("===", scrut.member("constructor"), JSLit("String")) case Var(name) => scope.resolveValue(name) match { case S(sym: NewClassSymbol) => - JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) + if (sym.needNew) + JSInstanceOf(scrut, translateVar(sym.lexicalName, false)) + else + JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) case S(sym: ModuleSymbol) => JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) - case S(CapturedSymbol(out, cls: NewClassSymbol)) => - JSInstanceOf(scrut, translateCapture(CapturedSymbol(out, cls)).member("class")) + case S(sym @ CapturedSymbol(out, cls: NewClassSymbol)) => + if (cls.needNew) + JSInstanceOf(scrut, translateCapture(sym)) + else + JSInstanceOf(scrut, translateCapture(sym).member("class")) case S(CapturedSymbol(out, mdl: ModuleSymbol)) => JSInstanceOf(scrut, translateCapture(CapturedSymbol(out, mdl)).member("class")) case S(_: MixinSymbol) => throw new CodeGenError(s"cannot match mixin $name") @@ -508,13 +514,18 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val nd = translateNewTypeDefinition(sym, N, false)(localScope) val ctorMth = localScope.declareValue("ctor", Some(false), false).runtimeName val (constructor, params) = translateNewClassParameters(nd) + val initList = + if (sym.needNew) + Ls(JSReturnStmt(S(JSIdent(sym.lexicalName)))) + else + Ls( + JSLetDecl.from(Ls(ctorMth)), + JSAssignExpr(JSIdent(ctorMth), JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(sym.lexicalName)), params)))).stmt, + JSExprStmt(JSAssignExpr(JSIdent(ctorMth).member("class"), JSIdent(sym.lexicalName))), + JSReturnStmt(S(JSIdent(ctorMth))) + ) JSConstDecl(sym.lexicalName, JSImmEvalFn( - N, Nil, R(Ls( - nd, JSLetDecl.from(Ls(ctorMth)), - JSAssignExpr(JSIdent(ctorMth), JSArrowFn(constructor, L(JSInvoke(JSNew(JSIdent(sym.lexicalName)), params)))).stmt, - JSExprStmt(JSAssignExpr(JSIdent(ctorMth).member("class"), JSIdent(sym.lexicalName))), - JSReturnStmt(S(JSIdent(ctorMth))) - )), Nil + N, Nil, R(nd :: initList), Nil )) case S(sym: MixinSymbol) => val localScope = scope.derive(s"local ${sym.lexicalName}") @@ -568,6 +579,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val name = current match { case JSIdent(nme) => nme case JSInvoke(JSIdent(nme), _) => nme + case JSNew(JSIdent(nme)) => nme + case JSInvoke(JSNew(JSIdent(nme)), _) => nme case f: JSField => f.property.name case JSInvoke(f: JSField, _) => f.property.name case _ => throw CodeGenError("unsupported parents.") @@ -577,11 +590,17 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case Some(CapturedSymbol(out, sym: MixinSymbol)) => JSInvoke(translateCapture(CapturedSymbol(out, sym)), Ls(base)) case Some(CapturedSymbol(out, sym: NuTypeSymbol)) if !mixinOnly => - translateCapture(CapturedSymbol(out, sym)).member("class") + if (sym.needNew) + translateCapture(CapturedSymbol(out, sym)) + else + translateCapture(CapturedSymbol(out, sym)).member("class") case Some(sym: MixinSymbol) => JSInvoke(translateVar(name, false), Ls(base)) - case Some(_: NuTypeSymbol) if !mixinOnly => - translateVar(name, false).member("class") + case Some(sym: NuTypeSymbol) if !mixinOnly => + if (sym.needNew) + translateVar(name, false) + else + translateVar(name, false).member("class") case _ => throw CodeGenError(s"unresolved parent $name.") } } diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 1bebf86a45..6c1c0f2b53 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -404,7 +404,9 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case Some(ctor @ Constructor(tup)) => if (has_params) err(msg"more than one constructor" -> S(l0) :: Nil) (tup, ctor.toLoc) - case _ => (params, N) + case _ => + if (has_params) (params, N) + else (Tup(Nil), tn.toLoc) } val res = NuTypeDef(kind, tn, tparams, real_params, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs, ctorLoc) diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index dddd99e418..adf595df33 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -148,8 +148,7 @@ class Foo { //│ const outer = this; //│ if (this.#Foo === undefined) { //│ class Foo {}; -//│ this.#Foo = (() => Object.freeze(new Foo())); -//│ this.#Foo.class = Foo; +//│ this.#Foo = Foo; //│ } //│ return this.#Foo; //│ } @@ -164,10 +163,10 @@ class Bar { super: { x: int } } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.164: super: { x: int } +//│ ║ l.163: super: { x: int } //│ ╙── ^^^^^ //│ ╔══[ERROR] Class `Bar` does not contain member `x` -//│ ║ l.164: super: { x: int } +//│ ║ l.163: super: { x: int } //│ ╙── ^ //│ class Bar() //│ // Prelude @@ -179,8 +178,7 @@ class Bar { //│ const outer = this; //│ if (this.#Bar === undefined) { //│ class Bar {}; -//│ this.#Bar = (() => Object.freeze(new Bar())); -//│ this.#Bar.class = Bar; +//│ this.#Bar = Bar; //│ } //│ return this.#Bar; //│ } @@ -236,8 +234,7 @@ class Baz { //│ ]); //│ } //│ }; -//│ this.#Baz = (() => Object.freeze(new Baz())); -//│ this.#Baz.class = Baz; +//│ this.#Baz = Baz; //│ } //│ return this.#Baz; //│ } diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 7c48ae651e..91a7bc3823 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -42,8 +42,7 @@ class B {} //│ const outer = this; //│ if (this.#B === undefined) { //│ class B {}; -//│ this.#B = (() => Object.freeze(new B())); -//│ this.#B.class = B; +//│ this.#B = B; //│ } //│ return this.#B; //│ } @@ -105,7 +104,7 @@ class D(x: int) { constructor(y: int) } //│ ╔══[PARSE ERROR] more than one constructor -//│ ║ l.104: class D(x: int) { +//│ ║ l.103: class D(x: int) { //│ ╙── ^^^^^ //│ class D(y: int) @@ -115,7 +114,7 @@ class E { constructor(y: int) } //│ ╔══[PARSE ERROR] more than one constructor -//│ ║ l.113: class E { +//│ ║ l.112: class E { //│ ╙── ^^^^^ //│ class E() @@ -123,8 +122,248 @@ class E { :e constructor(x: int) //│ ╔══[ERROR] constructor must be in a class. -//│ ║ l.124: constructor(x: int) +//│ ║ l.123: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ () //│ Code generation encountered an error: //│ unexpected constructor. + +:e +:js +class F(x: int) extends C(x + 1) {} +class G extends C(2) {} +class H extends B {} +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.133: class F(x: int) extends C(x + 1) {} +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.134: class G extends C(2) {} +//│ ╙── ^^^^ +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.135: class H extends B {} +//│ ╙── ^ +//│ class F(x: int) +//│ class G() +//│ class H() +//│ // Prelude +//│ class TypingUnit6 { +//│ #F; +//│ #G; +//│ #H; +//│ constructor() { +//│ } +//│ get F() { +//│ const outer = this; +//│ if (this.#F === undefined) { +//│ class F extends C { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ super(x + 1); +//│ this.#x = x; +//│ } +//│ }; +//│ this.#F = ((x) => Object.freeze(new F(x))); +//│ this.#F.class = F; +//│ } +//│ return this.#F; +//│ } +//│ get G() { +//│ const outer = this; +//│ if (this.#G === undefined) { +//│ class G extends C { +//│ constructor() { +//│ super(2); +//│ } +//│ }; +//│ this.#G = G; +//│ } +//│ return this.#G; +//│ } +//│ get H() { +//│ const outer = this; +//│ if (this.#H === undefined) { +//│ class H extends B { +//│ constructor() { +//│ super(); +//│ } +//│ }; +//│ this.#H = H; +//│ } +//│ return this.#H; +//│ } +//│ } +//│ const typing_unit6 = new TypingUnit6; +//│ globalThis.F = typing_unit6.F; +//│ globalThis.G = typing_unit6.G; +//│ globalThis.H = typing_unit6.H; +//│ // End of generated code + +:js +fun f(c) = + if c is + F(x) then x + G() then 2 + _ then 0 +//│ fun f: anything -> int +//│ // Prelude +//│ class TypingUnit7 {} +//│ const typing_unit7 = new TypingUnit7; +//│ // Query 1 +//│ globalThis.f = function f(c) { +//│ return ((() => { +//│ let a; +//│ return a = c, a instanceof F.class ? ((x) => x)(c.x) : a instanceof G ? 2 : 0; +//│ })()); +//│ }; +//│ // End of generated code + +f(F(12)) +f(new G()) +//│ int +//│ res +//│ = 12 +//│ res +//│ = 2 + +:js +:e +module I { + class J { + constructor(x: int) + } + module K { + class L extends J(0) + } +} +//│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) +//│ ║ l.236: class L extends J(0) +//│ ╙── ^^^^ +//│ module I() { +//│ class J(x: int) +//│ module K() { +//│ class L() +//│ } +//│ } +//│ // Prelude +//│ class TypingUnit9 { +//│ #I; +//│ constructor() { +//│ } +//│ get I() { +//│ const outer = this; +//│ if (this.#I === undefined) { +//│ class I { +//│ #J; +//│ #K; +//│ constructor() { +//│ } +//│ get K() { +//│ const outer1 = this; +//│ if (this.#K === undefined) { +//│ class K { +//│ #L; +//│ constructor() { +//│ } +//│ get L() { +//│ const outer2 = this; +//│ if (this.#L === undefined) { +//│ class L extends outer1.J { +//│ constructor() { +//│ super(0); +//│ } +//│ }; +//│ this.#L = L; +//│ } +//│ return this.#L; +//│ } +//│ } +//│ this.#K = new K(); +//│ this.#K.class = K; +//│ } +//│ return this.#K; +//│ } +//│ get J() { +//│ const outer1 = this; +//│ if (this.#J === undefined) { +//│ class J { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ } +//│ }; +//│ this.#J = J; +//│ } +//│ return this.#J; +//│ } +//│ } +//│ this.#I = new I(); +//│ this.#I.class = I; +//│ } +//│ return this.#I; +//│ } +//│ } +//│ const typing_unit9 = new TypingUnit9; +//│ globalThis.I = typing_unit9.I; +//│ // End of generated code + +:js +fun g(x: int) = + class L { + constructor(y: int) + fun ll = x + y + } + L +//│ fun g: (x: int,) -> (y: int,) -> L +//│ // Prelude +//│ class TypingUnit10 {} +//│ const typing_unit10 = new TypingUnit10; +//│ // Query 1 +//│ globalThis.g = function g(x) { +//│ return ((() => { +//│ const L = (() => { +//│ class L { +//│ #y; +//│ get y() { return this.#y; } +//│ constructor(y) { +//│ this.#y = y; +//│ } +//│ get ll() { +//│ const y = this.#y; +//│ return x + y; +//│ } +//│ } +//│ return L; +//│ })(); +//│ return L; +//│ })()); +//│ }; +//│ // End of generated code + +// FIXME +:js +let m = g(1) +let n = new m(2) +n.ll +//│ let m: (y: int,) -> L +//│ let n: L +//│ int +//│ // Prelude +//│ class TypingUnit11 {} +//│ const typing_unit11 = new TypingUnit11; +//│ // Query 1 +//│ globalThis.m = g(1); +//│ // Query 2 +//│ globalThis.n = m(2); +//│ // Query 3 +//│ res = n.ll; +//│ // End of generated code +//│ m +//│ = [class L] +//│ n +//│ Runtime error: +//│ TypeError: Class constructor L cannot be invoked without 'new' +//│ res +//│ Runtime error: +//│ ReferenceError: n is not defined diff --git a/shared/src/test/diff/nu/ClassField.mls b/shared/src/test/diff/nu/ClassField.mls index 2ef4c13b11..dd6f6ec421 100644 --- a/shared/src/test/diff/nu/ClassField.mls +++ b/shared/src/test/diff/nu/ClassField.mls @@ -47,7 +47,7 @@ typeof(cls) mixin Base //│ mixin Base() -class Derived extends Base +class Derived() extends Base //│ class Derived() // * Strangely, we now get `{ class: [Function: Derived] }` diff --git a/shared/src/test/diff/nu/Dates.mls b/shared/src/test/diff/nu/Dates.mls new file mode 100644 index 0000000000..e4b1b00085 --- /dev/null +++ b/shared/src/test/diff/nu/Dates.mls @@ -0,0 +1,18 @@ +:NewDefs + +declare class Date { + constructor(date: number) + fun toString(): string +} +//│ class Date(date: number) { +//│ fun toString: () -> string +//│ } + +let date1 = new Date(12345678) +date1.toString() +//│ let date1: Date +//│ string +//│ date1 +//│ = 1970-01-01T03:25:45.678Z +//│ res +//│ = 'Thu Jan 01 1970 11:25:45 GMT+0800 (China Standard Time)' diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index 0c7a75bde0..202cf41bfa 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -20,7 +20,7 @@ c.NC0 //│ ╙── ^^^^ //│ error //│ res -//│ = [Function (anonymous)] { class: [class NC0] } +//│ = [class NC0] module M0 { @@ -37,7 +37,7 @@ M0.NC0 //│ ╙── ^^^^ //│ error //│ res -//│ = [Function (anonymous)] { class: [class NC0] } +//│ = [class NC0] module M1 { From 2d356965e38af4854a68cf6489ab6d3b5e2878aa Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 11 May 2023 15:25:09 +0800 Subject: [PATCH 281/498] WIP Add a test --- .../src/test/diff/nu/ImplicitMethodPolym.mls | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 shared/src/test/diff/nu/ImplicitMethodPolym.mls diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls new file mode 100644 index 0000000000..f806c89263 --- /dev/null +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -0,0 +1,146 @@ +:NewDefs + + +module M { + fun id(x) = x +} +//│ module M() { +//│ fun id: 'a -> 'a +//│ } + +M.id +//│ 'a -> 'a +//│ res +//│ = [Function: id] + +M.id(true) +//│ true +//│ res +//│ = true + +M.id(0) +//│ 0 +//│ res +//│ = 0 + + +class C { + fun id1(x) = x + fun f = (id1(true), id1(0)) + fun id2(x) = x +} +//│ class C() { +//│ fun f: (0 | true | 'a, 0 | true | 'b,) +//│ fun id1: ('b & 'a) -> (0 | true | 'a) +//│ fun id2: 'c -> 'c +//│ } + +// FIXME +module M extends C { + fun g = (this.id2(true), this.id2(0)) +} +//│ ╔══[ERROR] Type `#M` does not contain member `id2` +//│ ║ l.40: fun g = (this.id2(true), this.id2(0)) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type `#M` does not contain member `id2` +//│ ║ l.40: fun g = (this.id2(true), this.id2(0)) +//│ ╙── ^^^^ +//│ module M() { +//│ fun f: forall 'a 'b. (0 | true | 'a, 0 | true | 'b,) +//│ fun g: (error, error,) +//│ fun id1: forall 'a 'b. ('b & 'a) -> (0 | true | 'a) +//│ fun id2: forall 'c. 'c -> 'c +//│ } + +M.id1 +//│ forall 'a. 'a -> (0 | true | 'a) +//│ res +//│ = [Function: id1] + +M.id2 +//│ forall 'a. 'a -> 'a +//│ res +//│ = [Function: id2] + +M.f +//│ (0 | true, 0 | true,) +//│ res +//│ = [ true, 0 ] + +M.g +//│ (error, error,) +//│ res +//│ = [ true, 0 ] + + +:e +module M extends C { + fun id1 = succ +} +//│ ╔══[ERROR] Type mismatch in definition of method id1: +//│ ║ l.78: fun id1 = succ +//│ ║ ^^^^^^^^^^ +//│ ╟── application of type `?a` does not match type `int | ~(?b & ?c)` +//│ ║ l.29: fun f = (id1(true), id1(0)) +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in definition of method id1: +//│ ║ l.78: fun id1 = succ +//│ ║ ^^^^^^^^^^ +//│ ╟── type `int` does not match type `0 | true | ?a` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.28: fun id1(x) = x +//│ ╙── ^ +//│ module M() { +//│ fun f: (0 | true, 0 | true,) +//│ fun id1: int -> int +//│ fun id2: forall 'a. 'a -> 'a +//│ } + +M.id1 +//│ int -> int +//│ res +//│ = [Function: succ] + + +(M : C).id1(false) +//│ 0 | false | true +//│ res +//│ = 1 + + +// FIXME? parsing/semantics of this, currently treated as a named tuple... +(M: C) +//│ (M: () -> C,) +//│ res +//│ = [ [Function (anonymous)] { class: [class C] } ] + + + +module None +//│ module None() + +// TODO parse +// TODO reject; polymophism should be blocked by mutation from distributing/refreshing +:pe +:e +module M { + mut val m = None + fun oops(x) = m := x +} +//│ ╔══[PARSE ERROR] Unexpected 'mut' keyword in expression position +//│ ║ l.127: mut val m = None +//│ ╙── ^^^ +//│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position +//│ ║ l.127: mut val m = None +//│ ╙── ^^^ +//│ ╔══[PARSE ERROR] Unexpected '=' here +//│ ║ l.127: mut val m = None +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: m +//│ ║ l.127: mut val m = None +//│ ╙── ^ +//│ module M() +//│ Code generation encountered an error: +//│ unresolved symbol m + + From e11001ba052db0ee350f6b9debb7b3bc5f47b502 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 12 May 2023 08:50:16 +0800 Subject: [PATCH 282/498] WIP: Refactor code --- shared/src/main/scala/mlscript/NewParser.scala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 6c1c0f2b53..788f9dc39b 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -358,12 +358,12 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D rec(toks, S(br.innerLoc), br.describe).concludeWith(_.maybeIndented((p, _) => p.typeParams)) case _ => Nil } - val (params, has_params) = yeetSpaces match { + val params = yeetSpaces match { case (br @ BRACKETS(Round, toks), loc) :: _ => consume val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO - (Tup(as).withLoc(S(loc)), true) - case _ => (Tup(Nil), false) + S(Tup(as).withLoc(S(loc))) + case _ => N } def otherParents: Ls[Term] = yeetSpaces match { case (COMMA, _) :: _ => @@ -402,11 +402,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } else ctor.headOption match { case Some(ctor @ Constructor(tup)) => - if (has_params) err(msg"more than one constructor" -> S(l0) :: Nil) + if (params.isDefined) err(msg"more than one constructor" -> S(l0) :: Nil) (tup, ctor.toLoc) case _ => - if (has_params) (params, N) - else (Tup(Nil), tn.toLoc) + (params.getOrElse(Tup(Nil)), if (params.isDefined) N else tn.toLoc) } val res = NuTypeDef(kind, tn, tparams, real_params, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs, ctorLoc) From 84a30f057ccfef280f3aa97d42497a04dcdc69a9 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 12 May 2023 09:07:13 +0800 Subject: [PATCH 283/498] WIP: Force new in new NuTypeSym --- shared/src/main/scala/mlscript/JSBackend.scala | 17 +++++++++++++---- .../src/test/diff/codegen/ConstructorStmt.mls | 5 +++-- .../test/diff/ecoop23/PolymorphicVariants.mls | 2 +- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 6 +++--- shared/src/test/diff/nu/GenericClasses.mls | 4 ++-- shared/src/test/diff/nu/NestedClasses.mls | 6 +++--- shared/src/test/diff/nu/ParamOverride.mls | 2 +- 7 files changed, 26 insertions(+), 16 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 5767b275ce..2b077d8435 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -111,8 +111,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: NuTypeSymbol with RuntimeSymbol) => - if (sym.needNew && isCallee) JSNew(translateNuTypeSymbol(sym)) - else translateNuTypeSymbol(sym) + translateNuTypeSymbol(sym) case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") scope.resolveValue("this") match { @@ -159,7 +158,11 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Function invocation case App(trm, Tup(args)) => val callee = trm match { - case Var(nme) => translateVar(nme, true) + case Var(nme) => scope.resolveValue(nme) match { + case S(sym: NuTypeSymbol with RuntimeSymbol) => + translateNuTypeSymbol(sym) + case _ => translateVar(nme, true) + } case _ => translateTerm(trm) } callee(args map { case (_, Fld(_, _, arg)) => translateTerm(arg) }: _*) @@ -288,7 +291,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { throw CodeGenError(s"if expression was not desugared") case New(N, TypingUnit(Nil)) => JSRecord(Nil) case New(S(TypeName(className) -> Tup(args)), TypingUnit(Nil)) => - val callee = translateVar(className, true) + val callee = scope.resolveValue(className) match { + case S(sym: NuTypeSymbol with RuntimeSymbol) => + if (sym.needNew) JSNew(translateNuTypeSymbol(sym)) + else throw CodeGenError(s"invalid `new` keyword in $className instantiation.") + case _ => + translateVar(className, true) + } callee(args.map { case (_, Fld(_, _, arg)) => translateTerm(arg) }: _*) case New(_, TypingUnit(_)) => throw CodeGenError("custom class body is not supported yet") diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index adf595df33..1f9580619b 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -188,7 +188,7 @@ class Bar { //│ // End of generated code :js -class Baz { +class Baz() { let x = 123 log((1, x)) let y = @@ -234,7 +234,8 @@ class Baz { //│ ]); //│ } //│ }; -//│ this.#Baz = Baz; +//│ this.#Baz = (() => Object.freeze(new Baz())); +//│ this.#Baz.class = Baz; //│ } //│ return this.#Baz; //│ } diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index c05c6bb0fe..bc53ebe043 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -15,7 +15,7 @@ let l = Cons(1, Nil) //│ l //│ = Cons {} -class NotFound +class NotFound() class Success[A](result: A) //│ class NotFound() //│ class Success[A](result: A) diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 0e42519908..13e12f12a5 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -59,8 +59,8 @@ let circles = go(2, 1024) // ******************* Adding More Language Constructs ******************* -class Univ -class Empty +class Univ() +class Empty() class Scale[Region](v: Vector, a: Region) //│ class Univ() //│ class Empty() @@ -295,7 +295,7 @@ IsUnivIsEmpty.isEmpty(circles) //│ res //│ = false -class Foo +class Foo() IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) //│ class Foo() //│ bool diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 513d081580..f354992e74 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -291,7 +291,7 @@ t.id :e -class TestBad { +class TestBad() { fun foo1(x: A) = x fun foo2(x: A) = x + 1 } @@ -302,7 +302,7 @@ class TestBad { //│ ║ l.296: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.294: class TestBad { +//│ ║ l.294: class TestBad() { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index 202cf41bfa..736bb58985 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -1,8 +1,8 @@ :NewDefs -class C0 { - class NC0 +class C0() { + class NC0() } //│ class C0() { //│ class NC0() @@ -20,7 +20,7 @@ c.NC0 //│ ╙── ^^^^ //│ error //│ res -//│ = [class NC0] +//│ = [Function (anonymous)] { class: [class NC0] } module M0 { diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index 48ccfb0a0c..ae87811999 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -38,7 +38,7 @@ mixin Derived1(n: int) { //│ } -class Test0 extends Base1(1/2), Derived1(1) +class Test0() extends Base1(1/2), Derived1(1) //│ class Test0() { //│ fun foo: (int, 1, number,) //│ fun original: number From 176f7cea6fb5344b208f6c1f8e9901bd0c1d2d24 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 12 May 2023 09:17:47 +0800 Subject: [PATCH 284/498] WIP: Fix New generation --- shared/src/main/scala/mlscript/JSBackend.scala | 9 +++------ shared/src/test/diff/codegen/OptionalParam.mls | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 2b077d8435..ed9abae7f2 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -291,12 +291,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { throw CodeGenError(s"if expression was not desugared") case New(N, TypingUnit(Nil)) => JSRecord(Nil) case New(S(TypeName(className) -> Tup(args)), TypingUnit(Nil)) => - val callee = scope.resolveValue(className) match { - case S(sym: NuTypeSymbol with RuntimeSymbol) => - if (sym.needNew) JSNew(translateNuTypeSymbol(sym)) - else throw CodeGenError(s"invalid `new` keyword in $className instantiation.") - case _ => - translateVar(className, true) + val callee = translateVar(className, true) match { + case n: JSNew => n + case t => JSNew(t) } callee(args.map { case (_, Fld(_, _, arg)) => translateTerm(arg) }: _*) case New(_, TypingUnit(_)) => diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 91a7bc3823..cf71149da8 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -341,7 +341,6 @@ fun g(x: int) = //│ }; //│ // End of generated code -// FIXME :js let m = g(1) let n = new m(2) @@ -355,15 +354,24 @@ n.ll //│ // Query 1 //│ globalThis.m = g(1); //│ // Query 2 -//│ globalThis.n = m(2); +//│ globalThis.n = new m(2); //│ // Query 3 //│ res = n.ll; //│ // End of generated code //│ m //│ = [class L] //│ n -//│ Runtime error: -//│ TypeError: Class constructor L cannot be invoked without 'new' +//│ = L {} //│ res +//│ = 3 + +// TODO reject +// :e +:re +class M() +let mm = new M() +//│ class M() +//│ let mm: M +//│ mm //│ Runtime error: -//│ ReferenceError: n is not defined +//│ TypeError: M is not a constructor From 66d41f279648dd67507d442fa96330bec17075e7 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 13 May 2023 02:06:38 +0800 Subject: [PATCH 285/498] Fix comments --- shared/src/main/scala/mlscript/NewLexer.scala | 4 +- .../src/main/scala/mlscript/ucs/Clause.scala | 12 +-- .../main/scala/mlscript/ucs/Conjunction.scala | 2 +- .../main/scala/mlscript/ucs/Desugarer.scala | 53 --------- .../main/scala/mlscript/ucs/LetBinding.scala | 6 +- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 1 - shared/src/test/diff/tapl/NuSimplyTyped.mls | 21 ---- shared/src/test/diff/tapl/NuUntyped.mls | 21 ---- shared/src/test/diff/tapl/SimplyTyped.mls | 101 ++++++++---------- shared/src/test/diff/tapl/Untyped.mls | 34 ++---- shared/src/test/diff/ucs/JSON.mls | 29 +---- 11 files changed, 67 insertions(+), 217 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 26040d2ebd..b79abe599b 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -57,7 +57,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { else (cur.reverseIterator.mkString, i) @tailrec final - def str(i: Int, escapeMode: Bool = false, cur: Ls[Char] = Nil): (Str, Int) = + def str(i: Int, escapeMode: Bool, cur: Ls[Char] = Nil): (Str, Int) = if (escapeMode) if (i < length) bytes(i) match { @@ -106,7 +106,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { lex(j, ind, next(j, COMMA)) case '"' => val j = i + 1 - val (chars, k) = str(j) + val (chars, k) = str(j, false) val k2 = if (bytes.lift(k) === Some('"')) k + 1 else { pe(msg"unclosed quotation mark") k diff --git a/shared/src/main/scala/mlscript/ucs/Clause.scala b/shared/src/main/scala/mlscript/ucs/Clause.scala index 12cd4c1c04..b91354d984 100644 --- a/shared/src/main/scala/mlscript/ucs/Clause.scala +++ b/shared/src/main/scala/mlscript/ucs/Clause.scala @@ -38,11 +38,11 @@ object Clause { override val scrutinee: Scrutinee, literal: SimpleTerm )(override val locations: Ls[Loc]) extends MatchClause { - override def toString(): String = s"«$scrutinee is $literal" + bindingsToString + override def toString: String = s"«$scrutinee is $literal" + bindingsToString } final case class MatchAny(override val scrutinee: Scrutinee)(override val locations: Ls[Loc]) extends MatchClause { - override def toString(): String = s"«$scrutinee is any" + bindingsToString + override def toString: String = s"«$scrutinee is any" + bindingsToString } final case class MatchClass( @@ -50,7 +50,7 @@ object Clause { className: Var, fields: Ls[Str -> Var] )(override val locations: Ls[Loc]) extends MatchClause { - override def toString(): String = s"«$scrutinee is $className»" + bindingsToString + override def toString: String = s"«$scrutinee is $className»" + bindingsToString } final case class MatchTuple( @@ -58,13 +58,13 @@ object Clause { arity: Int, fields: Ls[Str -> Var] )(override val locations: Ls[Loc]) extends Clause { - override def toString(): String = s"«$scrutinee is Tuple#$arity»" + bindingsToString + override def toString: String = s"«$scrutinee is Tuple#$arity»" + bindingsToString } final case class BooleanTest(test: Term)( override val locations: Ls[Loc] ) extends Clause { - override def toString(): String = s"«$test»" + bindingsToString + override def toString: String = s"«$test»" + bindingsToString } /** @@ -73,6 +73,6 @@ object Clause { final case class Binding(name: Var, term: Term, isField: Bool)( override val locations: Ls[Loc] ) extends Clause { - override def toString(): String = s"«$name = $term»" + bindingsToString + override def toString: String = s"«$name = $term»" + bindingsToString } } diff --git a/shared/src/main/scala/mlscript/ucs/Conjunction.scala b/shared/src/main/scala/mlscript/ucs/Conjunction.scala index 18f03eff28..f0928dccef 100644 --- a/shared/src/main/scala/mlscript/ucs/Conjunction.scala +++ b/shared/src/main/scala/mlscript/ucs/Conjunction.scala @@ -9,7 +9,7 @@ import scala.annotation.tailrec * A `Conjunction` represents a list of `Clause`s. */ final case class Conjunction(clauses: Ls[Clause], trailingBindings: Ls[LetBinding]) { - override def toString(): String = + override def toString: String = clauses.mkString("", " and ", "") + { (if (trailingBindings.isEmpty) "" else " ") + (trailingBindings match { diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 98888beb50..f5d3325f94 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -765,48 +765,6 @@ class Desugarer extends TypeDefs { self: Typer => } }(_ => s"[checkExhaustive] ${t.describe}") - // private def summarizePatterns(t: MutCaseOf)(implicit ctx: Ctx, raise: Raise): ExhaustivenessMap = traceUCS("[summarizePatterns]") { - // val m = MutMap.empty[Str \/ Int, MutMap[Var, MutCase]] - // def rec(t: MutCaseOf): Unit = traceUCS(s"[rec] ${t.describe}") { - // t match { - // case Consequent(term) => () - // case MissingCase => () - // case IfThenElse(_, whenTrue, whenFalse) => - // rec(whenTrue) - // rec(whenFalse) - // case Match(scrutinee, branches, default) => - // val key = getScurtineeKey(scrutinee) - // val patternMap = m.getOrElseUpdate(key, MutMap.empty) - // branches.foreach { - // case mutCase @ MutCase.Literal(literal, consequent) => - // literal match { - // case tof @ Var(n) if n === "true" || n === "false" => - // if (!patternMap.contains(tof)) { - // patternMap += ((tof, mutCase)) - // } - // case _ => () // TODO: Summarize literals. - // } - // rec(consequent) - // case mutCase @ MutCase.Constructor((className, _), consequent) => - // if (!patternMap.contains(className)) { - // patternMap += ((className, mutCase)) - // } - // rec(consequent) - // } - // default.foreach(rec) - // } - // }() - // rec(t) - // printlnUCS("Summarized patterns") - // if (m.isEmpty) - // printlnUCS(" ") - // else - // m.foreach { case (scrutinee, patterns) => - // printlnUCS(s" * $scrutinee => " + patterns.keysIterator.mkString(", ")) - // } - // Map.from(m.iterator.map { case (key, patternMap) => key -> Map.from(patternMap) }) - // }(_ => "[summarizePatterns]") - /** * Make a term from a mutable case tree. * This should be called after exhaustiveness checking. @@ -993,17 +951,6 @@ class Desugarer extends TypeDefs { self: Typer => className -> td.baseClasses.iterator.map(_.name).toList } |> Map.from Desugarer.transitiveClosure(superClassMap) - // ctx.tyDefs2 - // val superClassMap = ctx.tyDefs2.iterator.map { case (className, dti) => - // className -> dti.decl.body - // } |> Map.from - // printlnUCS("• ctx.tyDefs") - // if (superClassMap.isEmpty) - // printlnUCS(" * ") - // else - // superClassMap.foreach { case (className, superClassNames) => - // printlnUCS(s" * $className <- ${superClassNames.mkString(", ")}") - // } }(_ => "[getClassHierarchy]") } diff --git a/shared/src/main/scala/mlscript/ucs/LetBinding.scala b/shared/src/main/scala/mlscript/ucs/LetBinding.scala index 167877245d..3d86c09f4f 100644 --- a/shared/src/main/scala/mlscript/ucs/LetBinding.scala +++ b/shared/src/main/scala/mlscript/ucs/LetBinding.scala @@ -13,13 +13,13 @@ object LetBinding { object Kind { case object ScrutineeAlias extends Kind { - override def toString(): String = "scrutinee alias" + override def toString: String = "scrutinee alias" } case object FieldExtraction extends Kind { - override def toString(): String = "pattern destruction" + override def toString: String = "pattern destruction" } case object InterleavedLet extends Kind { - override def toString(): String = "interleaved let" + override def toString: String = "interleaved let" } } } diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index ad42627a90..8607b174f0 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -40,7 +40,6 @@ fun mk(n) = if n is //│ where //│ 'E :> Add['E] | Lit | Neg['E] -// TODO support this in UCS :stats TestLang.eval(mk(0)) //│ int diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls index e9d8c66fa1..e34f1c569e 100644 --- a/shared/src/test/diff/tapl/NuSimplyTyped.mls +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -1,27 +1,6 @@ :NewParser :NewDefs -:escape -// You can push debug messages to this magic array. -let Array: { from: anything => { push: anything => anything, join: string => string } } -let _Array = Array -let logs: { push: anything => anything, join: string => string } = _Array.from([]) -let debug: anything => anything = x => logs.push(x) -fun showDebug = logs.join("\n") -//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let logs: {join: string -> string, push: anything -> anything} -//│ let debug: anything -> anything -//│ fun showDebug: string -//│ Array -//│ = -//│ _Array -//│ = [Function: Array] -//│ logs -//│ = [] -//│ debug -//│ = [Function: debug] - let str = toString fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index f39f502a7d..2ecfed25be 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -1,27 +1,6 @@ :NewParser :NewDefs -:escape -// You can push debug messages to this magic array. -let Array: { from: anything => { push: anything => anything, join: string => string } } -let _Array = Array -let logs: { push: anything => anything, join: string => string } = _Array.from([]) -let debug: anything => anything = x => logs.push(x) -fun showDebug = logs.join("\n") -//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let logs: {join: string -> string, push: anything -> anything} -//│ let debug: anything -> anything -//│ fun showDebug: string -//│ Array -//│ = -//│ _Array -//│ = [Function: Array] -//│ logs -//│ = [] -//│ debug -//│ = [Function: debug] - fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) diff --git a/shared/src/test/diff/tapl/SimplyTyped.mls b/shared/src/test/diff/tapl/SimplyTyped.mls index eecd08ede5..6e097a41e1 100644 --- a/shared/src/test/diff/tapl/SimplyTyped.mls +++ b/shared/src/test/diff/tapl/SimplyTyped.mls @@ -1,23 +1,5 @@ :NewParser -:escape -// You can push debug messages to this magic array. -let Array: { from: anything => { push: anything => anything, join: string => string } } -let _Array = Array -let logs: { push: anything => anything, join: string => string } = _Array.from([]) -let debug: anything => anything = x => logs.push(x) -fun showDebug = logs.join("\n") -//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = -//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = [Function: Array] -//│ logs: {join: string -> string, push: anything -> anything} -//│ = [] -//│ debug: anything -> anything -//│ = [Function: debug] -//│ showDebug: string -//│ = [Function: showDebug] - fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) @@ -239,75 +221,75 @@ fun typeTerm(t, ctx) = Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) Err(message) then Err(message) //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.224: fun typeTerm(t, ctx) = +//│ ║ l.206: fun typeTerm(t, ctx) = //│ ║ ^^^^^^^^^^ -//│ ║ l.225: if t is +//│ ║ l.207: if t is //│ ║ ^^^^^^^^^ -//│ ║ l.226: Lit(_, ty) then Ok(ty) +//│ ║ l.208: Lit(_, ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.227: Var(name) and find(ctx, name) is +//│ ║ l.209: Var(name) and find(ctx, name) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.228: Some(ty) then Ok(ty) +//│ ║ l.210: Some(ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.229: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ l.211: None then Err(concat3("unbound variable `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.230: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ l.212: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.231: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ l.213: Ok(resTy) then Ok(FunctionType(ty, resTy)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.232: Err(message) then Err(message) +//│ ║ l.214: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.233: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ l.215: App(lhs, rhs) and typeTerm(lhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.234: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ l.216: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.235: Ok(aTy) and +//│ ║ l.217: Ok(aTy) and //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ l.218: typeEqual(pTy, aTy) then Ok(resTy) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ l.219: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.238: Err(message) then Err(message) +//│ ║ l.220: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.239: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ l.221: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.240: Err(message) then Err(message) +//│ ║ l.222: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.224: fun typeTerm(t, ctx) = +//│ ║ l.206: fun typeTerm(t, ctx) = //│ ║ ^^^^^^^^^^ -//│ ║ l.225: if t is +//│ ║ l.207: if t is //│ ║ ^^^^^^^^^ -//│ ║ l.226: Lit(_, ty) then Ok(ty) +//│ ║ l.208: Lit(_, ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.227: Var(name) and find(ctx, name) is +//│ ║ l.209: Var(name) and find(ctx, name) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.228: Some(ty) then Ok(ty) +//│ ║ l.210: Some(ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.229: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ l.211: None then Err(concat3("unbound variable `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.230: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ l.212: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.231: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ l.213: Ok(resTy) then Ok(FunctionType(ty, resTy)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.232: Err(message) then Err(message) +//│ ║ l.214: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.233: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ l.215: App(lhs, rhs) and typeTerm(lhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.234: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ l.216: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.235: Ok(aTy) and +//│ ║ l.217: Ok(aTy) and //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.236: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ l.218: typeEqual(pTy, aTy) then Ok(resTy) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.237: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ l.219: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.238: Err(message) then Err(message) +//│ ║ l.220: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.239: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ l.221: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.240: Err(message) then Err(message) +//│ ║ l.222: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ typeTerm: ('rhs, 'right,) -> (Err & {message: 'message} | Ok & {value: 'ty}) @@ -315,15 +297,15 @@ fun typeTerm(t, ctx) = //│ 'message :> string //│ 'right <: 'right0 & (Empty | Node & {key: string, left: 'right, right: 'right}) //│ 'right0 <: Empty | Node & {key: string, left: 'right0, right: 'right0, value: 'ty & 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType))} -//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'lhs & 'lty & 'rhs0 & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)), rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'ty & 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType))} | Var & {name: string} +//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'rhs0 & 'lhs & 'lty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)), rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'ty & 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType))} | Var & {name: string} //│ 'a <: {lhs: 'rhs0 & 'lhs, rhs: 'rhs1} //│ 'rhs1 :> 'ty //│ <: 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) //│ 'b <: {lhs: 'rhs2, rhs: 'rhs2} //│ 'rhs2 <: FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType //│ 'ty :> 'lty | FunctionType & {lhs: 'lty, rhs: 'ty} | 'rhs1 -//│ 'rhs0 <: FunctionType & {lhs: 'rhs0, rhs: 'rhs0} | PrimitiveType | ~FunctionType & ~PrimitiveType //│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} +//│ 'rhs0 <: FunctionType & {lhs: 'rhs0, rhs: 'rhs0} | PrimitiveType | ~FunctionType & ~PrimitiveType //│ = [Function: typeTerm] // FIXME @@ -344,12 +326,13 @@ fun showTypeTerm(t, ctx) = //│ 'c <: {lhs: 'rhs5, rhs: 'rhs5} //│ 'rhs5 <: FunctionType & 'c | PrimitiveType | ~FunctionType & ~PrimitiveType //│ 'rhs0 <: Abs & {lhs: 'rhs0, lty: 'lhs, rhs: 'rhs0} | App & {lhs: 'rhs0 & (Abs & {lhs: 'rhs0, lty: 'lhs} | ~#Abs), rhs: 'rhs0} | Lit | Var -//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'rhs2 & 'lhs & 'rhs6, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'rhs6} | Var & {name: string} -//│ 'rhs6 <: 'lhs & (PrimitiveType & {name: string} | {lhs: 'rhs2 & 'lhs, rhs: 'rhs6} & (FunctionType & 'd | FunctionType & ~#FunctionType)) -//│ 'd <: {lhs: 'rhs7, rhs: 'rhs7} -//│ 'rhs7 <: FunctionType & 'd | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} +//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'lhs & 'rhs2 & (PrimitiveType & {name: string} | 'd & (FunctionType & 'e | FunctionType & ~#FunctionType)), rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'rhs6} | Var & {name: string} +//│ 'd <: {lhs: 'rhs2 & 'lhs, rhs: 'rhs6} +//│ 'rhs6 <: 'lhs & (PrimitiveType & {name: string} | 'd & (FunctionType & 'e | FunctionType & ~#FunctionType)) +//│ 'e <: {lhs: 'rhs7, rhs: 'rhs7} +//│ 'rhs7 <: FunctionType & 'e | PrimitiveType | ~FunctionType & ~PrimitiveType //│ 'rhs2 <: FunctionType & {lhs: 'rhs2, rhs: 'rhs2} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} //│ = [Function: showTypeTerm] // FIXME diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls index ace6292343..4dbba3420c 100644 --- a/shared/src/test/diff/tapl/Untyped.mls +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -1,23 +1,5 @@ :NewParser -:escape -// You can push debug messages to this magic array. -let Array: { from: anything => { push: anything => anything, join: string => string } } -let _Array = Array -let logs: { push: anything => anything, join: string => string } = _Array.from([]) -let debug: anything => anything = x => logs.push(x) -fun showDebug = logs.join("\n") -//│ Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = -//│ _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ = [Function: Array] -//│ logs: {join: string -> string, push: anything -> anything} -//│ = [] -//│ debug: anything -> anything -//│ = [Function: debug] -//│ showDebug: string -//│ = [Function: showDebug] - fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) @@ -414,13 +396,13 @@ fun showSubst(t, n, v) = //│ where //│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var //│ 'rhs0 <: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var -//│ 'a <: 'rhs1 & 'lhs & 'rhs2 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'b | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'c | {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'c <: 'rhs1 & 'lhs & 'rhs2 & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'd <: 'rhs1 & 'lhs & 'rhs2 & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) +//│ 'a <: 'lhs & 'rhs2 & 'rhs1 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'b | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'c | {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'c <: 'lhs & 'rhs2 & 'rhs1 & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'd <: 'lhs & 'rhs2 & 'rhs1 & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) //│ 'b <: {lhs: 'rhs0, rhs: 'rhs0} +//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var //│ 'lhs <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | ~Abs //│ 'rhs2 <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | App & {lhs: 'lhs & 'rhs2, rhs: 'rhs2} | Var -//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var //│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var //│ = [Function: showSubst] @@ -479,14 +461,14 @@ fun showStepByValue(t) = ) //│ showStepByValue: ('rhs & (Abs | App & 'a | Var)) -> string //│ where -//│ 'a <: {lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), rhs: 'lhs & 'rhs0 & 'rhs2 & 'rhs3 & (Abs | App & 'a | Var)} -//│ 'rhs2 <: Abs & {rhs: 'rhs2} | App & {lhs: 'rhs2, rhs: 'rhs2} | Var | ~Abs & ~App & ~Var +//│ 'a <: {lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), rhs: 'rhs2 & 'lhs & 'rhs0 & 'rhs3 & (Abs | App & 'a | Var)} +//│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var //│ 'rhs1 <: Abs & 'b | App & 'c | Var & 'd | 'e & ~#Abs & ~#App & ~#Var -//│ 'b <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'c | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'd | {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'e & ~#Abs & ~#App & ~#Var) +//│ 'b <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'c | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'd | {lhs: Var & {name: string} | ~Var, rhs: 'rhs2} & 'e & ~#Abs & ~#App & ~#Var) //│ 'd <: 'rhs4 & 'lhs & 'rhs0 & (Abs & {name: anything} & 'b | App & {name: anything} & 'c | Var | {name: anything} & 'e & ~#Abs & ~#App & ~#Var) //│ 'e <: 'rhs4 & 'lhs & 'rhs0 & (Abs & 'b | App & 'c | Var & 'd | ~#Abs & ~#App & ~#Var) //│ 'c <: {lhs: 'rhs1, rhs: 'rhs1} -//│ 'rhs3 <: 'rhs1 & 'rhs4 +//│ 'rhs2 <: 'rhs1 & 'rhs4 //│ 'rhs4 <: Abs & {lhs: Var, rhs: 'rhs4} | App & {lhs: 'rhs4, rhs: 'rhs4} | Var //│ 'lhs <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | ~Abs //│ 'rhs0 <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | App & {lhs: 'lhs & 'rhs0, rhs: 'rhs0} | Var diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index 35aa3c9bf0..ce5b47c5e4 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -2,43 +2,24 @@ :NewDefs :escape -// You can push debug messages to this magic array. -let Array: { from: anything => { push: anything => anything, join: string => string } } -let _Array = Array -let logs: { push: anything => anything, join: string => string } = _Array.from([]) -let debug: anything => anything = x => logs.push(x) -fun showDebug = logs.join("\n") // We need to use some native methods on `String`. let String: nothing let asNativeString: anything => { length: int, charCodeAt: int => int, charAt: int => string, slice: int => string } = String let StringInstance: { fromCharCode: int => string } = String // We will validate our implementation with the built-in `JSON.parse`. let JSON: { parse: string => anything, stringify: anything => string } -//│ let Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let _Array: {from: anything -> {join: string -> string, push: anything -> anything}} -//│ let logs: {join: string -> string, push: anything -> anything} -//│ let debug: anything -> anything -//│ fun showDebug: string //│ let String: nothing //│ let asNativeString: anything -> {charAt: int -> string, charCodeAt: int -> int, length: int, slice: int -> string} //│ let StringInstance: {fromCharCode: int -> string} //│ let JSON: {parse: string -> anything, stringify: anything -> string} -//│ Array -//│ = -//│ _Array -//│ = [Function: Array] -//│ logs -//│ = [] -//│ debug -//│ = [Function: debug] //│ String -//│ = [Function: showDebug] +//│ = //│ asNativeString -//│ = +//│ = [Function: String] //│ StringInstance //│ = [Function: String] //│ JSON -//│ = [Function: String] +//│ = JSON.parse("{ \"xs\": [1, 2, 3], \"yes\": true, \"no\": false, \"insane\": null }") //│ anything @@ -123,10 +104,10 @@ fun listJoin(xs, sep) = //│ type List[A] = Cons[A] | Nil //│ module Nil() //│ class Cons[A](head: A, tail: List[A]) -//│ fun listConcat: forall 'A 'a 'A0. (Cons['A0] | Nil, List['A] & 'a,) -> (Cons['A] | 'a) +//│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) //│ fun listJoin: forall 'A1. (Cons['A1] | Nil, string,) -> string //│ where -//│ 'A0 <: 'A +//│ 'A <: 'A0 type TreeMap[A] = Node[A] | Empty module Empty From 8694f1c738cff6d2601ab3ac80533120c026f0f1 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 16 May 2023 15:59:41 +0800 Subject: [PATCH 286/498] WIP: Rename field and generate .class in new --- shared/src/main/scala/mlscript/JSBackend.scala | 15 ++++++++------- .../src/main/scala/mlscript/codegen/Symbol.scala | 8 ++++---- shared/src/test/diff/codegen/OptionalParam.mls | 16 ++++++++++------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index ed9abae7f2..110018c40b 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -111,7 +111,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: NuTypeSymbol with RuntimeSymbol) => - translateNuTypeSymbol(sym) + if (sym.isPlain || !isCallee) translateNuTypeSymbol(sym) + else translateNuTypeSymbol(sym).member("class") case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") scope.resolveValue("this") match { @@ -330,14 +331,14 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSBinary("===", scrut.member("constructor"), JSLit("String")) case Var(name) => scope.resolveValue(name) match { case S(sym: NewClassSymbol) => - if (sym.needNew) + if (sym.isPlain) JSInstanceOf(scrut, translateVar(sym.lexicalName, false)) else JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) case S(sym: ModuleSymbol) => JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) case S(sym @ CapturedSymbol(out, cls: NewClassSymbol)) => - if (cls.needNew) + if (cls.isPlain) JSInstanceOf(scrut, translateCapture(sym)) else JSInstanceOf(scrut, translateCapture(sym).member("class")) @@ -521,7 +522,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ctorMth = localScope.declareValue("ctor", Some(false), false).runtimeName val (constructor, params) = translateNewClassParameters(nd) val initList = - if (sym.needNew) + if (sym.isPlain) Ls(JSReturnStmt(S(JSIdent(sym.lexicalName)))) else Ls( @@ -596,14 +597,14 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case Some(CapturedSymbol(out, sym: MixinSymbol)) => JSInvoke(translateCapture(CapturedSymbol(out, sym)), Ls(base)) case Some(CapturedSymbol(out, sym: NuTypeSymbol)) if !mixinOnly => - if (sym.needNew) + if (sym.isPlain) translateCapture(CapturedSymbol(out, sym)) else translateCapture(CapturedSymbol(out, sym)).member("class") case Some(sym: MixinSymbol) => JSInvoke(translateVar(name, false), Ls(base)) case Some(sym: NuTypeSymbol) if !mixinOnly => - if (sym.needNew) + if (sym.isPlain) translateVar(name, false) else translateVar(name, false).member("class") @@ -675,7 +676,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val privateIdent = JSIdent(s"this.#${classSymbol.lexicalName}") val outerStmt = JSConstDecl(outerSymbol.runtimeName, JSIdent("this")) val initList = - if (classSymbol.needNew) + if (classSymbol.isPlain) Ls(JSExprStmt(JSAssignExpr(privateIdent, JSIdent(classSymbol.lexicalName)))) else Ls( diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index d8cacf4d4c..4cff6769aa 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -33,7 +33,7 @@ sealed trait NuTypeSymbol { val ctor: Ls[Statement] // statements in the constructor val nested: Ls[NuTypeDef] // nested class/mixin/module val superParameters: Ls[Term] // parameters that need to be passed to the `super()` - val needNew: Bool + val isPlain: Bool } sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol { @@ -120,7 +120,7 @@ final case class NewClassSymbol( superParameters: Ls[Term], nested: Ls[NuTypeDef], isNested: Bool, - needNew: Bool + isPlain: Bool ) extends TypeSymbol with RuntimeSymbol with NuTypeSymbol { override def toString: Str = s"new class $lexicalName" @@ -147,7 +147,7 @@ final case class MixinSymbol( // Mixins should pass `...rest` to the `super()` // But the variable name is not sure when we create the symbol object override val superParameters: Ls[Term] = Nil - val needNew: Bool = false + val isPlain: Bool = false } final case class ModuleSymbol( @@ -165,7 +165,7 @@ final case class ModuleSymbol( // Modules should have fixed names determined by users override def runtimeName: Str = lexicalName - val needNew: Bool = false + val isPlain: Bool = false } // capture runtime symbols in the outside module/class/mixin diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index cf71149da8..4b2ed7b757 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -365,13 +365,17 @@ n.ll //│ res //│ = 3 -// TODO reject -// :e -:re class M() -let mm = new M() //│ class M() + +:js +let mm = new M() //│ let mm: M +//│ // Prelude +//│ class TypingUnit13 {} +//│ const typing_unit13 = new TypingUnit13; +//│ // Query 1 +//│ globalThis.mm = new M.class(); +//│ // End of generated code //│ mm -//│ Runtime error: -//│ TypeError: M is not a constructor +//│ = M {} From f8c603aac20d1ac292a28fb02c0340ace63ed370 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Tue, 16 May 2023 16:30:24 +0800 Subject: [PATCH 287/498] WIP: Change NuTypeDef --- .../src/main/scala/mlscript/JSBackend.scala | 12 +- .../src/main/scala/mlscript/NewParser.scala | 21 ++-- shared/src/main/scala/mlscript/Typer.scala | 16 ++- .../main/scala/mlscript/codegen/Helpers.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 18 ++- shared/src/main/scala/mlscript/syntax.scala | 5 +- .../src/test/diff/codegen/OptionalParam.mls | 103 ++++++------------ shared/src/test/diff/nu/Dates.mls | 14 ++- 8 files changed, 79 insertions(+), 112 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 110018c40b..60bc3bd17c 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -942,26 +942,26 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } typeDefs.foreach { - case td @ NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { val (body, members, stmts, nested) = prepare(mxName, fs, pars, unit) val sym = MixinSymbol(mxName, tps map { _._2.name }, body, members, stmts, nested, isNested).tap(scope.register) if (!td.isDecl) mixins += sym } - case td @ NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) val sym = ModuleSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) if (!td.isDecl) modules += sym } - case td @ NuTypeDef(Als, TypeName(nme), tps, _, sig, pars, _, _, _) => { + case td @ NuTypeDef(Als, TypeName(nme), tps, _, ctor, plain, sig, pars, _, _, _) => { scope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) } - case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) val sym = - NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested, td.hasExtraCtor).tap(scope.register) + NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested, plain).tap(scope.register) if (!td.isDecl) classes += sym } - case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { val (body, members, _, _) = prepare(nme, fs, pars, unit) val sym = scope.declareTrait(nme, tps map { _._2.name }, body, members) if (!td.isDecl) traits += sym diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 788f9dc39b..b46da931a1 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -390,25 +390,20 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => Nil } val tu = curlyTypingUnit - val (ctor, body) = tu.entities.partition { + val (ctors: Ls[Constructor], body) = tu.entities.partition { case _: Constructor => true case _ => false } - val (real_params, ctorLoc) = - if (ctor.length > 1) { - err(msg"more than one constructor" -> S(l0) :: Nil) - (Tup(Nil), N) - } - else ctor.headOption match { - case Some(ctor @ Constructor(tup)) => - if (params.isDefined) err(msg"more than one constructor" -> S(l0) :: Nil) - (tup, ctor.toLoc) - case _ => - (params.getOrElse(Tup(Nil)), if (params.isDefined) N else tn.toLoc) + val ctor = + if (ctors.length > 1) { + err(msg"A class may only have one constructor" -> S(l0) :: Nil) + N } + else ctors.headOption - val res = NuTypeDef(kind, tn, tparams, real_params, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs, ctorLoc) + val res = + NuTypeDef(kind, tn, tparams, params.getOrElse(Tup(Nil)), ctor, params.isEmpty, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs) R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "val" | "let")), l0) :: c) => // TODO support rec? diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 988788e148..7717c9faf9 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -357,9 +357,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case CompletedTypeInfo(mem: TypedNuTypeDef) => S(mem.td.kind, mem.tparams.size) case ti: DelayedTypeInfo => ti.decl match { - case NuTypeDef(k @ (Cls | Nms | Als), _, tps, _, _, _, _, _, _) => + case NuTypeDef(k @ (Cls | Nms | Als), _, tps, _, _, _, _, _, _, _, _) => S(k, tps.size) - case NuTypeDef(k @ (Mxn | Trt), nme, tps, _, _, _, _, _, _) => + case NuTypeDef(k @ (Mxn | Trt), nme, tps, _, _, _, _, _, _, _, _) => err(msg"${k.str} ${nme.name} cannot be used as a type", loc) S(k, tps.size) case fd: NuFunDef => @@ -1311,28 +1311,32 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => - NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))( - td.declareLoc, td.abstractLoc, td.ctorLoc) + NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), N, td.isPlain, S(go(body)), Nil, N, N, TypingUnit(Nil))( + td.declareLoc, td.abstractLoc) } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + N,//TODO + td.isPlain, N, Nil,//TODO Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc, td.ctorLoc) + mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) } case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + td.ctor, + td.isPlain, N,//TODO Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc, td.ctorLoc) + mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) } case tf @ TypedNuFun(level, fd, bodyTy) => NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc) diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index a8634332d3..848d74d69d 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -85,7 +85,7 @@ object Helpers { s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, ${inspect(term)})" case NuFunDef(lt, nme, targs, R(ty)) => s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, $ty)" - case NuTypeDef(kind, nme, tparams, params, sig, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => s"NuTypeDef(${kind.str}, ${nme.name}, ${tparams.mkString("(", ", ", ")")}, ${ inspect(params)}, ${parents.map(inspect).mkString("(", ", ", ")")}, $sup, $ths, ${inspect(body)})" case others => others.toString() diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 46a9727715..a468d2f3ff 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -136,10 +136,10 @@ trait TypeLikeImpl extends Located { self: TypeLike => // })).mkString("\n") // })).mkString("", "\n", "\n") })).mkString - case NuTypeDef(kind @ Als, nme, tparams, params, sig, parents, sup, ths, body) => + case NuTypeDef(kind @ Als, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => s"type ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")} = ${ sig.getOrElse(die).showIn(ctx, 0)}" - case NuTypeDef(kind, nme, tparams, params, sig, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => val bodyCtx = ctx.indent s"${kind.str} ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}(${ params.fields.map { @@ -177,7 +177,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList - case NuTypeDef(kind, nme, tparams, params, sig, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => // TODO improve this mess tparams.map(_._2) ::: params.fields.collect { case (_, Fld(_, _, Asc(_, ty))) => ty @@ -389,10 +389,8 @@ trait NuDeclImpl extends Located { self: NuDecl => def kind: DeclKind val declareLoc: Opt[Loc] val abstractLoc: Opt[Loc] - val ctorLoc: Opt[Loc] def isDecl: Bool = declareLoc.nonEmpty def isAbstract: Bool = abstractLoc.nonEmpty - def hasExtraCtor: Bool = ctorLoc.nonEmpty def declStr: Str = if (isDecl) "declare " else "" val nameVar: Var = self match { case td: NuTypeDef => td.nme.toVar @@ -416,7 +414,7 @@ trait NuDeclImpl extends Located { self: NuDecl => case NuFunDef(N, n, _, b) => s"fun $n" case NuFunDef(S(false), n, _, b) => s"let $n" case NuFunDef(S(true), n, _, b) => s"let rec $n" - case NuTypeDef(k, n, tps, sps, sig, parents, sup, ths, bod) => + case NuTypeDef(k, n, tps, sps, ctor, plain, sig, parents, sup, ths, bod) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}(${ // sps.mkString("(",",",")") sps})${sig.fold("")(": " + _.showDbg2)}${ @@ -734,9 +732,9 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => + case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => ??? // TODO - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => + case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) require(pars.size === 0, pars) @@ -744,7 +742,7 @@ trait StatementImpl extends Located { self: Statement => require(ths.isEmpty, ths) require(unit.entities.isEmpty, unit) Nil -> (TypeDef(k, nme, tps.map(_._2), sig.get, Nil, Nil, Nil) :: Nil) - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => + case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { case L(ds) => diags += ds; Top @@ -879,7 +877,7 @@ trait StatementImpl extends Located { self: Statement => case Inst(bod) => bod :: Nil case Super() => Nil case Constructor(lst) => lst :: Nil - case NuTypeDef(k, nme, tps, ps, sig, pars, sup, ths, bod) => + case NuTypeDef(k, nme, tps, ps, ctor, plain, sig, pars, sup, ths, bod) => nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 949ecf6e18..0750cfbb38 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -182,12 +182,14 @@ final case class NuTypeDef( nme: TypeName, tparams: Ls[(Opt[VarianceInfo], TypeName)], params: Tup, // the specialized parameters for that type + ctor: Opt[Constructor], + isPlain: Bool, sig: Opt[Type], parents: Ls[Term], superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit -)(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc], val ctorLoc: Opt[Loc]) +)(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc]) extends NuDecl with Statement final case class NuFunDef( @@ -199,7 +201,6 @@ final case class NuFunDef( val body: Located = rhs.fold(identity, identity) def kind: DeclKind = Val val abstractLoc: Opt[Loc] = None - val ctorLoc: Opt[Loc] = None } diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 4b2ed7b757..38f57a1ea6 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -54,11 +54,9 @@ class B {} :js class C { constructor(x: int) - fun f = x + 1 + // TODO: fun f = x + 1 } -//│ class C(x: int) { -//│ fun f: int -//│ } +//│ class C() //│ // Prelude //│ class TypingUnit2 { //│ #C; @@ -67,17 +65,7 @@ class C { //│ get C() { //│ const outer = this; //│ if (this.#C === undefined) { -//│ class C { -//│ #x; -//│ get x() { return this.#x; } -//│ constructor(x) { -//│ this.#x = x; -//│ } -//│ get f() { -//│ const x = this.#x; -//│ return x + 1; -//│ } -//│ }; +//│ class C {}; //│ this.#C = C; //│ } //│ return this.#C; @@ -87,42 +75,41 @@ class C { //│ globalThis.C = typing_unit2.C; //│ // End of generated code +// TODO +:e let c = new C(1) -c.x -c.f -//│ let c: C -//│ int +// c.x +// c.f +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.80: let c = new C(1) +//│ ║ ^^^^ +//│ ╟── argument of type `(1,)` does not match type `()` +//│ ║ l.80: let c = new C(1) +//│ ╙── ^^^ +//│ let c: C | error //│ c //│ = C {} -//│ res -//│ = 1 -//│ res -//│ = 2 - -:pe +// TODO: make ctor function. class D(x: int) { constructor(y: int) } -//│ ╔══[PARSE ERROR] more than one constructor -//│ ║ l.103: class D(x: int) { -//│ ╙── ^^^^^ -//│ class D(y: int) +//│ class D(x: int) :pe class E { constructor(x: int) constructor(y: int) } -//│ ╔══[PARSE ERROR] more than one constructor -//│ ║ l.112: class E { -//│ ╙── ^^^^^ +//│ ╔══[PARSE ERROR] A class may only have one constructor +//│ ║ l.99: class E { +//│ ╙── ^^^^^ //│ class E() // TODO: better check? :e constructor(x: int) //│ ╔══[ERROR] constructor must be in a class. -//│ ║ l.123: constructor(x: int) +//│ ║ l.110: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ () //│ Code generation encountered an error: @@ -134,13 +121,13 @@ class F(x: int) extends C(x + 1) {} class G extends C(2) {} class H extends B {} //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.133: class F(x: int) extends C(x + 1) {} +//│ ║ l.120: class F(x: int) extends C(x + 1) {} //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.134: class G extends C(2) {} +//│ ║ l.121: class G extends C(2) {} //│ ╙── ^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.135: class H extends B {} +//│ ║ l.122: class H extends B {} //│ ╙── ^ //│ class F(x: int) //│ class G() @@ -237,10 +224,10 @@ module I { } } //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.236: class L extends J(0) +//│ ║ l.223: class L extends J(0) //│ ╙── ^^^^ //│ module I() { -//│ class J(x: int) +//│ class J() //│ module K() { //│ class L() //│ } @@ -286,13 +273,7 @@ module I { //│ get J() { //│ const outer1 = this; //│ if (this.#J === undefined) { -//│ class J { -//│ #x; -//│ get x() { return this.#x; } -//│ constructor(x) { -//│ this.#x = x; -//│ } -//│ }; +//│ class J {}; //│ this.#J = J; //│ } //│ return this.#J; @@ -312,10 +293,10 @@ module I { fun g(x: int) = class L { constructor(y: int) - fun ll = x + y + // TODO: fun ll = x + y } L -//│ fun g: (x: int,) -> (y: int,) -> L +//│ fun g: (x: int,) -> () -> L //│ // Prelude //│ class TypingUnit10 {} //│ const typing_unit10 = new TypingUnit10; @@ -323,17 +304,7 @@ fun g(x: int) = //│ globalThis.g = function g(x) { //│ return ((() => { //│ const L = (() => { -//│ class L { -//│ #y; -//│ get y() { return this.#y; } -//│ constructor(y) { -//│ this.#y = y; -//│ } -//│ get ll() { -//│ const y = this.#y; -//│ return x + y; -//│ } -//│ } +//│ class L {} //│ return L; //│ })(); //│ return L; @@ -343,27 +314,17 @@ fun g(x: int) = :js let m = g(1) -let n = new m(2) -n.ll -//│ let m: (y: int,) -> L -//│ let n: L -//│ int +// TODO: let n = new m(2) +// TODO: n.ll +//│ let m: () -> L //│ // Prelude //│ class TypingUnit11 {} //│ const typing_unit11 = new TypingUnit11; //│ // Query 1 //│ globalThis.m = g(1); -//│ // Query 2 -//│ globalThis.n = new m(2); -//│ // Query 3 -//│ res = n.ll; //│ // End of generated code //│ m //│ = [class L] -//│ n -//│ = L {} -//│ res -//│ = 3 class M() //│ class M() diff --git a/shared/src/test/diff/nu/Dates.mls b/shared/src/test/diff/nu/Dates.mls index e4b1b00085..08cdba1c5a 100644 --- a/shared/src/test/diff/nu/Dates.mls +++ b/shared/src/test/diff/nu/Dates.mls @@ -4,14 +4,22 @@ declare class Date { constructor(date: number) fun toString(): string } -//│ class Date(date: number) { +//│ class Date() { //│ fun toString: () -> string //│ } +// TODO: +:e let date1 = new Date(12345678) date1.toString() -//│ let date1: Date -//│ string +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.13: let date1 = new Date(12345678) +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── argument of type `(12345678,)` does not match type `()` +//│ ║ l.13: let date1 = new Date(12345678) +//│ ╙── ^^^^^^^^^^ +//│ let date1: Date | error +//│ error | string //│ date1 //│ = 1970-01-01T03:25:45.678Z //│ res From 37481e742677cb7c8309f95d1f6629a52a8e2bd2 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 17 May 2023 16:01:05 +0800 Subject: [PATCH 288/498] WIP: Add assignment for constructor and move constructor outside the modifier --- .../src/main/scala/mlscript/NewParser.scala | 37 +++-- shared/src/main/scala/mlscript/helpers.scala | 6 +- shared/src/main/scala/mlscript/syntax.scala | 3 +- .../src/test/diff/codegen/OptionalParam.mls | 137 +++++++++++++----- shared/src/test/diff/nu/Declarations.mls | 3 - shared/src/test/diff/parser/IfThenElse.mls | 60 ++++---- 6 files changed, 159 insertions(+), 87 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index b46da931a1..6b11310188 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -282,8 +282,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D yeetSpaces go(acc.copy(acc.mods + ("abstract" -> l0))) case _ if acc.mods.isEmpty => acc - case (KEYWORD("constructor"), l0) :: _ => - acc case (KEYWORD("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module" | "fun" | "val"), l0) :: _ => acc case (tok, loc) :: _ => @@ -302,20 +300,25 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case Nil => Nil case (NEWLINE, _) :: _ => consume; block case (SPACE, _) :: _ => consume; block + case (KEYWORD("constructor"), l0) :: _ => + consume + val res = yeetSpaces match { + case (br @ BRACKETS(Round, toks), loc) :: _ => + consume + val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO + val body = curlyTypingUnit.entities + Constructor(Tup(as).withLoc(S(loc)), body) + case _ => + err(msg"Expect parameter list for the constructor" -> S(l0) :: Nil) + Constructor(Tup(Nil), Nil) + } + val t = R(res.withLoc(S(l0 ++ res.getLoc))) + yeetSpaces match { + case (NEWLINE, _) :: _ => consume; t :: block + case _ => t :: Nil + } case c => val t = c match { - case ModifierSet(mods, (KEYWORD("constructor"), l0) :: c) => - consume - val res = yeetSpaces match { - case (br @ BRACKETS(Round, toks), loc) :: _ => - consume - val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO - Constructor(Tup(as).withLoc(S(loc))) - case _ => - err(msg"Expect parameter list for the constructor" -> S(l0) :: Nil) - Constructor(Tup(Nil)) - } - R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c) => consume val (isDecl, mods2) = mods.handle("declare") @@ -495,6 +498,12 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D exprOrIf(0, allowSpace = false) } yeetSpaces match { + case (KEYWORD("="), l0) :: _ => t match { + case R(v: Var) => + consume + R(Ass(v, expr(0))) :: block + case _ => t :: Nil + } case (KEYWORD(";"), _) :: _ => consume; t :: block case (NEWLINE, _) :: _ => consume; t :: block case _ => t :: Nil diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index a468d2f3ff..0f830a29cd 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -545,6 +545,7 @@ trait TermImpl extends StatementImpl { self: Term => case Forall(ps, bod) => s"forall ${ps.mkString(", ")}. ${bod}" case Inst(bod) => s"${bod.print(true)}!" case Super() => "super" + case Ass(lhs, rhs) => s"${lhs} = ${rhs}" }} def toTypeRaise(implicit raise: Raise): Type = toType match { @@ -876,7 +877,8 @@ trait StatementImpl extends Located { self: Statement => case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil case Super() => Nil - case Constructor(lst) => lst :: Nil + case Constructor(params, body) => params :: body + case Ass(lhs, rhs) => lhs :: rhs :: Nil case NuTypeDef(k, nme, tps, ps, ctor, plain, sig, pars, sup, ths, bod) => nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil } @@ -886,7 +888,7 @@ trait StatementImpl extends Located { self: Statement => case LetS(isRec, name, rhs) => s"let${if (isRec) " rec" else ""} $name = $rhs" case DatatypeDefn(head, body) => s"data type $head of $body" case DataDefn(head) => s"data $head" - case Constructor(lst) => s"constructor($lst)" + case Constructor(params, _) => s"constructor($params)" case _: Term => super.toString case d: Decl => d.showDbg case d: NuDecl => d.showDbg diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 0750cfbb38..91b7071f2e 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -81,6 +81,7 @@ final case class Where(body: Term, where: Ls[Statement]) extends Ter final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term final case class Super() extends Term +final case class Ass(lhs: Var, rhs: Term) extends Term // x = y in constructors. TODO: make lhs term sealed abstract class IfBody extends IfBodyImpl // final case class IfTerm(expr: Term) extends IfBody // rm? @@ -112,7 +113,7 @@ sealed trait Statement extends StatementImpl final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement final case class DataDefn(body: Term) extends Statement final case class DatatypeDefn(head: Term, body: Term) extends Statement -final case class Constructor(lst: Tup) extends Statement +final case class Constructor(params: Tup, body: Ls[Statement]) extends Statement sealed trait DesugaredStatement extends Statement with DesugaredStatementImpl diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 38f57a1ea6..cf52eab1ab 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -54,7 +54,6 @@ class B {} :js class C { constructor(x: int) - // TODO: fun f = x + 1 } //│ class C() //│ // Prelude @@ -78,22 +77,64 @@ class C { // TODO :e let c = new C(1) -// c.x -// c.f //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.80: let c = new C(1) +//│ ║ l.79: let c = new C(1) //│ ║ ^^^^ //│ ╟── argument of type `(1,)` does not match type `()` -//│ ║ l.80: let c = new C(1) +//│ ║ l.79: let c = new C(1) //│ ╙── ^^^ //│ let c: C | error //│ c //│ = C {} -// TODO: make ctor function. + + +:js class D(x: int) { - constructor(y: int) + constructor(y: int) { + x = y + 1 + } + log(x) } //│ class D(x: int) +//│ // Prelude +//│ function log(x) { +//│ return console.info(x); +//│ } +//│ class TypingUnit4 { +//│ #D; +//│ constructor() { +//│ } +//│ get D() { +//│ const outer = this; +//│ if (this.#D === undefined) { +//│ class D { +//│ #x; +//│ get x() { return this.#x; } +//│ constructor(x) { +//│ this.#x = x; +//│ log(x); +//│ } +//│ }; +//│ this.#D = ((x) => Object.freeze(new D(x))); +//│ this.#D.class = D; +//│ } +//│ return this.#D; +//│ } +//│ } +//│ const typing_unit4 = new TypingUnit4; +//│ globalThis.D = typing_unit4.D; +//│ // End of generated code + +let dd = new D(41) +dd.x +//│ let dd: D +//│ int +//│ dd +//│ = D {} +//│ // Output +//│ 41 +//│ res +//│ = 41 :pe class E { @@ -101,15 +142,15 @@ class E { constructor(y: int) } //│ ╔══[PARSE ERROR] A class may only have one constructor -//│ ║ l.99: class E { -//│ ╙── ^^^^^ +//│ ║ l.140: class E { +//│ ╙── ^^^^^ //│ class E() // TODO: better check? :e constructor(x: int) //│ ╔══[ERROR] constructor must be in a class. -//│ ║ l.110: constructor(x: int) +//│ ║ l.151: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ () //│ Code generation encountered an error: @@ -121,19 +162,19 @@ class F(x: int) extends C(x + 1) {} class G extends C(2) {} class H extends B {} //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.120: class F(x: int) extends C(x + 1) {} +//│ ║ l.161: class F(x: int) extends C(x + 1) {} //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.121: class G extends C(2) {} +//│ ║ l.162: class G extends C(2) {} //│ ╙── ^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.122: class H extends B {} +//│ ║ l.163: class H extends B {} //│ ╙── ^ //│ class F(x: int) //│ class G() //│ class H() //│ // Prelude -//│ class TypingUnit6 { +//│ class TypingUnit7 { //│ #F; //│ #G; //│ #H; @@ -180,10 +221,10 @@ class H extends B {} //│ return this.#H; //│ } //│ } -//│ const typing_unit6 = new TypingUnit6; -//│ globalThis.F = typing_unit6.F; -//│ globalThis.G = typing_unit6.G; -//│ globalThis.H = typing_unit6.H; +//│ const typing_unit7 = new TypingUnit7; +//│ globalThis.F = typing_unit7.F; +//│ globalThis.G = typing_unit7.G; +//│ globalThis.H = typing_unit7.H; //│ // End of generated code :js @@ -194,8 +235,8 @@ fun f(c) = _ then 0 //│ fun f: anything -> int //│ // Prelude -//│ class TypingUnit7 {} -//│ const typing_unit7 = new TypingUnit7; +//│ class TypingUnit8 {} +//│ const typing_unit8 = new TypingUnit8; //│ // Query 1 //│ globalThis.f = function f(c) { //│ return ((() => { @@ -224,7 +265,7 @@ module I { } } //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.223: class L extends J(0) +//│ ║ l.264: class L extends J(0) //│ ╙── ^^^^ //│ module I() { //│ class J() @@ -233,7 +274,7 @@ module I { //│ } //│ } //│ // Prelude -//│ class TypingUnit9 { +//│ class TypingUnit10 { //│ #I; //│ constructor() { //│ } @@ -285,26 +326,34 @@ module I { //│ return this.#I; //│ } //│ } -//│ const typing_unit9 = new TypingUnit9; -//│ globalThis.I = typing_unit9.I; +//│ const typing_unit10 = new TypingUnit10; +//│ globalThis.I = typing_unit10.I; //│ // End of generated code :js fun g(x: int) = class L { - constructor(y: int) - // TODO: fun ll = x + y + constructor(y: int) { + x = y + 1 + } + fun ll = x + 1 } L //│ fun g: (x: int,) -> () -> L //│ // Prelude -//│ class TypingUnit10 {} -//│ const typing_unit10 = new TypingUnit10; +//│ class TypingUnit11 {} +//│ const typing_unit11 = new TypingUnit11; //│ // Query 1 //│ globalThis.g = function g(x) { //│ return ((() => { //│ const L = (() => { -//│ class L {} +//│ class L { +//│ constructor() { +//│ } +//│ get ll() { +//│ return x + 1; +//│ } +//│ } //│ return L; //│ })(); //│ return L; @@ -312,19 +361,37 @@ fun g(x: int) = //│ }; //│ // End of generated code +// TODO: :js +:e let m = g(1) -// TODO: let n = new m(2) -// TODO: n.ll +let n = new m(2) +n.ll +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.368: let n = new m(2) +//│ ║ ^^^^ +//│ ╟── argument of type `(2,)` does not match type `()` +//│ ║ l.368: let n = new m(2) +//│ ╙── ^^^ //│ let m: () -> L +//│ let n: L | error +//│ error | int //│ // Prelude -//│ class TypingUnit11 {} -//│ const typing_unit11 = new TypingUnit11; +//│ class TypingUnit12 {} +//│ const typing_unit12 = new TypingUnit12; //│ // Query 1 //│ globalThis.m = g(1); +//│ // Query 2 +//│ globalThis.n = new m(2); +//│ // Query 3 +//│ res = n.ll; //│ // End of generated code //│ m //│ = [class L] +//│ n +//│ = L {} +//│ res +//│ = 2 class M() //│ class M() @@ -333,8 +400,8 @@ class M() let mm = new M() //│ let mm: M //│ // Prelude -//│ class TypingUnit13 {} -//│ const typing_unit13 = new TypingUnit13; +//│ class TypingUnit14 {} +//│ const typing_unit14 = new TypingUnit14; //│ // Query 1 //│ globalThis.mm = new M.class(); //│ // End of generated code diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index 4ef374b00e..a1d2d0b249 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -123,9 +123,6 @@ declare 42 //│ ╔══[PARSE ERROR] Unexpected literal token after modifier //│ ║ l.119: declare 42 //│ ╙── ^^ -//│ ╔══[PARSE ERROR] Unexpected literal token after modifier -//│ ║ l.119: declare 42 -//│ ╙── ^^ //│ 42 //│ res //│ = 42 diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 7a1bcf0077..152a9895ee 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -260,23 +260,19 @@ if lol else 2 //│ Parsed: {if (lol) then undefined} -:pe x = if true then false else maybe //│ |x| |#=| |#if| |true| |#then| |false| |#else| |maybe| -//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.264: x = if true then false else maybe -//│ ╙── ^ -//│ Parsed: {x} +//│ Parsed: {x = if (true) then false else maybe} :pe x = if true then y = 1 //│ |x| |#=|→|#if| |true| |#then|←|↵|y| |#=| |1| -//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.272: x = -//│ ╙── ^ -//│ Parsed: {x} +//│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here +//│ ║ l.269: if true then +//│ ╙── ^ +//│ Parsed: {x = {if (true) then undefined}; y = 1} if a == 0 and b == @@ -291,7 +287,7 @@ if a == 2 and b then "" //│ |2| |and| |b| |#then| |""| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.291: 2 and b then "" +//│ ║ l.287: 2 and b then "" //│ ╙── ^^^^^^^^^^^^^^^ //│ Parsed: {undefined} @@ -322,7 +318,7 @@ if else 1 //│ |#else| |1| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.322: else 1 +//│ ║ l.318: else 1 //│ ╙── ^^^^^^ //│ Parsed: {undefined} @@ -330,7 +326,7 @@ else 1 1 else 2 //│ |1| |#else| |2| //│ ╔══[PARSE ERROR] Expected end of input; found 'else' keyword instead -//│ ║ l.330: 1 else 2 +//│ ║ l.326: 1 else 2 //│ ╙── ^^^^ //│ Parsed: {1} @@ -375,7 +371,7 @@ if a is Left x then x //│ |#if| |a| |is|→|Left| |x| |#then| |x|←| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.375: Left x then x +//│ ║ l.371: Left x then x //│ ╙── ^^^^^^ //│ Parsed: {if a is ‹(Left (x,)) then x›} @@ -386,9 +382,9 @@ if a is then y //│ |#if| |a| |is|→|Left|(|x|)| |#then| |x|↵|#let| |y| |#=| |a| |+| |1|↵|#then| |y|←| //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.385: let y = a + 1 +//│ ║ l.381: let y = a + 1 //│ ║ ^^^^^ -//│ ║ l.386: then y +//│ ║ l.382: then y //│ ╙── ^^^^^^^^ //│ Parsed: {if a is ‹(Left (x,)) then x; let y = undefined›} @@ -401,19 +397,19 @@ if a is if let Some(x) = v then 123 //│ |#if| |#let| |Some|(|x|)| |#=| |v| |#then| |123| //│ ╔══[PARSE ERROR] Expected '='; found parenthesis section instead -//│ ║ l.401: if let Some(x) = v then 123 +//│ ║ l.397: if let Some(x) = v then 123 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' in expression position -//│ ║ l.401: if let Some(x) = v then 123 +//│ ║ l.397: if let Some(x) = v then 123 //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.401: if let Some(x) = v then 123 +//│ ║ l.397: if let Some(x) = v then 123 //│ ╙── ^^^^^^^^^^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found let binding instead -//│ ║ l.401: if let Some(x) = v then 123 +//│ ║ l.397: if let Some(x) = v then 123 //│ ║ ^ //│ ╟── Note: 'if' expression started here: -//│ ║ l.401: if let Some(x) = v then 123 +//│ ║ l.397: if let Some(x) = v then 123 //│ ╙── ^^ //│ Parsed: {if (let Some = undefined in undefined) then undefined} @@ -422,19 +418,19 @@ if let Some(x) = v then 123 if let Some(x) = v and cond then 123 //│ |#if| |#let| |Some|(|x|)| |#=| |v| |and| |cond| |#then| |123| //│ ╔══[PARSE ERROR] Expected '='; found parenthesis section instead -//│ ║ l.422: if let Some(x) = v and cond then 123 +//│ ║ l.418: if let Some(x) = v and cond then 123 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' in expression position -//│ ║ l.422: if let Some(x) = v and cond then 123 +//│ ║ l.418: if let Some(x) = v and cond then 123 //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.422: if let Some(x) = v and cond then 123 +//│ ║ l.418: if let Some(x) = v and cond then 123 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found let binding instead -//│ ║ l.422: if let Some(x) = v and cond then 123 +//│ ║ l.418: if let Some(x) = v and cond then 123 //│ ║ ^ //│ ╟── Note: 'if' expression started here: -//│ ║ l.422: if let Some(x) = v and cond then 123 +//│ ║ l.418: if let Some(x) = v and cond then 123 //│ ╙── ^^ //│ Parsed: {if (let Some = undefined in undefined) then undefined} @@ -461,7 +457,7 @@ if true + 1 //│ |#if| |true|→|#then| |0|↵|+| |1|←| //│ ╔══[PARSE ERROR] Unexpected operator here -//│ ║ l.461: + 1 +//│ ║ l.457: + 1 //│ ╙── ^ //│ Parsed: {if (true) then 0} @@ -490,7 +486,7 @@ if true + 1 //│ |#if| |true|→|#then| |0|←|→|+| |1|←| //│ ╔══[PARSE ERROR] Expected end of input; found indented block instead -//│ ║ l.490: + 1 +//│ ║ l.486: + 1 //│ ╙── ^^ //│ Parsed: {if (true) then 0} @@ -501,7 +497,7 @@ if true + 1 //│ |#if| |true|→|#then| |0|↵|#else| |0|←|→|+| |1|←| //│ ╔══[PARSE ERROR] Expected end of input; found indented block instead -//│ ║ l.501: + 1 +//│ ║ l.497: + 1 //│ ╙── ^^ //│ Parsed: {if (true) then 0 else 0} @@ -536,10 +532,10 @@ if true (if true) //│ |(|#if| |true|)| //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found reference instead -//│ ║ l.536: (if true) +//│ ║ l.532: (if true) //│ ║ ^^^^ //│ ╟── Note: 'if' expression started here: -//│ ║ l.536: (if true) +//│ ║ l.532: (if true) //│ ╙── ^^ //│ Parsed: {'(' if (true) then undefined ')'} @@ -547,7 +543,7 @@ if true (if true then) //│ |(|#if| |true| |#then|)| //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.547: (if true then) +//│ ║ l.543: (if true then) //│ ╙── ^ //│ Parsed: {'(' if (true) then undefined ')'} @@ -559,7 +555,7 @@ if true then; if true then; else; //│ |#if| |true| |#then|#;| |#else|#;| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.559: if true then; else; +//│ ║ l.555: if true then; else; //│ ╙── ^^^^ //│ Parsed: {if (true) then undefined; undefined} From 34b18645988150e4618402d3c29210b3754c0376 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 17 May 2023 17:01:56 +0800 Subject: [PATCH 289/498] Update CI: run on all PRs --- .github/workflows/scala.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index ffbc8ccbaf..374e4e0017 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -4,7 +4,6 @@ on: push: branches: [ mlscript ] pull_request: - branches: [ mlscript ] jobs: build: From a098242f6fc2e007d0ff670eb4e1e114c38cdf73 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 17 May 2023 17:03:52 +0800 Subject: [PATCH 290/498] clean up --- .../src/main/scala/mlscript/NuTypeDefs.scala | 74 +++++++------------ .../main/scala/mlscript/TyperHelpers.scala | 10 +-- 2 files changed, 32 insertions(+), 52 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 18144b6017..f21c88578e 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -244,7 +244,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => level: Level, td: NuTypeDef, ttu: TypedTypingUnit, tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, - tags: ST, + selfTy: ST, inheritedTags: Set[TypeName], parentTP: Map[Str, NuMember] )(val instanceType: ST, // * only meant to be used in `force` and `variances` @@ -255,7 +255,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, params, tags, inheritedTags) + def typeSignature: ST = typeSignatureOf(td, level, tparams, params, selfTy, inheritedTags) /** Includes class-name-coded type parameter fields. */ lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { @@ -316,7 +316,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), - f(pol, tags), + f(pol, selfTy), inheritedTags, parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, )(f(pol, instanceType)) @@ -327,7 +327,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), - f(pol, tags), + f(pol, selfTy), inheritedTags, parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap, )(f(pol, instanceType)) @@ -401,20 +401,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, tags: ST, ihtags: Set[TypeName]): ST = td.kind match { + def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, selfTy: ST, ihtags: Set[TypeName]): ST = td.kind match { case Nms => ClassTag(Var(td.nme.name), - // TODO base classes - Set.single(TN("Eql")) union ihtags + Set.single(TN("Eql")) union ihtags // Eql and ihtags (parent tags) )(provTODO) case Cls => PolymorphicType.mk(level, FunctionType( TupleType(params.mapKeys(some))(provTODO), ClassTag(Var(td.nme.name), - // TODO base classes - Set.single(TypeName("Eql")) union ihtags - )(provTODO) & tags & RecordType.mk( + Set.single(TypeName("Eql")) union ihtags // Eql and ihtags (parent tags) + )(provTODO) & selfTy & RecordType.mk( tparams.map { case (tn, tv, vi) => // TODO use vi Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } )(provTODO) @@ -539,12 +537,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypeProvenance(decl.toLoc, decl.describe) println(s"${ctx.lvl}. Created lazy type info for $decl") - - // YTODO: - // Add here thes ecomputations: - // type ParentSpec = (Term, Var, Ls[Opt[Var] -> Fld]) - // val parentSpecs: Ls[ParentSpec] = td.parents.flatMap { - // and derive from these the full set of transitively inherited tags type ParentSpec = (Term, Var, Ls[Type], Ls[Opt[Var] -> Fld]) val parentSpecs: Ls[ParentSpec] = @@ -699,6 +691,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => private lazy val thisTV: TV = freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) + // refresh trait/class def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : (T, Map[Str, NuMember]) = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty @@ -736,11 +729,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] -> parTP.map { - case (nme, tv) => rawName+"#"+nme.name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + case (nme, tv) => rawName+"#"+nme.name -> + NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) }.toMap - // } - - // raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] // FIXME } @@ -837,8 +828,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // } // inherit traits - def inherit(parents: Ls[ParentSpec], superType: ST, tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) - : (ST, ST, Ls[NuMember], Map[Str, NuMember]) = + def inherit(parents: Ls[ParentSpec], tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) + : (ST, Ls[NuMember], Map[Str, NuMember]) = parents match { case (p, v @ Var(trtName), parTargs, args) :: ps => ctx.get(trtName) match { @@ -847,27 +838,25 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => info match { case rawTrt: TypedNuTrt => if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) - val (trt, vm) = refreshGen[TypedNuTrt](info, v , parTargs)// FIXME - + val (trt, vm) = refreshGen[TypedNuTrt](info, v , parTargs) inherit(ps, - superType & trt.thisTy, - tags & trt.selfTy, + tags & trt.selfTy, memberUn(members, trt.members.values.toList), - vms ++ vm ++ trt.parentTP + vms ++ vm ++ trt.parentTP // with type members of parent class ) case _ => err(msg"trait can only inherit traits", p.toLoc) - (superType, tags, members, vms) + (tags, members, vms) } case _ => err(msg"Could not find definition `${trtName}`", p.toLoc) - (superType, tags, members, vms) + (tags, members, vms) } - case Nil => (superType, tags, members, vms) + case Nil => (tags, members, vms) } - val (thisType, tags, baseMems, vms) = - inherit(parentSpecs, TopType/*TODO*/, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) + val (tags, baseMems, vms) = + inherit(parentSpecs, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) // val selfType = tags & sig_ty val selfType = sig_ty @@ -879,7 +868,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, - thisType, + TopType, // thisType None, selfType, inheritedTags, @@ -1035,7 +1024,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val ttu = typeTypingUnit(td.body, topLevel = false) // TODO report non-unit result/statements? - // TODO check overriding case class Pack( clsMem: Ls[NuMember], @@ -1054,7 +1042,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val info = lti.complete() info match { case rawCls: TypedNuCls => - // if (parTargs.nonEmpty) err(msg"class type arguments not yet supported", p.toLoc) if (pack.bsCls.isDefined) err(msg"cannot inherit from more than one base class: ${ pack.bsCls.get} and ${parNme}", v.toLoc) @@ -1074,6 +1061,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val numem = paramMems ++ cls.members.values.toList + // parent class fields/methods val res = pack.clsMem ++ numem.flatMap { m => pack.clsMem.find(x => x.name == m.name) match { case S(mem: TypedNuTermDef) => Nil @@ -1091,7 +1079,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) // FIXME + val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) computeBaseClassTrait(ps, pack.copy( trtMem = memberUn(pack.trtMem, trt.members.values.toList), @@ -1100,8 +1088,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => computeBaseClassTrait(ps, pack) } - case _ => - computeBaseClassTrait(ps, pack) + case _ => computeBaseClassTrait(ps, pack) } case Nil => pack } @@ -1112,7 +1099,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val impltdMems = clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers - // TODO: overriding check of parent class doesn't seem working + // overriding check for class/interface inheritance (bsMembers ++ ifaceMembers).foreach { m => lazy val parSign = m match { case nt: TypedNuTermDef => nt.typeSignature @@ -1139,8 +1126,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams, typedParams, mems /* ++ ifaceMembers.map(d => d.name -> d).toMap */, // if (td.kind is Nms) TopType else thisTV TopType, - // ifaceAnnot, - TopType, // TODO use signature + TopType, // TODO selfTy: use signature inheritedTags, ptps )(thisType) -> impltdMems @@ -1227,12 +1213,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // todo: check fd.rhs => TypedNuFun(a.level, a.fd, a.bodyType & b.bodyType) - // case (S(a: NuParam), S(b: NuParam)) - // if a.level == b.level - // && a.nme.name == b.nme.name - // && a.isType == b.isType - // => - // NuParam(a.nme, a.ty && b.ty, a.isType)(a.level) case(S(a), N) => a case(N, S(b)) => b case _ => diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 0ab58931db..7367af2236 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1010,7 +1010,7 @@ abstract class TyperHelpers { Typer: Typer => case S(td: TypedNuCls) => assert(td.tparams.size === targs.size) clsNameToNomTag(td.decl)(provTODO, ctx) & - td.tags & + td.selfTy & RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.nme.name + "#" + tn.name @@ -1174,18 +1174,18 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, pvms) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, ptps) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) - pvms.valuesIterator.foreach(applyMem(pol)) + ptps.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, pvms) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, ptps) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) // thisTy.foreach(apply(pol.invar)(_)) - pvms.valuesIterator.foreach(applyMem(pol)) + ptps.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTy) case TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) From 374f7c095acd7d96eb0c775535246986c06ef3fe Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 17 May 2023 17:17:14 +0800 Subject: [PATCH 291/498] WIP: Generate overrided constructor --- .../src/main/scala/mlscript/JSBackend.scala | 31 +++++-- .../main/scala/mlscript/codegen/Codegen.scala | 14 ++- .../main/scala/mlscript/codegen/Symbol.scala | 6 +- .../src/test/diff/codegen/OptionalParam.mls | 86 ++++++++++++------- 4 files changed, 98 insertions(+), 39 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 60bc3bd17c..f7ac3d56ba 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -301,6 +301,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { throw CodeGenError("custom class body is not supported yet") case Forall(_, bod) => translateTerm(bod) case TyApp(base, _) => translateTerm(base) + case Ass(Var(name), _) => + throw CodeGenError(s"assignment of $name is not supported outside a constructor") case _: Bind | _: Test | If(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") } @@ -708,9 +710,16 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val fields = sym.body.collectFields ++ sym.body.collectTypeNames.flatMap(resolveTraitFields) - val ctorParams = fields.map { f => - memberList += NewClassMemberSymbol(f, Some(false), false).tap(nuTypeScope.register) - constructorScope.declareValue(f, Some(false), false).runtimeName + val ctorParams = sym.ctorParams match { + case Some(lst) => + lst.map { p => + constructorScope.declareValue(p, Some(false), false).runtimeName + } + case _ => + fields.map { f => + memberList += NewClassMemberSymbol(f, Some(false), false).tap(nuTypeScope.register) + constructorScope.declareValue(f, Some(false), false).runtimeName + } } sym.methods.foreach { @@ -768,6 +777,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val getters = new ListBuffer[Str]() val stmts = sym.ctor.flatMap { + case Ass(Var(name), rhs) => Ls( + JSAssignExpr(JSIdent(s"this.#$name"), translateTerm(rhs)(constructorScope)).stmt, + JSConstDecl(constructorScope.declareValue(name, S(false), false).runtimeName, JSIdent(s"this.#$name")) + ) case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil case NuFunDef(_, Var(nme), _, Left(rhs)) => getters += nme; Ls[JSStmt]( JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), @@ -792,7 +805,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { members, traits, translateSelfDeclaration(selfSymbol) ::: tempDecs ::: stmts, - typeList.toList + typeList.toList, + sym.ctorParams.isDefined ) } @@ -956,9 +970,16 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { scope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) } case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { + val (params, preStmts) = ctor match { + case S(Constructor(Tup(ls), stmts)) => (S(ls.map { + case (S(Var(nme)), _) => nme + case _ => throw CodeGenError(s"Unexpected constructor parameters in $nme.") + }), stmts) + case _ => (N, Nil) + } val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) val sym = - NewClassSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested, plain).tap(scope.register) + NewClassSymbol(nme, tps map { _._2.name }, params, body, members, preStmts ++ stmts, pars, nested, isNested, plain).tap(scope.register) if (!td.isDecl) classes += sym } case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 437187ceb3..36cf7cc1a0 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -841,7 +841,8 @@ final case class JSClassNewDecl( methods: Ls[JSClassMemberDecl], implements: Ls[Str], initStmts: Ls[JSStmt], - nestedTypes: Ls[Str] + nestedTypes: Ls[Str], + ctorOverrided: Bool ) extends JSStmt { def toSourceCode: SourceCode = { val constructor: SourceCode = { @@ -870,10 +871,15 @@ final case class JSClassNewDecl( buffer += s" $name.implement(this);" } - assert(fields.length === ctorParams.length, s"fields and ctorParams have different size in class $name.") - fields.lazyZip(ctorParams).foreach { (field, param) => - buffer += s" this.#$field = $param;" // TODO: invalid name? + // if the default constructor is overrided, we generate the overrided version + // otherwise, generate based on the class fields + if (!ctorOverrided) { + assert(fields.length === ctorParams.length, s"fields and ctorParams have different size in class $name.") + fields.lazyZip(ctorParams).foreach { (field, param) => + buffer += s" this.#$field = $param;" // TODO: invalid name? + } } + initStmts.foreach { s => s.toSourceCode.indented.indented.toString.split("\n").foreach { line => buffer += line diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index 4cff6769aa..f5646356a2 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -33,7 +33,8 @@ sealed trait NuTypeSymbol { val ctor: Ls[Statement] // statements in the constructor val nested: Ls[NuTypeDef] // nested class/mixin/module val superParameters: Ls[Term] // parameters that need to be passed to the `super()` - val isPlain: Bool + val isPlain: Bool // is this a plain class in JS + val ctorParams: Opt[Ls[Str]] // parameters in the constructor } sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol { @@ -114,6 +115,7 @@ object NewClassMemberSymbol { final case class NewClassSymbol( lexicalName: Str, params: Ls[Str], + ctorParams: Opt[Ls[Str]], body: Type, methods: Ls[MethodDef[Left[Term, Type]]], ctor: Ls[Statement], @@ -148,6 +150,7 @@ final case class MixinSymbol( // But the variable name is not sure when we create the symbol object override val superParameters: Ls[Term] = Nil val isPlain: Bool = false + val ctorParams: Opt[Ls[Str]] = N } final case class ModuleSymbol( @@ -166,6 +169,7 @@ final case class ModuleSymbol( // Modules should have fixed names determined by users override def runtimeName: Str = lexicalName val isPlain: Bool = false + val ctorParams: Opt[Ls[Str]] = N } // capture runtime symbols in the outside module/class/mixin diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index cf52eab1ab..7f1ad3a0c2 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -74,7 +74,7 @@ class C { //│ globalThis.C = typing_unit2.C; //│ // End of generated code -// TODO +// TODO: typing :e let c = new C(1) //│ ╔══[ERROR] Type mismatch in application: @@ -87,7 +87,6 @@ let c = new C(1) //│ c //│ = C {} - :js class D(x: int) { constructor(y: int) { @@ -110,8 +109,9 @@ class D(x: int) { //│ class D { //│ #x; //│ get x() { return this.#x; } -//│ constructor(x) { -//│ this.#x = x; +//│ constructor(y) { +//│ this.#x = y + 1; +//│ const x = this.#x; //│ log(x); //│ } //│ }; @@ -132,9 +132,9 @@ dd.x //│ dd //│ = D {} //│ // Output -//│ 41 +//│ 42 //│ res -//│ = 41 +//│ = 42 :pe class E { @@ -332,14 +332,14 @@ module I { :js fun g(x: int) = - class L { - constructor(y: int) { - x = y + 1 + class L(y: int) { + constructor(z: int) { + y = z + 1 } - fun ll = x + 1 + fun ll = x + y } L -//│ fun g: (x: int,) -> () -> L +//│ fun g: (x: int,) -> (y: int,) -> L //│ // Prelude //│ class TypingUnit11 {} //│ const typing_unit11 = new TypingUnit11; @@ -348,50 +348,50 @@ fun g(x: int) = //│ return ((() => { //│ const L = (() => { //│ class L { -//│ constructor() { +//│ #y; +//│ get y() { return this.#y; } +//│ constructor(z) { +//│ this.#y = z + 1; +//│ const y = this.#y; //│ } //│ get ll() { -//│ return x + 1; +//│ const y = this.#y; +//│ return x + y; //│ } //│ } -//│ return L; +//│ let ctor; +//│ ctor = ((y) => new L(y)); +//│ ctor.class = L; +//│ return ctor; //│ })(); //│ return L; //│ })()); //│ }; //│ // End of generated code -// TODO: :js -:e let m = g(1) -let n = new m(2) +let n = m(2) n.ll -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.368: let n = new m(2) -//│ ║ ^^^^ -//│ ╟── argument of type `(2,)` does not match type `()` -//│ ║ l.368: let n = new m(2) -//│ ╙── ^^^ -//│ let m: () -> L -//│ let n: L | error -//│ error | int +//│ let m: (y: int,) -> L +//│ let n: L +//│ int //│ // Prelude //│ class TypingUnit12 {} //│ const typing_unit12 = new TypingUnit12; //│ // Query 1 //│ globalThis.m = g(1); //│ // Query 2 -//│ globalThis.n = new m(2); +//│ globalThis.n = m(2); //│ // Query 3 //│ res = n.ll; //│ // End of generated code //│ m -//│ = [class L] +//│ = [Function: ctor] { class: [class L] } //│ n //│ = L {} //│ res -//│ = 2 +//│ = 4 class M() //│ class M() @@ -407,3 +407,31 @@ let mm = new M() //│ // End of generated code //│ mm //│ = M {} + +fun h(z: int) = + class N { + constructor(x: int) { + log(x + z) + } + } + N +//│ fun h: (z: int,) -> () -> N + +// TODO: typing +:e +let hh = h(1) +new hh(1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.423: new hh(1) +//│ ║ ^^^^^ +//│ ╟── argument of type `(1,)` does not match type `()` +//│ ║ l.423: new hh(1) +//│ ╙── ^^^ +//│ let hh: () -> N +//│ N | error +//│ hh +//│ = [class N] +//│ res +//│ = N {} +//│ // Output +//│ 2 From 6531044602b200e4eb9f2cf583a2be44594b2d11 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 17 May 2023 17:39:47 +0800 Subject: [PATCH 292/498] fix trait error msg --- .../src/main/scala/mlscript/NuTypeDefs.scala | 6 +- .../main/scala/mlscript/TypeSimplifier.scala | 1 - shared/src/main/scala/mlscript/Typer.scala | 6 +- .../main/scala/mlscript/ucs/Desugarer.scala | 3 + shared/src/test/diff/nu/Interfaces.mls | 122 +++++++++--------- 5 files changed, 73 insertions(+), 65 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index f21c88578e..13eb78a0a3 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -201,14 +201,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => selfTy: ST, inheritedTags: Set[TypeName], parentTP: Map[Str, NuMember] - ) extends TypedNuTypeDef(Trt) with TypedNuTermDef with PolyNuDecl + ) extends TypedNuTypeDef(Trt) with PolyNuDecl { def decl: NuTypeDef = td def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy, inheritedTags) + // def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy, inheritedTags) lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => @@ -1123,7 +1123,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } TypedNuCls(outerCtx.lvl, td, ttu, - tparams, typedParams, mems /* ++ ifaceMembers.map(d => d.name -> d).toMap */, + tparams, typedParams, mems, // if (td.kind is Nms) TopType else thisTV TopType, TopType, // TODO selfTy: use signature diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index acb8540922..7d3a31cc87 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -4,7 +4,6 @@ import scala.collection.mutable.{Map => MutMap, Set => MutSet, LinkedHashMap, Li import scala.collection.immutable.{SortedMap, SortedSet} import scala.util.chaining._ import mlscript.utils._, shorthands._ -import scala.util.Try trait TypeSimplifier { self: Typer => diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 2c676972f0..56e67da8ad 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -359,7 +359,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) ti.decl match { case NuTypeDef(k @ (Cls | Nms | Als | Trt), _, tps, _, _, _, _, _, _) => S(k, tps.size) - case NuTypeDef(k @ (Mxn /* | Trt */), nme, tps, _, _, _, _, _, _) => + case NuTypeDef(k @ Mxn, nme, tps, _, _, _, _, _, _) => err(msg"${k.str} ${nme.name} cannot be used as a type", loc) S(k, tps.size) case fd: NuFunDef => @@ -1332,7 +1332,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, vms) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, sfty, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), @@ -1342,7 +1342,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, vms) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, sfty, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index ae4a4c00ec..4fd8492c88 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -163,6 +163,9 @@ class Desugarer extends TypeDefs { self: Typer => case classNameVar @ Var(className) => ctx.tyDefs.get(className).orElse(ctx.get(className)) match { case S(ti: LazyTypeInfo) if (ti.kind is Cls) || (ti.kind is Nms) => + case S(ti: LazyTypeInfo) if (ti.kind is Trt) => throw new DesugaringException({ + msg"Cannot match on trait `$className`" + }, classNameVar.toLoc) case S(_: TypeDef) => case _ => throw new DesugaringException({ msg"Cannot find constructor `$className` in scope" diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 4038c1673f..a8bcf72a32 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -447,11 +447,17 @@ if b is //│ ╙── into type `nothing` //│ anything +:e +let tt1 = Test +//│ ╔══[ERROR] trait Test cannot be used in term position +//│ ║ l.451: let tt1 = Test +//│ ╙── ^^^^ +//│ let tt1: error -// TODO report proper error +:e fun mt(x) = if x is Test then 1 else 0 -//│ ╔══[ERROR] Cannot find constructor `Test` in scope -//│ ║ l.452: fun mt(x) = if x is Test then 1 else 0 +//│ ╔══[ERROR] Cannot match on trait `Test` +//│ ║ l.458: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -492,40 +498,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.490: fun fto(w: WP): EM = w +//│ ║ l.496: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.490: fun fto(w: WP): EM = w +//│ ║ l.496: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.490: fun fto(w: WP): EM = w +//│ ║ l.496: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.490: fun fto(w: WP): EM = w +//│ ║ l.496: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.491: z: WP +//│ ║ l.497: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.470: let z: ZL +//│ ║ l.476: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.491: z: WP +//│ ║ l.497: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.491: z: WP +//│ ║ l.497: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.492: g: ZL +//│ ║ l.498: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.469: let g: Geo +//│ ║ l.475: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.492: g: ZL +//│ ║ l.498: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.492: g: ZL +//│ ║ l.498: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -564,20 +570,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.563: fun foo(x) = x && false +//│ ║ l.569: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.563: fun foo(x) = x && false +//│ ║ l.569: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.563: fun foo(x) = x && false +//│ ║ l.569: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.563: fun foo(x) = x && false +//│ ║ l.569: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.534: fun foo(x) = x + 1 +//│ ║ l.540: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: (Test & 'a) -> (Oth | 'a) @@ -589,32 +595,32 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.588: class Eh extends Bs(1) +//│ ║ l.594: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.588: class Eh extends Bs(1) +//│ ║ l.594: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.533: class Bs(a: bool) { +//│ ║ l.539: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in integer literal: -//│ ║ l.588: class Eh extends Bs(1) +//│ ║ l.594: class Eh extends Bs(1) //│ ║ ^ //│ ╟── integer literal of type `1` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.533: class Bs(a: bool) { +//│ ║ l.539: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.589: class Eh1 extends Bs +//│ ║ l.595: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.534: fun foo(x) = x + 1 +//│ ║ l.540: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.534: fun foo(x) = x + 1 +//│ ║ l.540: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.534: fun foo(x) = x + 1 +//│ ║ l.540: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -623,7 +629,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.590: class Eh3 extends Bs(false), Test +//│ ║ l.596: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -679,7 +685,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.680: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.686: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^ //│ class Bc12() @@ -696,11 +702,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.697: class Bc31(baz: bool) extends Bc3 +//│ ║ l.703: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.671: let baz : int +//│ ║ l.677: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -709,11 +715,11 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.709: let foo = true +//│ ║ l.715: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.668: class Bc1(foo: int) +//│ ║ l.674: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -760,13 +766,13 @@ bp: Base[(int, bool)] :e bp: Base[(int, int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.761: bp: Base[(int, int)] +//│ ║ l.767: bp: Base[(int, int)] //│ ║ ^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.753: let bp: BPar[bool] +//│ ║ l.759: let bp: BPar[bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.761: bp: Base[(int, int)] +//│ ║ l.767: bp: Base[(int, int)] //│ ╙── ^^^ //│ Base[(int, int,)] @@ -798,7 +804,7 @@ fb(cp1, 2) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.799: trait BErr1 extends Base +//│ ║ l.805: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -807,38 +813,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.808: class DerBad1 extends Base[int, int] +//│ ║ l.814: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.808: class DerBad1 extends Base[int, int] +//│ ║ l.814: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.818: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -905,11 +911,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.906: class Fischl(age: bool) extends Oz +//│ ║ l.912: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.899: let age: int +//│ ║ l.905: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -928,20 +934,20 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.928: fun foo(x) = x && true +//│ ║ l.934: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.928: fun foo(x) = x && true +//│ ║ l.934: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.928: fun foo(x) = x && true +//│ ║ l.934: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.928: fun foo(x) = x && true +//│ ║ l.934: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.920: fun foo(x) = x + 1 +//│ ║ l.926: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go() { //│ fun foo: bool -> bool @@ -958,11 +964,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.959: class Ohhh(x: bool) extends Ha +//│ ║ l.965: class Ohhh(x: bool) extends Ha //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.950: class Ha { let x: int = 1 } +//│ ║ l.956: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) From bd493399c345abb88c2c53dccdab9296ddb1c11b Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 17 May 2023 19:25:57 +0800 Subject: [PATCH 293/498] small cleanup --- .../src/main/scala/mlscript/NuTypeDefs.scala | 18 +++++------------- shared/src/main/scala/mlscript/TypeDefs.scala | 1 - 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 13eb78a0a3..9929757ff2 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -149,7 +149,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), - sign.map(_.freshenAbove(lim, rigidify)), // todo + sign.map(_.freshenAbove(lim, rigidify)), tags.freshenAbove(lim, rigidify), inheritedTags, pvms.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap @@ -207,8 +207,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name - - // def typeSignature: ST = typeSignatureOf(td, level, tparams, Nil, selfTy, inheritedTags) lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => @@ -404,14 +402,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, selfTy: ST, ihtags: Set[TypeName]): ST = td.kind match { case Nms => ClassTag(Var(td.nme.name), - Set.single(TN("Eql")) union ihtags // Eql and ihtags (parent tags) + ihtags + TN("Eql") // Eql and ihtags (parent tags) )(provTODO) case Cls => PolymorphicType.mk(level, FunctionType( TupleType(params.mapKeys(some))(provTODO), ClassTag(Var(td.nme.name), - Set.single(TypeName("Eql")) union ihtags // Eql and ihtags (parent tags) + ihtags + TN("Eql") // Eql and ihtags (parent tags) )(provTODO) & selfTy & RecordType.mk( tparams.map { case (tn, tv, vi) => // TODO use vi Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } @@ -822,10 +820,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "this" -> VarSymbol(thisTV, Var("this")) val sig_ty = typeType(td.sig.getOrElse(Top)) - // td.sig match { - // case S(sig) => - // case N => () - // } // inherit traits def inherit(parents: Ls[ParentSpec], tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) @@ -868,7 +862,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuTrt(outerCtx.lvl, td, ttu, tparams, mems, - TopType, // thisType + TopType, // thisType (same as Cls) None, selfType, inheritedTags, @@ -1215,9 +1209,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuFun(a.level, a.fd, a.bodyType & b.bodyType) case(S(a), N) => a case(N, S(b)) => b - case _ => - err(msg"invalid $n", N) - ??? + case _ => lastWords("unreachable") } } } diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 1338542d89..be1d3c9d7a 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -112,7 +112,6 @@ class TypeDefs extends NuTypeDefs { self: Typer => def clsNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { require((td.kind is Cls) || (td.kind is Nms) || (td.kind is Trt), td.kind) - // YTODO: use ctx.tyDefs2 to get the lazy type info and the iags ClassTag(Var(td.nme.name), // ctx.allBaseClassesOf(td.nme.name) Set.single(TypeName("Eql")) // TODO superclasses From 002615d39eec830011b154a77657733947a0986f Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 18 May 2023 13:12:09 +0800 Subject: [PATCH 294/498] Check constructor in mixin and module, fix spelling and improve code --- shared/src/main/scala/mlscript/JSBackend.scala | 17 +++++++---------- shared/src/main/scala/mlscript/NuTypeDefs.scala | 4 ++++ .../main/scala/mlscript/codegen/Codegen.scala | 6 +++--- shared/src/test/diff/codegen/OptionalParam.mls | 16 ++++++++++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index f7ac3d56ba..e5fcc0d205 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -68,7 +68,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { translatePattern(base) case Inst(bod) => translatePattern(bod) case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf | _: Subs | _: Assign - | If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super => + | If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super | _: Ass => throw CodeGenError(s"term ${inspect(t)} is not a valid pattern") } @@ -236,7 +236,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } case (nt: NuTypeDef, _) => translateLocalNewType(nt)(blkScope) // TODO: find out if we need to support this. - case (_: Def | _: TypeDef | _: NuFunDef | _: DataDefn | _: DatatypeDefn | _: LetS, _) => + case (_: Def | _: TypeDef | _: NuFunDef | _: DataDefn | _: DatatypeDefn | _: LetS | _: Constructor, _) => throw CodeGenError("unsupported definitions in blocks") }.toList)), Nil @@ -710,17 +710,14 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val fields = sym.body.collectFields ++ sym.body.collectTypeNames.flatMap(resolveTraitFields) - val ctorParams = sym.ctorParams match { - case Some(lst) => - lst.map { p => - constructorScope.declareValue(p, Some(false), false).runtimeName - } - case _ => - fields.map { f => + val ctorParams = sym.ctorParams.fold( + fields.map { f => memberList += NewClassMemberSymbol(f, Some(false), false).tap(nuTypeScope.register) constructorScope.declareValue(f, Some(false), false).runtimeName } - } + )(lst => lst.map { p => + constructorScope.declareValue(p, Some(false), false).runtimeName + }) sym.methods.foreach { case MethodDef(_, _, Var(nme), _, _) => memberList += NewClassMemberSymbol(nme, N, true).tap(nuTypeScope.register) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 88eaf4bff1..9fd04b9274 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -603,6 +603,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val signatures = typedSignatures ctx ++= signatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) + + if (((td.kind is Nms) || (td.kind is Mxn)) && td.ctor.isDefined) + err(msg"${td.kind.str} constructor overriden is not supported", + td.ctor.fold[Opt[Loc]](N)(c => c.toLoc)) val (res, funMembers) = td.kind match { diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 36cf7cc1a0..e1b478e6d6 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -842,7 +842,7 @@ final case class JSClassNewDecl( implements: Ls[Str], initStmts: Ls[JSStmt], nestedTypes: Ls[Str], - ctorOverrided: Bool + ctorOverridden: Bool ) extends JSStmt { def toSourceCode: SourceCode = { val constructor: SourceCode = { @@ -871,9 +871,9 @@ final case class JSClassNewDecl( buffer += s" $name.implement(this);" } - // if the default constructor is overrided, we generate the overrided version + // if the default constructor is overridden, we generate the overridden version // otherwise, generate based on the class fields - if (!ctorOverrided) { + if (!ctorOverridden) { assert(fields.length === ctorParams.length, s"fields and ctorParams have different size in class $name.") fields.lazyZip(ctorParams).foreach { (field, param) => buffer += s" this.#$field = $param;" // TODO: invalid name? diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 7f1ad3a0c2..e1f104fc68 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -435,3 +435,19 @@ new hh(1) //│ = N {} //│ // Output //│ 2 + +:e +module O { + constructor(x: int) +} +mixin P { + constructor(x: int) +} +//│ ╔══[ERROR] module constructor overriden is not supported +//│ ║ l.441: constructor(x: int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] mixin constructor overriden is not supported +//│ ║ l.444: constructor(x: int) +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ module O() +//│ mixin P() From 0781e3ec2cb6ec253eeeb27f877b6c1b35e8a267 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 18 May 2023 13:25:23 +0800 Subject: [PATCH 295/498] Remove comment --- .../src/test/diff/codegen/OptionalParam.mls | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index e1f104fc68..569baa8a2f 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -146,11 +146,10 @@ class E { //│ ╙── ^^^^^ //│ class E() -// TODO: better check? :e constructor(x: int) //│ ╔══[ERROR] constructor must be in a class. -//│ ║ l.151: constructor(x: int) +//│ ║ l.150: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ () //│ Code generation encountered an error: @@ -162,13 +161,13 @@ class F(x: int) extends C(x + 1) {} class G extends C(2) {} class H extends B {} //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.161: class F(x: int) extends C(x + 1) {} +//│ ║ l.160: class F(x: int) extends C(x + 1) {} //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.162: class G extends C(2) {} +//│ ║ l.161: class G extends C(2) {} //│ ╙── ^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.163: class H extends B {} +//│ ║ l.162: class H extends B {} //│ ╙── ^ //│ class F(x: int) //│ class G() @@ -265,7 +264,7 @@ module I { } } //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.264: class L extends J(0) +//│ ║ l.263: class L extends J(0) //│ ╙── ^^^^ //│ module I() { //│ class J() @@ -422,10 +421,10 @@ fun h(z: int) = let hh = h(1) new hh(1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.423: new hh(1) +//│ ║ l.422: new hh(1) //│ ║ ^^^^^ //│ ╟── argument of type `(1,)` does not match type `()` -//│ ║ l.423: new hh(1) +//│ ║ l.422: new hh(1) //│ ╙── ^^^ //│ let hh: () -> N //│ N | error @@ -444,10 +443,10 @@ mixin P { constructor(x: int) } //│ ╔══[ERROR] module constructor overriden is not supported -//│ ║ l.441: constructor(x: int) +//│ ║ l.440: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] mixin constructor overriden is not supported -//│ ║ l.444: constructor(x: int) +//│ ║ l.443: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ module O() //│ mixin P() From 70fd4428389ced270d71054b7803d37c74f87087 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 18 May 2023 16:00:10 +0800 Subject: [PATCH 296/498] Fix minor problems mentioned in PR comments --- shared/src/test/diff/parser/{NuParser.mls => NegativeLits.mls} | 0 shared/src/test/diff/tapl/SimplyTyped.mls | 1 - 2 files changed, 1 deletion(-) rename shared/src/test/diff/parser/{NuParser.mls => NegativeLits.mls} (100%) diff --git a/shared/src/test/diff/parser/NuParser.mls b/shared/src/test/diff/parser/NegativeLits.mls similarity index 100% rename from shared/src/test/diff/parser/NuParser.mls rename to shared/src/test/diff/parser/NegativeLits.mls diff --git a/shared/src/test/diff/tapl/SimplyTyped.mls b/shared/src/test/diff/tapl/SimplyTyped.mls index 6e097a41e1..2b386c208b 100644 --- a/shared/src/test/diff/tapl/SimplyTyped.mls +++ b/shared/src/test/diff/tapl/SimplyTyped.mls @@ -308,7 +308,6 @@ fun typeTerm(t, ctx) = //│ 'rhs0 <: FunctionType & {lhs: 'rhs0, rhs: 'rhs0} | PrimitiveType | ~FunctionType & ~PrimitiveType //│ = [Function: typeTerm] -// FIXME fun showTypeTerm(t, ctx) = if typeTerm(t, ctx) is Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) From b89fa16117d2129197d59fc4ecbb41e8d21f9412 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 18 May 2023 16:02:58 +0800 Subject: [PATCH 297/498] Fix the warning in UCS source files --- shared/src/main/scala/mlscript/ucs/LetBinding.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/scala/mlscript/ucs/LetBinding.scala b/shared/src/main/scala/mlscript/ucs/LetBinding.scala index 3d86c09f4f..6e08b3ce2d 100644 --- a/shared/src/main/scala/mlscript/ucs/LetBinding.scala +++ b/shared/src/main/scala/mlscript/ucs/LetBinding.scala @@ -6,7 +6,7 @@ import mlscript.utils.shorthands._ import scala.collection.immutable.Set import scala.collection.mutable.{Set => MutSet, Buffer} -case class LetBinding(val kind: LetBinding.Kind, val recursive: Bool, val name: Var, val term: Term) +final case class LetBinding(val kind: LetBinding.Kind, val recursive: Bool, val name: Var, val term: Term) object LetBinding { sealed abstract class Kind From 14a232a822b8552dad2d19a83228552e7fffd05e Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Thu, 18 May 2023 16:27:53 +0800 Subject: [PATCH 298/498] Try to fix more warnings --- shared/src/main/scala/mlscript/helpers.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 02cd4c9f00..6b2a45b19d 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -218,7 +218,7 @@ trait TypeImpl extends Located { self: Type => case _: Union | _: Function | _: Tuple | _: Recursive | _: Neg | _: Rem | _: Bounds | _: WithExtension | Top | Bot | _: Literal | _: TypeVar | _: AppliedType | _: TypeName - | _: Constrained | _ : Splice | _: TypeTag | _: PolyType => + | _: Constrained | _ : Splice | _: TypeTag | _: PolyType | _: Selection => Nil } @@ -232,7 +232,8 @@ trait TypeImpl extends Located { self: Type => case Inter(lhs, rhs) => lhs.collectTypeNames ++ rhs.collectTypeNames case _: Union | _: Function | _: Record | _: Tuple | _: Recursive | _: Neg | _: Rem | _: Bounds | _: WithExtension | Top | Bot | _: PolyType - | _: Literal | _: TypeVar | _: Constrained | _ : Splice | _: TypeTag => + | _: Literal | _: TypeVar | _: Constrained | _ : Splice | _: TypeTag + | _: Selection => Nil } @@ -245,7 +246,8 @@ trait TypeImpl extends Located { self: Type => case Inter(ty1, ty2) => ty1.collectBodyFieldsAndTypes ++ ty2.collectBodyFieldsAndTypes case _: Union | _: Function | _: Tuple | _: Recursive | _: Neg | _: Rem | _: Bounds | _: WithExtension | Top | Bot | _: PolyType - | _: Literal | _: TypeVar | _: AppliedType | _: TypeName | _: Constrained | _ : Splice | _: TypeTag => + | _: Literal | _: TypeVar | _: AppliedType | _: TypeName | _: Constrained | _ : Splice | _: TypeTag + | _: Selection => Nil } } @@ -729,6 +731,8 @@ trait StatementImpl extends Located { self: Statement => ).withLocOf(hd) :: cs) case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => ??? // TODO + case NuTypeDef(Mxn, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => + ??? // TODO case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), sig, pars, sup, ths, unit) => // TODO properly check: require(fs.isEmpty, fs) From 1fc76273e23ce83dee1954c11aa947bd620f7e0d Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Thu, 18 May 2023 17:11:48 +0800 Subject: [PATCH 299/498] merge the class inheritance function --- .../scala/mlscript/ConstraintSolver.scala | 2 - .../src/main/scala/mlscript/NuTypeDefs.scala | 231 ++++++++---------- shared/src/test/diff/gadt/Exp1.mls | 36 +-- shared/src/test/diff/nu/InterfaceMono.mls | 11 +- shared/src/test/diff/nu/Interfaces.mls | 53 ++-- 5 files changed, 147 insertions(+), 186 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index a6d84c5e32..1bb5c16f77 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -656,7 +656,6 @@ class ConstraintSolver extends NormalForms { self: Typer => // } } case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => - // TODO: inherited trait tags println(s"class checking $pt $pts") if (pts.contains(pt) || pts.exists(p => pt.parentsST.contains(p.id))) println(s"OK $pt <: ${pts.mkString(" | ")}") @@ -684,7 +683,6 @@ class ConstraintSolver extends NormalForms { self: Typer => } } case (LhsRefined(N, ts, r, trs), RhsBases(pts, N, trs2)) => - // TODO inherited trait tags println(s"tag checking ${ts} ${pts}") if (pts.exists(p => ts.toList.flatMap { case TraitTag(n, h) => n :: h.toList.map(n => Var(n.name)) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 9929757ff2..e19dbc8a18 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -917,91 +917,137 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val tparamFields = tparamMems.map(p => p.nme.toVar -> p.ty) assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) + + case class Pack( + superType: ST, + clsMem: Ls[NuMember], + bsCls: Opt[Str], + bsMem: Ls[NuMember], + trtMem: Ls[NuMember], + pTP: Map[Str, NuMember] + ) - def inherit(parents: Ls[ParentSpec], superType: ST, members: Ls[NuMember]) - : (ST, Ls[NuMember]) = + def inherit(parents: Ls[ParentSpec], pack: Pack): Pack = parents match { - case (p, v @ Var(mxnNme), mxnTargs, mxnArgs) :: ps => - val newMembs = trace(s"${lvl}. Inheriting from $p") { - ctx.get(mxnNme) match { + case (p, v @ Var(parNme), parTargs, parArgs) :: ps => + trace(s"${lvl}. Inheriting from $p") { + ctx.get(parNme) match { case S(lti: LazyTypeInfo) => - - lti.complete().freshen match { - case mxn: TypedNuMxn => - if (mxnTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) - - // println(s"Fresh $mxn") - - assert(finalType.level === lvl) - assert(mxn.superTV.level === lvl) - assert(mxn.thisTV.level === lvl) - - constrain(superType, mxn.superTV) - constrain(finalType, mxn.thisTV) + val info = lti.complete() + info match { + case rawMxn: TypedNuMxn => + val mxn = rawMxn.freshen.asInstanceOf[TypedNuMxn] + val newMembs = { + if (parTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) + + // println(s"Fresh $mxn") + + assert(finalType.level === lvl) + assert(mxn.superTV.level === lvl) + assert(mxn.thisTV.level === lvl) + + constrain(pack.superType, mxn.superTV) + constrain(finalType, mxn.thisTV) + + if (parArgs.sizeCompare(mxn.params) =/= 0) + err(msg"mixin $parNme expects ${ + mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) + + val paramMems = mxn.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + } + + // TODO check overriding + val bodyMems = mxn.ttu.entities + + paramMems ++ bodyMems + } + + val newSuperType = WithType( + pack.superType, + RecordType( + newMembs.collect{ + case m: NuParam => m.nme.toVar -> m.ty + case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) + } + )(provTODO) + )(provTODO) + inherit(ps, pack.copy( + superType=newSuperType, + clsMem=pack.clsMem ++ newMembs + )) + + case rawTrt: TypedNuTrt => + if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) + val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) + + inherit(ps, pack.copy( + trtMem = memberUn(pack.trtMem, trt.members.values.toList), + pTP = pack.pTP ++ ptp ++ trt.parentTP + )) + + case rawCls: TypedNuCls => + if (pack.bsCls.isDefined) + err(msg"cannot inherit from more than one base class: ${ + pack.bsCls.get} and ${parNme}", v.toLoc) + + val (cls, ptp) = refreshGen[TypedNuCls](info, v, parTargs) - if (mxnArgs.sizeCompare(mxn.params) =/= 0) - err(msg"mixin $mxnNme expects ${ - mxn.params.size.toString} parameter(s); got ${mxnArgs.size.toString}", Loc(v :: mxnArgs.unzip._2)) + if (parArgs.sizeCompare(cls.params) =/= 0) + err(msg"class $parNme expects ${ + cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - val paramMems = mxn.params.lazyZip(mxnArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec implicit val genLambdas: GenLambdas = true val a_ty = typeTerm(a) p.lb.foreach(constrain(_, a_ty)) constrain(a_ty, p.ub) NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } - - // TODO check overriding - val bodyMems = mxn.ttu.entities - - paramMems ++ bodyMems - - case trt: TypedNuTrt => Nil // handled in computeBaseClass - case cls: TypedNuCls => Nil // handled in computeBaseClass + inherit(ps, pack.copy( + bsCls = S(parNme), + bsMem = paramMems ++ cls.members.values.toList, + pTP = pack.pTP ++ ptp ++ cls.parentTP + )) + case als: TypedNuAls => // TODO dealias first? err(msg"Cannot inherit from a type alias", p.toLoc) - Nil + inherit(ps, pack) case als: NuParam => // TODO first-class mixins/classes... err(msg"Cannot inherit from a parameter", p.toLoc) - Nil + inherit(ps, pack) // case als: NuTypeParam => // err(msg"Cannot inherit from a type parameter", p.toLoc) // Nil case cls: TypedNuFun => err(msg"Cannot inherit from a function", p.toLoc) - Nil + inherit(ps, pack) } case S(_) => err(msg"Cannot inherit from this", p.toLoc) - Nil + inherit(ps, pack) case N => - err(msg"Could not find definition `${mxnNme}`", p.toLoc) - Nil + err(msg"Could not find definition `${parNme}`", p.toLoc) + inherit(ps, pack) } }() - val newSuperType = WithType( - superType, - RecordType( - newMembs.collect{ - case m: NuParam => m.nme.toVar -> m.ty - case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) - } - )(provTODO) - )(provTODO) - inherit(ps, newSuperType, members ++ newMembs) case Nil => - val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & + val thisType = WithType(pack.superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { assert(finalType.level === lvl) constrain(thisType, finalType) - members + pack.clsMem }() // println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") - (thisType, members) + pack.copy(superType = thisType) } // * We start from an empty super type. @@ -1010,87 +1056,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) - val (thisType, baseMems) = - inherit(parentSpecs, baseType, tparamMems ++ paramMems) - + val Pack(thisType, baseMems, _, bsMembers, ifaceMembers, ptps) = + inherit(parentSpecs, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) + ctx += "super" -> VarSymbol(thisType, Var("super")) - val ttu = typeTypingUnit(td.body, topLevel = false) - // TODO report non-unit result/statements? - - case class Pack( - clsMem: Ls[NuMember], - bsCls: Opt[Str], - bsMem: Ls[NuMember], - trtMem: Ls[NuMember], - pTP: Map[Str, NuMember] - ) - - // compute base class and interfaces - def computeBaseClassTrait(parents: Ls[ParentSpec], pack: Pack): Pack = - parents match { - case (p, v @ Var(parNme), parTargs, parArgs) :: ps => - ctx.get(parNme) match { - case S(lti: LazyTypeInfo) => - val info = lti.complete() - info match { - case rawCls: TypedNuCls => - if (pack.bsCls.isDefined) - err(msg"cannot inherit from more than one base class: ${ - pack.bsCls.get} and ${parNme}", v.toLoc) - - val (cls, ptp) = refreshGen[TypedNuCls](info, v, parTargs) - - if (parArgs.sizeCompare(cls.params) =/= 0) - err(msg"class $parNme expects ${ - cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - - val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) - } - val numem = paramMems ++ cls.members.values.toList - - // parent class fields/methods - val res = pack.clsMem ++ numem.flatMap { m => - pack.clsMem.find(x => x.name == m.name) match { + val cmems = baseMems ++ ttu.entities + val impltdMems = cmems ++ bsMembers.flatMap { m => + cmems.find(x => x.name == m.name) match { case S(mem: TypedNuTermDef) => Nil case S(pm: NuParam) => Nil case _ => m :: Nil } } - - computeBaseClassTrait(ps, pack.copy( - clsMem = res, - bsCls = S(parNme), - bsMem = cls.members.values.toList, - pTP = pack.pTP ++ ptp ++ cls.parentTP - )) - - case rawTrt: TypedNuTrt => - if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) - - computeBaseClassTrait(ps, pack.copy( - trtMem = memberUn(pack.trtMem, trt.members.values.toList), - pTP = pack.pTP ++ ptp ++ trt.parentTP - )) - - case _ => computeBaseClassTrait(ps, pack) - } - case _ => computeBaseClassTrait(ps, pack) - } - case Nil => pack - } - - val Pack(clsMems, _, bsMembers, ifaceMembers, ptps) = - computeBaseClassTrait(parentSpecs, Pack(baseMems ++ ttu.entities, N, Nil, Nil, Map.empty)) - - val impltdMems = clsMems val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers // overriding check for class/interface inheritance @@ -1199,7 +1178,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val nms = Set.from(l.map(_.name) ++ r.map(_.name)).toList nms.map {n => (l.find(x => x.name == n), r.find(x => x.name == n)) match { - case(S(a: TypedNuFun), S(b: TypedNuFun)) + case (S(a: TypedNuFun), S(b: TypedNuFun)) if a.level == b.level && a.fd.isLetRec == b.fd.isLetRec && a.fd.nme == b.fd.nme @@ -1207,9 +1186,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // todo: check fd.rhs => TypedNuFun(a.level, a.fd, a.bodyType & b.bodyType) - case(S(a), N) => a - case(N, S(b)) => b - case _ => lastWords("unreachable") + case (S(a), _) => a // for other cases, we take the first one (is it a good idea ?) + case (N, S(b)) => b + case (N, N) => lastWords("unreachable") } } } diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 908e269460..69fefb07d1 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -38,31 +38,9 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.9: } //│ ╙── ^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.6: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.7: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.8: Pair then 1 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.9: } -//│ ╙── ^ //│ ╔══[ERROR] Cannot inherit from a function //│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ╙── ^^^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.6: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.7: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.8: Pair then 1 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.9: } -//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.6: fun test = if this is //│ ║ ^^^^^^^ @@ -82,7 +60,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] :e // TODO Lit(0).test //│ ╔══[ERROR] Type `Lit` does not contain member `test` -//│ ║ l.83: Lit(0).test +//│ ║ l.61: Lit(0).test //│ ╙── ^^^^^ //│ error //│ res @@ -103,8 +81,8 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.104: Pair['a, 'b](l, r) then [l, r] -//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ ║ l.82: Pair['a, 'b](l, r) then [l, r] +//│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared @@ -116,11 +94,11 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.116: fun f(x: a) = x -//│ ╙── ^ +//│ ║ l.94: fun f(x: a) = x +//│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.117: f(l) -//│ ╙── ^ +//│ ║ l.95: f(l) +//│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: //│ unresolved symbol l diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index a47c5b61cc..fff2d64b3c 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -236,7 +236,6 @@ class C1[A] { fun a: A = a } //│ fun a: A //│ } -// TODO class C2 extends C1[int] { fun a = 1 } //│ class C2() { //│ fun a: 1 @@ -262,19 +261,19 @@ class C extends MyTrait[int] { fun a = 1 } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.262: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.262: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.262: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.263: class C extends MyTrait[int] { fun a = false } +//│ ║ l.262: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ //│ ╟── from signature of member a: -//│ ║ l.249: trait MyTrait[A] { fun a: A } +//│ ║ l.248: trait MyTrait[A] { fun a: A } //│ ╙── ^^^^ //│ class C() { //│ fun a: false diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index a8bcf72a32..cd80f0e065 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -717,6 +717,13 @@ class Bc11 extends Bc1(1) { //│ ╔══[ERROR] Type mismatch in reference: //│ ║ l.715: let foo = true //│ ║ ^^^^ +//│ ╟── reference of type `true` does not match type `1` +//│ ╟── Note: constraint arises from integer literal: +//│ ║ l.714: class Bc11 extends Bc1(1) { +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.715: let foo = true +//│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: //│ ║ l.674: class Bc1(foo: int) @@ -766,13 +773,13 @@ bp: Base[(int, bool)] :e bp: Base[(int, int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.767: bp: Base[(int, int)] +//│ ║ l.774: bp: Base[(int, int)] //│ ║ ^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.759: let bp: BPar[bool] +//│ ║ l.766: let bp: BPar[bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.767: bp: Base[(int, int)] +//│ ║ l.774: bp: Base[(int, int)] //│ ╙── ^^^ //│ Base[(int, int,)] @@ -804,7 +811,7 @@ fb(cp1, 2) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.805: trait BErr1 extends Base +//│ ║ l.812: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -813,38 +820,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.814: class DerBad1 extends Base[int, int] +//│ ║ l.821: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.814: class DerBad1 extends Base[int, int] +//│ ║ l.821: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.824: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -911,11 +918,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.912: class Fischl(age: bool) extends Oz +//│ ║ l.919: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.905: let age: int +//│ ║ l.912: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -934,20 +941,20 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.934: fun foo(x) = x && true +//│ ║ l.941: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.934: fun foo(x) = x && true +//│ ║ l.941: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.934: fun foo(x) = x && true +//│ ║ l.941: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.934: fun foo(x) = x && true +//│ ║ l.941: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.926: fun foo(x) = x + 1 +//│ ║ l.933: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go() { //│ fun foo: bool -> bool @@ -964,11 +971,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.965: class Ohhh(x: bool) extends Ha +//│ ║ l.972: class Ohhh(x: bool) extends Ha //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.956: class Ha { let x: int = 1 } +//│ ║ l.963: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) From 87f4fabd02d665c7d6fe7abae692695c8d67f708 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 18 May 2023 19:25:48 +0800 Subject: [PATCH 300/498] Update error message --- shared/src/main/scala/mlscript/NuTypeDefs.scala | 2 +- shared/src/test/diff/codegen/OptionalParam.mls | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 9fd04b9274..95ce6c8f33 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -605,7 +605,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx ++= signatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) if (((td.kind is Nms) || (td.kind is Mxn)) && td.ctor.isDefined) - err(msg"${td.kind.str} constructor overriden is not supported", + err(msg"Explicit ${td.kind.str} constructors are not supported.", td.ctor.fold[Opt[Loc]](N)(c => c.toLoc)) val (res, funMembers) = td.kind match { diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 569baa8a2f..817cf15042 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -442,10 +442,10 @@ module O { mixin P { constructor(x: int) } -//│ ╔══[ERROR] module constructor overriden is not supported +//│ ╔══[ERROR] Explicit module constructors are not supported. //│ ║ l.440: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] mixin constructor overriden is not supported +//│ ╔══[ERROR] Explicit mixin constructors are not supported. //│ ║ l.443: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ module O() From c9edfca84f1126c4be02760011eb1c84f1f88431 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 18 May 2023 19:34:49 +0800 Subject: [PATCH 301/498] Refactor --- shared/src/main/scala/mlscript/NewParser.scala | 9 ++++----- shared/src/main/scala/mlscript/helpers.scala | 1 + shared/src/main/scala/mlscript/syntax.scala | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 6b11310188..1692f1feeb 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -223,7 +223,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D errExpr case R(d: NuDecl) => d case R(e: Term) => e - case R(c: Constructor) => c case _ => ??? } TypingUnit(es) @@ -393,13 +392,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case _ => Nil } val tu = curlyTypingUnit - val (ctors: Ls[Constructor], body) = tu.entities.partition { - case _: Constructor => true - case _ => false + val (ctors, body) = tu.entities.partitionMap { + case c: Constructor => L(c) + case t => R(t) } val ctor = - if (ctors.length > 1) { + if (ctors.lengthIs > 1) { err(msg"A class may only have one constructor" -> S(l0) :: Nil) N } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 0f830a29cd..6cd1985d53 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -496,6 +496,7 @@ trait TermImpl extends StatementImpl { self: Term => case Forall(_, _) => s"forall clause" case Inst(bod) => "explicit instantiation" case Super() => "super" + case Constructor(_, _) => "constructor" } } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 91b7071f2e..6717c0c685 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -81,6 +81,7 @@ final case class Where(body: Term, where: Ls[Statement]) extends Ter final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term final case class Super() extends Term +final case class Constructor(params: Tup, body: Ls[Statement]) extends Term // constructor(...) { ... } final case class Ass(lhs: Var, rhs: Term) extends Term // x = y in constructors. TODO: make lhs term sealed abstract class IfBody extends IfBodyImpl @@ -113,7 +114,6 @@ sealed trait Statement extends StatementImpl final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement final case class DataDefn(body: Term) extends Statement final case class DatatypeDefn(head: Term, body: Term) extends Statement -final case class Constructor(params: Tup, body: Ls[Statement]) extends Statement sealed trait DesugaredStatement extends Statement with DesugaredStatementImpl From fec2eb8e649379e9473ab6b94ae582d4a734b815 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Thu, 18 May 2023 20:40:07 +0800 Subject: [PATCH 302/498] fix some trait problems --- .../src/main/scala/mlscript/NuTypeDefs.scala | 101 ++++++--- shared/src/test/diff/nu/InterfaceMono.mls | 191 +++++++++++++++--- 2 files changed, 239 insertions(+), 53 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index e19dbc8a18..0fd94c340b 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -835,7 +835,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (trt, vm) = refreshGen[TypedNuTrt](info, v , parTargs) inherit(ps, tags & trt.selfTy, - memberUn(members, trt.members.values.toList), + memberUnion(members, trt.members.values.toList), vms ++ vm ++ trt.parentTP // with type members of parent class ) case _ => @@ -856,8 +856,32 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val selfType = sig_ty val ttu = typeTypingUnit(td.body, topLevel = false) - val trtMems = baseMems ++ ttu.entities - val mems = typedSignatureMembers.toMap ++ trtMems.map(d => d.name -> d).toMap + val mems = + baseMems.map(d => d.name -> d).toMap ++ + typedSignatureMembers.toMap ++ + ttu.entities.map(d => d.name -> d).toMap + + // check trait overriding + baseMems.foreach { m => + lazy val parSign = m match { + case nt: TypedNuTermDef => nt.typeSignature + case np: NuParam => np.typeSignature + case _ => ??? // probably no other cases + } + (typedSignatureMembers.map(_._2) ++ ttu.entities).find(x => x.name == m.name) match { + case S(mem: TypedNuTermDef) => + val memSign = mem.typeSignature + implicit val prov: TP = memSign.prov + println(s"checking overriding `${m.name}`") + constrain(memSign, parSign) + case S(pm: NuParam) => + val pmSign = pm.typeSignature + implicit val prov: TP = pmSign.prov + println(s"checking overriding `${m.name}`") + constrain(pmSign, parSign) + case _ => () + } + } TypedNuTrt(outerCtx.lvl, td, ttu, tparams, @@ -925,7 +949,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => bsMem: Ls[NuMember], trtMem: Ls[NuMember], pTP: Map[Str, NuMember] - ) + ) def inherit(parents: Ls[ParentSpec], pack: Pack): Pack = parents match { @@ -986,7 +1010,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) inherit(ps, pack.copy( - trtMem = memberUn(pack.trtMem, trt.members.values.toList), + trtMem = memberUnion(pack.trtMem, trt.members.values.toList), pTP = pack.pTP ++ ptp ++ trt.parentTP )) @@ -1062,14 +1086,22 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "super" -> VarSymbol(thisType, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) - val cmems = baseMems ++ ttu.entities + // local members overrides mixin members + val cmems = ttu.entities ++ baseMems.flatMap { m => + ttu.entities.find(x => x.name == m.name) match { + case S(mem: TypedNuTermDef) => Nil + case S(pm: NuParam) => Nil + case _ => m :: Nil + } + } + // local members overrides parent members val impltdMems = cmems ++ bsMembers.flatMap { m => - cmems.find(x => x.name == m.name) match { - case S(mem: TypedNuTermDef) => Nil - case S(pm: NuParam) => Nil - case _ => m :: Nil - } - } + cmems.find(x => x.name == m.name) match { + case S(mem: TypedNuTermDef) => Nil + case S(pm: NuParam) => Nil + case _ => m :: Nil + } + } val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers // overriding check for class/interface inheritance @@ -1174,21 +1206,40 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - def memberUn(l: Ls[NuMember], r: Ls[NuMember])(implicit raise: Raise): Ls[NuMember] = { + // intersection of members + def memberUnion(l: Ls[NuMember], r: Ls[NuMember])(implicit raise: Raise): Ls[NuMember] = { val nms = Set.from(l.map(_.name) ++ r.map(_.name)).toList - nms.map {n => + nms.flatMap {n => (l.find(x => x.name == n), r.find(x => x.name == n)) match { - case (S(a: TypedNuFun), S(b: TypedNuFun)) - if a.level == b.level - && a.fd.isLetRec == b.fd.isLetRec - && a.fd.nme == b.fd.nme - && a.fd.tparams == b.fd.tparams - // todo: check fd.rhs - => - TypedNuFun(a.level, a.fd, a.bodyType & b.bodyType) - case (S(a), _) => a // for other cases, we take the first one (is it a good idea ?) - case (N, S(b)) => b - case (N, N) => lastWords("unreachable") + case (S(a: TypedNuFun), S(b: TypedNuFun)) => + if (a.level != b.level) + err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", a.fd.toLoc) + if (a.fd.tparams != b.fd.tparams) + err(msg"method ${a.name} has different type parameter to${b.name}", a.fd.toLoc) + val fd = NuFunDef((a.fd.isLetRec, b.fd.isLetRec) match { + case (S(a), S(b)) => S(a || b) + case _ => N // if one is fun, then it will be fun + }, a.fd.nme, a.fd.tparams, a.fd.rhs)(a.fd.declareLoc, N) + println(s"united ${a.name}") + TypedNuFun(a.level, fd, a.bodyType & b.bodyType) :: Nil + case (S(a: NuParam), S(b: NuParam)) => + if (a.level != b.level) + err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) + NuParam(a.nme, a.ty && b.ty)(a.level) :: Nil + case (S(a: NuParam), S(b: TypedNuFun)) => // not sure + if (a.level != b.level) + err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) + NuParam(a.nme, a.ty && FieldType(S(b.bodyType), b.bodyType)(b.bodyType.prov))(a.level) :: Nil + case (S(a: TypedNuFun), S(b: NuParam)) => // not sure + if (a.level != b.level) + err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) + NuParam(b.nme, FieldType(S(a.bodyType), a.bodyType)(a.bodyType.prov) && b.ty)(b.level) :: Nil + case (S(a), N) => a :: Nil + case (N, S(b)) => b :: Nil + case (S(a), S(b)) => + err(msg"intersection of ${a.name} and ${b.name} is currently not supported", N) + Nil + case (N, N) => Nil } } } diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index fff2d64b3c..7d2b52e130 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -117,29 +117,14 @@ class Goodstatt(size: 1 | 2) extends RefinedStadt { class Errcity(size: int) extends SizedStadt { fun bar = "hahaha" } -//│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.118: fun bar = "hahaha" -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"hahaha"` is not a function -//│ ║ l.118: fun bar = "hahaha" -//│ ║ ^^^^^^^^ -//│ ╟── but it flows into definition of method bar with expected type `int -> int` -//│ ║ l.118: fun bar = "hahaha" -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── Note: constraint arises from function type: -//│ ║ l.96: fun bar: int -> int -//│ ║ ^^^^^^^^^^ -//│ ╟── from signature of member bar: -//│ ║ l.96: fun bar: int -> int -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member foo is declared in parent trait but not implemented +//│ ╔══[ERROR] Member name is declared in parent trait but not implemented //│ ║ l.117: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.118: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.119: } //│ ╙── ^ -//│ ╔══[ERROR] Member name is declared in parent trait but not implemented +//│ ╔══[ERROR] Member foo is declared in parent trait but not implemented //│ ║ l.117: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.118: fun bar = "hahaha" @@ -153,6 +138,21 @@ class Errcity(size: int) extends SizedStadt { //│ ╟── Note: constraint arises from union type: //│ ║ l.95: let size: 1 | 2 | 3 //│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in definition of method bar: +//│ ║ l.118: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── string literal of type `"hahaha"` is not a function +//│ ║ l.118: fun bar = "hahaha" +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into definition of method bar with expected type `int -> int` +//│ ║ l.118: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from function type: +//│ ║ l.96: fun bar: int -> int +//│ ║ ^^^^^^^^^^ +//│ ╟── from signature of member bar: +//│ ║ l.96: fun bar: int -> int +//│ ╙── ^^^^^^^^^^^^^^^ //│ class Errcity(size: int) { //│ fun bar: "hahaha" //│ } @@ -184,11 +184,31 @@ mixin Fooo { //│ fun foo: anything -> 0 //│ } -// FIXME +class Grassberg(name: "grass" | "GRASS") extends More, SizedStadt, Fooo +//│ class Grassberg(name: "GRASS" | "grass") { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun foo: anything -> 0 +//│ fun more: number -> bool +//│ fun size: 1 +//│ } + +:e class Dirtberg extends More, SizedStadt, Fooo { let name = "dirt" fun size = 4 // this should not check } +//│ ╔══[ERROR] Type mismatch in definition of method size: +//│ ║ l.198: fun size = 4 // this should not check +//│ ║ ^^^^^^^^ +//│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` +//│ ║ l.198: fun size = 4 // this should not check +//│ ║ ^ +//│ ╟── but it flows into definition of method size with expected type `1 | 2 | 3` +//│ ║ l.198: fun size = 4 // this should not check +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.95: let size: 1 | 2 | 3 +//│ ╙── ^^^^^^^^^ //│ class Dirtberg() { //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 @@ -213,19 +233,19 @@ class A { fun x: int = 1 } :e class B extends A { fun x = "A" } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.214: class B extends A { fun x = "A" } +//│ ║ l.234: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── string literal of type `"A"` is not an instance of type `int` -//│ ║ l.214: class B extends A { fun x = "A" } +//│ ║ l.234: class B extends A { fun x = "A" } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `int` -//│ ║ l.214: class B extends A { fun x = "A" } +//│ ║ l.234: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.208: class A { fun x: int = 1 } +//│ ║ l.228: class A { fun x: int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.208: class A { fun x: int = 1 } +//│ ║ l.228: class A { fun x: int = 1 } //│ ╙── ^^^^^^^^^^ //│ class B() { //│ fun x: "A" @@ -261,22 +281,137 @@ class C extends MyTrait[int] { fun a = 1 } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.262: class C extends MyTrait[int] { fun a = false } +//│ ║ l.282: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.262: class C extends MyTrait[int] { fun a = false } +//│ ║ l.282: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.262: class C extends MyTrait[int] { fun a = false } +//│ ║ l.282: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.262: class C extends MyTrait[int] { fun a = false } +//│ ║ l.282: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ //│ ╟── from signature of member a: -//│ ║ l.248: trait MyTrait[A] { fun a: A } +//│ ║ l.268: trait MyTrait[A] { fun a: A } //│ ╙── ^^^^ //│ class C() { //│ fun a: false //│ } +trait T1 { + let foo : 1 | 2 | 3 + fun bar : string | bool +} +trait T2 { + let foo : 2 | 3 | 4 + let bar : int | bool +} +//│ trait T1() { +//│ fun bar: bool | string +//│ let foo: 1 | 2 | 3 +//│ } +//│ trait T2() { +//│ let bar: bool | int +//│ let foo: 2 | 3 | 4 +//│ } + +trait T4 extends T1, T2 { + fun foo: 2 +} +//│ trait T4() { +//│ fun bar: bool +//│ fun foo: 2 +//│ } + +class C1(foo: 2, bar: true) extends T4 +//│ class C1(foo: 2, bar: true) + +:e +class C3 extends T4{ + fun foo = 3 + fun bar = false +} +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.333: fun foo = 3 +//│ ║ ^^^^^^^ +//│ ╟── integer literal of type `3` does not match type `2` +//│ ║ l.333: fun foo = 3 +//│ ║ ^ +//│ ╟── but it flows into definition of method foo with expected type `2` +//│ ║ l.333: fun foo = 3 +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.321: fun foo: 2 +//│ ║ ^ +//│ ╟── from signature of member foo: +//│ ║ l.321: fun foo: 2 +//│ ╙── ^^^^^^ +//│ class C3() { +//│ fun bar: false +//│ fun foo: 3 +//│ } + +:e +class C2(foo: int, bar: string) extends T4 +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.357: class C2(foo: int, bar: string) extends T4 +//│ ║ ^^^^^^ +//│ ╟── type `string` does not match type `bool | int` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.309: let bar : int | bool +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.357: class C2(foo: int, bar: string) extends T4 +//│ ║ ^^^ +//│ ╟── type `int` does not match type `2` +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.321: fun foo: 2 +//│ ║ ^ +//│ ╟── from signature of member foo: +//│ ║ l.321: fun foo: 2 +//│ ╙── ^^^^^^ +//│ class C2(foo: int, bar: string) + +:e +trait T5 extends T4 { + let foo: 4 +} +//│ ╔══[ERROR] Type mismatch in literal type: +//│ ║ l.379: let foo: 4 +//│ ║ ^ +//│ ╟── type `4` does not match type `2` +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.321: fun foo: 2 +//│ ║ ^ +//│ ╟── from signature of member foo: +//│ ║ l.321: fun foo: 2 +//│ ╙── ^^^^^^ +//│ trait T5() { +//│ fun bar: bool +//│ let foo: 4 +//│ } + +:e +trait T3 extends T1, T2 { + let foo: true +} +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.398: let foo: true +//│ ║ ^^^^ +//│ ╟── type `true` does not match type `1 | 2 | 3` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.304: let foo : 1 | 2 | 3 +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.398: let foo: true +//│ ║ ^^^^ +//│ ╟── type `true` does not match type `2 | 3 | 4` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.308: let foo : 2 | 3 | 4 +//│ ╙── ^^^^^^^^^ +//│ trait T3() { +//│ fun bar: bool +//│ let foo: true +//│ } From 2ea30efbb975ef7c2662f4032093b7ce6bb03dec Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 19 May 2023 14:46:14 +0800 Subject: [PATCH 303/498] Use statement --- shared/src/main/scala/mlscript/NewParser.scala | 1 + shared/src/main/scala/mlscript/helpers.scala | 1 - shared/src/main/scala/mlscript/syntax.scala | 8 ++++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 1692f1feeb..d32c7a1b23 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -223,6 +223,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D errExpr case R(d: NuDecl) => d case R(e: Term) => e + case R(c: Constructor) => c case _ => ??? } TypingUnit(es) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 6cd1985d53..0f830a29cd 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -496,7 +496,6 @@ trait TermImpl extends StatementImpl { self: Term => case Forall(_, _) => s"forall clause" case Inst(bod) => "explicit instantiation" case Super() => "super" - case Constructor(_, _) => "constructor" } } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 6717c0c685..5fb8d76758 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -81,7 +81,6 @@ final case class Where(body: Term, where: Ls[Statement]) extends Ter final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term final case class Super() extends Term -final case class Constructor(params: Tup, body: Ls[Statement]) extends Term // constructor(...) { ... } final case class Ass(lhs: Var, rhs: Term) extends Term // x = y in constructors. TODO: make lhs term sealed abstract class IfBody extends IfBodyImpl @@ -111,9 +110,10 @@ trait IdentifiedTerm sealed abstract class SimpleTerm extends Term with IdentifiedTerm with SimpleTermImpl sealed trait Statement extends StatementImpl -final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement -final case class DataDefn(body: Term) extends Statement -final case class DatatypeDefn(head: Term, body: Term) extends Statement +final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement +final case class DataDefn(body: Term) extends Statement +final case class DatatypeDefn(head: Term, body: Term) extends Statement +final case class Constructor(params: Tup, body: Ls[Statement]) extends Statement // constructor(...) { ... } sealed trait DesugaredStatement extends Statement with DesugaredStatementImpl From 771f60ccd695fdcc7e4953511aeb90d0fc610361 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 19 May 2023 16:31:57 +0800 Subject: [PATCH 304/498] Add various tests --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- shared/src/test/diff/codegen/Shadowing.mls | 23 ++ shared/src/test/diff/codegen/Super.mls | 3 +- shared/src/test/diff/mlscript/Huawei2.mls | 34 +++ shared/src/test/diff/nu/Huawei1.mls | 60 +++++ .../src/test/diff/nu/ImplicitMethodPolym.mls | 29 ++- shared/src/test/diff/nu/NewNew.mls | 76 ++++++ shared/src/test/diff/nu/SimpleTraitImpl.mls | 238 ++++++++++++++++++ 8 files changed, 454 insertions(+), 11 deletions(-) create mode 100644 shared/src/test/diff/codegen/Shadowing.mls create mode 100644 shared/src/test/diff/mlscript/Huawei2.mls create mode 100644 shared/src/test/diff/nu/Huawei1.mls create mode 100644 shared/src/test/diff/nu/NewNew.mls create mode 100644 shared/src/test/diff/nu/SimpleTraitImpl.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 0fd94c340b..94132fe660 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -422,7 +422,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => - /** Type checks a typing unit, which is a sequence of possibly-nutually-recursive type and function definitions + /** Type checks a typing unit, which is a sequence of possibly-mutually-recursive type and function definitions * interleaved with plain statements. */ def typeTypingUnit(tu: TypingUnit, topLevel: Bool) (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]): TypedTypingUnit = diff --git a/shared/src/test/diff/codegen/Shadowing.mls b/shared/src/test/diff/codegen/Shadowing.mls new file mode 100644 index 0000000000..0bd6862c08 --- /dev/null +++ b/shared/src/test/diff/codegen/Shadowing.mls @@ -0,0 +1,23 @@ +:NewDefs + + +:js +x => + x => + x + 1 +//│ anything -> int -> int +//│ // Prelude +//│ let res; +//│ class TypingUnit {} +//│ const typing_unit = new TypingUnit; +//│ // Query 1 +//│ res = ((x) => (() => { +//│ return ((x) => (() => { +//│ return x + 1; +//│ })()); +//│ })()); +//│ // End of generated code +//│ res +//│ = [Function: res] + + diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index aa500a3b7b..c4e3d07e6b 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -86,7 +85,7 @@ mixin Foo2 { fun foo2 = super } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.86: fun foo2 = super +//│ ║ l.85: fun foo2 = super //│ ╙── ^^^^^ //│ mixin Foo2() { //│ super: 'super diff --git a/shared/src/test/diff/mlscript/Huawei2.mls b/shared/src/test/diff/mlscript/Huawei2.mls new file mode 100644 index 0000000000..a8e0499b65 --- /dev/null +++ b/shared/src/test/diff/mlscript/Huawei2.mls @@ -0,0 +1,34 @@ + +class C[A]: { a: A -> A } +//│ Defined class C[=A] + +class D: C[int] & { b: int } +//│ Defined class D + +d = D{a = id; b = if true then 0 else 1} +//│ d: D with {a: forall 'a. 'a -> 'a, b: 0 | 1} +//│ = D { a: [Function: id], b: 0 } + +d.a true +//│ res: true +//│ = true + +d.a 0 +//│ res: 0 +//│ = 0 + +d : #D +//│ res: D +//│ = D { a: [Function: id], b: 0 } + +def foo x = case x of D -> x.b, _ -> 0 +//│ foo: ((D\a with {b: 'b}) | ~D) -> (0 | 'b) +//│ = [Function: foo] + +// Overloading through intersections: not supported +// foo: ((D\a with {b: 'b}) -> 'b) & (~D -> 0) + +foo d +//│ res: 0 | 1 +//│ = 0 + diff --git a/shared/src/test/diff/nu/Huawei1.mls b/shared/src/test/diff/nu/Huawei1.mls new file mode 100644 index 0000000000..562aa49d39 --- /dev/null +++ b/shared/src/test/diff/nu/Huawei1.mls @@ -0,0 +1,60 @@ +:NewDefs + + +class C[A](x: A) { + fun foo = x +} +//│ class C[A](x: A) { +//│ fun foo: A +//│ } + +let c = C(123) +//│ let c: C[123] +//│ c +//│ = C {} + +class B +//│ class B() + +fun bar(c) = if c is + C(y) then y + B then 0 +//│ fun bar: forall 'x. (B | C['x]) -> (0 | 'x) + +bar(c) +//│ 0 | 123 +//│ res +//│ = 123 + +fun bar(c) = if c is + C(y) then y + 1 + B then 0 + else 1 +//│ fun bar: (C[int] | ~C[anything]) -> int + +bar(c) +//│ int +//│ res +//│ = 124 + +:e +bar(C(true)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.41: bar(C(true)) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── reference of type `true` is not an instance of type `int` +//│ ║ l.41: bar(C(true)) +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.30: C(y) then y + 1 +//│ ║ ^ +//│ ╟── from reference: +//│ ║ l.29: fun bar(c) = if c is +//│ ║ ^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.4: class C[A](x: A) { +//│ ╙── ^ +//│ error | int +//│ res +//│ = 2 + diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index f806c89263..12eb1ebb09 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -35,15 +35,28 @@ class C { //│ fun id2: 'c -> 'c //│ } +// FIXME +module M extends C { + this.id2(true) +} +//│ ╔══[ERROR] Type `#M` does not contain member `id2` +//│ ║ l.40: this.id2(true) +//│ ╙── ^^^^ +//│ module M() { +//│ fun f: forall 'a 'b. (0 | true | 'a, 0 | true | 'b,) +//│ fun id1: forall 'a 'b. ('b & 'a) -> (0 | true | 'a) +//│ fun id2: forall 'c. 'c -> 'c +//│ } + // FIXME module M extends C { fun g = (this.id2(true), this.id2(0)) } //│ ╔══[ERROR] Type `#M` does not contain member `id2` -//│ ║ l.40: fun g = (this.id2(true), this.id2(0)) +//│ ║ l.53: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ //│ ╔══[ERROR] Type `#M` does not contain member `id2` -//│ ║ l.40: fun g = (this.id2(true), this.id2(0)) +//│ ║ l.53: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ //│ module M() { //│ fun f: forall 'a 'b. (0 | true | 'a, 0 | true | 'b,) @@ -78,13 +91,13 @@ module M extends C { fun id1 = succ } //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.78: fun id1 = succ +//│ ║ l.91: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╟── application of type `?a` does not match type `int | ~(?b & ?c)` //│ ║ l.29: fun f = (id1(true), id1(0)) //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.78: fun id1 = succ +//│ ║ l.91: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╟── type `int` does not match type `0 | true | ?a` //│ ╟── Note: constraint arises from reference: @@ -128,16 +141,16 @@ module M { fun oops(x) = m := x } //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword in expression position -//│ ║ l.127: mut val m = None +//│ ║ l.140: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.127: mut val m = None +//│ ║ l.140: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' here -//│ ║ l.127: mut val m = None +//│ ║ l.140: mut val m = None //│ ╙── ^ //│ ╔══[ERROR] identifier not found: m -//│ ║ l.127: mut val m = None +//│ ║ l.140: mut val m = None //│ ╙── ^ //│ module M() //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls new file mode 100644 index 0000000000..1221bf856f --- /dev/null +++ b/shared/src/test/diff/nu/NewNew.mls @@ -0,0 +1,76 @@ +:NewDefs + + +class Foo(x: int) +//│ class Foo(x: int) + +let f = Foo(1) +//│ let f: Foo +//│ f +//│ = Foo {} + +let f = new Foo(1) +//│ let f: Foo +//│ f +//│ = Foo {} + +if f is Foo then 1 else 0 +//│ 0 | 1 +//│ res +//│ = 1 + +if f is Foo(a) then a else 0 +//│ int +//│ res +//│ = 1 + + +class Point[A](x: A, y: A) +//│ class Point[A](x: A, y: A) + +let origin = new Point(0, 0) +//│ let origin: Point[0] +//│ origin +//│ = Point {} + +// TODO +let origin = Point[int](0, 0) +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.37: let origin = Point[int](0, 0) +//│ ╙── ^^^^^^^^^^ +//│ let origin: error +//│ origin +//│ = Point {} + +// FIXME +let origin = new Point[int](0, 0) +//│ ╔══[PARSE ERROR] Unexpected application after `new` keyword +//│ ║ l.46: let origin = new Point[int](0, 0) +//│ ╙── ^^^^^^^^^^^^^^^^ +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + +// FIXME +new {} +//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword +//│ ║ l.54: new {} +//│ ╙── ^^ +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + +// FIXME +new +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.61: new +//│ ╙── ^ +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + +// FIXME +new + x: 0 +//│ ╔══[PARSE ERROR] Unexpected type ascription after `new` keyword +//│ ║ l.69: x: 0 +//│ ╙── ^ +//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + + + diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls new file mode 100644 index 0000000000..d1de25aa4c --- /dev/null +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -0,0 +1,238 @@ +:NewDefs + +:NoJS // TODO enable JS + + + +trait T1 { fun x: 0 | 1 } +trait T2 { fun x: 1 | 2 } +//│ trait T1() { +//│ fun x: 0 | 1 +//│ } +//│ trait T2() { +//│ fun x: 1 | 2 +//│ } + +:e +class C1 { fun x: 0 | 2 } +//│ ╔══[ERROR] Member x is declared but not defined +//│ ║ l.17: class C1 { fun x: 0 | 2 } +//│ ╙── ^ +//│ class C1() { +//│ fun x: 0 | 2 +//│ } + +class C1 { fun x: 0 | 2 = 0 } +//│ class C1() { +//│ fun x: 0 | 2 +//│ } + + + +:e +module M extends C1, T1 +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^^^^^^^^^^^^ +//│ ╟── type `2` does not match type `0 | 1` +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^ +//│ ╟── but it flows into union type with expected type `0 | 1` +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ║ ^^^^^ +//│ ╟── from signature of member x: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ module M() { +//│ fun x: 0 | 2 +//│ } + +:e +module M extends T1, C1 +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^^^^^^^^^^^^ +//│ ╟── type `2` does not match type `0 | 1` +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^ +//│ ╟── but it flows into union type with expected type `0 | 1` +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ║ ^^^^^ +//│ ╟── from signature of member x: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ module M() { +//│ fun x: 0 | 2 +//│ } + +:e +module M extends T1, T2, C1 { + fun x = this.x +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.76: fun x = this.x +//│ ╙── ^^ +//│ module M() { +//│ fun x: error +//│ } + +:e +module M extends T1, T2, C1 { + fun x: 0 + fun x = this.x +} +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.88: fun x = this.x +//│ ║ ^^^^^^^^^^ +//│ ╟── type `0` does not match type `1 | 2` +//│ ║ l.87: fun x: 0 +//│ ║ ^ +//│ ╟── but it flows into field selection with expected type `1 | 2` +//│ ║ l.88: fun x = this.x +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.8: trait T2 { fun x: 1 | 2 } +//│ ║ ^^^^^ +//│ ╟── from signature of member x: +//│ ║ l.8: trait T2 { fun x: 1 | 2 } +//│ ╙── ^^^^^^^^ +//│ module M() { +//│ fun x: 0 +//│ } + +module M extends C1, T2 { + fun x: 2 + fun x = this.x +} +//│ module M() { +//│ fun x: 2 +//│ } + + + +:e +class C2 extends T1 +//│ ╔══[ERROR] Member x is declared in parent trait but not implemented +//│ ║ l.120: class C2 extends T1 +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ class C2() + +// TODO +// abstract class C2 extends T1 + +class C2 extends T1 { fun x = 1 } +//│ class C2() { +//│ fun x: 1 +//│ } + +:e +class C2 extends T1, T2 { fun x = 2 } +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.135: class C2 extends T1, T2 { fun x = 2 } +//│ ║ ^^^^^ +//│ ╟── integer literal of type `2` does not match type `0 | 1` +//│ ║ l.135: class C2 extends T1, T2 { fun x = 2 } +//│ ║ ^ +//│ ╟── but it flows into definition of method x with expected type `0 | 1` +//│ ║ l.135: class C2 extends T1, T2 { fun x = 2 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ║ ^^^^^ +//│ ╟── from signature of member x: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ class C2() { +//│ fun x: 2 +//│ } + +class C2 extends T1, T2 { fun x = 1 } +//│ class C2() { +//│ fun x: 1 +//│ } + +:e +class C3 extends C2 { fun x = 111 } +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.161: class C3 extends C2 { fun x = 111 } +//│ ║ ^^^^^^^ +//│ ╟── integer literal of type `111` does not match type `1` +//│ ║ l.161: class C3 extends C2 { fun x = 111 } +//│ ║ ^^^ +//│ ╟── but it flows into definition of method x with expected type `1` +//│ ║ l.161: class C3 extends C2 { fun x = 111 } +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from integer literal: +//│ ║ l.155: class C2 extends T1, T2 { fun x = 1 } +//│ ║ ^ +//│ ╟── from definition of method x: +//│ ║ l.155: class C2 extends T1, T2 { fun x = 1 } +//│ ╙── ^^^^^ +//│ class C3() { +//│ fun x: 111 +//│ } + +class C3 extends C2 { fun x = 1 } +//│ class C3() { +//│ fun x: 1 +//│ } + +class C2 extends C1, T1 { fun x = 0 } +//│ class C2() { +//│ fun x: 0 +//│ } + +class C2 extends T1, C1 { fun x = 0 } +//│ class C2() { +//│ fun x: 0 +//│ } + +:e +class C2 extends C1, T1 { fun x = 1 } +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.197: class C2 extends C1, T1 { fun x = 1 } +//│ ║ ^^^^^ +//│ ╟── integer literal of type `1` does not match type `0 | 2` +//│ ║ l.197: class C2 extends C1, T1 { fun x = 1 } +//│ ║ ^ +//│ ╟── but it flows into definition of method x with expected type `0 | 2` +//│ ║ l.197: class C2 extends C1, T1 { fun x = 1 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^^^^^ +//│ ╟── from definition of method x: +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ╙── ^^^^^^^^^^^^ +//│ class C2() { +//│ fun x: 1 +//│ } + +:e +class C2 extends T1, C1 { fun x = 1 } +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.218: class C2 extends T1, C1 { fun x = 1 } +//│ ║ ^^^^^ +//│ ╟── integer literal of type `1` does not match type `0 | 2` +//│ ║ l.218: class C2 extends T1, C1 { fun x = 1 } +//│ ║ ^ +//│ ╟── but it flows into definition of method x with expected type `0 | 2` +//│ ║ l.218: class C2 extends T1, C1 { fun x = 1 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ ^^^^^ +//│ ╟── from definition of method x: +//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ╙── ^^^^^^^^^^^^ +//│ class C2() { +//│ fun x: 1 +//│ } + + From 48488080eea0088244cbd826b6b6c3b52e5e4c10 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Fri, 19 May 2023 18:14:42 +0800 Subject: [PATCH 305/498] refactor --- .../src/main/scala/mlscript/NuTypeDefs.scala | 78 ++++++++----------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 0fd94c340b..708443f764 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -862,26 +862,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ttu.entities.map(d => d.name -> d).toMap // check trait overriding - baseMems.foreach { m => - lazy val parSign = m match { - case nt: TypedNuTermDef => nt.typeSignature - case np: NuParam => np.typeSignature - case _ => ??? // probably no other cases - } - (typedSignatureMembers.map(_._2) ++ ttu.entities).find(x => x.name == m.name) match { - case S(mem: TypedNuTermDef) => - val memSign = mem.typeSignature - implicit val prov: TP = memSign.prov - println(s"checking overriding `${m.name}`") - constrain(memSign, parSign) - case S(pm: NuParam) => - val pmSign = pm.typeSignature - implicit val prov: TP = pmSign.prov - println(s"checking overriding `${m.name}`") - constrain(pmSign, parSign) - case _ => () - } - } + implCheck(baseMems, typedSignatureMembers.map(_._2) ++ ttu.entities, true)(td) TypedNuTrt(outerCtx.lvl, td, ttu, tparams, @@ -1088,11 +1069,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // local members overrides mixin members val cmems = ttu.entities ++ baseMems.flatMap { m => - ttu.entities.find(x => x.name == m.name) match { - case S(mem: TypedNuTermDef) => Nil - case S(pm: NuParam) => Nil - case _ => m :: Nil - } + ttu.entities.find(x => x.name == m.name) match { + case S(mem: TypedNuTermDef) => Nil + case S(pm: NuParam) => Nil + case _ => m :: Nil + } } // local members overrides parent members val impltdMems = cmems ++ bsMembers.flatMap { m => @@ -1105,27 +1086,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers // overriding check for class/interface inheritance - (bsMembers ++ ifaceMembers).foreach { m => - lazy val parSign = m match { - case nt: TypedNuTermDef => nt.typeSignature - case np: NuParam => np.typeSignature - case _ => ??? // probably no other cases - } - impltdMems.find(x => x.name == m.name) match { - case S(mem: TypedNuTermDef) => - val memSign = mem.typeSignature - implicit val prov: TP = memSign.prov - println(s"checking overriding `${m.name}`") - constrain(memSign, parSign) - case S(pm: NuParam) => - val pmSign = pm.typeSignature - implicit val prov: TP = pmSign.prov - constrain(pmSign, parSign) - case S(_) => Nil - case N => - err(msg"Member ${m.name} is declared in parent trait but not implemented", td.toLoc) - } - } + implCheck(bsMembers ++ ifaceMembers, impltdMems, false)(td) TypedNuCls(outerCtx.lvl, td, ttu, tparams, typedParams, mems, @@ -1205,6 +1166,31 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" } + + def implCheck(abst: Ls[NuMember], impl: Ls[NuMember], isTrt: Bool)(td: NuTypeDef)(implicit raise: Raise, ctx: Ctx) = { + abst.foreach { m => + lazy val parSign = m match { + case nt: TypedNuTermDef => nt.typeSignature + case np: NuParam => np.typeSignature + case _ => ??? // probably no other cases + } + impl.find(x => x.name == m.name) match { + case S(mem: TypedNuTermDef) => + val memSign = mem.typeSignature + implicit val prov: TP = memSign.prov + println(s"checking overriding `${m.name}`") + constrain(memSign, parSign) + case S(pm: NuParam) => + val pmSign = pm.typeSignature + implicit val prov: TP = pmSign.prov + constrain(pmSign, parSign) + case S(_) => () + case N => + if (!isTrt) + err(msg"Member ${m.name} is declared in parent trait but not implemented", td.toLoc) + } + } + } // intersection of members def memberUnion(l: Ls[NuMember], r: Ls[NuMember])(implicit raise: Raise): Ls[NuMember] = { From ab848a16e0060e283ca19f916a8eb1a7516737cf Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 20 May 2023 12:54:51 +0800 Subject: [PATCH 306/498] WIP Refactor: move parent spec typing out of complete() --- .../scala/mlscript/ConstraintSolver.scala | 12 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 352 ++++++++++-------- .../test/diff/ecoop23/PolymorphicVariants.mls | 28 +- shared/src/test/diff/nu/BadClassInherit.mls | 53 +++ shared/src/test/diff/nu/BadClasses.mls | 17 + .../src/test/diff/nu/ImplicitMethodPolym.mls | 128 +++++-- shared/src/test/diff/nu/InterfaceMono.mls | 2 +- shared/src/test/diff/nu/Interfaces.mls | 159 ++++---- 8 files changed, 470 insertions(+), 281 deletions(-) create mode 100644 shared/src/test/diff/nu/BadClassInherit.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 1bb5c16f77..17e3a63d86 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -69,6 +69,7 @@ class ConstraintSolver extends NormalForms { self: Typer => info.typedFields.get(fld) match { case S(fty) => S(fty) case N => + // TODO try to use `info.parentSpecs`? if (info.allFields.contains(fld)) // TODO don't report this if the field can be found somewhere else! foundRec = S(ErrorReport(msg"Indirectly-recursive member should have type annotation" -> fld.toLoc :: Nil)) N @@ -90,12 +91,12 @@ class ConstraintSolver extends NormalForms { self: Typer => } info.complete() match { + case cls: TypedNuCls => handle(cls.virtualMembers) + case trt: TypedNuTrt => handle(trt.virtualMembers) + case _ => ??? // TODO + } - case cls: TypedNuCls => handle(cls.virtualMembers) - case trt: TypedNuTrt => handle(trt.virtualMembers) - case _ => ??? // TODO } - } println(s"Lookup ${info.decl.name}.${fld.name} : $raw where ${raw.fold("")(_.ub.showBounds)}") @@ -1635,12 +1636,13 @@ class ConstraintSolver extends NormalForms { self: Typer => println(s"$tv2 <: ${tv2.upperBounds}") tv2 } else { + // NOTE: tv.level may be different from lvl; is that OK? freshened += tv -> rv rv } case None => val v = freshVar(tv.prov, S(tv), tv.nameHint)(if (tv.level > below) tv.level else { - assert(lvl <= below, "this condition shoudl not be true for the result to be correct") + assert(lvl <= below, "this condition should be false for the result to be correct") lvl }) freshened += tv -> v diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8e4c3b67d6..a2584ae7c9 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -186,7 +186,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol, body) ) } - + sealed trait PolyNuDecl extends TypedNuDecl { def tparams: TyParams } @@ -336,7 +336,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => td: NuTypeDef, thisTV: ST, superTV: ST, tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], ttu: TypedTypingUnit, - ) extends TypedNuTypeDef(Mxn) + ) extends TypedNuTypeDef(Mxn) with PolyNuDecl { val level: Level = thisTV.level - 1 // TODO cleaner def decl: NuTypeDef = td @@ -370,6 +370,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => : TypedNuFun = withLevel { implicit ctx => this match { case TypedNuFun(level, fd, ty) => TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) + // .tap(res => println(s"Freshen[$level,${ctx.lvl}] $this ~> $res")) }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) @@ -537,25 +538,125 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => println(s"${ctx.lvl}. Created lazy type info for $decl") type ParentSpec = (Term, Var, Ls[Type], Ls[Opt[Var] -> Fld]) - val parentSpecs: Ls[ParentSpec] = - decl match { - case td: NuTypeDef if td.kind == Trt || td.kind == Cls || td.kind == Nms => - td.parents.flatMap { - case v @ Var(nme) => - S(v, v, Nil, Nil) - case p @ App(v @ Var(nme), Tup(args)) => - S(p, v, Nil, args) - case TyApp(v @ Var(nme), targs) => - S(v, v, targs, Nil) - case p @ App(TyApp(v @ Var(nme), targs), Tup(args)) => - S(p, v, targs, args) - case p => - err(msg"Unsupported parent specification", p.toLoc) // TODO - N - } - case _ => Nil + val parentSpecs: Ls[ParentSpec] = decl match { + case td: NuTypeDef => + td.parents.flatMap { + case v @ Var(nme) => + S(v, v, Nil, Nil) + case p @ App(v @ Var(nme), Tup(args)) => + S(p, v, Nil, args) + case TyApp(v @ Var(nme), targs) => + S(v, v, targs, Nil) + case p @ App(TyApp(v @ Var(nme), targs), Tup(args)) => + S(p, v, targs, args) + case p => + err(msg"Unsupported parent specification", p.toLoc) // TODO + N + } + case _ => Nil } - + + type TypedParentSpec = (TypedNuTypeDef, Ls[NuMember], Map[Str, NuMember], Opt[Loc]) + + lazy val typedParents: Ls[TypedParentSpec] = ctx.nest.nextLevel { implicit ctx => + + ctx ++= paramSymbols + + parentSpecs.flatMap { + case (p, v @ Var(parNme), parTargs, parArgs) => + trace(s"${lvl}. Typing parent spec $p") { + ctx.get(parNme) match { + case S(lti: LazyTypeInfo) => + val info = lti.complete() + info match { + + case rawMxn: TypedNuMxn => + + // println(s"Raw $rawMxn") + val mxn = rawMxn.freshen.asInstanceOf[TypedNuMxn] + // println(s"Fresh $mxn") + + val newMembs = { + if (parTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) + + if (parArgs.sizeCompare(mxn.params) =/= 0) + err(msg"mixin $parNme expects ${ + mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) + + val paramMems = mxn.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + } + + val bodyMems = mxn.ttu.entities // TODO Q: why not `mxn.members`? + + paramMems ++ bodyMems + + } + println(s"Members $newMembs") + + S((mxn, newMembs, + Map.empty[Str, NuMember], // TODO add ptp here once we support explicit type args + p.toLoc + )) + + case rawTrt: TypedNuTrt => + if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) + val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) + + val paramMems = Nil // * Maybe support trait params? (not sure) + S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) + + case rawCls: TypedNuCls => + + val (cls, ptp) = refreshGen[TypedNuCls](info, v, parTargs) + + if (parArgs.sizeCompare(cls.params) =/= 0) + err(msg"class $parNme expects ${ + cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) + + val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + } + + S((cls, paramMems, ptp ++ cls.parentTP, p.toLoc)) + + case als: TypedNuAls => + // TODO dealias first? + err(msg"Cannot inherit from a type alias", p.toLoc) + N + case als: NuParam => + // TODO first-class mixins/classes... + err(msg"Cannot inherit from a parameter", p.toLoc) + N + // case als: NuTypeParam => + // err(msg"Cannot inherit from a type parameter", p.toLoc) + // Nil + case cls: TypedNuFun => + err(msg"Cannot inherit from a function", p.toLoc) + N + + } + case S(_) => + err(msg"Cannot inherit from this", p.toLoc) + N + case N => + err(msg"Could not find definition `${parNme}`", p.toLoc) + N + } + }() + } + + } + + def lookupTags(parents: Ls[ParentSpec], tags: Set[TypeName]): Set[TypeName] = { parents match { case Nil => tags @@ -690,7 +791,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) // refresh trait/class - def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : (T, Map[Str, NuMember]) = { + def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : (T, Map[Str, NuParam]) = { implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty @@ -821,36 +922,22 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val sig_ty = typeType(td.sig.getOrElse(Top)) - // inherit traits - def inherit(parents: Ls[ParentSpec], tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) + def inherit(parents: Ls[TypedParentSpec], tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) : (ST, Ls[NuMember], Map[Str, NuMember]) = parents match { - case (p, v @ Var(trtName), parTargs, args) :: ps => - ctx.get(trtName) match { - case S(lti: LazyTypeInfo) => - val info = lti.complete() - info match { - case rawTrt: TypedNuTrt => - if (args.nonEmpty) err(msg"trait arguments not yet supported", p.toLoc) - val (trt, vm) = refreshGen[TypedNuTrt](info, v , parTargs) - inherit(ps, - tags & trt.selfTy, - memberUnion(members, trt.members.values.toList), - vms ++ vm ++ trt.parentTP // with type members of parent class - ) - case _ => - err(msg"trait can only inherit traits", p.toLoc) - (tags, members, vms) - } - case _ => - err(msg"Could not find definition `${trtName}`", p.toLoc) - (tags, members, vms) - } - case Nil => (tags, members, vms) + case (trt: TypedNuTrt, newMembs, tpms, loc) :: ps => + inherit(ps, + tags & trt.selfTy, + memberUnion(members, trt.members.values.toList), + vms ++ tpms // with type members of parent class + ) + case (_, _, _, loc) :: ps => + err(msg"trait can only inherit from traits", loc) + inherit(ps, tags, members, vms) + case Nil => (tags, members, vms) } - val (tags, baseMems, vms) = - inherit(parentSpecs, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) + inherit(typedParents, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) // val selfType = tags & sig_ty val selfType = sig_ty @@ -932,125 +1019,71 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => pTP: Map[Str, NuMember] ) - def inherit(parents: Ls[ParentSpec], pack: Pack): Pack = - parents match { - case (p, v @ Var(parNme), parTargs, parArgs) :: ps => - trace(s"${lvl}. Inheriting from $p") { - ctx.get(parNme) match { - case S(lti: LazyTypeInfo) => - val info = lti.complete() - info match { - case rawMxn: TypedNuMxn => - val mxn = rawMxn.freshen.asInstanceOf[TypedNuMxn] - val newMembs = { - if (parTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) - - // println(s"Fresh $mxn") - - assert(finalType.level === lvl) - assert(mxn.superTV.level === lvl) - assert(mxn.thisTV.level === lvl) - - constrain(pack.superType, mxn.superTV) - constrain(finalType, mxn.thisTV) - - if (parArgs.sizeCompare(mxn.params) =/= 0) - err(msg"mixin $parNme expects ${ - mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - - val paramMems = mxn.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) - } - - // TODO check overriding - val bodyMems = mxn.ttu.entities - - paramMems ++ bodyMems - } - - val newSuperType = WithType( - pack.superType, - RecordType( - newMembs.collect{ - case m: NuParam => m.nme.toVar -> m.ty - case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) - } - )(provTODO) - )(provTODO) - inherit(ps, pack.copy( - superType=newSuperType, - clsMem=pack.clsMem ++ newMembs - )) - - case rawTrt: TypedNuTrt => - if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) - - inherit(ps, pack.copy( - trtMem = memberUnion(pack.trtMem, trt.members.values.toList), - pTP = pack.pTP ++ ptp ++ trt.parentTP - )) - - case rawCls: TypedNuCls => - if (pack.bsCls.isDefined) - err(msg"cannot inherit from more than one base class: ${ - pack.bsCls.get} and ${parNme}", v.toLoc) - - val (cls, ptp) = refreshGen[TypedNuCls](info, v, parTargs) - - if (parArgs.sizeCompare(cls.params) =/= 0) - err(msg"class $parNme expects ${ - cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - - val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) - } - inherit(ps, pack.copy( - bsCls = S(parNme), - bsMem = paramMems ++ cls.members.values.toList, - pTP = pack.pTP ++ ptp ++ cls.parentTP - )) + def inherit(parents: Ls[TypedParentSpec], pack: Pack): Pack = parents match { + case (p, newMembs, tpms, loc) :: ps => p match { + + + case mxn: TypedNuMxn => + + assert(finalType.level === lvl) + assert(mxn.superTV.level === lvl) + assert(mxn.thisTV.level === lvl) + + constrain(pack.superType, mxn.superTV) + constrain(finalType, mxn.thisTV) + + assert(tpms.isEmpty) // FIXME + + val newSuperType = WithType( + pack.superType, + RecordType( + newMembs.collect{ + case m: NuParam => m.nme.toVar -> m.ty + case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) + } + )(provTODO) + )(provTODO) + + inherit(ps, pack.copy( + superType = newSuperType, + clsMem = pack.clsMem ++ newMembs // FIXME add `mxn.members.values.toList`? + )) + + case trt: TypedNuTrt => + + inherit(ps, pack.copy( + trtMem = memberUnion(pack.trtMem, trt.members.values.toList), + pTP = pack.pTP ++ tpms + )) - case als: TypedNuAls => - // TODO dealias first? - err(msg"Cannot inherit from a type alias", p.toLoc) - inherit(ps, pack) - case als: NuParam => - // TODO first-class mixins/classes... - err(msg"Cannot inherit from a parameter", p.toLoc) - inherit(ps, pack) - // case als: NuTypeParam => - // err(msg"Cannot inherit from a type parameter", p.toLoc) - // Nil - case cls: TypedNuFun => - err(msg"Cannot inherit from a function", p.toLoc) - inherit(ps, pack) - } - case S(_) => - err(msg"Cannot inherit from this", p.toLoc) - inherit(ps, pack) - case N => - err(msg"Could not find definition `${parNme}`", p.toLoc) - inherit(ps, pack) - } - }() + case cls: TypedNuCls => + val parNme = cls.nme.name + + if (pack.bsCls.isDefined) + err(msg"cannot inherit from more than one base class: ${ + pack.bsCls.get} and ${parNme}", loc) + + inherit(ps, pack.copy( + bsCls = S(parNme), + bsMem = newMembs ++ cls.members.values.toList, + pTP = pack.pTP ++ tpms + )) + + case als: TypedNuAls => // Should be rejected in `typedParents` + inherit(ps, pack) + + } case Nil => val thisType = WithType(pack.superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) + trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { assert(finalType.level === lvl) constrain(thisType, finalType) pack.clsMem }() + // println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") pack.copy(superType = thisType) } @@ -1062,8 +1095,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) val Pack(thisType, baseMems, _, bsMembers, ifaceMembers, ptps) = - inherit(parentSpecs, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) - + inherit(typedParents, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) + ctx += "super" -> VarSymbol(thisType, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) @@ -1167,7 +1200,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - def implCheck(abst: Ls[NuMember], impl: Ls[NuMember], isTrt: Bool)(td: NuTypeDef)(implicit raise: Raise, ctx: Ctx) = { + private def implCheck(abst: Ls[NuMember], impl: Ls[NuMember], isTrt: Bool)(td: NuTypeDef) + (implicit raise: Raise, ctx: Ctx): Unit = { abst.foreach { m => lazy val parSign = m match { case nt: TypedNuTermDef => nt.typeSignature diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 6d95c90181..6d22b5e6c0 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -272,14 +272,14 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) :ns module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: forall 'A 'A0 'a 'b 'c. ('d, 'a,) -> ('e | 'b | 'c | 'f) +//│ fun eval: forall 'a 'b 'A 'A0 'c. ('d, 'a,) -> ('e | 'c | 'b | 'f) //│ } //│ where -//│ 'c :> #Abs & {Abs#A = 'A1} -//│ 'b :> #App & {App#A = 'A2} -//│ 'a <: #App & {App#A <: 'A0} | (#Abs & {Abs#A <: 'A} | 'g & ~#Abs) & ~#App -//│ 'A <: 't -//│ 'A0 <: 't0 & 's +//│ 'b :> #Abs & {Abs#A = 'A1} +//│ 'c :> #App & {App#A = 'A2} +//│ 'a <: #App & {App#A <: 'A} | (#Abs & {Abs#A <: 'A0} | 'g & ~#Abs) & ~#App +//│ 'A0 <: 't +//│ 'A <: 't0 & 's //│ 'd :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} //│ <: 'h & (Cons['A4] | Nil) //│ 'h :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} @@ -392,19 +392,19 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: forall 'a 'r 'b 'r0 'c 'l 'd 'A 'A0 'l0. ('e, 'd,) -> ('f | 'c | 'd | 'b) +//│ fun eval: forall 'r 'r0 'a 'A 'b 'c 'l 'd 'A0 'l0. ('e, 'a,) -> ('f | 'd | 'a | 'b) //│ } //│ where //│ 'b :> #Num -//│ 'c :> #Num -//│ 'd <: 'a -//│ 'a <: #Var | (#Num | (#Add & {Add#A <: 'A0} | #Mul & {Mul#A <: 'A} & ~#Add) & ~#Num) & ~#Var -//│ 'A <: 'r & 'l0 +//│ 'd :> #Num +//│ 'a <: 'c +//│ 'c <: #Var | (#Num | (#Add & {Add#A <: 'A0} | #Mul & {Mul#A <: 'A} & ~#Add) & ~#Num) & ~#Var +//│ 'A <: 'r0 & 'l0 //│ 'l0 <: 'g -//│ 'r <: 'g -//│ 'A0 <: 'r0 & 'l -//│ 'l <: 'g //│ 'r0 <: 'g +//│ 'A0 <: 'r & 'l +//│ 'l <: 'g +//│ 'r <: 'g //│ 'e :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} //│ <: 'h //│ 'h :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls new file mode 100644 index 0000000000..93806f7572 --- /dev/null +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -0,0 +1,53 @@ +:NewDefs + + +class C1(x: int) +//│ class C1(x: int) + +:e +class C2(x: int) extends C1(y) { + val y = x +} +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.8: class C2(x: int) extends C1(y) { +//│ ╙── ^ +//│ class C2(x: int) { +//│ let y: int +//│ } + +:e +class C2 extends C1(y) { + val y: int +} +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.19: class C2 extends C1(y) { +//│ ╙── ^ +//│ class C2() { +//│ let y: int +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol y + +:e +class C2 extends C1(this.y) { + val y: int +} +//│ ╔══[ERROR] identifier not found: this +//│ ║ l.32: class C2 extends C1(this.y) { +//│ ╙── ^^^^ +//│ class C2() { +//│ let y: int +//│ } + + +class C1(x: C1) +//│ class C1(x: C1) + +:e +class C2 extends C1(this) +//│ ╔══[ERROR] identifier not found: this +//│ ║ l.47: class C2 extends C1(this) +//│ ╙── ^^^^ +//│ class C2() + + diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 3537677663..c28ee5e843 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -104,3 +104,20 @@ class C1 { fun oops = this.x } //│ } +:e +class C { fun x: int } +//│ ╔══[ERROR] Member x is declared but not defined +//│ ║ l.108: class C { fun x: int } +//│ ╙── ^ +//│ class C() { +//│ fun x: int +//│ } + +// FIXME should error +// :e +class C { val x: int } +//│ class C() { +//│ let x: int +//│ } + + diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 12eb1ebb09..f0146872b5 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -2,28 +2,107 @@ module M { - fun id(x) = x + fun id1(x) = x } //│ module M() { -//│ fun id: 'a -> 'a +//│ fun id1: 'a -> 'a //│ } -M.id +M.id1 //│ 'a -> 'a //│ res -//│ = [Function: id] +//│ = [Function: id1] -M.id(true) +M.id1(true) //│ true //│ res //│ = true -M.id(0) +M.id1(0) //│ 0 //│ res //│ = 0 +module M { + fun id1(x) = x + id1(0) +} +//│ module M() { +//│ fun id1: 'a -> (0 | 'a) +//│ } + +M.id1 +//│ 'a -> (0 | 'a) +//│ res +//│ = [Function: id1] + +// :d +mixin Mx { + fun id1(x) = x +} +//│ mixin Mx() { +//│ fun id1: 'a -> 'a +//│ } + +// FIXME: inconsistency: order of freshening matters!! if TV freshened from thisTy, result is different +// :d +module M extends Mx { + val r = this.id1(0) +} +//│ module M() { +//│ fun id1: forall 'a. 'a -> 'a +//│ let r: 0 +//│ } + +// :d +mixin Mx { + fun id1(x) = this.id2(x) +} +//│ mixin Mx() { +//│ this: {id2: 'a -> 'b} +//│ fun id1: 'a -> 'b +//│ } + +:e +module M extends Mx { + this.id1(0) +} +//│ ╔══[ERROR] Type `#M & {id1: ?a -> ?b}` does not contain member `id2` +//│ ║ l.60: fun id1(x) = this.id2(x) +//│ ╙── ^^^^ +//│ module M() { +//│ fun id1: anything -> error +//│ } +//│ Runtime error: +//│ TypeError: self.id2 is not a function + +:e +module M extends Mx { + fun id2(x) = (x, x) + this.id1(0) +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.60: fun id1(x) = this.id2(x) +//│ ╙── ^^^^ +//│ module M() { +//│ fun id1: anything -> error +//│ fun id2: 'a -> ('a, 'a,) +//│ } + +// :d +module M extends Mx { + fun id2: 'a => ('a, 'a) + fun id2(x) = (x, x) + this.id1(0) +} +//│ module M() { +//│ fun id1: 'a -> ('a | 0, 'a | 0,) +//│ fun id2: forall 'a0. 'a0 -> ('a0, 'a0,) +//│ } + + + class C { fun id1(x) = x fun f = (id1(true), id1(0)) @@ -36,12 +115,13 @@ class C { //│ } // FIXME +// :d module M extends C { this.id2(true) } //│ ╔══[ERROR] Type `#M` does not contain member `id2` -//│ ║ l.40: this.id2(true) -//│ ╙── ^^^^ +//│ ║ l.120: this.id2(true) +//│ ╙── ^^^^ //│ module M() { //│ fun f: forall 'a 'b. (0 | true | 'a, 0 | true | 'b,) //│ fun id1: forall 'a 'b. ('b & 'a) -> (0 | true | 'a) @@ -53,11 +133,11 @@ module M extends C { fun g = (this.id2(true), this.id2(0)) } //│ ╔══[ERROR] Type `#M` does not contain member `id2` -//│ ║ l.53: fun g = (this.id2(true), this.id2(0)) -//│ ╙── ^^^^ +//│ ║ l.133: fun g = (this.id2(true), this.id2(0)) +//│ ╙── ^^^^ //│ ╔══[ERROR] Type `#M` does not contain member `id2` -//│ ║ l.53: fun g = (this.id2(true), this.id2(0)) -//│ ╙── ^^^^ +//│ ║ l.133: fun g = (this.id2(true), this.id2(0)) +//│ ╙── ^^^^ //│ module M() { //│ fun f: forall 'a 'b. (0 | true | 'a, 0 | true | 'b,) //│ fun g: (error, error,) @@ -91,18 +171,18 @@ module M extends C { fun id1 = succ } //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.91: fun id1 = succ -//│ ║ ^^^^^^^^^^ +//│ ║ l.171: fun id1 = succ +//│ ║ ^^^^^^^^^^ //│ ╟── application of type `?a` does not match type `int | ~(?b & ?c)` -//│ ║ l.29: fun f = (id1(true), id1(0)) -//│ ╙── ^^^^^^^^^ +//│ ║ l.108: fun f = (id1(true), id1(0)) +//│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.91: fun id1 = succ -//│ ║ ^^^^^^^^^^ +//│ ║ l.171: fun id1 = succ +//│ ║ ^^^^^^^^^^ //│ ╟── type `int` does not match type `0 | true | ?a` //│ ╟── Note: constraint arises from reference: -//│ ║ l.28: fun id1(x) = x -//│ ╙── ^ +//│ ║ l.107: fun id1(x) = x +//│ ╙── ^ //│ module M() { //│ fun f: (0 | true, 0 | true,) //│ fun id1: int -> int @@ -141,16 +221,16 @@ module M { fun oops(x) = m := x } //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword in expression position -//│ ║ l.140: mut val m = None +//│ ║ l.220: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.140: mut val m = None +//│ ║ l.220: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' here -//│ ║ l.140: mut val m = None +//│ ║ l.220: mut val m = None //│ ╙── ^ //│ ╔══[ERROR] identifier not found: m -//│ ║ l.140: mut val m = None +//│ ║ l.220: mut val m = None //│ ╙── ^ //│ module M() //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 7d2b52e130..be16eba5c7 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -29,7 +29,7 @@ class What1(toString: string) extends Showable :e trait NoShow extends What1("hi") -//│ ╔══[ERROR] trait can only inherit traits +//│ ╔══[ERROR] trait can only inherit from traits //│ ║ l.31: trait NoShow extends What1("hi") //│ ╙── ^^^^^^^^^^^ //│ trait NoShow() diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index cd80f0e065..fe02646a78 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -314,14 +314,17 @@ class E1 extends Test { :e trait TE1 extends C trait TE2 extends M, Test -//│ ╔══[ERROR] trait can only inherit traits +//│ ╔══[ERROR] trait can only inherit from traits //│ ║ l.315: trait TE1 extends C //│ ╙── ^ -//│ ╔══[ERROR] trait can only inherit traits +//│ ╔══[ERROR] trait can only inherit from traits //│ ║ l.316: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1() -//│ trait TE2() +//│ trait TE2() { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } :e class E2 extends Test { @@ -329,13 +332,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.328: fun foo = true +//│ ║ l.331: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.328: fun foo = true +//│ ║ l.331: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.328: fun foo = true +//│ ║ l.331: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -352,16 +355,16 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.353: class D extends Test[int], Test[bool] +//│ ║ l.356: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.353: class D extends Test[int], Test[bool] +//│ ║ l.356: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member foo is declared in parent trait but not implemented -//│ ║ l.353: class D extends Test[int], Test[bool] +//│ ║ l.356: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.353: class D extends Test[int], Test[bool] +//│ ║ l.356: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class D() @@ -412,10 +415,10 @@ let b: Base = f :e if b is Foo(a) then a else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.413: if b is Foo(a) then a else 0 +//│ ║ l.416: if b is Foo(a) then a else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.396: class Foo[A](aa: (A, A)) extends Base +//│ ║ l.399: class Foo[A](aa: (A, A)) extends Base //│ ║ ^ //│ ╙── into type `nothing` //│ (??A, ??A,) | 0 @@ -423,10 +426,10 @@ if b is Foo(a) then a else 0 // FIXME? why does it happen in this case and not above? if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.424: if b is Bar(f) then f else 0 +//│ ║ l.427: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.397: class Bar[B](f: B => B) extends Base +//│ ║ l.400: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -435,14 +438,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.434: if b is +//│ ║ l.437: if b is //│ ║ ^^^^ -//│ ║ l.435: Foo(a) then a +//│ ║ l.438: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.436: Bar(f) then f +//│ ║ l.439: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.396: class Foo[A](aa: (A, A)) extends Base +//│ ║ l.399: class Foo[A](aa: (A, A)) extends Base //│ ║ ^ //│ ╙── into type `nothing` //│ anything @@ -450,14 +453,14 @@ if b is :e let tt1 = Test //│ ╔══[ERROR] trait Test cannot be used in term position -//│ ║ l.451: let tt1 = Test +//│ ║ l.454: let tt1 = Test //│ ╙── ^^^^ //│ let tt1: error :e fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot match on trait `Test` -//│ ║ l.458: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.461: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -498,40 +501,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.496: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.496: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.496: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.496: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.497: z: WP +//│ ║ l.500: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.476: let z: ZL +//│ ║ l.479: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.497: z: WP +//│ ║ l.500: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.497: z: WP +//│ ║ l.500: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.498: g: ZL +//│ ║ l.501: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.475: let g: Geo +//│ ║ l.478: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.498: g: ZL +//│ ║ l.501: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.498: g: ZL +//│ ║ l.501: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -570,20 +573,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.569: fun foo(x) = x && false +//│ ║ l.572: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.569: fun foo(x) = x && false +//│ ║ l.572: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.569: fun foo(x) = x && false +//│ ║ l.572: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.569: fun foo(x) = x && false +//│ ║ l.572: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.540: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: (Test & 'a) -> (Oth | 'a) @@ -595,32 +598,32 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.594: class Eh extends Bs(1) +//│ ║ l.597: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.594: class Eh extends Bs(1) +//│ ║ l.597: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.539: class Bs(a: bool) { +//│ ║ l.542: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in integer literal: -//│ ║ l.594: class Eh extends Bs(1) +//│ ║ l.597: class Eh extends Bs(1) //│ ║ ^ //│ ╟── integer literal of type `1` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.539: class Bs(a: bool) { +//│ ║ l.542: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.595: class Eh1 extends Bs +//│ ║ l.598: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.540: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.540: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.540: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -629,7 +632,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.596: class Eh3 extends Bs(false), Test +//│ ║ l.599: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -685,8 +688,8 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.686: class Bc12 extends Bc1(1), Bc2(true) -//│ ╙── ^^^ +//│ ║ l.689: class Bc12 extends Bc1(1), Bc2(true) +//│ ╙── ^^^^^^^^^ //│ class Bc12() class Bc02 extends Bc1(1:int) { @@ -702,11 +705,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.703: class Bc31(baz: bool) extends Bc3 +//│ ║ l.706: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.677: let baz : int +//│ ║ l.680: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -715,18 +718,18 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.715: let foo = true +//│ ║ l.718: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.714: class Bc11 extends Bc1(1) { +//│ ║ l.717: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.715: let foo = true +//│ ║ l.718: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.674: class Bc1(foo: int) +//│ ║ l.677: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -773,13 +776,13 @@ bp: Base[(int, bool)] :e bp: Base[(int, int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.774: bp: Base[(int, int)] +//│ ║ l.777: bp: Base[(int, int)] //│ ║ ^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.766: let bp: BPar[bool] +//│ ║ l.769: let bp: BPar[bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.774: bp: Base[(int, int)] +//│ ║ l.777: bp: Base[(int, int)] //│ ╙── ^^^ //│ Base[(int, int,)] @@ -811,7 +814,7 @@ fb(cp1, 2) :e trait BErr1 extends Base //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.812: trait BErr1 extends Base +//│ ║ l.815: trait BErr1 extends Base //│ ╙── ^^^^ //│ trait BErr1() { //│ fun f: 'A -> 'A @@ -820,38 +823,38 @@ trait BErr1 extends Base :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.821: class DerBad1 extends Base[int, int] +//│ ║ l.824: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.821: class DerBad1 extends Base[int, int] +//│ ║ l.824: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.831: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -918,11 +921,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.919: class Fischl(age: bool) extends Oz +//│ ║ l.922: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.912: let age: int +//│ ║ l.915: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -941,20 +944,20 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.941: fun foo(x) = x && true +//│ ║ l.944: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.941: fun foo(x) = x && true +//│ ║ l.944: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.941: fun foo(x) = x && true +//│ ║ l.944: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.941: fun foo(x) = x && true +//│ ║ l.944: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.933: fun foo(x) = x + 1 +//│ ║ l.936: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go() { //│ fun foo: bool -> bool @@ -971,11 +974,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.972: class Ohhh(x: bool) extends Ha +//│ ║ l.975: class Ohhh(x: bool) extends Ha //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.963: class Ha { let x: int = 1 } +//│ ║ l.966: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) From 380209c5245910001af51586a98170d16ea56318 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sat, 20 May 2023 18:48:32 +0800 Subject: [PATCH 307/498] Change body's type --- shared/src/main/scala/mlscript/JSBackend.scala | 2 +- shared/src/main/scala/mlscript/NewParser.scala | 4 ++-- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/main/scala/mlscript/syntax.scala | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index e5fcc0d205..53de52a6bf 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -968,7 +968,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { val (params, preStmts) = ctor match { - case S(Constructor(Tup(ls), stmts)) => (S(ls.map { + case S(Constructor(Tup(ls), Blk(stmts))) => (S(ls.map { case (S(Var(nme)), _) => nme case _ => throw CodeGenError(s"Unexpected constructor parameters in $nme.") }), stmts) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index d32c7a1b23..1392ca1201 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -307,10 +307,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D consume val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO val body = curlyTypingUnit.entities - Constructor(Tup(as).withLoc(S(loc)), body) + Constructor(Tup(as).withLoc(S(loc)), Blk(body)) case _ => err(msg"Expect parameter list for the constructor" -> S(l0) :: Nil) - Constructor(Tup(Nil), Nil) + Constructor(Tup(Nil), Blk(Nil)) } val t = R(res.withLoc(S(l0 ++ res.getLoc))) yeetSpaces match { diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 0f830a29cd..66db949ccc 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -877,7 +877,7 @@ trait StatementImpl extends Located { self: Statement => case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil case Super() => Nil - case Constructor(params, body) => params :: body + case Constructor(params, body) => params :: body :: Nil case Ass(lhs, rhs) => lhs :: rhs :: Nil case NuTypeDef(k, nme, tps, ps, ctor, plain, sig, pars, sup, ths, bod) => nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 5fb8d76758..c44edb8111 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -110,10 +110,10 @@ trait IdentifiedTerm sealed abstract class SimpleTerm extends Term with IdentifiedTerm with SimpleTermImpl sealed trait Statement extends StatementImpl -final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement -final case class DataDefn(body: Term) extends Statement -final case class DatatypeDefn(head: Term, body: Term) extends Statement -final case class Constructor(params: Tup, body: Ls[Statement]) extends Statement // constructor(...) { ... } +final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement +final case class DataDefn(body: Term) extends Statement +final case class DatatypeDefn(head: Term, body: Term) extends Statement +final case class Constructor(params: Tup, body: Term) extends Statement // constructor(...) { ... } sealed trait DesugaredStatement extends Statement with DesugaredStatementImpl From bf67ba89cdd9dbaa1ae18749e38856e32d3bf90d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 22 May 2023 12:13:21 +0800 Subject: [PATCH 308/498] WIP Add some tests --- .../src/test/diff/nu/ImplicitMethodPolym.mls | 8 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 54 +++++++ .../test/diff/nu/TrickyGenericInheritance.mls | 144 ++++++++++++++++++ 3 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 shared/src/test/diff/nu/TrickyGenericInheritance.mls diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index f0146872b5..5abffe8cc8 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -45,8 +45,9 @@ mixin Mx { //│ fun id1: 'a -> 'a //│ } -// FIXME: inconsistency: order of freshening matters!! if TV freshened from thisTy, result is different -// :d +// * Note: the order of freshening matters! +// * if TV freshened transitively from traversing the `this` refinement at a lower ctx level, +// * as in the case below, the result is different. module M extends Mx { val r = this.id1(0) } @@ -55,7 +56,6 @@ module M extends Mx { //│ let r: 0 //│ } -// :d mixin Mx { fun id1(x) = this.id2(x) } @@ -90,7 +90,7 @@ module M extends Mx { //│ fun id2: 'a -> ('a, 'a,) //│ } -// :d +// * Notice that `id1` is no longer generalized! module M extends Mx { fun id2: 'a => ('a, 'a) fun id2(x) = (x, x) diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index d1de25aa4c..d96ecc75de 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -236,3 +236,57 @@ class C2 extends T1, C1 { fun x = 1 } //│ } + +:e +trait T2 { val r = 1(1) } +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.241: trait T2 { val r = 1(1) } +//│ ║ ^^^^ +//│ ╟── integer literal of type `1` is not a function +//│ ║ l.241: trait T2 { val r = 1(1) } +//│ ╙── ^ +//│ trait T2() { +//│ let r: error +//│ } + +:e // FIXME +class C2 extends T2 +//│ ╔══[ERROR] Member r is declared in parent trait but not implemented +//│ ║ l.253: class C2 extends T2 +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ class C2() + + +:e +trait T2[A] { + val r = C2().x +} +class C2 extends T2[int] +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.261: trait T2[A] { +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.262: val r = C2().x +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.263: } +//│ ╙── ^ +//│ ╔══[ERROR] Cannot inherit from a function +//│ ║ l.264: class C2 extends T2[int] +//│ ╙── ^^ +//│ ╔══[ERROR] Type `C2` does not contain member `x` +//│ ║ l.262: val r = C2().x +//│ ╙── ^^ +//│ trait T2[A]() { +//│ let r: error +//│ } +//│ class C2() + +:e // FIXME +C2() : T2['X] +//│ ╔══[ERROR] Type `C2` does not contain member `T2#A` +//│ ║ l.261: trait T2[A] { +//│ ╙── ^ +//│ T2['X] +//│ where +//│ 'X :> error + + diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls new file mode 100644 index 0000000000..aaf15592ff --- /dev/null +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -0,0 +1,144 @@ +:NewDefs + +:NoJS // TODO + + +trait T1[A] { + fun f: A -> A +} +//│ trait T1[A]() { +//│ fun f: A -> A +//│ } + +:e +class C1 extends T1 { + fun f(x: int) = x +} +//│ ╔══[ERROR] trait T1 expects 1 type parameter(s); got 0 +//│ ║ l.14: class C1 extends T1 { +//│ ╙── ^^ +//│ class C1() { +//│ fun f: (x: int,) -> int +//│ } + +class C1 extends T1['FigureItOut] { + fun f(x: int) = x +} +//│ class C1() { +//│ fun f: (x: int,) -> int +//│ } + +let c1 = new C1 +//│ let c1: C1 + +c1.f +//│ (x: int,) -> int + +(c1 : T1).f +//│ (??A & 'A) -> ('A | ??A0) + +(c1 : T1['X]).f +//│ int -> int + +:ns +(c1 : T1).f +//│ 'f +//│ where +//│ 'f :> 'A -> 'A +//│ 'A := in ??A out ??A0 + +:ns +(c1 : T1['X]).f +//│ 'f +//│ where +//│ 'f :> 'A -> 'A +//│ 'A := 'X +//│ 'X :> int +//│ <: 'FigureItOut +//│ 'FigureItOut :> int +//│ <: 'X & 'X0 & int +//│ 'X0 :> int +//│ <: 'FigureItOut + + + +// * The more tricky case: + +:e +trait T2[A] { + fun f: A -> A + val r = C2().f(false) +} +class C2 extends T2['FigureItOut] { + fun f(x: int) = x +} +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.68: trait T2[A] { +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.69: fun f: A -> A +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.70: val r = C2().f(false) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.71: } +//│ ╙── ^ +//│ ╔══[ERROR] Cannot inherit from a function +//│ ║ l.72: class C2 extends T2['FigureItOut] { +//│ ╙── ^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.70: val r = C2().f(false) +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `int` +//│ ║ l.70: val r = C2().f(false) +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.73: fun f(x: int) = x +//│ ╙── ^^^ +//│ trait T2[A]() { +//│ fun f: A -> A +//│ let r: error | int +//│ } +//│ class C2() { +//│ fun f: (x: int,) -> int +//│ } + +:e +trait T2[A] { + fun f: A -> A + val r = (C2() : T2['X]).f(false) +} +class C2 extends T2['FigureItOut] { + fun f(x: int) = x +} +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.105: trait T2[A] { +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.106: fun f: A -> A +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.107: val r = (C2() : T2['X]).f(false) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.108: } +//│ ╙── ^ +//│ ╔══[ERROR] Cannot inherit from a function +//│ ║ l.109: class C2 extends T2['FigureItOut] { +//│ ╙── ^^ +//│ ╔══[ERROR] Type `C2` does not contain member `T2#A` +//│ ║ l.105: trait T2[A] { +//│ ╙── ^ +//│ trait T2[A]() { +//│ fun f: A -> A +//│ let r: error | false +//│ } +//│ class C2() { +//│ fun f: (x: int,) -> int +//│ } + +:e // FIXME +C2() : T2['X] +//│ ╔══[ERROR] Type `C2` does not contain member `T2#A` +//│ ║ l.105: trait T2[A] { +//│ ╙── ^ +//│ T2['X] +//│ where +//│ 'X :> error + + From 2cb36d4a6ec4f7ef623da686d32bf0197ea560cb Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 22 May 2023 12:55:55 +0800 Subject: [PATCH 309/498] WIP Use proper Dummy typed declarations --- .../src/main/scala/mlscript/NuTypeDefs.scala | 29 +++++++++++++++++-- shared/src/main/scala/mlscript/Typer.scala | 2 ++ .../main/scala/mlscript/TyperHelpers.scala | 5 ++++ shared/src/test/diff/gadt/Exp1.mls | 14 +++------ shared/src/test/diff/nu/SimpleTraitImpl.mls | 3 -- .../test/diff/nu/TrickyGenericInheritance.mls | 18 ++++-------- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index a2584ae7c9..6526a49ac4 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -359,6 +359,24 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } + /** Used when there was an error while tying a definition. */ + case class TypedNuDummy(d: NuDecl) extends TypedNuDecl with TypedNuTermDef { + def level = MinLevel + def kind: DeclKind = Val + def name: Str = d.name + def typeSignature: ST = errType + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) = + this + def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + this + def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) + (implicit ctx: Ctx): TypedNuTermDef = + this + } + + /** Note: the type `bodyType` is stored *without* its polymorphic wrapper! (unlike `typeSignature`) */ case class TypedNuFun(level: Level, fd: NuFunDef, bodyType: ST) extends TypedNuDecl with TypedNuTermDef { def kind: DeclKind = Val @@ -643,6 +661,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"Cannot inherit from a function", p.toLoc) N + case cls: TypedNuDummy => + N + } case S(_) => err(msg"Cannot inherit from this", p.toLoc) @@ -836,9 +857,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { if (isComputing) { - val ty = err(msg"Unhandled cyclic definition", decl.toLoc) - // * Hacky: return a dummy decl to avoid possible infinite completion recursions - TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top))(N, N), ty) + // val ty = err(msg"Unhandled cyclic definition", decl.toLoc) + // // * Hacky: return a dummy decl to avoid possible infinite completion recursions + // TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top))(N, N), ty) + err(msg"Unhandled cyclic definition", decl.toLoc) + TypedNuDummy(decl) } else trace(s"Completing ${decl.showDbg}") { println(s"Type params ${tparams.mkString(" ")}") diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 56e67da8ad..c91b7348b6 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1356,6 +1356,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) NuFunDef(fd.isLetRec, fd.nme, Nil, R(go(tf.typeSignature)))(fd.declareLoc, fd.signature) case p: NuParam => ??? // TODO + case TypedNuDummy(d) => + ??? // TODO } def goLike(ty: TypeLike)(implicit ectx: ExpCtx): mlscript.TypeLike = ty match { case ty: SimpleType => diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 7367af2236..fdd2ba55cb 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -797,6 +797,8 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ cls.parentTP.valuesIterator.flatMap(childrenPolMem) + case prm: NuParam => childrenPolField(pol)(prm.ty) + case TypedNuDummy(d) => N } ents ::: tu.result.toList.map(pol -> _) }} @@ -845,6 +847,7 @@ abstract class TyperHelpers { Typer: Typer => private def childrenMem(m: NuMember): List[ST] = m match { case NuParam(nme, ty) => ty.lb.toList ::: ty.ub :: Nil case TypedNuFun(level, fd, ty) => ty :: Nil + case TypedNuDummy(d) => Nil } def children(includeBounds: Bool): List[SimpleType] = this match { case tv @ AssignedVariable(ty) => if (includeBounds) ty :: Nil else Nil @@ -885,6 +888,7 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.instanceType) + case TypedNuDummy(d) => Nil } ents ::: tu.result.toList } @@ -1195,6 +1199,7 @@ abstract class TyperHelpers { Typer: Typer => apply(pol.contravar)(superTV) case NuParam(nme, ty) => applyField(pol)(ty) case TypedNuFun(level, fd, ty) => apply(pol)(ty) + case TypedNuDummy(d) => () // case NuTypeParam(nme, ty) => applyField(pol)(ty) } def apply(pol: PolMap)(st: ST): Unit = st match { diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 69fefb07d1..50fa813698 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -24,9 +24,6 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.9: } //│ ╙── ^ -//│ ╔══[ERROR] Cannot inherit from a function -//│ ║ l.11: class Lit(n: int) extends Exp[int] -//│ ╙── ^^^ //│ ╔══[ERROR] Unhandled cyclic definition //│ ║ l.5: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,9 +35,6 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.9: } //│ ╙── ^ -//│ ╔══[ERROR] Cannot inherit from a function -//│ ║ l.12: class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.6: fun test = if this is //│ ║ ^^^^^^^ @@ -60,7 +54,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] :e // TODO Lit(0).test //│ ╔══[ERROR] Type `Lit` does not contain member `test` -//│ ║ l.61: Lit(0).test +//│ ║ l.55: Lit(0).test //│ ╙── ^^^^^ //│ error //│ res @@ -81,7 +75,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.82: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.76: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -94,10 +88,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.94: fun f(x: a) = x +//│ ║ l.88: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.95: f(l) +//│ ║ l.89: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index d96ecc75de..4afbf87bc9 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -269,9 +269,6 @@ class C2 extends T2[int] //│ ║ ^^^^^^^^^^^^^^^^ //│ ║ l.263: } //│ ╙── ^ -//│ ╔══[ERROR] Cannot inherit from a function -//│ ║ l.264: class C2 extends T2[int] -//│ ╙── ^^ //│ ╔══[ERROR] Type `C2` does not contain member `x` //│ ║ l.262: val r = C2().x //│ ╙── ^^ diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index aaf15592ff..9594134d66 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -81,9 +81,6 @@ class C2 extends T2['FigureItOut] { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.71: } //│ ╙── ^ -//│ ╔══[ERROR] Cannot inherit from a function -//│ ║ l.72: class C2 extends T2['FigureItOut] { -//│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.70: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^ @@ -110,19 +107,16 @@ class C2 extends T2['FigureItOut] { fun f(x: int) = x } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.105: trait T2[A] { +//│ ║ l.102: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.106: fun f: A -> A +//│ ║ l.103: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.107: val r = (C2() : T2['X]).f(false) +//│ ║ l.104: val r = (C2() : T2['X]).f(false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.108: } +//│ ║ l.105: } //│ ╙── ^ -//│ ╔══[ERROR] Cannot inherit from a function -//│ ║ l.109: class C2 extends T2['FigureItOut] { -//│ ╙── ^^ //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.105: trait T2[A] { +//│ ║ l.102: trait T2[A] { //│ ╙── ^ //│ trait T2[A]() { //│ fun f: A -> A @@ -135,7 +129,7 @@ class C2 extends T2['FigureItOut] { :e // FIXME C2() : T2['X] //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.105: trait T2[A] { +//│ ║ l.102: trait T2[A] { //│ ╙── ^ //│ T2['X] //│ where From adf0a710ffef469d18921b88a41b1e6aa5255b21 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 22 May 2023 13:51:35 +0800 Subject: [PATCH 310/498] WIP Small improvements in error message --- shared/src/main/scala/mlscript/NuTypeDefs.scala | 6 ++++-- shared/src/test/diff/nu/ImplicitMethodPolym.mls | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 6526a49ac4..660fb9c0b5 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -119,6 +119,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName def decl: NuTypeDef def tparams: TyParams + def members: Map[Str, NuMember] + val allFields: Set[Var] = members.valuesIterator.map(_.name |> Var).toSet override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = withLevel { implicit ctx => this match { @@ -170,6 +172,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = td.kind def name: Str = nme.name def nme: mlscript.TypeName = td.nme + def members: Map[Str, NuMember] = Map.empty def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl = @@ -793,10 +796,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => lazy val allFields: Set[Var] = decl match { case td: NuTypeDef => - // TODO also get fields from parents! (td.params.fields.iterator.flatMap(_._1) ++ td.body.entities.iterator.collect { case fd: NuFunDef => fd.nme - }).toSet + }).toSet ++ typedParents.flatMap(_._1.allFields) case _: NuFunDef => Set.empty } diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 5abffe8cc8..8be4a99a3f 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -114,12 +114,12 @@ class C { //│ fun id2: 'c -> 'c //│ } -// FIXME +// TODO support // :d module M extends C { this.id2(true) } -//│ ╔══[ERROR] Type `#M` does not contain member `id2` +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.120: this.id2(true) //│ ╙── ^^^^ //│ module M() { @@ -128,14 +128,14 @@ module M extends C { //│ fun id2: forall 'c. 'c -> 'c //│ } -// FIXME +// TODO support module M extends C { fun g = (this.id2(true), this.id2(0)) } -//│ ╔══[ERROR] Type `#M` does not contain member `id2` +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.133: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ -//│ ╔══[ERROR] Type `#M` does not contain member `id2` +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.133: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ //│ module M() { From 42ea186144590925c7719553d918e59aab6b3571 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 22 May 2023 14:32:22 +0800 Subject: [PATCH 311/498] Use Blk --- shared/src/main/scala/mlscript/syntax.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index c44edb8111..553d611344 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -113,7 +113,7 @@ sealed trait Statement extends StatementImpl final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement final case class DataDefn(body: Term) extends Statement final case class DatatypeDefn(head: Term, body: Term) extends Statement -final case class Constructor(params: Tup, body: Term) extends Statement // constructor(...) { ... } +final case class Constructor(params: Tup, body: Blk) extends Statement // constructor(...) { ... } sealed trait DesugaredStatement extends Statement with DesugaredStatementImpl From 4c8b5d5ffa92ca41fe8b8c6f58dfecd2b27c7500 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Mon, 22 May 2023 14:41:31 +0800 Subject: [PATCH 312/498] WIP Improve memberUnion --- .../src/main/scala/mlscript/NuTypeDefs.scala | 36 +++++++++---------- shared/src/test/diff/nu/InterfaceMono.mls | 14 ++++---- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 660fb9c0b5..f1e8ac469d 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1253,40 +1253,40 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // intersection of members def memberUnion(l: Ls[NuMember], r: Ls[NuMember])(implicit raise: Raise): Ls[NuMember] = { - val nms = Set.from(l.map(_.name) ++ r.map(_.name)).toList - nms.flatMap {n => - (l.find(x => x.name == n), r.find(x => x.name == n)) match { - case (S(a: TypedNuFun), S(b: TypedNuFun)) => + def merge(ltm: NuMember, rtm: Option[NuMember]) = { + (ltm, rtm) match { + case (a: TypedNuFun, S(b: TypedNuFun)) => if (a.level != b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", a.fd.toLoc) if (a.fd.tparams != b.fd.tparams) - err(msg"method ${a.name} has different type parameter to${b.name}", a.fd.toLoc) + err(msg"method ${a.name} has mismatch type parameters", a.fd.toLoc) val fd = NuFunDef((a.fd.isLetRec, b.fd.isLetRec) match { case (S(a), S(b)) => S(a || b) case _ => N // if one is fun, then it will be fun }, a.fd.nme, a.fd.tparams, a.fd.rhs)(a.fd.declareLoc, N) println(s"united ${a.name}") - TypedNuFun(a.level, fd, a.bodyType & b.bodyType) :: Nil - case (S(a: NuParam), S(b: NuParam)) => + S(TypedNuFun(a.level, fd, a.bodyType & b.bodyType)) + case (a: NuParam, S(b: NuParam)) => if (a.level != b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) - NuParam(a.nme, a.ty && b.ty)(a.level) :: Nil - case (S(a: NuParam), S(b: TypedNuFun)) => // not sure + S(NuParam(a.nme, a.ty && b.ty)(a.level)) + case (a: NuParam, S(b: TypedNuFun)) => // not sure if (a.level != b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) - NuParam(a.nme, a.ty && FieldType(S(b.bodyType), b.bodyType)(b.bodyType.prov))(a.level) :: Nil - case (S(a: TypedNuFun), S(b: NuParam)) => // not sure + S(NuParam(a.nme, a.ty && FieldType(S(b.bodyType), b.bodyType)(b.bodyType.prov))(a.level)) + case (a: TypedNuFun, S(b: NuParam)) => // not sure if (a.level != b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) - NuParam(b.nme, FieldType(S(a.bodyType), a.bodyType)(a.bodyType.prov) && b.ty)(b.level) :: Nil - case (S(a), N) => a :: Nil - case (N, S(b)) => b :: Nil - case (S(a), S(b)) => - err(msg"intersection of ${a.name} and ${b.name} is currently not supported", N) - Nil - case (N, N) => Nil + S(NuParam(b.nme, FieldType(S(a.bodyType), a.bodyType)(a.bodyType.prov) && b.ty)(b.level)) + case (a, N) => S(a) + case (a, S(b)) => + err(msg"intersection of member ${a.name} is currently not supported", N) + N } } + l.foldLeft(r.map(d => d.name -> d).toMap) { case (acc, ltm) => + acc.updatedWith(ltm.name)(merge(ltm, _)) + }.values.toList } } diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index be16eba5c7..4e5d5016a8 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -357,13 +357,6 @@ class C3 extends T4{ class C2(foo: int, bar: string) extends T4 //│ ╔══[ERROR] Type mismatch in type reference: //│ ║ l.357: class C2(foo: int, bar: string) extends T4 -//│ ║ ^^^^^^ -//│ ╟── type `string` does not match type `bool | int` -//│ ╟── Note: constraint arises from union type: -//│ ║ l.309: let bar : int | bool -//│ ╙── ^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.357: class C2(foo: int, bar: string) extends T4 //│ ║ ^^^ //│ ╟── type `int` does not match type `2` //│ ╟── Note: constraint arises from literal type: @@ -372,6 +365,13 @@ class C2(foo: int, bar: string) extends T4 //│ ╟── from signature of member foo: //│ ║ l.321: fun foo: 2 //│ ╙── ^^^^^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.357: class C2(foo: int, bar: string) extends T4 +//│ ║ ^^^^^^ +//│ ╟── type `string` does not match type `bool | int` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.309: let bar : int | bool +//│ ╙── ^^^^^^^^^^ //│ class C2(foo: int, bar: string) :e From 7b0697491fcd0bfcb9e8c6661bc3246310955ec2 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 22 May 2023 15:27:10 +0800 Subject: [PATCH 313/498] Changes from meeting --- .../scala/mlscript/ConstraintSolver.scala | 17 +-- .../src/main/scala/mlscript/NuTypeDefs.scala | 75 +++++----- shared/src/test/diff/nu/SimpleTraitImpl.mls | 140 ++++++++++++------ 3 files changed, 142 insertions(+), 90 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 17e3a63d86..f8369a5f74 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -684,16 +684,15 @@ class ConstraintSolver extends NormalForms { self: Typer => } } case (LhsRefined(N, ts, r, trs), RhsBases(pts, N, trs2)) => - println(s"tag checking ${ts} ${pts}") - if (pts.exists(p => ts.toList.flatMap { - case TraitTag(n, h) => n :: h.toList.map(n => Var(n.name)) - case _ => Nil - }.contains(p.id))) - println(s"OK $ts <: $pts") - else - reportError() + println(s"Tag checking ${ts} ${pts}") + if (pts.exists(p => ts.iterator.flatMap { + case TraitTag(n, h) => n :: h.toList.map(n => Var(n.name)) + case _ => Nil + }.contains(p.id))) + println(s"OK $ts <: $pts") + else reportError() case (LhsRefined(N, ts, r, _), RhsBases(pts, S(L(_: FunctionType | _: ArrayBase)), _)) => - reportError() + reportError() case (LhsRefined(S(b: TupleType), ts, r, _), RhsBases(pts, S(L(ty: TupleType)), _)) if b.fields.size === ty.fields.size => (b.fields.unzip._2 lazyZip ty.fields.unzip._2).foreach { (l, r) => diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index f1e8ac469d..63eb6f8221 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -155,7 +155,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tags.freshenAbove(lim, rigidify), inheritedTags, pvms.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap - ) + ) } } val td: NuTypeDef @@ -826,34 +826,34 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => raw.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) val parTP = raw.tparams.lazyZip(parTargs).map { case ((tn, _tv, vi), targTy) => - val targ = typeType(targTy) - val tv = (targ match { - case tv: TV => - // TODO - println(s"Passing ${tn.name} :: ${_tv} <=< ${tv}") - tv - case _ => - println(s"Assigning ${tn.name} :: ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - tv - }) - freshened += _tv -> tv - tn -> tv - } + val targ = typeType(targTy) + val tv = (targ match { + case tv: TV => + // TODO + println(s"Passing ${tn.name} :: ${_tv} <=< ${tv}") + tv + case _ => + println(s"Assigning ${tn.name} :: ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! + // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) + freshened += _tv -> tv + tn -> tv + } - println(s"collected ${parTP}") - - raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] -> - parTP.map { - case (nme, tv) => rawName+"#"+nme.name -> - NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - }.toMap + println(s"collected ${parTP}") + + raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] -> + parTP.map { + case (nme, tv) => rawName+"#"+nme.name -> + NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + }.toMap } @@ -1079,14 +1079,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inherit(ps, pack.copy( trtMem = memberUnion(pack.trtMem, trt.members.values.toList), pTP = pack.pTP ++ tpms - )) + )) case cls: TypedNuCls => val parNme = cls.nme.name - if (pack.bsCls.isDefined) + pack.bsCls.foreach { cls => err(msg"cannot inherit from more than one base class: ${ - pack.bsCls.get} and ${parNme}", loc) + cls} and ${parNme}", loc) + } inherit(ps, pack.copy( bsCls = S(parNme), @@ -1233,7 +1234,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case np: NuParam => np.typeSignature case _ => ??? // probably no other cases } - impl.find(x => x.name == m.name) match { + impl.find(x => x.name === m.name) match { case S(mem: TypedNuTermDef) => val memSign = mem.typeSignature implicit val prov: TP = memSign.prov @@ -1256,9 +1257,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def merge(ltm: NuMember, rtm: Option[NuMember]) = { (ltm, rtm) match { case (a: TypedNuFun, S(b: TypedNuFun)) => - if (a.level != b.level) + if (a.level =/= b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", a.fd.toLoc) - if (a.fd.tparams != b.fd.tparams) + if (a.fd.tparams =/= b.fd.tparams) err(msg"method ${a.name} has mismatch type parameters", a.fd.toLoc) val fd = NuFunDef((a.fd.isLetRec, b.fd.isLetRec) match { case (S(a), S(b)) => S(a || b) @@ -1267,15 +1268,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => println(s"united ${a.name}") S(TypedNuFun(a.level, fd, a.bodyType & b.bodyType)) case (a: NuParam, S(b: NuParam)) => - if (a.level != b.level) + if (a.level =/= b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) S(NuParam(a.nme, a.ty && b.ty)(a.level)) case (a: NuParam, S(b: TypedNuFun)) => // not sure - if (a.level != b.level) + if (a.level =/= b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) S(NuParam(a.nme, a.ty && FieldType(S(b.bodyType), b.bodyType)(b.bodyType.prov))(a.level)) case (a: TypedNuFun, S(b: NuParam)) => // not sure - if (a.level != b.level) + if (a.level =/= b.level) err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) S(NuParam(b.nme, FieldType(S(a.bodyType), a.bodyType)(a.bodyType.prov) && b.ty)(b.level)) case (a, N) => S(a) diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index 4afbf87bc9..8036a3ed9f 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -13,7 +13,7 @@ trait T2 { fun x: 1 | 2 } //│ fun x: 1 | 2 //│ } -:e +:e // TODO mk abstract class C1 { fun x: 0 | 2 } //│ ╔══[ERROR] Member x is declared but not defined //│ ║ l.17: class C1 { fun x: 0 | 2 } @@ -22,6 +22,58 @@ class C1 { fun x: 0 | 2 } //│ fun x: 0 | 2 //│ } +:e +module M extends C1, T1 { + fun x = 2 +} +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.27: fun x = 2 +//│ ║ ^^^^^ +//│ ╟── integer literal of type `2` does not match type `0 | 1` +//│ ║ l.27: fun x = 2 +//│ ║ ^ +//│ ╟── but it flows into definition of method x with expected type `0 | 1` +//│ ║ l.27: fun x = 2 +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ║ ^^^^^ +//│ ╟── from signature of member x: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ module M() { +//│ fun x: 2 +//│ } + +:e // TODO mk abstract +class C2 extends C1, T1 +//│ ╔══[ERROR] Type mismatch in signature of member x: +//│ ║ l.17: class C1 { fun x: 0 | 2 } +//│ ║ ^^^^^^^^ +//│ ╟── type `2` does not match type `0 | 1` +//│ ║ l.17: class C1 { fun x: 0 | 2 } +//│ ║ ^ +//│ ╟── but it flows into union type with expected type `0 | 1` +//│ ║ l.17: class C1 { fun x: 0 | 2 } +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ║ ^^^^^ +//│ ╟── from signature of member x: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ class C2() { +//│ fun x: 0 | 2 +//│ } + +// * TODO error? +module M extends C2 { + fun x = 2 +} +//│ module M() { +//│ fun x: 2 +//│ } + class C1 { fun x: 0 | 2 = 0 } //│ class C1() { //│ fun x: 0 | 2 @@ -32,13 +84,13 @@ class C1 { fun x: 0 | 2 = 0 } :e module M extends C1, T1 //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^^^^^^^^ //│ ╟── type `2` does not match type `0 | 1` -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^ //│ ╟── but it flows into union type with expected type `0 | 1` -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } @@ -53,13 +105,13 @@ module M extends C1, T1 :e module M extends T1, C1 //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^^^^^^^^ //│ ╟── type `2` does not match type `0 | 1` -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^ //│ ╟── but it flows into union type with expected type `0 | 1` -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } @@ -76,8 +128,8 @@ module M extends T1, T2, C1 { fun x = this.x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.76: fun x = this.x -//│ ╙── ^^ +//│ ║ l.128: fun x = this.x +//│ ╙── ^^ //│ module M() { //│ fun x: error //│ } @@ -88,14 +140,14 @@ module M extends T1, T2, C1 { fun x = this.x } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.88: fun x = this.x -//│ ║ ^^^^^^^^^^ +//│ ║ l.140: fun x = this.x +//│ ║ ^^^^^^^^^^ //│ ╟── type `0` does not match type `1 | 2` -//│ ║ l.87: fun x: 0 -//│ ║ ^ +//│ ║ l.139: fun x: 0 +//│ ║ ^ //│ ╟── but it flows into field selection with expected type `1 | 2` -//│ ║ l.88: fun x = this.x -//│ ║ ^^^^^^ +//│ ║ l.140: fun x = this.x +//│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.8: trait T2 { fun x: 1 | 2 } //│ ║ ^^^^^ @@ -119,7 +171,7 @@ module M extends C1, T2 { :e class C2 extends T1 //│ ╔══[ERROR] Member x is declared in parent trait but not implemented -//│ ║ l.120: class C2 extends T1 +//│ ║ l.172: class C2 extends T1 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C2() @@ -134,13 +186,13 @@ class C2 extends T1 { fun x = 1 } :e class C2 extends T1, T2 { fun x = 2 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.135: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.187: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── integer literal of type `2` does not match type `0 | 1` -//│ ║ l.135: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.187: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 1` -//│ ║ l.135: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.187: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } @@ -160,19 +212,19 @@ class C2 extends T1, T2 { fun x = 1 } :e class C3 extends C2 { fun x = 111 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.161: class C3 extends C2 { fun x = 111 } +//│ ║ l.213: class C3 extends C2 { fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── integer literal of type `111` does not match type `1` -//│ ║ l.161: class C3 extends C2 { fun x = 111 } +//│ ║ l.213: class C3 extends C2 { fun x = 111 } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `1` -//│ ║ l.161: class C3 extends C2 { fun x = 111 } +//│ ║ l.213: class C3 extends C2 { fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.155: class C2 extends T1, T2 { fun x = 1 } +//│ ║ l.207: class C2 extends T1, T2 { fun x = 1 } //│ ║ ^ //│ ╟── from definition of method x: -//│ ║ l.155: class C2 extends T1, T2 { fun x = 1 } +//│ ║ l.207: class C2 extends T1, T2 { fun x = 1 } //│ ╙── ^^^^^ //│ class C3() { //│ fun x: 111 @@ -196,19 +248,19 @@ class C2 extends T1, C1 { fun x = 0 } :e class C2 extends C1, T1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.197: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.249: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.197: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.249: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.197: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.249: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── from definition of method x: -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ╙── ^^^^^^^^^^^^ //│ class C2() { //│ fun x: 1 @@ -217,19 +269,19 @@ class C2 extends C1, T1 { fun x = 1 } :e class C2 extends T1, C1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.218: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.270: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.218: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.270: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.218: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.270: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── from definition of method x: -//│ ║ l.25: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } //│ ╙── ^^^^^^^^^^^^ //│ class C2() { //│ fun x: 1 @@ -237,22 +289,22 @@ class C2 extends T1, C1 { fun x = 1 } -:e +:e // FIXME reject impl in interface trait T2 { val r = 1(1) } //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.241: trait T2 { val r = 1(1) } +//│ ║ l.293: trait T2 { val r = 1(1) } //│ ║ ^^^^ //│ ╟── integer literal of type `1` is not a function -//│ ║ l.241: trait T2 { val r = 1(1) } +//│ ║ l.293: trait T2 { val r = 1(1) } //│ ╙── ^ //│ trait T2() { //│ let r: error //│ } -:e // FIXME +:e class C2 extends T2 //│ ╔══[ERROR] Member r is declared in parent trait but not implemented -//│ ║ l.253: class C2 extends T2 +//│ ║ l.305: class C2 extends T2 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C2() @@ -263,14 +315,14 @@ trait T2[A] { } class C2 extends T2[int] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.261: trait T2[A] { +//│ ║ l.313: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.262: val r = C2().x +//│ ║ l.314: val r = C2().x //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.263: } +//│ ║ l.315: } //│ ╙── ^ //│ ╔══[ERROR] Type `C2` does not contain member `x` -//│ ║ l.262: val r = C2().x +//│ ║ l.314: val r = C2().x //│ ╙── ^^ //│ trait T2[A]() { //│ let r: error @@ -280,7 +332,7 @@ class C2 extends T2[int] :e // FIXME C2() : T2['X] //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.261: trait T2[A] { +//│ ║ l.313: trait T2[A] { //│ ╙── ^ //│ T2['X] //│ where From f45cfeb09296de1dcb71b35f9a148a27e7fa58c2 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 22 May 2023 16:32:59 +0800 Subject: [PATCH 314/498] WIP Add/update tests --- shared/src/test/diff/codegen/New.mls | 97 +++++++++++++++++++ .../src/test/diff/codegen/OptionalParam.mls | 30 +++--- shared/src/test/diff/nu/Abstract.mls | 15 +++ shared/src/test/diff/nu/Dates.mls | 18 ++-- 4 files changed, 137 insertions(+), 23 deletions(-) create mode 100644 shared/src/test/diff/codegen/New.mls diff --git a/shared/src/test/diff/codegen/New.mls b/shared/src/test/diff/codegen/New.mls new file mode 100644 index 0000000000..4959e5a833 --- /dev/null +++ b/shared/src/test/diff/codegen/New.mls @@ -0,0 +1,97 @@ +:NewDefs + + +class C +//│ class C() + +:js +new C +//│ C +//│ // Prelude +//│ class TypingUnit1 {} +//│ const typing_unit1 = new TypingUnit1; +//│ // Query 1 +//│ res = new C(); +//│ // End of generated code +//│ res +//│ = C {} + +:re // TODO reject in type checking +:js +C() +//│ C +//│ // Prelude +//│ class TypingUnit2 {} +//│ const typing_unit2 = new TypingUnit2; +//│ // Query 1 +//│ res = C(); +//│ // End of generated code +//│ res +//│ Runtime error: +//│ TypeError: Class constructor C cannot be invoked without 'new' + +:js +let c = C +//│ let c: () -> C +//│ // Prelude +//│ class TypingUnit3 {} +//│ const typing_unit3 = new TypingUnit3; +//│ // Query 1 +//│ globalThis.c = C; +//│ // End of generated code +//│ c +//│ = [class C] + +:re // TODO reject in type checking +c() +//│ C +//│ res +//│ Runtime error: +//│ TypeError: Class constructor C cannot be invoked without 'new' + + +class C() +//│ class C() + +:js +new C +//│ C +//│ // Prelude +//│ class TypingUnit6 {} +//│ const typing_unit6 = new TypingUnit6; +//│ // Query 1 +//│ res = new C.class(); +//│ // End of generated code +//│ res +//│ = C {} + +:js +C() +//│ C +//│ // Prelude +//│ class TypingUnit7 {} +//│ const typing_unit7 = new TypingUnit7; +//│ // Query 1 +//│ res = C(); +//│ // End of generated code +//│ res +//│ = C {} + +:js +let c = C +//│ let c: () -> C +//│ // Prelude +//│ class TypingUnit8 {} +//│ const typing_unit8 = new TypingUnit8; +//│ // Query 1 +//│ globalThis.c1 = C; +//│ // End of generated code +//│ c +//│ = [Function (anonymous)] { class: [class C] } + +c() +//│ C +//│ res +//│ = C {} + + diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 817cf15042..2782e2de76 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -74,14 +74,13 @@ class C { //│ globalThis.C = typing_unit2.C; //│ // End of generated code -// TODO: typing -:e +:e // TODO: typing let c = new C(1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.79: let c = new C(1) +//│ ║ l.78: let c = new C(1) //│ ║ ^^^^ //│ ╟── argument of type `(1,)` does not match type `()` -//│ ║ l.79: let c = new C(1) +//│ ║ l.78: let c = new C(1) //│ ╙── ^^^ //│ let c: C | error //│ c @@ -142,14 +141,14 @@ class E { constructor(y: int) } //│ ╔══[PARSE ERROR] A class may only have one constructor -//│ ║ l.140: class E { +//│ ║ l.139: class E { //│ ╙── ^^^^^ //│ class E() :e constructor(x: int) //│ ╔══[ERROR] constructor must be in a class. -//│ ║ l.150: constructor(x: int) +//│ ║ l.149: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ () //│ Code generation encountered an error: @@ -161,13 +160,13 @@ class F(x: int) extends C(x + 1) {} class G extends C(2) {} class H extends B {} //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.160: class F(x: int) extends C(x + 1) {} +//│ ║ l.159: class F(x: int) extends C(x + 1) {} //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.161: class G extends C(2) {} +//│ ║ l.160: class G extends C(2) {} //│ ╙── ^^^^ //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.162: class H extends B {} +//│ ║ l.161: class H extends B {} //│ ╙── ^ //│ class F(x: int) //│ class G() @@ -264,7 +263,7 @@ module I { } } //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) -//│ ║ l.263: class L extends J(0) +//│ ║ l.262: class L extends J(0) //│ ╙── ^^^^ //│ module I() { //│ class J() @@ -416,15 +415,14 @@ fun h(z: int) = N //│ fun h: (z: int,) -> () -> N -// TODO: typing -:e +:e // TODO: typing let hh = h(1) new hh(1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.422: new hh(1) +//│ ║ l.420: new hh(1) //│ ║ ^^^^^ //│ ╟── argument of type `(1,)` does not match type `()` -//│ ║ l.422: new hh(1) +//│ ║ l.420: new hh(1) //│ ╙── ^^^ //│ let hh: () -> N //│ N | error @@ -443,10 +441,10 @@ mixin P { constructor(x: int) } //│ ╔══[ERROR] Explicit module constructors are not supported. -//│ ║ l.440: constructor(x: int) +//│ ║ l.438: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Explicit mixin constructors are not supported. -//│ ║ l.443: constructor(x: int) +//│ ║ l.441: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ module O() //│ mixin P() diff --git a/shared/src/test/diff/nu/Abstract.mls b/shared/src/test/diff/nu/Abstract.mls index e1173b64ac..3c212ddd8b 100644 --- a/shared/src/test/diff/nu/Abstract.mls +++ b/shared/src/test/diff/nu/Abstract.mls @@ -1,8 +1,23 @@ :NewDefs + abstract class Foo(x: int) { fun f(y: int) = x + y } //│ class Foo(x: int) { //│ fun f: (y: int,) -> int //│ } + + +:e // TODO +abstract class Foo(x: int) { + fun f: int -> int +} +//│ ╔══[ERROR] Member f is declared but not defined +//│ ║ l.14: fun f: int -> int +//│ ╙── ^ +//│ class Foo(x: int) { +//│ fun f: int -> int +//│ } + + diff --git a/shared/src/test/diff/nu/Dates.mls b/shared/src/test/diff/nu/Dates.mls index 08cdba1c5a..053bdcfb6a 100644 --- a/shared/src/test/diff/nu/Dates.mls +++ b/shared/src/test/diff/nu/Dates.mls @@ -1,26 +1,30 @@ :NewDefs + declare class Date { constructor(date: number) fun toString(): string + fun toLocaleString(locales: string | Array[string], options: anything): string } //│ class Date() { +//│ fun toLocaleString: (locales: Array[string] | string, options: anything,) -> string //│ fun toString: () -> string //│ } -// TODO: -:e +:e // TODO ctor typing let date1 = new Date(12345678) -date1.toString() //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.13: let date1 = new Date(12345678) +//│ ║ l.15: let date1 = new Date(12345678) //│ ║ ^^^^^^^^^^^^^^ //│ ╟── argument of type `(12345678,)` does not match type `()` -//│ ║ l.13: let date1 = new Date(12345678) +//│ ║ l.15: let date1 = new Date(12345678) //│ ╙── ^^^^^^^^^^ //│ let date1: Date | error -//│ error | string //│ date1 //│ = 1970-01-01T03:25:45.678Z + +date1.toLocaleString("en-US", { timeZone: "America/New_York" }) +//│ error | string //│ res -//│ = 'Thu Jan 01 1970 11:25:45 GMT+0800 (China Standard Time)' +//│ = '12/31/1969, 10:25:45 PM' + From 7d68faf0f5f86d0b9efa9ea5b1bf27464ef5232b Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Mon, 22 May 2023 16:58:31 +0800 Subject: [PATCH 315/498] refined frenshenAbove and refreshGen --- .../src/main/scala/mlscript/NuTypeDefs.scala | 126 ++++++++++-------- 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 63eb6f8221..fad222c28f 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -121,43 +121,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def tparams: TyParams def members: Map[Str, NuMember] val allFields: Set[Var] = members.valuesIterator.map(_.name |> Var).toSet - - override def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]): TypedNuTypeDef = withLevel { implicit ctx => - this match { - case m @ TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => - TypedNuMxn(td, - thisTV.freshenAbove(lim, rigidify), - superTV.freshenAbove(lim, rigidify), - tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), - params.mapValues(_.freshenAbove(lim, rigidify)), - members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - ttu.freshenAbove(lim, rigidify)) - case cls @ TypedNuCls(level, td, ttu, tparams, params, members, thisTy, tags, inheritedTags, pvms) => - TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), - tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), - params.mapValues(_.freshenAbove(lim, rigidify)), - members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - thisTy.freshenAbove(lim, rigidify), - tags.freshenAbove(lim, rigidify), - inheritedTags, - pvms.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap - )(cls.instanceType.freshenAbove(lim, rigidify)) - case cls @ TypedNuAls(level, td, tparams, body) => - TypedNuAls(level, td, - tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), - body.freshenAbove(lim, rigidify)) - case cls @ TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, tags, inheritedTags, pvms) => - TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), - tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), - members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - thisTy.freshenAbove(lim, rigidify), - sign.map(_.freshenAbove(lim, rigidify)), - tags.freshenAbove(lim, rigidify), - inheritedTags, - pvms.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap - ) - } - } val td: NuTypeDef val prov: TP = TypeProvenance(td.toLoc, td.describe, isType = true) val level: Level @@ -173,6 +136,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def name: Str = nme.name def nme: mlscript.TypeName = td.nme def members: Map[Str, NuMember] = Map.empty + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + : TypedNuAls = withLevel { implicit ctx => + TypedNuAls(level, td, + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), + body.freshenAbove(lim, rigidify)) + } def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl = @@ -215,6 +186,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) } ++ parentTP + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + : TypedNuTrt = withLevel { implicit ctx => + TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, + thisTy.freshenAbove(lim, rigidify), + sign.map(_.freshenAbove(lim, rigidify)), + selfTy.freshenAbove(lim, rigidify), + inheritedTags, + parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap + ) + } def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -309,6 +294,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def varianceOf(tv: TV)(implicit ctx: Ctx): VarianceInfo = variances.getOrElse(tv, VarianceInfo.in) + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + : TypedNuCls = withLevel { implicit ctx => + TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), + params.mapValues(_.freshenAbove(lim, rigidify)), + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, + thisTy.freshenAbove(lim, rigidify), + selfTy.freshenAbove(lim, rigidify), + inheritedTags, + parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap + )(this.instanceType.freshenAbove(lim, rigidify)) + } def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -346,6 +345,19 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name + + def freshenAbove(lim: Int, rigidify: Bool) + (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + : TypedNuMxn = withLevel { implicit ctx => + TypedNuMxn(td, + thisTV.freshenAbove(lim, rigidify), + superTV.freshenAbove(lim, rigidify), + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), + params.mapValues(_.freshenAbove(lim, rigidify)), + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, + ttu.freshenAbove(lim, rigidify) + ) + } def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = @@ -594,7 +606,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawMxn: TypedNuMxn => // println(s"Raw $rawMxn") - val mxn = rawMxn.freshen.asInstanceOf[TypedNuMxn] + val (fr, ptp) = refreshGen(rawMxn, v, parTargs) + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + val mxn = rawMxn.freshenAbove(info.level, rigidify = false) // println(s"Fresh $mxn") val newMembs = { @@ -626,15 +641,21 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - val (trt, ptp) = refreshGen[TypedNuTrt](info, v, parTargs) + + val (fr, ptp) = refreshGen(rawTrt, v, parTargs) + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + val trt = rawTrt.freshenAbove(info.level, rigidify = false) val paramMems = Nil // * Maybe support trait params? (not sure) S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) case rawCls: TypedNuCls => - - val (cls, ptp) = refreshGen[TypedNuCls](info, v, parTargs) - + val (fr, ptp) = refreshGen(rawCls, v, parTargs) + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + val cls = rawCls.freshenAbove(info.level, rigidify = false) + if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) @@ -814,15 +835,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) // refresh trait/class - def refreshGen[T <: PolyNuDecl](info: NuMember, v: Var, parTargs: Ls[Type]) : (T, Map[Str, NuParam]) = { - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - - val raw = info.asInstanceOf[T] + def refreshGen(raw: PolyNuDecl, v: Var, parTargs: Ls[Type]): (MutMap[TV, ST], Map[Str, NuParam]) = { + val freshened: MutMap[TV, ST] = MutMap.empty val rawName = v.name if (raw.tparams.sizeCompare(parTargs.size) =/= 0) - err(msg"${if (raw.isInstanceOf[TypedNuTrt]) "trait" else "class"} $rawName expects ${ + err(msg"${raw.kind.str} $rawName expects ${ raw.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) val parTP = raw.tparams.lazyZip(parTargs).map { case ((tn, _tv, vi), targTy) => @@ -844,16 +862,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tv }) freshened += _tv -> tv - tn -> tv + rawName+"#"+tn.name -> NuParam(tn, FieldType(S(tv), tv)(provTODO))(level) } - - println(s"collected ${parTP}") - - raw.freshenAbove(info.level, rigidify = false).asInstanceOf[T] -> - parTP.map { - case (nme, tv) => rawName+"#"+nme.name -> - NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - }.toMap + + freshened -> parTP.toMap } From 5761dad0dab5047201c60ad3b049c02aedebaf02 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Mon, 22 May 2023 17:15:13 +0800 Subject: [PATCH 316/498] fix refresh for mixins --- .../src/main/scala/mlscript/NuTypeDefs.scala | 20 ++++++++++--------- .../test/diff/nu/GenericClassInheritance.mls | 14 +++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index fad222c28f..981694fc24 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -606,7 +606,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawMxn: TypedNuMxn => // println(s"Raw $rawMxn") - val (fr, ptp) = refreshGen(rawMxn, v, parTargs) + val (fr, ptp) = refreshHelper(rawMxn, v, N) // type args inferred implicit val frenshened: MutMap[TV,ST] = fr implicit val shadows: Shadows = Shadows.empty val mxn = rawMxn.freshenAbove(info.level, rigidify = false) @@ -642,7 +642,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - val (fr, ptp) = refreshGen(rawTrt, v, parTargs) + val (fr, ptp) = refreshHelper(rawTrt, v, S(parTargs)) implicit val frenshened: MutMap[TV,ST] = fr implicit val shadows: Shadows = Shadows.empty val trt = rawTrt.freshenAbove(info.level, rigidify = false) @@ -651,7 +651,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) case rawCls: TypedNuCls => - val (fr, ptp) = refreshGen(rawCls, v, parTargs) + val (fr, ptp) = refreshHelper(rawCls, v, S(parTargs)) implicit val frenshened: MutMap[TV,ST] = fr implicit val shadows: Shadows = Shadows.empty val cls = rawCls.freshenAbove(info.level, rigidify = false) @@ -834,16 +834,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => private lazy val thisTV: TV = freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) - // refresh trait/class - def refreshGen(raw: PolyNuDecl, v: Var, parTargs: Ls[Type]): (MutMap[TV, ST], Map[Str, NuParam]) = { + // refresh trait/class/mixin + def refreshHelper(raw: PolyNuDecl, v: Var, parTargs: Opt[Ls[Type]]): (MutMap[TV, ST], Map[Str, NuParam]) = { val freshened: MutMap[TV, ST] = MutMap.empty val rawName = v.name - if (raw.tparams.sizeCompare(parTargs.size) =/= 0) - err(msg"${raw.kind.str} $rawName expects ${ - raw.tparams.size.toString} type parameter(s); got ${parTargs.size.toString}", Loc(v :: parTargs)) + parTargs foreach { pta => + if (raw.tparams.sizeCompare(pta.size) =/= 0) + err(msg"${raw.kind.str} $rawName expects ${ + raw.tparams.size.toString} type parameter(s); got ${pta.size.toString}", Loc(v :: pta)) + } - val parTP = raw.tparams.lazyZip(parTargs).map { case ((tn, _tv, vi), targTy) => + val parTP = raw.tparams.lazyZip(parTargs.getOrElse(Nil)).map { case ((tn, _tv, vi), targTy) => val targ = typeType(targTy) val tv = (targ match { case tv: TV => diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 0b001d2239..e8490f0502 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -43,3 +43,17 @@ class WrongRoom extends Room[bool]("wrong") { //│ class WrongRoom() { //│ fun foo: int -> int //│ } + +mixin Test[A] { + fun bar: (A, A) + fun bar = (this.a, this.a) +} +//│ mixin Test[A]() { +//│ this: {a: A} +//│ fun bar: (A, A,) +//│ } + +class A(a: int) extends Test +//│ class A(a: int) { +//│ fun bar: (int, int,) +//│ } From 7da889ca03874d8f8971fabcdbb7a833d4ad1903 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Mon, 22 May 2023 17:32:13 +0800 Subject: [PATCH 317/498] Update shared/src/main/scala/mlscript/NewParser.scala Co-authored-by: Lionel Parreaux --- shared/src/main/scala/mlscript/NewParser.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 1392ca1201..c645e2dc13 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -400,7 +400,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D val ctor = if (ctors.lengthIs > 1) { - err(msg"A class may only have one constructor" -> S(l0) :: Nil) + err(msg"A class may only have at most one explicit constructor" -> S(l0) :: Nil) N } else ctors.headOption From c71156a49157d0c577eb5c8efac45fe35e2015cd Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 22 May 2023 14:41:46 +0800 Subject: [PATCH 318/498] WIP Add test related to polymorphism level mismatches in inheritance + misc --- .../src/main/scala/mlscript/NuTypeDefs.scala | 12 --- shared/src/test/diff/nu/Andong.mls | 2 +- shared/src/test/diff/nu/ClassesInMixins.mls | 31 +++++-- .../test/diff/nu/GenericClassInheritance.mls | 28 ++---- shared/src/test/diff/nu/GenericMixins.mls | 86 ++++++++++++++++++- .../diff/nu/InheritanceLevelMismatches.mls | 41 +++++++++ shared/src/test/diff/nu/MixinParameters.mls | 3 +- 7 files changed, 155 insertions(+), 48 deletions(-) create mode 100644 shared/src/test/diff/nu/InheritanceLevelMismatches.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 981694fc24..b641eb679e 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -29,15 +29,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => protected def withLevel[R](k: Ctx => R)(implicit ctx: Ctx): R = k(ctx.copy(lvl = level + 1)) - /** Used in inheritance processing, for parent types. */ - def freshen(implicit ctx: Ctx): NuMember = { - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - withLevel { implicit ctx => - freshenAbove(level, rigidify = false) - } - } - def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuMember @@ -873,9 +864,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { if (isComputing) { - // val ty = err(msg"Unhandled cyclic definition", decl.toLoc) - // // * Hacky: return a dummy decl to avoid possible infinite completion recursions - // TypedNuFun(0, NuFunDef(N, decl.nameVar, Nil, R(Top))(N, N), ty) err(msg"Unhandled cyclic definition", decl.toLoc) TypedNuDummy(decl) } diff --git a/shared/src/test/diff/nu/Andong.mls b/shared/src/test/diff/nu/Andong.mls index ed6471fc81..6aaf3029eb 100644 --- a/shared/src/test/diff/nu/Andong.mls +++ b/shared/src/test/diff/nu/Andong.mls @@ -1,5 +1,4 @@ :NewDefs -:NoJS class Union(a: Region, b: Region) @@ -15,3 +14,4 @@ fun hmm(x) = if x is Union(z, y) then x //│ fun hmm: forall 'Region. Union['Region] -> Union['Region] + diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 5dd8012c96..62442a239f 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -1,5 +1,4 @@ :NewDefs -:NoJS // TODO @@ -20,41 +19,53 @@ module M extends Test M.f //│ Foo +//│ res +//│ = Foo {} M.f.n //│ int +//│ res +//│ = 123 :e M.Foo //│ ╔══[ERROR] access to class member not yet supported -//│ ║ l.28: M.Foo +//│ ║ l.31: M.Foo //│ ╙── ^^^^ //│ error +//│ res +//│ = [Function (anonymous)] { class: [class Foo] } :e // TODO support fun foo(x) = if x is M.Foo then 1 //│ ╔══[ERROR] illegal pattern -//│ ║ l.35: fun foo(x) = if x is M.Foo then 1 +//│ ║ l.40: fun foo(x) = if x is M.Foo then 1 //│ ╙── ^^^^^ //│ fun foo: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared :e mixin Test2 { let f = Foo(1) } //│ ╔══[ERROR] identifier not found: Foo -//│ ║ l.42: mixin Test2 { let f = Foo(1) } +//│ ║ l.49: mixin Test2 { let f = Foo(1) } //│ ╙── ^^^ //│ mixin Test2() { //│ let f: error //│ } +//│ Code generation encountered an error: +//│ unresolved symbol Foo :e mixin Test3 { fun f(x) = if x is Foo then 1 } //│ ╔══[ERROR] Cannot find constructor `Foo` in scope -//│ ║ l.51: mixin Test3 { fun f(x) = if x is Foo then 1 } +//│ ║ l.60: mixin Test3 { fun f(x) = if x is Foo then 1 } //│ ╙── ^^^ //│ mixin Test3() { //│ fun f: anything -> error //│ } +//│ Code generation encountered an error: +//│ if expression was not desugared @@ -68,14 +79,14 @@ mixin Test { Add(l, r) then this.size(l) + this.size(r) } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.64: class Add(lhs: A, rhs: A) { +//│ ║ l.75: class Add(lhs: A, rhs: A) { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.65: let cached = size(this) +//│ ║ l.76: let cached = size(this) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.66: } +//│ ║ l.77: } //│ ╙── ^^^ //│ ╔══[ERROR] Illegal pattern `Add` -//│ ║ l.68: Add(l, r) then this.size(l) + this.size(r) +//│ ║ l.79: Add(l, r) then this.size(l) + this.size(r) //│ ╙── ^^^ //│ mixin Test() { //│ class Add[A](lhs: A, rhs: A) { @@ -84,5 +95,7 @@ mixin Test { //│ class Lit(n: int) //│ fun size: anything -> error //│ } +//│ Code generation encountered an error: +//│ if expression was not desugared diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index e8490f0502..bc07b1e7c7 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -1,5 +1,4 @@ :NewDefs -:NoJS class Room[A](name: string) { fun foo(x: A) = x @@ -20,40 +19,27 @@ class WrongRoom extends Room[bool]("wrong") { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.20: fun foo(x) = x + 1 +//│ ║ l.19: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.19: class WrongRoom extends Room[bool]("wrong") { +//│ ║ l.18: class WrongRoom extends Room[bool]("wrong") { //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.20: fun foo(x) = x + 1 +//│ ║ l.19: fun foo(x) = x + 1 //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.20: fun foo(x) = x + 1 +//│ ║ l.19: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── operator application of type `int` is not an instance of type `bool` -//│ ║ l.20: fun foo(x) = x + 1 +//│ ║ l.19: fun foo(x) = x + 1 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.19: class WrongRoom extends Room[bool]("wrong") { +//│ ║ l.18: class WrongRoom extends Room[bool]("wrong") { //│ ║ ^^^^ //│ ╟── from reference: -//│ ║ l.5: fun foo(x: A) = x +//│ ║ l.4: fun foo(x: A) = x //│ ╙── ^ //│ class WrongRoom() { //│ fun foo: int -> int //│ } -mixin Test[A] { - fun bar: (A, A) - fun bar = (this.a, this.a) -} -//│ mixin Test[A]() { -//│ this: {a: A} -//│ fun bar: (A, A,) -//│ } - -class A(a: int) extends Test -//│ class A(a: int) { -//│ fun bar: (int, int,) -//│ } diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 73d9bc9e2e..bbe4fcaa6a 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -1,19 +1,99 @@ :NewDefs + // TODO support -mixin BaseTest { +mixin BaseTest[A] { fun test(x: A) = x } //│ ╔══[ERROR] type identifier not found: A -//│ ║ l.6: fun test(x: A) = x +//│ ║ l.7: fun test(x: A) = x //│ ╙── ^ //│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A28' -mixin BaseTest(x: A) { +mixin BaseTest[A](x: A) { fun test = x } //│ mixin BaseTest[A](x: A) { //│ fun test: A //│ } + + +mixin Test[A] { + fun foo: A -> A + fun foo = id + fun bar: (A -> A) -> (A -> A) + fun bar = id +} +//│ mixin Test[A]() { +//│ fun bar: (A -> A) -> A -> A +//│ fun foo: A -> A +//│ } + +class C extends Test { + fun baz1 = this.foo(0) + fun baz2 = this.bar(this.foo) +} +//│ class C() { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun baz1: 0 +//│ fun baz2: forall 'a. 'a -> 'a +//│ fun foo: forall 'a. 'a -> 'a +//│ } + + + +mixin Test[A] { + fun foo: A -> A + fun foo = id + fun bar: (A, A) + fun bar = (this.arg, this.arg) + fun baz = foo(this.arg) +} +//│ mixin Test[A]() { +//│ this: {arg: A & 'a} +//│ fun bar: (A, A,) +//│ fun baz: 'a +//│ fun foo: A -> A +//│ } + +class C(arg: int) extends Test +//│ class C(arg: int) { +//│ fun bar: (int, int,) +//│ fun baz: int +//│ fun foo: forall 'a. 'a -> 'a +//│ } + +:e // TODO support or produce better error (arg is not actually recursive) +class C extends Test { + fun arg = 123 +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.52: fun baz = foo(this.arg) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.51: fun bar = (this.arg, this.arg) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.51: fun bar = (this.arg, this.arg) +//│ ╙── ^^^^ +//│ class C() { +//│ fun arg: 123 +//│ fun bar: (error, error,) +//│ fun baz: error +//│ fun foo: forall 'a. 'a -> 'a +//│ } + +class C extends Test { + fun arg: int + fun arg = 123 +} +//│ class C() { +//│ fun arg: int +//│ fun bar: (int, int,) +//│ fun baz: int +//│ fun foo: forall 'a. 'a -> 'a +//│ } + + diff --git a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls new file mode 100644 index 0000000000..8f1db51149 --- /dev/null +++ b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls @@ -0,0 +1,41 @@ +:NewDefs + +:NoJS // TODO + + +trait T1 { fun x: 0 | 1 } +//│ trait T1() { +//│ fun x: 0 | 1 +//│ } + +// FIXME +module Foo { + trait T2 { fun x: 1 | 2 } + class C extends T1, T2 { fun x = 1 } +} +//│ ╔══[ERROR] member x has mismatch levels 1 and 2 +//│ ║ l.6: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ module Foo() { +//│ class C() { +//│ fun x: 1 +//│ } +//│ trait T2() { +//│ fun x: 1 | 2 +//│ } +//│ } + + +mixin Foo { fun f = this.x } +//│ mixin Foo() { +//│ this: {x: 'x} +//│ fun f: 'x +//│ } + +// FIXME +module Bar { + class C extends Foo +} +//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed + + diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index af9b11d424..78894b2a0a 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -1,5 +1,4 @@ :NewDefs -:NoJS mixin BaseTest(x: int) { @@ -14,7 +13,7 @@ mixin BaseTest(x) { fun test = x } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.13: mixin BaseTest(x) { +//│ ║ l.12: mixin BaseTest(x) { //│ ╙── ^ //│ mixin BaseTest(x: error) { //│ fun test: error From 76c422f5d99018d0ab26186ad6ca4b255038ca82 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Mon, 22 May 2023 18:09:47 +0800 Subject: [PATCH 319/498] WIP add test (ref to member in base class) --- .../src/test/diff/nu/MonoClassInheritance.mls | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 shared/src/test/diff/nu/MonoClassInheritance.mls diff --git a/shared/src/test/diff/nu/MonoClassInheritance.mls b/shared/src/test/diff/nu/MonoClassInheritance.mls new file mode 100644 index 0000000000..ef55988232 --- /dev/null +++ b/shared/src/test/diff/nu/MonoClassInheritance.mls @@ -0,0 +1,58 @@ +:NewDefs + +mixin Test[A] { + fun bar: (A, A) + fun bar = (this.a, this.a) +} +//│ mixin Test[A]() { +//│ this: {a: A} +//│ fun bar: (A, A,) +//│ } + +class A(a: int) extends Test +//│ class A(a: int) { +//│ fun bar: (int, int,) +//│ } + +class P(p: int) { + fun foo(x) = x + p +} +//│ class P(p: int) { +//│ fun foo: int -> int +//│ } + +// FIXME +class C1(a: int) extends P(a) { fun bar = this.foo(0) } +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.25: class C1(a: int) extends P(a) { fun bar = this.foo(0) } +//│ ╙── ^^^^ +//│ class C1(a: int) { +//│ fun bar: error +//│ fun foo: int -> int +//│ } + +// FIXME +class C2(a: int, b: int) extends P(a + b) { + fun foo(x) = x * this.p + a * b +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.36: fun foo(x) = x * this.p + a * b +//│ ╙── ^^ +//│ class C2(a: int, b: int) { +//│ fun foo: int -> int +//│ } + +let c2 = C2(1, 2) +//│ let c2: C2 +//│ c2 +//│ = C2 {} + +c2.foo(2) +//│ int +//│ res +//│ = 8 + +c2.p +//│ int +//│ res +//│ = 3 From be8fe0c92a7b58c502a809f199a14dd07effe365 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 22 May 2023 18:24:49 +0800 Subject: [PATCH 320/498] WIP Rename test and add one case --- ...ce.mls => InferredInheritanceTypeArgs.mls} | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) rename shared/src/test/diff/nu/{MonoClassInheritance.mls => InferredInheritanceTypeArgs.mls} (71%) diff --git a/shared/src/test/diff/nu/MonoClassInheritance.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls similarity index 71% rename from shared/src/test/diff/nu/MonoClassInheritance.mls rename to shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index ef55988232..cf0a8cab16 100644 --- a/shared/src/test/diff/nu/MonoClassInheritance.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -1,5 +1,6 @@ :NewDefs + mixin Test[A] { fun bar: (A, A) fun bar = (this.a, this.a) @@ -21,22 +22,22 @@ class P(p: int) { //│ fun foo: int -> int //│ } -// FIXME +:e // FIXME class C1(a: int) extends P(a) { fun bar = this.foo(0) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.25: class C1(a: int) extends P(a) { fun bar = this.foo(0) } +//│ ║ l.26: class C1(a: int) extends P(a) { fun bar = this.foo(0) } //│ ╙── ^^^^ //│ class C1(a: int) { //│ fun bar: error //│ fun foo: int -> int //│ } -// FIXME +:e // FIXME class C2(a: int, b: int) extends P(a + b) { fun foo(x) = x * this.p + a * b } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.36: fun foo(x) = x * this.p + a * b +//│ ║ l.37: fun foo(x) = x * this.p + a * b //│ ╙── ^^ //│ class C2(a: int, b: int) { //│ fun foo: int -> int @@ -56,3 +57,16 @@ c2.p //│ int //│ res //│ = 3 + + +class Test[A](x: A) +//│ class Test[A](x: A) + +:e // TODO support +class A(a: int) extends Test(a) +//│ ╔══[ERROR] class Test expects 1 type parameter(s); got 0 +//│ ║ l.65: class A(a: int) extends Test(a) +//│ ╙── ^^^^ +//│ class A(a: int) + + From 7cc87c08f4ebe6347d5c11caad23044ccd36695b Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Mon, 22 May 2023 18:40:19 +0800 Subject: [PATCH 321/498] WIP add ty arg inference for class and traits --- .../src/main/scala/mlscript/NuTypeDefs.scala | 4 +- .../test/diff/nu/GenericClassInheritance.mls | 50 ++++++++++++++--- .../diff/nu/InferredInheritanceTypeArgs.mls | 54 +++++++++++++++++-- shared/src/test/diff/nu/Interfaces.mls | 53 +++++++++--------- .../test/diff/nu/TrickyGenericInheritance.mls | 38 ++++++------- 5 files changed, 141 insertions(+), 58 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index b641eb679e..d8eec39f96 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -633,7 +633,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawTrt: TypedNuTrt => if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) - val (fr, ptp) = refreshHelper(rawTrt, v, S(parTargs)) + val (fr, ptp) = refreshHelper(rawTrt, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided implicit val frenshened: MutMap[TV,ST] = fr implicit val shadows: Shadows = Shadows.empty val trt = rawTrt.freshenAbove(info.level, rigidify = false) @@ -642,7 +642,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) case rawCls: TypedNuCls => - val (fr, ptp) = refreshHelper(rawCls, v, S(parTargs)) + val (fr, ptp) = refreshHelper(rawCls, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided implicit val frenshened: MutMap[TV,ST] = fr implicit val shadows: Shadows = Shadows.empty val cls = rawCls.freshenAbove(info.level, rigidify = false) diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index bc07b1e7c7..d69538f469 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -14,27 +14,65 @@ class BigRoom extends Room[bool]("big") //│ where //│ 'A := bool +// FIXME +class InferredRoom extends Room("infer") { + fun foo(x) = x && true +} +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.19: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.3: class Room[A](name: string) { +//│ ║ ^ +//│ ╟── into reference of type `bool` +//│ ║ l.19: fun foo(x) = x && true +//│ ╙── ^ +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.19: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.19: fun foo(x) = x && true +//│ ║ ^^^^^^^^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this operator application: +//│ ║ l.19: fun foo(x) = x && true +//│ ╙── ^^^^^^^^^ +//│ class InferredRoom() { +//│ fun foo: bool -> bool +//│ } + +:e +class TooManyRoom extends Room[int, string]("too many") +//│ ╔══[ERROR] class Room expects 1 type parameter(s); got 2 +//│ ║ l.45: class TooManyRoom extends Room[int, string]("too many") +//│ ╙── ^^^^^^^^^^^^^^^^ +//│ class TooManyRoom() { +//│ fun foo: (x: 'A,) -> 'A +//│ } +//│ where +//│ 'A := int + :e class WrongRoom extends Room[bool]("wrong") { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.19: fun foo(x) = x + 1 +//│ ║ l.57: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.18: class WrongRoom extends Room[bool]("wrong") { +//│ ║ l.56: class WrongRoom extends Room[bool]("wrong") { //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.19: fun foo(x) = x + 1 +//│ ║ l.57: fun foo(x) = x + 1 //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.19: fun foo(x) = x + 1 +//│ ║ l.57: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── operator application of type `int` is not an instance of type `bool` -//│ ║ l.19: fun foo(x) = x + 1 +//│ ║ l.57: fun foo(x) = x + 1 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.18: class WrongRoom extends Room[bool]("wrong") { +//│ ║ l.56: class WrongRoom extends Room[bool]("wrong") { //│ ║ ^^^^ //│ ╟── from reference: //│ ║ l.4: fun foo(x: A) = x diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index cf0a8cab16..36c6c9b413 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -62,11 +62,57 @@ c2.p class Test[A](x: A) //│ class Test[A](x: A) -:e // TODO support class A(a: int) extends Test(a) -//│ ╔══[ERROR] class Test expects 1 type parameter(s); got 0 -//│ ║ l.65: class A(a: int) extends Test(a) -//│ ╙── ^^^^ //│ class A(a: int) +let a1 = A(1) +//│ let a1: A +//│ a1 +//│ = A {} +a1: Test['x] +//│ Test['x] +//│ where +//│ 'x :> int +//│ res +//│ = A {} + +a1.x +//│ int +//│ res +//│ = 1 + +:NoJS +trait Foo[A] { + fun foo[A](x: A): A +} +//│ trait Foo[A]() { +//│ fun foo: forall 'A. (x: 'A,) -> 'A +//│ } + +// FIXME +class B extends Foo { + fun foo(x) = x + 1 +} +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.95: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.87: fun foo[A](x: A): A +//│ ║ ^ +//│ ╟── into reference of type `int` +//│ ║ l.95: fun foo(x) = x + 1 +//│ ╙── ^ +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.95: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.95: fun foo(x) = x + 1 +//│ ║ ^^^^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this operator application: +//│ ║ l.95: fun foo(x) = x + 1 +//│ ╙── ^^^^^ +//│ class B() { +//│ fun foo: int -> int +//│ } diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index fe02646a78..e45f057de3 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -811,50 +811,53 @@ let cp1 = CP() fb(cp1, 2) //│ (int, int,) -:e -trait BErr1 extends Base -//│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 0 -//│ ║ l.815: trait BErr1 extends Base -//│ ╙── ^^^^ -//│ trait BErr1() { +trait BInfer1 extends Base +//│ trait BInfer1() { //│ fun f: 'A -> 'A //│ } +trait BInfer2 extends Base { + fun f: int -> int +} +//│ trait BInfer2() { +//│ fun f: int -> int +//│ } + :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.824: class DerBad1 extends Base[int, int] +//│ ║ l.827: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.824: class DerBad1 extends Base[int, int] +//│ ║ l.827: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.834: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -921,11 +924,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.922: class Fischl(age: bool) extends Oz +//│ ║ l.925: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.915: let age: int +//│ ║ l.918: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -944,20 +947,20 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.944: fun foo(x) = x && true +//│ ║ l.947: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.944: fun foo(x) = x && true +//│ ║ l.947: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.944: fun foo(x) = x && true +//│ ║ l.947: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.944: fun foo(x) = x && true +//│ ║ l.947: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.936: fun foo(x) = x + 1 +//│ ║ l.939: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go() { //│ fun foo: bool -> bool @@ -974,11 +977,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.975: class Ohhh(x: bool) extends Ha +//│ ║ l.978: class Ohhh(x: bool) extends Ha //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.966: class Ha { let x: int = 1 } +//│ ║ l.969: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index 9594134d66..a27b35fe4d 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -10,13 +10,9 @@ trait T1[A] { //│ fun f: A -> A //│ } -:e class C1 extends T1 { fun f(x: int) = x } -//│ ╔══[ERROR] trait T1 expects 1 type parameter(s); got 0 -//│ ║ l.14: class C1 extends T1 { -//│ ╙── ^^ //│ class C1() { //│ fun f: (x: int,) -> int //│ } @@ -73,22 +69,22 @@ class C2 extends T2['FigureItOut] { fun f(x: int) = x } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.68: trait T2[A] { +//│ ║ l.64: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.69: fun f: A -> A +//│ ║ l.65: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.70: val r = C2().f(false) +//│ ║ l.66: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.71: } +//│ ║ l.67: } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.70: val r = C2().f(false) +//│ ║ l.66: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.70: val r = C2().f(false) +//│ ║ l.66: val r = C2().f(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.73: fun f(x: int) = x +//│ ║ l.69: fun f(x: int) = x //│ ╙── ^^^ //│ trait T2[A]() { //│ fun f: A -> A @@ -107,17 +103,17 @@ class C2 extends T2['FigureItOut] { fun f(x: int) = x } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.102: trait T2[A] { -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.103: fun f: A -> A -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.104: val r = (C2() : T2['X]).f(false) +//│ ║ l.98: trait T2[A] { +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.99: fun f: A -> A +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.100: val r = (C2() : T2['X]).f(false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.105: } +//│ ║ l.101: } //│ ╙── ^ //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.102: trait T2[A] { -//│ ╙── ^ +//│ ║ l.98: trait T2[A] { +//│ ╙── ^ //│ trait T2[A]() { //│ fun f: A -> A //│ let r: error | false @@ -129,8 +125,8 @@ class C2 extends T2['FigureItOut] { :e // FIXME C2() : T2['X] //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.102: trait T2[A] { -//│ ╙── ^ +//│ ║ l.98: trait T2[A] { +//│ ╙── ^ //│ T2['X] //│ where //│ 'X :> error From 7405870ab975c271212796c4ac7e14ad8d7ab740 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 22 May 2023 18:56:32 +0800 Subject: [PATCH 322/498] Make params optional --- .../src/main/scala/mlscript/JSBackend.scala | 34 +++++++++---------- .../src/main/scala/mlscript/NewParser.scala | 2 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 10 +++--- shared/src/main/scala/mlscript/Typer.scala | 12 +++---- .../main/scala/mlscript/codegen/Helpers.scala | 4 +-- .../main/scala/mlscript/codegen/Symbol.scala | 8 ++--- shared/src/main/scala/mlscript/helpers.scala | 28 ++++++++------- shared/src/main/scala/mlscript/syntax.scala | 7 ++-- 8 files changed, 53 insertions(+), 52 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 53de52a6bf..a7b62e13b7 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -111,7 +111,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ident = JSIdent(sym.runtimeName) if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident case S(sym: NuTypeSymbol with RuntimeSymbol) => - if (sym.isPlain || !isCallee) translateNuTypeSymbol(sym) + if (sym.isPlainJSClass || !isCallee) translateNuTypeSymbol(sym) else translateNuTypeSymbol(sym).member("class") case S(sym: NewClassMemberSymbol) => if (sym.isByvalueRec.getOrElse(false) && !sym.isLam) throw CodeGenError(s"unguarded recursive use of by-value binding $name") @@ -333,14 +333,14 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { JSBinary("===", scrut.member("constructor"), JSLit("String")) case Var(name) => scope.resolveValue(name) match { case S(sym: NewClassSymbol) => - if (sym.isPlain) + if (sym.isPlainJSClass) JSInstanceOf(scrut, translateVar(sym.lexicalName, false)) else JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) case S(sym: ModuleSymbol) => JSInstanceOf(scrut, translateVar(sym.lexicalName, false).member("class")) case S(sym @ CapturedSymbol(out, cls: NewClassSymbol)) => - if (cls.isPlain) + if (cls.isPlainJSClass) JSInstanceOf(scrut, translateCapture(sym)) else JSInstanceOf(scrut, translateCapture(sym).member("class")) @@ -524,7 +524,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ctorMth = localScope.declareValue("ctor", Some(false), false).runtimeName val (constructor, params) = translateNewClassParameters(nd) val initList = - if (sym.isPlain) + if (sym.isPlainJSClass) Ls(JSReturnStmt(S(JSIdent(sym.lexicalName)))) else Ls( @@ -599,14 +599,14 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case Some(CapturedSymbol(out, sym: MixinSymbol)) => JSInvoke(translateCapture(CapturedSymbol(out, sym)), Ls(base)) case Some(CapturedSymbol(out, sym: NuTypeSymbol)) if !mixinOnly => - if (sym.isPlain) + if (sym.isPlainJSClass) translateCapture(CapturedSymbol(out, sym)) else translateCapture(CapturedSymbol(out, sym)).member("class") case Some(sym: MixinSymbol) => JSInvoke(translateVar(name, false), Ls(base)) case Some(sym: NuTypeSymbol) if !mixinOnly => - if (sym.isPlain) + if (sym.isPlainJSClass) translateVar(name, false) else translateVar(name, false).member("class") @@ -678,7 +678,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val privateIdent = JSIdent(s"this.#${classSymbol.lexicalName}") val outerStmt = JSConstDecl(outerSymbol.runtimeName, JSIdent("this")) val initList = - if (classSymbol.isPlain) + if (classSymbol.isPlainJSClass) Ls(JSExprStmt(JSAssignExpr(privateIdent, JSIdent(classSymbol.lexicalName)))) else Ls( @@ -953,20 +953,20 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } typeDefs.foreach { - case td @ NuTypeDef(Mxn, TypeName(mxName), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { - val (body, members, stmts, nested) = prepare(mxName, fs, pars, unit) + case td @ NuTypeDef(Mxn, TypeName(mxName), tps, tup, ctor, sig, pars, sup, ths, unit) => { + val (body, members, stmts, nested) = prepare(mxName, tup.getOrElse(Tup(Nil)).fields, pars, unit) val sym = MixinSymbol(mxName, tps map { _._2.name }, body, members, stmts, nested, isNested).tap(scope.register) if (!td.isDecl) mixins += sym } - case td @ NuTypeDef(Nms, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { - val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) + case td @ NuTypeDef(Nms, TypeName(nme), tps, tup, ctor, sig, pars, sup, ths, unit) => { + val (body, members, stmts, nested) = prepare(nme, tup.getOrElse(Tup(Nil)).fields, pars, unit) val sym = ModuleSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) if (!td.isDecl) modules += sym } - case td @ NuTypeDef(Als, TypeName(nme), tps, _, ctor, plain, sig, pars, _, _, _) => { + case td @ NuTypeDef(Als, TypeName(nme), tps, _, ctor, sig, pars, _, _, _) => { scope.declareTypeAlias(nme, tps map { _._2.name }, sig.getOrElse(Top)) } - case td @ NuTypeDef(Cls, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Cls, TypeName(nme), tps, tup, ctor, sig, pars, sup, ths, unit) => { val (params, preStmts) = ctor match { case S(Constructor(Tup(ls), Blk(stmts))) => (S(ls.map { case (S(Var(nme)), _) => nme @@ -974,13 +974,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { }), stmts) case _ => (N, Nil) } - val (body, members, stmts, nested) = prepare(nme, fs, pars, unit) + val (body, members, stmts, nested) = prepare(nme, tup.getOrElse(Tup(Nil)).fields, pars, unit) val sym = - NewClassSymbol(nme, tps map { _._2.name }, params, body, members, preStmts ++ stmts, pars, nested, isNested, plain).tap(scope.register) + NewClassSymbol(nme, tps map { _._2.name }, params, body, members, preStmts ++ stmts, pars, nested, isNested, td.isPlainJSClass).tap(scope.register) if (!td.isDecl) classes += sym } - case td @ NuTypeDef(Trt, TypeName(nme), tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => { - val (body, members, _, _) = prepare(nme, fs, pars, unit) + case td @ NuTypeDef(Trt, TypeName(nme), tps, tup, ctor, sig, pars, sup, ths, unit) => { + val (body, members, _, _) = prepare(nme, tup.getOrElse(Tup(Nil)).fields, pars, unit) val sym = scope.declareTrait(nme, tps map { _._2.name }, body, members) if (!td.isDecl) traits += sym } diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 1392ca1201..cc583edcee 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -406,7 +406,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D else ctors.headOption val res = - NuTypeDef(kind, tn, tparams, params.getOrElse(Tup(Nil)), ctor, params.isEmpty, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs) + NuTypeDef(kind, tn, tparams, params, ctor, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs) R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "val" | "let")), l0) :: c) => // TODO support rec? diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 95ce6c8f33..00ec58fd5e 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -456,7 +456,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => lazy val typedParams: Ls[Var -> FieldType] = ctx.nest.nextLevel { implicit ctx => decl match { case td: NuTypeDef => - td.params.fields.map { + td.params.getOrElse(Tup(Nil)).fields.map { case (S(nme), Fld(mut, spec, value)) => assert(!mut && !spec, "TODO") // TODO value.toType match { @@ -517,7 +517,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => lazy val allFields: Set[Var] = decl match { case td: NuTypeDef => // TODO also get fields from parents! - (td.params.fields.iterator.flatMap(_._1) ++ td.body.entities.iterator.collect { + (td.params.getOrElse(Tup(Nil)).fields.iterator.flatMap(_._1) ++ td.body.entities.iterator.collect { case fd: NuFunDef => fd.nme }).toSet case _: NuFunDef => Set.empty @@ -616,8 +616,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Als => - if (td.params.fields.nonEmpty) - err(msg"type alias definitions cannot have value parameters" -> td.params.toLoc :: Nil) + if (td.params.getOrElse(Tup(Nil)).fields.nonEmpty) + err(msg"type alias definitions cannot have value parameters" -> td.params.getOrElse(Tup(Nil)).toLoc :: Nil) if (td.parents.nonEmpty) err(msg"type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) @@ -742,7 +742,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )(provTODO) inherit(ps, newSuperType, members ++ newMembs) case Nil => - val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params, isType = true)))(provTODO) & + val thisType = WithType(superType, RecordType(typedParams)(ttp(td.params.getOrElse(Tup(Nil)), isType = true)))(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 7717c9faf9..55bfd4517d 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -357,9 +357,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case CompletedTypeInfo(mem: TypedNuTypeDef) => S(mem.td.kind, mem.tparams.size) case ti: DelayedTypeInfo => ti.decl match { - case NuTypeDef(k @ (Cls | Nms | Als), _, tps, _, _, _, _, _, _, _, _) => + case NuTypeDef(k @ (Cls | Nms | Als), _, tps, _, _, _, _, _, _, _) => S(k, tps.size) - case NuTypeDef(k @ (Mxn | Trt), nme, tps, _, _, _, _, _, _, _, _) => + case NuTypeDef(k @ (Mxn | Trt), nme, tps, _, _, _, _, _, _, _) => err(msg"${k.str} ${nme.name} cannot be used as a type", loc) S(k, tps.size) case fd: NuFunDef => @@ -1311,15 +1311,14 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => - NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), N, td.isPlain, S(go(body)), Nil, N, N, TypingUnit(Nil))( + NuTypeDef(td.kind, td.nme, td.tparams, S(Tup(Nil)), N, S(go(body)), Nil, N, N, TypingUnit(Nil))( td.declareLoc, td.abstractLoc) } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, - Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + S(Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub)))))), N,//TODO - td.isPlain, N, Nil,//TODO Option.when(!(TopType <:< superTy))(go(superTy)), @@ -1329,9 +1328,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, - Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), + S(Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub)))))), td.ctor, - td.isPlain, N,//TODO Nil,//TODO N,//TODO diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 848d74d69d..44e657c316 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -85,9 +85,9 @@ object Helpers { s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, ${inspect(term)})" case NuFunDef(lt, nme, targs, R(ty)) => s"NuFunDef(${lt}, ${nme.name}, ${targs.mkString("[", ", ", "]")}, $ty)" - case NuTypeDef(kind, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => s"NuTypeDef(${kind.str}, ${nme.name}, ${tparams.mkString("(", ", ", ")")}, ${ - inspect(params)}, ${parents.map(inspect).mkString("(", ", ", ")")}, $sup, $ths, ${inspect(body)})" + inspect(params.getOrElse(Tup(Nil)))}, ${parents.map(inspect).mkString("(", ", ", ")")}, $sup, $ths, ${inspect(body)})" case others => others.toString() } .mkString("TypingUnit(", ", ", ")") diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index f5646356a2..d85c267b2e 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -33,7 +33,7 @@ sealed trait NuTypeSymbol { val ctor: Ls[Statement] // statements in the constructor val nested: Ls[NuTypeDef] // nested class/mixin/module val superParameters: Ls[Term] // parameters that need to be passed to the `super()` - val isPlain: Bool // is this a plain class in JS + val isPlainJSClass: Bool // is this a plain class in JS val ctorParams: Opt[Ls[Str]] // parameters in the constructor } @@ -122,7 +122,7 @@ final case class NewClassSymbol( superParameters: Ls[Term], nested: Ls[NuTypeDef], isNested: Bool, - isPlain: Bool + isPlainJSClass: Bool ) extends TypeSymbol with RuntimeSymbol with NuTypeSymbol { override def toString: Str = s"new class $lexicalName" @@ -149,7 +149,7 @@ final case class MixinSymbol( // Mixins should pass `...rest` to the `super()` // But the variable name is not sure when we create the symbol object override val superParameters: Ls[Term] = Nil - val isPlain: Bool = false + val isPlainJSClass: Bool = false val ctorParams: Opt[Ls[Str]] = N } @@ -168,7 +168,7 @@ final case class ModuleSymbol( // Modules should have fixed names determined by users override def runtimeName: Str = lexicalName - val isPlain: Bool = false + val isPlainJSClass: Bool = false val ctorParams: Opt[Ls[Str]] = N } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 66db949ccc..6c9770adf8 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -136,13 +136,13 @@ trait TypeLikeImpl extends Located { self: TypeLike => // })).mkString("\n") // })).mkString("", "\n", "\n") })).mkString - case NuTypeDef(kind @ Als, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => + case NuTypeDef(kind @ Als, nme, tparams, params, ctor, sig, parents, sup, ths, body) => s"type ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")} = ${ sig.getOrElse(die).showIn(ctx, 0)}" - case NuTypeDef(kind, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => val bodyCtx = ctx.indent s"${kind.str} ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}(${ - params.fields.map { + params.getOrElse(Tup(Nil)).fields.map { case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) case (N, _) => "???" case (S(nme), rhs) => nme.name @@ -177,9 +177,9 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Constrained(b, bs, ws) => b :: bs.flatMap(c => c._1 :: c._2 :: Nil) ::: ws.flatMap(c => c.lb :: c.ub :: Nil) case Signature(xs, res) => xs ::: res.toList case NuFunDef(isLetRec, nme, targs, rhs) => targs ::: rhs.toOption.toList - case NuTypeDef(kind, nme, tparams, params, ctor, plain, sig, parents, sup, ths, body) => + case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => // TODO improve this mess - tparams.map(_._2) ::: params.fields.collect { + tparams.map(_._2) ::: params.getOrElse(Tup(Nil)).fields.collect { case (_, Fld(_, _, Asc(_, ty))) => ty } ::: sig.toList ::: sup.toList ::: ths.toList ::: Signature(body.entities.collect { case d: NuDecl => d @@ -414,10 +414,10 @@ trait NuDeclImpl extends Located { self: NuDecl => case NuFunDef(N, n, _, b) => s"fun $n" case NuFunDef(S(false), n, _, b) => s"let $n" case NuFunDef(S(true), n, _, b) => s"let rec $n" - case NuTypeDef(k, n, tps, sps, ctor, plain, sig, parents, sup, ths, bod) => + case NuTypeDef(k, n, tps, sps, ctor, sig, parents, sup, ths, bod) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}(${ // sps.mkString("(",",",")") - sps})${sig.fold("")(": " + _.showDbg2)}${ + sps.getOrElse(Tup(Nil))})${sig.fold("")(": " + _.showDbg2)}${ if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" } } @@ -733,17 +733,19 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Nms, nme, tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => + case NuTypeDef(Nms, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => ??? // TODO - case NuTypeDef(k @ Als, nme, tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => + case NuTypeDef(k @ Als, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => // TODO properly check: - require(fs.isEmpty, fs) + require(tup.getOrElse(Tup(Nil)).fields.isEmpty, tup) require(pars.size === 0, pars) require(sig.isDefined) require(ths.isEmpty, ths) require(unit.entities.isEmpty, unit) Nil -> (TypeDef(k, nme, tps.map(_._2), sig.get, Nil, Nil, Nil) :: Nil) - case NuTypeDef(k @ (Cls | Trt), nme, tps, tup @ Tup(fs), ctor, plain, sig, pars, sup, ths, unit) => + case NuTypeDef(k @ (Cls | Trt), nme, tps, opt, ctor, sig, pars, sup, ths, unit) => + val tup = opt.getOrElse(Tup(Nil)) + val fs = tup.fields val diags = Buffer.empty[Diagnostic] def tt(trm: Term): Type = trm.toType match { case L(ds) => diags += ds; Top @@ -879,8 +881,8 @@ trait StatementImpl extends Located { self: Statement => case Super() => Nil case Constructor(params, body) => params :: body :: Nil case Ass(lhs, rhs) => lhs :: rhs :: Nil - case NuTypeDef(k, nme, tps, ps, ctor, plain, sig, pars, sup, ths, bod) => - nme :: tps.map(_._2) ::: ps :: pars ::: ths.toList ::: bod :: Nil + case NuTypeDef(k, nme, tps, ps, ctor, sig, pars, sup, ths, bod) => + nme :: tps.map(_._2) ::: ps.getOrElse(Tup(Nil)) :: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 553d611344..5ed427c1f5 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -182,16 +182,17 @@ final case class NuTypeDef( kind: TypeDefKind, nme: TypeName, tparams: Ls[(Opt[VarianceInfo], TypeName)], - params: Tup, // the specialized parameters for that type + params: Opt[Tup], // the specialized parameters for that type ctor: Opt[Constructor], - isPlain: Bool, sig: Opt[Type], parents: Ls[Term], superAnnot: Opt[Type], thisAnnot: Opt[Type], body: TypingUnit )(val declareLoc: Opt[Loc], val abstractLoc: Opt[Loc]) - extends NuDecl with Statement + extends NuDecl with Statement { + def isPlainJSClass: Bool = params.isEmpty + } final case class NuFunDef( isLetRec: Opt[Bool], // None means it's a `fun`, which is always recursive; Some means it's a `let` From f5ff36cdc909cb864e3fc4e64a87611ba0ea829e Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 22 May 2023 18:58:38 +0800 Subject: [PATCH 323/498] Rerun test --- shared/src/test/diff/codegen/OptionalParam.mls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 2782e2de76..7832bdad24 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -140,7 +140,7 @@ class E { constructor(x: int) constructor(y: int) } -//│ ╔══[PARSE ERROR] A class may only have one constructor +//│ ╔══[PARSE ERROR] A class may only have at most one explicit constructor //│ ║ l.139: class E { //│ ╙── ^^^^^ //│ class E() From 17d05de981fed32186bda502eac46d44717569a9 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Mon, 22 May 2023 22:46:13 +0800 Subject: [PATCH 324/498] Describe `FIXME` without actual errors --- shared/src/test/diff/ucs/Hygiene.mls | 11 ++++++++++- shared/src/test/diff/ucs/HygienicBindings.mls | 6 +++--- shared/src/test/diff/ucs/Wildcard.mls | 4 +--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/shared/src/test/diff/ucs/Hygiene.mls b/shared/src/test/diff/ucs/Hygiene.mls index 554635f1be..9dbe128a34 100644 --- a/shared/src/test/diff/ucs/Hygiene.mls +++ b/shared/src/test/diff/ucs/Hygiene.mls @@ -7,9 +7,18 @@ class Right[T](value: T) //│ class Left[T](value: T) //│ class Right[T](value: T) -// FIXME unhygienic +// FIXME unhygienic, the `x` in the second branch shadows parameter `x` fun foo(x) = if x is Some(Left(y)) then x Some(x) then x //│ fun foo: forall 'value. Some['value & (Left[anything] | ~#Left)] -> 'value +foo(Some(Left(1))) +//│ Left[1] +//│ res +//│ = Left {} + +foo(Some(2)) +//│ 2 +//│ res +//│ = 2 diff --git a/shared/src/test/diff/ucs/HygienicBindings.mls b/shared/src/test/diff/ucs/HygienicBindings.mls index 6684e39d20..2471ff86a9 100644 --- a/shared/src/test/diff/ucs/HygienicBindings.mls +++ b/shared/src/test/diff/ucs/HygienicBindings.mls @@ -37,7 +37,7 @@ fun h1(a) = a is None then 0 //│ fun h1: forall 'leftValue. (None | Some[Right['leftValue]]) -> (0 | 'leftValue) -// FIXME: This is the desugared version of the test case above. +// This is the desugared version of the test case above. fun h1'(a) = if a is Some then @@ -124,7 +124,7 @@ fun h2(a) = //│ Code generation encountered an error: //│ unresolved symbol y -// FIXME +// FIXME: Some results are wrong. fun h3(x, y, f, p) = if x is _ and f(x) is y and p(x) then y @@ -142,7 +142,7 @@ h3("anything", "anything", _ => "not me", _ => false) //│ res //│ = 'should be me' -// FIXME +// FIXME: Some results are wrong. fun h4(x, y, p) = if x is y and p(x) then y diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index 15cc780cab..470632a4c7 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -109,8 +109,6 @@ fun w3_1(x, f) = //│ ╙── ^ //│ fun w3_1: forall 'a. ('a, 'a -> anything,) -> 0 -// FIXME -// Accidentally found some code generator errors. w3_1(0, _ => true) w3_1(0, _ => false) //│ 0 @@ -123,7 +121,7 @@ w3_1(0, _ => false) fun w3_1_1(x, f) = if f(x) is a then a else 0 //│ ╔══[WARNING] Found a redundant else branch -//│ ║ l.124: if f(x) is a then a else 0 +//│ ║ l.122: if f(x) is a then a else 0 //│ ╙── ^ //│ fun w3_1_1: forall 'a 'b. ('a, 'a -> 'b,) -> 'b From 3e77b1ccf50e745b923c8e1df5af0a02c9a281a8 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 24 May 2023 17:25:17 +0800 Subject: [PATCH 325/498] WIP add type arg support for mixins (inference broken) --- .../scala/mlscript/ConstraintSolver.scala | 1 + .../src/main/scala/mlscript/NuTypeDefs.scala | 13 ++++---- .../main/scala/mlscript/TyperHelpers.scala | 7 +++++ .../test/diff/nu/GenericClassInheritance.mls | 31 +++++++++++++++++++ shared/src/test/diff/nu/GenericMixins.mls | 13 ++++---- 5 files changed, 52 insertions(+), 13 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index f8369a5f74..e9810f7874 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -93,6 +93,7 @@ class ConstraintSolver extends NormalForms { self: Typer => info.complete() match { case cls: TypedNuCls => handle(cls.virtualMembers) case trt: TypedNuTrt => handle(trt.virtualMembers) + case mxn: TypedNuMxn => handle(mxn.virtualMembers) case _ => ??? // TODO } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index d8eec39f96..2c24a043ea 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -337,6 +337,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name + lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } + def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) : TypedNuMxn = withLevel { implicit ctx => @@ -597,15 +602,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawMxn: TypedNuMxn => // println(s"Raw $rawMxn") - val (fr, ptp) = refreshHelper(rawMxn, v, N) // type args inferred + val (fr, ptp) = refreshHelper(rawMxn, v, if (parTargs.isEmpty) N else S(parTargs)) // type args inferred implicit val frenshened: MutMap[TV,ST] = fr implicit val shadows: Shadows = Shadows.empty val mxn = rawMxn.freshenAbove(info.level, rigidify = false) // println(s"Fresh $mxn") - val newMembs = { - if (parTargs.nonEmpty) err(msg"mixin type arguments not yet supported", p.toLoc) - + val newMembs = { if (parArgs.sizeCompare(mxn.params) =/= 0) err(msg"mixin $parNme expects ${ mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) @@ -1164,8 +1167,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) - implicit val vars: Map[Str, SimpleType] = - outerVars ++ Map.empty // TODO type params val thisTV = freshVar(provTODO, N, S("this")) val superTV = freshVar(provTODO, N, S("super")) ctx += "this" -> VarSymbol(thisTV, Var("this")) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index fdd2ba55cb..38f0e14e18 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -781,6 +781,7 @@ abstract class TyperHelpers { Typer: Typer => case tf: TypedNuFun => PolMap.pos -> tf.bodyType :: Nil case mxn: TypedNuMxn => + mxn.tparams.iterator.map(pol.invar -> _._2) ++ mxn.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> mxn.superTV) ++ S(pol.contravar -> mxn.thisTV) @@ -878,6 +879,7 @@ abstract class TyperHelpers { Typer: Typer => case als: TypedNuAls => als.tparams.iterator.map(_._2) ++ S(als.body) case mxn: TypedNuMxn => + mxn.tparams.iterator.map(_._2) ++ mxn.members.valuesIterator.flatMap(childrenMem) ++ S(mxn.superTV) ++ S(mxn.thisTV) @@ -888,6 +890,11 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.instanceType) + case cls: TypedNuTrt => + cls.tparams.iterator.map(_._2) ++ + // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) + cls.members.valuesIterator.flatMap(childrenMem) ++ + S(cls.thisTy) case TypedNuDummy(d) => Nil } ents ::: tu.result.toList diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index d69538f469..f556cd67b9 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -81,3 +81,34 @@ class WrongRoom extends Room[bool]("wrong") { //│ fun foo: int -> int //│ } +// :d +mixin M1[A] { + fun f1(x: A): A = x + fun f2(x: A): (A, A) = (x, x) +} +//│ mixin M1[A]() { +//│ fun f1: (x: A,) -> A +//│ fun f2: (x: A,) -> (A, A,) +//│ } + +// FIXME +class A1 extends M1 { + fun f1(x: int) = x +} +//│ class A1() { +//│ fun f1: (x: int,) -> int +//│ fun f2: (x: 'A,) -> ('A, 'A,) +//│ } + +class A2[S, T] extends M1[(S, T)] +//│ class A2[S, T]() { +//│ fun f1: (x: (S, T,),) -> (S, T,) +//│ fun f2: (x: (S, T,),) -> ((S, T,), (S, T,),) +//│ } + +// FIXME +class A3(f1: bool => bool) extends M1 +//│ class A3(f1: bool -> bool) { +//│ fun f1: (x: 'A,) -> 'A +//│ fun f2: (x: 'A,) -> ('A, 'A,) +//│ } diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index bbe4fcaa6a..960a46ea42 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -6,10 +6,9 @@ mixin BaseTest[A] { fun test(x: A) = x } -//│ ╔══[ERROR] type identifier not found: A -//│ ║ l.7: fun test(x: A) = x -//│ ╙── ^ -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: key not found: A28' +//│ mixin BaseTest[A]() { +//│ fun test: (x: A,) -> A +//│ } mixin BaseTest[A](x: A) { fun test = x @@ -70,13 +69,13 @@ class C extends Test { fun arg = 123 } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.52: fun baz = foo(this.arg) +//│ ║ l.51: fun baz = foo(this.arg) //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.51: fun bar = (this.arg, this.arg) +//│ ║ l.50: fun bar = (this.arg, this.arg) //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.51: fun bar = (this.arg, this.arg) +//│ ║ l.50: fun bar = (this.arg, this.arg) //│ ╙── ^^^^ //│ class C() { //│ fun arg: 123 From 725e8dbaf275acc4fbc1ea936307c8e826852823 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Wed, 24 May 2023 17:50:51 +0800 Subject: [PATCH 326/498] WIP added tests --- .../test/diff/nu/GenericClassInheritance.mls | 37 +++++++++++- .../diff/nu/InferredInheritanceTypeArgs.mls | 60 ++++++++++++++----- 2 files changed, 80 insertions(+), 17 deletions(-) diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index f556cd67b9..df9b7bffc9 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -81,7 +81,6 @@ class WrongRoom extends Room[bool]("wrong") { //│ fun foo: int -> int //│ } -// :d mixin M1[A] { fun f1(x: A): A = x fun f2(x: A): (A, A) = (x, x) @@ -91,7 +90,6 @@ mixin M1[A] { //│ fun f2: (x: A,) -> (A, A,) //│ } -// FIXME class A1 extends M1 { fun f1(x: int) = x } @@ -106,9 +104,42 @@ class A2[S, T] extends M1[(S, T)] //│ fun f2: (x: (S, T,),) -> ((S, T,), (S, T,),) //│ } -// FIXME class A3(f1: bool => bool) extends M1 //│ class A3(f1: bool -> bool) { //│ fun f1: (x: 'A,) -> 'A //│ fun f2: (x: 'A,) -> ('A, 'A,) //│ } + +mixin M2[A] { + fun m: A = this.a +} +//│ mixin M2[A]() { +//│ this: {a: A} +//│ fun m: A +//│ } + +class B1(a: int) extends M2[int] +//│ class B1(a: int) { +//│ fun m: int +//│ } + +class B2[A](a: int => A) extends M2 +//│ class B2[A](a: int -> A) { +//│ fun m: int -> A +//│ } + +:e +class E1(a: int) extends M2[bool] +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.132: class E1(a: int) extends M2[bool] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `int` is not an instance of type `bool` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.132: class E1(a: int) extends M2[bool] +//│ ║ ^^^^ +//│ ╟── from field selection: +//│ ║ l.114: fun m: A = this.a +//│ ╙── ^^^^^^ +//│ class E1(a: int) { +//│ fun m: bool +//│ } diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 36c6c9b413..cebf4aaea2 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -15,6 +15,38 @@ class A(a: int) extends Test //│ fun bar: (int, int,) //│ } +mixin Test2[S, T] { + fun x: (S, T) + fun x = (this.s, this.t) + fun fb: S => (S, S) + fun fb(h: S) = (this.s, h) +} +//│ mixin Test2[S, T]() { +//│ this: {s: S, t: T} +//│ fun fb: S -> (S, S,) +//│ fun x: (S, T,) +//│ } + +class A1[B](s: bool, t: B) extends Test2[bool, B] +//│ class A1[B](s: bool, t: B) { +//│ fun fb: (h: bool,) -> (bool, bool,) +//│ fun x: (bool, B,) +//│ } + +// TODO: Investigate type of fb +class A2[A](s: A, t: int) extends Test2 +//│ class A2[A](s: A, t: int) { +//│ fun fb: (h: 'S,) -> (A, A | 'S,) +//│ fun x: (A, int,) +//│ } + +// TODO: Investigate type of fb +class A3(s: int, t: bool) extends Test2 +//│ class A3(s: int, t: bool) { +//│ fun fb: (h: 'S,) -> (int, 'S | int,) +//│ fun x: (int, bool,) +//│ } + class P(p: int) { fun foo(x) = x + p } @@ -25,7 +57,7 @@ class P(p: int) { :e // FIXME class C1(a: int) extends P(a) { fun bar = this.foo(0) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.26: class C1(a: int) extends P(a) { fun bar = this.foo(0) } +//│ ║ l.58: class C1(a: int) extends P(a) { fun bar = this.foo(0) } //│ ╙── ^^^^ //│ class C1(a: int) { //│ fun bar: error @@ -37,7 +69,7 @@ class C2(a: int, b: int) extends P(a + b) { fun foo(x) = x * this.p + a * b } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.37: fun foo(x) = x * this.p + a * b +//│ ║ l.69: fun foo(x) = x * this.p + a * b //│ ╙── ^^ //│ class C2(a: int, b: int) { //│ fun foo: int -> int @@ -95,24 +127,24 @@ class B extends Foo { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.95: fun foo(x) = x + 1 -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.127: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.87: fun foo[A](x: A): A -//│ ║ ^ +//│ ║ l.119: fun foo[A](x: A): A +//│ ║ ^ //│ ╟── into reference of type `int` -//│ ║ l.95: fun foo(x) = x + 1 -//│ ╙── ^ +//│ ║ l.127: fun foo(x) = x + 1 +//│ ╙── ^ //│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.95: fun foo(x) = x + 1 -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.127: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.95: fun foo(x) = x + 1 -//│ ║ ^^^^^ +//│ ║ l.127: fun foo(x) = x + 1 +//│ ║ ^^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this operator application: -//│ ║ l.95: fun foo(x) = x + 1 -//│ ╙── ^^^^^ +//│ ║ l.127: fun foo(x) = x + 1 +//│ ╙── ^^^^^ //│ class B() { //│ fun foo: int -> int //│ } From 21d6dc5cf5be712ea9f9494153b0ed7ef98a8296 Mon Sep 17 00:00:00 2001 From: Meowcolm024 Date: Thu, 25 May 2023 16:21:38 +0800 Subject: [PATCH 327/498] small fix --- .../src/main/scala/mlscript/NuTypeDefs.scala | 18 +++++++++--------- .../src/main/scala/mlscript/TyperHelpers.scala | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 2c24a043ea..70c49bec8a 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -174,9 +174,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def name: Str = nme.name lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { - case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } ++ parentTP + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } ++ parentTP def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) @@ -236,9 +236,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => /** Includes class-name-coded type parameter fields. */ lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { - case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } ++ parentTP + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } ++ parentTP // TODO // def checkVariances @@ -338,9 +338,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def name: Str = nme.name lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { - case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) - } + case (nme @ TypeName(name), tv, _) => + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + } def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 38f0e14e18..391a67c26a 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -793,11 +793,11 @@ abstract class TyperHelpers { Typer: Typer => S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.instanceType) ++ cls.parentTP.valuesIterator.flatMap(childrenPolMem) - case cls: TypedNuTrt => - cls.tparams.iterator.map(pol.invar -> _._2) ++ - cls.members.valuesIterator.flatMap(childrenPolMem) ++ - S(pol.contravar -> cls.thisTy) ++ - cls.parentTP.valuesIterator.flatMap(childrenPolMem) + case trt: TypedNuTrt => + trt.tparams.iterator.map(pol.invar -> _._2) ++ + trt.members.valuesIterator.flatMap(childrenPolMem) ++ + S(pol.contravar -> trt.thisTy) ++ + trt.parentTP.valuesIterator.flatMap(childrenPolMem) case prm: NuParam => childrenPolField(pol)(prm.ty) case TypedNuDummy(d) => N } @@ -890,11 +890,11 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.instanceType) - case cls: TypedNuTrt => - cls.tparams.iterator.map(_._2) ++ + case trt: TypedNuTrt => + trt.tparams.iterator.map(_._2) ++ // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) - cls.members.valuesIterator.flatMap(childrenMem) ++ - S(cls.thisTy) + trt.members.valuesIterator.flatMap(childrenMem) ++ + S(trt.thisTy) case TypedNuDummy(d) => Nil } ents ::: tu.result.toList From 856eff5fa7cd25ff3a35368159830c86741da005 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 25 May 2023 19:16:25 +0800 Subject: [PATCH 328/498] Refactor code --- shared/src/main/scala/mlscript/Typer.scala | 4 ++-- shared/src/main/scala/mlscript/helpers.scala | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index fd7bca88e5..8afe868ebc 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1306,7 +1306,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { case TypedNuAls(level, td, tparams, body) => ectx(tparams) |> { implicit ectx => - NuTypeDef(td.kind, td.nme, td.tparams, S(Tup(Nil)), N, S(go(body)), Nil, N, N, TypingUnit(Nil))( + NuTypeDef(td.kind, td.nme, td.tparams, N, N, S(go(body)), Nil, N, N, TypingUnit(Nil))( td.declareLoc, td.abstractLoc) } case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => @@ -1323,7 +1323,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case TypedNuCls(level, td, ttu, tparams, params, members, thisTy) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, - S(Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub)))))), + Opt.when(td.params.isDefined)(Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub)))))), td.ctor, N,//TODO Nil,//TODO diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 1e25eb43a8..8b0a8a994c 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -739,7 +739,7 @@ trait StatementImpl extends Located { self: Statement => ??? // TODO case NuTypeDef(k @ Als, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => // TODO properly check: - require(tup.getOrElse(Tup(Nil)).fields.isEmpty, tup) + require(tup.forall(tup => tup.fields.isEmpty), tup) require(pars.size === 0, pars) require(sig.isDefined) require(ths.isEmpty, ths) @@ -884,7 +884,7 @@ trait StatementImpl extends Located { self: Statement => case Constructor(params, body) => params :: body :: Nil case Ass(lhs, rhs) => lhs :: rhs :: Nil case NuTypeDef(k, nme, tps, ps, ctor, sig, pars, sup, ths, bod) => - nme :: tps.map(_._2) ::: ps.getOrElse(Tup(Nil)) :: pars ::: ths.toList ::: bod :: Nil + nme :: tps.map(_._2) ::: ps.toList ::: pars ::: ths.toList ::: bod :: Nil } From f8e792befff6aba928c10035b91a1c595b885b44 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 26 May 2023 09:46:53 +0800 Subject: [PATCH 329/498] Don't print empty list for classes without parameters --- shared/src/main/scala/mlscript/helpers.scala | 9 ++--- .../src/test/diff/codegen/ConstructorStmt.mls | 6 ++-- shared/src/test/diff/codegen/Mixin.mls | 8 ++--- shared/src/test/diff/codegen/Nested.mls | 34 +++++++++---------- shared/src/test/diff/codegen/New.mls | 2 +- shared/src/test/diff/codegen/NuClasses.mls | 8 ++--- .../src/test/diff/codegen/OptionalParam.mls | 20 +++++------ shared/src/test/diff/codegen/Super.mls | 6 ++-- .../test/diff/ecoop23/ExpressionProblem.mls | 8 ++--- shared/src/test/diff/ecoop23/Intro.mls | 4 +-- .../test/diff/ecoop23/PolymorphicVariants.mls | 10 +++--- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 16 ++++----- shared/src/test/diff/gadt/Exp1.mls | 2 +- shared/src/test/diff/nu/BadAliases.mls | 2 +- shared/src/test/diff/nu/BadClasses.mls | 16 ++++----- shared/src/test/diff/nu/BadScopes.mls | 2 +- shared/src/test/diff/nu/BadSuper.mls | 4 +-- shared/src/test/diff/nu/BadUCS.mls | 8 ++--- .../test/diff/nu/BasicClassInheritance.mls | 2 +- shared/src/test/diff/nu/BasicClasses.mls | 2 +- shared/src/test/diff/nu/BasicMixins.mls | 6 ++-- shared/src/test/diff/nu/ClassesInMixins.mls | 2 +- shared/src/test/diff/nu/CtorStatements.mls | 2 +- shared/src/test/diff/nu/Dates.mls | 2 +- shared/src/test/diff/nu/Declarations.mls | 10 +++--- shared/src/test/diff/nu/EncodedLists.mls | 2 +- shared/src/test/diff/nu/EqlClasses.mls | 2 +- shared/src/test/diff/nu/EvalNegNeg.mls | 2 +- .../test/diff/nu/ExpressionProblem_repro.mls | 6 ++-- .../test/diff/nu/ExpressionProblem_small.mls | 2 +- shared/src/test/diff/nu/FilterMap.mls | 6 ++-- shared/src/test/diff/nu/FunPoly.mls | 2 +- shared/src/test/diff/nu/GADTMono.mls | 2 +- shared/src/test/diff/nu/GenericClasses.mls | 4 +-- shared/src/test/diff/nu/GenericMethods.mls | 2 +- shared/src/test/diff/nu/GenericModules.mls | 6 ++-- shared/src/test/diff/nu/ListConsNil.mls | 2 +- shared/src/test/diff/nu/MetaWrap.mls | 6 ++-- shared/src/test/diff/nu/MethodSignatures.mls | 4 +-- shared/src/test/diff/nu/MutualRec.mls | 20 +++++------ shared/src/test/diff/nu/NestedClasses.mls | 8 ++--- shared/src/test/diff/nu/ParamOverride.mls | 2 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 12 +++---- shared/src/test/diff/nu/SelfRec.mls | 4 +-- .../src/test/diff/nu/ThisRefinedClasses.mls | 6 ++-- shared/src/test/diff/nu/TypeAliases.mls | 2 +- shared/src/test/diff/nu/TypeSelections.mls | 2 +- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 2 +- .../diff/nu/repro_PolymorphicVariants.mls | 2 +- shared/src/test/diff/tapl/NuSimplyTyped.mls | 4 +-- shared/src/test/diff/tapl/NuUntyped.mls | 4 +-- shared/src/test/diff/ucs/ElseIf.mls | 4 +-- shared/src/test/diff/ucs/Exhaustiveness.mls | 2 +- shared/src/test/diff/ucs/HygienicBindings.mls | 4 +-- shared/src/test/diff/ucs/JSON.mls | 8 ++--- shared/src/test/diff/ucs/LitUCS.mls | 2 +- shared/src/test/diff/ucs/NestedBranches.mls | 4 +-- shared/src/test/diff/ucs/Tree.mls | 4 +-- shared/src/test/diff/ucs/Wildcard.mls | 2 +- shared/src/test/diff/ucs/zipWith.mls | 4 +-- 60 files changed, 171 insertions(+), 170 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 8b0a8a994c..67ca847bb7 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -141,13 +141,14 @@ trait TypeLikeImpl extends Located { self: TypeLike => sig.getOrElse(die).showIn(ctx, 0)}" case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => val bodyCtx = ctx.indent - s"${kind.str} ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}(${ - params.getOrElse(Tup(Nil)).fields.map { + s"${kind.str} ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}${params match { + case S(Tup(fields)) => s"(${fields.map { case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) case (N, _) => "???" case (S(nme), rhs) => nme.name - }.mkString(", ") - })${parents match { + }.mkString(", ")})" + case _ => "" + }}${parents match { case Nil => "" case ps => ps.mkString(", ") // TODO pp }}${if (body.entities.isEmpty && sup.isEmpty && ths.isEmpty) "" else diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 1f9580619b..57555b0c62 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -5,7 +5,7 @@ module Test0 { log("Hello!") } -//│ module Test0() +//│ module Test0 //│ // Prelude //│ function log(x) { //│ return console.info(x); @@ -138,7 +138,7 @@ class Foo { //│ ╔══[ERROR] Class `Foo` does not contain member `x` //│ ║ l.136: this: { x: int } //│ ╙── ^ -//│ class Foo() +//│ class Foo //│ // Prelude //│ class TypingUnit7 { //│ #Foo; @@ -168,7 +168,7 @@ class Bar { //│ ╔══[ERROR] Class `Bar` does not contain member `x` //│ ║ l.163: super: { x: int } //│ ╙── ^ -//│ class Bar() +//│ class Bar //│ // Prelude //│ class TypingUnit8 { //│ #Bar; diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index b919dc807d..92bc86f94e 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -351,7 +351,7 @@ mixin EvalNegNeg { :js :ShowRepl module TestLang extends EvalBase, EvalNeg, EvalNegNeg -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'A -> int //│ } //│ where @@ -541,7 +541,7 @@ mixin Bazz(y: int) :js module Barr extends Fooo(0), Bazz(1) -//│ module Barr() { +//│ module Barr { //│ fun f: (int, 0,) //│ } //│ // Prelude @@ -594,7 +594,7 @@ mixin Base { :re module Test extends Base -//│ module Test() { +//│ module Test { //│ fun x: error //│ } //│ Runtime error: @@ -610,7 +610,7 @@ mixin MC(c: int) :js module MM extends MA(1), MB(2, 3), MC(4) -//│ module MM() +//│ module MM //│ // Prelude //│ class TypingUnit22 { //│ #MM; diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index a498579da0..f6c7a25994 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -8,7 +8,7 @@ module A { fun b = x + 1 } } -//│ module A() { +//│ module A { //│ class B(x: int) { //│ fun b: int //│ } @@ -177,7 +177,7 @@ module D { class E(x: int) {} fun createE(x: int) = E(x + 1) } -//│ module D() { +//│ module D { //│ class E(x: int) //│ fun createE: (x: int,) -> E //│ } @@ -424,8 +424,8 @@ module G { } } } -//│ module G() { -//│ module H() { +//│ module G { +//│ module H { //│ class J(x: int) { //│ fun ii: (a: int,) -> I //│ } @@ -543,7 +543,7 @@ module H { let i = I(x + 1) } } -//│ module H() { +//│ module H { //│ class I(x: int) //│ class J(x: int) { //│ let i: I @@ -735,7 +735,7 @@ module J { //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) //│ ║ l.730: class N(x: int) extends K(x + 2), L //│ ╙── ^^^^^^^^ -//│ module J() { +//│ module J { //│ class K(x: int) //│ mixin L() //│ class M() @@ -853,8 +853,8 @@ module K { } } } -//│ module K() { -//│ module L() { +//│ module K { +//│ module L { //│ class M() { //│ fun f: 42 //│ } @@ -888,10 +888,10 @@ module L { //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) //│ ║ l.884: class P(y: int) extends M(y + 1) {} //│ ╙── ^^^^^^^^ -//│ module L() { +//│ module L { //│ class M(x: int) -//│ module N() { -//│ module O() { +//│ module N { +//│ module O { //│ class P(y: int) //│ } //│ } @@ -933,8 +933,8 @@ M.N.op(M.P()) //│ ╔══[ERROR] access to class member not yet supported //│ ║ l.929: M.N.op(M.P()) //│ ╙── ^^ -//│ module M() { -//│ module N() { +//│ module M { +//│ module N { //│ fun op: anything -> (0 | 1 | 2) //│ } //│ class O() @@ -1021,8 +1021,8 @@ module N { //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) //│ ║ l.1017: class P() extends Q //│ ╙── ^ -//│ module N() { -//│ module O() { +//│ module N { +//│ module O { //│ class P() //│ } //│ class Q() @@ -1341,8 +1341,8 @@ module Test { log(3) Foo } -//│ module Test() { -//│ module Foo() +//│ module Test { +//│ module Foo //│ } :js diff --git a/shared/src/test/diff/codegen/New.mls b/shared/src/test/diff/codegen/New.mls index 4959e5a833..787ec3dee5 100644 --- a/shared/src/test/diff/codegen/New.mls +++ b/shared/src/test/diff/codegen/New.mls @@ -2,7 +2,7 @@ class C -//│ class C() +//│ class C :js new C diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index e040b20353..96951c1d21 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -51,7 +51,7 @@ module Test3 { //│ class Test2(n: int) { //│ fun inc: Test2 //│ } -//│ module Test3() { +//│ module Test3 { //│ fun inc: int -> Test2 //│ } @@ -87,7 +87,7 @@ module Foo { fun f = C0() class C0() } -//│ module Foo() { +//│ module Foo { //│ class C0() //│ fun f: C0 //│ } @@ -109,7 +109,7 @@ module M1 extends M0(123) { fun m = "m" fun bar = "bar" } -//│ module M1() { +//│ module M1 { //│ fun bar: "bar" //│ fun foo: (int, int, int,) //│ fun m: "m" @@ -138,7 +138,7 @@ module M2 { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.135: fun bar(x) = x + y + this.m //│ ╙── ^^ -//│ module M2() { +//│ module M2 { //│ fun foo: int -> int //│ let m: 100 //│ } diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 7832bdad24..e87ca9fe3d 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -32,7 +32,7 @@ class A(x: int) {} :js class B {} -//│ class B() +//│ class B //│ // Prelude //│ class TypingUnit1 { //│ #B; @@ -55,7 +55,7 @@ class B {} class C { constructor(x: int) } -//│ class C() +//│ class C //│ // Prelude //│ class TypingUnit2 { //│ #C; @@ -143,7 +143,7 @@ class E { //│ ╔══[PARSE ERROR] A class may only have at most one explicit constructor //│ ║ l.139: class E { //│ ╙── ^^^^^ -//│ class E() +//│ class E :e constructor(x: int) @@ -169,8 +169,8 @@ class H extends B {} //│ ║ l.161: class H extends B {} //│ ╙── ^ //│ class F(x: int) -//│ class G() -//│ class H() +//│ class G +//│ class H //│ // Prelude //│ class TypingUnit7 { //│ #F; @@ -265,10 +265,10 @@ module I { //│ ╔══[ERROR] Class inheritance is not supported yet (use mixins) //│ ║ l.262: class L extends J(0) //│ ╙── ^^^^ -//│ module I() { -//│ class J() -//│ module K() { -//│ class L() +//│ module I { +//│ class J +//│ module K { +//│ class L //│ } //│ } //│ // Prelude @@ -446,5 +446,5 @@ mixin P { //│ ╔══[ERROR] Explicit mixin constructors are not supported. //│ ║ l.441: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ module O() +//│ module O //│ mixin P() diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index aa500a3b7b..4f6168b7a8 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -68,7 +68,7 @@ mixin Foo1 { //│ // End of generated code module Test0 extends Foo0, Foo1 -//│ module Test0() { +//│ module Test0 { //│ let foo0: 1 //│ let foo1: 0 //│ } @@ -117,7 +117,7 @@ mixin Foo2 { :re :js module Test0 extends Foo2 -//│ module Test0() { +//│ module Test0 { //│ fun foo2: anything //│ } //│ // Prelude @@ -159,7 +159,7 @@ Test0.foo2 class Foo extends Foo0 { fun foo0(n) = [super.foo0, super.foo0 + n] } -//│ class Foo() { +//│ class Foo { //│ fun foo0: int -> (0, int,) //│ } diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index b7b077695b..df18daa5b7 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -36,7 +36,7 @@ mixin EvalBase { module TestLang extends EvalBase -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'a -> int //│ } //│ where @@ -74,7 +74,7 @@ module TestLang extends EvalNothing, EvalAddLit //│ this: {eval: 'lhs -> int} //│ fun eval: (Add['lhs] | Lit | 'a & ~#Add & ~#Lit) -> (int | 'b) //│ } -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'c -> int //│ } //│ where @@ -115,7 +115,7 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'a -> int //│ } //│ where @@ -190,7 +190,7 @@ mixin EvalNegNeg { //│ } module TestLang extends EvalBase, EvalNeg, EvalNegNeg -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'A -> int //│ } //│ where diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index b659ebde50..488c7e0269 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -8,7 +8,7 @@ class Some(value: A) module None //│ class Some[A](value: A) -//│ module None() +//│ module None @@ -92,7 +92,7 @@ class MyPoint(x: int, y: int, color: Color, parent: Some[MyPoint] | None) module CompareMyPoint extends ComparePoint, CompareColored, CompareNested -//│ module CompareMyPoint() { +//│ module CompareMyPoint { //│ fun compare: ('a, 'b,) -> bool //│ } //│ where diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index bc53ebe043..1b9ca2ac8a 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -8,7 +8,7 @@ class Cons[out A](head: A, tail: Cons[A] | Nil) module Nil //│ class Cons[A](head: A, tail: Cons[A] | Nil) -//│ module Nil() +//│ module Nil let l = Cons(1, Nil) //│ let l: Cons[1] @@ -80,7 +80,7 @@ mixin EvalLambda { // FIXME type simplification :ns module Test1 extends EvalVar, EvalLambda -//│ module Test1() { +//│ module Test1 { //│ fun eval: ('a, 'b,) -> ('c | 'd | 'e | 'f) //│ } //│ where @@ -225,7 +225,7 @@ mixin EvalExpr { //│ } module Test2 extends EvalVar, EvalExpr -//│ module Test2() { +//│ module Test2 { //│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, 'a,) -> (Num | Var | 'result | 'a) //│ } //│ where @@ -275,7 +275,7 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) // FIXME type simplification :ns module Test3 extends EvalVar, EvalExpr, EvalLambda -//│ module Test3() { +//│ module Test3 { //│ fun eval: ('a, 'b,) -> ('c | 'd | 'e | 'f) //│ } //│ where @@ -412,7 +412,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num :ns // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr -//│ module Test3() { +//│ module Test3 { //│ fun eval: ('a, 'b,) -> ('c | 'd | 'b | 'e) //│ } //│ where diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index ddd5634746..cfeacbc231 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -81,7 +81,7 @@ mixin SizeExt { //│ } module TestSize extends SizeBase, SizeExt -//│ module TestSize() { +//│ module TestSize { //│ fun size: 'a -> int //│ } //│ where @@ -124,7 +124,7 @@ mixin Contains { //│ } module TestContains extends Contains -//│ module TestContains() { +//│ module TestContains { //│ fun contains: ('a, {x: int, y: int},) -> bool //│ } //│ where @@ -180,13 +180,13 @@ module SizeText extends Text //│ ╔══[ERROR] Module `SizeText` does not contain member `size` //│ ║ l.159: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ -//│ module SizeText() { +//│ module SizeText { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string //│ } // * Note: this inferred type got *much worse* after this commit (field access type refinement) module SizeText extends SizeBase, Text -//│ module SizeText() { +//│ module SizeText { //│ fun size: 'a -> int //│ fun text: (Circle | Intersect[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]] | Outside['a] | Translate[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]] | Union[Circle | Intersect['Region] | Outside['Region0] | Translate['Region1] | Union['Region2]]) -> string //│ } @@ -250,7 +250,7 @@ mixin IsEmpty { //│ } module IsUnivIsEmpty extends IsUniv, IsEmpty -//│ module IsUnivIsEmpty() { +//│ module IsUnivIsEmpty { //│ fun isEmpty: 'a -> bool //│ fun isUniv: 'b -> bool //│ } @@ -259,7 +259,7 @@ module IsUnivIsEmpty extends IsUniv, IsEmpty //│ 'b <: Intersect['b] | Outside['a] | Scale['b] | Translate['b] | Union['b] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ module IsUnivIsEmpty extends IsEmpty, IsUniv -//│ module IsUnivIsEmpty() { +//│ module IsUnivIsEmpty { //│ fun isEmpty: 'a -> bool //│ fun isUniv: 'b -> bool //│ } @@ -301,7 +301,7 @@ mixin Eliminate { //│ } module TestElim extends Eliminate -//│ module TestElim() { +//│ module TestElim { //│ fun eliminate: 'a -> 'b //│ } //│ where @@ -344,7 +344,7 @@ TestElim.eliminate(mk(100)) // ************************************************************************* module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate -//│ module Lang() { +//│ module Lang { //│ fun contains: ('a, {x: int, y: int},) -> bool //│ fun eliminate: 'b -> 'c //│ fun isEmpty: 'd -> bool diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index dfd98e1495..6feb3e30ee 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -32,7 +32,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ╟── reference of type `#Exp & {Exp#A = ?A}` does not match type `Lit | Pair[?L, ?R]` //│ ║ l.6: fun test = if this is //│ ╙── ^^^^ -//│ class Exp[A]() { +//│ class Exp[A] { //│ fun test: 0 | 1 //│ } //│ class Lit(n: int) diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index 1728931c38..4ed1de30d8 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -36,7 +36,7 @@ type Test(n: int) = n //│ type Test = error class Base -//│ class Base() +//│ class Base :pe :e diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index f758d40b27..59fe4043c0 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -10,14 +10,14 @@ class C0 extends M0 //│ ╔══[ERROR] mixin M0 expects 1 parameters; got 0 //│ ║ l.9: class C0 extends M0 //│ ╙── ^^ -//│ class C0() +//│ class C0 :e class C0 extends M0(1, 2) //│ ╔══[ERROR] mixin M0 expects 1 parameters; got 2 //│ ║ l.16: class C0 extends M0(1, 2) //│ ╙── ^^^^^^^ -//│ class C0() +//│ class C0 :e class C0 extends M0(true) @@ -30,7 +30,7 @@ class C0 extends M0(true) //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: mixin M0(x: int) //│ ╙── ^^^ -//│ class C0() +//│ class C0 // TODO catch this at typing (lack of `this`) @@ -38,7 +38,7 @@ class Foo { fun foo = 0 fun bar = foo } -//│ class Foo() { +//│ class Foo { //│ fun bar: 0 //│ fun foo: 0 //│ } @@ -48,7 +48,7 @@ class Foo { let foo = 0 fun bar = foo } -//│ class Foo() { +//│ class Foo { //│ fun bar: 0 //│ let foo: 0 //│ } @@ -58,7 +58,7 @@ module Bar { fun hello = 0 type I = int } -//│ module Bar() { +//│ module Bar { //│ type I = int //│ fun hello: 0 //│ } @@ -91,7 +91,7 @@ class Foo[A] { 42: A } //│ ╟── Note: constraint arises from type parameter: //│ ║ l.86: class Foo[A] { 42: A } //│ ╙── ^ -//│ class Foo[A]() +//│ class Foo[A] :e @@ -99,7 +99,7 @@ class C1 { fun oops = this.x } //│ ╔══[ERROR] Class `C1` does not contain member `x` //│ ║ l.98: class C1 { fun oops = this.x } //│ ╙── ^^ -//│ class C1() { +//│ class C1 { //│ fun oops: error //│ } diff --git a/shared/src/test/diff/nu/BadScopes.mls b/shared/src/test/diff/nu/BadScopes.mls index 9cdea7ca24..555e7ce4a9 100644 --- a/shared/src/test/diff/nu/BadScopes.mls +++ b/shared/src/test/diff/nu/BadScopes.mls @@ -32,7 +32,7 @@ class Bar { x } //│ ║ l.30: class Bar { x } //│ ╙── ^ //│ class Foo(x: int) -//│ class Bar() +//│ class Bar //│ Code generation encountered an error: //│ unresolved symbol x diff --git a/shared/src/test/diff/nu/BadSuper.mls b/shared/src/test/diff/nu/BadSuper.mls index eafaee489d..8b5c47dbfc 100644 --- a/shared/src/test/diff/nu/BadSuper.mls +++ b/shared/src/test/diff/nu/BadSuper.mls @@ -25,7 +25,7 @@ mixin M1 { :re module C0 extends M0, M1 C0.g -//│ module C0() { +//│ module C0 { //│ fun f: 42 //│ fun g: {f: 42} //│ } @@ -42,7 +42,7 @@ class Foo { //│ ╔══[ERROR] Illegal use of `super` //│ ║ l.40: fun f = super //│ ╙── ^^^^^ -//│ class Foo() { +//│ class Foo { //│ fun f: Foo //│ } //│ Syntax error: diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index fcea2c2e23..8430d79f14 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -2,7 +2,7 @@ class Foo -//│ class Foo() +//│ class Foo fun foo(x) = if x is Foo then 0 //│ fun foo: Foo -> 0 @@ -11,8 +11,8 @@ fun foo(x) = if x is Foo then 0 module Bar { class Foo0 } -//│ module Bar() { -//│ class Foo0() +//│ module Bar { +//│ class Foo0 //│ } fun foo(x) = if x is Bar then 0 @@ -102,7 +102,7 @@ fun foo(x) = if x is foo() then 0 module Nil class Cons[out A](head: A, tail: Cons[A] | Nil) -//│ module Nil() +//│ module Nil //│ class Cons[A](head: A, tail: Cons[A] | Nil) fun join(xs) = diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 330b8b6a45..271fcb46f0 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -2,7 +2,7 @@ class A -//│ class A() +//│ class A // TODO class B(m: int) extends A diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 9bc30a330b..fc886cd19e 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -60,7 +60,7 @@ class C { fun id(x) = x fun const(x) = id } -//│ class C() { +//│ class C { //│ fun const: forall 'a. anything -> 'a -> 'a //│ fun id: forall 'a. 'a -> 'a //│ } diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index f464c974c5..f2d27ff74c 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -18,7 +18,7 @@ mixin BaseTest { module Base0 extends Base, BaseTest -//│ module Base0() { +//│ module Base0 { //│ let base: 42 //│ fun test: 42 //│ } @@ -210,7 +210,7 @@ mixin Wrap { // :d module WrapBase1 extends WrapBase, Wrap -//│ module WrapBase1() { +//│ module WrapBase1 { //│ fun wrap: 'a -> ('a,) //│ fun wrapA: int -> (int,) //│ } @@ -273,7 +273,7 @@ WrapBase1.wrapA("ok") module WrapBase2 extends WrapBase, Wrap, Wrap, Wrap -//│ module WrapBase2() { +//│ module WrapBase2 { //│ fun wrap: 'a -> ((('a,),),) //│ fun wrapA: int -> (((int,),),) //│ } diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index c1af29bb86..230a77ccc5 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -13,7 +13,7 @@ mixin Test { //│ } module M extends Test -//│ module M() { +//│ module M { //│ class Foo(n: int) //│ let f: Foo //│ } diff --git a/shared/src/test/diff/nu/CtorStatements.mls b/shared/src/test/diff/nu/CtorStatements.mls index e9a7f45544..9a59b4de2a 100644 --- a/shared/src/test/diff/nu/CtorStatements.mls +++ b/shared/src/test/diff/nu/CtorStatements.mls @@ -12,7 +12,7 @@ log("Hello!") module Test0 { log("Hello!") } -//│ module Test0() +//│ module Test0 Test0 //│ Test0 diff --git a/shared/src/test/diff/nu/Dates.mls b/shared/src/test/diff/nu/Dates.mls index 053bdcfb6a..21491d1d47 100644 --- a/shared/src/test/diff/nu/Dates.mls +++ b/shared/src/test/diff/nu/Dates.mls @@ -6,7 +6,7 @@ declare class Date { fun toString(): string fun toLocaleString(locales: string | Array[string], options: anything): string } -//│ class Date() { +//│ class Date { //│ fun toLocaleString: (locales: Array[string] | string, options: anything,) -> string //│ fun toString: () -> string //│ } diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index a1d2d0b249..6cb2ff356d 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -20,7 +20,7 @@ atob(str) declare module console { fun error: string -> unit } -//│ module console() { +//│ module console { //│ fun error: string -> unit //│ } @@ -45,7 +45,7 @@ console.log("hello") declare module Foo { fun foo: int } -//│ module Foo() { +//│ module Foo { //│ fun foo: int //│ } @@ -70,7 +70,7 @@ declare type A = int declare class Sanitizer { fun sanitizeFor(element: string, input: string): string } -//│ class Sanitizer() { +//│ class Sanitizer { //│ fun sanitizeFor: (element: string, input: string,) -> string //│ } @@ -94,8 +94,8 @@ declare module Buffer { // fun from1(a: Array[int]): this.Buffer2 = from1(a) // FIXME // fun from2(a: Array[int]): Buffer.Buffer2 = from2(a) // FIXME } -//│ module Buffer() { -//│ class Buffer2() { +//│ module Buffer { +//│ class Buffer2 { //│ let length: int //│ } //│ fun bar: int diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index 14ad4af65f..a65ddd43d7 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -8,7 +8,7 @@ class List { } let Nil: List let Cons: (head: 'a, tail: List<'a>) => List<'a> -//│ class List[A]() { +//│ class List[A] { //│ fun match: forall 'res. (ifNil: () -> 'res, ifCons: ('res, List[A],) -> 'res,) -> 'res //│ } //│ let Nil: List[nothing] diff --git a/shared/src/test/diff/nu/EqlClasses.mls b/shared/src/test/diff/nu/EqlClasses.mls index 041defb51e..1810e05aa5 100644 --- a/shared/src/test/diff/nu/EqlClasses.mls +++ b/shared/src/test/diff/nu/EqlClasses.mls @@ -3,7 +3,7 @@ module Mod -//│ module Mod() +//│ module Mod Mod === Mod //│ bool diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index f77a17807c..89dc401ec0 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -48,7 +48,7 @@ mixin EvalNegNeg { module TestLang extends EvalBase, EvalNeg, EvalNegNeg -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'A -> int //│ } //│ where diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index 240b86972d..0f7f90fd8b 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -56,7 +56,7 @@ mixin EvalAdd { //│ } module TestLang extends EvalAdd -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'a -> nothing //│ } //│ where @@ -82,7 +82,7 @@ mixin EvalBase { module TestLang extends EvalBase -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'a -> int //│ } //│ where @@ -132,7 +132,7 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'a -> int //│ } //│ where diff --git a/shared/src/test/diff/nu/ExpressionProblem_small.mls b/shared/src/test/diff/nu/ExpressionProblem_small.mls index ea0cee1c4b..50dc318817 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_small.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_small.mls @@ -44,7 +44,7 @@ mixin EvalNeg { //│ } module TestLang extends EvalNothing, EvalAddLit, EvalNeg -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'a -> int //│ } //│ where diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 916cfcdd35..351964999e 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -17,7 +17,7 @@ module Nil class Cons[out A](head: A, tail: Cons[A] | Nil) -//│ module Nil() +//│ module Nil //│ class Cons[A](head: A, tail: Cons[A] | Nil) @@ -37,8 +37,8 @@ fun filtermap(f, xs) = if xs is module True module False -//│ module True() -//│ module False() +//│ module True +//│ module False class Pair[A, B](lhs: A, rhs: B) //│ class Pair[A, B](lhs: A, rhs: B) diff --git a/shared/src/test/diff/nu/FunPoly.mls b/shared/src/test/diff/nu/FunPoly.mls index 76eada40c3..29bd55d4a1 100644 --- a/shared/src/test/diff/nu/FunPoly.mls +++ b/shared/src/test/diff/nu/FunPoly.mls @@ -60,7 +60,7 @@ module Helper { fun id(x) = x } //│ fun test: (1, true,) -//│ module Helper() { +//│ module Helper { //│ fun id: forall 'a. 'a -> 'a //│ } diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index ba71213812..ed0e693fc1 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -6,7 +6,7 @@ class Exp[type A] //│ ╔══[PARSE ERROR] Unexpected 'type' keyword here //│ ║ l.5: class Exp[type A] //│ ╙── ^^^^ -//│ class Exp() +//│ class Exp // TODO class Lit(n: int) extends Exp[int] diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index f354992e74..3d848946a1 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -2,7 +2,7 @@ class C -//│ class C[A]() +//│ class C[A] fun f(x) = if x is C then x //│ fun f: forall 'A. C['A] -> C['A] @@ -108,7 +108,7 @@ module None { fun map(f) = None fun map_A(f: nothing -> anything) = None } -//│ module None() { +//│ module None { //│ fun get: nothing //│ fun map: anything -> None //│ fun map_A: (f: nothing -> anything,) -> None diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 2ed49e0fe0..2ec4cdf18e 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -108,7 +108,7 @@ module Test { //│ ╔══[ERROR] Member bar is declared but not defined //│ ║ l.102: fun bar: 'A //│ ╙── ^^^ -//│ module Test() { +//│ module Test { //│ fun bar: nothing //│ fun foo: forall 'A. 'A -> 'A //│ fun test: forall 'A0. (x: 'A0,) -> 'A0 diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 5e74d9bf43..8093b519d0 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -19,7 +19,7 @@ module Test { //│ ╔══[ERROR] Member poly1 is declared but not defined //│ ║ l.10: fun poly1: forall 'a; 'a -> 'a //│ ╙── ^^^^^ -//│ module Test[A]() { +//│ module Test[A] { //│ fun bar: A -> A //│ fun baz: (x: A,) -> A //│ fun foo: A -> A @@ -147,7 +147,7 @@ test(Test) module Test { fun foo = id } -//│ module Test[A]() { +//│ module Test[A] { //│ fun foo: forall 'a. 'a -> 'a //│ } @@ -161,7 +161,7 @@ module Test { fun foo: A => A fun foo = id } -//│ module Test[A]() { +//│ module Test[A] { //│ fun foo: A -> A //│ } diff --git a/shared/src/test/diff/nu/ListConsNil.mls b/shared/src/test/diff/nu/ListConsNil.mls index d079e5588c..56cdd8c248 100644 --- a/shared/src/test/diff/nu/ListConsNil.mls +++ b/shared/src/test/diff/nu/ListConsNil.mls @@ -7,7 +7,7 @@ class Cons[out A](head: A, tail: List[A]) module Nil //│ type List[A] = Cons[A] | Nil //│ class Cons[A](head: A, tail: List[A]) -//│ module Nil() +//│ module Nil diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index e8b3adcaa1..fb418fa230 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -54,7 +54,7 @@ mixin WithType { module Test0 extends Base, WithUid -//│ module Test0() { +//│ module Test0 { //│ fun getUid: {uid: 'uid, underlying: 'underlying} -> 'uid //│ fun rewrap: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying0} //│ fun setUid: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying0} @@ -62,7 +62,7 @@ module Test0 extends Base, WithUid //│ } module Test0 extends Base, WithUid, WithUid -//│ module Test0() { +//│ module Test0 { //│ fun getUid: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid //│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {uid: int | 'uid1, underlying: 'underlying0}} //│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: int,) -> {uid: int | 'uid0, underlying: 'underlying2 | {uid: int | 'uid1, underlying: 'underlying0}} @@ -71,7 +71,7 @@ module Test0 extends Base, WithUid, WithUid module Test1 extends Base, WithUid, WithType -//│ module Test1() { +//│ module Test1 { //│ fun getType: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty //│ fun getUid: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'uid //│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 3fada7539e..7b6b5f2a81 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -12,8 +12,8 @@ module M { //│ ╔══[ERROR] type identifier not found: A //│ ║ l.9: fun a: A //│ ╙── ^ -//│ module M() { -//│ class A() +//│ module M { +//│ class A //│ fun a: error //│ } diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 25072cd5aa..b4184b1b96 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -102,10 +102,10 @@ module Test0_1 { module Test0_2 { fun b = 123 } -//│ module Test0_1() { +//│ module Test0_1 { //│ fun a: 123 //│ } -//│ module Test0_2() { +//│ module Test0_2 { //│ fun b: 123 //│ } @@ -118,7 +118,7 @@ class Test0_1 { class Test0_2() { fun b = 123 } -//│ class Test0_1() { +//│ class Test0_1 { //│ fun a: 123 //│ } //│ class Test0_2() { @@ -136,10 +136,10 @@ module Test1_2 { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.134: fun b = Test1_1.a //│ ╙── ^^ -//│ module Test1_1() { +//│ module Test1_1 { //│ fun a: error //│ } -//│ module Test1_2() { +//│ module Test1_2 { //│ fun b: error //│ } @@ -157,10 +157,10 @@ class Test1_2 { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.155: fun b = Test1_1().a //│ ╙── ^^ -//│ class Test1_1() { +//│ class Test1_1 { //│ fun a: error //│ } -//│ class Test1_2() { +//│ class Test1_2 { //│ fun b: error //│ } @@ -180,13 +180,13 @@ module Test2_2 { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.177: fun c = Test2_1.a //│ ╙── ^^ -//│ module Test2_1() { +//│ module Test2_1 { //│ fun a: 123 | error //│ fun d: error //│ fun n: 456 //│ fun t2: Test2_2 //│ } -//│ module Test2_2() { +//│ module Test2_2 { //│ fun b: 123 //│ fun c: error //│ fun e: error @@ -215,7 +215,7 @@ module Test3 { //│ class Test2(n: int) { //│ fun inc: Test2 //│ } -//│ module Test3() { +//│ module Test3 { //│ fun inc: (t: Test2,) -> Test2 //│ } diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index 736bb58985..2a8cc3913a 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -26,8 +26,8 @@ c.NC0 module M0 { class NC0 } -//│ module M0() { -//│ class NC0() +//│ module M0 { +//│ class NC0 //│ } :e @@ -43,8 +43,8 @@ M0.NC0 module M1 { module NM1 } -//│ module M1() { -//│ module NM1() +//│ module M1 { +//│ module NM1 //│ } :e diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index ae87811999..a0d3f050a4 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -68,7 +68,7 @@ t.foo module Test1 extends Base1(1/2), Derived1(1) { fun n = this.n } -//│ module Test1() { +//│ module Test1 { //│ fun foo: (int, 1, number,) //│ fun n: 1 //│ fun original: number diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index f510799a12..8ba339fe1d 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -17,7 +17,7 @@ class List { } let Nil: () => List<'a> let Cons: (head: 'a, tail: List<'a>) => List<'a> -//│ class List[A]() { +//│ class List[A] { //│ fun match: forall 'res. (ifNil: () -> 'res, ifCons: (A, List[A],) -> 'res,) -> 'res //│ } //│ let Nil: forall 'a. () -> List['a] @@ -25,7 +25,7 @@ let Cons: (head: 'a, tail: List<'a>) => List<'a> class NotFound class Success(result: A) -//│ class NotFound() +//│ class NotFound //│ class Success[A](result: A) fun eq(l: string, r: string): bool @@ -104,7 +104,7 @@ mixin EvalLambda { //│ <: 'a1 module Test1 extends EvalVar, EvalLambda -//│ module Test1() { +//│ module Test1 { //│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> 'b //│ } //│ where @@ -163,7 +163,7 @@ mixin EvalExpr { //│ } module Test2 extends EvalVar, EvalExpr -//│ module Test2() { +//│ module Test2 { //│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> ('b | Num | Var | 'a) //│ } //│ where @@ -183,7 +183,7 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) //│ Abs[Var] | Add[Num | Var] | Num | Var module Test3 extends EvalVar, EvalExpr, EvalLambda -//│ module Test3() { +//│ module Test3 { //│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> 'b //│ } //│ where @@ -203,7 +203,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(N //│ 'a :> App['a] | Abs['a] | Abs[Var] | Var | Add[Num | Var] | Num module Test3 extends EvalVar, EvalLambda, EvalExpr -//│ module Test3() { +//│ module Test3 { //│ fun eval: (List[{_1: string, _2: 'b}], 'a,) -> ('a | 'b) //│ } //│ where diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index d930812b52..855aa6f756 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -56,7 +56,7 @@ class Foo4 { //│ ╟── reference of type `() -> #Foo4` does not have field 'test' //│ ║ l.51: fun test = [Foo4.test] //│ ╙── ^^^^ -//│ class Foo4() { +//│ class Foo4 { //│ fun test: (error,) //│ } @@ -93,7 +93,7 @@ class Foo6[A](x: A) { //│ } module N -//│ module N() +//│ module N :e class Foo7[A](head: A, tail: Foo7[A] | N) { diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 19cb4e3dca..049ca3355b 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -12,7 +12,7 @@ class Foo { fun test = this.x } //│ ╔══[ERROR] Class `Foo` does not contain member `x` //│ ║ l.11: class Foo { fun test = this.x } //│ ╙── ^^ -//│ class Foo() { +//│ class Foo { //│ fun test: error //│ } @@ -46,7 +46,7 @@ class Foo { //│ ╔══[ERROR] Class `Foo` does not contain member `x` //│ ║ l.43: this: { x: 'a } //│ ╙── ^ -//│ class Foo() +//│ class Foo // TODO @@ -58,7 +58,7 @@ class Test { this: { x: int}; fun test = this.x } //│ ╔══[ERROR] Class `Test` does not contain member `x` //│ ║ l.54: class Test { this: { x: int}; fun test = this.x } //│ ╙── ^ -//│ class Test() { +//│ class Test { //│ fun test: error //│ } diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index a9c5d082a7..4ae330a8bd 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -5,7 +5,7 @@ type I = int //│ type I = int class CI1 -//│ class CI1() +//│ class CI1 // :e type AI1 = Array[int] diff --git a/shared/src/test/diff/nu/TypeSelections.mls b/shared/src/test/diff/nu/TypeSelections.mls index 2c29e565b8..8b842f6fe8 100644 --- a/shared/src/test/diff/nu/TypeSelections.mls +++ b/shared/src/test/diff/nu/TypeSelections.mls @@ -6,7 +6,7 @@ module M { class C(n: int) fun mkC = C } -//│ module M() { +//│ module M { //│ class C(n: int) //│ type T = int -> int //│ fun mkC: (n: int,) -> C diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index 8607b174f0..9a5880a179 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -25,7 +25,7 @@ mixin EvalBase { // module TestLang extends EvalBase, EvalNeg module TestLang extends EvalBase -//│ module TestLang() { +//│ module TestLang { //│ fun eval: 'a -> int //│ } //│ where diff --git a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls index b995026755..706bdc9ce1 100644 --- a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls +++ b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls @@ -5,7 +5,7 @@ class Cons[out A](head: A, tail: Cons[A] | Nil) module Nil //│ class Cons[A](head: A, tail: Cons[A] | Nil) -//│ module Nil() +//│ module Nil class Abs[A](x: string, t: A) class App[A](s: A, t: A) diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls index e34f1c569e..3e13cc3cfc 100644 --- a/shared/src/test/diff/tapl/NuSimplyTyped.mls +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -27,7 +27,7 @@ class Some[A](value: A) module None //│ type Option[A] = Some[A] | None //│ class Some[A](value: A) -//│ module None() +//│ module None type Result[A, B] = Ok[A] | Err[B] class Ok[A](value: A) @@ -66,7 +66,7 @@ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) module Empty //│ type TreeMap[A] = Node[A] | Empty //│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) -//│ module Empty() +//│ module Empty fun insert(t, k, v) = if t is diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index 2ecfed25be..2c831e9ec5 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -55,7 +55,7 @@ module None { //│ class Some[A](value: A) { //│ fun toString: () -> string //│ } -//│ module None() { +//│ module None { //│ fun toString: () -> "None" //│ } @@ -64,7 +64,7 @@ class Cons[A](head: A, tail: List[A]) module Nil //│ type List[A] = Cons[A] | Nil //│ class Cons[A](head: A, tail: List[A]) -//│ module Nil() +//│ module Nil fun list1(x) = Cons(x, Nil) fun list2(x, y) = Cons(x, list1(y)) diff --git a/shared/src/test/diff/ucs/ElseIf.mls b/shared/src/test/diff/ucs/ElseIf.mls index d960bc750b..54d3585433 100644 --- a/shared/src/test/diff/ucs/ElseIf.mls +++ b/shared/src/test/diff/ucs/ElseIf.mls @@ -22,8 +22,8 @@ fun f(x, y) = if x == module True module False -//│ module True() -//│ module False() +//│ module True +//│ module False :e :ge diff --git a/shared/src/test/diff/ucs/Exhaustiveness.mls b/shared/src/test/diff/ucs/Exhaustiveness.mls index cd476faa27..4f80c223fb 100644 --- a/shared/src/test/diff/ucs/Exhaustiveness.mls +++ b/shared/src/test/diff/ucs/Exhaustiveness.mls @@ -58,7 +58,7 @@ class Node[A](value: int, left: Tree[A], right: Tree[A]) { //│ ║ l.49: == value then true //│ ╙── ^^^^^^^^^^^^ //│ type Tree[A] = Node[A] | Empty -//│ module Empty() { +//│ module Empty { //│ fun contains: anything -> false //│ } //│ class Node[A](value: int, left: Tree[A], right: Tree[A]) { diff --git a/shared/src/test/diff/ucs/HygienicBindings.mls b/shared/src/test/diff/ucs/HygienicBindings.mls index 2471ff86a9..724fd49dea 100644 --- a/shared/src/test/diff/ucs/HygienicBindings.mls +++ b/shared/src/test/diff/ucs/HygienicBindings.mls @@ -4,7 +4,7 @@ type Option[out T] = None | Some[T] module None class Some[out T](value: T) //│ type Option[T] = Some[T] | None -//│ module None() +//│ module None //│ class Some[T](value: T) type Either[A, B] = Left[A] | Right[B] @@ -18,7 +18,7 @@ type List[out A] = Nil | Cons[A] module Nil class Cons[out A](head: A, tail: List[A]) //│ type List[A] = Cons[A] | Nil -//│ module Nil() +//│ module Nil //│ class Cons[A](head: A, tail: List[A]) fun h0(a) = diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index ce5b47c5e4..0fa5c29a92 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -85,7 +85,7 @@ type Option[A] = Some[A] | None module None class Some[A](value: A) //│ type Option[A] = Some[A] | None -//│ module None() +//│ module None //│ class Some[A](value: A) type List[A] = Cons[A] | Nil @@ -102,7 +102,7 @@ fun listJoin(xs, sep) = Nil then toString(x) _ then concat3(toString(x), sep, listJoin(xs', sep)) //│ type List[A] = Cons[A] | Nil -//│ module Nil() +//│ module Nil //│ class Cons[A](head: A, tail: List[A]) //│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) //│ fun listJoin: forall 'A1. (Cons['A1] | Nil, string,) -> string @@ -132,7 +132,7 @@ fun traverse(t, f) = Node(key, value, left, right) then listConcat(traverse(left, f), Cons(f(key, value), traverse(right, f))) //│ type TreeMap[A] = Node[A] | Empty -//│ module Empty() +//│ module Empty //│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) //│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] //│ fun find: forall 'A0. (Empty | Node['A0], string,) -> (None | Some['A0]) @@ -160,7 +160,7 @@ class JsonArray(elements: List[JsonValue]) { fun toString() = concat3("[", listJoin(elements, ", "), "]") } //│ type JsonValue = JsonArray | JsonBoolean | JsonNumber | JsonObject | JsonString | JsonNull -//│ module JsonNull() { +//│ module JsonNull { //│ fun toString: () -> "null" //│ } //│ class JsonBoolean(value: bool) { diff --git a/shared/src/test/diff/ucs/LitUCS.mls b/shared/src/test/diff/ucs/LitUCS.mls index ea76bb8481..ffddf11017 100644 --- a/shared/src/test/diff/ucs/LitUCS.mls +++ b/shared/src/test/diff/ucs/LitUCS.mls @@ -1,7 +1,7 @@ :NewDefs module A -//│ module A() +//│ module A // This one is easy to fix but what about the next one? // The following example can better reveal the essence of the problem. diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index fca44522c3..acdb8bf7e8 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -9,10 +9,10 @@ module Nil class Cons[A](head: A, tail: Cons[A] | Nil) class Pair[A, B](fst: A, snd: B) //│ class Some[A](value: A) -//│ module None() +//│ module None //│ class Left[A](leftValue: A) //│ class Right[A](rightValue: A) -//│ module Nil() +//│ module Nil //│ class Cons[A](head: A, tail: Cons[A] | Nil) //│ class Pair[A, B](fst: A, snd: B) diff --git a/shared/src/test/diff/ucs/Tree.mls b/shared/src/test/diff/ucs/Tree.mls index c4af73ef95..e66b2dac07 100644 --- a/shared/src/test/diff/ucs/Tree.mls +++ b/shared/src/test/diff/ucs/Tree.mls @@ -5,13 +5,13 @@ class Some[A](value: A) module None //│ type Option[A] = Some[A] | None //│ class Some[A](value: A) -//│ module None() +//│ module None type Tree[A] = Node[A] | Empty module Empty class Node[A](value: int, left: Tree[A], right: Tree[A]) //│ type Tree[A] = Node[A] | Empty -//│ module Empty() +//│ module Empty //│ class Node[A](value: int, left: Tree[A], right: Tree[A]) fun find(t, v) = if t is diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index 47d8a63ad7..5f39eb4917 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -5,7 +5,7 @@ type Option[T] = None | Some[T] module None class Some[T](value: T) //│ type Option[T] = Some[T] | None -//│ module None() +//│ module None //│ class Some[T](value: T) type Either[A, B] = Left[A] | Right[B] diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index 61edd35e1b..15adf3f90c 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -12,7 +12,7 @@ module None { fun value = nothing } class Some[out A](value: A) -//│ module None() { +//│ module None { //│ fun value: nothing //│ } //│ class Some[A](value: A) @@ -26,7 +26,7 @@ class Cons[out A](head: A, tail: List[A]) { fun toArray = [head, tail.toArray] } //│ type List[A] = Cons[A] | Nil -//│ module Nil() { +//│ module Nil { //│ fun toArray: () //│ } //│ class Cons[A](head: A, tail: List[A]) { From ab12a0c3fffce2de8aed05864a601d01c39b28a4 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 26 May 2023 10:17:19 +0800 Subject: [PATCH 330/498] Ignore traits in inheritance clauses and improve translate parent error message --- shared/src/main/scala/mlscript/JSBackend.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index a7b62e13b7..279d3b6610 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -596,6 +596,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } scope.resolveValue(name) match { + case Some(CapturedSymbol(_, _: TraitSymbol)) => base // TODO: case Some(CapturedSymbol(out, sym: MixinSymbol)) => JSInvoke(translateCapture(CapturedSymbol(out, sym)), Ls(base)) case Some(CapturedSymbol(out, sym: NuTypeSymbol)) if !mixinOnly => @@ -603,6 +604,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { translateCapture(CapturedSymbol(out, sym)) else translateCapture(CapturedSymbol(out, sym)).member("class") + case Some(_: TraitSymbol) => base // TODO: case Some(sym: MixinSymbol) => JSInvoke(translateVar(name, false), Ls(base)) case Some(sym: NuTypeSymbol) if !mixinOnly => @@ -610,7 +612,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { translateVar(name, false) else translateVar(name, false).member("class") - case _ => throw CodeGenError(s"unresolved parent $name.") + case Some(t) => throw CodeGenError(s"unexpected parent symbol $t.") + case N => throw CodeGenError(s"unresolved parent $name.") } } From 15209b639d0b0aeb3a64488e80978d0eb326a6a0 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Fri, 26 May 2023 16:11:45 +0800 Subject: [PATCH 331/498] Try to fix warnings --- shared/src/main/scala/mlscript/ConstraintSolver.scala | 2 +- shared/src/main/scala/mlscript/MLParser.scala | 1 + shared/src/main/scala/mlscript/NewParser.scala | 2 ++ shared/src/main/scala/mlscript/TypeDefs.scala | 5 +++++ shared/src/main/scala/mlscript/TypeSimplifier.scala | 1 + shared/src/main/scala/mlscript/Typer.scala | 2 ++ shared/src/main/scala/mlscript/TyperHelpers.scala | 2 ++ shared/src/main/scala/mlscript/codegen/Helpers.scala | 2 ++ .../scala/mlscript/codegen/typescript/TsTypegen.scala | 1 + shared/src/main/scala/mlscript/helpers.scala | 10 ++++++---- 10 files changed, 23 insertions(+), 5 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index f22e06ffd8..5e4271083a 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -695,7 +695,7 @@ class ConstraintSolver extends NormalForms { self: Typer => err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", // ttp(fld)) fld.toLoc).toUpper(noProv) - // case _ => ??? + case _ => ??? // TODO: } println(s"Lookup ${cls.td.nme.name}.${fld.name} : $res where ${res.ub.showBounds}") res diff --git a/shared/src/main/scala/mlscript/MLParser.scala b/shared/src/main/scala/mlscript/MLParser.scala index fe84c67b66..356ad15f05 100644 --- a/shared/src/main/scala/mlscript/MLParser.scala +++ b/shared/src/main/scala/mlscript/MLParser.scala @@ -214,6 +214,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { } case (k @ Als, id, ts) => "=" ~ ty map (bod => TypeDef(k, id, ts, bod, Nil, Nil, Nil)) case (k @ Nms, _, _) => throw new NotImplementedError("Namespaces are not supported yet.") + case (k @ Mxn, _, _) => throw new NotImplementedError("Mixins are not supported yet.") }) def tyParams[p: P]: P[Ls[TypeName]] = ("[" ~ tyName.rep(0, ",") ~ "]").?.map(_.toList.flatten) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index bcfec9746c..5698c11f0a 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -288,6 +288,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D // TODO support indented blocks of modified declarations... err(msg"Unexpected ${tok.describe} token after modifier${if (acc.mods.sizeIs > 1) "s" else ""}" -> S(loc) :: Nil) acc + case Nil => + ??? // TODO: } def unapply(__ : Ls[TokLoc]): S[ModifierSet -> Ls[TokLoc]] = { val res = go(_modifiersCache) diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 66d0975a2e..c2a74bb857 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -277,6 +277,9 @@ class TypeDefs extends NuTypeDefs { self: Typer => case Als => err(msg"cannot inherit from a type alias", prov.loco) false + case Mxn => + err(msg"cannot inherit from a mixin", prov.loco) + false } case ComposedType(false, l, r) => checkParents(l) && checkParents(r) case ComposedType(true, l, r) => @@ -366,12 +369,14 @@ class TypeDefs extends NuTypeDefs { self: Typer => PolymorphicType(MinLevel, FunctionType( singleTup(tv), tv & nomTag & RecordType.mk(tparamTags)(noProv) )(originProv(td.nme.toLoc, "trait constructor", td.nme.name))) + case _ => ??? // TODO: } ctx += n.name -> VarSymbol(ctor, Var(n.name)) } true } checkParents(td.bodyTy) && checkCycle(td.bodyTy)(Set.single(L(td.nme))) && checkAbstractAddCtors + case _ => ??? // TODO: } def checkRegular(ty: SimpleType)(implicit reached: Map[Str, Ls[SimpleType]]): Bool = ty match { case tr @ TypeRef(defn, targs) => reached.get(defn.name) match { diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 68a61898fd..563dbb6e8c 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -123,6 +123,7 @@ trait TypeSimplifier { self: Typer => else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil else v -> default :: Nil } + case S(_) => ??? // TODO: case N => ??? // TODO use info.explicitVariances } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 8afe868ebc..8e0585c355 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -461,6 +461,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) msg"Type alias ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) case Nms => err( msg"Namespaces ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) + case Mxn => err( + msg"Mixin ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) } case _ => e() } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 68f8dc34f1..6ce50d0a87 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -81,6 +81,7 @@ abstract class TyperHelpers { Typer: Typer => def substLike(ty: TL, map: Map[SimpleType, SimpleType], substInMap: Bool): TL = ty match { case ty: ST => subst(ty, map, substInMap) + case _ => ??? // TODO } def subst(st: SimpleType, map: Map[SimpleType, SimpleType], substInMap: Bool = false) (implicit cache: MutMap[TypeVariable, SimpleType] = MutMap.empty): SimpleType = @@ -790,6 +791,7 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.instanceType) + case _ => ??? // TODO: } ents ::: tu.result.toList.map(pol -> _) }} diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 44e657c316..27ae9ba47b 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -56,6 +56,8 @@ object Helpers { case Where(bod, sts) => s"Where(${inspect(bod)}, ...)" case Forall(ps, bod) => s"Forall($ps, ${inspect(bod)})" case Inst(bod) => s"Inst(${inspect(bod)})" + case Ass(lhs, rhs) => s"Ass(${inspect(lhs)}, ${inspect(rhs)})" + case Super() => "Super()" } def inspect(body: IfBody): Str = body match { diff --git a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala index 1873077fa3..328c996401 100644 --- a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala +++ b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala @@ -81,6 +81,7 @@ final class TsTypegenCodeBuilder { case (classInfo: ClassSymbol) => addTypeGenClassDef(classInfo, methods) case (aliasInfo: TypeAliasSymbol) => addTypeGenTypeAlias(aliasInfo) case (traitInfo: TraitSymbol) => addTypegenTraitDef(traitInfo, methods) + case _ => ??? // TODO: } } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 67ca847bb7..1101bfde3b 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -600,10 +600,10 @@ trait TermImpl extends StatementImpl { self: Term => // case Sel(receiver, field) => Selection(receiver.toType_!, TypeName(field.name).withLocOf(field)) - case Sel(receiver, fieldName) => receiver match { - case Var(name) if !name.startsWith("`") => TypeName(s"$name.$fieldName") - case _ => throw new NotAType(this) - } + // case Sel(receiver, fieldName) => receiver match { + // case Var(name) if !name.startsWith("`") => TypeName(s"$name.$fieldName") + // case _ => throw new NotAType(this) + // } // TODO: // case Let(isRec, name, rhs, body) => ??? // case Blk(stmts) => ??? @@ -738,6 +738,8 @@ trait StatementImpl extends Located { self: Statement => ).withLocOf(hd) :: cs) case NuTypeDef(Nms, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => ??? // TODO + case NuTypeDef(Mxn, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => + ??? // TODO case NuTypeDef(k @ Als, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => // TODO properly check: require(tup.forall(tup => tup.fields.isEmpty), tup) From f4e0e692ec5ae554b98d5f1541fcc81e623ff3ba Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sat, 27 May 2023 10:14:51 +0800 Subject: [PATCH 332/498] Refactor --- shared/src/main/scala/mlscript/NewParser.scala | 4 ++-- shared/src/main/scala/mlscript/Typer.scala | 2 ++ shared/src/main/scala/mlscript/TyperHelpers.scala | 2 ++ .../main/scala/mlscript/codegen/typescript/TsTypegen.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 1 + 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 5698c11f0a..2919783b3c 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -849,11 +849,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D }).withLoc(acc.toLoc.fold(some(loc))(_ ++ loc |> some)) exprCont(res, prec, allowNewlines) - case (br @ BRACKETS(Square, toks), loc) :: _ => // * Currently unreachable because we match Square brackets as tparams + /*case (br @ BRACKETS(Square, toks), loc) :: _ => // * Currently unreachable because we match Square brackets as tparams consume val idx = rec(toks, S(br.innerLoc), "subscript").concludeWith(_.expr(0)) val res = Subs(acc, idx.withLoc(S(loc))) - exprCont(res, prec, allowNewlines) + exprCont(res, prec, allowNewlines)*/ case (br @ BRACKETS(Round, toks), loc) :: _ => consume diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 8e0585c355..c5de5c1abc 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -439,6 +439,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case S(AbstractConstructor(_, _)) => die case S(VarSymbol(t: SimpleType, _)) => t case N => err(msg"undeclared this" -> ty.toLoc :: Nil) + case _ => ??? // TODO } case tn @ TypeTag(name) => rec(TypeName(name.decapitalize)) // TODO rm this hack // case tn @ TypeTag(name) => rec(TypeName(name)) @@ -1108,6 +1109,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) if (!founPoly) warn(msg"Inferred type `${bod_ty.expPos}` of this ${ bod_ty.prov.desc} cannot be instantiated", prov.loco) res + case _ => ??? // TODO } }(r => s"$lvl. : ${r}") diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 6ce50d0a87..401bd4bf38 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -840,6 +840,7 @@ abstract class TyperHelpers { Typer: Typer => private def childrenMem(m: NuMember): List[ST] = m match { case NuParam(nme, ty, isType) => ty.lb.toList ::: ty.ub :: Nil case TypedNuFun(level, fd, ty) => ty :: Nil + case _ => ??? // TODO: } def children(includeBounds: Bool): List[SimpleType] = this match { case tv @ AssignedVariable(ty) => if (includeBounds) ty :: Nil else Nil @@ -880,6 +881,7 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.instanceType) + case _ => ??? // TODO: } ents ::: tu.result.toList } diff --git a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala index 328c996401..04bb77d51e 100644 --- a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala +++ b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala @@ -574,7 +574,7 @@ final class TsTypegenCodeBuilder { }.getOrElse(SourceCode(tvarName)) case Constrained(base, tvbs, where) => throw CodeGenError(s"Cannot generate type for `where` clause $tvbs $where") - case _: Splice | _: TypeTag | _: PolyType => + case _: Splice | _: TypeTag | _: PolyType | _: Selection => throw CodeGenError(s"Cannot yet generate type for: $mlType") } } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 1101bfde3b..2d5bebf21c 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -499,6 +499,7 @@ trait TermImpl extends StatementImpl { self: Term => case Forall(_, _) => s"forall clause" case Inst(bod) => "explicit instantiation" case Super() => "super" + case Ass(lhs, rhs) => "assign for ctor" } } From 703200f0cf9f16f654a85df326e8a32bb7e2728f Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sat, 27 May 2023 10:33:57 +0800 Subject: [PATCH 333/498] Fix errors in compiler --- .../scala/mlscript/compiler/ClassLifter.scala | 24 +++++++++---------- .../mlscript/compiler/PrettyPrinter.scala | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index f4afa1aa8c..7418663a33 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -180,8 +180,8 @@ class ClassLifter(logDebugMsg: Boolean = false) { }.fold(emptyCtx)(_ ++ _) case TyApp(trm, tpLst) => getFreeVars(trm).addT(tpLst.flatMap(_.collectTypeNames.map(TypeName(_)))) - case NuTypeDef(_, nm, tps, param, _, pars, _, _, body) => - val prmVs = getFreeVars(param)(using emptyCtx, Map(), None) + case NuTypeDef(_, nm, tps, param, _, _, pars, _, _, body) => + val prmVs = getFreeVars(param.getOrElse(Tup(Nil)))(using emptyCtx, Map(), None) val newVs = prmVs.vSet ++ getFields(body.entities) + Var(nm.name) val nCtx = ctx.addV(newVs).addT(nm).addT(tps.map(_._2)) val parVs = pars.map(getFreeVars(_)(using nCtx)).fold(emptyCtx)(_ ++ _) @@ -197,7 +197,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { } private def collectClassInfo(cls: NuTypeDef, preClss: Set[TypeName])(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): ClassInfoCache = { - val NuTypeDef(_, nm, tps, param, _, pars, _, _, body) = cls + val NuTypeDef(_, nm, tps, param, _, _, pars, _, _, body) = cls log(s"grep context of ${cls.nme.name} under {\n$ctx\n$cache\n$outer\n}\n") val (clses, funcs, trms) = splitEntities(cls.body.entities) val (supNms, rcdFlds) = pars.map(getSupClsInfoByTerm).unzip @@ -208,7 +208,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { (v, ret) }.unzip log(s"par record: ${flds._2.flatten}") - val fields = (param.fields.flatMap(tupleEntityToVar) ++ funcs.map(_.nme) ++ clses.map(x => Var(x.nme.name)) ++ trms.flatMap(grepFieldsInTrm) ++ flds._1).toSet + val fields = (param.fold(Nil)(t => t.fields).flatMap(tupleEntityToVar) ++ funcs.map(_.nme) ++ clses.map(x => Var(x.nme.name)) ++ trms.flatMap(grepFieldsInTrm) ++ flds._1).toSet val nCtx = ctx.addV(fields).addV(flds._1).extT(tps.map(_._2)) val tmpCtx = ((body.entities.map(getFreeVars(_)(using nCtx)) ++ pars.map(getFreeVars(_)(using nCtx))).fold(emptyCtx)(_ ++ _).moveT2V(preClss) ).addT(flds._2.flatten.toSet).extV(supNms.flatten.map(x => Var(x.name))) @@ -378,15 +378,15 @@ class ClassLifter(logDebugMsg: Boolean = false) { log(s"new $t in ctx $ctx, $cache, $outer") val nTpNm = TypeName(genAnoName(t.name)) val cls = cache.get(t).get - val supArgs = Tup(cls.body.params.fields.flatMap(tupleEntityToVar).map(toFldsEle)) - val anoCls = NuTypeDef(Cls, nTpNm, Nil, cls.body.params, None, - List(App(Var(t.name), supArgs)), None, None, tu)(None) + val supArgs = Tup(cls.body.params.fold(Nil)(t => t.fields).flatMap(tupleEntityToVar).map(toFldsEle)) + val anoCls = NuTypeDef(Cls, nTpNm, Nil, cls.body.params, None, None, + List(App(Var(t.name), supArgs)), None, None, tu)(None, None) val nSta = New(Some((nTpNm, prm)), TypingUnit(Nil)) val ret = liftEntities(List(anoCls, nSta)) (Blk(ret._1), ret._2) case New(None, tu) => val nTpNm = TypeName(genAnoName()) - val anoCls = NuTypeDef(Cls, nTpNm, Nil, Tup(Nil), None, Nil, None, None, tu)(None) + val anoCls = NuTypeDef(Cls, nTpNm, Nil, None, None, None, Nil, None, None, tu)(None, None) val nSta = New(Some((nTpNm, Tup(Nil))), TypingUnit(Nil)) val ret = liftEntities(List(anoCls, nSta)) (Blk(ret._1), ret._2) @@ -626,7 +626,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { ).flatten.toMap } log("lift type " + target.toString() + " with cache " + cache.toString()) - val NuTypeDef(kind, nme, tps, params, sig, pars, supAnn, thisAnn, body) = target + val NuTypeDef(kind, nme, tps, params, _, sig, pars, supAnn, thisAnn, body) = target val nOuter = cache.get(nme) val ClassInfoCache(_, nName, freeVs, flds, inners, sups, _, _, _) = nOuter.get val (clsList, funcList, termList) = splitEntities(body.entities) @@ -637,15 +637,15 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nCtx = freeVs.addT(nTps) val nParams = outer.map(x => List(toFldsEle(Var(genParName(x.liftedNm.name))))).getOrElse(Nil) - ++ params.fields + ++ params.fold(Nil)(t => t.fields) ++ freeVs.vSet.map(toFldsEle) val nPars = pars.map(liftTerm(_)(using emptyCtx, nCache, nOuter)).unzip val nFuncs = funcList.map(liftFunc(_)(using emptyCtx, nCache, nOuter)).unzip val nTerms = termList.map(liftTerm(_)(using emptyCtx, nCache, nOuter)).unzip clsList.foreach(x => liftTypeDefNew(x)(using nCache, nOuter)) retSeq = retSeq.appended(NuTypeDef( - kind, nName, nTps.map((None, _)), Tup(nParams), None, nPars._1, - None, None, TypingUnit(nFuncs._1 ++ nTerms._1))(None)) + kind, nName, nTps.map((None, _)), S(Tup(nParams)), None, None, nPars._1, + None, None, TypingUnit(nFuncs._1 ++ nTerms._1))(None, None)) } def liftTypingUnit(rawUnit: TypingUnit): TypingUnit = { diff --git a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala index 8bdee95fcb..54b1106f54 100644 --- a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala @@ -1,6 +1,6 @@ package mlscript.compiler -import mlscript.{TypingUnit, NuFunDef, NuTypeDef, Term} +import mlscript.{TypingUnit, NuFunDef, NuTypeDef, Term, Tup} import mlscript.compiler.debug.DebugOutput // For pretty printing terms in debug output. @@ -47,7 +47,7 @@ object PrettyPrinter: + (if tyDef.tparams.isEmpty then "" else tyDef.tparams.map(_._2.name).mkString("[", ",", "]")) - + "(" + tyDef.params + ")" + + "(" + tyDef.params.getOrElse(Tup(Nil)) + ")" + (if tyDef.parents.isEmpty then "" else ": " + tyDef.parents.map(_.toString).mkString(", ")) From ca3e01df6d0b07a51cffcb21dd40e0fac48177c8 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 31 May 2023 13:22:59 +0800 Subject: [PATCH 334/498] Minor polish --- .../shared/main/scala/mlscript/compiler/ClassLifter.scala | 5 ++++- shared/src/main/scala/mlscript/ConstraintSolver.scala | 2 +- shared/src/main/scala/mlscript/TypeDefs.scala | 4 ++-- shared/src/main/scala/mlscript/Typer.scala | 8 ++++---- shared/src/main/scala/mlscript/TyperHelpers.scala | 7 ++++--- .../scala/mlscript/codegen/typescript/TsTypegen.scala | 2 +- shared/src/test/diff/nu/MethodSignatures.mls | 2 +- 7 files changed, 17 insertions(+), 13 deletions(-) diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index 7418663a33..350a5eb032 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -405,6 +405,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (bod2, ctx) = liftTerm(bod) val (sts2, ctx2) = liftEntities(sts) (Where(bod2, sts2), ctx2) + case _: Ass | _: Super => ??? // TODO } //serves for lifting Tup(Some(_), Fld(_, _, trm)), where trm refers to a type @@ -534,13 +535,14 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (body2, ctx) = liftType(body) PolyType(targs, body2) -> ctx case Top | Bot | _: Literal | _: TypeTag | _: TypeVar => target.asInstanceOf[Type] -> emptyCtx + case _: Selection => ??? // TODO } private def liftFunc(func: NuFunDef)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (NuFunDef, LocalContext) = { log(s"liftFunc $func under $ctx # $cache # $outer") val NuFunDef(rec, nm, tpVs, body) = func - body match{ + body match { case Left(value) => val ret = liftTerm(value)(using ctx.addV(nm).addT(tpVs)) (func.copy(rhs = Left(ret._1))(None), ret._2) @@ -551,6 +553,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { case R(tv) => R(tv) -> emptyCtx }.unzip (func.copy(rhs = Right(PolyType(nTargs._1, nBody._1)))(None), nTargs._2.fold(nBody._2)(_ ++ _)) + case _ => ??? // TODO } } diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 5e4271083a..a649975df6 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -695,7 +695,7 @@ class ConstraintSolver extends NormalForms { self: Typer => err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", // ttp(fld)) fld.toLoc).toUpper(noProv) - case _ => ??? // TODO: + case _ => ??? // TODO } println(s"Lookup ${cls.td.nme.name}.${fld.name} : $res where ${res.ub.showBounds}") res diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index c2a74bb857..6bd15b2e7a 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -369,14 +369,14 @@ class TypeDefs extends NuTypeDefs { self: Typer => PolymorphicType(MinLevel, FunctionType( singleTup(tv), tv & nomTag & RecordType.mk(tparamTags)(noProv) )(originProv(td.nme.toLoc, "trait constructor", td.nme.name))) - case _ => ??? // TODO: + case _ => ??? // TODO } ctx += n.name -> VarSymbol(ctor, Var(n.name)) } true } checkParents(td.bodyTy) && checkCycle(td.bodyTy)(Set.single(L(td.nme))) && checkAbstractAddCtors - case _ => ??? // TODO: + case _ => ??? // TODO } def checkRegular(ty: SimpleType)(implicit reached: Map[Str, Ls[SimpleType]]): Bool = ty match { case tr @ TypeRef(defn, targs) => reached.get(defn.name) match { diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index c5de5c1abc..d5eded8222 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -436,10 +436,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) ClassTag(lit, lit.baseClasses)(tyTp(ty.toLoc, "literal type")) case TypeName("this") => ctx.env.get("this") match { - case S(AbstractConstructor(_, _)) => die + case S(_: AbstractConstructor | _: LazyTypeInfo) => die case S(VarSymbol(t: SimpleType, _)) => t - case N => err(msg"undeclared this" -> ty.toLoc :: Nil) - case _ => ??? // TODO + case N => err(msg"undeclared `this`" -> ty.toLoc :: Nil) } case tn @ TypeTag(name) => rec(TypeName(name.decapitalize)) // TODO rm this hack // case tn @ TypeTag(name) => rec(TypeName(name)) @@ -1109,7 +1108,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) if (!founPoly) warn(msg"Inferred type `${bod_ty.expPos}` of this ${ bod_ty.prov.desc} cannot be instantiated", prov.loco) res - case _ => ??? // TODO + case Ass(lhs, rhs) => + err(msg"Unexpected equation in this position", term.toLoc) } }(r => s"$lvl. : ${r}") diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 401bd4bf38..a0df16fcb9 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -791,7 +791,7 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.instanceType) - case _ => ??? // TODO: + case _ => ??? // TODO } ents ::: tu.result.toList.map(pol -> _) }} @@ -840,7 +840,7 @@ abstract class TyperHelpers { Typer: Typer => private def childrenMem(m: NuMember): List[ST] = m match { case NuParam(nme, ty, isType) => ty.lb.toList ::: ty.ub :: Nil case TypedNuFun(level, fd, ty) => ty :: Nil - case _ => ??? // TODO: + case _ => ??? // TODO } def children(includeBounds: Bool): List[SimpleType] = this match { case tv @ AssignedVariable(ty) => if (includeBounds) ty :: Nil else Nil @@ -881,7 +881,8 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.instanceType) - case _ => ??? // TODO: + case p: NuParam => + p.ty.lb.toList ::: p.ty.ub :: Nil } ents ::: tu.result.toList } diff --git a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala index 04bb77d51e..f78a903844 100644 --- a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala +++ b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala @@ -81,7 +81,7 @@ final class TsTypegenCodeBuilder { case (classInfo: ClassSymbol) => addTypeGenClassDef(classInfo, methods) case (aliasInfo: TypeAliasSymbol) => addTypeGenTypeAlias(aliasInfo) case (traitInfo: TraitSymbol) => addTypegenTraitDef(traitInfo, methods) - case _ => ??? // TODO: + case _ => ??? // TODO } } diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 7b6b5f2a81..b7d744c4b6 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -23,7 +23,7 @@ module M { fun a: this.A fun a = 1 } -//│ ╔══[ERROR] undeclared this +//│ ╔══[ERROR] undeclared `this` //│ ║ l.23: fun a: this.A //│ ╙── ^^^^ //│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached and unexpected state. From 73df7bde3393032dc0c4bf4252ae8284c081c389 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 31 May 2023 13:26:14 +0800 Subject: [PATCH 335/498] Rename Ass to Eqn --- .../shared/main/scala/mlscript/compiler/ClassLifter.scala | 2 +- shared/src/main/scala/mlscript/JSBackend.scala | 6 +++--- shared/src/main/scala/mlscript/NewParser.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 2 +- shared/src/main/scala/mlscript/codegen/Helpers.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 6 +++--- shared/src/main/scala/mlscript/syntax.scala | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index 350a5eb032..9aa8919d3a 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -405,7 +405,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (bod2, ctx) = liftTerm(bod) val (sts2, ctx2) = liftEntities(sts) (Where(bod2, sts2), ctx2) - case _: Ass | _: Super => ??? // TODO + case _: Eqn | _: Super => ??? // TODO } //serves for lifting Tup(Some(_), Fld(_, _, trm)), where trm refers to a type diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 279d3b6610..726bc31617 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -68,7 +68,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { translatePattern(base) case Inst(bod) => translatePattern(bod) case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf | _: Subs | _: Assign - | If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super | _: Ass => + | If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super | _: Eqn => throw CodeGenError(s"term ${inspect(t)} is not a valid pattern") } @@ -301,7 +301,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { throw CodeGenError("custom class body is not supported yet") case Forall(_, bod) => translateTerm(bod) case TyApp(base, _) => translateTerm(base) - case Ass(Var(name), _) => + case Eqn(Var(name), _) => throw CodeGenError(s"assignment of $name is not supported outside a constructor") case _: Bind | _: Test | If(_, _) | _: Splc | _: Where => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") @@ -777,7 +777,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val getters = new ListBuffer[Str]() val stmts = sym.ctor.flatMap { - case Ass(Var(name), rhs) => Ls( + case Eqn(Var(name), rhs) => Ls( JSAssignExpr(JSIdent(s"this.#$name"), translateTerm(rhs)(constructorScope)).stmt, JSConstDecl(constructorScope.declareValue(name, S(false), false).runtimeName, JSIdent(s"this.#$name")) ) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 2919783b3c..24c15e85ca 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -503,7 +503,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case (KEYWORD("="), l0) :: _ => t match { case R(v: Var) => consume - R(Ass(v, expr(0))) :: block + R(Eqn(v, expr(0))) :: block case _ => t :: Nil } case (KEYWORD(";"), _) :: _ => consume; t :: block diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index d5eded8222..b1aebfeb15 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1108,7 +1108,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) if (!founPoly) warn(msg"Inferred type `${bod_ty.expPos}` of this ${ bod_ty.prov.desc} cannot be instantiated", prov.loco) res - case Ass(lhs, rhs) => + case Eqn(lhs, rhs) => err(msg"Unexpected equation in this position", term.toLoc) } }(r => s"$lvl. : ${r}") diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 27ae9ba47b..2d3f33423b 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -56,7 +56,7 @@ object Helpers { case Where(bod, sts) => s"Where(${inspect(bod)}, ...)" case Forall(ps, bod) => s"Forall($ps, ${inspect(bod)})" case Inst(bod) => s"Inst(${inspect(bod)})" - case Ass(lhs, rhs) => s"Ass(${inspect(lhs)}, ${inspect(rhs)})" + case Eqn(lhs, rhs) => s"Ass(${inspect(lhs)}, ${inspect(rhs)})" case Super() => "Super()" } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 2d5bebf21c..1f12b7828f 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -499,7 +499,7 @@ trait TermImpl extends StatementImpl { self: Term => case Forall(_, _) => s"forall clause" case Inst(bod) => "explicit instantiation" case Super() => "super" - case Ass(lhs, rhs) => "assign for ctor" + case Eqn(lhs, rhs) => "assign for ctor" } } @@ -549,7 +549,7 @@ trait TermImpl extends StatementImpl { self: Term => case Forall(ps, bod) => s"forall ${ps.mkString(", ")}. ${bod}" case Inst(bod) => s"${bod.print(true)}!" case Super() => "super" - case Ass(lhs, rhs) => s"${lhs} = ${rhs}" + case Eqn(lhs, rhs) => s"${lhs} = ${rhs}" }} def toTypeRaise(implicit raise: Raise): Type = toType match { @@ -886,7 +886,7 @@ trait StatementImpl extends Located { self: Statement => case Inst(bod) => bod :: Nil case Super() => Nil case Constructor(params, body) => params :: body :: Nil - case Ass(lhs, rhs) => lhs :: rhs :: Nil + case Eqn(lhs, rhs) => lhs :: rhs :: Nil case NuTypeDef(k, nme, tps, ps, ctor, sig, pars, sup, ths, bod) => nme :: tps.map(_._2) ::: ps.toList ::: pars ::: ths.toList ::: bod :: Nil } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 5ed427c1f5..cfe6938462 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -81,7 +81,7 @@ final case class Where(body: Term, where: Ls[Statement]) extends Ter final case class Forall(params: Ls[TypeVar], body: Term) extends Term final case class Inst(body: Term) extends Term final case class Super() extends Term -final case class Ass(lhs: Var, rhs: Term) extends Term // x = y in constructors. TODO: make lhs term +final case class Eqn(lhs: Var, rhs: Term) extends Term // equations such as x = y, notably used in constructors; TODO: make lhs a Term sealed abstract class IfBody extends IfBodyImpl // final case class IfTerm(expr: Term) extends IfBody // rm? From b547a713ebfc133f6aea0ec6d927d0aaf6a07c55 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Wed, 31 May 2023 11:18:58 +0800 Subject: [PATCH 336/498] Update lifter pretty printer --- .../shared/main/scala/mlscript/compiler/PrettyPrinter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala index 54b1106f54..979591cd00 100644 --- a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala @@ -47,7 +47,7 @@ object PrettyPrinter: + (if tyDef.tparams.isEmpty then "" else tyDef.tparams.map(_._2.name).mkString("[", ",", "]")) - + "(" + tyDef.params.getOrElse(Tup(Nil)) + ")" + + tyDef.params.fold("")(params => s"($params)") + (if tyDef.parents.isEmpty then "" else ": " + tyDef.parents.map(_.toString).mkString(", ")) From 8e71947d169d8c06942fa88e42ec985c1f7d9296 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 31 May 2023 15:12:45 +0800 Subject: [PATCH 337/498] WIP Fix general handling of signatures in classes and traits --- .../scala/mlscript/ConstraintSolver.scala | 4 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 148 ++++++++++-------- shared/src/main/scala/mlscript/Typer.scala | 28 ++-- .../main/scala/mlscript/TyperHelpers.scala | 49 ++++-- shared/src/main/scala/mlscript/helpers.scala | 4 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 36 ++--- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 72 ++++----- shared/src/test/diff/gadt/Exp1.mls | 16 +- shared/src/test/diff/nu/BasicMixins.mls | 60 ++++--- shared/src/test/diff/nu/ClassSignatures.mls | 38 ++++- shared/src/test/diff/nu/GADTMono.mls | 12 +- shared/src/test/diff/nu/Interfaces.mls | 4 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 136 ++++++++++++++++ shared/src/test/diff/nu/TraitParameters.mls | 13 ++ .../test/diff/nu/TrickyGenericInheritance.mls | 34 ++-- 15 files changed, 442 insertions(+), 212 deletions(-) create mode 100644 shared/src/test/diff/nu/RawUnionTraitSignatures.mls create mode 100644 shared/src/test/diff/nu/TraitParameters.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index e9810f7874..a1ad3e03e9 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -132,7 +132,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } freshened += _tv -> (targ match { - case tv: TypeVarOrRigidVar => tv + case tv: TypeVarOrRigidVar => println(s"Immediate $tv := $targ"); tv case _ => println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") val tv = @@ -150,7 +150,7 @@ class ConstraintSolver extends NormalForms { self: Typer => raw.freshenAbove(info.level, rigidify = false) } - println(s"Fresh ${info.decl.name}.${fld.name} : $freshenedRaw where ${freshenedRaw.map(_.ub.showBounds)}") + println(s"Fresh[${info.level}] ${info.decl.name}.${fld.name} : $freshenedRaw where ${freshenedRaw.map(_.ub.showBounds)}") freshenedRaw } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 70c49bec8a..f6ef83d2fc 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -162,8 +162,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams: TyParams, members: Map[Str, NuMember], thisTy: ST, - sign: Opt[ST], - selfTy: ST, + sign: ST, inheritedTags: Set[TypeName], parentTP: Map[Str, NuMember] ) extends TypedNuTypeDef(Trt) with PolyNuDecl @@ -185,8 +184,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), - sign.map(_.freshenAbove(lim, rigidify)), - selfTy.freshenAbove(lim, rigidify), + sign.freshenAbove(lim, rigidify), inheritedTags, parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap ) @@ -198,8 +196,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), - sign.map(f(pol, _)), - f(pol, selfTy), + f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap ) @@ -209,8 +206,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), - sign.map(f(pol, _)), - f(pol, selfTy), + f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap ) @@ -219,9 +215,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuCls( level: Level, td: NuTypeDef, ttu: TypedTypingUnit, - tparams: TyParams, params: Ls[Var -> FieldType], - members: Map[Str, NuMember], thisTy: ST, //typeSignature: ST, - selfTy: ST, + tparams: TyParams, + params: Ls[Var -> FieldType], + members: Map[Str, NuMember], + thisTy: ST, + sign: ST, inheritedTags: Set[TypeName], parentTP: Map[Str, NuMember] )(val instanceType: ST, // * only meant to be used in `force` and `variances` @@ -232,7 +230,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name - def typeSignature: ST = typeSignatureOf(td, level, tparams, params, selfTy, inheritedTags) + def typeSignature: ST = typeSignatureOf(td, level, tparams, params, sign, inheritedTags) /** Includes class-name-coded type parameter fields. */ lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { @@ -294,7 +292,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), - selfTy.freshenAbove(lim, rigidify), + sign.freshenAbove(lim, rigidify), inheritedTags, parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap )(this.instanceType.freshenAbove(lim, rigidify)) @@ -307,7 +305,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), - f(pol, selfTy), + f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, )(f(pol, instanceType)) @@ -318,7 +316,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), - f(pol, selfTy), + f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap, )(f(pol, instanceType)) @@ -634,7 +632,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )) case rawTrt: TypedNuTrt => - if (parArgs.nonEmpty) err(msg"trait parameters not yet supported", p.toLoc) + if (parArgs.nonEmpty) err(msg"trait arguments are not yet supported", p.toLoc) val (fr, ptp) = refreshHelper(rawTrt, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided implicit val frenshened: MutMap[TV,ST] = fr @@ -827,44 +825,19 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => private lazy val thisTV: TV = freshVar(provTODO, N, S(decl.name.decapitalize))(lvl + 1) - - // refresh trait/class/mixin - def refreshHelper(raw: PolyNuDecl, v: Var, parTargs: Opt[Ls[Type]]): (MutMap[TV, ST], Map[Str, NuParam]) = { - val freshened: MutMap[TV, ST] = MutMap.empty + + def refreshHelper(raw: PolyNuDecl, v: Var, parTargs: Opt[Ls[Type]]) + (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]) + : (MutMap[TV, ST], Map[Str, NuParam]) = { val rawName = v.name - parTargs foreach { pta => if (raw.tparams.sizeCompare(pta.size) =/= 0) err(msg"${raw.kind.str} $rawName expects ${ raw.tparams.size.toString} type parameter(s); got ${pta.size.toString}", Loc(v :: pta)) } - - val parTP = raw.tparams.lazyZip(parTargs.getOrElse(Nil)).map { case ((tn, _tv, vi), targTy) => - val targ = typeType(targTy) - val tv = (targ match { - case tv: TV => - // TODO - println(s"Passing ${tn.name} :: ${_tv} <=< ${tv}") - tv - case _ => - println(s"Assigning ${tn.name} :: ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - tv - }) - freshened += _tv -> tv - rawName+"#"+tn.name -> NuParam(tn, FieldType(S(tv), tv)(provTODO))(level) - } - - freshened -> parTP.toMap + refreshHelper2(raw: PolyNuDecl, v: Var, parTargs.map(_.map(typeType(_)))) } - def complete()(implicit raise: Raise): TypedNuDecl = result.getOrElse { if (isComputing) { err(msg"Unhandled cyclic definition", decl.toLoc) @@ -943,21 +916,52 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val signatures = typedSignatures ctx ++= signatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) + // * To type signatures correctly, we need to deal with type unbound variables 'X, + // * which should be treated as unknowns (extruded skolems). + // * Allowing such type variables is important for the typing of signatures such as + // * `: Foo | Bar` where `Foo` and `Bar` take type parameters, + // * as these will be (in the future) desugared to `: Foo['A0] | Bar['A1]` + def typeTypeSignature(sign: Type)(implicit ctx: Ctx): ST = { + val outer = ctx + val ty = ctx.nest.nextLevel { implicit ctx => + // * Type the signature in a higher level, so as to contain unbound type vars + val ty = typeType(td.sig.getOrElse(Top)) + // * Make these type vars skolems + implicit val freshened: MutMap[TV, ST] = MutMap.empty + implicit val shadows: Shadows = Shadows.empty + ty.freshenAbove(outer.lvl, rigidify = true) + } + // * Create a lower-levl type variable to extrude the type through it, + // * which will result in making the unbound type vars extruded skolems (i.e., unknowns) + val res = freshVar(provTODO, N, N)(ctx.lvl) + // * Subtle note: it is sufficient and important to add the type as a LB of the TV + // * instead of unifying them because: + // * 1. currently we expand type defs the same no matter of the position polarity + // * so `class S: T` is always expanded as `#S & 'X` where `'X :> T` + // * 2. we don't want to have to check every single subtype of S against T, + // * as this check will already have been performed generally when typing class T, + // * but this would happen if we instead expanded into a type equivalent to #S & T... + constrain(ty, res) + res + } + val (res, funMembers) = td.kind match { case Trt => + if (td.params.fields.nonEmpty) err(msg"trait parameters are not yet supported", td.params.toLoc) + ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols ctx += "this" -> VarSymbol(thisTV, Var("this")) - val sig_ty = typeType(td.sig.getOrElse(Top)) + val sig_ty = td.sig.fold(TopType: ST)(typeTypeSignature) def inherit(parents: Ls[TypedParentSpec], tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) : (ST, Ls[NuMember], Map[Str, NuMember]) = parents match { case (trt: TypedNuTrt, newMembs, tpms, loc) :: ps => inherit(ps, - tags & trt.selfTy, + tags & trt.sign, memberUnion(members, trt.members.values.toList), vms ++ tpms // with type members of parent class ) @@ -969,9 +973,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (tags, baseMems, vms) = inherit(typedParents, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) - // val selfType = tags & sig_ty - val selfType = sig_ty - val ttu = typeTypingUnit(td.body, topLevel = false) val mems = baseMems.map(d => d.name -> d).toMap ++ @@ -982,11 +983,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => implCheck(baseMems, typedSignatureMembers.map(_._2) ++ ttu.entities, true)(td) TypedNuTrt(outerCtx.lvl, td, ttu, - tparams, - mems, - TopType, // thisType (same as Cls) - None, - selfType, + tparams, + mems, + TopType, // thisType (same as Cls) + sig_ty, inheritedTags, vms ) -> Nil @@ -1021,12 +1021,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "this" -> VarSymbol(thisTV, Var("this")) - val sig_ty = typeType(td.sig.getOrElse(Top)) - td.sig match { - case S(sig) => - err(msg"type signatures not yet supported for classes", sig.toLoc) - case N => () - } + val sig_ty = td.sig.fold(TopType: ST)(typeTypeSignature) implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) @@ -1156,7 +1151,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams, typedParams, mems, // if (td.kind is Nms) TopType else thisTV TopType, - TopType, // TODO selfTy: use signature + sig_ty, inheritedTags, ptps )(thisType) -> impltdMems @@ -1255,6 +1250,33 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } + def refreshHelper2(raw: PolyNuDecl, v: Var, parTargs: Opt[Ls[ST]]) + (implicit ctx: Ctx): (MutMap[TV, ST], Map[Str, NuParam]) = { + val freshened: MutMap[TV, ST] = MutMap.empty + val rawName = v.name + + val parTP = raw.tparams.lazyZip(parTargs.getOrElse(Nil)).map { case ((tn, _tv, vi), targ) => + val tv = (targ match { + case tv: TV => + println(s"Passing ${tn.name} :: ${_tv} <=< ${tv}") + tv + case _ => + println(s"Assigning ${tn.name} :: ${_tv} := $targ where ${targ.showBounds}") + val tv = + freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + println(s"Set ${tv} ~> ${_tv}") + assert(tv.assignedTo.isEmpty) + tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") + tv + }) + freshened += _tv -> tv + rawName+"#"+tn.name -> NuParam(tn, FieldType(S(tv), tv)(provTODO))(ctx.lvl) + } + + freshened -> parTP.toMap + } + // intersection of members def memberUnion(l: Ls[NuMember], r: Ls[NuMember])(implicit raise: Raise): Ls[NuMember] = { def merge(ltm: NuMember, rtm: Option[NuMember]) = { diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index c91b7348b6..0ae4f4bf61 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -350,20 +350,25 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val typeType2 = () // val outerCtxLvl = MinLevel + 1 val outerCtxLvl = ctx.lvl + def checkKind(k: DeclKind, nme: Str, loc: Opt[Loc]): Unit = k match { + case Cls | Nms | Als | Trt => () + case _ => err(msg"${k.str} ${nme} cannot be used as a type", loc); () + } def typeNamed(loc: Opt[Loc], name: Str): (() => ST) \/ (TypeDefKind, Int) = newDefsInfo.get(name) .orElse(ctx.tyDefs.get(name).map(td => (td.kind, td.tparamsargs.size))) .orElse(ctx.get(name).flatMap { - case CompletedTypeInfo(mem: TypedNuTypeDef) => S(mem.td.kind, mem.tparams.size) + case CompletedTypeInfo(mem: TypedNuTypeDef) => + checkKind(mem.decl.kind, mem.nme.name, loc) + S(mem.td.kind, mem.tparams.size) case ti: DelayedTypeInfo => + checkKind(ti.decl.kind, ti.decl.name, loc) ti.decl match { case NuTypeDef(k @ (Cls | Nms | Als | Trt), _, tps, _, _, _, _, _, _) => S(k, tps.size) case NuTypeDef(k @ Mxn, nme, tps, _, _, _, _, _, _) => - err(msg"${k.str} ${nme.name} cannot be used as a type", loc) S(k, tps.size) case fd: NuFunDef => - err(msg"function ${fd.nme.name} cannot be used as a type", loc) N } case _ => N @@ -432,7 +437,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case TypeName("this") => ctx.env.get("this") match { case S(AbstractConstructor(_, _)) => die - case S(VarSymbol(t: SimpleType, _)) => t + case S(VarSymbol + (t: SimpleType, _)) => t case N => err(msg"undeclared this" -> ty.toLoc :: Nil) } case tn @ TypeTag(name) => rec(TypeName(name.decapitalize)) // TODO rm this hack @@ -464,7 +470,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case Als => err( msg"Type alias ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) case Nms => err( - msg"Namespaces ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) + msg"Module ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) + case Mxn => err( + msg"Mixin ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) } case _ => e() } @@ -1327,26 +1335,26 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), N, - Nil,//TODO + Nil, // TODO mixin parents? Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, sfty, ihtags, ptps) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, sign, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), - N,//TODO + Option.when(!(TopType <:< sign))(go(sign)), Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, sfty, ihtags, ptps) => + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), - N,//TODO + Option.when(!(TopType <:< sign))(go(sign)), Nil,//TODO N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 391a67c26a..3d8b102679 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1,6 +1,6 @@ package mlscript -import scala.collection.mutable.{Map => MutMap, Set => MutSet, LinkedHashMap, LinkedHashSet} +import scala.collection.mutable.{Map => MutMap, SortedMap => MutSortMap, Set => MutSet, LinkedHashMap, LinkedHashSet} import scala.collection.immutable.{SortedMap, SortedSet} import scala.annotation.tailrec import mlscript.utils._, shorthands._ @@ -791,12 +791,14 @@ abstract class TyperHelpers { Typer: Typer => cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ + S(pol.covar -> cls.sign) ++ S(pol.covar -> cls.instanceType) ++ cls.parentTP.valuesIterator.flatMap(childrenPolMem) case trt: TypedNuTrt => trt.tparams.iterator.map(pol.invar -> _._2) ++ trt.members.valuesIterator.flatMap(childrenPolMem) ++ - S(pol.contravar -> trt.thisTy) ++ + S(pol.contravar -> trt.thisTy) ++ + S(pol.covar -> trt.sign) ++ trt.parentTP.valuesIterator.flatMap(childrenPolMem) case prm: NuParam => childrenPolField(pol)(prm.ty) case TypedNuDummy(d) => N @@ -885,16 +887,17 @@ abstract class TyperHelpers { Typer: Typer => S(mxn.thisTV) case cls: TypedNuCls => cls.tparams.iterator.map(_._2) ++ - // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) cls.params.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil) ++ cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ + S(cls.sign) ++ S(cls.instanceType) case trt: TypedNuTrt => trt.tparams.iterator.map(_._2) ++ - // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) trt.members.valuesIterator.flatMap(childrenMem) ++ - S(trt.thisTy) + S(trt.thisTy) ++ + S(trt.sign) ++ + trt.parentTP.valuesIterator.flatMap(childrenMem) case TypedNuDummy(d) => Nil } ents ::: tu.result.toList @@ -1009,9 +1012,17 @@ abstract class TyperHelpers { Typer: Typer => substSyntax(td.body)(td.tparams.lazyZip(targs).map { case (tp, ta) => SkolemTag(tp._2.level, tp._2)(noProv) -> ta }.toMap) - case S(td: TypedNuTrt) => + case S(td: TypedNuTrt) => assert(td.tparams.size === targs.size) - td.selfTy & + // println(s"EXP ${td.sign}") + val (freshenMap, _) = refreshHelper2(td, Var(td.name).withLoc(prov.loco), S(targs)) // infer ty args if not provided + val freshSelf = { + implicit val freshened: MutMap[TV, ST] = freshenMap + implicit val shadows: Shadows = Shadows.empty + td.sign.freshenAbove(td.level, rigidify = false) + } + // println(s"Fresh $freshSelf") + freshSelf & trtNameToNomTag(td.decl)(provTODO, ctx) & RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi @@ -1020,8 +1031,14 @@ abstract class TyperHelpers { Typer: Typer => })(provTODO) case S(td: TypedNuCls) => assert(td.tparams.size === targs.size) + val (freshenMap, _) = refreshHelper2(td, Var(td.name).withLoc(prov.loco), S(targs)) // infer ty args if not provided + val freshSelf = { + implicit val freshened: MutMap[TV, ST] = freshenMap + implicit val shadows: Shadows = Shadows.empty + td.sign.freshenAbove(td.level, rigidify = false) + } clsNameToNomTag(td.decl)(provTODO, ctx) & - td.selfTy & + freshSelf & RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => // TODO use vi val fldNme = td.nme.name + "#" + tn.name @@ -1041,7 +1058,9 @@ abstract class TyperHelpers { Typer: Typer => // * Definition was not forced yet, which indicates an error (hopefully) lastWords("cannot expand unforced type alias") case d => - wat("unexpected declaration in type reference", d) + // * Other kinds of type defs are not allowed to be used as types + // * (an error should have been reported earlier) + errType } } }.getOrElse { @@ -1185,19 +1204,19 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, _, _, ptps) => + case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, sign, _, ptps) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) - ptps.valuesIterator.foreach(applyMem(pol)) - // thisTy.foreach(apply(pol.invar)(_)) apply(pol.contravar)(thisTy) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, _, ptps) => + apply(pol.contravar)(sign) + ptps.valuesIterator.foreach(applyMem(pol)) + case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, ptps) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) - // thisTy.foreach(apply(pol.invar)(_)) - ptps.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTy) + apply(pol.covar)(sign) + ptps.valuesIterator.foreach(applyMem(pol)) case TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 661f4eea04..da6428181f 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -147,9 +147,9 @@ trait TypeLikeImpl extends Located { self: TypeLike => case (N, _) => "???" case (S(nme), rhs) => nme.name }.mkString(", ") - })${parents match { + })${sig.fold("")(": " + _.showIn(bodyCtx, 0))}${parents match { case Nil => "" - case ps => ps.mkString(", ") // TODO pp + case ps => "extends " + ps.mkString(", ") // TODO pp parent terms... }}${if (body.entities.isEmpty && sup.isEmpty && ths.isEmpty) "" else " {\n" + sup.fold("")(s"${bodyCtx.indStr}super: " + _.showIn(bodyCtx, 0) + "\n") + ths.fold("")(s"${bodyCtx.indStr}this: " + _.showIn(bodyCtx, 0) + "\n") + diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 6d22b5e6c0..dbff16ed02 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -81,14 +81,14 @@ mixin EvalLambda { :ns module Test1 extends EvalVar, EvalLambda //│ module Test1() { -//│ fun eval: forall 'A 'A0 'a 'b 'c. ('d, 'a,) -> ('e | 'c | 'b | 'f) +//│ fun eval: forall 'a 'b 'A 'A0 'c. ('d, 'b,) -> ('e | 'c | 'a | 'f) //│ } //│ where -//│ 'b :> #Abs & {Abs#A = 'A1} +//│ 'a :> #Abs & {Abs#A = 'A1} //│ 'c :> #App & {App#A = 'A2} -//│ 'a <: #App & {App#A <: 'A0} | (#Abs & {Abs#A <: 'A} | 'g & ~#Abs) & ~#App -//│ 'A <: 't -//│ 'A0 <: 't0 & 's +//│ 'b <: #App & {App#A <: 'A} | (#Abs & {Abs#A <: 'A0} | 'g & ~#Abs) & ~#App +//│ 'A0 <: 't +//│ 'A <: 't0 & 's //│ 't0 <: 'h //│ 'h <: #App & {App#A <: 'A3} | (#Abs & {Abs#A <: 'A4} | 'g & ~#Abs) & ~#App //│ 'A4 <: 't @@ -272,7 +272,7 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) :ns module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3() { -//│ fun eval: forall 'a 'b 'A 'A0 'c. ('d, 'a,) -> ('e | 'c | 'b | 'f) +//│ fun eval: forall 'a 'b 'A 'c 'A0. ('d, 'a,) -> ('e | 'c | 'b | 'f) //│ } //│ where //│ 'b :> #Abs & {Abs#A = 'A1} @@ -392,19 +392,19 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3() { -//│ fun eval: forall 'r 'r0 'a 'A 'b 'c 'l 'd 'A0 'l0. ('e, 'a,) -> ('f | 'd | 'a | 'b) +//│ fun eval: forall 'r 'r0 'a 'b 'c 'l 'd 'A 'A0 'l0. ('e, 'b,) -> ('f | 'c | 'b | 'a) //│ } //│ where -//│ 'b :> #Num -//│ 'd :> #Num -//│ 'a <: 'c -//│ 'c <: #Var | (#Num | (#Add & {Add#A <: 'A0} | #Mul & {Mul#A <: 'A} & ~#Add) & ~#Num) & ~#Var -//│ 'A <: 'r0 & 'l0 +//│ 'a :> #Num +//│ 'c :> #Num +//│ 'b <: 'd +//│ 'd <: #Var | (#Num | (#Add & {Add#A <: 'A0} | #Mul & {Mul#A <: 'A} & ~#Add) & ~#Num) & ~#Var +//│ 'A <: 'r & 'l0 //│ 'l0 <: 'g -//│ 'r0 <: 'g -//│ 'A0 <: 'r & 'l -//│ 'l <: 'g //│ 'r <: 'g +//│ 'A0 <: 'r0 & 'l +//│ 'l <: 'g +//│ 'r0 <: 'g //│ 'e :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} //│ <: 'h //│ 'h :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} @@ -434,14 +434,14 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr //│ <: 'A7 //│ 'A7 :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var //│ <: 'result -//│ 'f :> forall 't 'u. 'v | 't | 'u | 'w +//│ 'f :> forall 't 'u. 'v | 'u | 't | 'w //│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) //│ 'w :> #Var | 'result //│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) //│ 'result :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var //│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) -//│ 'u :> #Abs & {Abs#A = 'A8} -//│ 't :> #App & {App#A = 'A5} +//│ 't :> #Abs & {Abs#A = 'A8} +//│ 'u :> #App & {App#A = 'A5} //│ 'v :> forall 'c1 'd1. 'f | 'c1 | 'e1 | 'd1 //│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) //│ 'd1 :> #Num diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index d25a8e8981..fa20f14c70 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -135,13 +135,13 @@ mixin Contains { module TestContains extends Contains //│ module TestContains() { -//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: int, y: int},) -> bool +//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region], {x: int, y: int},) -> bool //│ } //│ where -//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'Region0 <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] +//│ 'a <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] +//│ 'a0 <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] +//│ 'Region <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] // TODO investigate :re @@ -190,16 +190,16 @@ mixin Text { :e module SizeText extends Text -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?a -> (?d | ?e | ?c | ?b | ?f)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?f -> (?c | ?b | ?d | ?e | ?a)}` does not contain member `size` //│ ║ l.184: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?a | ?f | ?b | ?d | ?c)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?c -> (?e | ?d | ?b | ?a | ?f)}` does not contain member `size` //│ ║ l.183: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?a | ?b | ?c | ?f | ?d)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?d -> (?a | ?b | ?f | ?c | ?e)}` does not contain member `size` //│ ║ l.182: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?c -> (?f | ?e | ?d | ?a | ?b)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?b -> (?d | ?f | ?e | ?c | ?a)}` does not contain member `size` //│ ║ l.181: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText() { @@ -272,20 +272,20 @@ mixin IsEmpty { module IsUnivIsEmpty extends IsUniv, IsEmpty //│ module IsUnivIsEmpty() { -//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) -//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) //│ } //│ where -//│ 'Region <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region1 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a3 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a4 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region2 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a2 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a1 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region0 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region2 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a3 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a4 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region1 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a2 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a0 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a1 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ module IsUnivIsEmpty extends IsEmpty, IsUniv //│ module IsUnivIsEmpty() { @@ -339,17 +339,17 @@ mixin Eliminate { module TestElim extends Eliminate //│ module TestElim() { -//│ fun eliminate: forall 'Region 'b 'Region0 'c. (Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> ('d | 'b | 'c) +//│ fun eliminate: forall 'Region 'b 'Region0 'c. (Intersect['Region0] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> ('d | 'c | 'b) //│ } //│ where -//│ 'd :> 'b | 'e -//│ 'b :> Outside['d | 'b | 'f] | Union['d | 'b | 'g | 'h] | Intersect['d | 'b | 'i | 'j] | Translate['d | 'b | 'k] | Scale['d | 'b | 'l] -//│ 'Region <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a0 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a1 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a2 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'k & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'Region0 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'g & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'd :> 'c | 'e +//│ 'c :> Outside['d | 'c | 'f] | Union['d | 'c | 'g | 'h] | Intersect['d | 'c | 'i | 'j] | Translate['d | 'c | 'k] | Scale['d | 'c | 'l] +//│ 'Region0 <: Intersect['Region0] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region] | 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a <: Intersect['Region0] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region] | 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a0 <: Intersect['Region0] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region] | 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a1 <: Intersect['Region0] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region] | 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'a2 <: Intersect['Region0] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region] | 'k & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'Region <: Intersect['Region0] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region] | 'g & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union TestElim.eliminate(Outside(Outside(Univ()))) //│ forall 'a. 'b | 'a @@ -393,7 +393,7 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ module Lang() { //│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: int, y: int},) -> bool //│ fun eliminate: forall 'b 'Region1 'c 'Region2. (Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> ('d | 'c | 'b) -//│ fun isEmpty: forall 'Region3 'Region4. (Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'e) +//│ fun isEmpty: forall 'Region3 'Region4. (Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'e) //│ fun isUniv: forall 'Region5 'Region6. (Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'e) //│ fun size: (Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ) -> int //│ fun text: (Circle | Intersect[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ]) -> string @@ -401,16 +401,16 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ where //│ 'a11 <: Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ //│ 'f <: Circle | Intersect[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] -//│ 'Region4 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region3 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'a5 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'Region6 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'a9 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'a10 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'Region5 <: Intersect['Region6] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region5] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a8 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a6 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a7 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region3 <: Intersect['Region4] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a8 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a6 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a7 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region4 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'd :> 'c | 'g //│ 'c :> Outside['d | 'c | 'h] | Union['d | 'c | 'i | 'j] | Intersect['d | 'c | 'k | 'l] | Translate['d | 'c | 'm] | Scale['d | 'c | 'n] //│ 'Region1 <: Intersect['Region1] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region2] | 'k & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 50fa813698..b77c22157c 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -1,18 +1,14 @@ :NewDefs -// TODO enable class signatures +// FIXME class Exp[A]: Pair | Lit { fun test = if this is Lit then 0 Pair then 1 } -// TODO enable class inheritance class Lit(n: int) extends Exp[int] class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition //│ ║ l.5: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +41,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] //│ ╟── reference of type `#Exp & {Exp#A = ?A}` does not match type `Lit | Pair[?L, ?R]` //│ ║ l.6: fun test = if this is //│ ╙── ^^^^ -//│ class Exp[A]() { +//│ class Exp[A](): Lit | Pair[anything, anything] { //│ fun test: 0 | 1 //│ } //│ class Lit(n: int) @@ -54,7 +50,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[A] :e // TODO Lit(0).test //│ ╔══[ERROR] Type `Lit` does not contain member `test` -//│ ║ l.55: Lit(0).test +//│ ║ l.51: Lit(0).test //│ ╙── ^^^^^ //│ error //│ res @@ -75,7 +71,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.76: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.72: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -88,10 +84,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.88: fun f(x: a) = x +//│ ║ l.84: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.89: f(l) +//│ ║ l.85: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 62b5a1d014..c9609baeb4 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -123,20 +123,36 @@ class Base2(x) extends BaseOf(x + 1), BaseTest //│ } :e -class Base1(x): BaseTest -//│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.126: class Base1(x): BaseTest -//│ ╙── ^ -//│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.126: class Base1(x): BaseTest -//│ ╙── ^^^^^^^^ -//│ class Base1(x: error) +class Base1(x: int): BaseTest +//│ ╔══[ERROR] mixin BaseTest cannot be used as a type +//│ ║ l.126: class Base1(x: int): BaseTest +//│ ╙── ^^^^^^^^ +//│ class Base1(x: int): BaseTest Base1 -//│ (x: error,) -> Base1 +//│ (x: int,) -> (Base1 & BaseTest) //│ res //│ = [Function (anonymous)] { class: [class Base1] } +:e +1 : BaseTest +//│ ╔══[ERROR] mixin BaseTest cannot be used as a type +//│ ║ l.138: 1 : BaseTest +//│ ╙── ^^^^^^^^ +//│ BaseTest +//│ res +//│ = 1 + +:e +error : BaseTest +//│ ╔══[ERROR] mixin BaseTest cannot be used as a type +//│ ║ l.147: error : BaseTest +//│ ╙── ^^^^^^^^ +//│ BaseTest +//│ res +//│ Runtime error: +//│ Error: unexpected runtime error + // :ns mixin Foo { @@ -150,31 +166,31 @@ mixin Foo { :e module Base1(base: int, misc: string) extends Foo //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.167: module Base1(base: int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.167: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'misc' -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.167: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.159: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.159: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.167: module Base1(base: int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.151: module Base1(base: int, misc: string) extends Foo +//│ ║ l.167: module Base1(base: int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.159: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.143: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.159: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ module Base1(base: int, misc: string) { //│ fun test: forall 'a. (int & 'a) -> (int, 'a, nothing,) @@ -257,16 +273,16 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.258: WrapBase1.wrapA("ok") +//│ ║ l.274: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.258: WrapBase1.wrapA("ok") +//│ ║ l.274: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.192: fun wrapA(x: int) = x : int +//│ ║ l.208: fun wrapA(x: int) = x : int //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.202: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.218: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ (int,) | error //│ res diff --git a/shared/src/test/diff/nu/ClassSignatures.mls b/shared/src/test/diff/nu/ClassSignatures.mls index 28fa2581c3..afa6733de1 100644 --- a/shared/src/test/diff/nu/ClassSignatures.mls +++ b/shared/src/test/diff/nu/ClassSignatures.mls @@ -1,22 +1,44 @@ :NewDefs -// TODO class Foo(): {} -//│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.5: class Foo(): {} -//│ ╙── ^^ //│ class Foo() -// TODO class Foo(): {} { fun x = 0 } -//│ ╔══[ERROR] type signatures not yet supported for classes -//│ ║ l.12: class Foo(): {} { -//│ ╙── ^^ //│ class Foo() { //│ fun x: 0 //│ } +class Foo(): { x: int } { + fun x = 0 +} +//│ class Foo(): {x: int} { +//│ fun x: 0 +//│ } + +class Foo(): { x: 'FigureItOut } { + fun x = 0 +} +//│ class Foo(): {x: ??FigureItOut} { +//│ fun x: 0 +//│ } + +:e +not(Foo().x) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.29: not(Foo().x) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── field selection of type `0 & ??FigureItOut` is not an instance of type `bool` +//│ ║ l.29: not(Foo().x) +//│ ╙── ^^^^^^^ +//│ bool | error +//│ res +//│ = true + +(f: Foo) => f.x +//│ (f: Foo,) -> (0 & ??FigureItOut) +//│ res +//│ = [Function: res] diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 836a229ecc..4a6bf95c9f 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -1,5 +1,5 @@ :NewDefs -:NoJS +:NoJS // TODO trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd class LitInt(n: int) extends Expr[int] @@ -9,7 +9,7 @@ class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) extends Expr[T] class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr[(S, T)] class Fst[S, T](p: Expr[(S, T)]) extends Expr[S] class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] -//│ trait Expr[A]() +//│ trait Expr[A](): Add | Cond[?] | Fst[?, ?] | LitBool | LitInt | Pair[?, ?] | Snd[?, ?] //│ class LitInt(n: int) //│ class LitBool(b: bool) //│ class Add(x: Expr[int], y: Expr[int]) @@ -50,10 +50,10 @@ fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.45: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `#Expr & (Add & {Expr#A = ?A} | Cond[?] & {Expr#A = ?A} | Fst[?, ?] & {Expr#A = ?A} | LitBool & {Expr#A = ?A} | LitInt & {Expr#A = ?A} | Pair[?, ?] & {Expr#A = ?A} | Snd[?, ?] & {Expr#A = ?A})` does not match type `Add | LitBool | LitInt` -//│ ║ l.41: fun eval[A](e: Expr[A]): A = -//│ ║ ^^^^^^^ -//│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt` +//│ ╟── type `Cond[?]` does not match type `Add | LitBool | LitInt | ~#Expr` +//│ ║ l.4: trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt | ~#Expr` //│ ║ l.43: e is LitInt(n) then n //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition: diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index e45f057de3..aa2cd050e9 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -373,7 +373,7 @@ class D extends Test[int], Test[bool] trait Base: A | B class A extends Base class B extends Base -//│ trait Base() +//│ trait Base(): A | B //│ class A() //│ class B() @@ -398,7 +398,7 @@ fun f(x: Base) = if x is trait Base: Foo | Bar class Foo[A](aa: (A, A)) extends Base class Bar[B](f: B => B) extends Base -//│ trait Base() +//│ trait Base(): Bar[?] | Foo[anything] //│ class Foo[A](aa: (A, A,)) //│ class Bar[B](f: B -> B) diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls new file mode 100644 index 0000000000..7d6bfe5e44 --- /dev/null +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -0,0 +1,136 @@ +:NewDefs +:NoJS // TODO + + +trait Foo[A] { fun x: A } +//│ trait Foo[A]() { +//│ fun x: A +//│ } + + +trait Base1: Foo +//│ trait Base1(): #Foo + +(b: Base1) => b.x +//│ (b: Base1,) -> ??A + +(b: Base1) => b : Foo +//│ (b: Base1,) -> #Foo + +:e +(b: Base1) => b : Foo['X] +//│ ╔══[ERROR] Type error in type ascription +//│ ║ l.21: (b: Base1) => b : Foo['X] +//│ ║ ^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.21: (b: Base1) => b : Foo['X] +//│ ║ ^^ +//│ ╟── back into type variable `A` +//│ ║ l.5: trait Foo[A] { fun x: A } +//│ ╙── ^ +//│ (b: Base1,) -> Foo['X] +//│ where +//│ 'X :> ??A +//│ <: ??A0 + +:e +1 : Foo[int] +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.37: 1 : Foo[int] +//│ ║ ^ +//│ ╟── integer literal of type `1` is not an instance of type `Foo` +//│ ╟── Note: constraint arises from applied type reference: +//│ ║ l.37: 1 : Foo[int] +//│ ╙── ^^^^^^^^ +//│ Foo[int] + + +trait Base1: Foo { val x: int } +//│ trait Base1(): #Foo { +//│ let x: int +//│ } + +(b: Base1) => b.x +//│ (b: Base1,) -> (int & ??A) + + +trait Base1: Foo[1 | 2] { val x: 0 | 1 } +//│ trait Base1(): Foo[1 | 2] { +//│ let x: 0 | 1 +//│ } + +(b: Base1) => b.x +//│ (b: Base1,) -> 1 + + +trait Base2: Foo['FigureItOut] +//│ trait Base2(): Foo[in ??FigureItOut out ??FigureItOut0] + +(b: Base2) => b.x +//│ (b: Base2,) -> ??FigureItOut + +(b: Base1) => b : Foo +//│ (b: Base1,) -> #Foo + +// :e +(b: Base2) => b : Foo['X] +//│ (b: Base2,) -> Foo['X] +//│ where +//│ 'X :> ??FigureItOut +//│ <: ??FigureItOut0 + + +// TODO reject +class Impl extends Base2 +//│ class Impl() + +(x: Impl) => x : Base2 +//│ (x: Impl,) -> Base2 + +:e +class Impl extends Base2, Foo +//│ ╔══[ERROR] Member x is declared in parent trait but not implemented +//│ ║ l.91: class Impl extends Base2, Foo +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ class Impl() + +class Impl extends Base2, Foo { + fun x = 1 +} +//│ class Impl() { +//│ fun x: 1 +//│ } + +Impl().x +//│ 1 + +Impl() : Base2 +//│ Base2 + +(Impl() : Base2).x +//│ ??FigureItOut + +class Impl2 extends Base2, Foo[int] { + fun x = 1 +} +//│ class Impl2() { +//│ fun x: 1 +//│ } + +(Impl2() : Base2).x +//│ ??FigureItOut + + + +trait Test1[A] { fun x: A } +trait Test2[A]: Test1[(A, A)] +//│ trait Test1[A]() { +//│ fun x: A +//│ } +//│ trait Test2[A](): Test1[(A, A,)] + +(t: Test2[int]) => t.x +//│ (t: Test2[int],) -> (int, int,) + + + diff --git a/shared/src/test/diff/nu/TraitParameters.mls b/shared/src/test/diff/nu/TraitParameters.mls new file mode 100644 index 0000000000..023fa849dc --- /dev/null +++ b/shared/src/test/diff/nu/TraitParameters.mls @@ -0,0 +1,13 @@ +:NewDefs + + +:e +trait Base1(x: int) +//│ ╔══[ERROR] trait parameters are not yet supported +//│ ║ l.5: trait Base1(x: int) +//│ ╙── ^^^^^^^^ +//│ trait Base1() +//│ Code generation encountered an error: +//│ traits are not supported yet. + + diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index a27b35fe4d..e2ef75a355 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -52,9 +52,7 @@ c1.f //│ 'X :> int //│ <: 'FigureItOut //│ 'FigureItOut :> int -//│ <: 'X & 'X0 & int -//│ 'X0 :> int -//│ <: 'FigureItOut +//│ <: 'X & int @@ -69,22 +67,22 @@ class C2 extends T2['FigureItOut] { fun f(x: int) = x } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.64: trait T2[A] { +//│ ║ l.62: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.65: fun f: A -> A +//│ ║ l.63: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.66: val r = C2().f(false) +//│ ║ l.64: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.67: } +//│ ║ l.65: } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.66: val r = C2().f(false) +//│ ║ l.64: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.66: val r = C2().f(false) +//│ ║ l.64: val r = C2().f(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.69: fun f(x: int) = x +//│ ║ l.67: fun f(x: int) = x //│ ╙── ^^^ //│ trait T2[A]() { //│ fun f: A -> A @@ -103,16 +101,16 @@ class C2 extends T2['FigureItOut] { fun f(x: int) = x } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.98: trait T2[A] { +//│ ║ l.96: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.99: fun f: A -> A +//│ ║ l.97: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.100: val r = (C2() : T2['X]).f(false) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.101: } -//│ ╙── ^ +//│ ║ l.98: val r = (C2() : T2['X]).f(false) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.99: } +//│ ╙── ^ //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.98: trait T2[A] { +//│ ║ l.96: trait T2[A] { //│ ╙── ^ //│ trait T2[A]() { //│ fun f: A -> A @@ -125,7 +123,7 @@ class C2 extends T2['FigureItOut] { :e // FIXME C2() : T2['X] //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.98: trait T2[A] { +//│ ║ l.96: trait T2[A] { //│ ╙── ^ //│ T2['X] //│ where From d2d6451e0cb631a91d1acbdc30b78fc378567b1a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 31 May 2023 18:25:55 +0800 Subject: [PATCH 338/498] Fix definition levels, freshening, and inferred pattern type arguments --- .../src/main/scala/mlscript/NuTypeDefs.scala | 109 +++++++------ shared/src/main/scala/mlscript/Typer.scala | 19 +-- .../main/scala/mlscript/TyperHelpers.scala | 2 +- .../test/diff/nu/GenericClassInheritance.mls | 78 ++++++---- shared/src/test/diff/nu/GenericModules.mls | 2 +- .../diff/nu/InheritanceLevelMismatches.mls | 13 +- shared/src/test/diff/nu/Interfaces.mls | 144 ++++++++---------- shared/src/test/diff/nu/NewNew.mls | 42 +++-- 8 files changed, 226 insertions(+), 183 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index f6ef83d2fc..fa6bdd9b27 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -27,7 +27,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind def level: Level - protected def withLevel[R](k: Ctx => R)(implicit ctx: Ctx): R = k(ctx.copy(lvl = level + 1)) + protected def withLevel[R](k: Ctx => R)(implicit ctx: Ctx): R = k(ctx.copy(lvl = ctx.lvl + 1)) def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) @@ -56,7 +56,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuParam = - NuParam(nme, ty.freshenAbove(lim, rigidify))(level) + NuParam(nme, ty.freshenAbove(lim, rigidify))(ctx.lvl) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember = @@ -75,7 +75,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : NuTypeParam = - NuTypeParam(nme, ty.freshenAbove(lim, rigidify))(level) + NuTypeParam(nme, ty.freshenAbove(lim, rigidify))(ctx.lvl) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember = @@ -130,11 +130,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) - : TypedNuAls = withLevel { implicit ctx => - TypedNuAls(level, td, + : TypedNuAls = { val outer = ctx; withLevel { implicit ctx => + TypedNuAls(outer.lvl, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), body.freshenAbove(lim, rigidify)) - } + }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl = @@ -179,8 +179,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) - : TypedNuTrt = withLevel { implicit ctx => - TypedNuTrt(level, td, ttu.freshenAbove(lim, rigidify), + : TypedNuTrt = { val outer = ctx; withLevel { implicit ctx => + TypedNuTrt(outer.lvl, td, ttu.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), @@ -188,7 +188,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inheritedTags, parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap ) - } + }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = @@ -286,17 +286,27 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) - : TypedNuCls = withLevel { implicit ctx => - TypedNuCls(level, td, ttu.freshenAbove(lim, rigidify), - tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), - params.mapValues(_.freshenAbove(lim, rigidify)), - members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - thisTy.freshenAbove(lim, rigidify), - sign.freshenAbove(lim, rigidify), - inheritedTags, - parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap + : TypedNuCls = { val outer = ctx; withLevel { implicit ctx => + // TODO do we even need ttu?! + // * Make sure to freshen tparams frist – and notably, before ttu! + val tparams_ = tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)) + val params_ = params.mapValues(_.freshenAbove(lim, rigidify)) + val members_ = members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap + val thisTy_ = thisTy.freshenAbove(lim, rigidify) + val sign_ = sign.freshenAbove(lim, rigidify) + val inheritedTags_ = inheritedTags + val parentTP_ = parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap + val ttu_ = ttu.freshenAbove(lim, rigidify) + TypedNuCls(outer.lvl, td, ttu_, + tparams_, + params_, + members_, + thisTy_, + sign_, + inheritedTags_, + parentTP_, )(this.instanceType.freshenAbove(lim, rigidify)) - } + }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -324,12 +334,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuMxn( + level: Level, td: NuTypeDef, thisTV: ST, superTV: ST, tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], ttu: TypedTypingUnit, ) extends TypedNuTypeDef(Mxn) with PolyNuDecl { - val level: Level = thisTV.level - 1 // TODO cleaner def decl: NuTypeDef = td def kind: DeclKind = td.kind def nme: TypeName = td.nme @@ -339,11 +349,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) } - + def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) - : TypedNuMxn = withLevel { implicit ctx => - TypedNuMxn(td, + : TypedNuMxn = { val outer = ctx; withLevel { implicit ctx => + TypedNuMxn(outer.lvl, td, thisTV.freshenAbove(lim, rigidify), superTV.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), @@ -351,17 +361,17 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, ttu.freshenAbove(lim, rigidify) ) - } + }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = - TypedNuMxn(td, f(pol.map(!_), thisTV), f(pol.map(!_), superTV), + TypedNuMxn(level, td, f(pol.map(!_), thisTV), f(pol.map(!_), superTV), tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = - TypedNuMxn(td, f(pol.contravar, thisTV), f(pol.contravar, superTV), + TypedNuMxn(level, td, f(pol.contravar, thisTV), f(pol.contravar, superTV), tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) @@ -394,11 +404,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - : TypedNuFun = withLevel { implicit ctx => this match { + : TypedNuFun = { val outer = ctx; withLevel { implicit ctx => this match { case TypedNuFun(level, fd, ty) => - TypedNuFun(level min ctx.lvl, fd, ty.freshenAbove(lim, rigidify)) + TypedNuFun(outer.lvl, fd, ty.freshenAbove(lim, rigidify)) // .tap(res => println(s"Freshen[$level,${ctx.lvl}] $this ~> $res")) - }} + }}} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -421,9 +431,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = - TypedTypingUnit(entities.map(_.freshenAbove(lim, rigidify)//.asInstanceOf[TypedNuTermDef] - ) - , result.map(_.freshenAbove(lim, rigidify))) + TypedTypingUnit(entities.map(_.freshenAbove(lim, rigidify)), result.map(_.freshenAbove(lim, rigidify))) } @@ -601,9 +609,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // println(s"Raw $rawMxn") val (fr, ptp) = refreshHelper(rawMxn, v, if (parTargs.isEmpty) N else S(parTargs)) // type args inferred - implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty - val mxn = rawMxn.freshenAbove(info.level, rigidify = false) + val mxn = { + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + implicit val ctx: Ctx = outerCtx + rawMxn.freshenAbove(info.level, rigidify = false) + } // println(s"Fresh $mxn") val newMembs = { @@ -635,19 +646,30 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if (parArgs.nonEmpty) err(msg"trait arguments are not yet supported", p.toLoc) val (fr, ptp) = refreshHelper(rawTrt, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided - implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty - val trt = rawTrt.freshenAbove(info.level, rigidify = false) + val trt = { + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + implicit val ctx: Ctx = outerCtx + rawTrt.freshenAbove(info.level, rigidify = false) + } val paramMems = Nil // * Maybe support trait params? (not sure) S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) case rawCls: TypedNuCls => + + println(s"Raw $rawCls") + val (fr, ptp) = refreshHelper(rawCls, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided - implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty - val cls = rawCls.freshenAbove(info.level, rigidify = false) - + val cls = { + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + implicit val ctx: Ctx = outerCtx + rawCls.freshenAbove(info.level, rigidify = false) + } + + println(s"Fresh[${ctx.lvl}] $cls") + if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) @@ -1159,6 +1181,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Mxn => if (td.parents.nonEmpty) err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) + val outer = ctx ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) @@ -1169,7 +1192,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val ttu = typeTypingUnit(td.body, topLevel = false) val impltdMems = paramMems ++ ttu.entities val mems = impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers - TypedNuMxn(td, thisTV, superTV, tparams, typedParams, mems, ttu) -> impltdMems + TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams, mems, ttu) -> impltdMems } } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 0ae4f4bf61..096105082e 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1095,7 +1095,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) } case New(S((nmedTy, trm)), TypingUnit(Nil)) => typeMonomorphicTerm(App(Var(nmedTy.base.name).withLocOf(nmedTy), trm)) - case New(base, args) => ??? + case New(base, args) => err(msg"Currently unsupported `new` syntax", term.toCoveringLoc) case TyApp(_, _) => // ??? // TODO handle err(msg"Type application syntax is not yet supported", term.toLoc) @@ -1167,19 +1167,12 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case cls: TypedNuCls => val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) - - val fresh_cls = { - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - cls.freshenAbove(cls.level, rigidify = false).asInstanceOf[TypedNuCls] - } - val ty = - // RecordType.mk(fresh_cls.params)(provTODO) // TODO?! - RecordType.mk(fresh_cls.tparams.map{ - case (tn, tv, vi) => // TODO use variances + RecordType.mk(cls.tparams.map { + case (tn, tv, vi) => + val nv = freshVar(tv.prov, S(tv), tv.nameHint) (Var(nme+"#"+tn.name).withLocOf(tn), - FieldType.mk(fresh_cls.varianceOf(tv), tv, tv)(provTODO)) + FieldType.mk(vi.getOrElse(cls.varianceOf(tv)), nv, nv)(provTODO)) })(provTODO) println(s"Match arm $nme: $tag & $ty") tag -> ty @@ -1330,7 +1323,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(Nil), S(go(body)), Nil, N, N, TypingUnit(Nil))(td.declareLoc) } - case TypedNuMxn(td, thisTy, superTy, tparams, params, members, ttu) => + case TypedNuMxn(level, td, thisTy, superTy, tparams, params, members, ttu) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub))))), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 3d8b102679..379eac4c40 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1217,7 +1217,7 @@ abstract class TyperHelpers { Typer: Typer => apply(pol.contravar)(thisTy) apply(pol.covar)(sign) ptps.valuesIterator.foreach(applyMem(pol)) - case TypedNuMxn(td, thisTV, superTV, tparams, params, members, ttu) => + case TypedNuMxn(level, td, thisTV, superTV, tparams, params, members, ttu) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index df9b7bffc9..452ca892a8 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -14,37 +14,23 @@ class BigRoom extends Room[bool]("big") //│ where //│ 'A := bool -// FIXME +// * Note that this essentially infers Room[Bool] class InferredRoom extends Room("infer") { fun foo(x) = x && true } -//│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.19: fun foo(x) = x && true -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.3: class Room[A](name: string) { -//│ ║ ^ -//│ ╟── into reference of type `bool` -//│ ║ l.19: fun foo(x) = x && true -//│ ╙── ^ -//│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.19: fun foo(x) = x && true -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.19: fun foo(x) = x && true -//│ ║ ^^^^^^^^^ -//│ ╟── adding a type annotation to any of the following terms may help resolve the problem -//│ ╟── • this operator application: -//│ ║ l.19: fun foo(x) = x && true -//│ ╙── ^^^^^^^^^ //│ class InferredRoom() { //│ fun foo: bool -> bool //│ } +InferredRoom() : Room['X] +//│ Room[bool] +//│ res +//│ = InferredRoom {} + :e class TooManyRoom extends Room[int, string]("too many") //│ ╔══[ERROR] class Room expects 1 type parameter(s); got 2 -//│ ║ l.45: class TooManyRoom extends Room[int, string]("too many") +//│ ║ l.31: class TooManyRoom extends Room[int, string]("too many") //│ ╙── ^^^^^^^^^^^^^^^^ //│ class TooManyRoom() { //│ fun foo: (x: 'A,) -> 'A @@ -57,22 +43,22 @@ class WrongRoom extends Room[bool]("wrong") { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.57: fun foo(x) = x + 1 +//│ ║ l.43: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.56: class WrongRoom extends Room[bool]("wrong") { +//│ ║ l.42: class WrongRoom extends Room[bool]("wrong") { //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.57: fun foo(x) = x + 1 +//│ ║ l.43: fun foo(x) = x + 1 //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.57: fun foo(x) = x + 1 +//│ ║ l.43: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── operator application of type `int` is not an instance of type `bool` -//│ ║ l.57: fun foo(x) = x + 1 +//│ ║ l.43: fun foo(x) = x + 1 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.56: class WrongRoom extends Room[bool]("wrong") { +//│ ║ l.42: class WrongRoom extends Room[bool]("wrong") { //│ ║ ^^^^ //│ ╟── from reference: //│ ║ l.4: fun foo(x: A) = x @@ -81,6 +67,38 @@ class WrongRoom extends Room[bool]("wrong") { //│ fun foo: int -> int //│ } + +class C0[A] { val a: A } +//│ class C0[A]() { +//│ let a: A +//│ } + +class C1[A] extends C0[A] +//│ class C1[A]() { +//│ let a: 'A +//│ } +//│ where +//│ 'A := A + +:pe +:e +new C1 : C1[int] +//│ ╔══[PARSE ERROR] Unexpected type ascription after `new` keyword +//│ ║ l.85: new C1 : C1[int] +//│ ╙── ^^ +//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ║ l.85: new C1 : C1[int] +//│ ╙── ^^^ +//│ error +//│ res +//│ = {} + +((new C1) : C1[int]) : C0['X] +//│ C0[int] +//│ res +//│ = C1 {} + + mixin M1[A] { fun f1(x: A): A = x fun f2(x: A): (A, A) = (x, x) @@ -131,14 +149,14 @@ class B2[A](a: int => A) extends M2 :e class E1(a: int) extends M2[bool] //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.132: class E1(a: int) extends M2[bool] +//│ ║ l.150: class E1(a: int) extends M2[bool] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.132: class E1(a: int) extends M2[bool] +//│ ║ l.150: class E1(a: int) extends M2[bool] //│ ║ ^^^^ //│ ╟── from field selection: -//│ ║ l.114: fun m: A = this.a +//│ ║ l.132: fun m: A = this.a //│ ╙── ^^^^^^ //│ class E1(a: int) { //│ fun m: bool diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 5a33006eb5..2f739ae240 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -129,7 +129,7 @@ Test: Test<'a> fun test(x) = if x is Test then x.foo -//│ fun test: forall 'A 'A0. Test[in 'A | 'A0 out 'A] -> 'A0 -> ('A | 'A0) +//│ fun test: forall 'A. Test['A] -> 'A -> 'A :e test(Test) diff --git a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls index 8f1db51149..91ef6f375a 100644 --- a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls +++ b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls @@ -8,14 +8,10 @@ trait T1 { fun x: 0 | 1 } //│ fun x: 0 | 1 //│ } -// FIXME module Foo { trait T2 { fun x: 1 | 2 } class C extends T1, T2 { fun x = 1 } } -//│ ╔══[ERROR] member x has mismatch levels 1 and 2 -//│ ║ l.6: trait T1 { fun x: 0 | 1 } -//│ ╙── ^^^^^^^^ //│ module Foo() { //│ class C() { //│ fun x: 1 @@ -32,10 +28,13 @@ mixin Foo { fun f = this.x } //│ fun f: 'x //│ } -// FIXME module Bar { - class C extends Foo + class C(x: int) extends Foo } -//│ /!!!\ Uncaught error: java.lang.AssertionError: assertion failed +//│ module Bar() { +//│ class C(x: int) { +//│ fun f: int +//│ } +//│ } diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index aa2cd050e9..fb1a2133a5 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -411,56 +411,46 @@ f.aa let b: Base = f //│ let b: Base -// Not sure why this one started failing when it used to extrude in peace -:e if b is Foo(a) then a else 0 -//│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.416: if b is Foo(a) then a else 0 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.399: class Foo[A](aa: (A, A)) extends Base -//│ ║ ^ -//│ ╙── into type `nothing` //│ (??A, ??A,) | 0 -// FIXME? why does it happen in this case and not above? +:e // * Note: an error is raised in this case and not above because B is invariant so it can't be widened if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.427: if b is Bar(f) then f else 0 +//│ ║ l.418: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope //│ ║ l.400: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 -// FIXME? +:e if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.437: if b is +//│ ║ l.428: if b is //│ ║ ^^^^ -//│ ║ l.438: Foo(a) then a +//│ ║ l.429: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.439: Bar(f) then f +//│ ║ l.430: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.399: class Foo[A](aa: (A, A)) extends Base -//│ ║ ^ -//│ ╙── into type `nothing` +//│ ╟── type variable `B` leaks out of its scope +//│ ║ l.400: class Bar[B](f: B => B) extends Base +//│ ╙── ^ //│ anything :e let tt1 = Test //│ ╔══[ERROR] trait Test cannot be used in term position -//│ ║ l.454: let tt1 = Test +//│ ║ l.444: let tt1 = Test //│ ╙── ^^^^ //│ let tt1: error :e fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot match on trait `Test` -//│ ║ l.461: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.451: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -501,40 +491,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.489: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.489: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.489: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.489: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.500: z: WP +//│ ║ l.490: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.479: let z: ZL +//│ ║ l.469: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.500: z: WP +//│ ║ l.490: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.500: z: WP +//│ ║ l.490: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.501: g: ZL +//│ ║ l.491: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.478: let g: Geo +//│ ║ l.468: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.501: g: ZL +//│ ║ l.491: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.501: g: ZL +//│ ║ l.491: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -573,20 +563,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.562: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.562: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.562: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.562: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.533: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2() { //│ fun ce: (Test & 'a) -> (Oth | 'a) @@ -598,32 +588,32 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.597: class Eh extends Bs(1) +//│ ║ l.587: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.597: class Eh extends Bs(1) +//│ ║ l.587: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.542: class Bs(a: bool) { +//│ ║ l.532: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in integer literal: -//│ ║ l.597: class Eh extends Bs(1) +//│ ║ l.587: class Eh extends Bs(1) //│ ║ ^ //│ ╟── integer literal of type `1` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.542: class Bs(a: bool) { +//│ ║ l.532: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.598: class Eh1 extends Bs +//│ ║ l.588: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.533: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.533: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.533: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: int @@ -632,7 +622,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.599: class Eh3 extends Bs(false), Test +//│ ║ l.589: class Eh3 extends Bs(false), Test //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Eh() { //│ fun foo: int -> int @@ -688,7 +678,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.689: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.679: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() @@ -705,11 +695,11 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.706: class Bc31(baz: bool) extends Bc3 +//│ ║ l.696: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.680: let baz : int +//│ ║ l.670: let baz : int //│ ╙── ^^^ //│ class Bc31(baz: bool) @@ -718,18 +708,18 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.718: let foo = true +//│ ║ l.708: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.717: class Bc11 extends Bc1(1) { +//│ ║ l.707: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.718: let foo = true +//│ ║ l.708: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.677: class Bc1(foo: int) +//│ ║ l.667: class Bc1(foo: int) //│ ╙── ^^^ //│ class Bc11() { //│ let foo: true @@ -776,13 +766,13 @@ bp: Base[(int, bool)] :e bp: Base[(int, int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.777: bp: Base[(int, int)] +//│ ║ l.767: bp: Base[(int, int)] //│ ║ ^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.769: let bp: BPar[bool] +//│ ║ l.759: let bp: BPar[bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.777: bp: Base[(int, int)] +//│ ║ l.767: bp: Base[(int, int)] //│ ╙── ^^^ //│ Base[(int, int,)] @@ -826,38 +816,38 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.827: class DerBad1 extends Base[int, int] +//│ ║ l.817: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.827: class DerBad1 extends Base[int, int] +//│ ║ l.817: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class DerBad1() :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.837: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.827: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B]() { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -924,11 +914,11 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.925: class Fischl(age: bool) extends Oz +//│ ║ l.915: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.918: let age: int +//│ ║ l.908: let age: int //│ ╙── ^^^ //│ class Fischl(age: bool) @@ -947,20 +937,20 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.947: fun foo(x) = x && true +//│ ║ l.937: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.947: fun foo(x) = x && true +//│ ║ l.937: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.947: fun foo(x) = x && true +//│ ║ l.937: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.947: fun foo(x) = x && true +//│ ║ l.937: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.939: fun foo(x) = x + 1 +//│ ║ l.929: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go() { //│ fun foo: bool -> bool @@ -977,11 +967,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.978: class Ohhh(x: bool) extends Ha +//│ ║ l.968: class Ohhh(x: bool) extends Ha //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.969: class Ha { let x: int = 1 } +//│ ║ l.959: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index 1221bf856f..2bc6ff6a4d 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -42,35 +42,55 @@ let origin = Point[int](0, 0) //│ origin //│ = Point {} -// FIXME +// TODO let origin = new Point[int](0, 0) //│ ╔══[PARSE ERROR] Unexpected application after `new` keyword //│ ║ l.46: let origin = new Point[int](0, 0) //│ ╙── ^^^^^^^^^^^^^^^^ -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ║ l.46: let origin = new Point[int](0, 0) +//│ ╙── ^^^ +//│ let origin: error +//│ origin +//│ = {} -// FIXME +// TODO new {} //│ ╔══[PARSE ERROR] Unexpected record after `new` keyword -//│ ║ l.54: new {} +//│ ║ l.59: new {} //│ ╙── ^^ -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ║ l.59: new {} +//│ ╙── ^^^ +//│ error +//│ res +//│ = {} -// FIXME +// TODO new //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.61: new +//│ ║ l.71: new //│ ╙── ^ -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ║ l.71: new +//│ ╙── ^^^ +//│ error +//│ res +//│ = {} -// FIXME +// TODO new x: 0 //│ ╔══[PARSE ERROR] Unexpected type ascription after `new` keyword -//│ ║ l.69: x: 0 +//│ ║ l.84: x: 0 //│ ╙── ^ -//│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing +//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ║ l.83: new +//│ ╙── ^^^ +//│ error +//│ res +//│ = {} From 6bc021b5d0de964743123dc5e62fd7e21f87a0d9 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 31 May 2023 23:51:15 +0800 Subject: [PATCH 339/498] Minor changes --- .../src/main/scala/mlscript/NuTypeDefs.scala | 18 +++++++++--------- .../src/main/scala/mlscript/TyperHelpers.scala | 14 +++++++------- shared/src/test/diff/ucs/zipWith.mls | 6 +++++- shared/src/test/scala/mlscript/DiffTests.scala | 10 ++++------ 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index e8d296822d..73174ed88c 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -335,7 +335,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuMxn( level: Level, - td: NuTypeDef, thisTV: ST, superTV: ST, + td: NuTypeDef, thisTy: ST, superTy: ST, tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], ttu: TypedTypingUnit, ) extends TypedNuTypeDef(Mxn) with PolyNuDecl @@ -354,8 +354,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) : TypedNuMxn = { val outer = ctx; withLevel { implicit ctx => TypedNuMxn(outer.lvl, td, - thisTV.freshenAbove(lim, rigidify), - superTV.freshenAbove(lim, rigidify), + thisTy.freshenAbove(lim, rigidify), + superTy.freshenAbove(lim, rigidify), tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, @@ -365,13 +365,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = - TypedNuMxn(level, td, f(pol.map(!_), thisTV), f(pol.map(!_), superTV), + TypedNuMxn(level, td, f(pol.map(!_), thisTy), f(pol.map(!_), superTy), tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = - TypedNuMxn(level, td, f(pol.contravar, thisTV), f(pol.contravar, superTV), + TypedNuMxn(level, td, f(pol.contravar, thisTy), f(pol.contravar, superTy), tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) @@ -1080,11 +1080,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case mxn: TypedNuMxn => assert(finalType.level === lvl) - assert(mxn.superTV.level === lvl) - assert(mxn.thisTV.level === lvl) + assert(mxn.superTy.level === lvl) + assert(mxn.thisTy.level === lvl) - constrain(pack.superType, mxn.superTV) - constrain(finalType, mxn.thisTV) + constrain(pack.superType, mxn.superTy) + constrain(finalType, mxn.thisTy) assert(tpms.isEmpty) // FIXME diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 05060ae702..0c5b74e2a7 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -784,8 +784,8 @@ abstract class TyperHelpers { Typer: Typer => case mxn: TypedNuMxn => mxn.tparams.iterator.map(pol.invar -> _._2) ++ mxn.members.valuesIterator.flatMap(childrenPolMem) ++ - S(pol.contravar -> mxn.superTV) ++ - S(pol.contravar -> mxn.thisTV) + S(pol.contravar -> mxn.superTy) ++ + S(pol.contravar -> mxn.thisTy) case cls: TypedNuCls => cls.tparams.iterator.map(pol.invar -> _._2) ++ // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) @@ -885,8 +885,8 @@ abstract class TyperHelpers { Typer: Typer => case mxn: TypedNuMxn => mxn.tparams.iterator.map(_._2) ++ mxn.members.valuesIterator.flatMap(childrenMem) ++ - S(mxn.superTV) ++ - S(mxn.thisTV) + S(mxn.superTy) ++ + S(mxn.thisTy) case cls: TypedNuCls => cls.tparams.iterator.map(_._2) ++ cls.params.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil) ++ @@ -1221,12 +1221,12 @@ abstract class TyperHelpers { Typer: Typer => apply(pol.contravar)(thisTy) apply(pol.covar)(sign) ptps.valuesIterator.foreach(applyMem(pol)) - case TypedNuMxn(level, td, thisTV, superTV, tparams, params, members, ttu) => + case TypedNuMxn(level, td, thisTy, superTy, tparams, params, members, ttu) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) - apply(pol.contravar)(thisTV) - apply(pol.contravar)(superTV) + apply(pol.contravar)(thisTy) + apply(pol.contravar)(superTy) case NuParam(nme, ty) => applyField(pol)(ty) case TypedNuFun(level, fd, ty) => apply(pol)(ty) case TypedNuDummy(d) => () diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index cf61a1e487..8ef94d7513 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -185,8 +185,12 @@ zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray //│ res //│ = [ [ 0, '0' ], [] ] -zipWith(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))).value.toArray +let ls = zipWith(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))) +ls.value.toArray +//│ let ls: None | Some[Cons[(0 | 1, "0" | "1",)] | Nil] //│ Array[anything] +//│ ls +//│ = Some {} //│ res //│ = [ [ 0, '0' ], [ [ 1, '1' ], [] ] ] diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 45527907df..f7204b8632 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -500,7 +500,6 @@ class DiffTests def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind - // ttu.entities.map(_.complete()(raise)).foreach { ttu.entities.foreach { // case p: typer.NuTypeParam => // output(s"${indStr}${p.name}: ${p.ty}") @@ -519,26 +518,25 @@ class DiffTests showTTU(tc.ttu, ind + 1) case tm: typer.TypedNuMxn => output(s"${indStr}mixin ${tm.name}") - output(s"${indStr} this: ${tm.thisTV} ${tm.thisTV.showBounds + output(s"${indStr} this: ${tm.thisTy} ${tm.thisTy.showBounds .indentNewLines(indStr+" |")}") - output(s"${indStr} super: ${tm.superTV} ${tm.superTV.showBounds + output(s"${indStr} super: ${tm.superTy} ${tm.superTy.showBounds .indentNewLines(indStr+" |")}") - // tm.ttu.entities.foreach { } showTTU(tm.ttu, ind + 1) case tf: typer.TypedNuFun => - // val exp = getType(tf.ty) output(s"${indStr}${tf.fd.isLetRec match { case S(false) => "let" case S(true) => "let rec" case N => "fun" }} ${tf.name}: ${tf.typeSignature} where ${tf.typeSignature.showBounds .indentNewLines(indStr+"|")}") + case typer.TypedNuDummy(d) => + output(s"${indStr} ${d.name}") } } if (mode.dbg || mode.explainErrors) { output("======== TYPED ========") showTTU(tpd, 0) - // output("res: " + tpd.result) tpd.result.foreach { res_ty => output("res: " + tpd.result + " where " + res_ty.showBounds) } From 350f8935c0686ff1d8477e37c307a9ed80b553f4 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 1 Jun 2023 00:15:20 +0800 Subject: [PATCH 340/498] Do not make class pattern typing complete the class --- .../src/main/scala/mlscript/NuTypeDefs.scala | 6 +- shared/src/main/scala/mlscript/Typer.scala | 31 ++- .../main/scala/mlscript/TyperDatatypes.scala | 2 + .../main/scala/mlscript/ucs/Desugarer.scala | 9 +- shared/src/test/diff/gadt/Exp1.mls | 67 ++---- shared/src/test/diff/gadt/Exp2.mls | 78 +++++++ shared/src/test/diff/gadt/ThisMatching.mls | 198 ++++++++++++++++++ shared/src/test/diff/nu/BadUCS.mls | 3 - shared/src/test/diff/nu/ClassesInMixins.mls | 16 +- 9 files changed, 327 insertions(+), 83 deletions(-) create mode 100644 shared/src/test/diff/gadt/Exp2.mls create mode 100644 shared/src/test/diff/gadt/ThisMatching.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 73174ed88c..1f3fff1b83 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1048,8 +1048,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx ++= paramSymbols - ctx += "this" -> VarSymbol(thisTV, Var("this")) - val sig_ty = td.sig.fold(TopType: ST)(typeTypeSignature) implicit val prov: TP = @@ -1131,7 +1129,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => val thisType = WithType(pack.superType, RecordType(typedParams)(ttp(td.params.getOrElse(Tup(Nil)), isType = true)))(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & - RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) + RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) & + sig_ty trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { assert(finalType.level === lvl) @@ -1152,6 +1151,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val Pack(thisType, baseMems, _, bsMembers, ifaceMembers, ptps) = inherit(typedParents, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) + ctx += "this" -> VarSymbol(thisTV, Var("this")) ctx += "super" -> VarSymbol(thisType, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index abab764824..2f9b41d0ea 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1143,7 +1143,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) (fv -> TopType :: Nil) -> typeTerm(b) } case Case(pat, bod, rest) => - val (tagTy: ST, patTy: ST) = pat match { + val (tagTy, patTy) : (ST, ST) = pat match { case lit: Lit => val t = ClassTag(lit, lit.baseClasses)(tp(pat.toLoc, "literal pattern")) t -> t @@ -1156,13 +1156,26 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) return ((e -> e) :: Nil) -> e } ctx.get(nme) match { - case S(td: LazyTypeInfo) => - if ((td.kind isnt Cls) && (td.kind isnt Nms) && (td.kind isnt Trt)) + case S(lti: LazyTypeInfo) => + if ((lti.kind isnt Cls) && (lti.kind isnt Nms) && (lti.kind isnt Trt)) err(msg"can only match on classes and traits", pat.toLoc)(raise) - td.complete() match { - case cls: TypedNuCls => - - val tag = clsNameToNomTag(cls.td)(tp(pat.toLoc, "class pattern"), ctx) + + val prov = tp(pat.toLoc, "class pattern") + + lti match { + case dti: DelayedTypeInfo => + val tag = clsNameToNomTag(dti.decl match { case decl: NuTypeDef => decl; case _ => die })(prov, ctx) + val ty = + RecordType.mk(dti.tparams.map { + case (tn, tv, vi) => + val nv = freshVar(tv.prov, S(tv), tv.nameHint) + (Var(nme+"#"+tn.name).withLocOf(tn), + FieldType.mk(vi.getOrElse(VarianceInfo.in), nv, nv)(provTODO)) + })(provTODO) + println(s"Match arm $nme: $tag & $ty") + tag -> ty + case CompletedTypeInfo(cls: TypedNuCls) => + val tag = clsNameToNomTag(cls.td)(prov, ctx) val ty = RecordType.mk(cls.tparams.map { case (tn, tv, vi) => @@ -1172,9 +1185,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) })(provTODO) println(s"Match arm $nme: $tag & $ty") tag -> ty - - case _ => bail() + case CompletedTypeInfo(_) => bail() } + case _ => err("type identifier not found: " + nme, pat.toLoc)(raise) bail() diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 1e1937351b..5cf1bd0001 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -39,12 +39,14 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => /** Some type information which may not yet be available. */ sealed abstract class LazyTypeInfo extends TypeInfo { def complete()(implicit raise: Raise): NuMember + def isComputing: Bool def kind: DeclKind } /** A LazyTypeInfo whose typing has been completed. */ case class CompletedTypeInfo(member: NuMember) extends LazyTypeInfo { def complete()(implicit raise: Raise): NuMember = member + def isComputing: Bool = false def kind: DeclKind = member.kind } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 7a70b5b2d9..de9b5297c1 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -241,11 +241,10 @@ class Desugarer extends TypeDefs { self: Typer => case app @ App(classNameVar @ Var(className), Tup(args)) => ctx.tyDefs.get(className).map(td => (td.kind, td.positionals)) .orElse(ctx.get(className) match { - case S(ti: LazyTypeInfo) => ti.complete() match { - case td: TypedNuCls => - S((td.decl.kind, td.params.map(_._1.name))) - case _ => throw new DesugaringException(msg"Illegal pattern `$className`", classNameVar.toLoc) - } + case S(ti: DelayedTypeInfo) if ti.decl.kind is Cls => + S((ti.decl.kind, ti.typedParams.map(_._1.name))) + case S(CompletedTypeInfo(td: TypedNuCls)) => + S((td.decl.kind, td.params.map(_._1.name))) case _ => throw new DesugaringException(msg"Illegal pattern `$className`", classNameVar.toLoc) }) match { case N => diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index be926883b2..6d073ad632 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -1,57 +1,13 @@ :NewDefs -// FIXME -class Exp[A]: Pair | Lit { - fun test = if this is - Lit then 0 - Pair then 1 -} +class Exp[A]: Pair | Lit class Lit(n: int) extends Exp[int] -class Pair[L, R](lhs: L, rhs: R) extends Exp[A] -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.6: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.7: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.8: Pair then 1 -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.5: class Exp[A]: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.6: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.7: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.8: Pair then 1 -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.6: fun test = if this is -//│ ║ ^^^^^^^ -//│ ║ l.7: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.8: Pair then 1 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── reference of type `#Exp & {Exp#A = ?A}` does not match type `Lit | Pair[?L, ?R]` -//│ ║ l.6: fun test = if this is -//│ ╙── ^^^^ -//│ class Exp[A]: Lit | Pair[anything, anything] { -//│ fun test: 0 | 1 -//│ } +class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +//│ class Exp[A]: Lit | Pair[anything, anything] //│ class Lit(n: int) //│ class Pair[L, R](lhs: L, rhs: R) -:e // TODO -Lit(0).test -//│ ╔══[ERROR] Type `Lit` does not contain member `test` -//│ ║ l.47: Lit(0).test -//│ ╙── ^^^^^ -//│ error -//│ res -//│ = 0 - fun f(p: Pair['a, 'b]) = p.lhs //│ fun f: forall 'a 'b. (p: Pair['a, 'b],) -> 'a @@ -63,11 +19,22 @@ fun f(e) = if e is // f: (Exp['a] & Pair) -> 0 +fun f(e) = if e is + Pair(l, r) then [l, r] + Lit(n) then n +//│ fun f: forall 'lhs 'rhs. (Lit | Pair['lhs, 'rhs]) -> (('lhs, 'rhs,) | int) + +(e: Exp['X]) => f(e) +//│ (e: Exp['X],) -> ((??L, ??R,) | int) +//│ res +//│ = [Function: res] + + :e // TODO support fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.68: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.35: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -80,10 +47,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.80: fun f(x: a) = x +//│ ║ l.47: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.81: f(l) +//│ ║ l.48: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls new file mode 100644 index 0000000000..5e71c0b170 --- /dev/null +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -0,0 +1,78 @@ +:NewDefs + + +class Exp[A]: Pair | Lit +class Lit(n: int) extends Exp[int] +class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +//│ class Exp[A]: Lit | Pair[?, ?] +//│ class Lit(n: int) +//│ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) + + +fun f(p: Pair['a, 'b]) = p.lhs +//│ fun f: forall 'L 'a 'b. (p: Pair['a, 'b],) -> Exp['L] +//│ where +//│ 'L := 'a + + +fun f(e) = if e is + Pair(l, r) then [l, r] +//│ fun f: forall 'L 'R. Pair['L, 'R] -> (Exp['L], Exp['R],) +// f: (Exp['a] & Pair) -> 0 + + +fun f(e) = if e is + Pair(l, r) then [l, r] + Lit(n) then n +//│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> ((Exp['L], Exp['R],) | int) + +:e +(e: Exp['X]) => f(e) +//│ ╔══[ERROR] Type error in application +//│ ║ l.30: (e: Exp['X]) => f(e) +//│ ║ ^^^^ +//│ ╟── type variable `L` leaks out of its scope +//│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +//│ ╙── ^ +//│ (e: Exp['X],) -> ((Exp['L], Exp['R],) | error | int) +//│ where +//│ 'R :> ??R +//│ <: ??R0 +//│ 'L :> ??L +//│ <: ??L0 +//│ res +//│ = [Function: res] + + +:e +fun f(e) = if e is + Pair(l, r) then f(l) + f(r) + Lit(n) then n +//│ ╔══[ERROR] Type error in definition +//│ ║ l.48: fun f(e) = if e is +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.49: Pair(l, r) then f(l) + f(r) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.50: Lit(n) then n +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── type variable `L` leaks out of its scope +//│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +//│ ╙── ^ +//│ ╔══[ERROR] Type error in definition +//│ ║ l.48: fun f(e) = if e is +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.49: Pair(l, r) then f(l) + f(r) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.50: Lit(n) then n +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── type variable `R` leaks out of its scope +//│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +//│ ╙── ^ +//│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> int +//│ where +//│ 'R :> ??R +//│ <: ??R0 +//│ 'L :> ??L +//│ <: ??L0 + + diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls new file mode 100644 index 0000000000..1471f6e1a7 --- /dev/null +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -0,0 +1,198 @@ +:NewDefs + + +// FIXME prevent use of `this` in ctor +module Dummy { + log(if this is Dummy then "duh!" else "huh?") +} +//│ module Dummy +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +module Dummy { + fun introspect = + if this is Dummy then "duh!" else "huh?" +} +//│ module Dummy { +//│ fun introspect: "duh!" | "huh?" +//│ } + +Dummy.introspect +//│ "duh!" | "huh?" +//│ res +//│ = 'duh!' + + +class Funny: int { fun test = this + 1 } +//│ class Funny: int { +//│ fun test: int +//│ } + +:e +class Unfunny { fun test = this + 1 } +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.32: class Unfunny { fun test = this + 1 } +//│ ║ ^^^^^^ +//│ ╟── reference of type `#Unfunny` is not an instance of type `int` +//│ ║ l.32: class Unfunny { fun test = this + 1 } +//│ ╙── ^^^^ +//│ class Unfunny { +//│ fun test: error | int +//│ } + + +class Exp: Pair | Lit { + fun test = if this is + Lit then 0 + Pair then 1 +} +class Lit(n: int) extends Exp +class Pair(lhs: Exp, rhs: Exp) extends Exp +//│ class Exp: Lit | Pair { +//│ fun test: 0 | 1 +//│ } +//│ class Lit(n: int) { +//│ fun test: 0 | 1 +//│ } +//│ class Pair(lhs: Exp, rhs: Exp) { +//│ fun test: 0 | 1 +//│ } + + +:e // TODO support +class Exp: Pair | Lit { + fun test = if this is + Lit then 0 + Pair(l, r) then 1 +} +class Lit(n: int) extends Exp +class Pair(lhs: Exp, rhs: Exp) extends Exp +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.63: class Exp: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.64: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.65: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.66: Pair(l, r) then 1 +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ +//│ class Exp: Lit | Pair { +//│ fun test: 0 | 1 +//│ } +//│ class Lit(n: int) { +//│ fun test: 0 | 1 +//│ } +//│ class Pair(lhs: Exp, rhs: Exp) + +// TODO +Pair(Lit(1), Lit(2)).test +//│ ╔══[ERROR] Type `Pair` does not contain member `test` +//│ ║ l.88: Pair(Lit(1), Lit(2)).test +//│ ╙── ^^^^^ +//│ error +//│ res +//│ = 1 + + +:e // TODO support? +class Exp: Pair | Lit { + fun test = if this is + Lit then 0 + Pair(l, r) then l.test + r.test +} +class Lit(n: int) extends Exp +class Pair(lhs: Exp, rhs: Exp) extends Exp +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.98: class Exp: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.99: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.100: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.101: Pair(l, r) then l.test + r.test +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.101: Pair(l, r) then l.test + r.test +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.101: Pair(l, r) then l.test + r.test +//│ ╙── ^^^^^ +//│ class Exp: Lit | Pair { +//│ fun test: int +//│ } +//│ class Lit(n: int) { +//│ fun test: int +//│ } +//│ class Pair(lhs: Exp, rhs: Exp) + + +:e // TODO support! +class Exp: Pair | Lit { + fun test : int + fun test = if this is + Lit then 0 + Pair(l, r) then l.test + r.test +} +class Lit(n: int) extends Exp +class Pair(lhs: Exp, rhs: Exp) extends Exp +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.130: class Exp: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.131: fun test : int +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.132: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.133: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.134: Pair(l, r) then l.test + r.test +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ class Exp: Lit | Pair { +//│ fun test: int +//│ } +//│ class Lit(n: int) { +//│ fun test: int +//│ } +//│ class Pair(lhs: Exp, rhs: Exp) + + +:e // TODO support +class Exp[A]: Pair | Lit { + fun test = if this is + Lit then 0 + Pair then 1 +} +class Lit(n: int) extends Exp[int] +class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.159: class Exp[A]: Pair | Lit { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.160: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.161: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.162: Pair then 1 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type error in `case` expression +//│ ║ l.160: fun test = if this is +//│ ║ ^^^^^^^ +//│ ║ l.161: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.162: Pair then 1 +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── type variable `L` leaks out of its scope +//│ ║ l.165: class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +//│ ╙── ^ +//│ class Exp[A]: Lit | Pair[anything, anything] { +//│ fun test: 0 | 1 +//│ } +//│ class Lit(n: int) { +//│ fun test: 0 | 1 +//│ } +//│ class Pair[L, R](lhs: L, rhs: R) + +Lit(0).test +//│ 0 | 1 +//│ res +//│ = 0 + + diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index 8430d79f14..9b419feec6 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -90,9 +90,6 @@ fun foo0(x) = if x is foo() then 0 :e fun foo(x) = if x is foo() then 0 -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.92: fun foo(x) = if x is foo() then 0 -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Illegal pattern `foo` //│ ║ l.92: fun foo(x) = if x is foo() then 0 //│ ╙── ^^^ diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 3fc4bd8d8d..8da5ce8bb8 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -69,7 +69,6 @@ mixin Test3 { fun f(x) = if x is Foo then 1 } -:e // TODO support mixin Test { class Lit(n: int) class Add(lhs: A, rhs: A) { @@ -78,22 +77,13 @@ mixin Test { fun size(x) = if x is Add(l, r) then this.size(l) + this.size(r) } -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.75: class Add(lhs: A, rhs: A) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.76: let cached = size(this) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Illegal pattern `Add` -//│ ║ l.79: Add(l, r) then this.size(l) + this.size(r) -//│ ╙── ^^^ //│ mixin Test() { +//│ this: {size: 'lhs -> int} //│ class Add[A](lhs: A, rhs: A) { -//│ let cached: error +//│ let cached: int //│ } //│ class Lit(n: int) -//│ fun size: anything -> error +//│ fun size: Add['lhs] -> int //│ } -//│ Code generation encountered an error: -//│ if expression was not desugared From 49d452dd0fb479c81ba2d9efcb9fe2acfd532310 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 1 Jun 2023 01:43:29 +0800 Subject: [PATCH 341/498] Try to avoid forcing completion upon field lookup --- .../scala/mlscript/ConstraintSolver.scala | 65 ++--- .../src/main/scala/mlscript/NuTypeDefs.scala | 256 +++++++++--------- .../main/scala/mlscript/TyperHelpers.scala | 2 +- shared/src/test/diff/gadt/ThisMatching.mls | 79 ++---- 4 files changed, 190 insertions(+), 212 deletions(-) diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index c75bbff83f..c87cff476f 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -55,7 +55,7 @@ class ConstraintSolver extends NormalForms { self: Typer => def lookupField(mkType: () => ST, clsNme: Opt[Str], rfnt: Var => Opt[FieldType], tags: SortedSet[AbstractTag], fld: Var) (implicit ctx: Ctx, raise: Raise) : FieldType - = { + = trace(s"Looking up field ${fld.name} in $clsNme & ${tags} & {...}") { val fromRft = rfnt(fld) @@ -64,39 +64,40 @@ class ConstraintSolver extends NormalForms { self: Typer => def getFieldType(info: DelayedTypeInfo): Opt[FieldType] = { // * The raw type of this member, with original references to the class' type variables/type parameters - val raw = if (info.isComputing) { + val raw = (if (info.isComputed) N else info.typedFields.get(fld)) match { - info.typedFields.get(fld) match { - case S(fty) => S(fty) - case N => - // TODO try to use `info.parentSpecs`? - if (info.allFields.contains(fld)) // TODO don't report this if the field can be found somewhere else! - foundRec = S(ErrorReport(msg"Indirectly-recursive member should have type annotation" -> fld.toLoc :: Nil)) - N - } + case S(fty) => S(fty) - } else { - - def handle(virtualMembers: Map[Str, NuMember]): Opt[FieldType] = - virtualMembers.get(fld.name) match { - case S(d: TypedNuFun) => - S(d.typeSignature.toUpper(provTODO)) - case S(p: NuParam) => - S(p.ty) - // case S(p: NuTypeParam) => - // S(p.ty) - case S(m) => - S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) - case N => N - } - - info.complete() match { - case cls: TypedNuCls => handle(cls.virtualMembers) - case trt: TypedNuTrt => handle(trt.virtualMembers) - case mxn: TypedNuMxn => handle(mxn.virtualMembers) - case _ => ??? // TODO - } + case N if info.isComputing => + + if (info.allFields.contains(fld)) // TODO don't report this if the field can be found somewhere else! + foundRec = S(ErrorReport(msg"Indirectly-recursive member should have type annotation" -> fld.toLoc :: Nil)) + + N + case N => + + def handle(virtualMembers: Map[Str, NuMember]): Opt[FieldType] = + virtualMembers.get(fld.name) match { + case S(d: TypedNuFun) => + S(d.typeSignature.toUpper(provTODO)) + case S(p: NuParam) => + S(p.ty) + // case S(p: NuTypeParam) => + // S(p.ty) + case S(m) => + S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) + case N => N + } + + info.complete() match { + case cls: TypedNuCls => handle(cls.virtualMembers) + case trt: TypedNuTrt => handle(trt.virtualMembers) + case mxn: TypedNuMxn => handle(mxn.virtualMembers) + case TypedNuDummy(d) => N + case _ => ??? // TODO + } + } println(s"Lookup ${info.decl.name}.${fld.name} : $raw where ${raw.fold("")(_.ub.showBounds)}") @@ -178,7 +179,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } } - } + }() // def lookupNuTypeDef(clsNme: Str, rfnt: Map[Var, FieldType]) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 1f3fff1b83..b02875ff9d 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -171,12 +171,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name - + lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) } ++ parentTP - + def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) : TypedNuTrt = { val outer = ctx; withLevel { implicit ctx => @@ -562,6 +562,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => var isComputing: Bool = false // Replace by a Ctx entry? var result: Opt[TypedNuDecl] = N + def isComputed: Bool = result.isDefined val level: Level = ctx.lvl @@ -572,8 +573,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => println(s"${ctx.lvl}. Created lazy type info for $decl") - type ParentSpec = (Term, Var, Ls[Type], Ls[Opt[Var] -> Fld]) - val parentSpecs: Ls[ParentSpec] = decl match { + type ParentSpec = (Term, Var, LazyTypeInfo, Ls[Type], Ls[Opt[Var] -> Fld]) + lazy val parentSpecs: Ls[ParentSpec] = decl match { case td: NuTypeDef => td.parents.flatMap { case v @ Var(nme) => @@ -587,6 +588,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case p => err(msg"Unsupported parent specification", p.toLoc) // TODO N + }.flatMap { + case (p, v @ Var(parNme), parTargs, parArgs) => + ctx.get(parNme) match { + case S(lti: LazyTypeInfo) => + S((p, v, lti, parTargs, parArgs)) + case S(_) => + err(msg"Cannot inherit from this", p.toLoc) + N + case N => + err(msg"Could not find definition `${parNme}`", p.toLoc) + N + } } case _ => Nil } @@ -598,117 +611,108 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx ++= paramSymbols parentSpecs.flatMap { - case (p, v @ Var(parNme), parTargs, parArgs) => + case (p, v @ Var(parNme), lti, parTargs, parArgs) => trace(s"${lvl}. Typing parent spec $p") { - ctx.get(parNme) match { - case S(lti: LazyTypeInfo) => - val info = lti.complete() - info match { + val info = lti.complete() + info match { + + case rawMxn: TypedNuMxn => + + // println(s"Raw $rawMxn") + val (fr, ptp) = refreshHelper(rawMxn, v, if (parTargs.isEmpty) N else S(parTargs)) // type args inferred + val mxn = { + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + implicit val ctx: Ctx = outerCtx + rawMxn.freshenAbove(info.level, rigidify = false) + } + // println(s"Fresh $mxn") + + val newMembs = { + if (parArgs.sizeCompare(mxn.params) =/= 0) + err(msg"mixin $parNme expects ${ + mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - case rawMxn: TypedNuMxn => - - // println(s"Raw $rawMxn") - val (fr, ptp) = refreshHelper(rawMxn, v, if (parTargs.isEmpty) N else S(parTargs)) // type args inferred - val mxn = { - implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty - implicit val ctx: Ctx = outerCtx - rawMxn.freshenAbove(info.level, rigidify = false) - } - // println(s"Fresh $mxn") - - val newMembs = { - if (parArgs.sizeCompare(mxn.params) =/= 0) - err(msg"mixin $parNme expects ${ - mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - - val paramMems = mxn.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) - } - - val bodyMems = mxn.ttu.entities // TODO Q: why not `mxn.members`? - - paramMems ++ bodyMems - - } - println(s"Members $newMembs") - - S((mxn, newMembs, - Map.empty[Str, NuMember], // TODO add ptp here once we support explicit type args - p.toLoc - )) - - case rawTrt: TypedNuTrt => - if (parArgs.nonEmpty) err(msg"trait arguments are not yet supported", p.toLoc) + val paramMems = mxn.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + } + + val bodyMems = mxn.ttu.entities // TODO Q: why not `mxn.members`? + + paramMems ++ bodyMems + + } + println(s"Members $newMembs") + + S((mxn, newMembs, + Map.empty[Str, NuMember], // TODO add ptp here once we support explicit type args + p.toLoc + )) + + case rawTrt: TypedNuTrt => + if (parArgs.nonEmpty) err(msg"trait arguments are not yet supported", p.toLoc) - val (fr, ptp) = refreshHelper(rawTrt, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided - val trt = { - implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty - implicit val ctx: Ctx = outerCtx - rawTrt.freshenAbove(info.level, rigidify = false) - } - - val paramMems = Nil // * Maybe support trait params? (not sure) - S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) - - case rawCls: TypedNuCls => - - println(s"Raw $rawCls") - - val (fr, ptp) = refreshHelper(rawCls, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided - val cls = { - implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty - implicit val ctx: Ctx = outerCtx - rawCls.freshenAbove(info.level, rigidify = false) - } - - println(s"Fresh[${ctx.lvl}] $cls") - - if (parArgs.sizeCompare(cls.params) =/= 0) - err(msg"class $parNme expects ${ - cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - - val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) - } - - S((cls, paramMems, ptp ++ cls.parentTP, p.toLoc)) - - case als: TypedNuAls => - // TODO dealias first? - err(msg"Cannot inherit from a type alias", p.toLoc) - N - case als: NuParam => - // TODO first-class mixins/classes... - err(msg"Cannot inherit from a parameter", p.toLoc) - N - // case als: NuTypeParam => - // err(msg"Cannot inherit from a type parameter", p.toLoc) - // Nil - case cls: TypedNuFun => - err(msg"Cannot inherit from a function", p.toLoc) - N - - case cls: TypedNuDummy => - N - + val (fr, ptp) = refreshHelper(rawTrt, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided + val trt = { + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + implicit val ctx: Ctx = outerCtx + rawTrt.freshenAbove(info.level, rigidify = false) } - case S(_) => - err(msg"Cannot inherit from this", p.toLoc) + + val paramMems = Nil // * Maybe support trait params? (not sure) + S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) + + case rawCls: TypedNuCls => + + println(s"Raw $rawCls") + + val (fr, ptp) = refreshHelper(rawCls, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided + val cls = { + implicit val frenshened: MutMap[TV,ST] = fr + implicit val shadows: Shadows = Shadows.empty + implicit val ctx: Ctx = outerCtx + rawCls.freshenAbove(info.level, rigidify = false) + } + + println(s"Fresh[${ctx.lvl}] $cls") + + if (parArgs.sizeCompare(cls.params) =/= 0) + err(msg"class $parNme expects ${ + cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) + + val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + } + + S((cls, paramMems, ptp ++ cls.parentTP, p.toLoc)) + + case als: TypedNuAls => + // TODO dealias first? + err(msg"Cannot inherit from a type alias", p.toLoc) N - case N => - err(msg"Could not find definition `${parNme}`", p.toLoc) + case als: NuParam => + // TODO first-class mixins/classes... + err(msg"Cannot inherit from a parameter", p.toLoc) + N + // case als: NuTypeParam => + // err(msg"Cannot inherit from a type parameter", p.toLoc) + // Nil + case cls: TypedNuFun => + err(msg"Cannot inherit from a function", p.toLoc) N + + case cls: TypedNuDummy => + N + } }() } @@ -719,23 +723,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def lookupTags(parents: Ls[ParentSpec], tags: Set[TypeName]): Set[TypeName] = { parents match { case Nil => tags - case (p, Var(nm), _, _) :: ps => - ctx.get(nm) match { - case S(lti: DelayedTypeInfo) => lti.kind match { + case (p, Var(nm), lti, _, _) :: ps => lti match { + case lti: DelayedTypeInfo => lti.kind match { case Trt | Cls | Nms => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) case _ => lookupTags(ps, tags) } - case S(lti: CompletedTypeInfo) => lti.kind match { - case Trt => lookupTags(ps, - Set.single(TypeName(nm)) union - lti.member.asInstanceOf[TypedNuTrt].inheritedTags union - tags) - case Cls | Nms => lookupTags(ps, - Set.single(TypeName(nm)) union - lti.member.asInstanceOf[TypedNuCls].inheritedTags union - tags) - case _ => lookupTags(ps, tags) - } + case CompletedTypeInfo(trt: TypedNuTrt) => + lookupTags(ps, Set.single(TypeName(nm)) union trt.inheritedTags union tags) + case CompletedTypeInfo(cls: TypedNuCls) => + lookupTags(ps, Set.single(TypeName(nm)) union cls.inheritedTags union tags) case _ => lookupTags(ps, tags) } } @@ -829,16 +825,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => fd.nme.name -> TypedNuFun(level + 1, fd, ty) }.toList + lazy val inheritedFields: Set[Var] = decl match { + case td: NuTypeDef => + parentSpecs.iterator.flatMap(_._3 match { + case dti: DelayedTypeInfo => dti.allFields + case CompletedTypeInfo(m: TypedNuTypeDef) => m.allFields + case _ => Set.empty}).toSet + case _: NuFunDef => Set.empty + } + lazy val allFields: Set[Var] = decl match { case td: NuTypeDef => (td.params.getOrElse(Tup(Nil)).fields.iterator.flatMap(_._1) ++ td.body.entities.iterator.collect { case fd: NuFunDef => fd.nme - }).toSet ++ typedParents.flatMap(_._1.allFields) + }).toSet ++ inheritedFields case _: NuFunDef => Set.empty } lazy val typedFields: Map[Var, FieldType] = - typedParams.toMap ++ typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) + (typedParams.toMap -- inheritedFields /* parameters can be overridden by inherited fields/methods */) ++ + typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) lazy val mutRecTV: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 0c5b74e2a7..232d12d679 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -991,7 +991,7 @@ abstract class TyperHelpers { Typer: Typer => ctx.tyDefs2.get(defn.name).forall(info => // * Object types do not need to be completed in order to be expanded info.kind.isInstanceOf[ObjDefKind] - || info.result.isDefined) + || info.isComputed) def expand(implicit ctx: Ctx, raise: Raise): SimpleType = { ctx.tyDefs2.get(defn.name) match { case S(info) => diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index 1471f6e1a7..52ec85a300 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -1,7 +1,7 @@ :NewDefs -// FIXME prevent use of `this` in ctor +:re // FIXME prevent use of `this` in ctor module Dummy { log(if this is Dummy then "duh!" else "huh?") } @@ -59,7 +59,6 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ } -:e // TODO support class Exp: Pair | Lit { fun test = if this is Lit then 0 @@ -67,34 +66,23 @@ class Exp: Pair | Lit { } class Lit(n: int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.63: class Exp: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.64: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.65: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.66: Pair(l, r) then 1 -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class Exp: Lit | Pair { //│ fun test: 0 | 1 //│ } //│ class Lit(n: int) { //│ fun test: 0 | 1 //│ } -//│ class Pair(lhs: Exp, rhs: Exp) +//│ class Pair(lhs: Exp, rhs: Exp) { +//│ fun test: 0 | 1 +//│ } -// TODO Pair(Lit(1), Lit(2)).test -//│ ╔══[ERROR] Type `Pair` does not contain member `test` -//│ ║ l.88: Pair(Lit(1), Lit(2)).test -//│ ╙── ^^^^^ -//│ error +//│ 0 | 1 //│ res //│ = 1 -:e // TODO support? +:e // TODO can we support this? class Exp: Pair | Lit { fun test = if this is Lit then 0 @@ -102,31 +90,23 @@ class Exp: Pair | Lit { } class Lit(n: int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.98: class Exp: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.99: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.100: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.101: Pair(l, r) then l.test + r.test -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.101: Pair(l, r) then l.test + r.test -//│ ╙── ^^^^^ +//│ ║ l.89: Pair(l, r) then l.test + r.test +//│ ╙── ^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.101: Pair(l, r) then l.test + r.test -//│ ╙── ^^^^^ +//│ ║ l.89: Pair(l, r) then l.test + r.test +//│ ╙── ^^^^^ //│ class Exp: Lit | Pair { //│ fun test: int //│ } //│ class Lit(n: int) { //│ fun test: int //│ } -//│ class Pair(lhs: Exp, rhs: Exp) +//│ class Pair(lhs: Exp, rhs: Exp) { +//│ fun test: int +//│ } -:e // TODO support! class Exp: Pair | Lit { fun test : int fun test = if this is @@ -135,27 +115,18 @@ class Exp: Pair | Lit { } class Lit(n: int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.130: class Exp: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.131: fun test : int -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.132: fun test = if this is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.133: Lit then 0 -//│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.134: Pair(l, r) then l.test + r.test -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Exp: Lit | Pair { //│ fun test: int //│ } //│ class Lit(n: int) { //│ fun test: int //│ } -//│ class Pair(lhs: Exp, rhs: Exp) +//│ class Pair(lhs: Exp, rhs: Exp) { +//│ fun test: int +//│ } -:e // TODO support +:e // TODO support – this requires implementing type member lookup without forced completion (we get constraints like Pair <: Pair#L) class Exp[A]: Pair | Lit { fun test = if this is Lit then 0 @@ -164,23 +135,23 @@ class Exp[A]: Pair | Lit { class Lit(n: int) extends Exp[int] class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.159: class Exp[A]: Pair | Lit { +//│ ║ l.130: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.160: fun test = if this is +//│ ║ l.131: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.161: Lit then 0 +//│ ║ l.132: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.162: Pair then 1 +//│ ║ l.133: Pair then 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.160: fun test = if this is +//│ ║ l.131: fun test = if this is //│ ║ ^^^^^^^ -//│ ║ l.161: Lit then 0 +//│ ║ l.132: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.162: Pair then 1 +//│ ║ l.133: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.165: class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +//│ ║ l.136: class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ ╙── ^ //│ class Exp[A]: Lit | Pair[anything, anything] { //│ fun test: 0 | 1 From 410300b4a6f059472a1cc4c3932531ca0e944bff Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Thu, 1 Jun 2023 09:58:52 +0800 Subject: [PATCH 342/498] Fix trait parents handling --- .../src/main/scala/mlscript/JSBackend.scala | 25 +++++++------------ shared/src/test/diff/nu/ParamOverride.mls | 2 +- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 726bc31617..75d220c62e 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -505,7 +505,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { protected def translateLocalNewType(typeDef: NuTypeDef)(implicit scope: Scope): JSConstDecl = { // TODO: support traitSymbols val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDef :: Nil, false) - if (!traitSymbols.isEmpty) throw CodeGenError("traits are not supported yet.") val sym = classSymbols match { case s :: _ => S(s) @@ -579,22 +578,17 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } private def translateParents(superFields: Ls[Term], constructorScope: Scope)(implicit scope: Scope): Opt[JSExpr] = { - val bases = superFields.map { - case App(lhs, _) => translateTerm(App(lhs, Tup(Ls())))(constructorScope) - case t => translateTerm(t)(constructorScope) - } - - def translateParent(current: JSExpr, base: JSExpr, mixinOnly: Bool): JSExpr = { - val name = current match { - case JSIdent(nme) => nme - case JSInvoke(JSIdent(nme), _) => nme - case JSNew(JSIdent(nme)) => nme - case JSInvoke(JSNew(JSIdent(nme)), _) => nme - case f: JSField => f.property.name - case JSInvoke(f: JSField, _) => f.property.name + def translateParent(current: Term, base: JSExpr, mixinOnly: Bool): JSExpr = { + def resolveName(term: Term): Str = term match { + case App(lhs, _) => resolveName(lhs) + case Var(name) => name + case Sel(_, Var(fieldName)) => fieldName + case TyApp(lhs, _) => resolveName(lhs) case _ => throw CodeGenError("unsupported parents.") } + val name = resolveName(current) + scope.resolveValue(name) match { case Some(CapturedSymbol(_, _: TraitSymbol)) => base // TODO: case Some(CapturedSymbol(out, sym: MixinSymbol)) => @@ -619,7 +613,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // for non-first parent classes, they must be mixins or we would get more than one parent classes, // which is not allowed in JS - bases match { + superFields match { case head :: tail => S(tail.foldLeft( translateParent(head, JSIdent("Object"), false) )((res, next) => translateParent(next, res, true))) @@ -732,7 +726,6 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // TODO: support traitSymbols val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(sym.nested, true)(nuTypeScope) - if (!traitSymbols.isEmpty) throw CodeGenError("traits are not supported yet.") if (keepTopLevelScope) // also declare in the top level for diff tests declareNewTypeDefs(sym.nested, false)(topLevelScope) diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index a0d3f050a4..87a1bec749 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -11,7 +11,7 @@ class Derived0(n: int) extends Base //│ ╙── ^^^^ //│ class Derived0(n: int) //│ Code generation encountered an error: -//│ unresolved symbol Base +//│ unresolved parent Base. mixin Base1(n: number) { From 0feb0653728edf224b59333972f18fc65d74f7a5 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 1 Jun 2023 18:14:25 +0800 Subject: [PATCH 343/498] Remove unnecessary TypedTypingUnit fields from typed type defs --- .../src/main/scala/mlscript/NuTypeDefs.scala | 65 ++++----- shared/src/main/scala/mlscript/Typer.scala | 6 +- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/test/diff/nu/BadClassInherit.mls | 31 ++++ shared/src/test/diff/nu/GenericMixins.mls | 135 +++++++++++++++--- .../diff/nu/InferredInheritanceTypeArgs.mls | 10 +- shared/src/test/diff/nu/ParamImplementing.mls | 38 +++++ .../src/test/scala/mlscript/DiffTests.scala | 4 +- 8 files changed, 220 insertions(+), 75 deletions(-) create mode 100644 shared/src/test/diff/nu/ParamImplementing.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index b02875ff9d..dac8c2d485 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -158,7 +158,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuTrt( - level: Level, td: NuTypeDef, ttu: TypedTypingUnit, + level: Level, td: NuTypeDef, tparams: TyParams, members: Map[Str, NuMember], thisTy: ST, @@ -180,7 +180,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) : TypedNuTrt = { val outer = ctx; withLevel { implicit ctx => - TypedNuTrt(outer.lvl, td, ttu.freshenAbove(lim, rigidify), + TypedNuTrt(outer.lvl, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), @@ -192,7 +192,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = - TypedNuTrt(level, td, ttu, + TypedNuTrt(level, td, tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), @@ -202,7 +202,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = - TypedNuTrt(level, td, ttu, + TypedNuTrt(level, td, tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), @@ -214,7 +214,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuCls( - level: Level, td: NuTypeDef, ttu: TypedTypingUnit, + level: Level, td: NuTypeDef, tparams: TyParams, params: Ls[Var -> FieldType], members: Map[Str, NuMember], @@ -287,30 +287,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) : TypedNuCls = { val outer = ctx; withLevel { implicit ctx => - // TODO do we even need ttu?! - // * Make sure to freshen tparams frist – and notably, before ttu! - val tparams_ = tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)) - val params_ = params.mapValues(_.freshenAbove(lim, rigidify)) - val members_ = members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap - val thisTy_ = thisTy.freshenAbove(lim, rigidify) - val sign_ = sign.freshenAbove(lim, rigidify) - val inheritedTags_ = inheritedTags - val parentTP_ = parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap - val ttu_ = ttu.freshenAbove(lim, rigidify) - TypedNuCls(outer.lvl, td, ttu_, - tparams_, - params_, - members_, - thisTy_, - sign_, - inheritedTags_, - parentTP_, + TypedNuCls(outer.lvl, td, + tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), + params.mapValues(_.freshenAbove(lim, rigidify)), + members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, + thisTy.freshenAbove(lim, rigidify), + sign.freshenAbove(lim, rigidify), + inheritedTags, + parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, )(this.instanceType.freshenAbove(lim, rigidify)) }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuCls(level, td, ttu, + TypedNuCls(level, td, tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, @@ -321,7 +311,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuCls(level, td, ttu, + TypedNuCls(level, td, tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, @@ -334,10 +324,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuMxn( - level: Level, - td: NuTypeDef, thisTy: ST, superTy: ST, + level: Level, td: NuTypeDef, + thisTy: ST, superTy: ST, tparams: TyParams, params: Ls[Var -> FieldType], - members: Map[Str, NuMember], ttu: TypedTypingUnit, + members: Map[Str, NuMember], ) extends TypedNuTypeDef(Mxn) with PolyNuDecl { def decl: NuTypeDef = td @@ -359,7 +349,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), params.mapValues(_.freshenAbove(lim, rigidify)), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - ttu.freshenAbove(lim, rigidify) ) }} @@ -368,13 +357,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuMxn(level, td, f(pol.map(!_), thisTy), f(pol.map(!_), superTy), tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), - members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, ttu) + members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(level, td, f(pol.contravar, thisTy), f(pol.contravar, superTy), tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), - members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, ttu) + members.mapValuesIter(_.mapPolMap(pol)(f)).toMap) } @@ -641,9 +630,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } - val bodyMems = mxn.ttu.entities // TODO Q: why not `mxn.members`? - - paramMems ++ bodyMems + paramMems ++ mxn.members.valuesIterator } println(s"Members $newMembs") @@ -1017,7 +1004,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // check trait overriding implCheck(baseMems, typedSignatureMembers.map(_._2) ++ ttu.entities, true)(td) - TypedNuTrt(outerCtx.lvl, td, ttu, + TypedNuTrt(outerCtx.lvl, td, tparams, mems, TopType, // thisType (same as Cls) @@ -1182,7 +1169,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // overriding check for class/interface inheritance implCheck(bsMembers ++ ifaceMembers, impltdMems, false)(td) - TypedNuCls(outerCtx.lvl, td, ttu, + TypedNuCls(outerCtx.lvl, td, tparams, typedParams, mems, // if (td.kind is Nms) TopType else thisTV TopType, @@ -1203,9 +1190,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "this" -> VarSymbol(thisTV, Var("this")) ctx += "super" -> VarSymbol(superTV, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) - val impltdMems = paramMems ++ ttu.entities + val impltdMems = ttu.entities val mems = impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers - TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams, mems, ttu) -> impltdMems + TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams, mems) -> impltdMems } } @@ -1238,7 +1225,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => result = S(res) res - }() + }(r => s"Completed ${r}") } def typeSignature(implicit raise: Raise): ST = decl match { diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 2f9b41d0ea..75dff2ecde 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1333,7 +1333,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) NuTypeDef(td.kind, td.nme, td.tparams, N, N, S(go(body)), Nil, N, N, TypingUnit(Nil))( td.declareLoc, td.abstractLoc) } - case TypedNuMxn(level, td, thisTy, superTy, tparams, params, members, ttu) => + case TypedNuMxn(level, td, thisTy, superTy, tparams, params, members) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, S(Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub)))))), @@ -1344,7 +1344,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) } - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, sign, ihtags, ptps) => + case TypedNuCls(level, td, tparams, params, members, thisTy, sign, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, Opt.when(td.params.isDefined)(Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub)))))), @@ -1355,7 +1355,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) } - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, ihtags, ptps) => + case TypedNuTrt(level, td, tparams, members, thisTy, sign, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, N, diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 232d12d679..7caf584feb 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1208,20 +1208,20 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, ttu, tparams, params, members, thisTy, sign, _, ptps) => + case TypedNuCls(level, td, tparams, params, members, thisTy, sign, _, ptps) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTy) apply(pol.contravar)(sign) ptps.valuesIterator.foreach(applyMem(pol)) - case TypedNuTrt(level, td, ttu, tparams, members, thisTy, sign, _, ptps) => + case TypedNuTrt(level, td, tparams, members, thisTy, sign, _, ptps) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) members.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTy) apply(pol.covar)(sign) ptps.valuesIterator.foreach(applyMem(pol)) - case TypedNuMxn(level, td, thisTy, superTy, tparams, params, members, ttu) => + case TypedNuMxn(level, td, thisTy, superTy, tparams, params, members) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) params.foreach(p => applyField(pol)(p._2)) members.valuesIterator.foreach(applyMem(pol)) diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index 9b40487714..c0cfeb8fc6 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -51,3 +51,34 @@ class C2 extends C1(this) //│ class C2 +class Foo { fun x: int = 1 } +mixin M { fun x = false } +//│ class Foo { +//│ fun x: int +//│ } +//│ mixin M() { +//│ fun x: false +//│ } + +:e +class Bar extends Foo, M +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.55: mixin M { fun x = false } +//│ ║ ^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `int` +//│ ║ l.55: mixin M { fun x = false } +//│ ║ ^^^^^ +//│ ╟── but it flows into definition of method x with expected type `int` +//│ ║ l.55: mixin M { fun x = false } +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ ^^^ +//│ ╟── from definition of method x: +//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ╙── ^^^^^^^^^^ +//│ class Bar { +//│ fun x: false +//│ } + + diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index cb3687efa2..5de1c6d4be 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -30,15 +30,80 @@ mixin Test[A] { //│ fun foo: A -> A //│ } -class C extends Test { +module C extends Test { fun baz1 = this.foo(0) fun baz2 = this.bar(this.foo) } -//│ class C { -//│ fun bar: forall 'a. 'a -> 'a -//│ fun baz1: 0 -//│ fun baz2: forall 'a. 'a -> 'a -//│ fun foo: forall 'a. 'a -> 'a +//│ module C { +//│ fun bar: ((0 | 'A) -> 'A) -> 'A -> (0 | 'A) +//│ fun baz1: 0 | 'A +//│ fun baz2: 'A -> (0 | 'A) +//│ fun foo: 'A -> (0 | 'A) +//│ } + +C.baz1 +//│ 0 +//│ res +//│ = 0 + +C.foo(1) +//│ 0 | 1 +//│ res +//│ = 1 + +C.foo(false) +//│ 0 | false +//│ res +//│ = false + +module C extends Test[int] { + fun baz1 = this.foo(0) + fun baz2 = this.bar(this.foo) +} +//│ module C { +//│ fun bar: (int -> int) -> int -> int +//│ fun baz1: int +//│ fun baz2: int -> int +//│ fun foo: int -> int +//│ } + +C.baz1 +//│ int +//│ res +//│ = 0 + +C.foo(1) +//│ int +//│ res +//│ = 1 + +:e +C.foo(false) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.81: C.foo(false) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `int` +//│ ║ l.81: C.foo(false) +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.59: module C extends Test[int] { +//│ ║ ^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.22: mixin Test[A] { +//│ ╙── ^ +//│ error | int +//│ res +//│ = false + +class C[A] extends Test[Array[A]] { + fun baz1 = this.foo([]) + fun baz2 = this.bar(this.foo) +} +//│ class C[A] { +//│ fun bar: (Array[A] -> Array[A]) -> Array[A] -> Array[A] +//│ fun baz1: Array[A] +//│ fun baz2: Array[A] -> Array[A] +//│ fun foo: Array[A] -> Array[A] //│ } @@ -59,29 +124,53 @@ mixin Test[A] { class C(arg: int) extends Test //│ class C(arg: int) { -//│ fun bar: (int, int,) +//│ fun bar: ('A | int, 'A | int,) //│ fun baz: int -//│ fun foo: forall 'a. 'a -> 'a +//│ fun foo: 'A -> ('A | int) +//│ } + +let c = C(1) +[c.foo(false), c.bar] +//│ let c: C +//│ (false | int, (int, int,),) +//│ c +//│ = C {} +//│ res +//│ = [ false, [ 1, 1 ] ] + +:e // FIXME +module D extends C(0) { + this.foo(false) +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.143: this.foo(false) +//│ ╙── ^^^^ +//│ module D { +//│ fun bar: forall 'A. ('A | int, 'A | int,) +//│ fun baz: int +//│ fun foo: forall 'A. 'A -> ('A | int) //│ } :e // TODO support or produce better error (arg is not actually recursive) -class C extends Test { +class C extends Test { // it also fails with Test[int]... fun arg = 123 } -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.51: fun baz = foo(this.arg) -//│ ╙── ^^^^ -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.50: fun bar = (this.arg, this.arg) -//│ ╙── ^^^^ -//│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.50: fun bar = (this.arg, this.arg) -//│ ╙── ^^^^ +//│ ╔══[ERROR] Type `#C & {bar: (?A, ?A,), baz: ?a, foo: ?A -> ?A}` does not contain member `arg` +//│ ║ l.116: fun baz = foo(this.arg) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type `#C & {bar: (?A, ?A,), baz: ?a, foo: ?A -> ?A}` does not contain member `arg` +//│ ║ l.115: fun bar = (this.arg, this.arg) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type `#C & {bar: (?A, ?A,), baz: ?a, foo: ?A -> ?A}` does not contain member `arg` +//│ ║ l.115: fun bar = (this.arg, this.arg) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Illegal position for this definition statement. +//│ ║ l.156: fun arg = 123 +//│ ╙── ^^^^^^^^^ //│ class C { -//│ fun arg: 123 -//│ fun bar: (error, error,) +//│ fun bar: ('A | error, 'A | error,) //│ fun baz: error -//│ fun foo: forall 'a. 'a -> 'a +//│ fun foo: 'A -> ('A | error) //│ } class C extends Test { @@ -90,9 +179,9 @@ class C extends Test { } //│ class C { //│ fun arg: int -//│ fun bar: (int, int,) +//│ fun bar: ('A | int, 'A | int,) //│ fun baz: int -//│ fun foo: forall 'a. 'a -> 'a +//│ fun foo: 'A -> ('A | int) //│ } diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 8603cce387..d67af7d181 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -29,22 +29,22 @@ mixin Test2[S, T] { class A1[B](s: bool, t: B) extends Test2[bool, B] //│ class A1[B](s: bool, t: B) { -//│ fun fb: (h: bool,) -> (bool, bool,) +//│ fun fb: bool -> (bool, bool,) //│ fun x: (bool, B,) //│ } // TODO: Investigate type of fb class A2[A](s: A, t: int) extends Test2 //│ class A2[A](s: A, t: int) { -//│ fun fb: (h: 'S,) -> (A, A | 'S,) -//│ fun x: (A, int,) +//│ fun fb: 'S -> (A | 'S, A | 'S,) +//│ fun x: (A | 'S, int,) //│ } // TODO: Investigate type of fb class A3(s: int, t: bool) extends Test2 //│ class A3(s: int, t: bool) { -//│ fun fb: (h: 'S,) -> (int, 'S | int,) -//│ fun x: (int, bool,) +//│ fun fb: 'S -> ('S | int, 'S | int,) +//│ fun x: ('S | int, bool,) //│ } class P(p: int) { diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls new file mode 100644 index 0000000000..7bb6282bb8 --- /dev/null +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -0,0 +1,38 @@ +:NewDefs + +:NoJS // TODO + + +trait T { fun x: int } +mixin M(x: bool) +//│ trait T { +//│ fun x: int +//│ } +//│ mixin M(x: bool) + +:e +class C extends T, M(false) +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.14: class C extends T, M(false) +//│ ║ ^^^^^ +//│ ╟── reference of type `false` is not an instance of type `int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.6: trait T { fun x: int } +//│ ║ ^^^ +//│ ╟── from signature of member x: +//│ ║ l.6: trait T { fun x: int } +//│ ╙── ^^^^^^ +//│ class C + + +trait T { fun x: int } +mixin M(x: number) +//│ trait T { +//│ fun x: int +//│ } +//│ mixin M(x: number) + +class C extends T, M(0) +//│ class C + + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index f7204b8632..5ac84ee450 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -515,14 +515,14 @@ class DiffTests output(s"${indStr}class ${tc.name}") output(s"${indStr} this: ${tc.thisTy} ${tc.thisTy.showBounds .indentNewLines(indStr+" |")}") - showTTU(tc.ttu, ind + 1) + // showTTU(tc.ttu, ind + 1) case tm: typer.TypedNuMxn => output(s"${indStr}mixin ${tm.name}") output(s"${indStr} this: ${tm.thisTy} ${tm.thisTy.showBounds .indentNewLines(indStr+" |")}") output(s"${indStr} super: ${tm.superTy} ${tm.superTy.showBounds .indentNewLines(indStr+" |")}") - showTTU(tm.ttu, ind + 1) + // showTTU(tm.ttu, ind + 1) case tf: typer.TypedNuFun => output(s"${indStr}${tf.fd.isLetRec match { case S(false) => "let" From 2c6a16efd1bee319f78b4cf4f2b953035c1be299 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 2 Jun 2023 15:34:36 +0800 Subject: [PATCH 344/498] Make large refactoring, cleanup, and misc improvements pass Inheritance and abstract class checking are still in flux --- .../scala/mlscript/ConstraintSolver.scala | 4 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 419 ++++++++++-------- .../main/scala/mlscript/TypeSimplifier.scala | 6 +- shared/src/main/scala/mlscript/Typer.scala | 12 +- .../main/scala/mlscript/TyperDatatypes.scala | 9 +- .../main/scala/mlscript/TyperHelpers.scala | 12 +- shared/src/main/scala/mlscript/helpers.scala | 10 +- shared/src/test/diff/codegen/Mixin.mls | 2 +- shared/src/test/diff/codegen/Nested.mls | 8 +- .../src/test/diff/codegen/OptionalParam.mls | 12 +- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 38 +- shared/src/test/diff/gadt/Exp1.mls | 4 +- shared/src/test/diff/gadt/Exp2.mls | 4 +- shared/src/test/diff/gadt/ThisMatching.mls | 20 +- shared/src/test/diff/nu/Abstract.mls | 23 - shared/src/test/diff/nu/AbstractClasses.mls | 153 +++++++ shared/src/test/diff/nu/BadAliases.mls | 18 +- shared/src/test/diff/nu/BadClassInherit.mls | 10 +- shared/src/test/diff/nu/BadClasses.mls | 2 +- shared/src/test/diff/nu/BadSignatures.mls | 100 +++++ .../test/diff/nu/BasicClassInheritance.mls | 31 +- shared/src/test/diff/nu/Dates.mls | 2 +- shared/src/test/diff/nu/Declarations.mls | 8 +- shared/src/test/diff/nu/DiamondInherit.mls | 165 +++++++ shared/src/test/diff/nu/GADTMono.mls | 14 +- .../test/diff/nu/GenericClassInheritance.mls | 31 +- shared/src/test/diff/nu/GenericMethods.mls | 4 +- shared/src/test/diff/nu/GenericMixins.mls | 2 +- shared/src/test/diff/nu/GenericModules.mls | 6 +- .../src/test/diff/nu/ImplicitMethodPolym.mls | 6 +- .../diff/nu/InferredInheritanceTypeArgs.mls | 41 +- .../diff/nu/InheritanceLevelMismatches.mls | 2 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 6 +- shared/src/test/diff/nu/InterfaceMono.mls | 231 ++++++---- shared/src/test/diff/nu/Interfaces.mls | 405 +++++++++-------- shared/src/test/diff/nu/MemberConfusion.mls | 6 +- .../src/test/diff/nu/MemberIntersections.mls | 117 +++++ shared/src/test/diff/nu/MethodSignatures.mls | 12 +- shared/src/test/diff/nu/MixinParameters.mls | 2 +- shared/src/test/diff/nu/ParamImplementing.mls | 6 +- shared/src/test/diff/nu/ParamPassing.mls | 2 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 17 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 247 +++++++---- .../test/diff/nu/TrickyGenericInheritance.mls | 24 +- shared/src/test/diff/nu/TypeAliases.mls | 8 +- shared/src/test/diff/nu/Vals.mls | 31 ++ .../src/test/scala/mlscript/DiffTests.scala | 2 +- 47 files changed, 1538 insertions(+), 756 deletions(-) delete mode 100644 shared/src/test/diff/nu/Abstract.mls create mode 100644 shared/src/test/diff/nu/AbstractClasses.mls create mode 100644 shared/src/test/diff/nu/BadSignatures.mls create mode 100644 shared/src/test/diff/nu/DiamondInherit.mls create mode 100644 shared/src/test/diff/nu/MemberIntersections.mls create mode 100644 shared/src/test/diff/nu/Vals.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index c87cff476f..064786b946 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -258,7 +258,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] val res = // td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] - td.freshenAbove(td.level, rigidify = false).asInstanceOf[TypedNuCls] + td.freshenAbove(td.level, rigidify = false) // println(res) // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) res @@ -642,7 +642,7 @@ class ConstraintSolver extends NormalForms { self: Typer => val info = ctx.tyDefs2(nme) info.typedParams.foreach { p => val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, p._1) - rec(fldTy.lb.get, RecordType(p._1 -> TypeRef(TypeName("Eql"), + rec(fldTy.lb.getOrElse(die), RecordType(p._1 -> TypeRef(TypeName("Eql"), fty.ub // FIXME check mutable? :: Nil )(provTODO).toUpper(provTODO) :: Nil)(provTODO), false) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index dac8c2d485..ce63bced06 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -25,7 +25,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed trait NuMember { def name: Str def kind: DeclKind + def toLoc: Opt[Loc] def level: Level + def isImplemented: Bool protected def withLevel[R](k: Ctx => R)(implicit ctx: Ctx): R = k(ctx.copy(lvl = ctx.lvl + 1)) @@ -51,6 +53,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = if (isType) Als // FIXME? else Val + def toLoc: Opt[Loc] = nme.toLoc + def isImplemented: Bool = true def typeSignature: ST = ty.ub def freshenAbove(lim: Int, rigidify: Bool) @@ -100,6 +104,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } + // TODO rm? /** Those declarations that introduce term names in scope. */ sealed trait TypedNuTermDef extends TypedNuDecl with AnyTypeDef { def typeSignature: ST @@ -109,6 +114,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sealed abstract class TypedNuTypeDef(kind: TypeDefKind) extends TypedNuDecl { def nme: TypeName def decl: NuTypeDef + def toLoc: Opt[Loc] = decl.toLoc def tparams: TyParams def members: Map[Str, NuMember] val allFields: Set[Var] = members.valuesIterator.map(_.name |> Var).toSet @@ -127,7 +133,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def name: Str = nme.name def nme: mlscript.TypeName = td.nme def members: Map[Str, NuMember] = Map.empty - + def isImplemented: Bool = td.sig.isDefined + def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) : TypedNuAls = { val outer = ctx; withLevel { implicit ctx => @@ -140,14 +147,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx): TypedNuDecl = TypedNuAls( level, td, - tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(N, tp._2).assertTV, tp._3)), f(pol, body) ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuDecl = TypedNuAls( level, td, - tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(pol.invar, tp._2).assertTV, tp._3)), f(pol, body) ) } @@ -171,6 +178,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name + def isImplemented: Bool = true lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => @@ -193,7 +201,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = TypedNuTrt(level, td, - tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(N, tp._2).assertTV, tp._3)), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), f(pol, sign), @@ -203,7 +211,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTrt = TypedNuTrt(level, td, - tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(pol.invar, tp._2).assertTV, tp._3)), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), f(pol, sign), @@ -229,6 +237,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name + def isImplemented: Bool = true def typeSignature: ST = typeSignatureOf(td, level, tparams, params, sign, inheritedTags) @@ -301,7 +310,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, - tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(N, tp._2).assertTV, tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), @@ -312,7 +321,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = TypedNuCls(level, td, - tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(pol.invar, tp._2).assertTV, tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), @@ -334,6 +343,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = td.kind def nme: TypeName = td.nme def name: Str = nme.name + def isImplemented: Bool = true lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => @@ -355,13 +365,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(level, td, f(pol.map(!_), thisTy), f(pol.map(!_), superTy), - tparams.map(tp => (tp._1, f(N, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(N, tp._2).assertTV, tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuMxn = TypedNuMxn(level, td, f(pol.contravar, thisTy), f(pol.contravar, superTy), - tparams.map(tp => (tp._1, f(pol.invar, tp._2).asInstanceOf[TV], tp._3)), + tparams.map(tp => (tp._1, f(pol.invar, tp._2).assertTV, tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap) } @@ -371,7 +381,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuDummy(d: NuDecl) extends TypedNuDecl with TypedNuTermDef { def level = MinLevel def kind: DeclKind = Val + def toLoc: Opt[Loc] = N def name: Str = d.name + def isImplemented: Bool = true def typeSignature: ST = errType def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) = @@ -386,50 +398,55 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => /** Note: the type `bodyType` is stored *without* its polymorphic wrapper! (unlike `typeSignature`) */ - case class TypedNuFun(level: Level, fd: NuFunDef, bodyType: ST) extends TypedNuDecl with TypedNuTermDef { + case class TypedNuFun(level: Level, fd: NuFunDef, bodyType: ST)(val isImplemented: Bool) + extends TypedNuDecl with TypedNuTermDef { def kind: DeclKind = Val def name: Str = fd.nme.name + def toLoc: Opt[Loc] = fd.toLoc lazy val typeSignature: ST = PolymorphicType.mk(level, bodyType) def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedNuFun = { val outer = ctx; withLevel { implicit ctx => this match { case TypedNuFun(level, fd, ty) => - TypedNuFun(outer.lvl, fd, ty.freshenAbove(lim, rigidify)) + TypedNuFun(outer.lvl, fd, ty.freshenAbove(lim, rigidify))(isImplemented) // .tap(res => println(s"Freshen[$level,${ctx.lvl}] $this ~> $res")) }}} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuFun(level, fd, f(pol, bodyType)) + TypedNuFun(level, fd, f(pol, bodyType))(isImplemented) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = - TypedNuFun(level, fd, f(pol, bodyType)) + TypedNuFun(level, fd, f(pol, bodyType))(isImplemented) } - case class TypedTypingUnit(entities: Ls[NuMember], result: Opt[ST]) extends OtherTypeLike { + case class TypedTypingUnit(implementedMembers: Ls[NuMember], result: Opt[ST]) extends OtherTypeLike { def map(f: ST => ST)(implicit ctx: Ctx): TypedTypingUnit = - TypedTypingUnit(entities.map(_.map(f)), result.map(f)) + TypedTypingUnit(implementedMembers.map(_.map(f)), result.map(f)) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedTypingUnit = - TypedTypingUnit(entities.map(_.mapPol(pol, smart)(f)), result.map(f(pol, _))) + TypedTypingUnit(implementedMembers.map(_.mapPol(pol, smart)(f)), result.map(f(pol, _))) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedTypingUnit = - TypedTypingUnit(entities.map(_.mapPolMap(pol)(f)), result.map(f(pol, _))) + TypedTypingUnit(implementedMembers.map(_.mapPolMap(pol)(f)), result.map(f(pol, _))) def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = - TypedTypingUnit(entities.map(_.freshenAbove(lim, rigidify)), result.map(_.freshenAbove(lim, rigidify))) + TypedTypingUnit(implementedMembers.map(_.freshenAbove(lim, rigidify)), result.map(_.freshenAbove(lim, rigidify))) } - def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, selfTy: ST, ihtags: Set[TypeName]): ST = td.kind match { + // TODO check this is not misused + def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, selfTy: ST, ihtags: Set[TypeName]) + : ST = td.kind match { case Nms => ClassTag(Var(td.nme.name), ihtags + TN("Eql") // Eql and ihtags (parent tags) )(provTODO) case Cls => + // TODO deal with classes without parameter lists (ie needing `new`) PolymorphicType.mk(level, FunctionType( TupleType(params.mapKeys(some))(provTODO), @@ -471,7 +488,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case fd @ NuFunDef(N, nme, tparams, R(rhs)) => funSigs.updateWith(nme.name) { case S(s) => - err(s"A type signature for '$nme' has already been given", fd.toLoc) + err(s"A type signature for '$nme' was already given", fd.toLoc) S(s) case N => S(fd) } @@ -622,12 +639,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"mixin $parNme expects ${ mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - val paramMems = mxn.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + val paramMems = mxn.params.lazyZip(parArgs).map { + case (nme -> p, _ -> Fld(_, _, a)) => // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } paramMems ++ mxn.members.valuesIterator @@ -656,7 +674,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawCls: TypedNuCls => - println(s"Raw $rawCls") + // println(s"Raw $rawCls") val (fr, ptp) = refreshHelper(rawCls, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided val cls = { @@ -666,7 +684,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => rawCls.freshenAbove(info.level, rigidify = false) } - println(s"Fresh[${ctx.lvl}] $cls") + // println(s"Fresh[${ctx.lvl}] $cls") if (parArgs.sizeCompare(cls.params) =/= 0) err(msg"class $parNme expects ${ @@ -767,7 +785,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (N, Fld(mut, spec, nme: Var)) => // assert(!mut && !spec, "TODO") // TODO // nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) - nme -> FieldType(N, err(msg"Class parameters currently need type annotations", nme.toLoc))(provTODO) + nme -> FieldType(N, err(msg"${td.kind.str.capitalize} parameters currently need type annotations", + nme.toLoc))(provTODO) case _ => ??? } case fd: NuFunDef => Nil @@ -777,15 +796,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => lazy val paramSymbols = typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) // TODO also import signatures from base classes and mixins! - lazy val typedSignatures: Ls[(NuFunDef, ST)] = decl match { + lazy val (typedSignatures, funImplems) : (Ls[(NuFunDef, ST)], Ls[NuFunDef]) = decl match { case td: NuTypeDef => ctx.nest.nextLevel { implicit ctx => val (signatures, rest) = td.body.entities.partitionMap { - case fd @ NuFunDef(N, nme, tparams, R(rhs)) => + case fd @ NuFunDef(N | S(false), nme, tparams, R(rhs)) => // currently `val`s are encoded with `S(false)` L((fd, rhs)) // TODO also pick up signature off implems with typed params/results case s => R(s) } - // TODO use `rest` + val implems = rest.collect { case fd @ NuFunDef(N | S(false), nme, tparams, L(rhs)) => fd } ctx ++= paramSymbols @@ -798,19 +817,21 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } |> { implicit vars => typeType(rhs).withProv( - TypeProvenance(Loc(rhs :: fd.nme :: fd.tparams), s"signature of member ${fd.nme.name}") + TypeProvenance(Loc(rhs :: fd.nme :: fd.tparams), s"signature of member `${fd.nme.name}`") ) } }) - } + } -> implems } - case _: NuFunDef => Nil + case _: NuFunDef => Nil -> Nil } - lazy val typedSignatureMembers: Ls[Str -> TypedNuFun] = + lazy val typedSignatureMembers: Ls[Str -> TypedNuFun] = { + val implemented = funImplems.iterator.map(_.nme.name).toSet typedSignatures.iterator.map { case (fd, ty) => - fd.nme.name -> TypedNuFun(level + 1, fd, ty) + fd.nme.name -> TypedNuFun(level + 1, fd, ty)(implemented.contains(fd.nme.name)) }.toList + } lazy val inheritedFields: Set[Var] = decl match { case td: NuTypeDef => @@ -875,9 +896,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => checkNoTyParams() val body_ty = ctx.poly { implicit ctx: Ctx => typeType(ty)(ctx, raise, - vars = vars ++ tps.map(tp => tp.asInstanceOf[L[TN]].value.name -> freshVar(provTODO, N)(1)).toMap) + vars = vars ++ tps.map { + case L(tn) => tn.name -> freshVar(provTODO, N)(1) + case _ => die + }.toMap) } - TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty)) + TypedNuFun(ctx.lvl, fd, PolymorphicType(ctx.lvl, body_ty))(isImplemented = false) case R(_) => die case L(body) => fd.isLetRec match { @@ -886,11 +910,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => implicit val gl: GenLambdas = true TypedNuFun(ctx.lvl, fd, typeTerm( Let(true, fd.nme, body, fd.nme) - )) + ))(isImplemented = true) case S(false) => // * Let bindings checkNoTyParams() implicit val gl: GenLambdas = true - TypedNuFun(ctx.lvl, fd, typeTerm(body)) + TypedNuFun(ctx.lvl, fd, typeTerm(body))(isImplemented = true) case N => // * We don't type functions polymorphically from the point of view of a typing unit // * to avoid cyclic-looking constraints due to the polymorphic recursion limitation, @@ -913,13 +937,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * especially in the context of open recursion and mixins. if (ctx.lvl === 1 || fd.signature.nonEmpty) typeTerm(body) - else outer_ctx |> { + else outer_ctx |> { implicit ctx: Ctx => println(s"Not typing polymorphicall (cf. not top level or not annotated)") - println(typedSignatureMembers) - implicit ctx: Ctx => typeTerm(body) } + typeTerm(body) } } }.withProv(TypeProvenance(fd.toLoc, s"definition of method ${fd.nme.name}")) - TypedNuFun(ctx.lvl, fd, body_ty) + TypedNuFun(ctx.lvl, fd, body_ty)(isImplemented = true) } } ctx.nextLevel { implicit ctx: Ctx => constrain(res_ty.bodyType, mutRecTV) } @@ -928,11 +951,82 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case td: NuTypeDef => - val signatures = typedSignatures - ctx ++= signatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) - + + def implemCheck(membersToImplem: Ls[NuMember], implems: Ls[NuMember]): Unit = { + + val implemsMap = MutMap.empty[Str, NuMember] + implems.foreach { m => + implemsMap.updateWith(m.name) { + case S(_) => + err(msg"Duplicated `${m.name}` member definition in `${td.name}`", m.toLoc) + N + case N => S(m) + } + } + + membersToImplem.foreach { m => + lazy val parSign = m match { + case nt: TypedNuTermDef => nt.typeSignature + case np: NuParam => np.typeSignature + case _ => ??? // probably no other cases + } + implemsMap.get(m.name) match { + case S(mem: TypedNuTermDef) => + val memSign = mem.typeSignature + implicit val prov: TP = memSign.prov + println(s"Checking overriding of `${m.name}`") + constrain(memSign, parSign) + case S(pm: NuParam) => + val pmSign = pm.typeSignature + implicit val prov: TP = pmSign.prov + constrain(pmSign, parSign) + case S(_) => () + case N => + if (!td.isDecl && td.kind =/= Trt && !td.isAbstract) + err(msg"Member `${m.name}` is declared in parent but not implemented" -> td.toLoc :: + msg"Declared here:" -> m.toLoc :: + Nil) + } + } + + } + + + // intersection of members + def membersInter(l: Ls[NuMember], r: Ls[NuMember]): Ls[NuMember] = { + def merge(ltm: NuMember, rtm: Option[NuMember]) = { + rtm.foreach(rtm => assert(rtm.level === ltm.level, (ltm.level, rtm.level))) + (ltm, rtm) match { + case (a: TypedNuFun, S(b: TypedNuFun)) => + assert(!(a.isImplemented && b.isImplemented)) + val fd = NuFunDef((a.fd.isLetRec, b.fd.isLetRec) match { + case (S(a), S(b)) => S(a || b) + case _ => N // if one is fun, then it will be fun + }, a.fd.nme, a.fd.tparams, a.fd.rhs)(a.fd.declareLoc, N) + S(TypedNuFun(a.level, fd, a.bodyType & b.bodyType)(a.isImplemented || b.isImplemented)) + case (a: NuParam, S(b: NuParam)) => + S(NuParam(a.nme, a.ty && b.ty)(a.level)) + case (a: NuParam, S(b: TypedNuFun)) => + S(TypedNuFun(a.level, b.fd, a.ty.ub & b.bodyType)(a.isImplemented || b.isImplemented)) + case (a: TypedNuFun, S(b: NuParam)) => + S(TypedNuFun(a.level, a.fd, b.ty.ub & a.bodyType)(a.isImplemented || b.isImplemented)) + case (a, N) => S(a) + case (a, S(b)) => + err(msg"Intersection of ${a.kind.str} member and ${b.kind.str} members currently unsupported" -> td.toLoc + :: msg"The ${a.kind.str} member is defined here:" -> a.toLoc + :: msg"The ${b.kind.str} member is defined here:" -> b.toLoc + :: Nil) + N + } + } + l.foldLeft(r.map(d => d.name -> d).toMap) { case (acc, ltm) => + acc.updatedWith(ltm.name)(merge(ltm, _)) + }.values.toList + } + + if (((td.kind is Nms) || (td.kind is Mxn)) && td.ctor.isDefined) - err(msg"Explicit ${td.kind.str} constructors are not supported.", + err(msg"Explicit ${td.kind.str} constructors are not supported", td.ctor.fold[Opt[Loc]](N)(c => c.toLoc)) // * To type signatures correctly, we need to deal with type unbound variables 'X, @@ -974,58 +1068,68 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols + ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) ctx += "this" -> VarSymbol(thisTV, Var("this")) val sig_ty = td.sig.fold(TopType: ST)(typeTypeSignature) - def inherit(parents: Ls[TypedParentSpec], tags: ST, members: Ls[NuMember], vms: Map[Str, NuMember]) + def inherit(parents: Ls[TypedParentSpec], tags: ST, members: Ls[NuMember], tparamMembs: Map[Str, NuMember]) : (ST, Ls[NuMember], Map[Str, NuMember]) = parents match { case (trt: TypedNuTrt, newMembs, tpms, loc) :: ps => inherit(ps, tags & trt.sign, - memberUnion(members, trt.members.values.toList), - vms ++ tpms // with type members of parent class + membersInter(members, trt.members.values.toList), + tparamMembs ++ tpms // with type members of parent class ) case (_, _, _, loc) :: ps => - err(msg"trait can only inherit from traits", loc) - inherit(ps, tags, members, vms) - case Nil => (tags, members, vms) + err(msg"A trait can only inherit from other traits", loc) + inherit(ps, tags, members, tparamMembs) + case Nil => (tags, members, tparamMembs) } - val (tags, baseMems, vms) = + val (tags, trtMembers, tparamMembs) = inherit(typedParents, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) + td.body.entities.foreach { + case fd @ NuFunDef(_, _, _, L(_)) => + err(msg"Method implementations in traits are not yet supported", fd.toLoc) + case _ => + } + val ttu = typeTypingUnit(td.body, topLevel = false) - val mems = - baseMems.map(d => d.name -> d).toMap ++ - typedSignatureMembers.toMap ++ - ttu.entities.map(d => d.name -> d).toMap - + + val allMembers = ( + trtMembers.iterator.map(d => d.name -> d) + ++ ttu.implementedMembers.map(d => d.name -> d) + ++ typedSignatureMembers + ).toMap + // check trait overriding - implCheck(baseMems, typedSignatureMembers.map(_._2) ++ ttu.entities, true)(td) - + // implemCheck(trtMembers, typedSignatureMembers.map(_._2) ++ ttu.implementedMembers) + implemCheck(trtMembers, typedSignatureMembers.map(_._2)) + TypedNuTrt(outerCtx.lvl, td, tparams, - mems, + allMembers, TopType, // thisType (same as Cls) sig_ty, inheritedTags, - vms + tparamMembs ) -> Nil } case Als => if (td.params.getOrElse(Tup(Nil)).fields.nonEmpty) - err(msg"type alias definitions cannot have value parameters" -> td.params.getOrElse(Tup(Nil)).toLoc :: Nil) + err(msg"Type alias definitions cannot have value parameters" -> td.params.getOrElse(Tup(Nil)).toLoc :: Nil) if (td.parents.nonEmpty) - err(msg"type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) + err(msg"Type alias definitions cannot extend parents" -> Loc(td.parents) :: Nil) val body_ty = td.sig match { case S(sig) => typeType(sig) case N => - err(msg"type alias definition requires a right-hand side", td.toLoc) + err(msg"Type alias definition requires a right-hand side", td.toLoc) } TypedNuAls(outerCtx.lvl, td, tparams, body_ty) -> Nil @@ -1040,6 +1144,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => Loc(typedParams.iterator.map(_._1))) ctx ++= paramSymbols + ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) val sig_ty = td.sig.fold(TopType: ST)(typeTypeSignature) @@ -1057,11 +1162,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class Pack( superType: ST, - clsMem: Ls[NuMember], - bsCls: Opt[Str], - bsMem: Ls[NuMember], - trtMem: Ls[NuMember], - pTP: Map[Str, NuMember] + mxnMembers: Ls[NuMember], + baseClsNme: Opt[Str], + baseClsMembers: Ls[NuMember], + traitMembers: Ls[NuMember], + tparamMembers: Map[Str, NuMember] ) def inherit(parents: Ls[TypedParentSpec], pack: Pack): Pack = parents match { @@ -1082,7 +1187,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val newSuperType = WithType( pack.superType, RecordType( - newMembs.collect{ + newMembs.collect { case m: NuParam => m.nme.toVar -> m.ty case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) } @@ -1090,29 +1195,30 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )(provTODO) inherit(ps, pack.copy( - superType = newSuperType, - clsMem = pack.clsMem ++ newMembs // FIXME add `mxn.members.values.toList`? + superType = newSuperType, + // mxnMembers = pack.mxnMembers ++ newMembs // FIXME add `mxn.members.values.toList`? + mxnMembers = newMembs ++ pack.mxnMembers )) case trt: TypedNuTrt => inherit(ps, pack.copy( - trtMem = memberUnion(pack.trtMem, trt.members.values.toList), - pTP = pack.pTP ++ tpms + traitMembers = membersInter(pack.traitMembers, trt.members.valuesIterator.toList), + tparamMembers = pack.tparamMembers ++ tpms )) case cls: TypedNuCls => val parNme = cls.nme.name - pack.bsCls.foreach { cls => + pack.baseClsNme.foreach { cls => err(msg"cannot inherit from more than one base class: ${ cls} and ${parNme}", loc) } inherit(ps, pack.copy( - bsCls = S(parNme), - bsMem = newMembs ++ cls.members.values.toList, - pTP = pack.pTP ++ tpms + baseClsNme = S(parNme), + baseClsMembers = newMembs ++ cls.members.valuesIterator.toList, + tparamMembers = pack.tparamMembers ++ tpms )) case als: TypedNuAls => // Should be rejected in `typedParents` @@ -1128,7 +1234,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { assert(finalType.level === lvl) constrain(thisType, finalType) - pack.clsMem }() // println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") @@ -1141,56 +1246,89 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) - val Pack(thisType, baseMems, _, bsMembers, ifaceMembers, ptps) = + val Pack(thisType, mxnMembers, _, baseClsMembers, traitMembers, tparamMembers) = inherit(typedParents, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) ctx += "this" -> VarSymbol(thisTV, Var("this")) ctx += "super" -> VarSymbol(thisType, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) - // local members overrides mixin members - val cmems = ttu.entities ++ baseMems.flatMap { m => - ttu.entities.find(x => x.name == m.name) match { - case S(mem: TypedNuTermDef) => Nil - case S(pm: NuParam) => Nil - case _ => m :: Nil - } - } - // local members overrides parent members - val impltdMems = cmems ++ bsMembers.flatMap { m => - cmems.find(x => x.name == m.name) match { - case S(mem: TypedNuTermDef) => Nil - case S(pm: NuParam) => Nil - case _ => m :: Nil + + // val impltdMems = + // // (baseClsMembers ++ mxnMembers ++ ttu.implementedMembers).distinctBy(_.name) + // (ttu.implementedMembers ++ mxnMembers ++ baseClsMembers).distinctBy(_.name) + + val memberNames = MutSet.empty[Str] + + // val definedMembers = ttu.implementedMembers + // memberNames ++= definedMembers.map(_.name) + // println(s"DM ${definedMembers}") + + val (baseClsImplemMembers, baseClsIfaceMembers) = + baseClsMembers.partition(_.isImplemented) + + val impltdMems = + (ttu.implementedMembers ++ mxnMembers ++ baseClsImplemMembers) + .filter(m => memberNames.add(m.name)) // TODD distinctBy + + // println(ttu.implementedMembers) + // println(impltdMems_old) + // println(impltdMems) + + // overriding check for class/interface inheritance + // implCheck(baseClsMembers ++ traitMembers, impltdMems, td.isAbstract)(td) + + // implemCheck(baseClsMembers ::: traitMembers, impltdMems) + val ifaceMembers = membersInter(baseClsMembers, traitMembers) + implemCheck(ifaceMembers, impltdMems) + + + val ifaceMembersMap = ifaceMembers.map(m => m.name -> m).toMap + // * ^ Note: there isn't supposed to be any meaningful duplicates in `ifaceMembers` + + // * Check signatures provided in this class against imherited signatures + typedSignatureMembers.foreach { case (nme, fun) => + ifaceMembersMap.get(nme) match { + case Some(m: TypedNuFun) => + implicit val prov: TP = + TypeProvenance(fun.toLoc, fun.fd.describe) + constrain(fun.typeSignature, m.typeSignature) + case Some(m) => + err(msg"Cannot override base ${m.kind.str} member `${nme}`", fun.fd.toLoc) + case None => } } - val mems = impltdMems.map(d => d.name -> d).toMap ++ typedSignatureMembers - - // overriding check for class/interface inheritance - implCheck(bsMembers ++ ifaceMembers, impltdMems, false)(td) + + + val allMembers = + (ifaceMembers ++ impltdMems).map(d => d.name -> d).toMap ++ typedSignatureMembers + + // // println(allMembers.map(m => (m._2, m._2.isImplemented))) + // println(allMembers.values.map(m => (m, m.isImplemented))) TypedNuCls(outerCtx.lvl, td, - tparams, typedParams, mems, - // if (td.kind is Nms) TopType else thisTV + tparams, typedParams, allMembers, TopType, sig_ty, inheritedTags, - ptps + tparamMembers )(thisType) -> impltdMems } + case Mxn => if (td.parents.nonEmpty) err(msg"mixin definitions cannot yet extend parents" -> Loc(td.parents) :: Nil) val outer = ctx ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols + ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) val thisTV = freshVar(provTODO, N, S("this")) val superTV = freshVar(provTODO, N, S("super")) ctx += "this" -> VarSymbol(thisTV, Var("this")) ctx += "super" -> VarSymbol(superTV, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) - val impltdMems = ttu.entities + val impltdMems = ttu.implementedMembers val mems = impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams, mems) -> impltdMems } @@ -1199,7 +1337,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO check member duplication? in mems or before? // * Check signatures - // val isAbstract = // TODO ctx.nextLevel { implicit ctx: Ctx => typedSignatures.foreach { case (fd, sign) => implicit val prov: TP = sign.prov @@ -1211,8 +1348,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(mem: NuParam) => case S(_) => ??? // TODO case N => - if (!td.isDecl && td.kind != Trt) - err(msg"Member ${fd.nme.name} is declared but not defined", fd.nme.toLoc) + if (!td.isDecl && td.kind != Trt && !td.isAbstract) + err(msg"Member `${fd.nme.name}` is declared but not defined", fd.nme.toLoc) } } } @@ -1246,32 +1383,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => s"${decl.name} ~> ${if (isComputing) "" else result.fold("")(_.toString)}" } - - private def implCheck(abst: Ls[NuMember], impl: Ls[NuMember], isTrt: Bool)(td: NuTypeDef) - (implicit raise: Raise, ctx: Ctx): Unit = { - abst.foreach { m => - lazy val parSign = m match { - case nt: TypedNuTermDef => nt.typeSignature - case np: NuParam => np.typeSignature - case _ => ??? // probably no other cases - } - impl.find(x => x.name === m.name) match { - case S(mem: TypedNuTermDef) => - val memSign = mem.typeSignature - implicit val prov: TP = memSign.prov - println(s"checking overriding `${m.name}`") - constrain(memSign, parSign) - case S(pm: NuParam) => - val pmSign = pm.typeSignature - implicit val prov: TP = pmSign.prov - constrain(pmSign, parSign) - case S(_) => () - case N => - if (!isTrt) - err(msg"Member ${m.name} is declared in parent trait but not implemented", td.toLoc) - } - } - } def refreshHelper2(raw: PolyNuDecl, v: Var, parTargs: Opt[Ls[ST]]) (implicit ctx: Ctx): (MutMap[TV, ST], Map[Str, NuParam]) = { @@ -1300,43 +1411,5 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => freshened -> parTP.toMap } - // intersection of members - def memberUnion(l: Ls[NuMember], r: Ls[NuMember])(implicit raise: Raise): Ls[NuMember] = { - def merge(ltm: NuMember, rtm: Option[NuMember]) = { - (ltm, rtm) match { - case (a: TypedNuFun, S(b: TypedNuFun)) => - if (a.level =/= b.level) - err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", a.fd.toLoc) - if (a.fd.tparams =/= b.fd.tparams) - err(msg"method ${a.name} has mismatch type parameters", a.fd.toLoc) - val fd = NuFunDef((a.fd.isLetRec, b.fd.isLetRec) match { - case (S(a), S(b)) => S(a || b) - case _ => N // if one is fun, then it will be fun - }, a.fd.nme, a.fd.tparams, a.fd.rhs)(a.fd.declareLoc, N) - println(s"united ${a.name}") - S(TypedNuFun(a.level, fd, a.bodyType & b.bodyType)) - case (a: NuParam, S(b: NuParam)) => - if (a.level =/= b.level) - err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) - S(NuParam(a.nme, a.ty && b.ty)(a.level)) - case (a: NuParam, S(b: TypedNuFun)) => // not sure - if (a.level =/= b.level) - err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) - S(NuParam(a.nme, a.ty && FieldType(S(b.bodyType), b.bodyType)(b.bodyType.prov))(a.level)) - case (a: TypedNuFun, S(b: NuParam)) => // not sure - if (a.level =/= b.level) - err(msg"member ${a.name} has mismatch levels ${a.level.toString} and ${b.level.toString}", N) - S(NuParam(b.nme, FieldType(S(a.bodyType), a.bodyType)(a.bodyType.prov) && b.ty)(b.level)) - case (a, N) => S(a) - case (a, S(b)) => - err(msg"intersection of member ${a.name} is currently not supported", N) - N - } - } - l.foldLeft(r.map(d => d.name -> d).toMap) { case (acc, ltm) => - acc.updatedWith(ltm.name)(merge(ltm, _)) - }.values.toList - } - } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 3df19b102c..ed51b0016d 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -301,8 +301,10 @@ trait TypeSimplifier { self: Typer => => val clsTyNme = TypeName(clsNme) val lti = ctx.tyDefs2(clsNme) - val defn = lti.result.getOrElse(die) - val cls = defn.asInstanceOf[TypedNuCls] + val cls = lti.result match { + case S(r: TypedNuCls) => r + case _ => die + } val rcdMap = rcd.fields.toMap diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 75dff2ecde..7d03f5d141 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -800,7 +800,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case VarSymbol(ty, _) => ty case ti: CompletedTypeInfo => ti.member match { - case ti: TypedNuTermDef => + case ti: TypedNuFun => + ti.typeSignature + case ti: TypedNuCls => + if (ti.decl.isAbstract) + err(msg"Class ${ti.nme} is abstract and cannot be instantiated", term.toLoc) ti.typeSignature case ti: TypedNuDecl => err(msg"${ti.kind.str} ${ti.name} cannot be used in term position", prov.loco) @@ -1350,7 +1354,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Opt.when(td.params.isDefined)(Tup(params.map(p => N -> Fld(false, false, Asc(p._1, go(p._2.ub)))))), td.ctor, Option.when(!(TopType <:< sign))(go(sign)), - Nil,//TODO + ihtags.toList.sorted.map(_.toVar), // TODO provide targs/args N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) @@ -1361,7 +1365,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) N, td.ctor, Option.when(!(TopType <:< sign))(go(sign)), - Nil,//TODO + ihtags.toList.sorted.map(_.toVar), // TODO provide targs/args N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) @@ -1380,7 +1384,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // else Constrained(res, bounds, Nil) res case OtherTypeLike(tu) => - val mems = tu.entities.map(goDecl) + val mems = tu.implementedMembers.map(goDecl) Signature(mems, tu.result.map(go)) } diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 5cf1bd0001..225fce1c7a 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -39,14 +39,12 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => /** Some type information which may not yet be available. */ sealed abstract class LazyTypeInfo extends TypeInfo { def complete()(implicit raise: Raise): NuMember - def isComputing: Bool def kind: DeclKind } /** A LazyTypeInfo whose typing has been completed. */ case class CompletedTypeInfo(member: NuMember) extends LazyTypeInfo { def complete()(implicit raise: Raise): NuMember = member - def isComputing: Bool = false def kind: DeclKind = member.kind } @@ -406,12 +404,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => override def toString = showProvOver(false)(id.idStr+s"<${parents.map(_.name).mkString(",")}>") } - sealed trait TypeVarOrRigidVar extends SimpleType { - def assertTV: TV = this match { - case tv: TV => tv - case _ => lastWords(s"$this was not a type variable") - } - } + sealed trait TypeVarOrRigidVar extends SimpleType sealed trait ObjectTag extends TypeTag { val id: SimpleTerm diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 7caf584feb..0b2cc72e40 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -252,6 +252,12 @@ abstract class TyperHelpers { Typer: Typer => trait SimpleTypeImpl { self: SimpleType => + // TODO eventually find a way of statically getting rid of those + def assertTV: TV = this match { + case tv: TV => tv + case _ => lastWords(s"$this was not a type variable") + } + def showProvOver(enabled: Bool)(str: Str): Str = if (enabled) str + prov.toString else str @@ -775,7 +781,7 @@ abstract class TyperHelpers { Typer: Typer => cs.flatMap(vbs => PolMap.pos -> vbs._1 :: PolMap.posAtNeg -> vbs._2 :: Nil) ::: pol -> bod :: Nil case OtherTypeLike(tu) => // tu.entities.flatMap(_.childrenPol) ::: tu.result.toList - val ents = tu.entities.flatMap { + val ents = tu.implementedMembers.flatMap { case ta: TypedNuAls => // Q: PolMap.neu or pol.invar?! ta.tparams.map(pol.invar -> _._2) ::: pol -> ta.body :: Nil @@ -877,7 +883,7 @@ abstract class TyperHelpers { Typer: Typer => case SpliceType(fs) => fs.flatMap{ case L(l) => l :: Nil case R(r) => r.lb.toList ::: r.ub :: Nil} case OtherTypeLike(tu) => // tu.childrenPol(PolMap.neu).map(tp => tp._1) - val ents = tu.entities.flatMap { + val ents = tu.implementedMembers.flatMap { case tf: TypedNuFun => tf.bodyType :: Nil case als: TypedNuAls => @@ -1201,7 +1207,7 @@ abstract class TyperHelpers { Typer: Typer => def applyLike(pol: PolMap)(ty: TypeLike): Unit = ty match { case ty: ST => apply(pol)(ty) case OtherTypeLike(tu) => - tu.entities.foreach(applyMem(pol)) + tu.implementedMembers.foreach(applyMem(pol)) tu.result.foreach(apply(pol)) } def applyMem(pol: PolMap)(m: NuMember): Unit = m match { diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index e599344da0..5ebbbfb9cf 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -139,9 +139,10 @@ trait TypeLikeImpl extends Located { self: TypeLike => case NuTypeDef(kind @ Als, nme, tparams, params, ctor, sig, parents, sup, ths, body) => s"type ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")} = ${ sig.getOrElse(die).showIn(ctx, 0)}" - case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => + case td @ NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => val bodyCtx = ctx.indent - s"${kind.str} ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}${params match { + s"${td.declareLoc.fold("")(_ => "declare ")}${td.abstractLoc.fold("")(_ => "abstract ")}${kind.str} ${ + nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}${params match { case S(Tup(fields)) => s"(${fields.map { case (N, Fld(_, _, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) case (N, _) => "???" @@ -150,7 +151,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case _ => "" }}${sig.fold("")(": " + _.showIn(bodyCtx, 0))}${parents match { case Nil => "" - case ps => "extends " + ps.mkString(", ") // TODO pp parent terms... + case ps => " extends " + ps.mkString(", ") // TODO pp parent terms... }}${if (body.entities.isEmpty && sup.isEmpty && ths.isEmpty) "" else " {\n" + sup.fold("")(s"${bodyCtx.indStr}super: " + _.showIn(bodyCtx, 0) + "\n") + ths.fold("")(s"${bodyCtx.indStr}this: " + _.showIn(bodyCtx, 0) + "\n") + @@ -569,6 +570,7 @@ trait TermImpl extends StatementImpl { self: Term => case App(App(Var("|"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), Tup(N -> Fld(false, false, lhs) :: Nil)), Tup(N -> Fld(false, false, rhs) :: Nil)) => Inter(lhs.toType_!, rhs.toType_!) case App(App(Var("->"), lhs), Tup(N -> Fld(false, false, rhs) :: Nil)) => Function(lhs.toType_!, rhs.toType_!) + case App(App(Var("->"), lhs), tup: Tup) => Function(lhs.toType_!, tup.toType_!) case App(App(Var("|"), lhs), rhs) => Union(lhs.toType_!, rhs.toType_!) case App(App(Var("&"), lhs), rhs) => Inter(lhs.toType_!, rhs.toType_!) case Lam(lhs, rhs) => Function(lhs.toType_!, rhs.toType_!) @@ -749,7 +751,7 @@ trait StatementImpl extends Located { self: Statement => require(sig.isDefined) require(ths.isEmpty, ths) require(unit.entities.isEmpty, unit) - Nil -> (TypeDef(k, nme, tps.map(_._2), sig.get, Nil, Nil, Nil) :: Nil) + Nil -> (TypeDef(k, nme, tps.map(_._2), sig.getOrElse(die), Nil, Nil, Nil) :: Nil) case NuTypeDef(k @ (Cls | Trt), nme, tps, opt, ctor, sig, pars, sup, ths, unit) => val tup = opt.getOrElse(Tup(Nil)) val fs = tup.fields diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 4f385d00cb..0a803cbfef 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -458,7 +458,7 @@ class Foo(x: int) class Bar(x: int, y: int) extends Foo(x + y) -//│ class Bar(x: int, y: int) +//│ class Bar(x: int, y: int) extends Foo mixin AA(a: int) { diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 383bb769f8..0e88c0ff4e 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -732,8 +732,8 @@ module J { //│ module J { //│ class K(x: int) //│ mixin L() -//│ class M() -//│ class N(x: int) +//│ class M() extends K +//│ class N(x: int) extends K //│ } //│ // Prelude //│ class TypingUnit14 { @@ -882,7 +882,7 @@ module L { //│ class M(x: int) //│ module N { //│ module O { -//│ class P(y: int) +//│ class P(y: int) extends M //│ } //│ } //│ } @@ -1009,7 +1009,7 @@ module N { } //│ module N { //│ module O { -//│ class P() +//│ class P() extends Q //│ } //│ class Q() //│ } diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index 8b2108f60b..bf9a1ca001 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -165,9 +165,9 @@ class H extends B {} //│ ╔══[ERROR] class C expects 0 parameter(s); got 1 //│ ║ l.160: class G extends C(2) {} //│ ╙── ^^^ -//│ class F(x: int) -//│ class G -//│ class H +//│ class F(x: int) extends C +//│ class G extends C +//│ class H extends B //│ // Prelude //│ class TypingUnit7 { //│ #F; @@ -265,7 +265,7 @@ module I { //│ module I { //│ class J //│ module K { -//│ class L +//│ class L extends J //│ } //│ } //│ // Prelude @@ -437,10 +437,10 @@ module O { mixin P { constructor(x: int) } -//│ ╔══[ERROR] Explicit module constructors are not supported. +//│ ╔══[ERROR] Explicit module constructors are not supported //│ ║ l.435: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Explicit mixin constructors are not supported. +//│ ╔══[ERROR] Explicit mixin constructors are not supported //│ ║ l.438: constructor(x: int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ module O diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index bbcb801f27..b7d3fcc3e4 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -191,8 +191,8 @@ module SizeText extends Text // * Note: this inferred type got *much worse* after this commit (field access type refinement) module SizeText extends SizeBase, Text //│ module SizeText { -//│ fun size: (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]) -> int -//│ fun text: (Circle | Intersect[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Outside[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Translate[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Union[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]]) -> string +//│ fun size: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]) -> int +//│ fun text: forall 'Region 'Region0. (Circle | Intersect[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Outside[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Translate[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Union[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]]) -> string //│ } //│ where //│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] @@ -254,23 +254,6 @@ mixin IsEmpty { module IsUnivIsEmpty extends IsUniv, IsEmpty //│ module IsUnivIsEmpty { -//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) -//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) -//│ } -//│ where -//│ 'Region <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region2 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a3 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a4 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region1 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a2 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a1 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ - -module IsUnivIsEmpty extends IsEmpty, IsUniv -//│ module IsUnivIsEmpty { //│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) //│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) //│ } @@ -286,6 +269,23 @@ module IsUnivIsEmpty extends IsEmpty, IsUniv //│ 'a1 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ //│ 'Region <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +module IsUnivIsEmpty extends IsEmpty, IsUniv +//│ module IsUnivIsEmpty { +//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ } +//│ where +//│ 'Region <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region2 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a3 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a4 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region1 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a2 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'a1 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ + IsUnivIsEmpty.isUniv(circles) //│ bool | 'a //│ res diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 6d073ad632..805f0cde47 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -5,8 +5,8 @@ class Exp[A]: Pair | Lit class Lit(n: int) extends Exp[int] class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[anything, anything] -//│ class Lit(n: int) -//│ class Pair[L, R](lhs: L, rhs: R) +//│ class Lit(n: int) extends Exp +//│ class Pair[L, R](lhs: L, rhs: R) extends Exp fun f(p: Pair['a, 'b]) = p.lhs diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index 5e71c0b170..9d2850a9ac 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -5,8 +5,8 @@ class Exp[A]: Pair | Lit class Lit(n: int) extends Exp[int] class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[?, ?] -//│ class Lit(n: int) -//│ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) +//│ class Lit(n: int) extends Exp +//│ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp fun f(p: Pair['a, 'b]) = p.lhs diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index 52ec85a300..6cdfc607f9 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -51,10 +51,10 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { //│ fun test: 0 | 1 //│ } -//│ class Lit(n: int) { +//│ class Lit(n: int) extends Exp { //│ fun test: 0 | 1 //│ } -//│ class Pair(lhs: Exp, rhs: Exp) { +//│ class Pair(lhs: Exp, rhs: Exp) extends Exp { //│ fun test: 0 | 1 //│ } @@ -69,10 +69,10 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { //│ fun test: 0 | 1 //│ } -//│ class Lit(n: int) { +//│ class Lit(n: int) extends Exp { //│ fun test: 0 | 1 //│ } -//│ class Pair(lhs: Exp, rhs: Exp) { +//│ class Pair(lhs: Exp, rhs: Exp) extends Exp { //│ fun test: 0 | 1 //│ } @@ -99,10 +99,10 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { //│ fun test: int //│ } -//│ class Lit(n: int) { +//│ class Lit(n: int) extends Exp { //│ fun test: int //│ } -//│ class Pair(lhs: Exp, rhs: Exp) { +//│ class Pair(lhs: Exp, rhs: Exp) extends Exp { //│ fun test: int //│ } @@ -118,10 +118,10 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { //│ fun test: int //│ } -//│ class Lit(n: int) { +//│ class Lit(n: int) extends Exp { //│ fun test: int //│ } -//│ class Pair(lhs: Exp, rhs: Exp) { +//│ class Pair(lhs: Exp, rhs: Exp) extends Exp { //│ fun test: int //│ } @@ -156,10 +156,10 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[anything, anything] { //│ fun test: 0 | 1 //│ } -//│ class Lit(n: int) { +//│ class Lit(n: int) extends Exp { //│ fun test: 0 | 1 //│ } -//│ class Pair[L, R](lhs: L, rhs: R) +//│ class Pair[L, R](lhs: L, rhs: R) extends Exp Lit(0).test //│ 0 | 1 diff --git a/shared/src/test/diff/nu/Abstract.mls b/shared/src/test/diff/nu/Abstract.mls deleted file mode 100644 index 3c212ddd8b..0000000000 --- a/shared/src/test/diff/nu/Abstract.mls +++ /dev/null @@ -1,23 +0,0 @@ -:NewDefs - - -abstract class Foo(x: int) { - fun f(y: int) = x + y -} -//│ class Foo(x: int) { -//│ fun f: (y: int,) -> int -//│ } - - -:e // TODO -abstract class Foo(x: int) { - fun f: int -> int -} -//│ ╔══[ERROR] Member f is declared but not defined -//│ ║ l.14: fun f: int -> int -//│ ╙── ^ -//│ class Foo(x: int) { -//│ fun f: int -> int -//│ } - - diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls new file mode 100644 index 0000000000..8bbe84d34b --- /dev/null +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -0,0 +1,153 @@ +:NewDefs + +:NoJS // TODO + + +abstract class Foo(x: int) { + fun f(y: int) = x + y +} +//│ abstract class Foo(x: int) { +//│ fun f: (y: int,) -> int +//│ } + +:e +Foo(1) +//│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated +//│ ║ l.14: Foo(1) +//│ ╙── ^^^ +//│ Foo + +:e // TODO allow with `new` keyword +new Foo(1) +//│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated +//│ ║ l.21: new Foo(1) +//│ ╙── ^^^^^^ +//│ Foo + + +abstract class Foo(x: int) { + fun f: int -> int +} +//│ abstract class Foo(x: int) { +//│ fun f: int -> int +//│ } + +:e +Foo(1) +//│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated +//│ ║ l.36: Foo(1) +//│ ╙── ^^^ +//│ Foo + +:e // TODO support +new Foo(1) { fun f = id } +//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ║ l.43: new Foo(1) { fun f = id } +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ error + + +abstract class Bar extends Foo(1) +//│ abstract class Bar extends Foo { +//│ fun f: int -> int +//│ } + +:e +module Baz extends Bar +Baz.f(1) +//│ ╔══[ERROR] Member `f` is declared in parent but not implemented +//│ ║ l.56: module Baz extends Bar +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.29: fun f: int -> int +//│ ╙── ^^^^^^^^^^^^^ +//│ module Baz extends Bar, Foo { +//│ fun f: int -> int +//│ } +//│ int + +module Baz extends Bar { + fun f(x) = x + 1 +} +Baz.f(1) +//│ module Baz extends Bar, Foo { +//│ fun f: int -> int +//│ } +//│ int + + + +abstract class C1 { fun x: int | string } +//│ abstract class C1 { +//│ fun x: int | string +//│ } + +trait T1 { fun x: int | bool } +//│ trait T1 { +//│ fun x: bool | int +//│ } + +:e +class C2 extends C1, T1 +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented +//│ ║ l.91: class C2 extends C1, T1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.80: abstract class C1 { fun x: int | string } +//│ ╙── ^^^^^^^^^^^^^^^ +//│ class C2 extends C1, T1 { +//│ fun x: int +//│ } + +class C2 extends C1, T1 { fun x = 1 } +//│ class C2 extends C1, T1 { +//│ fun x: 1 +//│ } + +abstract class C2 extends C1, T1 +//│ abstract class C2 extends C1, T1 { +//│ fun x: int +//│ } + +:e +class C3 extends C2 +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented +//│ ║ l.113: class C3 extends C2 +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.80: abstract class C1 { fun x: int | string } +//│ ╙── ^^^^^^^^^^^^^^^ +//│ class C3 extends C1, C2, T1 { +//│ fun x: int +//│ } + +class C3 extends C2 { fun x = 1 } +//│ class C3 extends C1, C2, T1 { +//│ fun x: 1 +//│ } + + + +abstract class C { + fun x : int + fun foo0 = x + fun foo1 = this.x +} +//│ abstract class C { +//│ fun foo0: int +//│ fun foo1: int +//│ fun x: int +//│ } + +class C { + val x : int + fun foo0 = x + fun foo1 = this.x +} +//│ class C { +//│ fun foo0: int +//│ fun foo1: int +//│ let x: int +//│ } + + diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index 4ed1de30d8..5189ed837a 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -20,14 +20,14 @@ type Foo[A] = { x: A, y: Foo[(A, A)] } // TODO support abstract types :e type Test -//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ╔══[ERROR] Type alias definition requires a right-hand side //│ ║ l.22: type Test //│ ╙── ^^^^^^^^^ //│ type Test = error :e type Test(n: int) = n -//│ ╔══[ERROR] type alias definitions cannot have value parameters +//│ ╔══[ERROR] Type alias definitions cannot have value parameters //│ ║ l.29: type Test(n: int) = n //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] type identifier not found: n @@ -44,7 +44,7 @@ type Test: Base //│ ╔══[PARSE ERROR] Expected end of input; found ':' instead //│ ║ l.43: type Test: Base //│ ╙── ^ -//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ╔══[ERROR] Type alias definition requires a right-hand side //│ ║ l.43: type Test: Base //│ ╙── ^^^^^^^^^ //│ type Test = error @@ -55,17 +55,17 @@ type Test: Base = int //│ ╔══[PARSE ERROR] Expected end of input; found ':' instead //│ ║ l.54: type Test: Base = int //│ ╙── ^ -//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ╔══[ERROR] Type alias definition requires a right-hand side //│ ║ l.54: type Test: Base = int //│ ╙── ^^^^^^^^^ //│ type Test = error :e type Test extends Base -//│ ╔══[ERROR] type alias definitions cannot extend parents +//│ ╔══[ERROR] Type alias definitions cannot extend parents //│ ║ l.64: type Test extends Base //│ ╙── ^^^^ -//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ╔══[ERROR] Type alias definition requires a right-hand side //│ ║ l.64: type Test extends Base //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ type Test = error @@ -76,17 +76,17 @@ type Test extends Base = int //│ ╔══[PARSE ERROR] Expected end of input; found '=' instead //│ ║ l.75: type Test extends Base = int //│ ╙── ^ -//│ ╔══[ERROR] type alias definitions cannot extend parents +//│ ╔══[ERROR] Type alias definitions cannot extend parents //│ ║ l.75: type Test extends Base = int //│ ╙── ^^^^ -//│ ╔══[ERROR] type alias definition requires a right-hand side +//│ ╔══[ERROR] Type alias definition requires a right-hand side //│ ║ l.75: type Test extends Base = int //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ type Test = error :e type Test = int extends Base -//│ ╔══[ERROR] type alias definitions cannot extend parents +//│ ╔══[ERROR] Type alias definitions cannot extend parents //│ ║ l.88: type Test = int extends Base //│ ╙── ^^^^ //│ type Test = int diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index c0cfeb8fc6..71ddf5ee10 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -11,7 +11,7 @@ class C2(x: int) extends C1(y) { //│ ╔══[ERROR] identifier not found: y //│ ║ l.8: class C2(x: int) extends C1(y) { //│ ╙── ^ -//│ class C2(x: int) { +//│ class C2(x: int) extends C1 { //│ let y: int //│ } @@ -22,7 +22,7 @@ class C2 extends C1(y) { //│ ╔══[ERROR] identifier not found: y //│ ║ l.19: class C2 extends C1(y) { //│ ╙── ^ -//│ class C2 { +//│ class C2 extends C1 { //│ let y: int //│ } //│ Code generation encountered an error: @@ -35,7 +35,7 @@ class C2 extends C1(this.y) { //│ ╔══[ERROR] identifier not found: this //│ ║ l.32: class C2 extends C1(this.y) { //│ ╙── ^^^^ -//│ class C2 { +//│ class C2 extends C1 { //│ let y: int //│ } @@ -48,7 +48,7 @@ class C2 extends C1(this) //│ ╔══[ERROR] identifier not found: this //│ ║ l.47: class C2 extends C1(this) //│ ╙── ^^^^ -//│ class C2 +//│ class C2 extends C1 class Foo { fun x: int = 1 } @@ -77,7 +77,7 @@ class Bar extends Foo, M //│ ╟── from definition of method x: //│ ║ l.54: class Foo { fun x: int = 1 } //│ ╙── ^^^^^^^^^^ -//│ class Bar { +//│ class Bar extends Foo { //│ fun x: false //│ } diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 057cd84169..00c3006046 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -106,7 +106,7 @@ class C1 { fun oops = this.x } :e class C { fun x: int } -//│ ╔══[ERROR] Member x is declared but not defined +//│ ╔══[ERROR] Member `x` is declared but not defined //│ ║ l.108: class C { fun x: int } //│ ╙── ^ //│ class C { diff --git a/shared/src/test/diff/nu/BadSignatures.mls b/shared/src/test/diff/nu/BadSignatures.mls new file mode 100644 index 0000000000..9187a8aef5 --- /dev/null +++ b/shared/src/test/diff/nu/BadSignatures.mls @@ -0,0 +1,100 @@ +:NewDefs + + +:e +trait T { + fun x : int + fun x = false +} +//│ ╔══[ERROR] Method implementations in traits are not yet supported +//│ ║ l.7: fun x = false +//│ ╙── ^^^^^^^^^ +//│ trait T { +//│ fun x: int +//│ } +//│ Code generation encountered an error: +//│ traits are not supported yet. + + +class A { fun x = 1 } +//│ class A { +//│ fun x: 1 +//│ } + +:e +class B() extends A { + fun x: int +} +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.26: fun x: int +//│ ║ ^^^^^^ +//│ ╟── type `int` does not match type `1` +//│ ║ l.26: fun x: int +//│ ║ ^^^ +//│ ╟── but it flows into signature of member `x` with expected type `1` +//│ ║ l.26: fun x: int +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from integer literal: +//│ ║ l.19: class A { fun x = 1 } +//│ ║ ^ +//│ ╟── from definition of method x: +//│ ║ l.19: class A { fun x = 1 } +//│ ╙── ^^^^^ +//│ class B() extends A { +//│ fun x: int +//│ } + +B().x +//│ int +//│ res +//│ = 1 + +(B() : A).x +//│ 1 +//│ res +//│ = 1 + +class C() extends B { fun x = 0 } +//│ class C() extends A, B { +//│ fun x: 0 +//│ } + +(C() : A).x +//│ 1 +//│ res +//│ = 0 + +:e +class B() extends A { + fun x: int + fun x = 1 +} +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.69: fun x: int +//│ ║ ^^^^^^ +//│ ╟── type `int` does not match type `1` +//│ ║ l.69: fun x: int +//│ ║ ^^^ +//│ ╟── but it flows into signature of member `x` with expected type `1` +//│ ║ l.69: fun x: int +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from integer literal: +//│ ║ l.19: class A { fun x = 1 } +//│ ║ ^ +//│ ╟── from definition of method x: +//│ ║ l.19: class A { fun x = 1 } +//│ ╙── ^^^^^ +//│ class B() extends A { +//│ fun x: int +//│ } + + +:e +mixin M { fun x : int } +//│ ╔══[ERROR] Member `x` is declared but not defined +//│ ║ l.93: mixin M { fun x : int } +//│ ╙── ^ +//│ mixin M() { +//│ fun x: int +//│ } + diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 0be5f5730b..d7d67468a7 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -4,22 +4,31 @@ class A //│ class A -// TODO class B(m: int) extends A -//│ class B(m: int) +//│ class B(m: int) extends A class A(n: int) //│ class A(n: int) -// TODO -class B(m: int) extends A(n + 1) -//│ ╔══[ERROR] identifier not found: n -//│ ║ l.16: class B(m: int) extends A(n + 1) -//│ ╙── ^ -//│ class B(m: int) -//│ Code generation encountered an error: -//│ unresolved symbol n - +class B(m: int) extends A(m + 1) +//│ class B(m: int) extends A + + +class A { + fun a1: int + fun a1 = 1 + fun a2 = 2 +} +//│ class A { +//│ fun a1: int +//│ fun a2: 2 +//│ } + +class B extends A +//│ class B extends A { +//│ fun a1: int +//│ fun a2: 2 +//│ } diff --git a/shared/src/test/diff/nu/Dates.mls b/shared/src/test/diff/nu/Dates.mls index 21491d1d47..b4393f8549 100644 --- a/shared/src/test/diff/nu/Dates.mls +++ b/shared/src/test/diff/nu/Dates.mls @@ -6,7 +6,7 @@ declare class Date { fun toString(): string fun toLocaleString(locales: string | Array[string], options: anything): string } -//│ class Date { +//│ declare class Date { //│ fun toLocaleString: (locales: Array[string] | string, options: anything,) -> string //│ fun toString: () -> string //│ } diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index 5c99e246a9..1c1b3f1a95 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -20,7 +20,7 @@ atob(str) declare module console { fun error: string -> unit } -//│ module console { +//│ declare module console { //│ fun error: string -> unit //│ } @@ -45,7 +45,7 @@ console.log("hello") declare module Foo { fun foo: int } -//│ module Foo { +//│ declare module Foo { //│ fun foo: int //│ } @@ -70,7 +70,7 @@ declare type A = int declare class Sanitizer { fun sanitizeFor(element: string, input: string): string } -//│ class Sanitizer { +//│ declare class Sanitizer { //│ fun sanitizeFor: (element: string, input: string,) -> string //│ } @@ -94,7 +94,7 @@ declare module Buffer { // fun from1(a: Array[int]): this.Buffer2 = from1(a) // FIXME // fun from2(a: Array[int]): Buffer.Buffer2 = from2(a) // FIXME } -//│ module Buffer { +//│ declare module Buffer { //│ class Buffer2 { //│ let length: int //│ } diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls new file mode 100644 index 0000000000..333337d853 --- /dev/null +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -0,0 +1,165 @@ +:NewDefs + +:NoJS // TODO + + + +trait Foo[A] { fun foo: A } +//│ trait Foo[A] { +//│ fun foo: A +//│ } + +module Bar extends Foo[int | bool], Foo[int | string] { + fun foo = 123 +} +//│ module Bar extends Foo { +//│ fun foo: 123 +//│ } + +Bar.foo +//│ 123 + +Bar : Foo['X] +//│ Foo['X] +//│ where +//│ 'X := int | string + +(Bar : Foo['X]).foo +//│ int | string + + +trait Foo[A] { fun foo: A; fun bar: A -> A } +//│ trait Foo[A] { +//│ fun bar: A -> A +//│ fun foo: A +//│ } + +module Bar extends Foo[int | bool], Foo[int | string] { + fun foo = 123 + fun bar = id +} +//│ module Bar extends Foo { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun foo: 123 +//│ } + +Bar.bar +//│ forall 'a. 'a -> 'a + +Bar : Foo['X] +//│ Foo['X] +//│ where +//│ 'X := int | string + + +trait T1 extends Foo[int | bool] +//│ trait T1 extends Foo { +//│ fun bar: 'A -> 'A +//│ fun foo: 'A +//│ } +//│ where +//│ 'A := bool | int + +module Bar extends T1, Foo[int | string] { + fun foo = 123 + fun bar = id +} +//│ module Bar extends Foo, T1 { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun foo: 123 +//│ } + +(Bar : Foo['X]).foo +//│ int | string + +(Bar : Foo['X]).bar +//│ ('A & (int | string)) -> ('A | int | string) + +(Bar : T1).foo +//│ bool | int + +let f = (Bar : T1).bar +f(true) +//│ let f: ('A & (bool | int)) -> ('A | bool | int) +//│ bool | int + +:e +module Bar extends T1, Foo[int | string] { + fun foo = 123 + fun bar(x) = x + 1 +} +//│ ╔══[ERROR] Type mismatch in definition of method bar: +//│ ║ l.89: fun bar(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type `bool` is not an instance of type `int` +//│ ║ l.55: trait T1 extends Foo[int | bool] +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.89: fun bar(x) = x + 1 +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method bar: +//│ ║ l.89: fun bar(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type `string` is not an instance of type `int` +//│ ║ l.87: module Bar extends T1, Foo[int | string] { +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.89: fun bar(x) = x + 1 +//│ ╙── ^ +//│ module Bar extends Foo, T1 { +//│ fun bar: int -> int +//│ fun foo: 123 +//│ } + + +trait Base[A] { fun foo: A; fun bar: A -> A } +trait Derived1[A] extends Base[A] +trait Derived2 extends Base[(int | string, int | string)] +//│ trait Base[A] { +//│ fun bar: A -> A +//│ fun foo: A +//│ } +//│ trait Derived1[A] extends Base { +//│ fun bar: 'A -> 'A +//│ fun foo: 'A +//│ } +//│ trait Derived2 extends Base { +//│ fun bar: 'A0 -> 'A0 +//│ fun foo: 'A0 +//│ } +//│ where +//│ 'A0 := (int | string, int | string,) +//│ 'A := A + +class Final extends Derived1[(int, int)], Derived2 { + fun foo = (123, 456) + fun bar([x, y]) = [error, error] +} +//│ class Final extends Base, Derived1, Derived2 { +//│ fun bar: (anything, anything,) -> (nothing, nothing,) +//│ fun foo: (123, 456,) +//│ } + +:e +class Final extends Derived1[(int, int)], Derived2 { + fun foo = (123, 456) + fun bar([x, y]) = [y, x] +} +//│ ╔══[ERROR] Type mismatch in definition of method bar: +//│ ║ l.146: fun bar([x, y]) = [y, x] +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `string` is not an instance of `int` +//│ ║ l.117: trait Derived2 extends Base[(int | string, int | string)] +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.144: class Final extends Derived1[(int, int)], Derived2 { +//│ ║ ^^^ +//│ ╟── from reference: +//│ ║ l.146: fun bar([x, y]) = [y, x] +//│ ╙── ^ +//│ class Final extends Base, Derived1, Derived2 { +//│ fun bar: (int, int,) -> (int | string, int | string,) +//│ fun foo: (123, 456,) +//│ } + + diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 13388aa82a..862c7c873d 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -10,13 +10,13 @@ class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr[(S, T)] class Fst[S, T](p: Expr[(S, T)]) extends Expr[S] class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] //│ trait Expr[A]: Add | Cond[?] | Fst[?, ?] | LitBool | LitInt | Pair[?, ?] | Snd[?, ?] -//│ class LitInt(n: int) -//│ class LitBool(b: bool) -//│ class Add(x: Expr[int], y: Expr[int]) -//│ class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) -//│ class Pair[S, T](a: Expr[S], b: Expr[T]) -//│ class Fst[S, T](p: Expr[(S, T,)]) -//│ class Snd[S, T](p: Expr[(S, T,)]) +//│ class LitInt(n: int) extends Expr +//│ class LitBool(b: bool) extends Expr +//│ class Add(x: Expr[int], y: Expr[int]) extends Expr +//│ class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) extends Expr +//│ class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr +//│ class Fst[S, T](p: Expr[(S, T,)]) extends Expr +//│ class Snd[S, T](p: Expr[(S, T,)]) extends Expr let l1 = LitInt(1) //│ let l1: LitInt diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 5cf5fca165..a9475ca190 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -8,7 +8,7 @@ class Room[A](name: string) { //│ } class BigRoom extends Room[bool]("big") -//│ class BigRoom { +//│ class BigRoom extends Room { //│ fun foo: (x: 'A,) -> 'A //│ } //│ where @@ -18,7 +18,7 @@ class BigRoom extends Room[bool]("big") class InferredRoom extends Room("infer") { fun foo(x) = x && true } -//│ class InferredRoom { +//│ class InferredRoom extends Room { //│ fun foo: bool -> bool //│ } @@ -32,7 +32,7 @@ class TooManyRoom extends Room[int, string]("too many") //│ ╔══[ERROR] class Room expects 1 type parameter(s); got 2 //│ ║ l.31: class TooManyRoom extends Room[int, string]("too many") //│ ╙── ^^^^^^^^^^^^^^^^ -//│ class TooManyRoom { +//│ class TooManyRoom extends Room { //│ fun foo: (x: 'A,) -> 'A //│ } //│ where @@ -63,7 +63,7 @@ class WrongRoom extends Room[bool]("wrong") { //│ ╟── from reference: //│ ║ l.4: fun foo(x: A) = x //│ ╙── ^ -//│ class WrongRoom { +//│ class WrongRoom extends Room { //│ fun foo: int -> int //│ } @@ -73,21 +73,19 @@ class C0[A] { val a: A } //│ let a: A //│ } -class C1[A] extends C0[A] -//│ class C1[A] { -//│ let a: 'A +class C1[A] extends C0[A] { val a = a } +//│ class C1[A] extends C0 { +//│ let a: nothing //│ } -//│ where -//│ 'A := A :pe :e new C1 : C1[int] //│ ╔══[PARSE ERROR] Unexpected type ascription after `new` keyword -//│ ║ l.85: new C1 : C1[int] +//│ ║ l.83: new C1 : C1[int] //│ ╙── ^^ //│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.85: new C1 : C1[int] +//│ ║ l.83: new C1 : C1[int] //│ ╙── ^^^ //│ error //│ res @@ -98,6 +96,11 @@ new C1 : C1[int] //│ res //│ = C1 {} +(new C1).a +//│ nothing +//│ res +//│ = undefined + mixin M1[A] { fun f1(x: A): A = x @@ -149,14 +152,14 @@ class B2[A](a: int => A) extends M2 :e class E1(a: int) extends M2[bool] //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.150: class E1(a: int) extends M2[bool] +//│ ║ l.153: class E1(a: int) extends M2[bool] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.150: class E1(a: int) extends M2[bool] +//│ ║ l.153: class E1(a: int) extends M2[bool] //│ ║ ^^^^ //│ ╟── from field selection: -//│ ║ l.132: fun m: A = this.a +//│ ║ l.135: fun m: A = this.a //│ ╙── ^^^^^^ //│ class E1(a: int) { //│ fun m: bool diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 457f6fb2f1..eeaec2e42a 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -102,10 +102,10 @@ module Test { fun bar: 'A fun test(x: A) = x } -//│ ╔══[ERROR] Member foo is declared but not defined +//│ ╔══[ERROR] Member `foo` is declared but not defined //│ ║ l.101: fun foo: 'A => 'A //│ ╙── ^^^ -//│ ╔══[ERROR] Member bar is declared but not defined +//│ ╔══[ERROR] Member `bar` is declared but not defined //│ ║ l.102: fun bar: 'A //│ ╙── ^^^ //│ module Test { diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 5de1c6d4be..fe2cd5fcfd 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -145,7 +145,7 @@ module D extends C(0) { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.143: this.foo(false) //│ ╙── ^^^^ -//│ module D { +//│ module D extends C { //│ fun bar: forall 'A. ('A | int, 'A | int,) //│ fun baz: int //│ fun foo: forall 'A. 'A -> ('A | int) diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 45cc354845..097a5b6f85 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -10,13 +10,13 @@ module Test { fun poly1: forall 'a; 'a -> 'a fun poly2: 'a -> 'a = id } -//│ ╔══[ERROR] Member foo is declared but not defined +//│ ╔══[ERROR] Member `foo` is declared but not defined //│ ║ l.6: fun foo: A => A //│ ╙── ^^^ -//│ ╔══[ERROR] Member poly0 is declared but not defined +//│ ╔══[ERROR] Member `poly0` is declared but not defined //│ ║ l.9: fun poly0: 'a -> 'a //│ ╙── ^^^^^ -//│ ╔══[ERROR] Member poly1 is declared but not defined +//│ ╔══[ERROR] Member `poly1` is declared but not defined //│ ║ l.10: fun poly1: forall 'a; 'a -> 'a //│ ╙── ^^^^^ //│ module Test[A] { diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index c64a3fc835..0a340d9246 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -122,7 +122,7 @@ module M extends C { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.120: this.id2(true) //│ ╙── ^^^^ -//│ module M { +//│ module M extends C { //│ fun f: forall 'a 'b. (0 | true | 'a, 0 | true | 'b,) //│ fun id1: forall 'a 'b. ('b & 'a) -> (0 | true | 'a) //│ fun id2: forall 'c. 'c -> 'c @@ -138,7 +138,7 @@ module M extends C { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.133: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ -//│ module M { +//│ module M extends C { //│ fun f: forall 'a 'b. (0 | true | 'a, 0 | true | 'b,) //│ fun g: (error, error,) //│ fun id1: forall 'a 'b. ('b & 'a) -> (0 | true | 'a) @@ -183,7 +183,7 @@ module M extends C { //│ ╟── Note: constraint arises from reference: //│ ║ l.107: fun id1(x) = x //│ ╙── ^ -//│ module M { +//│ module M extends C { //│ fun f: (0 | true, 0 | true,) //│ fun id1: int -> int //│ fun id2: forall 'a. 'a -> 'a diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index d67af7d181..7832dab13e 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -59,7 +59,7 @@ class C1(a: int) extends P(a) { fun bar = this.foo(0) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.58: class C1(a: int) extends P(a) { fun bar = this.foo(0) } //│ ╙── ^^^^ -//│ class C1(a: int) { +//│ class C1(a: int) extends P { //│ fun bar: error //│ fun foo: int -> int //│ } @@ -71,7 +71,7 @@ class C2(a: int, b: int) extends P(a + b) { //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.69: fun foo(x) = x * this.p + a * b //│ ╙── ^^ -//│ class C2(a: int, b: int) { +//│ class C2(a: int, b: int) extends P { //│ fun foo: int -> int //│ } @@ -95,7 +95,7 @@ class Test[A](x: A) //│ class Test[A](x: A) class A(a: int) extends Test(a) -//│ class A(a: int) +//│ class A(a: int) extends Test let a1 = A(1) //│ let a1: A @@ -114,7 +114,9 @@ a1.x //│ res //│ = 1 -:NoJS + +:NoJS // TODO + trait Foo[A] { fun foo[A](x: A): A } @@ -122,29 +124,28 @@ trait Foo[A] { //│ fun foo: forall 'A. (x: 'A,) -> 'A //│ } -// FIXME +:e class B extends Foo { fun foo(x) = x + 1 } -//│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.127: fun foo(x) = x + 1 +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.129: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.119: fun foo[A](x: A): A +//│ ╟── type `A` is not an instance of type `int` +//│ ║ l.121: fun foo[A](x: A): A //│ ║ ^ -//│ ╟── into reference of type `int` -//│ ║ l.127: fun foo(x) = x + 1 +//│ ╟── Note: constraint arises from reference: +//│ ║ l.129: fun foo(x) = x + 1 //│ ╙── ^ -//│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.127: fun foo(x) = x + 1 +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.129: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.127: fun foo(x) = x + 1 +//│ ╟── operator application of type `int` does not match type `A` +//│ ║ l.129: fun foo(x) = x + 1 //│ ║ ^^^^^ -//│ ╟── adding a type annotation to any of the following terms may help resolve the problem -//│ ╟── • this operator application: -//│ ║ l.127: fun foo(x) = x + 1 -//│ ╙── ^^^^^ -//│ class B { +//│ ╟── Note: constraint arises from method type parameter: +//│ ║ l.121: fun foo[A](x: A): A +//│ ╙── ^ +//│ class B extends Foo { //│ fun foo: int -> int //│ } diff --git a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls index 00d85f4e40..9933ce198c 100644 --- a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls +++ b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls @@ -13,7 +13,7 @@ module Foo { class C extends T1, T2 { fun x = 1 } } //│ module Foo { -//│ class C { +//│ class C extends T1, T2 { //│ fun x: 1 //│ } //│ trait T2 { diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index a3bf07093b..7ddeb26405 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -9,7 +9,7 @@ trait Into[T] { //│ } trait Nat extends Into[int] -//│ trait Nat { +//│ trait Nat extends Into { //│ fun into: 'T //│ } //│ where @@ -18,7 +18,7 @@ trait Nat extends Into[int] trait Product[A, B] extends Into[A] { let pair: (A, B) } -//│ trait Product[A, B] { +//│ trait Product[A, B] extends Into { //│ fun into: 'T //│ let pair: (A, B,) //│ } @@ -28,7 +28,7 @@ trait Product[A, B] extends Into[A] { class TwoInts(pair: (int, int)) extends Product[int, int] { fun into = pair._1 + pair._2 } -//│ class TwoInts(pair: (int, int,)) { +//│ class TwoInts(pair: (int, int,)) extends Into, Product { //│ fun into: int //│ } diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index ac43b20aac..95ec2db676 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -19,20 +19,20 @@ class Point(x: int, y: int) extends Showable { fun mlen = x + y fun toString = "I'm a point" } -//│ class Point(x: int, y: int) { +//│ class Point(x: int, y: int) extends Showable { //│ fun mlen: int //│ fun toString: "I'm a point" //│ } class What1(toString: string) extends Showable -//│ class What1(toString: string) +//│ class What1(toString: string) extends Showable :e trait NoShow extends What1("hi") -//│ ╔══[ERROR] trait can only inherit from traits +//│ ╔══[ERROR] A trait can only inherit from other traits //│ ║ l.31: trait NoShow extends What1("hi") //│ ╙── ^^^^^^^^^^^ -//│ trait NoShow +//│ trait NoShow extends Showable, What1 :e class ErrC1 extends Showable @@ -40,9 +40,12 @@ class ErrC2 extends Showable { fun toString = 114 } class ErrC3(toString: string -> string) extends Showable -//│ ╔══[ERROR] Member toString is declared in parent trait but not implemented +//│ ╔══[ERROR] Member `toString` is declared in parent but not implemented //│ ║ l.38: class ErrC1 extends Showable -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.5: fun toString: string +//│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method toString: //│ ║ l.40: fun toString = 114 //│ ║ ^^^^^^^^^^^^^^ @@ -55,7 +58,7 @@ class ErrC3(toString: string -> string) extends Showable //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun toString: string //│ ║ ^^^^^^ -//│ ╟── from signature of member toString: +//│ ╟── from signature of member `toString`: //│ ║ l.5: fun toString: string //│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in function type: @@ -65,14 +68,16 @@ class ErrC3(toString: string -> string) extends Showable //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun toString: string //│ ║ ^^^^^^ -//│ ╟── from signature of member toString: +//│ ╟── from signature of member `toString`: //│ ║ l.5: fun toString: string //│ ╙── ^^^^^^^^^^^^^^^^ -//│ class ErrC1 -//│ class ErrC2 { +//│ class ErrC1 extends Showable { +//│ fun toString: string +//│ } +//│ class ErrC2 extends Showable { //│ fun toString: 114 //│ } -//│ class ErrC3(toString: string -> string) +//│ class ErrC3(toString: string -> string) extends Showable trait Stadt { let name: string @@ -85,7 +90,7 @@ trait RefinedStadt extends Stadt { let size: int fun foo: bool -> int } -//│ trait RefinedStadt { +//│ trait RefinedStadt extends Stadt { //│ fun foo: bool -> int //│ let name: string //│ let size: int @@ -95,7 +100,7 @@ trait SizedStadt extends RefinedStadt { let size: 1 | 2 | 3 fun bar: int -> int } -//│ trait SizedStadt { +//│ trait SizedStadt extends RefinedStadt, Stadt { //│ fun bar: int -> int //│ fun foo: bool -> int //│ let name: string @@ -107,7 +112,7 @@ class Goodstatt(size: 1 | 2) extends RefinedStadt { fun bar(x) = x fun foo(t) = if t && true then this.size else 0 } -//│ class Goodstatt(size: 1 | 2) { +//│ class Goodstatt(size: 1 | 2) extends RefinedStadt, Stadt { //│ fun bar: 'a -> 'a //│ fun foo: bool -> (0 | 1 | 2) //│ let name: "good" @@ -117,47 +122,58 @@ class Goodstatt(size: 1 | 2) extends RefinedStadt { class Errcity(size: int) extends SizedStadt { fun bar = "hahaha" } -//│ ╔══[ERROR] Member name is declared in parent trait but not implemented -//│ ║ l.117: class Errcity(size: int) extends SizedStadt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.118: fun bar = "hahaha" -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member foo is declared in parent trait but not implemented -//│ ║ l.117: class Errcity(size: int) extends SizedStadt { +//│ ╔══[ERROR] Member `name` is declared in parent but not implemented +//│ ║ l.122: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.118: fun bar = "hahaha" -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.123: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.83: let name: string +//│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.117: class Errcity(size: int) extends SizedStadt { +//│ ║ l.122: class Errcity(size: int) extends SizedStadt { //│ ║ ^^^ //│ ╟── type `int` does not match type `1 | 2 | 3` //│ ╟── Note: constraint arises from union type: -//│ ║ l.95: let size: 1 | 2 | 3 -//│ ╙── ^^^^^^^^^ +//│ ║ l.100: let size: 1 | 2 | 3 +//│ ║ ^^^^^^^^^ +//│ ╟── from signature of member `size`: +//│ ║ l.100: let size: 1 | 2 | 3 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented +//│ ║ l.122: class Errcity(size: int) extends SizedStadt { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.123: fun bar = "hahaha" +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.91: fun foo: bool -> int +//│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.118: fun bar = "hahaha" +//│ ║ l.123: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── string literal of type `"hahaha"` is not a function -//│ ║ l.118: fun bar = "hahaha" +//│ ║ l.123: fun bar = "hahaha" //│ ║ ^^^^^^^^ //│ ╟── but it flows into definition of method bar with expected type `int -> int` -//│ ║ l.118: fun bar = "hahaha" +//│ ║ l.123: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.96: fun bar: int -> int -//│ ║ ^^^^^^^^^^ -//│ ╟── from signature of member bar: -//│ ║ l.96: fun bar: int -> int -//│ ╙── ^^^^^^^^^^^^^^^ -//│ class Errcity(size: int) { +//│ ║ l.101: fun bar: int -> int +//│ ║ ^^^^^^^^^^ +//│ ╟── from signature of member `bar`: +//│ ║ l.101: fun bar: int -> int +//│ ╙── ^^^^^^^^^^^^^^^ +//│ class Errcity(size: int) extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: "hahaha" +//│ fun foo: bool -> int +//│ let name: string //│ } module Omg extends Stadt { fun name = "omg!!!" fun cool(x) = x + x } -//│ module Omg { +//│ module Omg extends Stadt { //│ fun cool: int -> int //│ fun name: "omg!!!" //│ } @@ -181,7 +197,7 @@ mixin Fooo { //│ } class Grassberg(name: "grass" | "GRASS") extends More, SizedStadt, Fooo -//│ class Grassberg(name: "GRASS" | "grass") { +//│ class Grassberg(name: "GRASS" | "grass") extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 //│ fun more: number -> bool @@ -194,18 +210,21 @@ class Dirtberg extends More, SizedStadt, Fooo { fun size = 4 // this should not check } //│ ╔══[ERROR] Type mismatch in definition of method size: -//│ ║ l.194: fun size = 4 // this should not check +//│ ║ l.210: fun size = 4 // this should not check //│ ║ ^^^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.194: fun size = 4 // this should not check +//│ ║ l.210: fun size = 4 // this should not check //│ ║ ^ //│ ╟── but it flows into definition of method size with expected type `1 | 2 | 3` -//│ ║ l.194: fun size = 4 // this should not check +//│ ║ l.210: fun size = 4 // this should not check //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.95: let size: 1 | 2 | 3 -//│ ╙── ^^^^^^^^^ -//│ class Dirtberg { +//│ ║ l.100: let size: 1 | 2 | 3 +//│ ║ ^^^^^^^^^ +//│ ╟── from signature of member `size`: +//│ ║ l.100: let size: 1 | 2 | 3 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ class Dirtberg extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 //│ fun more: number -> bool @@ -214,7 +233,7 @@ class Dirtberg extends More, SizedStadt, Fooo { //│ } class Iceburg(name: string) extends RefinedStadt, More, Fooo -//│ class Iceburg(name: string) { +//│ class Iceburg(name: string) extends RefinedStadt, Stadt { //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 //│ fun more: number -> bool @@ -229,21 +248,21 @@ class A { fun x: int = 1 } :e class B extends A { fun x = "A" } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.230: class B extends A { fun x = "A" } +//│ ║ l.249: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── string literal of type `"A"` is not an instance of type `int` -//│ ║ l.230: class B extends A { fun x = "A" } +//│ ║ l.249: class B extends A { fun x = "A" } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `int` -//│ ║ l.230: class B extends A { fun x = "A" } +//│ ║ l.249: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.224: class A { fun x: int = 1 } +//│ ║ l.243: class A { fun x: int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.224: class A { fun x: int = 1 } +//│ ║ l.243: class A { fun x: int = 1 } //│ ╙── ^^^^^^^^^^ -//│ class B { +//│ class B extends A { //│ fun x: "A" //│ } @@ -253,7 +272,7 @@ class C1[A] { fun a: A = a } //│ } class C2 extends C1[int] { fun a = 1 } -//│ class C2 { +//│ class C2 extends C1 { //│ fun a: 1 //│ } @@ -270,28 +289,28 @@ trait MyTrait[A] { fun a: A } // :d // :ds class C extends MyTrait[int] { fun a = 1 } -//│ class C { +//│ class C extends MyTrait { //│ fun a: 1 //│ } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.278: class C extends MyTrait[int] { fun a = false } +//│ ║ l.297: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.278: class C extends MyTrait[int] { fun a = false } +//│ ║ l.297: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.278: class C extends MyTrait[int] { fun a = false } +//│ ║ l.297: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.278: class C extends MyTrait[int] { fun a = false } +//│ ║ l.297: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ -//│ ╟── from signature of member a: -//│ ║ l.264: trait MyTrait[A] { fun a: A } +//│ ╟── from signature of member `a`: +//│ ║ l.283: trait MyTrait[A] { fun a: A } //│ ╙── ^^^^ -//│ class C { +//│ class C extends MyTrait { //│ fun a: false //│ } @@ -316,13 +335,13 @@ trait T2 { trait T4 extends T1, T2 { fun foo: 2 } -//│ trait T4 { +//│ trait T4 extends T1, T2 { //│ fun bar: bool //│ fun foo: 2 //│ } class C1(foo: 2, bar: true) extends T4 -//│ class C1(foo: 2, bar: true) +//│ class C1(foo: 2, bar: true) extends T1, T2, T4 :e class C3 extends T4{ @@ -330,21 +349,21 @@ class C3 extends T4{ fun bar = false } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.329: fun foo = 3 +//│ ║ l.348: fun foo = 3 //│ ║ ^^^^^^^ //│ ╟── integer literal of type `3` does not match type `2` -//│ ║ l.329: fun foo = 3 +//│ ║ l.348: fun foo = 3 //│ ║ ^ //│ ╟── but it flows into definition of method foo with expected type `2` -//│ ║ l.329: fun foo = 3 +//│ ║ l.348: fun foo = 3 //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from literal type: -//│ ║ l.317: fun foo: 2 +//│ ║ l.336: fun foo: 2 //│ ║ ^ -//│ ╟── from signature of member foo: -//│ ║ l.317: fun foo: 2 +//│ ╟── from signature of member `foo`: +//│ ║ l.336: fun foo: 2 //│ ╙── ^^^^^^ -//│ class C3 { +//│ class C3 extends T1, T2, T4 { //│ fun bar: false //│ fun foo: 3 //│ } @@ -352,39 +371,47 @@ class C3 extends T4{ :e class C2(foo: int, bar: string) extends T4 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.353: class C2(foo: int, bar: string) extends T4 +//│ ║ l.372: class C2(foo: int, bar: string) extends T4 //│ ║ ^^^ //│ ╟── type `int` does not match type `2` //│ ╟── Note: constraint arises from literal type: -//│ ║ l.317: fun foo: 2 +//│ ║ l.336: fun foo: 2 //│ ║ ^ -//│ ╟── from signature of member foo: -//│ ║ l.317: fun foo: 2 +//│ ╟── from signature of member `foo`: +//│ ║ l.336: fun foo: 2 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.353: class C2(foo: int, bar: string) extends T4 +//│ ║ l.372: class C2(foo: int, bar: string) extends T4 //│ ║ ^^^^^^ //│ ╟── type `string` does not match type `bool | int` //│ ╟── Note: constraint arises from union type: -//│ ║ l.305: let bar : int | bool -//│ ╙── ^^^^^^^^^^ -//│ class C2(foo: int, bar: string) +//│ ║ l.324: let bar : int | bool +//│ ║ ^^^^^^^^^^ +//│ ╟── from signature of member `bar`: +//│ ║ l.324: let bar : int | bool +//│ ╙── ^^^^^^^^^^^^^^^^ +//│ class C2(foo: int, bar: string) extends T1, T2, T4 :e trait T5 extends T4 { let foo: 4 } -//│ ╔══[ERROR] Type mismatch in literal type: -//│ ║ l.375: let foo: 4 -//│ ║ ^ +//│ ╔══[ERROR] Type mismatch in signature of member `foo`: +//│ ║ l.397: let foo: 4 +//│ ║ ^^^^^^ //│ ╟── type `4` does not match type `2` +//│ ║ l.397: let foo: 4 +//│ ║ ^ +//│ ╟── but it flows into signature of member `foo` with expected type `2` +//│ ║ l.397: let foo: 4 +//│ ║ ^^^^^^ //│ ╟── Note: constraint arises from literal type: -//│ ║ l.317: fun foo: 2 +//│ ║ l.336: fun foo: 2 //│ ║ ^ -//│ ╟── from signature of member foo: -//│ ║ l.317: fun foo: 2 +//│ ╟── from signature of member `foo`: +//│ ║ l.336: fun foo: 2 //│ ╙── ^^^^^^ -//│ trait T5 { +//│ trait T5 extends T1, T2, T4 { //│ fun bar: bool //│ let foo: 4 //│ } @@ -393,21 +420,37 @@ trait T5 extends T4 { trait T3 extends T1, T2 { let foo: true } -//│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.394: let foo: true -//│ ║ ^^^^ +//│ ╔══[ERROR] Type mismatch in signature of member `foo`: +//│ ║ l.421: let foo: true +//│ ║ ^^^^^^^^^ //│ ╟── type `true` does not match type `1 | 2 | 3` -//│ ╟── Note: constraint arises from union type: -//│ ║ l.300: let foo : 1 | 2 | 3 -//│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.394: let foo: true +//│ ║ l.421: let foo: true //│ ║ ^^^^ +//│ ╟── but it flows into signature of member `foo` with expected type `1 | 2 | 3` +//│ ║ l.421: let foo: true +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.319: let foo : 1 | 2 | 3 +//│ ║ ^^^^^^^^^ +//│ ╟── from signature of member `foo`: +//│ ║ l.319: let foo : 1 | 2 | 3 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in signature of member `foo`: +//│ ║ l.421: let foo: true +//│ ║ ^^^^^^^^^ //│ ╟── type `true` does not match type `2 | 3 | 4` +//│ ║ l.421: let foo: true +//│ ║ ^^^^ +//│ ╟── but it flows into signature of member `foo` with expected type `2 | 3 | 4` +//│ ║ l.421: let foo: true +//│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.304: let foo : 2 | 3 | 4 -//│ ╙── ^^^^^^^^^ -//│ trait T3 { +//│ ║ l.323: let foo : 2 | 3 | 4 +//│ ║ ^^^^^^^^^ +//│ ╟── from signature of member `foo`: +//│ ║ l.323: let foo : 2 | 3 | 4 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ trait T3 extends T1, T2 { //│ fun bar: bool //│ let foo: true //│ } diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 6b0d3fda6b..26394e9b6f 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -1,5 +1,6 @@ :NewDefs -:NoJS + +:NoJS // TODO trait Test { fun foo: int @@ -18,7 +19,7 @@ module M extends Test { fun foo = 0 fun bar = not } -//│ module M { +//│ module M extends Test { //│ fun bar: bool -> bool //│ fun foo: 0 //│ } @@ -33,7 +34,7 @@ trait Oth extends Test { let a : int fun cool : int -> bool } -//│ trait Oth { +//│ trait Oth extends Test { //│ let a: int //│ fun bar: bool -> bool //│ fun cool: int -> bool @@ -53,23 +54,23 @@ oth1: Test M : Oth oth1: M //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.53: M : Oth +//│ ║ l.54: M : Oth //│ ║ ^ //│ ╟── reference of type `M` is not an instance of type `Oth` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.53: M : Oth +//│ ║ l.54: M : Oth //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.54: oth1: M +//│ ║ l.55: oth1: M //│ ║ ^^^^ //│ ╟── type `#Oth` is not an instance of type `M` -//│ ║ l.43: let oth1: Oth +//│ ║ l.44: let oth1: Oth //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `M` -//│ ║ l.54: oth1: M +//│ ║ l.55: oth1: M //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.54: oth1: M +//│ ║ l.55: oth1: M //│ ╙── ^ //│ M @@ -95,7 +96,7 @@ trait Anemo { //│ } trait Mixed extends Geo, Anemo -//│ trait Mixed { +//│ trait Mixed extends Anemo, Geo { //│ fun get: bool //│ fun ter: nothing //│ let v: 2 @@ -106,7 +107,7 @@ class C extends Test { fun foo: 1 = 1 fun bar(x) = x } -//│ class C { +//│ class C extends Test { //│ fun bar: bool -> bool //│ fun foo: 1 //│ } @@ -127,7 +128,7 @@ class F extends Oth, M, Mixed { let a = 3 let v = 2 } -//│ class F { +//│ class F extends Anemo, Geo, Mixed, Oth, Test { //│ let a: 3 //│ fun bar: bool -> bool //│ fun cool: number -> bool @@ -159,16 +160,16 @@ fog: Test & Anemo :e fog: F //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.160: fog: F +//│ ║ l.161: fog: F //│ ║ ^^^ //│ ╟── type `Mixed & Oth` is not an instance of type `F` -//│ ║ l.153: let fog: Oth & Mixed +//│ ║ l.154: let fog: Oth & Mixed //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `F` -//│ ║ l.160: fog: F +//│ ║ l.161: fog: F //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.160: fog: F +//│ ║ l.161: fog: F //│ ╙── ^ //│ F @@ -194,16 +195,16 @@ c: Test :e c: Oth //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.195: c: Oth +//│ ║ l.196: c: Oth //│ ║ ^ //│ ╟── application of type `C` is not an instance of type `Oth` -//│ ║ l.175: let c = C() +//│ ║ l.176: let c = C() //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#Oth` -//│ ║ l.195: c: Oth +//│ ║ l.196: c: Oth //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.195: c: Oth +//│ ║ l.196: c: Oth //│ ╙── ^^^ //│ Oth @@ -223,16 +224,16 @@ fun ffm(x: F) = x.get :e fun fee(x: Test) = x: Oth //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.224: fun fee(x: Test) = x: Oth +//│ ║ l.225: fun fee(x: Test) = x: Oth //│ ║ ^ //│ ╟── type `#Test` is not an instance of type `Oth` -//│ ║ l.224: fun fee(x: Test) = x: Oth +//│ ║ l.225: fun fee(x: Test) = x: Oth //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `#Oth` -//│ ║ l.224: fun fee(x: Test) = x: Oth +//│ ║ l.225: fun fee(x: Test) = x: Oth //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.224: fun fee(x: Test) = x: Oth +//│ ║ l.225: fun fee(x: Test) = x: Oth //│ ╙── ^^^ //│ fun fee: (x: Test,) -> Oth @@ -264,21 +265,21 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.264: fun a1 = 4 +//│ ║ l.265: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.264: fun a1 = 4 +//│ ║ l.265: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.264: fun a1 = 4 +//│ ║ l.265: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.253: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.254: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ -//│ ╟── from signature of member a1: -//│ ║ l.253: trait A1 { fun a1: 1 | 2 | 3 } +//│ ╟── from signature of member `a1`: +//│ ║ l.254: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ -//│ class Ea1 { +//│ class Ea1 extends A1, A2 { //│ fun a1: 4 //│ } @@ -292,7 +293,7 @@ trait Ele { class CE extends Ele { fun ce(x) = x } -//│ class CE { +//│ class CE extends Ele { //│ fun ce: (Test & 'a) -> (Oth | 'a) //│ } @@ -300,26 +301,30 @@ class CE extends Ele { class E1 extends Test { fun foo = 2 } -//│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.300: class E1 extends Test { +//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented +//│ ║ l.301: class E1 extends Test { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.301: fun foo = 2 -//│ ╙── ^^^^^^^^^^^^^ -//│ class E1 { +//│ ║ l.302: fun foo = 2 +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.7: fun bar: bool -> bool +//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ class E1 extends Test { +//│ fun bar: bool -> bool //│ fun foo: 2 //│ } :e trait TE1 extends C trait TE2 extends M, Test -//│ ╔══[ERROR] trait can only inherit from traits -//│ ║ l.313: trait TE1 extends C +//│ ╔══[ERROR] A trait can only inherit from other traits +//│ ║ l.318: trait TE1 extends C //│ ╙── ^ -//│ ╔══[ERROR] trait can only inherit from traits -//│ ║ l.314: trait TE2 extends M, Test +//│ ╔══[ERROR] A trait can only inherit from other traits +//│ ║ l.319: trait TE2 extends M, Test //│ ╙── ^ -//│ trait TE1 -//│ trait TE2 { +//│ trait TE1 extends C, Test +//│ trait TE2 extends Test { //│ fun bar: bool -> bool //│ fun foo: int //│ } @@ -330,21 +335,21 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.329: fun foo = true +//│ ║ l.334: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.329: fun foo = true +//│ ║ l.334: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.329: fun foo = true +//│ ║ l.334: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: fun foo: int +//│ ║ l.6: fun foo: int //│ ║ ^^^ -//│ ╟── from signature of member foo: -//│ ║ l.5: fun foo: int +//│ ╟── from signature of member `foo`: +//│ ║ l.6: fun foo: int //│ ╙── ^^^^^^^^ -//│ class E2 { +//│ class E2 extends Test { //│ fun bar: bool -> bool //│ fun foo: true //│ } @@ -353,18 +358,27 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ║ l.359: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.354: class D extends Test[int], Test[bool] +//│ ║ l.359: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Member foo is declared in parent trait but not implemented -//│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.354: class D extends Test[int], Test[bool] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ class D +//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented +//│ ║ l.359: class D extends Test[int], Test[bool] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.6: fun foo: int +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented +//│ ║ l.359: class D extends Test[int], Test[bool] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.7: fun bar: bool -> bool +//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ class D extends Test { +//│ fun bar: bool -> bool +//│ fun foo: int +//│ } @@ -372,8 +386,8 @@ trait Base: A | B class A extends Base class B extends Base //│ trait Base: A | B -//│ class A -//│ class B +//│ class A extends Base +//│ class B extends Base let b: Base = A() @@ -397,8 +411,8 @@ trait Base: Foo | Bar class Foo[A](aa: (A, A)) extends Base class Bar[B](f: B => B) extends Base //│ trait Base: Bar[?] | Foo[anything] -//│ class Foo[A](aa: (A, A,)) -//│ class Bar[B](f: B -> B) +//│ class Foo[A](aa: (A, A,)) extends Base +//│ class Bar[B](f: B -> B) extends Base let f: Foo = Foo((1, 2)) //│ let f: Foo[anything] @@ -415,10 +429,10 @@ if b is Foo(a) then a else 0 :e // * Note: an error is raised in this case and not above because B is invariant so it can't be widened if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.416: if b is Bar(f) then f else 0 +//│ ║ l.430: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.398: class Bar[B](f: B => B) extends Base +//│ ║ l.412: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -427,28 +441,28 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.426: if b is +//│ ║ l.440: if b is //│ ║ ^^^^ -//│ ║ l.427: Foo(a) then a +//│ ║ l.441: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.428: Bar(f) then f +//│ ║ l.442: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.398: class Bar[B](f: B => B) extends Base +//│ ║ l.412: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything :e let tt1 = Test //│ ╔══[ERROR] trait Test cannot be used in term position -//│ ║ l.442: let tt1 = Test +//│ ║ l.456: let tt1 = Test //│ ╙── ^^^^ //│ let tt1: error :e fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot match on trait `Test` -//│ ║ l.449: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.463: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -458,10 +472,10 @@ trait GL extends Geo trait WP extends ZL, GL trait EM extends WP, Geo //│ trait Geo -//│ trait ZL -//│ trait GL -//│ trait WP -//│ trait EM +//│ trait ZL extends Geo +//│ trait GL extends Geo +//│ trait WP extends GL, Geo, ZL +//│ trait EM extends GL, Geo, WP, ZL let g: Geo let z: ZL @@ -489,40 +503,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.487: fun fto(w: WP): EM = w +//│ ║ l.501: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.487: fun fto(w: WP): EM = w +//│ ║ l.501: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.487: fun fto(w: WP): EM = w +//│ ║ l.501: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.487: fun fto(w: WP): EM = w +//│ ║ l.501: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.488: z: WP +//│ ║ l.502: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.467: let z: ZL +//│ ║ l.481: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.488: z: WP +//│ ║ l.502: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.488: z: WP +//│ ║ l.502: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.489: g: ZL +//│ ║ l.503: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.466: let g: Geo +//│ ║ l.480: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.489: g: ZL +//│ ║ l.503: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.489: g: ZL +//│ ║ l.503: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -538,7 +552,7 @@ class Ih extends Bs(false) { fun bar(x) = x fun foo(x) = 1 } -//│ class Ih { +//│ class Ih extends Bs { //│ fun bar: 'a -> 'a //│ fun foo: anything -> 1 //│ } @@ -553,7 +567,7 @@ ih1: Bs //│ Bs ih1.a -//│ bool +//│ false :e class Eh2 extends Bs(true), Ele { @@ -561,22 +575,22 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.560: fun foo(x) = x && false +//│ ║ l.574: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ??_` is not an instance of type `bool` +//│ ╟── expression of type `int & ?a` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.560: fun foo(x) = x && false +//│ ║ l.574: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.560: fun foo(x) = x && false +//│ ║ l.574: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.560: fun foo(x) = x && false +//│ ╟── operator application of type `bool` does not match type `int | ?a` +//│ ║ l.574: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.531: fun foo(x) = x + 1 +//│ ║ l.545: fun foo(x) = x + 1 //│ ╙── ^^^^^ -//│ class Eh2 { +//│ class Eh2 extends Bs, Ele { //│ fun ce: (Test & 'a) -> (Oth | 'a) //│ fun foo: bool -> bool //│ } @@ -586,49 +600,53 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.585: class Eh extends Bs(1) +//│ ║ l.599: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.585: class Eh extends Bs(1) +//│ ║ l.599: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.530: class Bs(a: bool) { +//│ ║ l.544: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in integer literal: -//│ ║ l.585: class Eh extends Bs(1) +//│ ║ l.599: class Eh extends Bs(1) //│ ║ ^ //│ ╟── integer literal of type `1` is not an instance of type `bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.530: class Bs(a: bool) { +//│ ║ l.544: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.586: class Eh1 extends Bs +//│ ║ l.600: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.531: fun foo(x) = x + 1 +//│ ║ l.545: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.531: fun foo(x) = x + 1 +//│ ║ l.545: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.531: fun foo(x) = x + 1 +//│ ║ l.545: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: fun foo: int +//│ ║ l.6: fun foo: int //│ ║ ^^^ -//│ ╟── from signature of member foo: -//│ ║ l.5: fun foo: int +//│ ╟── from signature of member `foo`: +//│ ║ l.6: fun foo: int //│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Member bar is declared in parent trait but not implemented -//│ ║ l.587: class Eh3 extends Bs(false), Test -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ class Eh { +//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented +//│ ║ l.601: class Eh3 extends Bs(false), Test +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.7: fun bar: bool -> bool +//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ class Eh extends Bs { //│ fun foo: int -> int //│ } -//│ class Eh1 { +//│ class Eh1 extends Bs { //│ fun foo: int -> int //│ } -//│ class Eh3 { +//│ class Eh3 extends Bs, Test { +//│ fun bar: bool -> bool //│ fun foo: int -> int //│ } @@ -637,14 +655,14 @@ class Ca(a: int) extends Oth { fun cool(x) = false fun bar(x) = x } -//│ class Ca(a: int) { +//│ class Ca(a: int) extends Oth, Test { //│ fun bar: bool -> bool //│ fun cool: anything -> false //│ fun foo: 1 //│ } class Cx(a: 1 | 2, b: bool) extends Ca(a) -//│ class Cx(a: 1 | 2, b: bool) { +//│ class Cx(a: 1 | 2, b: bool) extends Ca, Oth, Test { //│ fun bar: bool -> bool //│ fun cool: anything -> false //│ fun foo: 1 @@ -676,14 +694,14 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.677: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.695: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ -//│ class Bc12 +//│ class Bc12 extends Bc1, Bc2 class Bc02 extends Bc1(1:int) { let foo = 2 } -//│ class Bc02 { +//│ class Bc02 extends Bc1 { //│ let foo: 2 //│ } @@ -693,33 +711,36 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.694: class Bc31(baz: bool) extends Bc3 +//│ ║ l.712: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ -//│ ╟── type `bool` is not an instance of type `int` +//│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.668: let baz : int -//│ ╙── ^^^ -//│ class Bc31(baz: bool) +//│ ║ l.686: let baz : int +//│ ║ ^^^ +//│ ╟── from signature of member `baz`: +//│ ║ l.686: let baz : int +//│ ╙── ^^^^^^^^^ +//│ class Bc31(baz: bool) extends Bc3 :e class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.706: let foo = true -//│ ║ ^^^^ -//│ ╟── reference of type `true` does not match type `1` -//│ ╟── Note: constraint arises from integer literal: -//│ ║ l.705: class Bc11 extends Bc1(1) { -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.706: let foo = true +//│ ║ l.727: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.665: class Bc1(foo: int) +//│ ║ l.683: class Bc1(foo: int) //│ ╙── ^^^ -//│ class Bc11 { +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.727: let foo = true +//│ ║ ^^^^ +//│ ╟── reference of type `true` does not match type `1` +//│ ╟── Note: constraint arises from integer literal: +//│ ║ l.726: class Bc11 extends Bc1(1) { +//│ ╙── ^ +//│ class Bc11 extends Bc1 { //│ let foo: true //│ } @@ -730,24 +751,28 @@ trait Base[A] { fun f: A -> A } //│ } class Der1 extends Base[int] { fun f(x) = x + 1 } -//│ class Der1 { +//│ class Der1 extends Base { //│ fun f: int -> int //│ } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } -//│ class Der2[A, B] { +//│ class Der2[A, B] extends Base { //│ fun f: (A, B,) -> (A, B,) //│ } +:e trait BInt extends Base[int] { fun f = error } -//│ trait BInt { +//│ ╔══[ERROR] Method implementations in traits are not yet supported +//│ ║ l.765: fun f = error +//│ ╙── ^^^^^^^^^ +//│ trait BInt extends Base { //│ fun f: nothing //│ } trait BPar[T] extends Base[(int,T)] -//│ trait BPar[T] { +//│ trait BPar[T] extends Base { //│ fun f: 'A -> 'A //│ } //│ where @@ -764,13 +789,13 @@ bp: Base[(int, bool)] :e bp: Base[(int, int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.765: bp: Base[(int, int)] +//│ ║ l.790: bp: Base[(int, int)] //│ ║ ^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.757: let bp: BPar[bool] +//│ ║ l.782: let bp: BPar[bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.765: bp: Base[(int, int)] +//│ ║ l.790: bp: Base[(int, int)] //│ ╙── ^^^ //│ Base[(int, int,)] @@ -789,7 +814,7 @@ fb(bp, false) class CP extends BPar[int] { fun f(x) = (x._2, x._1) } -//│ class CP { +//│ class CP extends BPar, Base { //│ fun f: {_1: int, _2: int} -> (int, int,) //│ } @@ -800,54 +825,61 @@ fb(cp1, 2) //│ (int, int,) trait BInfer1 extends Base -//│ trait BInfer1 { +//│ trait BInfer1 extends Base { //│ fun f: 'A -> 'A //│ } trait BInfer2 extends Base { fun f: int -> int } -//│ trait BInfer2 { +//│ trait BInfer2 extends Base { //│ fun f: int -> int //│ } :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.815: class DerBad1 extends Base[int, int] +//│ ║ l.840: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member f is declared in parent trait but not implemented -//│ ║ l.815: class DerBad1 extends Base[int, int] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ class DerBad1 +//│ ╔══[ERROR] Member `f` is declared in parent but not implemented +//│ ║ l.840: class DerBad1 extends Base[int, int] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.748: trait Base[A] { fun f: A -> A } +//│ ╙── ^^^^^^^^^ +//│ class DerBad1 extends Base { +//│ fun f: 'A -> 'A +//│ } +//│ where +//│ 'A := int :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.825: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ -//│ class Der2[A, B] { +//│ class Der2[A, B] extends Base { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) //│ } @@ -877,10 +909,14 @@ k1.k.g k1.k.p //│ bool +:e trait Tb extends Ta[int] { let p = false } -//│ trait Tb { +//│ ╔══[ERROR] Method implementations in traits are not yet supported +//│ ║ l.914: let p = false +//│ ╙── ^^^^^^^^^ +//│ trait Tb extends Ta { //│ let g: 'T //│ let p: false //│ } @@ -891,7 +927,7 @@ class Ctb extends Tb { let p = false let g = 2 } -//│ class Ctb { +//│ class Ctb extends Ta, Tb { //│ let g: 2 //│ let p: false //│ } @@ -900,7 +936,7 @@ class G1[A](x: A) //│ class G1[A](x: A) class GI(x: int) extends G1[int](x) -//│ class GI(x: int) +//│ class GI(x: int) extends G1 trait Oz { let age: int @@ -912,16 +948,19 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.913: class Fischl(age: bool) extends Oz +//│ ║ l.949: class Fischl(age: bool) extends Oz //│ ║ ^^^^ -//│ ╟── type `bool` is not an instance of type `int` +//│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.906: let age: int -//│ ╙── ^^^ -//│ class Fischl(age: bool) +//│ ║ l.942: let age: int +//│ ║ ^^^ +//│ ╟── from signature of member `age`: +//│ ║ l.942: let age: int +//│ ╙── ^^^^^^^^ +//│ class Fischl(age: bool) extends Oz class Klee(age: 1 | 2 | 3) extends Oz -//│ class Klee(age: 1 | 2 | 3) +//│ class Klee(age: 1 | 2 | 3) extends Oz class Fate { fun foo(x) = x + 1 @@ -935,22 +974,22 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.935: fun foo(x) = x && true +//│ ║ l.974: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ??_` is not an instance of type `bool` +//│ ╟── expression of type `int & ?a` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.935: fun foo(x) = x && true +//│ ║ l.974: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.935: fun foo(x) = x && true +//│ ║ l.974: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.935: fun foo(x) = x && true +//│ ╟── operator application of type `bool` does not match type `int | ?a` +//│ ║ l.974: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.927: fun foo(x) = x + 1 +//│ ║ l.966: fun foo(x) = x + 1 //│ ╙── ^^^^^ -//│ class Go { +//│ class Go extends Fate { //│ fun foo: bool -> bool //│ } @@ -960,18 +999,18 @@ class Ha { let x: int = 1 } //│ } class Haha(x: 1 | 2) extends Ha -//│ class Haha(x: 1 | 2) +//│ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.966: class Ohhh(x: bool) extends Ha -//│ ║ ^^^^ +//│ ║ l.1005: class Ohhh(x: bool) extends Ha +//│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.957: class Ha { let x: int = 1 } +//│ ║ l.996: class Ha { let x: int = 1 } //│ ╙── ^^^ -//│ class Ohhh(x: bool) +//│ class Ohhh(x: bool) extends Ha trait TA[A] { let a : A } //│ trait TA[A] { @@ -979,10 +1018,10 @@ trait TA[A] { let a : A } //│ } class G1[A, B](a: A, b: B) extends TA[A] -//│ class G1[A, B](a: A, b: B) +//│ class G1[A, B](a: A, b: B) extends TA class G2[T](x: T) extends G1[T, int](x, 1) -//│ class G2[T](x: T) +//│ class G2[T](x: T) extends G1, TA let g21 = G2(false) //│ let g21: G2[false] diff --git a/shared/src/test/diff/nu/MemberConfusion.mls b/shared/src/test/diff/nu/MemberConfusion.mls index 9e3f8b684d..d627b04a4a 100644 --- a/shared/src/test/diff/nu/MemberConfusion.mls +++ b/shared/src/test/diff/nu/MemberConfusion.mls @@ -25,7 +25,7 @@ class C(a: int) extends B //│ ╟── Note: constraint arises from string literal: //│ ║ l.14: class B { let a = "hi" } //│ ╙── ^^^^ -//│ class C(a: int) +//│ class C(a: int) extends B mixin M { let b = "hi" } @@ -39,7 +39,7 @@ class B { let a = 1 : int } //│ } class C(a: int, b: int) extends B, M -//│ class C(a: int, b: int) { +//│ class C(a: int, b: int) extends B { //│ let b: "hi" //│ } @@ -68,7 +68,7 @@ class C(a: int) { fun a = a } //│ } class C(a: int, b: int) extends B, M { let b = "hi" } -//│ class C(a: int, b: int) { +//│ class C(a: int, b: int) extends B { //│ let b: "hi" //│ } diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls new file mode 100644 index 0000000000..6234954272 --- /dev/null +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -0,0 +1,117 @@ +:NewDefs + +:NoJS // TODO + + +trait T1 { fun f[A]: A -> A } +trait T2 { fun f[B, C]: (B, C) -> (B, C) } +trait T3 extends T1, T2 +//│ trait T1 { +//│ fun f: forall 'A. 'A -> 'A +//│ } +//│ trait T2 { +//│ fun f: forall 'B 'C. ('B, 'C,) -> ('B, 'C,) +//│ } +//│ trait T3 extends T1, T2 { +//│ fun f: forall 'A 'B 'C. 'A -> 'A & ('B, 'C,) -> ('B, 'C,) +//│ } + + +trait S1 { class f } +//│ trait S1 { +//│ class f +//│ } + +:e +trait S2 extends T1, S1 +//│ ╔══[ERROR] Intersection of value member and class members currently unsupported +//│ ║ l.26: trait S2 extends T1, S1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── The value member is defined here: +//│ ║ l.6: trait T1 { fun f[A]: A -> A } +//│ ║ ^^^^^^^^^^^^ +//│ ╟── The class member is defined here: +//│ ║ l.20: trait S1 { class f } +//│ ╙── ^^^^^^^ +//│ trait S2 extends S1, T1 + +trait S2 { class f } +//│ trait S2 { +//│ class f +//│ } + +:e +trait S3 extends S1, S2 +//│ ╔══[ERROR] Intersection of class member and class members currently unsupported +//│ ║ l.44: trait S3 extends S1, S2 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── The class member is defined here: +//│ ║ l.20: trait S1 { class f } +//│ ║ ^^^^^^^ +//│ ╟── The class member is defined here: +//│ ║ l.38: trait S2 { class f } +//│ ╙── ^^^^^^^ +//│ trait S3 extends S1, S2 + + +trait S1 { val f: int -> int } +//│ trait S1 { +//│ let f: int -> int +//│ } + +trait S2 extends T1, S1 +//│ trait S2 extends S1, T1 { +//│ fun f: forall 'A. 'A -> 'A & int -> int +//│ } + +trait S3 extends S1, T1 +//│ trait S3 extends S1, T1 { +//│ fun f: forall 'A. int -> int & 'A -> 'A +//│ } + + +class C1(x: int | bool) +trait T1 { val x: int | string } +//│ class C1(x: bool | int) +//│ trait T1 { +//│ let x: int | string +//│ } + +class C2 extends C1(0), T1 +//│ class C2 extends C1, T1 + +:e +class C2 extends C1(false), T1 +//│ ╔══[ERROR] Type mismatch in reference: +//│ ║ l.84: class C2 extends C1(false), T1 +//│ ║ ^^^^^ +//│ ╟── reference of type `false` does not match type `int | string` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.74: trait T1 { val x: int | string } +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from signature of member `x`: +//│ ║ l.74: trait T1 { val x: int | string } +//│ ╙── ^^^^^^^^^^^^^^^ +//│ class C2 extends C1, T1 + +:e +class C2 extends C1("oops"), T1 +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.98: class C2 extends C1("oops"), T1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── string literal of type `"oops"` does not match type `bool | int` +//│ ║ l.98: class C2 extends C1("oops"), T1 +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.73: class C1(x: int | bool) +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in string literal: +//│ ║ l.98: class C2 extends C1("oops"), T1 +//│ ║ ^^^^^^ +//│ ╟── string literal of type `"oops"` does not match type `bool | int` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.73: class C1(x: int | bool) +//│ ╙── ^^^^^^^^^^ +//│ class C2 extends C1, T1 + + diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index e23ce1e0ec..645d091668 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -14,7 +14,7 @@ module Oops { module Oops { fun a : int } -//│ ╔══[ERROR] Member a is declared but not defined +//│ ╔══[ERROR] Member `a` is declared but not defined //│ ║ l.15: fun a : int //│ ╙── ^ //│ module Oops { @@ -27,7 +27,7 @@ module Oops { fun a : string fun a = a } -//│ ╔══[ERROR] A type signature for 'a' has already been given +//│ ╔══[ERROR] A type signature for 'a' was already given //│ ║ l.27: fun a : string //│ ╙── ^^^^^^^^^^ //│ module Oops { @@ -51,7 +51,7 @@ module Oops { //│ ╟── Note: constraint arises from type reference: //│ ║ l.39: fun a : int //│ ║ ^^^ -//│ ╟── from signature of member a: +//│ ╟── from signature of member `a`: //│ ║ l.39: fun a : int //│ ╙── ^^^^^^^ //│ module Oops { @@ -67,7 +67,7 @@ module Oops { //│ ║ l.64: fun a = 2 //│ ╙── ^^^^^ //│ module Oops { -//│ fun a: 2 +//│ fun a: 1 //│ } @@ -113,7 +113,7 @@ module A { //│ ╟── Note: constraint arises from type variable: //│ ║ l.101: fun i : 'a //│ ║ ^^ -//│ ╟── from signature of member i: +//│ ╟── from signature of member `i`: //│ ║ l.101: fun i : 'a //│ ╙── ^^^^^^ //│ module A { @@ -142,7 +142,7 @@ module M { //│ ╟── Note: constraint arises from type reference: //│ ║ l.130: fun a: A //│ ║ ^ -//│ ╟── from signature of member a: +//│ ╟── from signature of member `a`: //│ ║ l.130: fun a: A //│ ╙── ^^^^ //│ module M { diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index 78894b2a0a..f4143ab9b3 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -12,7 +12,7 @@ mixin BaseTest(x: int) { mixin BaseTest(x) { fun test = x } -//│ ╔══[ERROR] Class parameters currently need type annotations +//│ ╔══[ERROR] Mixin parameters currently need type annotations //│ ║ l.12: mixin BaseTest(x) { //│ ╙── ^ //│ mixin BaseTest(x: error) { diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls index 7bb6282bb8..4ea5616380 100644 --- a/shared/src/test/diff/nu/ParamImplementing.mls +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -19,10 +19,10 @@ class C extends T, M(false) //│ ╟── Note: constraint arises from type reference: //│ ║ l.6: trait T { fun x: int } //│ ║ ^^^ -//│ ╟── from signature of member x: +//│ ╟── from signature of member `x`: //│ ║ l.6: trait T { fun x: int } //│ ╙── ^^^^^^ -//│ class C +//│ class C extends T trait T { fun x: int } @@ -33,6 +33,6 @@ mixin M(x: number) //│ mixin M(x: number) class C extends T, M(0) -//│ class C +//│ class C extends T diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index db8a960ca2..8635dc6424 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -7,7 +7,7 @@ class Foo(x: int) class Bar(x: int, y: int) extends Foo(x + y) -//│ class Bar(x: int, y: int) +//│ class Bar(x: int, y: int) extends Foo mixin AA(a: int) { diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index 03f7d79741..3753365c72 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -82,22 +82,27 @@ trait Base2: Foo['FigureItOut] // TODO reject class Impl extends Base2 -//│ class Impl +//│ class Impl extends Base2 (x: Impl) => x : Base2 //│ (x: Impl,) -> Base2 :e class Impl extends Base2, Foo -//│ ╔══[ERROR] Member x is declared in parent trait but not implemented +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented //│ ║ l.91: class Impl extends Base2, Foo -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ class Impl +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.5: trait Foo[A] { fun x: A } +//│ ╙── ^^^^ +//│ class Impl extends Base2, Foo { +//│ fun x: nothing +//│ } class Impl extends Base2, Foo { fun x = 1 } -//│ class Impl { +//│ class Impl extends Base2, Foo { //│ fun x: 1 //│ } @@ -113,7 +118,7 @@ Impl() : Base2 class Impl2 extends Base2, Foo[int] { fun x = 1 } -//│ class Impl2 { +//│ class Impl2 extends Base2, Foo { //│ fun x: 1 //│ } diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index 4a2ccf6635..a2c4bc5a41 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -13,12 +13,8 @@ trait T2 { fun x: 1 | 2 } //│ fun x: 1 | 2 //│ } -:e // TODO mk abstract -class C1 { fun x: 0 | 2 } -//│ ╔══[ERROR] Member x is declared but not defined -//│ ║ l.17: class C1 { fun x: 0 | 2 } -//│ ╙── ^ -//│ class C1 { +abstract class C1 { fun x: 0 | 2 } +//│ abstract class C1 { //│ fun x: 0 | 2 //│ } @@ -27,50 +23,49 @@ module M extends C1, T1 { fun x = 2 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.27: fun x = 2 +//│ ║ l.23: fun x = 2 //│ ║ ^^^^^ //│ ╟── integer literal of type `2` does not match type `0 | 1` -//│ ║ l.27: fun x = 2 +//│ ║ l.23: fun x = 2 //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 1` -//│ ║ l.27: fun x = 2 +//│ ║ l.23: fun x = 2 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ║ ^^^^^ -//│ ╟── from signature of member x: +//│ ╟── from signature of member `x`: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ -//│ module M { +//│ module M extends C1, T1 { //│ fun x: 2 //│ } -:e // TODO mk abstract -class C2 extends C1, T1 -//│ ╔══[ERROR] Type mismatch in signature of member x: -//│ ║ l.17: class C1 { fun x: 0 | 2 } -//│ ║ ^^^^^^^^ -//│ ╟── type `2` does not match type `0 | 1` -//│ ║ l.17: class C1 { fun x: 0 | 2 } -//│ ║ ^ -//│ ╟── but it flows into union type with expected type `0 | 1` -//│ ║ l.17: class C1 { fun x: 0 | 2 } -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from union type: -//│ ║ l.7: trait T1 { fun x: 0 | 1 } -//│ ║ ^^^^^ -//│ ╟── from signature of member x: -//│ ║ l.7: trait T1 { fun x: 0 | 1 } -//│ ╙── ^^^^^^^^ -//│ class C2 { -//│ fun x: 0 | 2 +abstract class C2 extends C1, T1 +//│ abstract class C2 extends C1, T1 { +//│ fun x: 0 //│ } -// * TODO error? +:e module M extends C2 { fun x = 2 } -//│ module M { +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.51: fun x = 2 +//│ ║ ^^^^^ +//│ ╟── integer literal of type `2` does not match type `0 | 1` +//│ ║ l.51: fun x = 2 +//│ ║ ^ +//│ ╟── but it flows into definition of method x with expected type `0 | 1` +//│ ║ l.51: fun x = 2 +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ║ ^^^^^ +//│ ╟── from signature of member `x`: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ module M extends C1, C2, T1 { //│ fun x: 2 //│ } @@ -84,42 +79,42 @@ class C1 { fun x: 0 | 2 = 0 } :e module M extends C1, T1 //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^^^^^^^^ //│ ╟── type `2` does not match type `0 | 1` -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^ //│ ╟── but it flows into union type with expected type `0 | 1` -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ║ ^^^^^ -//│ ╟── from signature of member x: +//│ ╟── from signature of member `x`: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ -//│ module M { +//│ module M extends C1, T1 { //│ fun x: 0 | 2 //│ } :e module M extends T1, C1 //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^^^^^^^^ //│ ╟── type `2` does not match type `0 | 1` -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^ //│ ╟── but it flows into union type with expected type `0 | 1` -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ║ ^^^^^ -//│ ╟── from signature of member x: +//│ ╟── from signature of member `x`: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ -//│ module M { +//│ module M extends C1, T1 { //│ fun x: 0 | 2 //│ } @@ -128,9 +123,9 @@ module M extends T1, T2, C1 { fun x = this.x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.128: fun x = this.x +//│ ║ l.123: fun x = this.x //│ ╙── ^^ -//│ module M { +//│ module M extends C1, T1, T2 { //│ fun x: error //│ } @@ -140,162 +135,212 @@ module M extends T1, T2, C1 { fun x = this.x } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.140: fun x = this.x +//│ ║ l.135: fun x = this.x //│ ║ ^^^^^^^^^^ //│ ╟── type `0` does not match type `1 | 2` -//│ ║ l.139: fun x: 0 +//│ ║ l.134: fun x: 0 //│ ║ ^ //│ ╟── but it flows into field selection with expected type `1 | 2` -//│ ║ l.140: fun x = this.x +//│ ║ l.135: fun x = this.x //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.8: trait T2 { fun x: 1 | 2 } //│ ║ ^^^^^ -//│ ╟── from signature of member x: +//│ ╟── from signature of member `x`: //│ ║ l.8: trait T2 { fun x: 1 | 2 } //│ ╙── ^^^^^^^^ -//│ module M { +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.134: fun x: 0 +//│ ║ ^^^^ +//│ ╟── type `0` does not match type `1 | 2` +//│ ║ l.134: fun x: 0 +//│ ║ ^ +//│ ╟── but it flows into signature of member `x` with expected type `1 | 2` +//│ ║ l.134: fun x: 0 +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.8: trait T2 { fun x: 1 | 2 } +//│ ║ ^^^^^ +//│ ╟── from signature of member `x`: +//│ ║ l.8: trait T2 { fun x: 1 | 2 } +//│ ╙── ^^^^^^^^ +//│ module M extends C1, T1, T2 { //│ fun x: 0 //│ } -module M extends C1, T2 { +class C extends C1, T2 { fun x: 2 fun x = this.x } -//│ module M { +//│ class C extends C1, T2 { //│ fun x: 2 //│ } +module M extends C { + fun x = 2 +} +M.x +//│ module M extends C, C1, T2 { +//│ fun x: 2 +//│ } +//│ 2 :e class C2 extends T1 -//│ ╔══[ERROR] Member x is declared in parent trait but not implemented -//│ ║ l.172: class C2 extends T1 -//│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ class C2 +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented +//│ ║ l.190: class C2 extends T1 +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ class C2 extends T1 { +//│ fun x: 0 | 1 +//│ } + +abstract class C2 extends T1 +//│ abstract class C2 extends T1 { +//│ fun x: 0 | 1 +//│ } -// TODO -// abstract class C2 extends T1 +:e +class C3 extends C2 +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented +//│ ║ l.207: class C3 extends C2 +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.7: trait T1 { fun x: 0 | 1 } +//│ ╙── ^^^^^^^^ +//│ class C3 extends C2, T1 { +//│ fun x: 0 | 1 +//│ } + +abstract class C3 extends C2 +//│ abstract class C3 extends C2, T1 { +//│ fun x: 0 | 1 +//│ } class C2 extends T1 { fun x = 1 } -//│ class C2 { +//│ class C2 extends T1 { //│ fun x: 1 //│ } :e class C2 extends T1, T2 { fun x = 2 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.187: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.229: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── integer literal of type `2` does not match type `0 | 1` -//│ ║ l.187: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.229: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 1` -//│ ║ l.187: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.229: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ║ ^^^^^ -//│ ╟── from signature of member x: +//│ ╟── from signature of member `x`: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ -//│ class C2 { +//│ class C2 extends T1, T2 { //│ fun x: 2 //│ } class C2 extends T1, T2 { fun x = 1 } -//│ class C2 { +//│ class C2 extends T1, T2 { //│ fun x: 1 //│ } :e class C3 extends C2 { fun x = 111 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.213: class C3 extends C2 { fun x = 111 } +//│ ║ l.255: class C3 extends C2 { fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── integer literal of type `111` does not match type `1` -//│ ║ l.213: class C3 extends C2 { fun x = 111 } +//│ ║ l.255: class C3 extends C2 { fun x = 111 } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `1` -//│ ║ l.213: class C3 extends C2 { fun x = 111 } +//│ ║ l.255: class C3 extends C2 { fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.207: class C2 extends T1, T2 { fun x = 1 } +//│ ║ l.249: class C2 extends T1, T2 { fun x = 1 } //│ ║ ^ //│ ╟── from definition of method x: -//│ ║ l.207: class C2 extends T1, T2 { fun x = 1 } +//│ ║ l.249: class C2 extends T1, T2 { fun x = 1 } //│ ╙── ^^^^^ -//│ class C3 { +//│ class C3 extends C2, T1, T2 { //│ fun x: 111 //│ } class C3 extends C2 { fun x = 1 } -//│ class C3 { +//│ class C3 extends C2, T1, T2 { //│ fun x: 1 //│ } class C2 extends C1, T1 { fun x = 0 } -//│ class C2 { +//│ class C2 extends C1, T1 { //│ fun x: 0 //│ } class C2 extends T1, C1 { fun x = 0 } -//│ class C2 { +//│ class C2 extends C1, T1 { //│ fun x: 0 //│ } :e class C2 extends C1, T1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.249: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.291: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.249: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.291: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.249: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.291: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── from definition of method x: -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ╙── ^^^^^^^^^^^^ -//│ class C2 { +//│ class C2 extends C1, T1 { //│ fun x: 1 //│ } :e class C2 extends T1, C1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.270: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.312: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.270: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.312: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.270: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.312: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ║ ^^^^^ //│ ╟── from definition of method x: -//│ ║ l.77: class C1 { fun x: 0 | 2 = 0 } +//│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } //│ ╙── ^^^^^^^^^^^^ -//│ class C2 { +//│ class C2 extends C1, T1 { //│ fun x: 1 //│ } -:e // FIXME reject impl in interface +:e trait T2 { val r = 1(1) } +//│ ╔══[ERROR] Method implementations in traits are not yet supported +//│ ║ l.335: trait T2 { val r = 1(1) } +//│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.293: trait T2 { val r = 1(1) } +//│ ║ l.335: trait T2 { val r = 1(1) } //│ ║ ^^^^ //│ ╟── integer literal of type `1` is not a function -//│ ║ l.293: trait T2 { val r = 1(1) } +//│ ║ l.335: trait T2 { val r = 1(1) } //│ ╙── ^ //│ trait T2 { //│ let r: error @@ -303,10 +348,15 @@ trait T2 { val r = 1(1) } :e class C2 extends T2 -//│ ╔══[ERROR] Member r is declared in parent trait but not implemented -//│ ║ l.305: class C2 extends T2 -//│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ class C2 +//│ ╔══[ERROR] Member `r` is declared in parent but not implemented +//│ ║ l.350: class C2 extends T2 +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.335: trait T2 { val r = 1(1) } +//│ ╙── ^^^^^^^^ +//│ class C2 extends T2 { +//│ let r: error +//│ } :e @@ -314,23 +364,26 @@ trait T2[A] { val r = C2().x } class C2 extends T2[int] +//│ ╔══[ERROR] Method implementations in traits are not yet supported +//│ ║ l.364: val r = C2().x +//│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.313: trait T2[A] { +//│ ║ l.363: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.314: val r = C2().x +//│ ║ l.364: val r = C2().x //│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type `C2` does not contain member `x` -//│ ║ l.314: val r = C2().x +//│ ║ l.364: val r = C2().x //│ ╙── ^^ //│ trait T2[A] { //│ let r: error //│ } -//│ class C2 +//│ class C2 extends T2 :e // FIXME C2() : T2['X] //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.313: trait T2[A] { +//│ ║ l.363: trait T2[A] { //│ ╙── ^ //│ T2['X] //│ where diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index b3f5218c8c..357efff342 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -13,14 +13,14 @@ trait T1[A] { class C1 extends T1 { fun f(x: int) = x } -//│ class C1 { +//│ class C1 extends T1 { //│ fun f: (x: int,) -> int //│ } class C1 extends T1['FigureItOut] { fun f(x: int) = x } -//│ class C1 { +//│ class C1 extends T1 { //│ fun f: (x: int,) -> int //│ } @@ -66,6 +66,9 @@ trait T2[A] { class C2 extends T2['FigureItOut] { fun f(x: int) = x } +//│ ╔══[ERROR] Method implementations in traits are not yet supported +//│ ║ l.64: val r = C2().f(false) +//│ ╙── ^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition //│ ║ l.62: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ @@ -86,7 +89,7 @@ class C2 extends T2['FigureItOut] { //│ fun f: A -> A //│ let r: error | int //│ } -//│ class C2 { +//│ class C2 extends T2 { //│ fun f: (x: int,) -> int //│ } @@ -98,28 +101,31 @@ trait T2[A] { class C2 extends T2['FigureItOut] { fun f(x: int) = x } +//│ ╔══[ERROR] Method implementations in traits are not yet supported +//│ ║ l.99: val r = (C2() : T2['X]).f(false) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.94: trait T2[A] { +//│ ║ l.97: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.95: fun f: A -> A +//│ ║ l.98: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.96: val r = (C2() : T2['X]).f(false) +//│ ║ l.99: val r = (C2() : T2['X]).f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.94: trait T2[A] { +//│ ║ l.97: trait T2[A] { //│ ╙── ^ //│ trait T2[A] { //│ fun f: A -> A //│ let r: error | false //│ } -//│ class C2 { +//│ class C2 extends T2 { //│ fun f: (x: int,) -> int //│ } :e // FIXME C2() : T2['X] //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.94: trait T2[A] { +//│ ║ l.97: trait T2[A] { //│ ╙── ^ //│ T2['X] //│ where diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index 4ae330a8bd..928203dea6 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -16,12 +16,12 @@ type AI2 = Array :e type AI3(n) = Array[int] -//│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.18: type AI3(n) = Array[int] -//│ ╙── ^ -//│ ╔══[ERROR] type alias definitions cannot have value parameters +//│ ╔══[ERROR] Type alias definitions cannot have value parameters //│ ║ l.18: type AI3(n) = Array[int] //│ ╙── ^^^ +//│ ╔══[ERROR] Type alias parameters currently need type annotations +//│ ║ l.18: type AI3(n) = Array[int] +//│ ╙── ^ //│ type AI3 = Array[int] // :e diff --git a/shared/src/test/diff/nu/Vals.mls b/shared/src/test/diff/nu/Vals.mls new file mode 100644 index 0000000000..7e9a5826b9 --- /dev/null +++ b/shared/src/test/diff/nu/Vals.mls @@ -0,0 +1,31 @@ +:NewDefs + + +val a = 1 +val b = a + 1 +//│ let a: 1 +//│ let b: int +//│ a +//│ = 1 +//│ b +//│ = 2 + + +// :e // FIXME should not type check +:ge +val c = d + 1 +val d = 1 +//│ let c: int +//│ let d: 1 +//│ Code generation encountered an error: +//│ unresolved symbol d + + +// :e // FIXME should not type check +val a = a +//│ let a: nothing +//│ a +//│ = 1 + + + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 5ac84ee450..425fad04ab 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -500,7 +500,7 @@ class DiffTests def showTTU(ttu: typer.TypedTypingUnit, ind: Int): Unit = { val indStr = " " * ind - ttu.entities.foreach { + ttu.implementedMembers.foreach { // case p: typer.NuTypeParam => // output(s"${indStr}${p.name}: ${p.ty}") case p: typer.NuParam => From 7ef1ded7c4eb4a8790d150385a817c9b43522e83 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 2 Jun 2023 23:55:20 +0800 Subject: [PATCH 345/498] Completely refactor inheritance checking code and fix many related issues --- .../src/main/scala/mlscript/NuTypeDefs.scala | 267 +++++++------- shared/src/main/scala/mlscript/Typer.scala | 10 +- .../main/scala/mlscript/TyperHelpers.scala | 26 +- .../main/scala/mlscript/utils/package.scala | 2 + .../test/diff/ecoop23/ExpressionProblem.mls | 1 - shared/src/test/diff/ecoop23/Intro.mls | 1 - .../test/diff/ecoop23/PolymorphicVariants.mls | 338 ++---------------- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 25 +- shared/src/test/diff/nu/AbstractClasses.mls | 12 +- shared/src/test/diff/nu/BadClassInherit.mls | 118 +++++- shared/src/test/diff/nu/BadClasses.mls | 7 +- shared/src/test/diff/nu/BadSignatures.mls | 11 +- shared/src/test/diff/nu/ExplicitVariance.mls | 143 ++++++++ shared/src/test/diff/nu/GenericMethods.mls | 14 +- shared/src/test/diff/nu/GenericModules.mls | 41 ++- .../diff/nu/InferredInheritanceTypeArgs.mls | 137 +++++-- shared/src/test/diff/nu/InterfaceMono.mls | 130 ++++--- shared/src/test/diff/nu/Interfaces.mls | 194 +++++----- shared/src/test/diff/nu/LocalLets.mls | 24 +- .../src/test/diff/nu/MemberIntersections.mls | 21 +- shared/src/test/diff/nu/MethodSignatures.mls | 43 +-- shared/src/test/diff/nu/Parens.mls | 75 ++-- .../test/diff/nu/RawUnionTraitSignatures.mls | 6 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 160 ++++++--- shared/src/test/diff/nu/TypeAliases.mls | 3 - .../diff/nu/repro_PolymorphicVariants.mls | 12 +- .../test/diff/{nu => ucs}/ParserFailures.mls | 3 +- shared/src/test/diff/ucs/zipWith.mls | 4 +- 28 files changed, 972 insertions(+), 856 deletions(-) rename shared/src/test/diff/{nu => ucs}/ParserFailures.mls (97%) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index ce63bced06..d7d8a8b568 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -29,6 +29,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def level: Level def isImplemented: Bool + def isValueParam: Bool = this match { + case p: NuParam => !p.isType + case _ => false + } + protected def withLevel[R](k: Ctx => R)(implicit ctx: Ctx): R = k(ctx.copy(lvl = ctx.lvl + 1)) def freshenAbove(lim: Int, rigidify: Bool) @@ -44,10 +49,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): NuMember + + def showBounds: Str = TypedTypingUnit(this :: Nil, N).showBounds } - case class NuParam(nme: NameRef, ty: FieldType)(val level: Level) extends NuMember { + case class NuParam(nme: NameRef, ty: FieldType)(val level: Level) extends NuMember with TypedNuTermDef { def name: Str = nme.name def isType: Bool = nme.isInstanceOf[TypeName] def kind: DeclKind = @@ -63,36 +70,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => NuParam(nme, ty.freshenAbove(lim, rigidify))(ctx.lvl) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): NuMember = + (implicit ctx: Ctx): NuParam = NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)))(level) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): NuMember = + (implicit ctx: Ctx): NuParam = NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)))(level) } - /* - // TODO: - case class NuTypeParam(nme: TN, ty: FieldType)(val level: Level) extends NuMember { - def name: Str = nme.name - - def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - : NuTypeParam = - NuTypeParam(nme, ty.freshenAbove(lim, rigidify))(ctx.lvl) - - def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): NuMember = - NuTypeParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)))(level) - - def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): NuMember = - NuTypeParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)))(level) - - def kind: DeclKind = Als // FIXME? - } - */ - sealed trait TypedNuDecl extends NuMember { def name: Str def level: Level @@ -231,7 +216,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inheritedTags: Set[TypeName], parentTP: Map[Str, NuMember] )(val instanceType: ST, // * only meant to be used in `force` and `variances` - ) extends TypedNuTypeDef(Cls) with TypedNuTermDef with PolyNuDecl + ) extends TypedNuTypeDef(Cls) with PolyNuDecl { def decl: NuTypeDef = td def kind: DeclKind = td.kind @@ -308,7 +293,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef = + (implicit ctx: Ctx): TypedNuCls = TypedNuCls(level, td, tparams.map(tp => (tp._1, f(N, tp._2).assertTV, tp._3)), params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), @@ -319,7 +304,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, )(f(pol, instanceType)) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef = + (implicit ctx: Ctx): TypedNuCls = TypedNuCls(level, td, tparams.map(tp => (tp._1, f(pol.invar, tp._2).assertTV, tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), @@ -329,6 +314,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inheritedTags, parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap, )(f(pol, instanceType)) + + override def toString: Str = s"TypedNuCls($level, ${td.nme},\n\t$tparams,\n\t$params,\n\tthis: $thisTy, ${ + members.lnIndent()},\n\t: $sign, $inheritedTags, $parentTP)" } @@ -374,6 +362,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tparams.map(tp => (tp._1, f(pol.invar, tp._2).assertTV, tp._3)), params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap) + + override def toString: Str = s"TypedNuMxn($level, ${td.nme},\n\tthis: $thisTy,\n\tsuper: $superTy,\n\ttparams: $tparams,\n\tparams: $params,\n\tmembers: ${members.lnIndent()}\n)" } @@ -414,10 +404,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => }}} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef = + (implicit ctx: Ctx): TypedNuFun = TypedNuFun(level, fd, f(pol, bodyType))(isImplemented) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) - (implicit ctx: Ctx): TypedNuTermDef = + (implicit ctx: Ctx): TypedNuFun = TypedNuFun(level, fd, f(pol, bodyType))(isImplemented) } @@ -435,6 +425,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) : TypedTypingUnit = TypedTypingUnit(implementedMembers.map(_.freshenAbove(lim, rigidify)), result.map(_.freshenAbove(lim, rigidify))) + override def toString: Str = s"TypedTypingUnit(${(implementedMembers :+ result).lnIndent()})" } @@ -453,8 +444,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ClassTag(Var(td.nme.name), ihtags + TN("Eql") // Eql and ihtags (parent tags) )(provTODO) & selfTy & RecordType.mk( - tparams.map { case (tn, tv, vi) => // TODO use vi - Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> FieldType(S(tv), tv)(provTODO) } + tparams.map { case (tn, tv, vi) => + // TODO also use computed variance info when available! + Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> + FieldType.mk(vi.getOrElse(VarianceInfo.in), tv, tv)(provTODO) } )(provTODO) )(provTODO) ) @@ -610,7 +603,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => Nil } - type TypedParentSpec = (TypedNuTypeDef, Ls[NuMember], Map[Str, NuMember], Opt[Loc]) + /** First list of members is for the typed arguments; + * the map of members is for the inherited virtual type argument members. */ + type TypedParentSpec = (TypedNuTypeDef, Ls[NuParam], Map[Str, NuMember], Opt[Loc]) lazy val typedParents: Ls[TypedParentSpec] = ctx.nest.nextLevel { implicit ctx => @@ -634,7 +629,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } // println(s"Fresh $mxn") - val newMembs = { + val argMembs = { if (parArgs.sizeCompare(mxn.params) =/= 0) err(msg"mixin $parNme expects ${ mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) @@ -648,12 +643,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } - paramMems ++ mxn.members.valuesIterator + paramMems //++ mxn.members.valuesIterator } - println(s"Members $newMembs") + println(s"Members $argMembs") - S((mxn, newMembs, + S((mxn, argMembs, Map.empty[Str, NuMember], // TODO add ptp here once we support explicit type args p.toLoc )) @@ -670,6 +665,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val paramMems = Nil // * Maybe support trait params? (not sure) + S((trt, paramMems, ptp ++ trt.parentTP, p.toLoc)) case rawCls: TypedNuCls => @@ -952,10 +948,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case td: NuTypeDef => - def implemCheck(membersToImplem: Ls[NuMember], implems: Ls[NuMember]): Unit = { + /** Checks everything is implemented and there are no implementation duplicates. */ + def implemCheck(implementedMembers: Ls[NuMember], toImplement: Ls[NuMember]): Unit = { val implemsMap = MutMap.empty[Str, NuMember] - implems.foreach { m => + implementedMembers.foreach { m => implemsMap.updateWith(m.name) { case S(_) => err(msg"Duplicated `${m.name}` member definition in `${td.name}`", m.toLoc) @@ -963,29 +960,46 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case N => S(m) } } - - membersToImplem.foreach { m => - lazy val parSign = m match { - case nt: TypedNuTermDef => nt.typeSignature - case np: NuParam => np.typeSignature - case _ => ??? // probably no other cases - } - implemsMap.get(m.name) match { - case S(mem: TypedNuTermDef) => - val memSign = mem.typeSignature - implicit val prov: TP = memSign.prov - println(s"Checking overriding of `${m.name}`") - constrain(memSign, parSign) - case S(pm: NuParam) => - val pmSign = pm.typeSignature - implicit val prov: TP = pmSign.prov - constrain(pmSign, parSign) - case S(_) => () - case N => - if (!td.isDecl && td.kind =/= Trt && !td.isAbstract) - err(msg"Member `${m.name}` is declared in parent but not implemented" -> td.toLoc :: + if (!td.isDecl && td.kind =/= Trt && !td.isAbstract) { + toImplement.foreach { m => + implemsMap.get(m.name) match { + case S(_) => + case N => + err(msg"Member `${m.name}` is declared in parent but not implemented in `${ + td.nme.name}`" -> td.nme.toLoc :: msg"Declared here:" -> m.toLoc :: Nil) + } + } + } + + } + + /** Checks overriding members against their parent types. */ + def overrideCheck(newMembers: Ls[NuMember], signatures: Ls[NuMember]): Unit = + ctx.nextLevel { implicit ctx: Ctx => // * Q: why exactly do we need `ctx.nextLevel`? + + val sigMap = MutMap.empty[Str, NuMember] + signatures.foreach { m => + sigMap.updateWith(m.name) { + case S(_) => die + case N => S(m) + } + } + + newMembers.foreach { m => + println(s"Checking overriding for `${m.name}`...") + (m, sigMap.get(m.name)) match { + case (_, N) => + case (m: TypedNuTermDef, S(fun: TypedNuTermDef)) => + val mSign = m.typeSignature + implicit val prov: TP = mSign.prov + constrain(mSign, fun.typeSignature) + case (_, S(that)) => + err(msg"${m.kind.str.capitalize} member `${m.name}` cannot override ${ + that.kind.str} member of the same name declared in parent" -> td.toLoc :: + msg"Declared here:" -> that.toLoc :: + Nil) } } @@ -1058,7 +1072,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => res } - val (res, funMembers) = td.kind match { + td.kind match { case Trt => td.params match { @@ -1076,7 +1090,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def inherit(parents: Ls[TypedParentSpec], tags: ST, members: Ls[NuMember], tparamMembs: Map[Str, NuMember]) : (ST, Ls[NuMember], Map[Str, NuMember]) = parents match { - case (trt: TypedNuTrt, newMembs, tpms, loc) :: ps => + case (trt: TypedNuTrt, argMembs, tpms, loc) :: ps => + assert(argMembs.isEmpty, argMembs) inherit(ps, tags & trt.sign, membersInter(members, trt.members.values.toList), @@ -1105,17 +1120,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ).toMap // check trait overriding - // implemCheck(trtMembers, typedSignatureMembers.map(_._2) ++ ttu.implementedMembers) - implemCheck(trtMembers, typedSignatureMembers.map(_._2)) + overrideCheck(typedSignatureMembers.map(_._2), trtMembers) TypedNuTrt(outerCtx.lvl, td, tparams, allMembers, - TopType, // thisType (same as Cls) + TopType, // thisType (same as for Cls) sig_ty, inheritedTags, tparamMembs - ) -> Nil + ) } case Als => @@ -1132,7 +1146,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"Type alias definition requires a right-hand side", td.toLoc) } - TypedNuAls(outerCtx.lvl, td, tparams, body_ty) -> Nil + TypedNuAls(outerCtx.lvl, td, tparams, body_ty) case Cls | Nms => @@ -1170,7 +1184,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ) def inherit(parents: Ls[TypedParentSpec], pack: Pack): Pack = parents match { - case (p, newMembs, tpms, loc) :: ps => p match { + case (p, argMembs, tpms, loc) :: ps => p match { case mxn: TypedNuMxn => @@ -1182,8 +1196,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => constrain(pack.superType, mxn.superTy) constrain(finalType, mxn.thisTy) - assert(tpms.isEmpty) // FIXME + assert(tpms.isEmpty) // Mixins do not introduce virtual members for type params + val newMembs = argMembs ++ mxn.members.valuesIterator.filterNot(_.isValueParam) val newSuperType = WithType( pack.superType, RecordType( @@ -1196,14 +1211,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inherit(ps, pack.copy( superType = newSuperType, - // mxnMembers = pack.mxnMembers ++ newMembs // FIXME add `mxn.members.values.toList`? mxnMembers = newMembs ++ pack.mxnMembers )) case trt: TypedNuTrt => + assert(argMembs.isEmpty, argMembs) + inherit(ps, pack.copy( - traitMembers = membersInter(pack.traitMembers, trt.members.valuesIterator.toList), + traitMembers = membersInter(pack.traitMembers, trt.members.valuesIterator.filterNot(_.isValueParam).toList), tparamMembers = pack.tparamMembers ++ tpms )) @@ -1217,7 +1233,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inherit(ps, pack.copy( baseClsNme = S(parNme), - baseClsMembers = newMembs ++ cls.members.valuesIterator.toList, + baseClsMembers = argMembs ++ cls.members.valuesIterator.filterNot(_.isValueParam), tparamMembers = pack.tparamMembers ++ tpms )) @@ -1253,66 +1269,61 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "super" -> VarSymbol(thisType, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) - - // val impltdMems = - // // (baseClsMembers ++ mxnMembers ++ ttu.implementedMembers).distinctBy(_.name) - // (ttu.implementedMembers ++ mxnMembers ++ baseClsMembers).distinctBy(_.name) - - val memberNames = MutSet.empty[Str] - - // val definedMembers = ttu.implementedMembers - // memberNames ++= definedMembers.map(_.name) - // println(s"DM ${definedMembers}") - val (baseClsImplemMembers, baseClsIfaceMembers) = baseClsMembers.partition(_.isImplemented) - val impltdMems = - (ttu.implementedMembers ++ mxnMembers ++ baseClsImplemMembers) - .filter(m => memberNames.add(m.name)) // TODD distinctBy - - // println(ttu.implementedMembers) - // println(impltdMems_old) - // println(impltdMems) + val newImplems = ttu.implementedMembers - // overriding check for class/interface inheritance - // implCheck(baseClsMembers ++ traitMembers, impltdMems, td.isAbstract)(td) + // * Those member implementations we inherit from the base class that are not overridden + val implemsInheritedFromBaseCls = { + val possiblyOverridingNames = (newImplems.iterator ++ mxnMembers).map(_.name).toSet + baseClsImplemMembers.iterator + .filterNot(possiblyOverridingNames contains _.name) + .toList + } + // * ... must type check against the trait signatures + trace(s"Checking base class implementations...") { + println(implemsInheritedFromBaseCls, newImplems) + overrideCheck(implemsInheritedFromBaseCls, traitMembers) + }() - // implemCheck(baseClsMembers ::: traitMembers, impltdMems) + // * The following are type signatures all implementations must satisfy + // * (but we already know the base class implems satisfy the baseClsMembers signatures) val ifaceMembers = membersInter(baseClsMembers, traitMembers) - implemCheck(ifaceMembers, impltdMems) + val clsSigns = typedSignatureMembers.map(_._2) - val ifaceMembersMap = ifaceMembers.map(m => m.name -> m).toMap - // * ^ Note: there isn't supposed to be any meaningful duplicates in `ifaceMembers` + // * We now check current and non-overridden mixin implementations against + // * the signatures from the base class and traits + val toCheck = + (newImplems.iterator ++ mxnMembers).distinctBy(_.name).toList + trace(s"Checking new implementations...") { + overrideCheck(toCheck, + (clsSigns.iterator ++ ifaceMembers).distinctBy(_.name).toList) + }() - // * Check signatures provided in this class against imherited signatures - typedSignatureMembers.foreach { case (nme, fun) => - ifaceMembersMap.get(nme) match { - case Some(m: TypedNuFun) => - implicit val prov: TP = - TypeProvenance(fun.toLoc, fun.fd.describe) - constrain(fun.typeSignature, m.typeSignature) - case Some(m) => - err(msg"Cannot override base ${m.kind.str} member `${nme}`", fun.fd.toLoc) - case None => - } - } + val impltdMems = ( + newImplems // local members override mixin members: + ++ mxnMembers // local and mixin members override parent members: + ++ baseClsImplemMembers + ).distinctBy(_.name) + + overrideCheck(clsSigns, ifaceMembers) + implemCheck(impltdMems, + (clsSigns.iterator ++ ifaceMembers.iterator) + .distinctBy(_.name).filterNot(_.isImplemented).toList) val allMembers = (ifaceMembers ++ impltdMems).map(d => d.name -> d).toMap ++ typedSignatureMembers - // // println(allMembers.map(m => (m._2, m._2.isImplemented))) - // println(allMembers.values.map(m => (m, m.isImplemented))) - TypedNuCls(outerCtx.lvl, td, tparams, typedParams, allMembers, TopType, sig_ty, inheritedTags, tparamMembers - )(thisType) -> impltdMems + )(thisType) } case Mxn => @@ -1329,32 +1340,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "super" -> VarSymbol(superTV, Var("super")) val ttu = typeTypingUnit(td.body, topLevel = false) val impltdMems = ttu.implementedMembers + val signs = typedSignatureMembers.map(_._2) + overrideCheck(impltdMems, signs) + implemCheck(impltdMems, signs) val mems = impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers - TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams, mems) -> impltdMems + TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams, mems) } } - // TODO check member duplication? in mems or before? - - // * Check signatures - ctx.nextLevel { implicit ctx: Ctx => - typedSignatures.foreach { case (fd, sign) => - implicit val prov: TP = sign.prov - funMembers.find(m => m.name === fd.nme.name) match { - case S(mem: TypedNuTermDef) => - val memSign = mem.typeSignature - implicit val prov: TP = memSign.prov - constrain(memSign, sign) - case S(mem: NuParam) => - case S(_) => ??? // TODO - case N => - if (!td.isDecl && td.kind != Trt && !td.isAbstract) - err(msg"Member `${fd.nme.name}` is declared but not defined", fd.nme.toLoc) - } - } - } - - res } } finally { isComputing = false } @@ -1362,7 +1355,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => result = S(res) res - }(r => s"Completed ${r}") + }(r => s"Completed ${r} where ${r.showBounds}") } def typeSignature(implicit raise: Raise): ST = decl match { @@ -1389,7 +1382,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val freshened: MutMap[TV, ST] = MutMap.empty val rawName = v.name - val parTP = raw.tparams.lazyZip(parTargs.getOrElse(Nil)).map { case ((tn, _tv, vi), targ) => + val parTP = raw.tparams.lazyZip(parTargs.getOrElse(raw.tparams.map { + case (_, tv, _) => freshVar(tv.prov, S(tv), tv.nameHint)(tv.level) + })).map { case ((tn, _tv, vi), targ) => val tv = (targ match { case tv: TV => println(s"Passing ${tn.name} :: ${_tv} <=< ${tv}") diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 7d03f5d141..330987624a 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -802,14 +802,14 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) ti.member match { case ti: TypedNuFun => ti.typeSignature + case p: NuParam => + p.typeSignature case ti: TypedNuCls => if (ti.decl.isAbstract) err(msg"Class ${ti.nme} is abstract and cannot be instantiated", term.toLoc) ti.typeSignature case ti: TypedNuDecl => err(msg"${ti.kind.str} ${ti.name} cannot be used in term position", prov.loco) - case p: NuParam => - p.typeSignature } case ti: DelayedTypeInfo => ti.typeSignature @@ -1325,10 +1325,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) def mkTypingUnit(thisTy: ST, members: Map[Str, NuMember])(implicit ectx: ExpCtx): TypingUnit = { val sorted = members.toList.sortBy(_._1) TypingUnit(sorted.collect { - case (_, td: TypedNuDecl) => goDecl(td) - // case (_, td: TypedNuFun) => ??? - // case (_, p: NuParam) => ??? - // case _ => die + case (_, d: TypedNuFun) => goDecl(d) + case (_, d: TypedNuTypeDef) => goDecl(d) }) } def goDecl(d: NuMember)(implicit ectx: ExpCtx): NuDecl = d match { diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 0b2cc72e40..972a22e8f5 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1016,6 +1016,12 @@ abstract class TyperHelpers { Typer: Typer => } def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = //if (defn.name.isCapitalized) { ctx.tyDefs2.get(defn.name).map { info => + lazy val mkTparamRcd = RecordType(info.tparams.lazyZip(targs).map { + case ((tn, tv, vi), ta) => + val fldNme = defn.name + "#" + tn.name + // TODO also use computed variance info when available! + Var(fldNme).withLocOf(tn) -> FieldType.mk(vi.getOrElse(VarianceInfo.in), ta, ta)(provTODO) + })(provTODO) info.result match { case S(td: TypedNuAls) => assert(td.tparams.size === targs.size) @@ -1034,11 +1040,7 @@ abstract class TyperHelpers { Typer: Typer => // println(s"Fresh $freshSelf") freshSelf & trtNameToNomTag(td.decl)(provTODO, ctx) & - RecordType(info.tparams.lazyZip(targs).map { - case ((tn, tv, vi), ta) => // TODO use vi - val fldNme = td.nme.name + "#" + tn.name - Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) - })(provTODO) + mkTparamRcd case S(td: TypedNuCls) => assert(td.tparams.size === targs.size) val (freshenMap, _) = refreshHelper2(td, Var(td.name).withLoc(prov.loco), S(targs)) // infer ty args if not provided @@ -1049,21 +1051,13 @@ abstract class TyperHelpers { Typer: Typer => } clsNameToNomTag(td.decl)(provTODO, ctx) & freshSelf & - RecordType(info.tparams.lazyZip(targs).map { - case ((tn, tv, vi), ta) => // TODO use vi - val fldNme = td.nme.name + "#" + tn.name - Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) - })(provTODO) - case _ => + mkTparamRcd + case _ => // * Case for when the type has not been completed yet info.decl match { case td: NuTypeDef if td.kind.isInstanceOf[ObjDefKind] => assert(td.tparams.size === targs.size) clsNameToNomTag(td)(provTODO, ctx) & - RecordType(info.tparams.lazyZip(targs).map { - case ((tn, tv, vi), ta) => // TODO use vi - val fldNme = td.nme.name + "#" + tn.name - Var(fldNme).withLocOf(tn) -> FieldType(S(ta), ta)(provTODO) - })(provTODO) + mkTparamRcd case td: NuTypeDef if td.kind is Als => // * Definition was not forced yet, which indicates an error (hopefully) lastWords("cannot expand unforced type alias") diff --git a/shared/src/main/scala/mlscript/utils/package.scala b/shared/src/main/scala/mlscript/utils/package.scala index b92819269d..77a52d4c36 100644 --- a/shared/src/main/scala/mlscript/utils/package.scala +++ b/shared/src/main/scala/mlscript/utils/package.scala @@ -56,6 +56,8 @@ package object utils { val ite = self.iterator if (ite.nonEmpty) ite.mkString(start, sep, end) else els } + def lnIndent(pre: String = "\t"): Str = + self.iterator.map("\n" + _.toString.indent(pre)).mkString def collectLast[B](f: Paf[A, B]): Opt[B] = self.iterator.collect(f).foldLeft[Opt[B]](N)((_, a) => S(a)) def toSortedSet(implicit ord: Ordering[A]): SortedSet[A] = SortedSet.from(self) diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index 1e44fe780b..25ce5d2e7f 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index 41ae71db5c..d0a4519e42 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 86e910a4af..28c838e1b6 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -16,7 +15,7 @@ let l = Cons(1, Nil) //│ = Cons {} class NotFound() -class Success[A](result: A) +class Success[out A](result: A) //│ class NotFound() //│ class Success[A](result: A) @@ -41,7 +40,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (Cons[{_1: string, _2: 'result}] | Nil, Var,) -> (Var | 'result) +//│ fun eval: (Cons[{_1: string, _2: 'A}] | Nil, Var,) -> ('A | Var) //│ } class Abs[A](x: string, t: A) @@ -77,89 +76,23 @@ mixin EvalLambda { //│ fun eval: ('a & (Cons['A0] | Nil), Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['A1] | App['A] | 'c) //│ } -// FIXME type simplification -:ns module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a 'b 'A 'A0 'c. ('d, 'b,) -> ('e | 'c | 'a | 'f) +//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'A}] | Nil, Abs['t] | App['A0] | Var,) -> ('b | 'a) //│ } //│ where -//│ 'a :> #Abs & {Abs#A = 'A1} -//│ 'c :> #App & {App#A = 'A2} -//│ 'b <: #App & {App#A <: 'A} | (#Abs & {Abs#A <: 'A0} | 'g & ~#Abs) & ~#App -//│ 'A0 <: 't -//│ 'A <: 't0 & 's -//│ 't0 <: 'h -//│ 'h <: #App & {App#A <: 'A3} | (#Abs & {Abs#A <: 'A4} | 'g & ~#Abs) & ~#App -//│ 'A4 <: 't -//│ 'A3 <: 't0 & 's -//│ 's <: 'i & (#Abs & {Abs#A <: 'A5} | 'j & ~#Abs) -//│ 'A5 <: 't1 -//│ 't1 <: 'k -//│ 'k <: #App & {App#A <: 'A6} | (#Abs & {Abs#A <: 'A7} | 'g & ~#Abs) & ~#App -//│ 'A7 <: 't -//│ 'A6 <: 't0 & 's -//│ 'i <: #App & {App#A <: 'A8} | (#Abs & {Abs#A <: 'A9} | 'g & ~#Abs) & ~#App -//│ 'A9 <: 't -//│ 't <: 'l -//│ 'l <: #App & {App#A <: 'A10} | (#Abs & {Abs#A <: 'A11} | 'g & ~#Abs) & ~#App -//│ 'g <: 'm -//│ 'm <: #Var -//│ 'A11 <: 't -//│ 'A10 <: 't0 & 's -//│ 'A8 <: 't0 & 's -//│ 'd :> #Cons & {Cons#A = 'A12} | #Cons & {Cons#A = 'A13} -//│ <: 'n & (Cons['A13] | Nil) -//│ 'n :> #Cons & {Cons#A = 'A12} | #Cons & {Cons#A = 'A13} -//│ <: 'o -//│ 'o :> #Cons & {Cons#A = 'A12} | #Cons & {Cons#A = 'A13} | Cons['A14] | Nil -//│ <: #Cons & {Cons#A <: 'A15} | #Nil & ~#Cons -//│ 'A14 := out 'A15 -//│ 'A12 :> ('x, 'p,) | ('x0, 'q,) -//│ <: 'A13 & 'A15 -//│ 'A13 :> ('x, 'p,) | ('x0, 'q,) -//│ <: 'A12 & 'A15 -//│ 'A15 :> ('x0, 'q,) | ('x, 'p,) -//│ <: 'head -//│ 'head :> ('x0, 'q,) | ('x, 'p,) -//│ <: {_2: 'r} & {_1: 'u} -//│ 'q :> forall 'v 'w. 'e | 'v | 'w | 'f -//│ <: 'r & 'A2 -//│ 'x0 :> string -//│ <: 'u -//│ 'p :> #Var -//│ <: 'r -//│ 'r :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var -//│ <: 'A16 -//│ 'A16 :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var -//│ <: 'A17 -//│ 'A17 :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var -//│ <: 'result -//│ 'e :> forall 'y 'z. 'e | 'y | 'z | 'f -//│ 'z :> #Abs & {Abs#A = 'A1} -//│ 'y :> #App & {App#A = 'A2} -//│ 'A2 :> (forall 'a1 'b1. 'e | 'a1 | 'b1 | 'f) | (forall 'v 'w. 'e | 'v | 'w | 'f) -//│ 'b1 :> #Abs & {Abs#A = 'A1} -//│ 'A1 :> forall 'c1 'd1. 'e | 'c1 | 'd1 | 'f -//│ 'f :> #Var | 'result -//│ 'result :> (forall 'v 'w. 'e | 'v | 'w | 'f) | #Var -//│ 'w :> #Abs & {Abs#A = 'A1} -//│ 'v :> #App & {App#A = 'A2} -//│ 'd1 :> #Abs & {Abs#A = 'A1} -//│ 'c1 :> #App & {App#A = 'A2} -//│ 'a1 :> #App & {App#A = 'A2} -//│ 'x :> string -//│ <: 'u -//│ 'u :> string -//│ <: 'e1 -//│ 'e1 := string +//│ 't <: Abs['t] | App['A0] | Var +//│ 'A0 <: Abs['t & (Abs['t] | App['A0] | Var)] | Abs['t] & ~#Abs | App['A0] | Var +//│ 'A :> 'b | 'a +//│ 'b :> 'A | Var | 'a +//│ 'a :> App['b | 'a] | Abs['b | 'a] Test1.eval(Nil, Var("a")) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'c :> (forall 'a. Var | 'b | 'a) | Var //│ res //│ = Var {} @@ -168,7 +101,7 @@ Test1.eval(Nil, Abs("b", Var("a"))) //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'c :> (forall 'a. Var | 'b | 'a) | Var //│ res //│ = Abs {} @@ -177,7 +110,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'c :> (forall 'a. Var | 'b | 'a) | Var //│ res //│ = Var {} @@ -186,7 +119,7 @@ Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c" //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Abs[Var] | Var | 'b | 'a +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Var //│ res //│ = Var {} @@ -223,7 +156,7 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'result}] | Nil, 'a & (Add['b] | Mul['b] | Num | Var),) -> (Num | Var | 'result | 'a) +//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'A}] | Nil, 'a & (Add['b] | Mul['b] | Num | Var),) -> ('A | Num | Var | 'a) //│ } //│ where //│ 'b <: Add['b] | Mul['b] | Num | Var @@ -247,16 +180,16 @@ Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.248: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.181: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.248: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.181: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.201: if v is +//│ ║ l.134: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.211: let vv = map_expr(eta, v) +//│ ║ l.144: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Num | Var | error //│ res @@ -268,113 +201,25 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) //│ res //│ = Add {} -// FIXME type simplification -:ns module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'a 'b 'A 'c 'A0. ('d, 'a,) -> ('e | 'c | 'b | 'f) +//│ fun eval: forall 'A 'a. (Cons[{_1: string, _2: 'A0}] | Nil, Abs['t] | App['A] | 'b & ~#Abs & ~#App,) -> ('c | 'a) //│ } //│ where -//│ 'b :> #Abs & {Abs#A = 'A1} -//│ 'c :> #App & {App#A = 'A2} -//│ 'a <: #App & {App#A <: 'A} | (#Abs & {Abs#A <: 'A0} | 'g & ~#Abs) & ~#App -//│ 'A0 <: 't -//│ 'A <: 't0 & 's -//│ 'd :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} -//│ <: 'h & (Cons['A4] | Nil) -//│ 'h :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} -//│ <: 'd & 'i -//│ 'i :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} -//│ <: 'j -//│ 'j :> #Cons & {Cons#A = 'A3} | #Cons & {Cons#A = 'A4} | Cons['A5] | Nil -//│ <: #Cons & {Cons#A <: 'A6} | #Nil & ~#Cons -//│ 'A5 := out 'A6 -//│ 'A3 :> ('x, 'k,) | ('x0, 'm,) -//│ <: 'A4 & 'A6 -//│ 'A4 :> ('x, 'k,) | ('x0, 'm,) -//│ <: 'A3 & 'A6 -//│ 'A6 :> ('x0, 'm,) | ('x, 'k,) -//│ <: 'head -//│ 'head :> ('x0, 'm,) | ('x, 'k,) -//│ <: {_2: 'n} & {_1: 'o} -//│ 'm :> forall 'p 'q. 'e | 'p | 'q | 'f -//│ <: 'n & 'A2 -//│ 'x0 :> string -//│ <: 'o -//│ 'k :> #Var -//│ <: 'n -//│ 'n :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var -//│ <: 'A7 -//│ 'A7 :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var -//│ <: 'A8 -//│ 'A8 :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var -//│ <: 'result -//│ 'e :> forall 'u 'v. 'e | 'u | 'v | 'f -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'v :> #Abs & {Abs#A = 'A1} -//│ 'u :> #App & {App#A = 'A2} -//│ 'A2 :> (forall 'b1 'c1. 'e | 'b1 | 'c1 | 'f) | (forall 'p 'q. 'e | 'p | 'q | 'f) -//│ 'c1 :> #Abs & {Abs#A = 'A1} -//│ 'A1 :> forall 'd1 'e1. 'e | 'd1 | 'e1 | 'f -//│ 'f :> forall 'f1 'g1. 'h1 | 'f1 | 'i1 | 'g1 -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'g1 :> #Num -//│ 'i1 <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & 'j1 -//│ 'j1 <: #Var | (#Num | (#Add & {Add#A <: 'A9} | #Mul & {Mul#A <: 'A10} & ~#Add) & ~#Num) & ~#Var -//│ 'A10 <: 'r & 'l -//│ 'l <: 'k1 -//│ 'r <: 'k1 -//│ 'A9 <: 'r0 & 'l0 -//│ 'l0 <: 'k1 -//│ 'r0 <: 'k1 -//│ 'k1 <: 'l1 -//│ 'l1 <: #App & {App#A <: 'A11} | (#Abs & {Abs#A <: 'A12} | 'g & ~#Abs) & ~#App -//│ 'A12 <: 't -//│ 'A11 <: 't0 & 's -//│ 't0 <: 'm1 -//│ 'm1 <: #App & {App#A <: 'A13} | (#Abs & {Abs#A <: 'A14} | 'g & ~#Abs) & ~#App -//│ 'A14 <: 't -//│ 'A13 <: 't0 & 's -//│ 's <: 'n1 & (#Abs & {Abs#A <: 'A15} | 'o1 & ~#Abs) -//│ 'A15 <: 't1 -//│ 't1 <: 'p1 -//│ 'p1 <: #App & {App#A <: 'A16} | (#Abs & {Abs#A <: 'A17} | 'g & ~#Abs) & ~#App -//│ 'A17 <: 't -//│ 'A16 <: 't0 & 's -//│ 'n1 <: #App & {App#A <: 'A18} | (#Abs & {Abs#A <: 'A19} | 'g & ~#Abs) & ~#App -//│ 'A19 <: 't -//│ 't <: 'q1 -//│ 'q1 <: #App & {App#A <: 'A20} | (#Abs & {Abs#A <: 'A21} | 'g & ~#Abs) & ~#App -//│ 'g <: 'i1 -//│ 'A21 <: 't -//│ 'A20 <: 't0 & 's -//│ 'A18 <: 't0 & 's -//│ 'f1 :> #Num -//│ 'h1 :> #Var | 'result -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'result :> (forall 'p 'q. 'e | 'p | 'q | 'f) | #Var -//│ <: (#Num | 'w & ~#Num) & (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) -//│ 'a1 :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} -//│ 'z :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} -//│ 'y :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} -//│ 'w :> #Var | #Abs & {Abs#A = 'A1} | #App & {App#A = 'A2} -//│ 'q :> #Abs & {Abs#A = 'A1} -//│ 'p :> #App & {App#A = 'A2} -//│ 'e1 :> #Abs & {Abs#A = 'A1} -//│ 'd1 :> #App & {App#A = 'A2} -//│ 'b1 :> #App & {App#A = 'A2} -//│ 'x :> string -//│ <: 'o -//│ 'o :> string -//│ <: 'r1 -//│ 'r1 := string +//│ 'A0 :> 'c | 'a +//│ 'c :> 'A0 | Num | Var | 'b | 'a +//│ 'a :> App['c | 'a] | Abs['c | 'a] +//│ 'b <: Add['d] | Mul['d] | Num | Var +//│ 'd <: Abs['t] | App['A] | 'b & ~#Abs & ~#App +//│ 't <: Abs['t] | App['A] | 'b & ~#Abs & ~#App +//│ 'A <: Abs['t & (Abs['t] | App['A] | 'b & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | 'b & ~#Abs & ~#App Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> Abs[Var] | Num | Var | 'b +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Num | Var //│ res //│ = Abs {} @@ -383,147 +228,40 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> Abs[Var] | Add[Num | Var] | Num | Var | 'b +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Num | Var] | Num | Var //│ res //│ = Var {} -// FIXME type simplification -:ns // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: forall 'r 'r0 'a 'b 'c 'l 'd 'A 'A0 'l0. ('e, 'b,) -> ('f | 'c | 'b | 'a) +//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'A}] | Nil, 'a & (Add['b] | Mul['b] | Num | Var),) -> ('a | 'c) //│ } //│ where -//│ 'a :> #Num -//│ 'c :> #Num -//│ 'b <: 'd -//│ 'd <: #Var | (#Num | (#Add & {Add#A <: 'A0} | #Mul & {Mul#A <: 'A} & ~#Add) & ~#Num) & ~#Var -//│ 'A <: 'r & 'l0 -//│ 'l0 <: 'g -//│ 'r <: 'g -//│ 'A0 <: 'r0 & 'l -//│ 'l <: 'g -//│ 'r0 <: 'g -//│ 'e :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} -//│ <: 'h -//│ 'h :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} -//│ <: 'e & 'i & (Cons['A2] | Nil) -//│ 'i :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} -//│ <: 'j -//│ 'j :> #Cons & {Cons#A = 'A1} | #Cons & {Cons#A = 'A2} | Cons['A3] | Nil -//│ <: #Cons & {Cons#A <: 'A4} | #Nil & ~#Cons -//│ 'A3 := out 'A4 -//│ 'A1 :> ('x, 'k,) | ('x0, 'm,) -//│ <: 'A2 & 'A4 -//│ 'A2 :> ('x, 'k,) | ('x0, 'm,) -//│ <: 'A1 & 'A4 -//│ 'A4 :> ('x0, 'm,) | ('x, 'k,) -//│ <: 'head -//│ 'head :> ('x0, 'm,) | ('x, 'k,) -//│ <: {_2: 'n} & {_1: 'o} -//│ 'm :> forall 'p 'q. 'f | 'p | 's | 'q -//│ <: 'n & 'A5 -//│ 'x0 :> string -//│ <: 'o -//│ 'k :> #Var -//│ <: 'n -//│ 'n :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var -//│ <: 'A6 -//│ 'A6 :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var -//│ <: 'A7 -//│ 'A7 :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var -//│ <: 'result -//│ 'f :> forall 't 'u. 'v | 'u | 't | 'w -//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) -//│ 'w :> #Var | 'result -//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) -//│ 'result :> (forall 'p 'q. 'f | 'p | 's | 'q) | #Var -//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) -//│ 't :> #Abs & {Abs#A = 'A8} -//│ 'u :> #App & {App#A = 'A5} -//│ 'v :> forall 'c1 'd1. 'f | 'c1 | 'e1 | 'd1 -//│ <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) -//│ 'd1 :> #Num -//│ 'e1 <: (#Num | 'b1 & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'y & ~#Num) & 'f1 -//│ 'f1 <: #Var | (#Num | (#Add & {Add#A <: 'A9} | #Mul & {Mul#A <: 'A10} & ~#Add) & ~#Num) & ~#Var -//│ 'A10 <: 'r1 & 'l1 -//│ 'l1 <: 'g -//│ 'r1 <: 'g -//│ 'A9 <: 'r2 & 'l2 -//│ 'l2 <: 'g -//│ 'r2 <: 'g -//│ 'b1 :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} -//│ 'A8 :> forall 'g1 'h1. 'f | 'g1 | 'i1 | 'h1 -//│ 'h1 :> #Num -//│ 'i1 <: 'j1 -//│ 'j1 <: #Var | (#Num | (#Add & {Add#A <: 'A11} | #Mul & {Mul#A <: 'A12} & ~#Add) & ~#Num) & ~#Var -//│ 'A12 <: 'r3 & 'l3 -//│ 'l3 <: 'g -//│ 'r3 <: 'g -//│ 'A11 <: 'r4 & 'l4 -//│ 'l4 <: 'g -//│ 'r4 <: 'g -//│ 'g <: 'k1 -//│ 'k1 <: (#Num | 'y & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'b1 & ~#Num) & 'l1 -//│ 'l1 <: #Var | (#Num | (#Add & {Add#A <: 'A13} | #Mul & {Mul#A <: 'A14} & ~#Add) & ~#Num) & ~#Var -//│ 'A14 <: 'r5 & 'l5 -//│ 'l5 <: 'g -//│ 'r5 <: 'g -//│ 'A13 <: 'r6 & 'l6 -//│ 'l6 <: 'g -//│ 'r6 <: 'g -//│ 'y :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} -//│ 'A5 :> (forall 'm1 'n1. 'f | 'm1 | 'o1 | 'n1) | (forall 'p 'q. 'f | 'p | 's | 'q) -//│ 'q :> #Num -//│ 's <: (#Num | 'b1 & ~#Num) & (#Num | 'a1 & ~#Num) & (#Num | 'z & ~#Num) & (#Num | 'y & ~#Num) & 'p1 -//│ 'p1 <: #Var | (#Num | (#Add & {Add#A <: 'A15} | #Mul & {Mul#A <: 'A16} & ~#Add) & ~#Num) & ~#Var -//│ 'A16 <: 'r7 & 'l7 -//│ 'l7 <: 'g -//│ 'r7 <: 'g -//│ 'A15 <: 'r8 & 'l8 -//│ 'l8 <: 'g -//│ 'r8 <: 'g -//│ 'z :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} -//│ 'a1 :> #Var | #Abs & {Abs#A = 'A8} | #App & {App#A = 'A5} -//│ 'p :> #Num -//│ 'n1 :> #Num -//│ 'o1 <: 'q1 -//│ 'q1 <: #Var | (#Num | (#Add & {Add#A <: 'A17} | #Mul & {Mul#A <: 'A18} & ~#Add) & ~#Num) & ~#Var -//│ 'A18 <: 'r9 & 'l9 -//│ 'l9 <: 'g -//│ 'r9 <: 'g -//│ 'A17 <: 'r10 & 'l10 -//│ 'l10 <: 'g -//│ 'r10 <: 'g -//│ 'm1 :> #Num -//│ 'g1 :> #Num -//│ 'c1 :> #Num -//│ 'x :> string -//│ <: 'o -//│ 'o :> string -//│ <: 'r1 -//│ 'r1 := string +//│ 'b <: Add['b] | Mul['b] | Num | Var +//│ 'A :> 'c +//│ 'c :> 'A | Abs[Num | 'c] | App[Num | 'c] | Num | Var // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.511: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.248: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.511: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.248: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.201: if v is +//│ ║ l.134: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.211: let vv = map_expr(eta, v) +//│ ║ l.144: let vv = map_expr(eta, v) //│ ╙── ^ -//│ Abs[Var] | error | 'a +//│ error | 'a //│ where -//│ 'a :> Abs[Num | 'a] | App[Num | 'a] | Num | Var +//│ 'a :> Abs[Var] | Num | Var | Abs['a] | App['a] //│ res //│ Runtime error: //│ Error: non-exhaustive case expression + diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index b7d3fcc3e4..36551ae44b 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -1,4 +1,3 @@ -:NewParser :NewDefs @@ -173,16 +172,16 @@ mixin Text { :e module SizeText extends Text //│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?c -> (?d | ?e | ?a | ?b | ?f)}` does not contain member `size` -//│ ║ l.166: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ║ l.165: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?b | ?a | ?f | ?d | ?c)}` does not contain member `size` -//│ ║ l.165: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ║ l.164: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?a -> (?d | ?e | ?f | ?b | ?c)}` does not contain member `size` -//│ ║ l.164: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ║ l.163: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?c -> (?d | ?b | ?a | ?f | ?e)}` does not contain member `size` -//│ ║ l.163: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ║ l.162: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string @@ -447,16 +446,16 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.448: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.447: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.357: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.356: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.115: if a is +//│ ║ l.114: if a is //│ ║ ^ //│ ╟── Note: type parameter Region is defined at: -//│ ║ l.17: class Translate[Region](v: Vector, a: Region) +//│ ║ l.16: class Translate[Region](v: Vector, a: Region) //│ ╙── ^^^^^^ //│ error //│ res @@ -467,16 +466,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.468: Lang.text(mk(100)) +//│ ║ l.467: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.357: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.356: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.468: Lang.text(mk(100)) +//│ ║ l.467: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.161: if e is +//│ ║ l.160: if e is //│ ╙── ^ //│ error | string //│ res diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index 8bbe84d34b..0b93c8b1af 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -55,9 +55,9 @@ abstract class Bar extends Foo(1) :e module Baz extends Bar Baz.f(1) -//│ ╔══[ERROR] Member `f` is declared in parent but not implemented +//│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `Baz` //│ ║ l.56: module Baz extends Bar -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.29: fun f: int -> int //│ ╙── ^^^^^^^^^^^^^ @@ -89,9 +89,9 @@ trait T1 { fun x: int | bool } :e class C2 extends C1, T1 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C2` //│ ║ l.91: class C2 extends C1, T1 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^ //│ ╟── Declared here: //│ ║ l.80: abstract class C1 { fun x: int | string } //│ ╙── ^^^^^^^^^^^^^^^ @@ -111,9 +111,9 @@ abstract class C2 extends C1, T1 :e class C3 extends C2 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C3` //│ ║ l.113: class C3 extends C2 -//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^ //│ ╟── Declared here: //│ ║ l.80: abstract class C1 { fun x: int | string } //│ ╙── ^^^^^^^^^^^^^^^ diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index 71ddf5ee10..f21bfc6c55 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -52,10 +52,56 @@ class C2 extends C1(this) class Foo { fun x: int = 1 } -mixin M { fun x = false } //│ class Foo { //│ fun x: int //│ } + +:e +class Bar extends Foo { fun x = false } +//│ ╔══[ERROR] Type mismatch in definition of method x: +//│ ║ l.60: class Bar extends Foo { fun x = false } +//│ ║ ^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `int` +//│ ║ l.60: class Bar extends Foo { fun x = false } +//│ ║ ^^^^^ +//│ ╟── but it flows into definition of method x with expected type `int` +//│ ║ l.60: class Bar extends Foo { fun x = false } +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ ^^^ +//│ ╟── from definition of method x: +//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ╙── ^^^^^^^^^^ +//│ class Bar extends Foo { +//│ fun x: false +//│ } + +:e +class Bar extends Foo { + fun x: bool + fun x = false +} +//│ ╔══[ERROR] Type mismatch in signature of member `x`: +//│ ║ l.82: fun x: bool +//│ ║ ^^^^^^^ +//│ ╟── type `bool` is not an instance of `int` +//│ ║ l.82: fun x: bool +//│ ║ ^^^^ +//│ ╟── but it flows into signature of member `x` with expected type `int` +//│ ║ l.82: fun x: bool +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ ^^^ +//│ ╟── from definition of method x: +//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ╙── ^^^^^^^^^^ +//│ class Bar extends Foo { +//│ fun x: bool +//│ } + +mixin M { fun x = false } //│ mixin M() { //│ fun x: false //│ } @@ -63,14 +109,14 @@ mixin M { fun x = false } :e class Bar extends Foo, M //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.55: mixin M { fun x = false } -//│ ║ ^^^^^^^^^ +//│ ║ l.104: mixin M { fun x = false } +//│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.55: mixin M { fun x = false } -//│ ║ ^^^^^ +//│ ║ l.104: mixin M { fun x = false } +//│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `int` -//│ ║ l.55: mixin M { fun x = false } -//│ ║ ^^^^^^^^^ +//│ ║ l.104: mixin M { fun x = false } +//│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.54: class Foo { fun x: int = 1 } //│ ║ ^^^ @@ -82,3 +128,61 @@ class Bar extends Foo, M //│ } +:NoJS // TODO + +class A { class X { fun f = 1 } } +trait B { class X { fun g = 1 } } +//│ class A { +//│ class X { +//│ fun f: 1 +//│ } +//│ } +//│ trait B { +//│ class X { +//│ fun g: 1 +//│ } +//│ } + +:e +class C extends A, B +//│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent +//│ ║ l.147: class C extends A, B +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.134: trait B { class X { fun g = 1 } } +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Intersection of class member and class members currently unsupported +//│ ║ l.147: class C extends A, B +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── The class member is defined here: +//│ ║ l.133: class A { class X { fun f = 1 } } +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── The class member is defined here: +//│ ║ l.134: trait B { class X { fun g = 1 } } +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ class C extends A, B { +//│ class X { +//│ fun f: 1 +//│ } +//│ } + +:e +class C extends A { + class X { fun g = 1 } +} +//│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent +//│ ║ l.170: class C extends A { +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.171: class X { fun g = 1 } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.133: class A { class X { fun f = 1 } } +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ class C extends A { +//│ class X { +//│ fun g: 1 +//│ } +//│ } + + + diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 00c3006046..4b87fa23e1 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -106,9 +106,12 @@ class C1 { fun oops = this.x } :e class C { fun x: int } -//│ ╔══[ERROR] Member `x` is declared but not defined +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C` //│ ║ l.108: class C { fun x: int } -//│ ╙── ^ +//│ ║ ^ +//│ ╟── Declared here: +//│ ║ l.108: class C { fun x: int } +//│ ╙── ^^^^^^ //│ class C { //│ fun x: int //│ } diff --git a/shared/src/test/diff/nu/BadSignatures.mls b/shared/src/test/diff/nu/BadSignatures.mls index 9187a8aef5..a328f744a9 100644 --- a/shared/src/test/diff/nu/BadSignatures.mls +++ b/shared/src/test/diff/nu/BadSignatures.mls @@ -25,7 +25,7 @@ class A { fun x = 1 } class B() extends A { fun x: int } -//│ ╔══[ERROR] Type mismatch in definition: +//│ ╔══[ERROR] Type mismatch in signature of member `x`: //│ ║ l.26: fun x: int //│ ║ ^^^^^^ //│ ╟── type `int` does not match type `1` @@ -69,7 +69,7 @@ class B() extends A { fun x: int fun x = 1 } -//│ ╔══[ERROR] Type mismatch in definition: +//│ ╔══[ERROR] Type mismatch in signature of member `x`: //│ ║ l.69: fun x: int //│ ║ ^^^^^^ //│ ╟── type `int` does not match type `1` @@ -91,9 +91,12 @@ class B() extends A { :e mixin M { fun x : int } -//│ ╔══[ERROR] Member `x` is declared but not defined +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `M` //│ ║ l.93: mixin M { fun x : int } -//│ ╙── ^ +//│ ║ ^ +//│ ╟── Declared here: +//│ ║ l.93: mixin M { fun x : int } +//│ ╙── ^^^^^^^ //│ mixin M() { //│ fun x: int //│ } diff --git a/shared/src/test/diff/nu/ExplicitVariance.mls b/shared/src/test/diff/nu/ExplicitVariance.mls index 38a5bc5bf8..5bbf93099d 100644 --- a/shared/src/test/diff/nu/ExplicitVariance.mls +++ b/shared/src/test/diff/nu/ExplicitVariance.mls @@ -42,6 +42,11 @@ fun foo(x: Foo[int]): Foo[number] = x //│ fun foo: (x: Foo[int],) -> Foo[number] + +// * Note that not checking variance annotations is actually sound in MLscript, +// * but can be surprising for users, who will find type errors at the use sites. + + // :e // TODO check variance annotations! class Oops0[in A](x: A) //│ class Oops0[A](x: A) @@ -50,4 +55,142 @@ class Oops0[in A](x: A) class Oops0[out A](x: A -> int) //│ class Oops0[A](x: A -> int) +let o = Oops0(id) +//│ let o: Oops0[nothing] +//│ o +//│ = Oops0 {} + +// * What happens is `Oops9{ A = nothing..'? }` is inferred for `o` (consistent with `A`'s covariance), +// * so all negative occurrences of `o.A` are viewed as `nothing` from the outside. +o.x +//│ nothing -> int +//│ res +//│ = [Function: id] + +// * Similarly, `Oops0[int]` here will expand to the equivalent `Oops0{ A = nothing..int }` +(o : Oops0[int]).x +//│ nothing -> int +//│ res +//│ = [Function: id] + +:e +o.x(123) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.77: o.x(123) +//│ ║ ^^^^^^^^ +//│ ╟── integer literal of type `123` does not match type `nothing` +//│ ║ l.77: o.x(123) +//│ ║ ^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.55: class Oops0[out A](x: A -> int) +//│ ╙── ^ +//│ error | int +//│ res +//│ = 123 + +:e +(o : Oops0[int]).x(123) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.92: (o : Oops0[int]).x(123) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── integer literal of type `123` does not match type `nothing` +//│ ║ l.92: (o : Oops0[int]).x(123) +//│ ║ ^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.55: class Oops0[out A](x: A -> int) +//│ ╙── ^ +//│ error | int +//│ res +//│ = 123 + + +class Oops1[out A](x: A -> A, y: A) +//│ class Oops1[A](x: A -> A, y: A) + +let o = Oops1(id, 123) +//│ let o: Oops1[123] +//│ o +//│ = Oops1 {} + +o.x +//│ nothing -> 123 +//│ res +//│ = [Function: id] + +:e +o.x(123) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.121: o.x(123) +//│ ║ ^^^^^^^^ +//│ ╟── integer literal of type `123` does not match type `nothing` +//│ ║ l.121: o.x(123) +//│ ║ ^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.107: class Oops1[out A](x: A -> A, y: A) +//│ ╙── ^ +//│ 123 | error +//│ res +//│ = 123 + +:re +o.x(error) + 1 +//│ int +//│ res +//│ Runtime error: +//│ Error: unexpected runtime error + + +class Oops2[out A](x: A -> A, y: A) +//│ class Oops2[A](x: A -> A, y: A) + +let o = Oops2(id, 123) +//│ let o: Oops2[123] +//│ o +//│ = Oops2 {} + +o.x +//│ nothing -> 123 +//│ res +//│ = [Function: id] + +:e +o.x(123) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.157: o.x(123) +//│ ║ ^^^^^^^^ +//│ ╟── integer literal of type `123` does not match type `nothing` +//│ ║ l.157: o.x(123) +//│ ║ ^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.143: class Oops2[out A](x: A -> A, y: A) +//│ ╙── ^ +//│ 123 | error +//│ res +//│ = 123 + +:e // * We will be able to make this work later, through `o.x : o.A -> o.A` and `o.y : o.A` +o.x(o.y) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.172: o.x(o.y) +//│ ║ ^^^^^^^^ +//│ ╟── integer literal of type `123` does not match type `nothing` +//│ ║ l.146: let o = Oops2(id, 123) +//│ ║ ^^^ +//│ ╟── but it flows into field selection with expected type `nothing` +//│ ║ l.172: o.x(o.y) +//│ ║ ^^^ +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.143: class Oops2[out A](x: A -> A, y: A) +//│ ╙── ^ +//│ 123 | error +//│ res +//│ = 123 + +:re +o.x(error) + 1 +//│ int +//│ res +//│ Runtime error: +//│ Error: unexpected runtime error + diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index eeaec2e42a..441096f83d 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -102,12 +102,18 @@ module Test { fun bar: 'A fun test(x: A) = x } -//│ ╔══[ERROR] Member `foo` is declared but not defined +//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Test` +//│ ║ l.100: module Test { +//│ ║ ^^^^ +//│ ╟── Declared here: //│ ║ l.101: fun foo: 'A => 'A -//│ ╙── ^^^ -//│ ╔══[ERROR] Member `bar` is declared but not defined +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Test` +//│ ║ l.100: module Test { +//│ ║ ^^^^ +//│ ╟── Declared here: //│ ║ l.102: fun bar: 'A -//│ ╙── ^^^ +//│ ╙── ^^^^^^^ //│ module Test { //│ fun bar: nothing //│ fun foo: forall 'A. 'A -> 'A diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 097a5b6f85..3c7518fa48 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -10,15 +10,24 @@ module Test { fun poly1: forall 'a; 'a -> 'a fun poly2: 'a -> 'a = id } -//│ ╔══[ERROR] Member `foo` is declared but not defined +//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Test` +//│ ║ l.5: module Test { +//│ ║ ^^^^ +//│ ╟── Declared here: //│ ║ l.6: fun foo: A => A -//│ ╙── ^^^ -//│ ╔══[ERROR] Member `poly0` is declared but not defined +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] Member `poly0` is declared in parent but not implemented in `Test` +//│ ║ l.5: module Test { +//│ ║ ^^^^ +//│ ╟── Declared here: //│ ║ l.9: fun poly0: 'a -> 'a -//│ ╙── ^^^^^ -//│ ╔══[ERROR] Member `poly1` is declared but not defined +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `poly1` is declared in parent but not implemented in `Test` +//│ ║ l.5: module Test { +//│ ║ ^^^^ +//│ ╟── Declared here: //│ ║ l.10: fun poly1: forall 'a; 'a -> 'a -//│ ╙── ^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ module Test[A] { //│ fun bar: A -> A //│ fun baz: (x: A,) -> A @@ -61,10 +70,10 @@ Test.poly2 :e Test.foo(1) //│ ╔══[ERROR] Type error in application -//│ ║ l.62: Test.foo(1) +//│ ║ l.71: Test.foo(1) //│ ║ ^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.62: Test.foo(1) +//│ ║ l.71: Test.foo(1) //│ ╙── ^ //│ error | ??A //│ res @@ -74,10 +83,10 @@ Test.foo(1) :e Test.foo(error) + 1 //│ ╔══[ERROR] Type error in operator application -//│ ║ l.75: Test.foo(error) + 1 +//│ ║ l.84: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.75: Test.foo(error) + 1 +//│ ║ l.84: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╙── into type `int` //│ error | int @@ -88,7 +97,7 @@ Test.foo(error) + 1 :e Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.89: Test .foo +//│ ║ l.98: Test .foo //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -97,8 +106,8 @@ Test .foo :e (Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.98: (Test).foo -//│ ╙── ^^^^^^^^^ +//│ ║ l.107: (Test).foo +//│ ╙── ^^^^^^^^^ //│ error //│ res //│ = undefined @@ -112,10 +121,10 @@ Test :e Test: Test<'a> //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.113: Test: Test<'a> +//│ ║ l.122: Test: Test<'a> //│ ║ ^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.113: Test: Test<'a> +//│ ║ l.122: Test: Test<'a> //│ ║ ^^ //│ ╟── back into type variable `A` //│ ║ l.5: module Test { @@ -134,7 +143,7 @@ fun test(x) = if x is Test then x.foo :e test(Test) //│ ╔══[ERROR] Type error in application -//│ ║ l.135: test(Test) +//│ ║ l.144: test(Test) //│ ║ ^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope //│ ║ l.5: module Test { diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 7832dab13e..facd8bd5df 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -117,35 +117,124 @@ a1.x :NoJS // TODO -trait Foo[A] { - fun foo[A](x: A): A -} + +trait Foo[A] { fun foo(x: A): A } +//│ trait Foo[A] { +//│ fun foo: (x: A,) -> A +//│ } + +// * This is pretty funky but it seems sound for now... +// * Inherited Foo's type arg is left "unspecified", and since it is not constrained, +// * it can be instantiated to any type by downstream callers of the methods! +module B extends Foo { fun foo(x) = x } +//│ module B extends Foo { +//│ fun foo: 'A -> 'A +//│ } + +B : Foo['X] +//│ Foo['X] + +B.foo +//│ 'a -> 'a + +B.foo(1) +//│ 1 + +module B extends Foo { fun foo(x) = x + 1 } +//│ module B extends Foo { +//│ fun foo: int -> int +//│ } + +B : Foo['X] +//│ Foo[int] + +B.foo +//│ int -> int + + +// * TODO: when +:pe +trait Foo[type A] { fun foo(x: A): A } +//│ ╔══[PARSE ERROR] Unexpected 'type' keyword here +//│ ║ l.157: trait Foo[type A] { fun foo(x: A): A } +//│ ╙── ^^^^ +//│ trait Foo { +//│ fun foo: (x: A,) -> A +//│ } + + +trait Foo[A] { fun a: A; fun foo(x: A): A } +//│ trait Foo[A] { +//│ fun a: A +//│ fun foo: (x: A,) -> A +//│ } + +class Bar[B](a: B) extends Foo { fun foo(x) = x } +//│ class Bar[B](a: B) extends Foo { +//│ fun foo: 'A -> 'A +//│ } +//│ where +//│ 'A :> B + +let b = Bar(123) +//│ let b: Bar[123] + +b : Foo['X] +//│ Foo['X] +//│ where +//│ 'X :> 123 + +b.foo +//│ 'a -> (123 | 'a) + + +// * Note the shadowed type variable `A` in `foo` +trait Foo[A] { fun foo[A](x: A): A } //│ trait Foo[A] { //│ fun foo: forall 'A. (x: 'A,) -> 'A //│ } +:e // FIXME +class B extends Foo { fun foo(x) = x } +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.198: class B extends Foo { fun foo(x) = x } +//│ ║ ^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.198: class B extends Foo { fun foo(x) = x } +//│ ║ ^ +//│ ╟── back into type variable `A` +//│ ║ l.192: trait Foo[A] { fun foo[A](x: A): A } +//│ ║ ^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this reference: +//│ ║ l.198: class B extends Foo { fun foo(x) = x } +//│ ╙── ^ +//│ class B extends Foo { +//│ fun foo: (??A & 'a) -> (??A0 | 'a) +//│ } + :e -class B extends Foo { - fun foo(x) = x + 1 -} -//│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.129: fun foo(x) = x + 1 -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `A` is not an instance of type `int` -//│ ║ l.121: fun foo[A](x: A): A -//│ ║ ^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.129: fun foo(x) = x + 1 -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.129: fun foo(x) = x + 1 -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── operator application of type `int` does not match type `A` -//│ ║ l.129: fun foo(x) = x + 1 -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from method type parameter: -//│ ║ l.121: fun foo[A](x: A): A -//│ ╙── ^ +class B extends Foo { fun foo(x) = x + 1 } +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.192: trait Foo[A] { fun foo[A](x: A): A } +//│ ║ ^ +//│ ╟── into reference of type `int` +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ╙── ^ +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ ^^^^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this operator application: +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ╙── ^^^^^ //│ class B extends Foo { //│ fun foo: int -> int //│ } + diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 95ec2db676..97393c6150 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -40,9 +40,9 @@ class ErrC2 extends Showable { fun toString = 114 } class ErrC3(toString: string -> string) extends Showable -//│ ╔══[ERROR] Member `toString` is declared in parent but not implemented +//│ ╔══[ERROR] Member `toString` is declared in parent but not implemented in `ErrC1` //│ ║ l.38: class ErrC1 extends Showable -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^ //│ ╟── Declared here: //│ ║ l.5: fun toString: string //│ ╙── ^^^^^^^^^^^^^^^^ @@ -122,32 +122,6 @@ class Goodstatt(size: 1 | 2) extends RefinedStadt { class Errcity(size: int) extends SizedStadt { fun bar = "hahaha" } -//│ ╔══[ERROR] Member `name` is declared in parent but not implemented -//│ ║ l.122: class Errcity(size: int) extends SizedStadt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.123: fun bar = "hahaha" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Declared here: -//│ ║ l.83: let name: string -//│ ╙── ^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.122: class Errcity(size: int) extends SizedStadt { -//│ ║ ^^^ -//│ ╟── type `int` does not match type `1 | 2 | 3` -//│ ╟── Note: constraint arises from union type: -//│ ║ l.100: let size: 1 | 2 | 3 -//│ ║ ^^^^^^^^^ -//│ ╟── from signature of member `size`: -//│ ║ l.100: let size: 1 | 2 | 3 -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented -//│ ║ l.122: class Errcity(size: int) extends SizedStadt { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.123: fun bar = "hahaha" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Declared here: -//│ ║ l.91: fun foo: bool -> int -//│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method bar: //│ ║ l.123: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ @@ -163,6 +137,28 @@ class Errcity(size: int) extends SizedStadt { //│ ╟── from signature of member `bar`: //│ ║ l.101: fun bar: int -> int //│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.122: class Errcity(size: int) extends SizedStadt { +//│ ║ ^^^ +//│ ╟── type `int` does not match type `1 | 2 | 3` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.100: let size: 1 | 2 | 3 +//│ ║ ^^^^^^^^^ +//│ ╟── from signature of member `size`: +//│ ║ l.100: let size: 1 | 2 | 3 +//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `name` is declared in parent but not implemented in `Errcity` +//│ ║ l.122: class Errcity(size: int) extends SizedStadt { +//│ ║ ^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.83: let name: string +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Errcity` +//│ ║ l.122: class Errcity(size: int) extends SizedStadt { +//│ ║ ^^^^^^^ +//│ ╟── Declared here: +//│ ║ l.91: fun foo: bool -> int +//│ ╙── ^^^^^^^^^^^^^^^^ //│ class Errcity(size: int) extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: "hahaha" //│ fun foo: bool -> int @@ -210,13 +206,13 @@ class Dirtberg extends More, SizedStadt, Fooo { fun size = 4 // this should not check } //│ ╔══[ERROR] Type mismatch in definition of method size: -//│ ║ l.210: fun size = 4 // this should not check +//│ ║ l.206: fun size = 4 // this should not check //│ ║ ^^^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.210: fun size = 4 // this should not check +//│ ║ l.206: fun size = 4 // this should not check //│ ║ ^ //│ ╟── but it flows into definition of method size with expected type `1 | 2 | 3` -//│ ║ l.210: fun size = 4 // this should not check +//│ ║ l.206: fun size = 4 // this should not check //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.100: let size: 1 | 2 | 3 @@ -248,19 +244,19 @@ class A { fun x: int = 1 } :e class B extends A { fun x = "A" } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.249: class B extends A { fun x = "A" } +//│ ║ l.245: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── string literal of type `"A"` is not an instance of type `int` -//│ ║ l.249: class B extends A { fun x = "A" } +//│ ║ l.245: class B extends A { fun x = "A" } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `int` -//│ ║ l.249: class B extends A { fun x = "A" } +//│ ║ l.245: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.243: class A { fun x: int = 1 } +//│ ║ l.239: class A { fun x: int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.243: class A { fun x: int = 1 } +//│ ║ l.239: class A { fun x: int = 1 } //│ ╙── ^^^^^^^^^^ //│ class B extends A { //│ fun x: "A" @@ -296,19 +292,19 @@ class C extends MyTrait[int] { fun a = 1 } :e class C extends MyTrait[int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.297: class C extends MyTrait[int] { fun a = false } +//│ ║ l.293: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.297: class C extends MyTrait[int] { fun a = false } +//│ ║ l.293: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.297: class C extends MyTrait[int] { fun a = false } +//│ ║ l.293: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.297: class C extends MyTrait[int] { fun a = false } +//│ ║ l.293: class C extends MyTrait[int] { fun a = false } //│ ║ ^^^ //│ ╟── from signature of member `a`: -//│ ║ l.283: trait MyTrait[A] { fun a: A } +//│ ║ l.279: trait MyTrait[A] { fun a: A } //│ ╙── ^^^^ //│ class C extends MyTrait { //│ fun a: false @@ -349,19 +345,19 @@ class C3 extends T4{ fun bar = false } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.348: fun foo = 3 +//│ ║ l.344: fun foo = 3 //│ ║ ^^^^^^^ //│ ╟── integer literal of type `3` does not match type `2` -//│ ║ l.348: fun foo = 3 +//│ ║ l.344: fun foo = 3 //│ ║ ^ //│ ╟── but it flows into definition of method foo with expected type `2` -//│ ║ l.348: fun foo = 3 +//│ ║ l.344: fun foo = 3 //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from literal type: -//│ ║ l.336: fun foo: 2 +//│ ║ l.332: fun foo: 2 //│ ║ ^ //│ ╟── from signature of member `foo`: -//│ ║ l.336: fun foo: 2 +//│ ║ l.332: fun foo: 2 //│ ╙── ^^^^^^ //│ class C3 extends T1, T2, T4 { //│ fun bar: false @@ -371,24 +367,24 @@ class C3 extends T4{ :e class C2(foo: int, bar: string) extends T4 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.372: class C2(foo: int, bar: string) extends T4 +//│ ║ l.368: class C2(foo: int, bar: string) extends T4 //│ ║ ^^^ //│ ╟── type `int` does not match type `2` //│ ╟── Note: constraint arises from literal type: -//│ ║ l.336: fun foo: 2 +//│ ║ l.332: fun foo: 2 //│ ║ ^ //│ ╟── from signature of member `foo`: -//│ ║ l.336: fun foo: 2 +//│ ║ l.332: fun foo: 2 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.372: class C2(foo: int, bar: string) extends T4 +//│ ║ l.368: class C2(foo: int, bar: string) extends T4 //│ ║ ^^^^^^ //│ ╟── type `string` does not match type `bool | int` //│ ╟── Note: constraint arises from union type: -//│ ║ l.324: let bar : int | bool +//│ ║ l.320: let bar : int | bool //│ ║ ^^^^^^^^^^ //│ ╟── from signature of member `bar`: -//│ ║ l.324: let bar : int | bool +//│ ║ l.320: let bar : int | bool //│ ╙── ^^^^^^^^^^^^^^^^ //│ class C2(foo: int, bar: string) extends T1, T2, T4 @@ -397,19 +393,19 @@ trait T5 extends T4 { let foo: 4 } //│ ╔══[ERROR] Type mismatch in signature of member `foo`: -//│ ║ l.397: let foo: 4 +//│ ║ l.393: let foo: 4 //│ ║ ^^^^^^ //│ ╟── type `4` does not match type `2` -//│ ║ l.397: let foo: 4 +//│ ║ l.393: let foo: 4 //│ ║ ^ //│ ╟── but it flows into signature of member `foo` with expected type `2` -//│ ║ l.397: let foo: 4 +//│ ║ l.393: let foo: 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from literal type: -//│ ║ l.336: fun foo: 2 +//│ ║ l.332: fun foo: 2 //│ ║ ^ //│ ╟── from signature of member `foo`: -//│ ║ l.336: fun foo: 2 +//│ ║ l.332: fun foo: 2 //│ ╙── ^^^^^^ //│ trait T5 extends T1, T2, T4 { //│ fun bar: bool @@ -421,34 +417,34 @@ trait T3 extends T1, T2 { let foo: true } //│ ╔══[ERROR] Type mismatch in signature of member `foo`: -//│ ║ l.421: let foo: true +//│ ║ l.417: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── type `true` does not match type `1 | 2 | 3` -//│ ║ l.421: let foo: true +//│ ║ l.417: let foo: true //│ ║ ^^^^ //│ ╟── but it flows into signature of member `foo` with expected type `1 | 2 | 3` -//│ ║ l.421: let foo: true +//│ ║ l.417: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.319: let foo : 1 | 2 | 3 +//│ ║ l.315: let foo : 1 | 2 | 3 //│ ║ ^^^^^^^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.319: let foo : 1 | 2 | 3 +//│ ║ l.315: let foo : 1 | 2 | 3 //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in signature of member `foo`: -//│ ║ l.421: let foo: true +//│ ║ l.417: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── type `true` does not match type `2 | 3 | 4` -//│ ║ l.421: let foo: true +//│ ║ l.417: let foo: true //│ ║ ^^^^ //│ ╟── but it flows into signature of member `foo` with expected type `2 | 3 | 4` -//│ ║ l.421: let foo: true +//│ ║ l.417: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.323: let foo : 2 | 3 | 4 +//│ ║ l.319: let foo : 2 | 3 | 4 //│ ║ ^^^^^^^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.323: let foo : 2 | 3 | 4 +//│ ║ l.319: let foo : 2 | 3 | 4 //│ ╙── ^^^^^^^^^^^^^^^ //│ trait T3 extends T1, T2 { //│ fun bar: bool diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 26394e9b6f..12858825a8 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -301,11 +301,9 @@ class CE extends Ele { class E1 extends Test { fun foo = 2 } -//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented +//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `E1` //│ ║ l.301: class E1 extends Test { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.302: fun foo = 2 -//│ ║ ^^^^^^^^^^^^^ +//│ ║ ^^ //│ ╟── Declared here: //│ ║ l.7: fun bar: bool -> bool //│ ╙── ^^^^^^^^^^^^^^^^^ @@ -318,10 +316,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] A trait can only inherit from other traits -//│ ║ l.318: trait TE1 extends C +//│ ║ l.316: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] A trait can only inherit from other traits -//│ ║ l.319: trait TE2 extends M, Test +//│ ║ l.317: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1 extends C, Test //│ trait TE2 extends Test { @@ -335,13 +333,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.334: fun foo = true +//│ ║ l.332: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.334: fun foo = true +//│ ║ l.332: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.334: fun foo = true +//│ ║ l.332: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.6: fun foo: int @@ -358,20 +356,20 @@ class E2 extends Test { :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.359: class D extends Test[int], Test[bool] +//│ ║ l.357: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.359: class D extends Test[int], Test[bool] +//│ ║ l.357: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented -//│ ║ l.359: class D extends Test[int], Test[bool] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `D` +//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ ^ //│ ╟── Declared here: //│ ║ l.6: fun foo: int //│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented -//│ ║ l.359: class D extends Test[int], Test[bool] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `D` +//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ ^ //│ ╟── Declared here: //│ ║ l.7: fun bar: bool -> bool //│ ╙── ^^^^^^^^^^^^^^^^^ @@ -429,10 +427,10 @@ if b is Foo(a) then a else 0 :e // * Note: an error is raised in this case and not above because B is invariant so it can't be widened if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.430: if b is Bar(f) then f else 0 +//│ ║ l.428: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.412: class Bar[B](f: B => B) extends Base +//│ ║ l.410: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 @@ -441,28 +439,28 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.440: if b is +//│ ║ l.438: if b is //│ ║ ^^^^ -//│ ║ l.441: Foo(a) then a +//│ ║ l.439: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.442: Bar(f) then f +//│ ║ l.440: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.412: class Bar[B](f: B => B) extends Base +//│ ║ l.410: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything :e let tt1 = Test //│ ╔══[ERROR] trait Test cannot be used in term position -//│ ║ l.456: let tt1 = Test +//│ ║ l.454: let tt1 = Test //│ ╙── ^^^^ //│ let tt1: error :e fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot match on trait `Test` -//│ ║ l.463: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.461: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error @@ -503,40 +501,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.501: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.501: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.501: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.501: fun fto(w: WP): EM = w +//│ ║ l.499: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.502: z: WP +//│ ║ l.500: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.481: let z: ZL +//│ ║ l.479: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.502: z: WP +//│ ║ l.500: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.502: z: WP +//│ ║ l.500: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.503: g: ZL +//│ ║ l.501: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.480: let g: Geo +//│ ║ l.478: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.503: g: ZL +//│ ║ l.501: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.503: g: ZL +//│ ║ l.501: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL @@ -575,20 +573,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.574: fun foo(x) = x && false +//│ ║ l.572: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ?a` is not an instance of type `bool` +//│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.574: fun foo(x) = x && false +//│ ║ l.572: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.574: fun foo(x) = x && false +//│ ║ l.572: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ?a` -//│ ║ l.574: fun foo(x) = x && false +//│ ╟── operator application of type `bool` does not match type `int | ??_` +//│ ║ l.572: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.545: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2 extends Bs, Ele { //│ fun ce: (Test & 'a) -> (Oth | 'a) @@ -600,32 +598,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.599: class Eh extends Bs(1) +//│ ║ l.597: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.599: class Eh extends Bs(1) +//│ ║ l.597: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.544: class Bs(a: bool) { -//│ ╙── ^^^^ -//│ ╔══[ERROR] Type mismatch in integer literal: -//│ ║ l.599: class Eh extends Bs(1) -//│ ║ ^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.544: class Bs(a: bool) { +//│ ║ l.542: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.600: class Eh1 extends Bs +//│ ║ l.598: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.545: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.545: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.545: fun foo(x) = x + 1 +//│ ║ l.543: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.6: fun foo: int @@ -633,9 +624,9 @@ class Eh3 extends Bs(false), Test //│ ╟── from signature of member `foo`: //│ ║ l.6: fun foo: int //│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented -//│ ║ l.601: class Eh3 extends Bs(false), Test -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Eh3` +//│ ║ l.599: class Eh3 extends Bs(false), Test +//│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.7: fun bar: bool -> bool //│ ╙── ^^^^^^^^^^^^^^^^^ @@ -694,7 +685,7 @@ class Bc3 { :e class Bc12 extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.695: class Bc12 extends Bc1(1), Bc2(true) +//│ ║ l.686: class Bc12 extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12 extends Bc1, Bc2 @@ -711,14 +702,14 @@ Bc02().foo :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.712: class Bc31(baz: bool) extends Bc3 +//│ ║ l.703: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.686: let baz : int +//│ ║ l.677: let baz : int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.686: let baz : int +//│ ║ l.677: let baz : int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: bool) extends Bc3 @@ -727,18 +718,11 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.727: let foo = true -//│ ║ ^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.683: class Bc1(foo: int) -//│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.727: let foo = true +//│ ║ l.718: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.726: class Bc11 extends Bc1(1) { +//│ ║ l.717: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ class Bc11 extends Bc1 { //│ let foo: true @@ -765,7 +749,7 @@ trait BInt extends Base[int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.765: fun f = error +//│ ║ l.749: fun f = error //│ ╙── ^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -789,13 +773,13 @@ bp: Base[(int, bool)] :e bp: Base[(int, int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.790: bp: Base[(int, int)] +//│ ║ l.774: bp: Base[(int, int)] //│ ║ ^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.782: let bp: BPar[bool] +//│ ║ l.766: let bp: BPar[bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.790: bp: Base[(int, int)] +//│ ║ l.774: bp: Base[(int, int)] //│ ╙── ^^^ //│ Base[(int, int,)] @@ -839,13 +823,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.840: class DerBad1 extends Base[int, int] +//│ ║ l.824: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `f` is declared in parent but not implemented -//│ ║ l.840: class DerBad1 extends Base[int, int] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `DerBad1` +//│ ║ l.824: class DerBad1 extends Base[int, int] +//│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.748: trait Base[A] { fun f: A -> A } +//│ ║ l.732: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^ //│ class DerBad1 extends Base { //│ fun f: 'A -> 'A @@ -856,28 +840,28 @@ class DerBad1 extends Base[int, int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.857: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -914,7 +898,7 @@ trait Tb extends Ta[int] { let p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.914: let p = false +//│ ║ l.898: let p = false //│ ╙── ^^^^^^^^^ //│ trait Tb extends Ta { //│ let g: 'T @@ -948,14 +932,14 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.949: class Fischl(age: bool) extends Oz +//│ ║ l.933: class Fischl(age: bool) extends Oz //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.942: let age: int +//│ ║ l.926: let age: int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.942: let age: int +//│ ║ l.926: let age: int //│ ╙── ^^^^^^^^ //│ class Fischl(age: bool) extends Oz @@ -974,20 +958,20 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.974: fun foo(x) = x && true +//│ ║ l.958: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ?a` is not an instance of type `bool` +//│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.974: fun foo(x) = x && true +//│ ║ l.958: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.974: fun foo(x) = x && true +//│ ║ l.958: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ?a` -//│ ║ l.974: fun foo(x) = x && true +//│ ╟── operator application of type `bool` does not match type `int | ??_` +//│ ║ l.958: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.966: fun foo(x) = x + 1 +//│ ║ l.950: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { //│ fun foo: bool -> bool @@ -1004,11 +988,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1005: class Ohhh(x: bool) extends Ha -//│ ║ ^^^^ +//│ ║ l.989: class Ohhh(x: bool) extends Ha +//│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.996: class Ha { let x: int = 1 } +//│ ║ l.980: class Ha { let x: int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: bool) extends Ha diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index 6e6143549b..5dea8fafce 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -1,24 +1,20 @@ -:NewParser +:NewDefs -// FIXME let f = let tmp = "ok" 123 -//│ ╔══[ERROR] Illegal position for this definition statement. -//│ ║ l.6: let tmp = "ok" -//│ ╙── ^^^^^^^^^^ -//│ f: 123 -//│ = 123 +//│ let f: 123 +//│ f +//│ = 123 -// TODO allow let x : int | string let x = 1 -//│ x: int | string -//│ = -//│ 1 -//│ <: x: -//│ int | string -//│ = 1 +//│ let x: int | string +//│ let x: 1 +//│ x +//│ = +//│ x +//│ = 1 diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index 6234954272..22df6ca42e 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -80,10 +80,13 @@ trait T1 { val x: int | string } class C2 extends C1(0), T1 //│ class C2 extends C1, T1 +C2().x : 0 +//│ 0 + :e class C2 extends C1(false), T1 //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.84: class C2 extends C1(false), T1 +//│ ║ l.87: class C2 extends C1(false), T1 //│ ║ ^^^^^ //│ ╟── reference of type `false` does not match type `int | string` //│ ╟── Note: constraint arises from union type: @@ -97,21 +100,15 @@ class C2 extends C1(false), T1 :e class C2 extends C1("oops"), T1 //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.98: class C2 extends C1("oops"), T1 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"oops"` does not match type `bool | int` -//│ ║ l.98: class C2 extends C1("oops"), T1 -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from union type: -//│ ║ l.73: class C1(x: int | bool) -//│ ╙── ^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in string literal: -//│ ║ l.98: class C2 extends C1("oops"), T1 -//│ ║ ^^^^^^ +//│ ║ l.101: class C2 extends C1("oops"), T1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"oops"` does not match type `bool | int` +//│ ║ l.101: class C2 extends C1("oops"), T1 +//│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.73: class C1(x: int | bool) //│ ╙── ^^^^^^^^^^ //│ class C2 extends C1, T1 + diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 645d091668..a34a8096d4 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -14,9 +14,12 @@ module Oops { module Oops { fun a : int } -//│ ╔══[ERROR] Member `a` is declared but not defined +//│ ╔══[ERROR] Member `a` is declared in parent but not implemented in `Oops` +//│ ║ l.14: module Oops { +//│ ║ ^^^^ +//│ ╟── Declared here: //│ ║ l.15: fun a : int -//│ ╙── ^ +//│ ╙── ^^^^^^^ //│ module Oops { //│ fun a: int //│ } @@ -28,7 +31,7 @@ module Oops { fun a = a } //│ ╔══[ERROR] A type signature for 'a' was already given -//│ ║ l.27: fun a : string +//│ ║ l.30: fun a : string //│ ╙── ^^^^^^^^^^ //│ module Oops { //│ fun a: string @@ -40,19 +43,19 @@ module Oops { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.40: fun a = false +//│ ║ l.43: fun a = false //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.40: fun a = false +//│ ║ l.43: fun a = false //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.40: fun a = false +//│ ║ l.43: fun a = false //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.39: fun a : int +//│ ║ l.42: fun a : int //│ ║ ^^^ //│ ╟── from signature of member `a`: -//│ ║ l.39: fun a : int +//│ ║ l.42: fun a : int //│ ╙── ^^^^^^^ //│ module Oops { //│ fun a: int @@ -64,7 +67,7 @@ module Oops { fun a = 2 } //│ ╔══[ERROR] Refininition of a -//│ ║ l.64: fun a = 2 +//│ ║ l.67: fun a = 2 //│ ╙── ^^^^^ //│ module Oops { //│ fun a: 1 @@ -102,19 +105,19 @@ module A { fun i(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method i: -//│ ║ l.102: fun i(x) = x +//│ ║ l.105: fun i(x) = x //│ ║ ^^^^^^^^ //│ ╟── function of type `?a -> ?a` does not match type `'a` -//│ ║ l.102: fun i(x) = x +//│ ║ l.105: fun i(x) = x //│ ║ ^^^^^^^ //│ ╟── but it flows into definition of method i with expected type `'a` -//│ ║ l.102: fun i(x) = x +//│ ║ l.105: fun i(x) = x //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.101: fun i : 'a +//│ ║ l.104: fun i : 'a //│ ║ ^^ //│ ╟── from signature of member `i`: -//│ ║ l.101: fun i : 'a +//│ ║ l.104: fun i : 'a //│ ╙── ^^^^^^ //│ module A { //│ fun i: nothing @@ -131,19 +134,19 @@ module M { fun a = 1 } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.131: fun a = 1 +//│ ║ l.134: fun a = 1 //│ ║ ^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `A` -//│ ║ l.131: fun a = 1 +//│ ║ l.134: fun a = 1 //│ ║ ^ //│ ╟── but it flows into definition of method a with expected type `A` -//│ ║ l.131: fun a = 1 +//│ ║ l.134: fun a = 1 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.130: fun a: A +//│ ║ l.133: fun a: A //│ ║ ^ //│ ╟── from signature of member `a`: -//│ ║ l.130: fun a: A +//│ ║ l.133: fun a: A //│ ╙── ^^^^ //│ module M { //│ class A @@ -157,7 +160,7 @@ module M { fun a = 1 } //│ ╔══[ERROR] undeclared `this` -//│ ║ l.156: fun a: this.A +//│ ║ l.159: fun a: this.A //│ ╙── ^^^^ //│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached and unexpected state. diff --git a/shared/src/test/diff/nu/Parens.mls b/shared/src/test/diff/nu/Parens.mls index 9a3bfc8f6a..0a3d72b020 100644 --- a/shared/src/test/diff/nu/Parens.mls +++ b/shared/src/test/diff/nu/Parens.mls @@ -1,66 +1,77 @@ -:NewParser +:NewDefs () -//│ res: () -//│ = [] +//│ () +//│ res +//│ = [] :pe (,) //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.9: (,) -//│ ╙── ^ +//│ ║ l.10: (,) +//│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.9: (,) -//│ ╙── ^ -//│ res: undefined -//│ = undefined +//│ ║ l.10: (,) +//│ ╙── ^ +//│ undefined +//│ res +//│ = undefined -// FIXME shouldn't parse like a 1-tuple... (1) -//│ res: 1 -//│ = 1 +//│ 1 +//│ res +//│ = 1 (1,) -//│ res: 1 -//│ = 1 +//│ 1 +//│ res +//│ = 1 (1, 2) -//│ res: (1, 2,) -//│ = [ 1, 2 ] +//│ (1, 2,) +//│ res +//│ = [ 1, 2 ] (1, 2,) -//│ res: (1, 2,) -//│ = [ 1, 2 ] +//│ (1, 2,) +//│ res +//│ = [ 1, 2 ] let x: () -//│ x: () -//│ = +//│ let x: () +//│ x +//│ = :pe let x: (,) //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.42: let x: (,) +//│ ║ l.48: let x: (,) //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.42: let x: (,) +//│ ║ l.48: let x: (,) //│ ╙── ^ -//│ x: undefined -//│ = +//│ let x: undefined +//│ x +//│ = let x: (1) -//│ x: 1 -//│ = +//│ let x: 1 +//│ x +//│ = let x: (1,) -//│ x: 1 -//│ = +//│ let x: 1 +//│ x +//│ = let x: (1, 2) -//│ x: (1, 2,) -//│ = +//│ let x: (1, 2,) +//│ x +//│ = let x: (1, 2,) -//│ x: (1, 2,) -//│ = +//│ let x: (1, 2,) +//│ x +//│ = diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index 3753365c72..34f27b9634 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -89,14 +89,14 @@ class Impl extends Base2 :e class Impl extends Base2, Foo -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `Impl` //│ ║ l.91: class Impl extends Base2, Foo -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.5: trait Foo[A] { fun x: A } //│ ╙── ^^^^ //│ class Impl extends Base2, Foo { -//│ fun x: nothing +//│ fun x: 'A //│ } class Impl extends Base2, Foo { diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index a2c4bc5a41..61a045e689 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -134,22 +134,7 @@ module M extends T1, T2, C1 { fun x: 0 fun x = this.x } -//│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.135: fun x = this.x -//│ ║ ^^^^^^^^^^ -//│ ╟── type `0` does not match type `1 | 2` -//│ ║ l.134: fun x: 0 -//│ ║ ^ -//│ ╟── but it flows into field selection with expected type `1 | 2` -//│ ║ l.135: fun x = this.x -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from union type: -//│ ║ l.8: trait T2 { fun x: 1 | 2 } -//│ ║ ^^^^^ -//│ ╟── from signature of member `x`: -//│ ║ l.8: trait T2 { fun x: 1 | 2 } -//│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in definition: +//│ ╔══[ERROR] Type mismatch in signature of member `x`: //│ ║ l.134: fun x: 0 //│ ║ ^^^^ //│ ╟── type `0` does not match type `1 | 2` @@ -188,9 +173,9 @@ M.x :e class C2 extends T1 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented -//│ ║ l.190: class C2 extends T1 -//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C2` +//│ ║ l.175: class C2 extends T1 +//│ ║ ^^ //│ ╟── Declared here: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ @@ -205,9 +190,9 @@ abstract class C2 extends T1 :e class C3 extends C2 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented -//│ ║ l.207: class C3 extends C2 -//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C3` +//│ ║ l.192: class C3 extends C2 +//│ ║ ^^ //│ ╟── Declared here: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ @@ -228,13 +213,13 @@ class C2 extends T1 { fun x = 1 } :e class C2 extends T1, T2 { fun x = 2 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.229: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.214: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── integer literal of type `2` does not match type `0 | 1` -//│ ║ l.229: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.214: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 1` -//│ ║ l.229: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.214: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } @@ -254,19 +239,19 @@ class C2 extends T1, T2 { fun x = 1 } :e class C3 extends C2 { fun x = 111 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.255: class C3 extends C2 { fun x = 111 } +//│ ║ l.240: class C3 extends C2 { fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── integer literal of type `111` does not match type `1` -//│ ║ l.255: class C3 extends C2 { fun x = 111 } +//│ ║ l.240: class C3 extends C2 { fun x = 111 } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `1` -//│ ║ l.255: class C3 extends C2 { fun x = 111 } +//│ ║ l.240: class C3 extends C2 { fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.249: class C2 extends T1, T2 { fun x = 1 } +//│ ║ l.234: class C2 extends T1, T2 { fun x = 1 } //│ ║ ^ //│ ╟── from definition of method x: -//│ ║ l.249: class C2 extends T1, T2 { fun x = 1 } +//│ ║ l.234: class C2 extends T1, T2 { fun x = 1 } //│ ╙── ^^^^^ //│ class C3 extends C2, T1, T2 { //│ fun x: 111 @@ -290,13 +275,13 @@ class C2 extends T1, C1 { fun x = 0 } :e class C2 extends C1, T1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.291: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.276: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.291: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.276: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.291: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.276: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } @@ -311,13 +296,13 @@ class C2 extends C1, T1 { fun x = 1 } :e class C2 extends T1, C1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.312: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.297: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.312: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.297: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.312: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.297: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.72: class C1 { fun x: 0 | 2 = 0 } @@ -334,59 +319,116 @@ class C2 extends T1, C1 { fun x = 1 } :e trait T2 { val r = 1(1) } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.335: trait T2 { val r = 1(1) } +//│ ║ l.320: trait T2 { val r = 1(1) } //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.335: trait T2 { val r = 1(1) } +//│ ║ l.320: trait T2 { val r = 1(1) } //│ ║ ^^^^ //│ ╟── integer literal of type `1` is not a function -//│ ║ l.335: trait T2 { val r = 1(1) } +//│ ║ l.320: trait T2 { val r = 1(1) } //│ ╙── ^ //│ trait T2 { //│ let r: error //│ } -:e class C2 extends T2 -//│ ╔══[ERROR] Member `r` is declared in parent but not implemented -//│ ║ l.350: class C2 extends T2 -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── Declared here: -//│ ║ l.335: trait T2 { val r = 1(1) } -//│ ╙── ^^^^^^^^ //│ class C2 extends T2 { //│ let r: error //│ } :e -trait T2[A] { +trait T3[A] { val r = C2().x } -class C2 extends T2[int] +class C2 extends T3[int] //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.364: val r = C2().x +//│ ║ l.342: val r = C2().x //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.363: trait T2[A] { +//│ ║ l.341: trait T3[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.364: val r = C2().x +//│ ║ l.342: val r = C2().x //│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type `C2` does not contain member `x` -//│ ║ l.364: val r = C2().x +//│ ║ l.342: val r = C2().x //│ ╙── ^^ -//│ trait T2[A] { +//│ trait T3[A] { //│ let r: error //│ } -//│ class C2 extends T2 +//│ class C2 extends T3 -:e // FIXME -C2() : T2['X] -//│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.363: trait T2[A] { +:e // * Note: lack of hygiene... happens only if class shadows previous C2 and is part of the error-throwing block +C2() : T3['X] +//│ ╔══[ERROR] Type `C2` does not contain member `T3#A` +//│ ║ l.341: trait T3[A] { //│ ╙── ^ -//│ T2['X] +//│ T3['X] //│ where //│ 'X :> error +class C3 extends T3[int] +//│ class C3 extends T3 { +//│ let r: error +//│ } + +C3() : T3['X] +//│ T3[int] + + + +trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ trait Foo { +//│ fun foo: forall 'A. (x: 'A,) -> 'A +//│ } + +class B extends Foo { fun foo = error } +//│ class B extends Foo { +//│ fun foo: nothing +//│ } + +:e // FIXME +class B extends Foo { fun foo(x) = x } +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.391: class B extends Foo { fun foo(x) = x } +//│ ║ ^^^^^^^^^^ +//│ ╟── type variable `'A` leaks out of its scope +//│ ║ l.380: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ ^^ +//│ ╟── back into type variable `'A` +//│ ║ l.380: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ ^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this reference: +//│ ║ l.391: class B extends Foo { fun foo(x) = x } +//│ ╙── ^ +//│ class B extends Foo { +//│ fun foo: (??A & 'a) -> (??A0 | 'a) +//│ } + +:e // FIXME +class B extends Foo { fun foo(x) = x + 1 } +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.410: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type variable `'A` leaks out of its scope +//│ ║ l.380: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ ^^ +//│ ╟── into reference of type `int` +//│ ║ l.410: class B extends Foo { fun foo(x) = x + 1 } +//│ ╙── ^ +//│ ╔══[ERROR] Type error in definition of method foo +//│ ║ l.410: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type variable `'A` leaks out of its scope +//│ ║ l.410: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ ^^^^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this operator application: +//│ ║ l.410: class B extends Foo { fun foo(x) = x + 1 } +//│ ╙── ^^^^^ +//│ class B extends Foo { +//│ fun foo: int -> int +//│ } + diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index 928203dea6..3e909ec9ad 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -19,9 +19,6 @@ type AI3(n) = Array[int] //│ ╔══[ERROR] Type alias definitions cannot have value parameters //│ ║ l.18: type AI3(n) = Array[int] //│ ╙── ^^^ -//│ ╔══[ERROR] Type alias parameters currently need type annotations -//│ ║ l.18: type AI3(n) = Array[int] -//│ ╙── ^ //│ type AI3 = Array[int] // :e diff --git a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls index c3898d50e6..c27afc59b3 100644 --- a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls +++ b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls @@ -12,6 +12,14 @@ class App[A](s: A, t: A) //│ class Abs[A](x: string, t: A) //│ class App[A](s: A, t: A) +fun eval(sub, v) = + if v is + Abs(x, t) then + eval(Cons((error, error), Nil), error) + eval(Cons(error, sub), error) + error +//│ fun eval: (Cons[anything] | Nil, Abs[anything],) -> nothing + mixin EvalLambda { fun eval(sub, v) = if v is @@ -25,8 +33,8 @@ mixin EvalLambda { //│ fun eval: (Cons['A] | Nil, Abs[anything],) -> nothing //│ } -// Note: this used to crash becayse of a current type simplification bug: analyze2 does not traverse TVs witht he correct PolMap -// The original unreduced version in PolymorphicVariants.mls still crashes... +// * Note: this used to crash because of a current type simplification bug: analyze2 does not traverse TVs witht he correct PolMap +// * The original unreduced version in PolymorphicVariants.mls still crashes... // :ds module Test1 extends EvalLambda //│ module Test1 { diff --git a/shared/src/test/diff/nu/ParserFailures.mls b/shared/src/test/diff/ucs/ParserFailures.mls similarity index 97% rename from shared/src/test/diff/nu/ParserFailures.mls rename to shared/src/test/diff/ucs/ParserFailures.mls index 61e2ff5a33..fca068c589 100644 --- a/shared/src/test/diff/nu/ParserFailures.mls +++ b/shared/src/test/diff/ucs/ParserFailures.mls @@ -1,4 +1,4 @@ -:NewParser +:NewDefs :NoJS // FIXME: Interleaved let bindings are not implemented in `IfOpsApp`. @@ -15,3 +15,4 @@ fun tt(x) = let y = 0 is B() then "B" //│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing + diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index 8ef94d7513..e444ff198a 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -166,7 +166,7 @@ fun zipWith(f, xs, ys) = Nil then None Nil then if ys is Nil then Some(Nil) else None -//│ fun zipWith: forall 'A 'head 'head0. (('head, 'head0,) -> 'A, Cons['head] | Nil, Cons['head0] | Nil,) -> (None | Some[Cons['A] | Nil]) +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Nil, Cons['head0] | Nil,) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Nil, Nil).value.toArray //│ Array[anything] @@ -200,7 +200,7 @@ fun zipWith_wrong2(f, xs, ys) = if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith_wrong2(f, xs, ys) is Some(tail) then Cons(Some(f(x, y)), tail) else if xs is Nil and ys is Nil then Some(Nil) else None -//│ fun zipWith_wrong2: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (Cons[Some['A]] | None | Some[Nil]) +//│ fun zipWith_wrong2: forall 'A 'head 'head0. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (Cons[Some['A]] | None | Some[Nil]) // * No type error! The definition and use are well-typed... zipWith_wrong2(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))) From 74d911b9e5650b9ab921e6f08b95979726776801 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 5 Jun 2023 17:40:58 +0800 Subject: [PATCH 346/498] Remove all the now useless `:NoJS` commands related to traits --- shared/src/test/diff/nu/AbstractClasses.mls | 42 +- shared/src/test/diff/nu/BadClassInherit.mls | 17 +- shared/src/test/diff/nu/DiamondInherit.mls | 51 +- shared/src/test/diff/nu/GADTMono.mls | 57 ++- .../diff/nu/InferredInheritanceTypeArgs.mls | 39 +- shared/src/test/diff/nu/Interfaces.mls | 445 ++++++++++++------ shared/src/test/diff/nu/MutualRec.mls | 63 ++- shared/src/test/diff/nu/ParamImplementing.mls | 8 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 56 ++- .../test/diff/nu/TrickyGenericInheritance.mls | 54 ++- 10 files changed, 573 insertions(+), 259 deletions(-) diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index 0b93c8b1af..6c5606b219 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -1,6 +1,5 @@ :NewDefs -:NoJS // TODO abstract class Foo(x: int) { @@ -13,16 +12,20 @@ abstract class Foo(x: int) { :e Foo(1) //│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated -//│ ║ l.14: Foo(1) +//│ ║ l.13: Foo(1) //│ ╙── ^^^ //│ Foo +//│ res +//│ = Foo {} :e // TODO allow with `new` keyword new Foo(1) //│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated -//│ ║ l.21: new Foo(1) +//│ ║ l.22: new Foo(1) //│ ╙── ^^^^^^ //│ Foo +//│ res +//│ = Foo {} abstract class Foo(x: int) { @@ -35,16 +38,20 @@ abstract class Foo(x: int) { :e Foo(1) //│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated -//│ ║ l.36: Foo(1) +//│ ║ l.39: Foo(1) //│ ╙── ^^^ //│ Foo +//│ res +//│ = Foo {} :e // TODO support new Foo(1) { fun f = id } //│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.43: new Foo(1) { fun f = id } +//│ ║ l.48: new Foo(1) { fun f = id } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ error +//│ Code generation encountered an error: +//│ custom class body is not supported yet abstract class Bar extends Foo(1) @@ -56,15 +63,18 @@ abstract class Bar extends Foo(1) module Baz extends Bar Baz.f(1) //│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `Baz` -//│ ║ l.56: module Baz extends Bar +//│ ║ l.63: module Baz extends Bar //│ ║ ^^^ //│ ╟── Declared here: -//│ ║ l.29: fun f: int -> int +//│ ║ l.32: fun f: int -> int //│ ╙── ^^^^^^^^^^^^^ //│ module Baz extends Bar, Foo { //│ fun f: int -> int //│ } //│ int +//│ res +//│ Runtime error: +//│ TypeError: Baz.f is not a function module Baz extends Bar { fun f(x) = x + 1 @@ -74,6 +84,8 @@ Baz.f(1) //│ fun f: int -> int //│ } //│ int +//│ res +//│ = 2 @@ -90,10 +102,10 @@ trait T1 { fun x: int | bool } :e class C2 extends C1, T1 //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C2` -//│ ║ l.91: class C2 extends C1, T1 -//│ ║ ^^ +//│ ║ l.103: class C2 extends C1, T1 +//│ ║ ^^ //│ ╟── Declared here: -//│ ║ l.80: abstract class C1 { fun x: int | string } +//│ ║ l.92: abstract class C1 { fun x: int | string } //│ ╙── ^^^^^^^^^^^^^^^ //│ class C2 extends C1, T1 { //│ fun x: int @@ -112,10 +124,10 @@ abstract class C2 extends C1, T1 :e class C3 extends C2 //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C3` -//│ ║ l.113: class C3 extends C2 +//│ ║ l.125: class C3 extends C2 //│ ║ ^^ //│ ╟── Declared here: -//│ ║ l.80: abstract class C1 { fun x: int | string } +//│ ║ l.92: abstract class C1 { fun x: int | string } //│ ╙── ^^^^^^^^^^^^^^^ //│ class C3 extends C1, C2, T1 { //│ fun x: int @@ -128,6 +140,7 @@ class C3 extends C2 { fun x = 1 } +:ge // TODO report this as a type error abstract class C { fun x : int fun foo0 = x @@ -138,7 +151,10 @@ abstract class C { //│ fun foo1: int //│ fun x: int //│ } +//│ Code generation encountered an error: +//│ unresolved symbol x +:ge // TODO report this as a type error class C { val x : int fun foo0 = x @@ -149,5 +165,7 @@ class C { //│ fun foo1: int //│ let x: int //│ } +//│ Code generation encountered an error: +//│ unresolved symbol x diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index f21bfc6c55..a0be7b9424 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -128,7 +128,6 @@ class Bar extends Foo, M //│ } -:NoJS // TODO class A { class X { fun f = 1 } } trait B { class X { fun g = 1 } } @@ -146,19 +145,19 @@ trait B { class X { fun g = 1 } } :e class C extends A, B //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.147: class C extends A, B +//│ ║ l.146: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── Declared here: -//│ ║ l.134: trait B { class X { fun g = 1 } } +//│ ║ l.133: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Intersection of class member and class members currently unsupported -//│ ║ l.147: class C extends A, B +//│ ║ l.146: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.133: class A { class X { fun f = 1 } } +//│ ║ l.132: class A { class X { fun f = 1 } } //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.134: trait B { class X { fun g = 1 } } +//│ ║ l.133: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C extends A, B { //│ class X { @@ -171,12 +170,12 @@ class C extends A { class X { fun g = 1 } } //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.170: class C extends A { +//│ ║ l.169: class C extends A { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.171: class X { fun g = 1 } +//│ ║ l.170: class X { fun g = 1 } //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Declared here: -//│ ║ l.133: class A { class X { fun f = 1 } } +//│ ║ l.132: class A { class X { fun f = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C extends A { //│ class X { diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index 333337d853..5cde0b8516 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -1,6 +1,5 @@ :NewDefs -:NoJS // TODO @@ -18,14 +17,20 @@ module Bar extends Foo[int | bool], Foo[int | string] { Bar.foo //│ 123 +//│ res +//│ = 123 Bar : Foo['X] //│ Foo['X] //│ where //│ 'X := int | string +//│ res +//│ = Bar { class: [class Bar extends Object] } (Bar : Foo['X]).foo //│ int | string +//│ res +//│ = 123 trait Foo[A] { fun foo: A; fun bar: A -> A } @@ -45,11 +50,15 @@ module Bar extends Foo[int | bool], Foo[int | string] { Bar.bar //│ forall 'a. 'a -> 'a +//│ res +//│ = [Function: id] Bar : Foo['X] //│ Foo['X] //│ where //│ 'X := int | string +//│ res +//│ = Bar { class: [class Bar extends Object] } trait T1 extends Foo[int | bool] @@ -71,17 +80,27 @@ module Bar extends T1, Foo[int | string] { (Bar : Foo['X]).foo //│ int | string +//│ res +//│ = 123 (Bar : Foo['X]).bar //│ ('A & (int | string)) -> ('A | int | string) +//│ res +//│ = [Function: id] (Bar : T1).foo //│ bool | int +//│ res +//│ = 123 let f = (Bar : T1).bar f(true) //│ let f: ('A & (bool | int)) -> ('A | bool | int) //│ bool | int +//│ f +//│ = [Function: id] +//│ res +//│ = true :e module Bar extends T1, Foo[int | string] { @@ -89,23 +108,23 @@ module Bar extends T1, Foo[int | string] { fun bar(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.89: fun bar(x) = x + 1 -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.108: fun bar(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.55: trait T1 extends Foo[int | bool] +//│ ║ l.64: trait T1 extends Foo[int | bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.89: fun bar(x) = x + 1 -//│ ╙── ^ +//│ ║ l.108: fun bar(x) = x + 1 +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.89: fun bar(x) = x + 1 -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.108: fun bar(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `string` is not an instance of type `int` -//│ ║ l.87: module Bar extends T1, Foo[int | string] { -//│ ║ ^^^^^^ +//│ ║ l.106: module Bar extends T1, Foo[int | string] { +//│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.89: fun bar(x) = x + 1 -//│ ╙── ^ +//│ ║ l.108: fun bar(x) = x + 1 +//│ ╙── ^ //│ module Bar extends Foo, T1 { //│ fun bar: int -> int //│ fun foo: 123 @@ -146,16 +165,16 @@ class Final extends Derived1[(int, int)], Derived2 { fun bar([x, y]) = [y, x] } //│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.146: fun bar([x, y]) = [y, x] +//│ ║ l.165: fun bar([x, y]) = [y, x] //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `string` is not an instance of `int` -//│ ║ l.117: trait Derived2 extends Base[(int | string, int | string)] +//│ ║ l.136: trait Derived2 extends Base[(int | string, int | string)] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.144: class Final extends Derived1[(int, int)], Derived2 { +//│ ║ l.163: class Final extends Derived1[(int, int)], Derived2 { //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.146: fun bar([x, y]) = [y, x] +//│ ║ l.165: fun bar([x, y]) = [y, x] //│ ╙── ^ //│ class Final extends Base, Derived1, Derived2 { //│ fun bar: (int, int,) -> (int | string, int | string,) diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 862c7c873d..8c45f673a7 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -1,5 +1,4 @@ :NewDefs -:NoJS // TODO trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd class LitInt(n: int) extends Expr[int] @@ -20,29 +19,35 @@ class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] let l1 = LitInt(1) //│ let l1: LitInt +//│ l1 +//│ = LitInt {} // TODO class Exp[type A] //│ ╔══[PARSE ERROR] Unexpected 'type' keyword here -//│ ║ l.25: class Exp[type A] +//│ ║ l.26: class Exp[type A] //│ ╙── ^^^^ //│ class Exp l1: Expr[int] //│ Expr[int] +//│ res +//│ = LitInt {} :e l1: Expr[bool] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.35: l1: Expr[bool] +//│ ║ l.38: l1: Expr[bool] //│ ║ ^^ //│ ╟── type `int` is not an instance of `bool` -//│ ║ l.5: class LitInt(n: int) extends Expr[int] +//│ ║ l.4: class LitInt(n: int) extends Expr[int] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.35: l1: Expr[bool] +//│ ║ l.38: l1: Expr[bool] //│ ╙── ^^^^ //│ Expr[bool] +//│ res +//│ = LitInt {} // FIXME fun eval[A](e: Expr[A]): A = @@ -51,57 +56,57 @@ fun eval[A](e: Expr[A]): A = e is LitBool(b) then b e is Add(x, y) then eval(x) + eval(y) //│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.50: e is LitInt(n) then n +//│ ║ l.55: e is LitInt(n) then n //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.51: e is LitBool(b) then b +//│ ║ l.56: e is LitBool(b) then b //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.52: e is Add(x, y) then eval(x) + eval(y) +//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Cond[?]` does not match type `Add | LitBool | LitInt | ~#Expr` -//│ ║ l.4: trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd +//│ ║ l.3: trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt | ~#Expr` -//│ ║ l.50: e is LitInt(n) then n +//│ ║ l.55: e is LitInt(n) then n //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.48: fun eval[A](e: Expr[A]): A = +//│ ║ l.53: fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.49: if +//│ ║ l.54: if //│ ║ ^^^^^^^ -//│ ║ l.50: e is LitInt(n) then n +//│ ║ l.55: e is LitInt(n) then n //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.51: e is LitBool(b) then b +//│ ║ l.56: e is LitBool(b) then b //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.52: e is Add(x, y) then eval(x) + eval(y) +//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of `int` -//│ ║ l.6: class LitBool(b: bool) extends Expr[bool] +//│ ║ l.5: class LitBool(b: bool) extends Expr[bool] //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.50: e is LitInt(n) then n +//│ ║ l.55: e is LitInt(n) then n //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.7: class Add(x: Expr[int], y: Expr[int]) extends Expr[int] +//│ ║ l.6: class Add(x: Expr[int], y: Expr[int]) extends Expr[int] //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.48: fun eval[A](e: Expr[A]): A = +//│ ║ l.53: fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.49: if +//│ ║ l.54: if //│ ║ ^^^^^^^ -//│ ║ l.50: e is LitInt(n) then n +//│ ║ l.55: e is LitInt(n) then n //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.51: e is LitBool(b) then b +//│ ║ l.56: e is LitBool(b) then b //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.52: e is Add(x, y) then eval(x) + eval(y) +//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.6: class LitBool(b: bool) extends Expr[bool] +//│ ║ l.5: class LitBool(b: bool) extends Expr[bool] //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `int` -//│ ║ l.50: e is LitInt(n) then n +//│ ║ l.55: e is LitInt(n) then n //│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.52: e is Add(x, y) then eval(x) + eval(y) +//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) //│ ╙── ^^^^^^^ //│ fun eval: (e: Expr[out bool | int],) -> (bool | int) diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index facd8bd5df..5774dd2fce 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -115,7 +115,6 @@ a1.x //│ = 1 -:NoJS // TODO trait Foo[A] { fun foo(x: A): A } @@ -133,12 +132,18 @@ module B extends Foo { fun foo(x) = x } B : Foo['X] //│ Foo['X] +//│ res +//│ = B { class: [class B extends Object] } B.foo //│ 'a -> 'a +//│ res +//│ = [Function: foo] B.foo(1) //│ 1 +//│ res +//│ = 1 module B extends Foo { fun foo(x) = x + 1 } //│ module B extends Foo { @@ -147,16 +152,20 @@ module B extends Foo { fun foo(x) = x + 1 } B : Foo['X] //│ Foo[int] +//│ res +//│ = B { class: [class B extends Object] } B.foo //│ int -> int +//│ res +//│ = [Function: foo] // * TODO: when :pe trait Foo[type A] { fun foo(x: A): A } //│ ╔══[PARSE ERROR] Unexpected 'type' keyword here -//│ ║ l.157: trait Foo[type A] { fun foo(x: A): A } +//│ ║ l.166: trait Foo[type A] { fun foo(x: A): A } //│ ╙── ^^^^ //│ trait Foo { //│ fun foo: (x: A,) -> A @@ -178,14 +187,20 @@ class Bar[B](a: B) extends Foo { fun foo(x) = x } let b = Bar(123) //│ let b: Bar[123] +//│ b +//│ = Bar {} b : Foo['X] //│ Foo['X] //│ where //│ 'X :> 123 +//│ res +//│ = Bar {} b.foo //│ 'a -> (123 | 'a) +//│ res +//│ = [Function: foo] // * Note the shadowed type variable `A` in `foo` @@ -197,17 +212,17 @@ trait Foo[A] { fun foo[A](x: A): A } :e // FIXME class B extends Foo { fun foo(x) = x } //│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.198: class B extends Foo { fun foo(x) = x } +//│ ║ l.213: class B extends Foo { fun foo(x) = x } //│ ║ ^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.198: class B extends Foo { fun foo(x) = x } +//│ ║ l.213: class B extends Foo { fun foo(x) = x } //│ ║ ^ //│ ╟── back into type variable `A` -//│ ║ l.192: trait Foo[A] { fun foo[A](x: A): A } +//│ ║ l.207: trait Foo[A] { fun foo[A](x: A): A } //│ ║ ^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.198: class B extends Foo { fun foo(x) = x } +//│ ║ l.213: class B extends Foo { fun foo(x) = x } //│ ╙── ^ //│ class B extends Foo { //│ fun foo: (??A & 'a) -> (??A0 | 'a) @@ -216,23 +231,23 @@ class B extends Foo { fun foo(x) = x } :e class B extends Foo { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.232: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.192: trait Foo[A] { fun foo[A](x: A): A } +//│ ║ l.207: trait Foo[A] { fun foo[A](x: A): A } //│ ║ ^ //│ ╟── into reference of type `int` -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.232: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^ //│ ╔══[ERROR] Type error in definition of method foo -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.232: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.232: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this operator application: -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.232: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^^^^^ //│ class B extends Foo { //│ fun foo: int -> int diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 12858825a8..1507888e51 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -1,6 +1,5 @@ :NewDefs -:NoJS // TODO trait Test { fun foo: int @@ -26,9 +25,13 @@ module M extends Test { M: Test //│ Test +//│ res +//│ = M { class: [class M extends Object] } ts(M) //│ int +//│ res +//│ = 0 trait Oth extends Test { let a : int @@ -43,36 +46,49 @@ trait Oth extends Test { let oth1: Oth //│ let oth1: Oth +//│ oth1 +//│ = oth1.bar(true) //│ bool +//│ res +//│ = +//│ oth1 is not implemented oth1: Test //│ Test +//│ res +//│ = +//│ oth1 is not implemented :e M : Oth oth1: M //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.54: M : Oth +//│ ║ l.65: M : Oth //│ ║ ^ //│ ╟── reference of type `M` is not an instance of type `Oth` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.54: M : Oth +//│ ║ l.65: M : Oth //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.55: oth1: M +//│ ║ l.66: oth1: M //│ ║ ^^^^ //│ ╟── type `#Oth` is not an instance of type `M` -//│ ║ l.44: let oth1: Oth +//│ ║ l.47: let oth1: Oth //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `M` -//│ ║ l.55: oth1: M +//│ ║ l.66: oth1: M //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.55: oth1: M +//│ ║ l.66: oth1: M //│ ╙── ^ //│ M +//│ res +//│ = M { class: [class M extends Object] } +//│ res +//│ = +//│ oth1 is not implemented trait Geo { let v: 2 | 3 @@ -103,11 +119,11 @@ trait Mixed extends Geo, Anemo //│ } -class C extends Test { +class C() extends Test { fun foo: 1 = 1 fun bar(x) = x } -//│ class C extends Test { +//│ class C() extends Test { //│ fun bar: bool -> bool //│ fun foo: 1 //│ } @@ -119,7 +135,7 @@ mixin M { //│ fun m1: 3 //│ } -class F extends Oth, M, Mixed { +class F() extends Oth, M, Mixed { fun cool(x) = x == 1 fun foo = 2 fun bar(x) = x @@ -128,7 +144,7 @@ class F extends Oth, M, Mixed { let a = 3 let v = 2 } -//│ class F extends Anemo, Geo, Mixed, Oth, Test { +//│ class F() extends Anemo, Geo, Mixed, Oth, Test { //│ let a: 3 //│ fun bar: bool -> bool //│ fun cool: number -> bool @@ -141,76 +157,108 @@ class F extends Oth, M, Mixed { let fi = F() //│ let fi: F +//│ fi +//│ = F {} fi : Oth & Geo //│ Geo & Oth +//│ res +//│ = F {} fi.get //│ true +//│ res +//│ = true fi: Test & Anemo //│ Anemo & Test +//│ res +//│ = F {} let fog: Oth & Mixed //│ let fog: Mixed & Oth +//│ fog +//│ = fog: Test & Anemo //│ Anemo & Test +//│ res +//│ = +//│ fog is not implemented :e fog: F //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.161: fog: F +//│ ║ l.190: fog: F //│ ║ ^^^ //│ ╟── type `Mixed & Oth` is not an instance of type `F` -//│ ║ l.154: let fog: Oth & Mixed +//│ ║ l.178: let fog: Oth & Mixed //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `F` -//│ ║ l.161: fog: F +//│ ║ l.190: fog: F //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.161: fog: F +//│ ║ l.190: fog: F //│ ╙── ^ //│ F +//│ res +//│ = +//│ fog is not implemented let c = C() //│ let c: C +//│ c +//│ = C {} c: Eql //│ Eql[C] +//│ res +//│ = C {} let ct: Test = c //│ let ct: Test +//│ ct +//│ = C {} c.foo //│ 1 +//│ res +//│ = 1 c.bar(true) //│ bool +//│ res +//│ = true // :d c: Test //│ Test +//│ res +//│ = C {} :e c: Oth //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.196: c: Oth +//│ ║ l.240: c: Oth //│ ║ ^ //│ ╟── application of type `C` is not an instance of type `Oth` -//│ ║ l.176: let c = C() +//│ ║ l.208: let c = C() //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#Oth` -//│ ║ l.196: c: Oth +//│ ║ l.240: c: Oth //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.196: c: Oth +//│ ║ l.240: c: Oth //│ ╙── ^^^ //│ Oth +//│ res +//│ = C {} // :d let c1: Test = C() //│ let c1: Test +//│ c1 +//│ = C {} // :d fun fcc(x: C) = x.foo @@ -224,32 +272,41 @@ fun ffm(x: F) = x.get :e fun fee(x: Test) = x: Oth //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.225: fun fee(x: Test) = x: Oth +//│ ║ l.273: fun fee(x: Test) = x: Oth //│ ║ ^ //│ ╟── type `#Test` is not an instance of type `Oth` -//│ ║ l.225: fun fee(x: Test) = x: Oth +//│ ║ l.273: fun fee(x: Test) = x: Oth //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `#Oth` -//│ ║ l.225: fun fee(x: Test) = x: Oth +//│ ║ l.273: fun fee(x: Test) = x: Oth //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.225: fun fee(x: Test) = x: Oth +//│ ║ l.273: fun fee(x: Test) = x: Oth //│ ╙── ^^^ //│ fun fee: (x: Test,) -> Oth fc(c) //│ Test +//│ res +//│ = C {} fun fts['a](x: 'a & Test) = x.foo fts(c) //│ fun fts: forall 'foo. (x: Test & {foo: 'foo} | Test & ~#Test,) -> 'foo //│ 1 +//│ res +//│ = [Function: fts] fts(oth1) //│ int +//│ res +//│ = +//│ oth1 is not implemented fts(c1) //│ int +//│ res +//│ = 1 trait A1 { fun a1: 1 | 2 | 3 } trait A2 { fun a1: 2 | 3 | 4 } @@ -265,19 +322,19 @@ class Ea1 extends A1, A2 { fun a1 = 4 } //│ ╔══[ERROR] Type mismatch in definition of method a1: -//│ ║ l.265: fun a1 = 4 +//│ ║ l.322: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.265: fun a1 = 4 +//│ ║ l.322: fun a1 = 4 //│ ║ ^ //│ ╟── but it flows into definition of method a1 with expected type `1 | 2 | 3` -//│ ║ l.265: fun a1 = 4 +//│ ║ l.322: fun a1 = 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.254: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.311: trait A1 { fun a1: 1 | 2 | 3 } //│ ║ ^^^^^^^^^ //│ ╟── from signature of member `a1`: -//│ ║ l.254: trait A1 { fun a1: 1 | 2 | 3 } +//│ ║ l.311: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1 extends A1, A2 { //│ fun a1: 4 @@ -302,10 +359,10 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `E1` -//│ ║ l.301: class E1 extends Test { +//│ ║ l.358: class E1 extends Test { //│ ║ ^^ //│ ╟── Declared here: -//│ ║ l.7: fun bar: bool -> bool +//│ ║ l.6: fun bar: bool -> bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class E1 extends Test { //│ fun bar: bool -> bool @@ -316,10 +373,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] A trait can only inherit from other traits -//│ ║ l.316: trait TE1 extends C +//│ ║ l.373: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] A trait can only inherit from other traits -//│ ║ l.317: trait TE2 extends M, Test +//│ ║ l.374: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1 extends C, Test //│ trait TE2 extends Test { @@ -333,45 +390,44 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.332: fun foo = true +//│ ║ l.389: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.332: fun foo = true +//│ ║ l.389: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.332: fun foo = true +//│ ║ l.389: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.6: fun foo: int +//│ ║ l.5: fun foo: int //│ ║ ^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.6: fun foo: int +//│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ class E2 extends Test { //│ fun bar: bool -> bool //│ fun foo: true //│ } -// TODO :e class D extends Test[int], Test[bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[int], Test[bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `D` -//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[int], Test[bool] //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.6: fun foo: int +//│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `D` -//│ ║ l.357: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[int], Test[bool] //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.7: fun bar: bool -> bool +//│ ║ l.6: fun bar: bool -> bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class D extends Test { //│ fun bar: bool -> bool @@ -381,23 +437,29 @@ class D extends Test[int], Test[bool] trait Base: A | B -class A extends Base -class B extends Base +class A() extends Base +class B() extends Base //│ trait Base: A | B -//│ class A extends Base -//│ class B extends Base +//│ class A() extends Base +//│ class B() extends Base let b: Base = A() //│ let b: Base +//│ b +//│ = A {} b: Base & (A | B) //│ A & Base | B & Base +//│ res +//│ = A {} if b is A then 0 B then 1 //│ 0 | 1 +//│ res +//│ = 0 fun f(x: Base) = if x is @@ -414,55 +476,72 @@ class Bar[B](f: B => B) extends Base let f: Foo = Foo((1, 2)) //│ let f: Foo[anything] +//│ f +//│ = Foo {} f.aa //│ (??A, ??A,) +//│ res +//│ = [ 1, 2 ] let b: Base = f //│ let b: Base +//│ b +//│ = Foo {} if b is Foo(a) then a else 0 //│ (??A, ??A,) | 0 +//│ res +//│ = [ 1, 2 ] :e // * Note: an error is raised in this case and not above because B is invariant so it can't be widened if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.428: if b is Bar(f) then f else 0 +//│ ║ l.498: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.410: class Bar[B](f: B => B) extends Base +//│ ║ l.472: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ (??B & 'B) -> ('B | ??B0) | 0 +//│ res +//│ = 0 :e if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.438: if b is +//│ ║ l.510: if b is //│ ║ ^^^^ -//│ ║ l.439: Foo(a) then a +//│ ║ l.511: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.440: Bar(f) then f +//│ ║ l.512: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.410: class Bar[B](f: B => B) extends Base +//│ ║ l.472: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything +//│ res +//│ = [ 1, 2 ] :e let tt1 = Test //│ ╔══[ERROR] trait Test cannot be used in term position -//│ ║ l.454: let tt1 = Test +//│ ║ l.528: let tt1 = Test //│ ╙── ^^^^ //│ let tt1: error +//│ tt1 +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'build') :e fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot match on trait `Test` -//│ ║ l.461: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.538: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared trait Geo trait ZL extends Geo @@ -483,6 +562,14 @@ let e: EM //│ let z: ZL //│ let w: WP //│ let e: EM +//│ g +//│ = +//│ z +//│ = +//│ w +//│ = +//│ e +//│ = fun fot(x: EM): Geo = x fun fit(x: EM): WP = x @@ -494,6 +581,19 @@ e: ZL & Geo //│ fun fot: (x: EM,) -> Geo //│ fun fit: (x: EM,) -> WP //│ Geo & ZL +//│ res +//│ = [Function: fot] +//│ res +//│ = [Function: fit] +//│ res +//│ = +//│ w is not implemented +//│ res +//│ = +//│ z is not implemented +//│ res +//│ = +//│ e is not implemented :e fun fto(w: WP): EM = w @@ -501,43 +601,51 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.599: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.599: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.599: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.499: fun fto(w: WP): EM = w +//│ ║ l.599: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.500: z: WP +//│ ║ l.600: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.479: let z: ZL +//│ ║ l.558: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.500: z: WP +//│ ║ l.600: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.500: z: WP +//│ ║ l.600: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.501: g: ZL +//│ ║ l.601: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.478: let g: Geo +//│ ║ l.557: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.501: g: ZL +//│ ║ l.601: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.501: g: ZL +//│ ║ l.601: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP,) -> EM //│ WP & ZL +//│ res +//│ = [Function: fto] +//│ res +//│ = +//│ z is not implemented +//│ res +//│ = +//│ g is not implemented class Bs(a: bool) { fun foo(x) = x + 1 @@ -546,26 +654,34 @@ class Bs(a: bool) { //│ fun foo: int -> int //│ } -class Ih extends Bs(false) { +class Ih() extends Bs(false) { fun bar(x) = x fun foo(x) = 1 } -//│ class Ih extends Bs { +//│ class Ih() extends Bs { //│ fun bar: 'a -> 'a //│ fun foo: anything -> 1 //│ } let ih1 = Ih() //│ let ih1: Ih +//│ ih1 +//│ = Ih {} ih1.foo(1) //│ 1 +//│ res +//│ = 1 ih1: Bs //│ Bs +//│ res +//│ = Ih {} ih1.a //│ false +//│ res +//│ = false :e class Eh2 extends Bs(true), Ele { @@ -573,20 +689,20 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.688: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.688: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.688: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.572: fun foo(x) = x && false +//│ ║ l.688: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.651: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2 extends Bs, Ele { //│ fun ce: (Test & 'a) -> (Oth | 'a) @@ -598,37 +714,37 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.597: class Eh extends Bs(1) +//│ ║ l.713: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.597: class Eh extends Bs(1) +//│ ║ l.713: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.542: class Bs(a: bool) { +//│ ║ l.650: class Bs(a: bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.598: class Eh1 extends Bs +//│ ║ l.714: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.651: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.651: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `int` -//│ ║ l.543: fun foo(x) = x + 1 +//│ ║ l.651: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.6: fun foo: int +//│ ║ l.5: fun foo: int //│ ║ ^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.6: fun foo: int +//│ ║ l.5: fun foo: int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Eh3` -//│ ║ l.599: class Eh3 extends Bs(false), Test +//│ ║ l.715: class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: -//│ ║ l.7: fun bar: bool -> bool +//│ ║ l.6: fun bar: bool -> bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class Eh extends Bs { //│ fun foo: int -> int @@ -661,15 +777,23 @@ class Cx(a: 1 | 2, b: bool) extends Ca(a) let cx1 = Cx(2, true) //│ let cx1: Cx +//│ cx1 +//│ = Cx {} cx1.bar(cx1.b) //│ bool +//│ res +//│ = true cx1: Test //│ Test +//│ res +//│ = Cx {} cx1: Ca //│ Ca +//│ res +//│ = Cx {} class Bc1(foo: int) class Bc2(bar: bool) @@ -683,33 +807,37 @@ class Bc3 { //│ } :e -class Bc12 extends Bc1(1), Bc2(true) +class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.686: class Bc12 extends Bc1(1), Bc2(true) -//│ ╙── ^^^^^^^^^ -//│ class Bc12 extends Bc1, Bc2 +//│ ║ l.810: class Bc12() extends Bc1(1), Bc2(true) +//│ ╙── ^^^^^^^^^ +//│ class Bc12() extends Bc1, Bc2 +//│ Code generation encountered an error: +//│ unexpected parent symbol new class Bc2. -class Bc02 extends Bc1(1:int) { +class Bc02() extends Bc1(1:int) { let foo = 2 } -//│ class Bc02 extends Bc1 { +//│ class Bc02() extends Bc1 { //│ let foo: 2 //│ } Bc02().foo //│ 2 +//│ res +//│ = 2 :e class Bc31(baz: bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.703: class Bc31(baz: bool) extends Bc3 +//│ ║ l.831: class Bc31(baz: bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.677: let baz : int +//│ ║ l.801: let baz : int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.677: let baz : int +//│ ║ l.801: let baz : int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: bool) extends Bc3 @@ -718,11 +846,11 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.718: let foo = true +//│ ║ l.846: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.717: class Bc11 extends Bc1(1) { +//│ ║ l.845: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ class Bc11 extends Bc1 { //│ let foo: true @@ -749,7 +877,7 @@ trait BInt extends Base[int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.749: fun f = error +//│ ║ l.877: fun f = error //│ ╙── ^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -766,47 +894,70 @@ let bi: BInt let bp: BPar[bool] //│ let bi: BInt //│ let bp: BPar[bool] +//│ bi +//│ = +//│ bp +//│ = bp: Base[(int, bool)] //│ Base[(int, bool,)] +//│ res +//│ = +//│ bp is not implemented :e bp: Base[(int, int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.774: bp: Base[(int, int)] +//│ ║ l.909: bp: Base[(int, int)] //│ ║ ^^ //│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.766: let bp: BPar[bool] +//│ ║ l.894: let bp: BPar[bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.774: bp: Base[(int, int)] +//│ ║ l.909: bp: Base[(int, int)] //│ ╙── ^^^ //│ Base[(int, int,)] +//│ res +//│ = +//│ bp is not implemented bi.f(1) //│ nothing +//│ res +//│ = +//│ bi is not implemented bp.f //│ ((int, bool,) & 'A) -> ((int, bool,) | 'A) +//│ res +//│ = +//│ bp is not implemented fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) //│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) fb(bp, false) //│ (int, bool,) +//│ res +//│ = +//│ bp is not implemented -class CP extends BPar[int] { +class CP() extends BPar[int] { fun f(x) = (x._2, x._1) } -//│ class CP extends BPar, Base { +//│ class CP() extends BPar, Base { //│ fun f: {_1: int, _2: int} -> (int, int,) //│ } let cp1 = CP() //│ let cp1: CP +//│ cp1 +//│ = CP {} fb(cp1, 2) //│ (int, int,) +//│ res +//│ = [ undefined, undefined ] trait BInfer1 extends Base //│ trait BInfer1 extends Base { @@ -823,13 +974,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[int, int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.824: class DerBad1 extends Base[int, int] +//│ ║ l.975: class DerBad1 extends Base[int, int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `DerBad1` -//│ ║ l.824: class DerBad1 extends Base[int, int] +//│ ║ l.975: class DerBad1 extends Base[int, int] //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.732: trait Base[A] { fun f: A -> A } +//│ ║ l.860: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^ //│ class DerBad1 extends Base { //│ fun f: 'A -> 'A @@ -840,28 +991,28 @@ class DerBad1 extends Base[int, int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.841: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) @@ -880,26 +1031,40 @@ class K[A](k: Ta[A]) let ta1: Ta[int] //│ let ta1: Ta[int] +//│ ta1 +//│ = let k1 = K(ta1) //│ let k1: K[int] +//│ k1 +//│ = +//│ ta1 is not implemented k1.k : Ta[int] //│ Ta[int] +//│ res +//│ = +//│ k1 and ta1 are not implemented k1.k.g //│ int +//│ res +//│ = +//│ k1 and ta1 are not implemented k1.k.p //│ bool +//│ res +//│ = +//│ k1 and ta1 are not implemented :e trait Tb extends Ta[int] { let p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.898: let p = false -//│ ╙── ^^^^^^^^^ +//│ ║ l.1063: let p = false +//│ ╙── ^^^^^^^^^ //│ trait Tb extends Ta { //│ let g: 'T //│ let p: false @@ -932,15 +1097,15 @@ trait Oz { :e class Fischl(age: bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.933: class Fischl(age: bool) extends Oz -//│ ║ ^^^^ +//│ ║ l.1098: class Fischl(age: bool) extends Oz +//│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.926: let age: int -//│ ║ ^^^ +//│ ║ l.1091: let age: int +//│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.926: let age: int -//│ ╙── ^^^^^^^^ +//│ ║ l.1091: let age: int +//│ ╙── ^^^^^^^^ //│ class Fischl(age: bool) extends Oz class Klee(age: 1 | 2 | 3) extends Oz @@ -958,21 +1123,21 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.958: fun foo(x) = x && true -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.1123: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `int & ??_` is not an instance of type `bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.958: fun foo(x) = x && true -//│ ╙── ^ +//│ ║ l.1123: fun foo(x) = x && true +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.958: fun foo(x) = x && true -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.1123: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.958: fun foo(x) = x && true -//│ ║ ^^^^^^^^^ +//│ ║ l.1123: fun foo(x) = x && true +//│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.950: fun foo(x) = x + 1 -//│ ╙── ^^^^^ +//│ ║ l.1115: fun foo(x) = x + 1 +//│ ╙── ^^^^^ //│ class Go extends Fate { //│ fun foo: bool -> bool //│ } @@ -988,12 +1153,12 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.989: class Ohhh(x: bool) extends Ha -//│ ║ ^^^^ +//│ ║ l.1154: class Ohhh(x: bool) extends Ha +//│ ║ ^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.980: class Ha { let x: int = 1 } -//│ ╙── ^^^ +//│ ║ l.1145: class Ha { let x: int = 1 } +//│ ╙── ^^^ //│ class Ohhh(x: bool) extends Ha trait TA[A] { let a : A } @@ -1009,12 +1174,20 @@ class G2[T](x: T) extends G1[T, int](x, 1) let g21 = G2(false) //│ let g21: G2[false] +//│ g21 +//│ = G2 {} g21: G1[bool, int] //│ G1[bool, int] +//│ res +//│ = G2 {} g21.a //│ bool +//│ res +//│ = false g21: TA[bool] //│ TA[bool] +//│ res +//│ = G2 {} diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index b4184b1b96..c9e3f2c169 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -1,5 +1,4 @@ :NewDefs -:NoJS // TODO @@ -7,28 +6,37 @@ class Foo() 123 //│ class Foo() //│ 123 +//│ res +//│ = 123 Foo //│ () -> Foo +//│ res +//│ = [Function (anonymous)] { class: [class Foo] } // TODO fun fooo(x) = class C(y, z) C(0, x) //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.16: class C(y, z) +//│ ║ l.19: class C(y, z) //│ ╙── ^ //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.16: class C(y, z) +//│ ║ l.19: class C(y, z) //│ ╙── ^ //│ fun fooo: error -> C +:ge // FIXME; + re-enable JS in tests below fun foo = bar fun bar = foo //│ fun foo: nothing //│ fun bar: nothing +//│ Code generation encountered an error: +//│ unresolved symbol bar + +:NoJS // TODO foo(bar) //│ nothing @@ -47,7 +55,6 @@ fun bar = {y: foo} //│ where //│ 'foo :> {x: {y: 'foo}} -// FIXME pretty-printing? foo //│ forall 'foo. 'foo //│ where @@ -134,7 +141,7 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.134: fun b = Test1_1.a +//│ ║ l.141: fun b = Test1_1.a //│ ╙── ^^ //│ module Test1_1 { //│ fun a: error @@ -155,7 +162,7 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.155: fun b = Test1_1().a +//│ ║ l.162: fun b = Test1_1().a //│ ╙── ^^ //│ class Test1_1 { //│ fun a: error @@ -165,7 +172,7 @@ class Test1_2 { //│ } -// TODO check TV hygiene +:e module Test2_1 { fun t2 = Test2_2 fun a = Test2_2.b @@ -178,7 +185,7 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.177: fun c = Test2_1.a +//│ ║ l.184: fun c = Test2_1.a //│ ╙── ^^ //│ module Test2_1 { //│ fun a: 123 | error @@ -198,14 +205,50 @@ Test2_1.t2.b Test2_1.a //│ 123 | error -// FIXME Test2_1.d //│ error Test2_1.n //│ 456 -// TODO leverage type annotation to find type +module Test2_1 { + fun t2 = Test2_2 + fun a: int + fun a = Test2_2.b + fun d = Test2_2.e + fun n: int + fun n = 456 +} +module Test2_2 { + fun b = 123 + fun c = Test2_1.a + fun e = Test2_1.n +} +//│ module Test2_1 { +//│ fun a: int +//│ fun d: int +//│ fun n: int +//│ fun t2: Test2_2 +//│ } +//│ module Test2_2 { +//│ fun b: 123 +//│ fun c: int +//│ fun e: int +//│ } + +Test2_1.t2.b +//│ 123 + +Test2_1.a +//│ int + +Test2_1.d +//│ int + +Test2_1.n +//│ int + + class Test2(n: int) { fun inc = Test3.inc(this) } diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls index 4ea5616380..ce4094559a 100644 --- a/shared/src/test/diff/nu/ParamImplementing.mls +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -1,7 +1,5 @@ :NewDefs -:NoJS // TODO - trait T { fun x: int } mixin M(x: bool) @@ -13,14 +11,14 @@ mixin M(x: bool) :e class C extends T, M(false) //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.14: class C extends T, M(false) +//│ ║ l.12: class C extends T, M(false) //│ ║ ^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.6: trait T { fun x: int } +//│ ║ l.4: trait T { fun x: int } //│ ║ ^^^ //│ ╟── from signature of member `x`: -//│ ║ l.6: trait T { fun x: int } +//│ ║ l.4: trait T { fun x: int } //│ ╙── ^^^^^^ //│ class C extends T diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index 34f27b9634..3d9478c9b0 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -1,5 +1,5 @@ :NewDefs -:NoJS // TODO + trait Foo[A] { fun x: A } @@ -13,17 +13,21 @@ trait Base1: Foo (b: Base1) => b.x //│ (b: Base1,) -> ??A +//│ res +//│ = [Function: res] (b: Base1) => b : Foo //│ (b: Base1,) -> #Foo +//│ res +//│ = [Function: res] :e (b: Base1) => b : Foo['X] //│ ╔══[ERROR] Type error in type ascription -//│ ║ l.21: (b: Base1) => b : Foo['X] +//│ ║ l.25: (b: Base1) => b : Foo['X] //│ ║ ^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.21: (b: Base1) => b : Foo['X] +//│ ║ l.25: (b: Base1) => b : Foo['X] //│ ║ ^^ //│ ╟── back into type variable `A` //│ ║ l.5: trait Foo[A] { fun x: A } @@ -32,17 +36,21 @@ trait Base1: Foo //│ where //│ 'X :> ??A //│ <: ??A0 +//│ res +//│ = [Function: res] :e 1 : Foo[int] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.37: 1 : Foo[int] +//│ ║ l.43: 1 : Foo[int] //│ ║ ^ //│ ╟── integer literal of type `1` is not an instance of type `Foo` //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.37: 1 : Foo[int] +//│ ║ l.43: 1 : Foo[int] //│ ╙── ^^^^^^^^ //│ Foo[int] +//│ res +//│ = 1 trait Base1: Foo { val x: int } @@ -52,6 +60,8 @@ trait Base1: Foo { val x: int } (b: Base1) => b.x //│ (b: Base1,) -> (int & ??A) +//│ res +//│ = [Function: res] trait Base1: Foo[1 | 2] { val x: 0 | 1 } @@ -61,6 +71,8 @@ trait Base1: Foo[1 | 2] { val x: 0 | 1 } (b: Base1) => b.x //│ (b: Base1,) -> 1 +//│ res +//│ = [Function: res] trait Base2: Foo['FigureItOut] @@ -68,9 +80,13 @@ trait Base2: Foo['FigureItOut] (b: Base2) => b.x //│ (b: Base2,) -> ??FigureItOut +//│ res +//│ = [Function: res] (b: Base1) => b : Foo //│ (b: Base1,) -> #Foo +//│ res +//│ = [Function: res] // :e (b: Base2) => b : Foo['X] @@ -78,6 +94,8 @@ trait Base2: Foo['FigureItOut] //│ where //│ 'X :> ??FigureItOut //│ <: ??FigureItOut0 +//│ res +//│ = [Function: res] // TODO reject @@ -86,44 +104,54 @@ class Impl extends Base2 (x: Impl) => x : Base2 //│ (x: Impl,) -> Base2 +//│ res +//│ = [Function: res] :e -class Impl extends Base2, Foo +class Impl() extends Base2, Foo //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `Impl` -//│ ║ l.91: class Impl extends Base2, Foo -//│ ║ ^^^^ +//│ ║ l.111: class Impl() extends Base2, Foo +//│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.5: trait Foo[A] { fun x: A } //│ ╙── ^^^^ -//│ class Impl extends Base2, Foo { +//│ class Impl() extends Base2, Foo { //│ fun x: 'A //│ } -class Impl extends Base2, Foo { +class Impl() extends Base2, Foo { fun x = 1 } -//│ class Impl extends Base2, Foo { +//│ class Impl() extends Base2, Foo { //│ fun x: 1 //│ } Impl().x //│ 1 +//│ res +//│ = 1 Impl() : Base2 //│ Base2 +//│ res +//│ = Impl {} (Impl() : Base2).x //│ ??FigureItOut +//│ res +//│ = 1 -class Impl2 extends Base2, Foo[int] { +class Impl2() extends Base2, Foo[int] { fun x = 1 } -//│ class Impl2 extends Base2, Foo { +//│ class Impl2() extends Base2, Foo { //│ fun x: 1 //│ } (Impl2() : Base2).x //│ ??FigureItOut +//│ res +//│ = 1 @@ -136,6 +164,8 @@ trait Test2[A]: Test1[(A, A)] (t: Test2[int]) => t.x //│ (t: Test2[int],) -> (int, int,) +//│ res +//│ = [Function: res] diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index 357efff342..c0a657ee9a 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -1,6 +1,5 @@ :NewDefs -:NoJS // TODO trait T1[A] { @@ -26,15 +25,23 @@ class C1 extends T1['FigureItOut] { let c1 = new C1 //│ let c1: C1 +//│ c1 +//│ = C1 {} c1.f //│ (x: int,) -> int +//│ res +//│ = [Function: f] (c1 : T1).f //│ (??A & 'A) -> ('A | ??A0) +//│ res +//│ = [Function: f] (c1 : T1['X]).f //│ int -> int +//│ res +//│ = [Function: f] :ns (c1 : T1).f @@ -42,6 +49,8 @@ c1.f //│ where //│ 'f :> 'A -> 'A //│ 'A := in ??A out ??A0 +//│ res +//│ = [Function: f] :ns (c1 : T1['X]).f @@ -53,6 +62,8 @@ c1.f //│ <: 'FigureItOut //│ 'FigureItOut :> int //│ <: 'X & int +//│ res +//│ = [Function: f] @@ -67,23 +78,23 @@ class C2 extends T2['FigureItOut] { fun f(x: int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.64: val r = C2().f(false) +//│ ║ l.75: val r = C2().f(false) //│ ╙── ^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.62: trait T2[A] { +//│ ║ l.73: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.63: fun f: A -> A +//│ ║ l.74: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.64: val r = C2().f(false) +//│ ║ l.75: val r = C2().f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.64: val r = C2().f(false) +//│ ║ l.75: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.64: val r = C2().f(false) +//│ ║ l.75: val r = C2().f(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.67: fun f(x: int) = x +//│ ║ l.78: fun f(x: int) = x //│ ╙── ^^^ //│ trait T2[A] { //│ fun f: A -> A @@ -102,18 +113,18 @@ class C2 extends T2['FigureItOut] { fun f(x: int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.99: val r = (C2() : T2['X]).f(false) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.110: val r = (C2() : T2['X]).f(false) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.97: trait T2[A] { -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.98: fun f: A -> A -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.99: val r = (C2() : T2['X]).f(false) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.108: trait T2[A] { +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.109: fun f: A -> A +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.110: val r = (C2() : T2['X]).f(false) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.97: trait T2[A] { -//│ ╙── ^ +//│ ║ l.108: trait T2[A] { +//│ ╙── ^ //│ trait T2[A] { //│ fun f: A -> A //│ let r: error | false @@ -125,10 +136,13 @@ class C2 extends T2['FigureItOut] { :e // FIXME C2() : T2['X] //│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.97: trait T2[A] { -//│ ╙── ^ +//│ ║ l.108: trait T2[A] { +//│ ╙── ^ //│ T2['X] //│ where //│ 'X :> error +//│ res +//│ Runtime error: +//│ TypeError: Class constructor C2 cannot be invoked without 'new' From 7e04047c5f5807863a2da39b5c0b37183e7abafc Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Tue, 6 Jun 2023 00:11:37 +0800 Subject: [PATCH 347/498] Fix top-level mutually-recursive functions (#167) --- .../src/main/scala/mlscript/JSBackend.scala | 14 ++++- shared/src/test/diff/nu/MutualRec.mls | 55 ++++++++++++++++--- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 75d220c62e..d72d63b27e 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -1330,6 +1330,15 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { (zeroWidthSpace + JSIdent("e") + zeroWidthSpace).log() :: Nil ) + otherStmts.foreach { + case fd @ NuFunDef(isLetRec, Var(nme), _, L(body)) if (isLetRec.isEmpty || isLetRec.getOrElse(false)) => + val isByname = isLetRec.isEmpty + val isByvalueRecIn = if (isByname) None else Some(true) + val bodyIsLam = body match { case _: Lam => true case _ => false } + scope.declareValue(nme, isByvalueRecIn, bodyIsLam) + case _ => () + } + // Generate statements. val queries = otherStmts.map { case NuFunDef(isLetRec, nme @ Var(name), tys, rhs @ L(body)) => @@ -1338,7 +1347,10 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { val bodyIsLam = body match { case _: Lam => true case _ => false } (if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) - val sym = scope.declareValue(name, isByvalueRecIn, bodyIsLam) + val sym = scope.resolveValue(name) match { + case Some(s: ValueSymbol) => s + case _ => scope.declareValue(name, isByvalueRecIn, bodyIsLam) + } try { val translated = translateTerm(body) scope.unregisterSymbol(sym) diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index c9e3f2c169..90131a0398 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -28,18 +28,17 @@ fun fooo(x) = -:ge // FIXME; + re-enable JS in tests below fun foo = bar fun bar = foo //│ fun foo: nothing //│ fun bar: nothing -//│ Code generation encountered an error: -//│ unresolved symbol bar - -:NoJS // TODO +:re foo(bar) //│ nothing +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded fun foo = {x: foo} @@ -55,26 +54,42 @@ fun bar = {y: foo} //│ where //│ 'foo :> {x: {y: 'foo}} +:re foo //│ forall 'foo. 'foo //│ where //│ 'foo :> {x: {y: 'foo}} +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded :ns +:re foo //│ forall 'foo. {x: {y: 'foo}} //│ where //│ 'foo :> {x: {y: 'foo}} +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded +:re foo.x //│ 'x //│ where //│ 'x :> {y: {x: 'x}} +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded +:re foo.x.y //│ 'foo //│ where //│ 'foo :> {x: {y: 'foo}} +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded fun foo(a) = {h: a, t: bar(a)} @@ -91,6 +106,8 @@ foo //│ 'c :> {h: 'a, t: 'c} //│ 'a <: 'b //│ 'b <: 'a +//│ res +//│ = [Function: foo3] fun foo(a) = {h1: a, t1: bar(a)} @@ -118,6 +135,8 @@ module Test0_2 { Test0_1.a //│ 123 +//│ res +//│ = 123 class Test0_1 { fun a = Test0_2().b @@ -141,7 +160,7 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.141: fun b = Test1_1.a +//│ ║ l.160: fun b = Test1_1.a //│ ╙── ^^ //│ module Test1_1 { //│ fun a: error @@ -150,8 +169,12 @@ module Test1_2 { //│ fun b: error //│ } +:re Test1_1.a //│ error +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded :e @@ -162,7 +185,7 @@ class Test1_2 { fun b = Test1_1().a } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.162: fun b = Test1_1().a +//│ ║ l.185: fun b = Test1_1().a //│ ╙── ^^ //│ class Test1_1 { //│ fun a: error @@ -185,7 +208,7 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.184: fun c = Test2_1.a +//│ ║ l.207: fun c = Test2_1.a //│ ╙── ^^ //│ module Test2_1 { //│ fun a: 123 | error @@ -201,15 +224,23 @@ module Test2_2 { Test2_1.t2.b //│ 123 +//│ res +//│ = 123 Test2_1.a //│ 123 | error +//│ res +//│ = 123 Test2_1.d //│ error +//│ res +//│ = 456 Test2_1.n //│ 456 +//│ res +//│ = 456 module Test2_1 { fun t2 = Test2_2 @@ -238,15 +269,23 @@ module Test2_2 { Test2_1.t2.b //│ 123 +//│ res +//│ = 123 Test2_1.a //│ int +//│ res +//│ = 123 Test2_1.d //│ int +//│ res +//│ = 456 Test2_1.n //│ int +//│ res +//│ = 456 class Test2(n: int) { From 8c4ce9de6a2280ade3071bb8b765f44d9273c2b8 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 6 Jun 2023 14:03:38 +0800 Subject: [PATCH 348/498] New primitive types (#168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Name primitive types with capital letters, e.g. `Int` instead of `int`. * Cleanly separate old-defs primitive types from new-defs ones – the former no longer mention `Eql` and the latter are now properly defined and typed in the initial context. * Make pattern matching require the scrutinee to be `Object` to recover theorems for free from parametric polymorphism. * In new-defs, emove `unit` and use `undefined` instead, consistent with JS semantics. * Make `Eql` a trait, which makes much more sense, especially since it's magic and has no runtime counterpart. --- .../scala/mlscript/ConstraintSolver.scala | 22 +- .../src/main/scala/mlscript/NormalForms.scala | 4 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 27 +- shared/src/main/scala/mlscript/TypeDefs.scala | 20 +- shared/src/main/scala/mlscript/Typer.scala | 99 +++-- .../main/scala/mlscript/TyperDatatypes.scala | 1 + .../main/scala/mlscript/TyperHelpers.scala | 19 +- shared/src/main/scala/mlscript/helpers.scala | 14 +- shared/src/main/scala/mlscript/syntax.scala | 5 +- .../main/scala/mlscript/utils/package.scala | 12 +- shared/src/test/diff/basics/Simplesub1.fun | 10 +- .../src/test/diff/codegen/ConstructorStmt.mls | 30 +- .../src/test/diff/codegen/FieldOverride.mls | 22 +- .../test/diff/codegen/IndirectRecursion.mls | 2 +- shared/src/test/diff/codegen/Inheritance.mls | 10 +- shared/src/test/diff/codegen/Mixin.mls | 79 ++-- shared/src/test/diff/codegen/Nested.mls | 144 +++---- shared/src/test/diff/codegen/NuClasses.mls | 36 +- shared/src/test/diff/codegen/NuFuns.mls | 37 +- .../src/test/diff/codegen/OptionalParam.mls | 60 +-- shared/src/test/diff/codegen/Shadowing.mls | 2 +- shared/src/test/diff/codegen/Super.mls | 2 +- shared/src/test/diff/codegen/TraitMethods.mls | 1 - .../src/test/diff/contys/AbstractBounds.mls | 2 +- .../test/diff/ecoop23/ExpressionProblem.mls | 78 ++-- shared/src/test/diff/ecoop23/Intro.mls | 40 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 96 ++--- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 256 ++++++------ shared/src/test/diff/fcp-lit/CPS_LB.mls | 2 +- shared/src/test/diff/fcp-lit/MLF.mls | 6 +- shared/src/test/diff/fcp-lit/PolyML.mls | 2 +- shared/src/test/diff/fcp-lit/PolyML2.mls | 6 +- shared/src/test/diff/fcp-lit/QML.mls | 4 +- shared/src/test/diff/fcp/Church_CT.mls | 154 ++++---- shared/src/test/diff/fcp/Church_ST.mls | 22 +- .../src/test/diff/fcp/ConstrainedTypes1.mls | 2 +- .../src/test/diff/fcp/ConstrainedTypes2.mls | 12 +- shared/src/test/diff/fcp/FCPTony.mls | 10 +- shared/src/test/diff/fcp/FunnyId.mls | 12 +- shared/src/test/diff/fcp/MoreChurch.mls | 10 +- shared/src/test/diff/fcp/NestedDataTypes.mls | 4 +- shared/src/test/diff/fcp/Proofs.mls | 2 +- .../test/diff/fcp/QML_exist_Classes_CT.mls | 108 +++--- .../test/diff/fcp/QML_exist_Classes_ST.mls | 48 +-- .../src/test/diff/fcp/QML_exist_Records.mls | 12 +- shared/src/test/diff/fcp/SystemF.mls | 2 +- shared/src/test/diff/fcp/SystemF_2.mls | 142 +++---- .../src/test/diff/fcp/ToChurchSimplif_CT.mls | 12 +- .../src/test/diff/fcp/ToChurchSimplif_ST.mls | 10 +- shared/src/test/diff/fcp/Vec.mls | 2 +- shared/src/test/diff/gadt/Exp1.mls | 8 +- shared/src/test/diff/gadt/Exp2.mls | 12 +- shared/src/test/diff/gadt/ThisMatching.mls | 44 +-- .../diff/mlf-examples/ex_casparticuliers.mls | 36 +- shared/src/test/diff/mlf-examples/ex_demo.mls | 72 ++-- .../src/test/diff/mlf-examples/ex_hashtbl.mls | 30 +- .../test/diff/mlf-examples/ex_predicative.mls | 24 +- .../test/diff/mlf-examples/ex_propagate.mls | 2 +- .../src/test/diff/mlf-examples/ex_selfapp.mls | 4 +- .../src/test/diff/mlf-examples/ex_shallow.mls | 10 +- .../test/diff/mlf-examples/ex_validate.mls | 2 +- shared/src/test/diff/mlscript/Addable.mls | 88 ++--- shared/src/test/diff/mlscript/Arrays.mls | 4 +- shared/src/test/diff/mlscript/Baber.mls | 8 +- shared/src/test/diff/mlscript/David.mls | 6 +- shared/src/test/diff/mlscript/David2.mls | 50 +-- shared/src/test/diff/mlscript/ExprProb.mls | 78 ++-- shared/src/test/diff/mlscript/ExprProb2.mls | 4 +- .../src/test/diff/mlscript/ExprProb_Inv.mls | 76 ++-- .../test/diff/mlscript/FunnySubsumptions.mls | 8 +- shared/src/test/diff/mlscript/MatchBool.mls | 4 +- shared/src/test/diff/mlscript/Methods2.mls | 4 +- shared/src/test/diff/mlscript/Misc.mls | 28 +- .../test/diff/mlscript/NestedClassArgs.mls | 18 +- .../diff/mlscript/PolyVariantCodeReuse.mls | 138 +++---- .../src/test/diff/mlscript/RecursiveTypes.mls | 24 +- .../test/diff/mlscript/RecursiveTypes2.mls | 6 +- shared/src/test/diff/mlscript/SelfNeg.mls | 8 +- shared/src/test/diff/mlscript/SelfNegs.mls | 2 +- shared/src/test/diff/mlscript/Stress.mls | 16 +- shared/src/test/diff/mlscript/StressDNF.mls | 10 +- .../src/test/diff/mlscript/StressTraits.mls | 30 +- shared/src/test/diff/mlscript/StressUgly.mls | 2 +- shared/src/test/diff/mlscript/Tony.mls | 2 +- .../test/diff/mlscript/TrickyExtrusion.mls | 12 +- shared/src/test/diff/mlscript/Trio.mls | 8 +- shared/src/test/diff/mlscript/TypeClasses.mls | 14 +- shared/src/test/diff/mlscript/TypeTags.mls | 5 +- .../test/diff/mlscript/Variant-sub-ad-hoc.mls | 4 +- shared/src/test/diff/mlscript/Variant-sub.mls | 4 +- shared/src/test/diff/mlscript/Yicong.mls | 4 +- shared/src/test/diff/mlscript/i56.mls | 8 +- shared/src/test/diff/nu/AbstractClasses.mls | 62 +-- shared/src/test/diff/nu/Ascription.mls | 28 +- shared/src/test/diff/nu/BadAliases.mls | 30 +- shared/src/test/diff/nu/BadClassInherit.mls | 58 +-- shared/src/test/diff/nu/BadClasses.mls | 24 +- shared/src/test/diff/nu/BadScopes.mls | 12 +- shared/src/test/diff/nu/BadSignatures.mls | 38 +- shared/src/test/diff/nu/BadUCS.mls | 2 +- .../test/diff/nu/BasicClassInheritance.mls | 18 +- shared/src/test/diff/nu/BasicClasses.mls | 66 ++-- shared/src/test/diff/nu/BasicMixins.mls | 101 +++-- shared/src/test/diff/nu/ClassField.mls | 16 +- shared/src/test/diff/nu/ClassSignatures.mls | 60 ++- shared/src/test/diff/nu/ClassesInMixins.mls | 18 +- shared/src/test/diff/nu/CtorStatements.mls | 2 +- shared/src/test/diff/nu/Dates.mls | 12 +- shared/src/test/diff/nu/Declarations.mls | 36 +- shared/src/test/diff/nu/DiamondInherit.mls | 58 +-- shared/src/test/diff/nu/EncodedLists.mls | 6 +- shared/src/test/diff/nu/Eql.mls | 127 +++--- shared/src/test/diff/nu/EqlClasses.mls | 34 +- shared/src/test/diff/nu/EvalNegNeg.mls | 28 +- shared/src/test/diff/nu/ExplicitVariance.mls | 76 ++-- .../test/diff/nu/ExpressionProblem_repro.mls | 54 +-- .../test/diff/nu/ExpressionProblem_small.mls | 24 +- shared/src/test/diff/nu/FieldRefinement.mls | 14 +- shared/src/test/diff/nu/FilterMap.mls | 38 +- shared/src/test/diff/nu/FunPatterns.mls | 14 +- shared/src/test/diff/nu/FunPoly.mls | 12 +- shared/src/test/diff/nu/FunSigs.mls | 18 +- shared/src/test/diff/nu/GADTMono.mls | 70 ++-- .../test/diff/nu/GenericClassInheritance.mls | 86 ++-- shared/src/test/diff/nu/GenericClasses.mls | 40 +- shared/src/test/diff/nu/GenericMethods.mls | 12 +- shared/src/test/diff/nu/GenericMixins.mls | 50 +-- shared/src/test/diff/nu/GenericModules.mls | 12 +- shared/src/test/diff/nu/Huawei1.mls | 8 +- .../src/test/diff/nu/ImplicitMethodPolym.mls | 8 +- .../diff/nu/InferredInheritanceTypeArgs.mls | 70 ++-- .../diff/nu/InheritanceLevelMismatches.mls | 6 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 66 ++-- shared/src/test/diff/nu/InterfaceMono.mls | 186 ++++----- shared/src/test/diff/nu/Interfaces.mls | 367 +++++++++--------- shared/src/test/diff/nu/LetRec.mls | 10 +- shared/src/test/diff/nu/ListConsNil.mls | 8 +- shared/src/test/diff/nu/LitMatch.mls | 39 ++ shared/src/test/diff/nu/LocalLets.mls | 4 +- shared/src/test/diff/nu/MemberConfusion.mls | 38 +- .../src/test/diff/nu/MemberIntersections.mls | 36 +- shared/src/test/diff/nu/MetaWrap.mls | 28 +- shared/src/test/diff/nu/MethodSignatures.mls | 24 +- shared/src/test/diff/nu/Misc.mls | 28 +- shared/src/test/diff/nu/MixinParameters.mls | 6 +- shared/src/test/diff/nu/ModuleParameters.mls | 12 +- shared/src/test/diff/nu/Mut.mls | 37 +- shared/src/test/diff/nu/MutualRec.mls | 24 +- shared/src/test/diff/nu/NamedArgs.mls | 4 +- shared/src/test/diff/nu/New.mls | 16 +- shared/src/test/diff/nu/NewNew.mls | 28 +- shared/src/test/diff/nu/NuScratch.mls | 1 + shared/src/test/diff/nu/Numbers.mls | 59 ++- shared/src/test/diff/nu/Object.mls | 143 +++++++ shared/src/test/diff/nu/OverrideShorthand.mls | 12 +- shared/src/test/diff/nu/ParamImplementing.mls | 25 +- shared/src/test/diff/nu/ParamOverride.mls | 62 +-- shared/src/test/diff/nu/ParamOverriding.mls | 12 +- shared/src/test/diff/nu/ParamPassing.mls | 24 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 109 +++--- .../test/diff/nu/RawUnionTraitSignatures.mls | 20 +- shared/src/test/diff/nu/SelfRec.mls | 18 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 10 +- .../src/test/diff/nu/ThisRefinedClasses.mls | 14 +- shared/src/test/diff/nu/TraitParameters.mls | 4 +- .../test/diff/nu/TrickyGenericInheritance.mls | 62 +-- shared/src/test/diff/nu/TypeAliases.mls | 26 +- shared/src/test/diff/nu/TypeSelections.mls | 12 +- shared/src/test/diff/nu/TypeVariables.mls | 8 +- shared/src/test/diff/nu/Uninstantiable.mls | 28 ++ shared/src/test/diff/nu/Vals.mls | 4 +- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 24 +- shared/src/test/diff/tapl/NuSimplyTyped.mls | 66 ++-- shared/src/test/diff/tapl/NuUntyped.mls | 104 ++--- shared/src/test/diff/tapl/Untyped.mls | 18 +- shared/src/test/diff/typegen/TypegenTerms.mls | 4 +- shared/src/test/diff/ucs/DirectLines.mls | 2 +- shared/src/test/diff/ucs/ElseIf.mls | 98 ++--- shared/src/test/diff/ucs/Exhaustiveness.mls | 2 +- shared/src/test/diff/ucs/Hygiene.mls | 2 +- shared/src/test/diff/ucs/HygienicBindings.mls | 8 +- shared/src/test/diff/ucs/JSON.mls | 120 +++--- shared/src/test/diff/ucs/LeadingAnd.mls | 2 +- shared/src/test/diff/ucs/MultiwayIf.mls | 49 ++- shared/src/test/diff/ucs/NestedBranches.mls | 30 +- .../src/test/diff/ucs/PlainConditionals.mls | 10 +- shared/src/test/diff/ucs/SimpleUCS.mls | 2 +- shared/src/test/diff/ucs/SplitAroundOp.mls | 2 +- shared/src/test/diff/ucs/Tree.mls | 12 +- shared/src/test/diff/ucs/WeirdIf.mls | 61 ++- shared/src/test/diff/ucs/Wildcard.mls | 38 +- shared/src/test/diff/ucs/zipWith.mls | 12 +- .../src/test/scala/mlscript/DiffTests.scala | 20 +- 193 files changed, 3416 insertions(+), 2963 deletions(-) create mode 100644 shared/src/test/diff/nu/LitMatch.mls create mode 100644 shared/src/test/diff/nu/Object.mls create mode 100644 shared/src/test/diff/nu/Uninstantiable.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 064786b946..f8298a1b9b 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -613,20 +613,18 @@ class ConstraintSolver extends NormalForms { self: Typer => rec(f0, f1, true) case (LhsRefined(S(f: FunctionType), ts, r, trs), RhsBases(pts, _, _)) => annoying(Nil, LhsRefined(N, ts, r, trs), Nil, done_rs) - + + // * Note: We could avoid the need for this rule by adding `Eql` to *all* class tag parent sets, + // * but I chose not to for performance reasons (better keep parent sets small). + case (LhsRefined(S(ct: ClassTag), ts, r, trs0), + RhsBases(ots, _, trs)) if EqlTag in ots => + println(s"OK ~ magic Eql ~") + // * These deal with the implicit Eql type member in primitive types. // * (Originally I added this to all such types, - // * but it requires not expanding primitive type refs + // * but it requires not expanding primitive type refs, // * which causes regressions in simplification // * because we don't yet simplify unexpanded type refs...) - case (LhsRefined(S(ct @ ClassTag(Var(nme @ ("int" | "number" | "string" | "bool")), _)), ts, r, trs0), - RhsBases(ots, S(R(RhsField(Var("Eql#A"), fldTy))), trs)) => - nme match { - case "int" | "number" => rec(fldTy.lb.getOrElse(TopType), DecType, false) - case "string" => rec(fldTy.lb.getOrElse(TopType), StrType, false) - case "bool" => rec(fldTy.lb.getOrElse(TopType), BoolType, false) - case _ => die - } case (LhsRefined(S(ct @ ClassTag(lit: Lit, _)), ts, r, trs0), RhsBases(ots, S(R(RhsField(Var("Eql#A"), fldTy))), trs)) => lit match { @@ -638,7 +636,7 @@ class ConstraintSolver extends NormalForms { self: Typer => // * This deals with the implicit Eql type member for user-defined classes. case (LhsRefined(S(ClassTag(Var(nme), _)), ts, r, trs0), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) - if ctx.tyDefs2.contains(nme) => if (newDefs && fldNme.name === "Eql#A") { + if ctx.tyDefs2.contains(nme) => if (newDefs && nme =/= "Eql" && fldNme.name === "Eql#A") { val info = ctx.tyDefs2(nme) info.typedParams.foreach { p => val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, p._1) @@ -1058,7 +1056,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } } } else { - (tr1.mkTag, tr2.mkTag) match { + (tr1.mkClsTag, tr2.mkClsTag) match { case (S(tag1), S(tag2)) if !(tag1 <:< tag2) => reportError() case _ => diff --git a/shared/src/main/scala/mlscript/NormalForms.scala b/shared/src/main/scala/mlscript/NormalForms.scala index 5035b87e58..09324175e0 100644 --- a/shared/src/main/scala/mlscript/NormalForms.scala +++ b/shared/src/main/scala/mlscript/NormalForms.scala @@ -200,7 +200,7 @@ class NormalForms extends TyperDatatypes { self: Typer => TypeRef(that.defn, newTargs)(that.prov) }) val res = LhsRefined(b, ts, rt, trs2) - that.mkTag.fold(S(res): Opt[LhsNf])(res & (_, pol)) + that.mkClsTag.fold(S(res): Opt[LhsNf])(res & (_, pol)) } def & (that: LhsNf, pol: Bool)(implicit ctx: Ctx, etf: ExpandTupleFields): Opt[LhsNf] = (this, that) match { case (_, LhsTop) => S(this) @@ -704,7 +704,7 @@ class NormalForms extends TyperDatatypes { self: Typer => case tr @ TypeRef(defn, targs) => // * TODO later: when proper TypeRef-based simplif. is implemented, can remove this special case if (preserveTypeRefs && !primitiveTypes.contains(defn.name) || !tr.canExpand) { - of(polymLvl, cons, LhsRefined(tr.mkTag, ssEmp, RecordType.empty, SortedMap(defn -> tr))) + of(polymLvl, cons, LhsRefined(tr.mkClsTag, ssEmp, RecordType.empty, SortedMap(defn -> tr))) } else mk(polymLvl, cons, tr.expandOrCrash, pol) case TypeBounds(lb, ub) => mk(polymLvl, cons, if (pol) ub else lb, pol) case PolymorphicType(lvl, bod) => mk(lvl, cons, bod, pol) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index d7d8a8b568..1de8a2f035 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -434,7 +434,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => : ST = td.kind match { case Nms => ClassTag(Var(td.nme.name), - ihtags + TN("Eql") // Eql and ihtags (parent tags) + ihtags + TN("Object") )(provTODO) case Cls => // TODO deal with classes without parameter lists (ie needing `new`) @@ -442,8 +442,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => FunctionType( TupleType(params.mapKeys(some))(provTODO), ClassTag(Var(td.nme.name), - ihtags + TN("Eql") // Eql and ihtags (parent tags) - )(provTODO) & selfTy & RecordType.mk( + ihtags + TN("Object") + )(provTODO) & RecordType.mk( + // * ^ Note: we used to include the self type here (& selfTy), + // * but it doesn't seem to be needed – if the class has a constructor, + // * then surely it satisfies the self type (once we check it). tparams.map { case (tn, tv, vi) => // TODO also use computed variance info when available! Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> @@ -499,7 +502,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => fd } - case _ => _decl + case td: NuTypeDef => + if (td.nme.name in reservedTypeNames) + err(msg"Type name '${td.nme.name}' is reserved", td.toLoc) + td } val lti = new DelayedTypeInfo(decl, implicitly) decl match { @@ -727,13 +733,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (p, Var(nm), lti, _, _) :: ps => lti match { case lti: DelayedTypeInfo => lti.kind match { case Trt | Cls | Nms => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) - case _ => lookupTags(ps, tags) + case Val | Mxn | Als => lookupTags(ps, tags) } case CompletedTypeInfo(trt: TypedNuTrt) => lookupTags(ps, Set.single(TypeName(nm)) union trt.inheritedTags union tags) case CompletedTypeInfo(cls: TypedNuCls) => lookupTags(ps, Set.single(TypeName(nm)) union cls.inheritedTags union tags) - case _ => lookupTags(ps, tags) + case CompletedTypeInfo(_: NuParam | _: TypedNuFun | _: TypedNuAls | _: TypedNuMxn | _: TypedNuDummy) => + lookupTags(ps, tags) } } } @@ -1069,7 +1076,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * as this check will already have been performed generally when typing class T, // * but this would happen if we instead expanded into a type equivalent to #S & T... constrain(ty, res) - res + // * Retrieve the extruded lower bound. + // * Note that there should be only one, and in particular it should not be recursive, + // * since the variable is never shared outside this scope. + res.lowerBounds match { + case lb :: Nil => TypeBounds.mk(TopType, lb) + case _ => die + } } td.kind match { diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index d72883ce9e..9c24cea802 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -111,19 +111,21 @@ class TypeDefs extends NuTypeDefs { self: Typer => Var(clsNme.name + "#" + tparamNme.name) def clsNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { - require((td.kind is Cls) || (td.kind is Nms) || (td.kind is Trt), td.kind) + require((td.kind is Cls) || (td.kind is Nms), td.kind) ClassTag(Var(td.nme.name), - // ctx.allBaseClassesOf(td.nme.name) - Set.single(TypeName("Eql")) // TODO superclasses - | ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) + if(newDefs) + Set.single(TN("Object")) + | ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) + else ctx.allBaseClassesOf(td.nme.name) )(prov) } def clsNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { - require(td.kind is Cls) + require((td.kind is Cls) || (td.kind is Nms), td.kind) if (newDefs && td.kind.str.isCapitalized) ClassTag(Var(td.nme.name), - // ctx.allBaseClassesOf(td.nme.name))(prov) - Set.single(TypeName("Eql")) // TODO superclasses - | ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) + if(newDefs) + Set.single(TN("Object")) + | ctx.tyDefs2.get(td.nme.name).map(_.inheritedTags).getOrElse(Set.empty) + else ctx.allBaseClassesOf(td.nme.name) )(prov) else ClassTag(Var(td.nme.name), ctx.allBaseClassesOf(td.nme.name))(prov) } @@ -185,7 +187,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => err(msg"Type names must start with a capital letter", td0.nme.toLoc) td0.copy(nme = td0.nme.copy(n).withLocOf(td0.nme)).withLocOf(td0) } - if (primitiveTypes.contains(n)) { + if (reservedTypeNames.contains(n)) { err(msg"Type name '$n' is reserved.", td.nme.toLoc) } td.tparams.groupBy(_.name).foreach { case s -> tps if tps.sizeIs > 1 => err( diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 330987624a..88f6f1ccae 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -14,7 +14,7 @@ import mlscript.Message._ * Inferred SimpleType values are then turned into CompactType values for simplification. * In order to turn the resulting CompactType into a mlscript.Type, we use `expandCompactType`. */ -class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) +class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var newDefs: Bool = false) extends ucs.Desugarer with TypeSimplifier { def funkyTuples: Bool = false @@ -33,8 +33,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) var irregularTypes: Boolean = false var constrainedTypes: Boolean = false - var newDefs: Bool = false - var recordProvenances: Boolean = true type Binding = Str -> SimpleType @@ -144,7 +142,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) tyDefs.get(name).fold(Set.empty[TypeName])(_.allBaseClasses(this)(Set.empty))) } object Ctx { - def init: Ctx = Ctx( + private val initBase: Ctx = Ctx( parent = N, env = MutMap.from(builtinBindings.iterator.map(nt => nt._1 -> VarSymbol(nt._2, Var(nt._1)))), mthEnv = MutMap.empty, @@ -155,6 +153,18 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) inRecursiveDef = N, MutMap.empty, ) + def init: Ctx = if (!newDefs) initBase else { + val res = initBase.copy( + tyDefs2 = MutMap.from(nuBuiltinTypes.map { t => + val lti = new DelayedTypeInfo(t, Map.empty)(initBase, e => lastWords(e.theMsg)) + initBase.env += t.nme.name -> lti + t.nme.name -> lti + }), + ) + implicit val raise: Raise = throw _ + res.tyDefs2.valuesIterator.foreach(_.complete()) + res + } val empty: Ctx = init } implicit def lvl(implicit ctx: Ctx): Int = ctx.lvl @@ -184,18 +194,25 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) val TopType: ExtrType = ExtrType(false)(noTyProv) val BotType: ExtrType = ExtrType(true)(noTyProv) - val UnitType: ClassTag = ClassTag(Var("unit"), semp)(noTyProv) + val UnitType: ClassTag = if (newDefs) ClassTag(UnitLit(true), semp)(noTyProv) + else ClassTag(Var("unit"), semp)(noTyProv) - val BoolType: ClassTag = ClassTag(Var("bool"), sing(TN("Eql")))(noTyProv) - val TrueType: ClassTag = ClassTag(Var("true"), sing(TN("bool")) + TN("Eql"))(noTyProv) - val FalseType: ClassTag = ClassTag(Var("false"), sing(TN("bool")) + TN("Eql"))(noTyProv) + val BoolType: ST = if (newDefs) TR(TN("Bool"), Nil)(noTyProv) + else ClassTag(Var("bool"), semp)(noTyProv) + val ObjType: ST = if (newDefs) TR(TN("Object"), Nil)(noTyProv) + else TopType + val IntType: ST = if (newDefs) TR(TN("Int"), Nil)(noTyProv) + else ClassTag(Var("int"), sing(TN("number")))(noTyProv) + val DecType: ST = if (newDefs) TR(TN("Num"), Nil)(noTyProv) + else ClassTag(Var("number"), semp)(noTyProv) + val StrType: ST = if (newDefs) TR(TN("Str"), Nil)(noTyProv) + else ClassTag(Var("string"), semp)(noTyProv) + val TrueType: ST = if (newDefs) TR(TN("true"), Nil)(noTyProv) + else ClassTag(Var("true"), sing(TN("bool")))(noTyProv) + val FalseType: ST = if (newDefs) TR(TN("false"), Nil)(noTyProv) + else ClassTag(Var("false"), sing(TN("bool")))(noTyProv) - val IntType: ClassTag = ClassTag(Var("int"), sing(TN("number")) + TN("Eql"))(noTyProv) - val DecType: ClassTag = ClassTag(Var("number"), sing(TN("Eql")))(noTyProv) - val StrType: ClassTag = ClassTag(Var("string"), sing(TN("Eql")))(noTyProv) - // val IntType: ST = TypeRef(TN("int"), Nil)(noTyProv) - // val DecType: ST = TypeRef(TN("number"), Nil)(noTyProv) - // val StrType: ST = TypeRef(TN("string"), Nil)(noTyProv) + val EqlTag: TraitTag = TraitTag(Var("Eql"), Set.empty)(noProv) val ErrTypeId: SimpleTerm = Var("error") @@ -204,13 +221,25 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) List("unit" -> UnitType, "bool" -> BoolType, "int" -> IntType, "number" -> DecType, "string" -> StrType, "anything" -> TopType, "nothing" -> BotType) + private val preludeLoc = Loc(0, 0, Origin("", 0, new FastParseHelpers(""))) + + val nuBuiltinTypes: Ls[NuTypeDef] = Ls( + NuTypeDef(Cls, TN("Object"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, N), + NuTypeDef(Trt, TN("Eql"), (S(VarianceInfo.contra), TN("A")) :: Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Cls, TN("Num"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Cls, TN("Int"), Nil, N, N, N, Var("Num") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Cls, TN("Bool"), Nil, N, N, S(Union(TN("true"), TN("false"))), Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Nms, TN("true"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Nms, TN("false"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Cls, TN("Str"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + ) val builtinTypes: Ls[TypeDef] = - TypeDef(Cls, TN("int"), Nil, TopType, Nil, Nil, sing(TN("number")) + TN("Eql"), N, Nil) :: - TypeDef(Cls, TN("number"), Nil, TopType, Nil, Nil, sing(TN("Eql")), N, Nil) :: - TypeDef(Cls, TN("bool"), Nil, TopType, Nil, Nil, sing(TN("Eql")), N, Nil) :: - TypeDef(Cls, TN("true"), Nil, TopType, Nil, Nil, sing(TN("bool")) + TN("Eql"), N, Nil) :: - TypeDef(Cls, TN("false"), Nil, TopType, Nil, Nil, sing(TN("bool")) + TN("Eql"), N, Nil) :: - TypeDef(Cls, TN("string"), Nil, TopType, Nil, Nil, sing(TN("Eql")), N, Nil) :: + TypeDef(Cls, TN("int"), Nil, TopType, Nil, Nil, sing(TN("number")), N, Nil) :: + TypeDef(Cls, TN("number"), Nil, TopType, Nil, Nil, semp, N, Nil) :: + TypeDef(Cls, TN("bool"), Nil, TopType, Nil, Nil, semp, N, Nil) :: + TypeDef(Cls, TN("true"), Nil, TopType, Nil, Nil, sing(TN("bool")), N, Nil) :: + TypeDef(Cls, TN("false"), Nil, TopType, Nil, Nil, sing(TN("bool")), N, Nil) :: + TypeDef(Cls, TN("string"), Nil, TopType, Nil, Nil, semp, N, Nil) :: TypeDef(Als, TN("undefined"), Nil, ClassTag(UnitLit(true), semp)(noProv), Nil, Nil, semp, N, Nil) :: TypeDef(Als, TN("null"), Nil, ClassTag(UnitLit(false), semp)(noProv), Nil, Nil, semp, N, Nil) :: TypeDef(Als, TN("anything"), Nil, TopType, Nil, Nil, semp, N, Nil) :: @@ -237,16 +266,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) tyDef.tvarVariances = S(MutMap(tv -> VarianceInfo.in)) tyDef } :: - { - val tv = freshVar(noTyProv, N)(1) - val tyDef = TypeDef(Cls, TN("Eql"), List(TN("A") -> tv), - TopType, Nil, Nil, semp, N, Nil) - tyDef.tvarVariances = S(MutMap(tv -> VarianceInfo.contra)) - tyDef - } :: Nil val primitiveTypes: Set[Str] = - builtinTypes.iterator.map(_.nme.name).flatMap(n => n.decapitalize :: n.capitalize :: Nil).toSet - "Eql" + builtinTypes.iterator.map(_.nme.name).flatMap(n => n.decapitalize :: n.capitalize :: Nil).toSet + + "Object" + "Num" + "Str" + val reservedTypeNames: Set[Str] = primitiveTypes + "Eql" def singleTup(ty: ST): ST = if (funkyTuples) ty else TupleType((N, ty.toUpper(ty.prov) ) :: Nil)(noProv) val builtinBindings: Bindings = { @@ -259,6 +283,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) Map( "true" -> TrueType, "false" -> FalseType, + "True" -> TypeRef(TN("True"), Nil)(noProv), + "False" -> TypeRef(TN("False"), Nil)(noProv), "NaN" -> DecType, "document" -> BotType, "window" -> BotType, @@ -438,7 +464,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) tyTp(App(n, Var("").withLocOf(f)).toCoveringLoc, "extension field")) } )(tyTp(r.toLoc, "extension record")))(tyTp(ty.toLoc, "extension type")) case Literal(lit) => - ClassTag(lit, lit.baseClasses)(tyTp(ty.toLoc, "literal type")) + ClassTag(lit, if (newDefs) lit.baseClassesNu + else lit.baseClassesOld)(tyTp(ty.toLoc, "literal type")) case TypeName("this") => ctx.env.get("this") match { case S(_: AbstractConstructor | _: LazyTypeInfo) => die @@ -669,11 +696,11 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) } // TODO also prevent rebinding of "not" - val reservedNames: Set[Str] = Set("|", "&", "~", ",", "neg", "and", "or", "is") + val reservedVarNames: Set[Str] = Set("|", "&", "~", ",", "neg", "and", "or", "is") object ValidVar { def unapply(v: Var)(implicit raise: Raise): S[Str] = S { - if (reservedNames(v.name)) + if (reservedVarNames(v.name)) err(s"Illegal use of reserved operator: " + v.name, v.toLoc)(raise) v.name @@ -818,7 +845,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) // ^ TODO maybe use a description passed in param? // currently we get things like "flows into variable reference" // but we used to get the better "flows into object receiver" or "flows into applied expression"... - case lit: Lit => ClassTag(lit, lit.baseClasses)(prov) + case lit: Lit => ClassTag(lit, if (newDefs) lit.baseClassesNu else lit.baseClassesOld)(prov) case Super() => err(s"Illegal use of `super`", term.toLoc)(raise) typeTerm(Var("super").withLocOf(term)) @@ -1079,6 +1106,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) (t_ty without rcd.fields.iterator.map(_._1).toSortedSet) & (rcd_ty, prov) case CaseOf(s, cs) => val s_ty = typeMonomorphicTerm(s) + if (newDefs) con(s_ty, ObjType.withProv(prov), TopType) val (tys, cs_ty) = typeArms(s |>? { case v: Var => v case Asc(v: Var, _) => v @@ -1149,7 +1177,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) case Case(pat, bod, rest) => val (tagTy, patTy) : (ST, ST) = pat match { case lit: Lit => - val t = ClassTag(lit, lit.baseClasses)(tp(pat.toLoc, "literal pattern")) + val t = ClassTag(lit, + if (newDefs) lit.baseClassesNu else lit.baseClassesOld)(tp(pat.toLoc, "literal pattern")) t -> t case v @ Var(nme) => val tpr = tp(pat.toLoc, "type pattern") @@ -1408,7 +1437,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool) nv }) case FunctionType(l, r) => Function(go(l), go(r)) - case ComposedType(true, l, r) => Union(go(l), go(r)) + case ct @ ComposedType(true, l, r) => + if (ct >:< (TrueType | FalseType)) TN("Bool") // TODO should rather be done in TypeSimplifier + else Union(go(l), go(r)) case ComposedType(false, l, r) => Inter(go(l), go(r)) case RecordType(fs) => Record(fs.mapValues(field)) case TupleType(fs) => Tuple(fs.mapValues(field)) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 225fce1c7a..cfc741984c 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -360,6 +360,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } type TR = TypeRef + val TR: TypeRef.type = TypeRef case class TypeRef(defn: TypeName, targs: Ls[SimpleType])(val prov: TypeProvenance) extends SimpleType with TypeRefImpl { def level: Level = targs.iterator.map(_.level).maxOption.getOrElse(0) def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = targs.iterator.map(_.levelBelow(ub)).maxOption.getOrElse(MinLevel) diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 972a22e8f5..34b1b81e75 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1054,10 +1054,15 @@ abstract class TyperHelpers { Typer: Typer => mkTparamRcd case _ => // * Case for when the type has not been completed yet info.decl match { - case td: NuTypeDef if td.kind.isInstanceOf[ObjDefKind] => + case td: NuTypeDef if td.kind.isInstanceOf[ClsLikeKind] => + // TODO in the future, add the self signature to DelayedTypeInfo and use it here assert(td.tparams.size === targs.size) clsNameToNomTag(td)(provTODO, ctx) & mkTparamRcd + case td: NuTypeDef if td.kind is Trt => + assert(td.tparams.size === targs.size) + trtNameToNomTag(td)(provTODO, ctx) & + mkTparamRcd case td: NuTypeDef if td.kind is Als => // * Definition was not forced yet, which indicates an error (hopefully) lastWords("cannot expand unforced type alias") @@ -1087,13 +1092,17 @@ abstract class TyperHelpers { Typer: Typer => }, td.targs.lazyZip(targs).toMap) //.withProv(prov) } //tap { res => println(s"Expand $this => $res") } private var tag: Opt[Opt[ClassTag]] = N - def expansionFallback(implicit ctx: Ctx): Opt[ST] = mkTag - def mkTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { + def expansionFallback(implicit ctx: Ctx): Opt[ST] = mkClsTag + def mkClsTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { val res = ctx.tyDefs.get(defn.name) match { - case S(td: TypeDef) if td.kind is Cls => S(clsNameToNomTag(td)(noProv, ctx)) + case S(td: TypeDef) if (td.kind is Cls) || (td.kind is Nms) => + S(clsNameToNomTag(td)(noProv, ctx)) + case S(td: TypeDef) if td.kind is Trt => + N case _ => ctx.tyDefs2.get(defn.name) match { case S(lti) => lti.decl match { - case td: NuTypeDef if td.kind is Cls => S(clsNameToNomTag(td)(noProv, ctx)) + case td: NuTypeDef if (td.kind is Cls) || (td.kind is Nms) => + S(clsNameToNomTag(td)(noProv, ctx)) case _ => N } case _ => N diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 5ebbbfb9cf..9bae3ba303 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -625,10 +625,16 @@ trait TermImpl extends StatementImpl { self: Term => private class NotAType(val trm: Statement) extends Throwable trait LitImpl { self: Lit => - def baseClasses: Set[TypeName] = this match { - case _: IntLit => Set.single(TypeName("int")) + TypeName("number") + TypeName("Eql") - case _: StrLit => Set.single(TypeName("string")) + TypeName("Eql") - case _: DecLit => Set.single(TypeName("number")) + TypeName("Eql") + def baseClassesOld: Set[TypeName] = this match { + case _: IntLit => Set.single(TypeName("int")) + TypeName("number") + case _: StrLit => Set.single(TypeName("string")) + case _: DecLit => Set.single(TypeName("number")) + case _: UnitLit => Set.empty + } + def baseClassesNu: Set[TypeName] = this match { + case _: IntLit => Set.single(TypeName("Int")) + TypeName("Num") + TypeName("Object") + case _: StrLit => Set.single(TypeName("Str")) + TypeName("Object") + case _: DecLit => Set.single(TypeName("Num")) + TypeName("Object") case _: UnitLit => Set.empty } } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index af75a412cf..8abb92debf 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -49,11 +49,12 @@ sealed abstract class DeclKind(val str: Str) case object Val extends DeclKind("value") sealed abstract class TypeDefKind(str: Str) extends DeclKind(str) sealed trait ObjDefKind -case object Cls extends TypeDefKind("class") with ObjDefKind +sealed trait ClsLikeKind extends ObjDefKind +case object Cls extends TypeDefKind("class") with ClsLikeKind case object Trt extends TypeDefKind("trait") with ObjDefKind case object Mxn extends TypeDefKind("mixin") case object Als extends TypeDefKind("type alias") -case object Nms extends TypeDefKind("module") with ObjDefKind +case object Nms extends TypeDefKind("module") with ClsLikeKind sealed abstract class Term extends Terms with TermImpl sealed abstract class Lit extends SimpleTerm with LitImpl diff --git a/shared/src/main/scala/mlscript/utils/package.scala b/shared/src/main/scala/mlscript/utils/package.scala index 77a52d4c36..10bd120245 100644 --- a/shared/src/main/scala/mlscript/utils/package.scala +++ b/shared/src/main/scala/mlscript/utils/package.scala @@ -12,12 +12,14 @@ package object utils { "org.wartremover.warts.Equals", "org.wartremover.warts.AsInstanceOf")) implicit final class AnyOps[A](self: A) { - def ===(other: A): Boolean = self == other - def =/=(other: A): Boolean = self != other - def is(other: AnyRef): Boolean = self.asInstanceOf[AnyRef] eq other - def isnt(other: AnyRef): Boolean = !(self.asInstanceOf[AnyRef] eq other) + def ===(other: A): Bool = self == other + def =/=(other: A): Bool = self != other + def is(other: AnyRef): Bool = self.asInstanceOf[AnyRef] eq other + def isnt(other: AnyRef): Bool = !(self.asInstanceOf[AnyRef] eq other) /** An alternative to === when in ScalaTest, which shadows our === */ - def =:=(other: A): Boolean = self == other + def =:=(other: A): Bool = self == other + def in(xs: A => Bool): Bool = xs(self) + def in(xs: Seq[_ >: A]): Bool = xs.exists(_ === self) } implicit class StringOps(private val self: String) extends AnyVal { diff --git a/shared/src/test/diff/basics/Simplesub1.fun b/shared/src/test/diff/basics/Simplesub1.fun index d39f003a50..7f95bf8735 100644 --- a/shared/src/test/diff/basics/Simplesub1.fun +++ b/shared/src/test/diff/basics/Simplesub1.fun @@ -134,7 +134,7 @@ f => { x: f 42, y: 123 }.y //│ res: (42 -> anything) -> 123 if true then { a: 1, b: true } else { b: false, c: 42 } -//│ res: {b: bool} +//│ res: {b: Bool} :e { a: 123, b: true }.c @@ -435,17 +435,17 @@ let rec x = (let y = (x x); (z => z)) // * Z combinator: // :e // Works thanks to inconsistent constrained types... (f => (x => f (v => (x x) v)) (x => f (v => (x x) v))) -//│ res: ((forall 'a 'b. 'a -> 'b +//│ res: ((forall 'a 'b. 'b -> 'a //│ where -//│ forall 'c 'd. 'd -> 'c +//│ forall 'c 'd. 'c -> 'd //│ where //│ 'e <: (forall 'f 'g. 'f -> 'g //│ where -//│ 'd <: 'd -> 'f -> 'g) -> 'c <: (forall 'c 'd. 'd -> 'c +//│ 'c <: 'c -> 'f -> 'g) -> 'd <: (forall 'c 'd. 'c -> 'd //│ where //│ 'e <: (forall 'f 'g. 'f -> 'g //│ where -//│ 'd <: 'd -> 'f -> 'g) -> 'c) -> 'a -> 'b) -> 'h & 'e) -> 'h +//│ 'c <: 'c -> 'f -> 'g) -> 'd) -> 'b -> 'a) -> 'h & 'e) -> 'h // * Function that takes arbitrarily many arguments: // :e // Works thanks to inconsistent constrained types... diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index cfe03b3acc..02cdef1bf2 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -60,10 +60,10 @@ Test0 //│ = Test0 { class: [class Test0] } :js -class A(a: int) { +class A(a: Int) { log(a) } -//│ class A(a: int) +//│ class A(a: Int) //│ // Prelude //│ class TypingUnit3 { //│ #A; @@ -133,10 +133,10 @@ let ab = A(0) :e :js class Foo { - this: { x: int } + this: { x: Int } } //│ ╔══[ERROR] Type `#Foo` does not contain member `x` -//│ ║ l.136: this: { x: int } +//│ ║ l.136: this: { x: Int } //│ ╙── ^ //│ class Foo //│ // Prelude @@ -160,13 +160,13 @@ class Foo { :e :js class Bar { - super: { x: int } + super: { x: Int } } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.163: super: { x: int } +//│ ║ l.163: super: { x: Int } //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#Bar` does not contain member `x` -//│ ║ l.163: super: { x: int } +//│ ║ l.163: super: { x: Int } //│ ╙── ^ //│ class Bar //│ // Prelude @@ -198,7 +198,7 @@ class Baz() { } //│ class Baz() { //│ let x: 123 -//│ let y: int +//│ let y: Int //│ } //│ // Prelude //│ class TypingUnit9 { @@ -247,7 +247,7 @@ class Baz() { let baz = Baz() log((baz.x, baz.y)) //│ let baz: Baz -//│ unit +//│ undefined //│ baz //│ = Baz {} //│ // Output @@ -263,11 +263,11 @@ log((baz.x, baz.y)) class Q() { let q = 42 fun qq = - let f = (x: int) => {q: x + q}; f(1) + let f = (x: Int) => {q: x + q}; f(1) } //│ class Q() { //│ let q: 42 -//│ fun qq: {q: int} +//│ fun qq: {q: Int} //│ } //│ // Prelude //│ class TypingUnit11 { @@ -305,7 +305,7 @@ class Q() { let q = Q() q.qq.q //│ let q: Q -//│ int +//│ Int //│ q //│ = Q {} //│ res @@ -314,10 +314,10 @@ q.qq.q :js class W() { let x = 42 - fun add(self: int) = x + self + fun add(self: Int) = x + self } //│ class W() { -//│ fun add: (self: int,) -> int +//│ fun add: (self: Int,) -> Int //│ let x: 42 //│ } //│ // Prelude @@ -354,7 +354,7 @@ class W() { let www = W() www.add(42) //│ let www: W -//│ int +//│ Int //│ // Prelude //│ class TypingUnit14 {} //│ const typing_unit14 = new TypingUnit14; diff --git a/shared/src/test/diff/codegen/FieldOverride.mls b/shared/src/test/diff/codegen/FieldOverride.mls index b7323e3da3..ff7c523be7 100644 --- a/shared/src/test/diff/codegen/FieldOverride.mls +++ b/shared/src/test/diff/codegen/FieldOverride.mls @@ -2,8 +2,8 @@ :NewDefs :js -class C(a: int) { let a = 1 } -//│ class C(a: int) { +class C(a: Int) { let a = 1 } +//│ class C(a: Int) { //│ let a: 1 //│ } //│ // Prelude @@ -45,13 +45,13 @@ a.a //│ = 1 :js -class C2(a: int, b: int) { +class C2(a: Int, b: Int) { let a = b + 1 let b = a + 1 } -//│ class C2(a: int, b: int) { -//│ let a: int -//│ let b: int +//│ class C2(a: Int, b: Int) { +//│ let a: Int +//│ let b: Int //│ } //│ // Prelude //│ class TypingUnit2 { @@ -89,7 +89,7 @@ let c2 = C2(1, 2) c2.a c2.b //│ let c2: C2 -//│ int +//│ Int //│ c2 //│ = C2 {} //│ res @@ -97,14 +97,14 @@ c2.b //│ res //│ = 4 -class C3(a: int) { +class C3(a: Int) { let a = 42 - class C4(a: int) { + class C4(a: Int) { let a = 44 } } -//│ class C3(a: int) { -//│ class C4(a: int) { +//│ class C3(a: Int) { +//│ class C4(a: Int) { //│ let a: 44 //│ } //│ let a: 42 diff --git a/shared/src/test/diff/codegen/IndirectRecursion.mls b/shared/src/test/diff/codegen/IndirectRecursion.mls index 068855c833..825f691ec7 100644 --- a/shared/src/test/diff/codegen/IndirectRecursion.mls +++ b/shared/src/test/diff/codegen/IndirectRecursion.mls @@ -149,7 +149,7 @@ def z = //│ ((anything -> nothing) -> anything) -> error //│ <: z: //│ (('a -> 'b) -> ('a -> 'b & 'c)) -> 'c -//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d. ?d -> ?c) -> ?e` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d. ?c -> ?d) -> ?e` exceeded recursion depth limit (250) //│ ║ l.148: (fun f -> (fun x -> f (fun v -> (x x) v)) (fun x -> f (fun v -> (x x) v))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. diff --git a/shared/src/test/diff/codegen/Inheritance.mls b/shared/src/test/diff/codegen/Inheritance.mls index 0f21f69ef1..63c065a121 100644 --- a/shared/src/test/diff/codegen/Inheritance.mls +++ b/shared/src/test/diff/codegen/Inheritance.mls @@ -1,3 +1,4 @@ + :js trait X: { x: int } class Y: X @@ -211,13 +212,13 @@ def checkP x = case x of { P -> true | _ -> false } -//│ checkS: anything -> bool +//│ checkS: anything -> Bool //│ = [Function: checkS] -//│ checkR: anything -> bool +//│ checkR: anything -> Bool //│ = [Function: checkR] -//│ checkQ: anything -> bool +//│ checkQ: anything -> Bool //│ = [Function: checkQ] -//│ checkP: anything -> bool +//│ checkP: anything -> Bool //│ = [Function: checkP] // Should pass all checks. @@ -256,3 +257,4 @@ bar = Bar{} bar.Foo //│ res: 1 //│ = 1 + diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 0a803cbfef..b29e375114 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -4,9 +4,9 @@ :js :ShowRepl class Add(lhs: E, rhs: E) -class Lit(n: int) +class Lit(n: Int) //│ class Add[E](lhs: E, rhs: E) -//│ class Lit(n: int) +//│ class Lit(n: Int) //│ // Prelude //│ let res; //│ class TypingUnit { @@ -107,12 +107,12 @@ class Lit(n: int) mixin EvalBase { fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n: Int Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit) -> int +//│ this: {eval: 'lhs -> Int} +//│ fun eval: (Add['lhs] | Lit) -> Int //│ } //│ // Prelude //│ class TypingUnit1 { @@ -235,8 +235,8 @@ mixin EvalNeg { } //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} -//│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) +//│ this: {eval: 'expr -> Int} +//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> (Int | 'b) //│ } //│ // Prelude //│ class TypingUnit3 { @@ -297,7 +297,7 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | Object & ~#Neg] | Object & 'a & ~#Neg) -> 'b //│ } //│ // Prelude //│ class TypingUnit4 { @@ -352,10 +352,12 @@ mixin EvalNegNeg { :ShowRepl module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang { -//│ fun eval: 'a -> int +//│ fun eval: 'a -> Int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] +//│ 'a <: Neg['A] | Object & 'b & ~#Neg +//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit | Neg['a] //│ // Prelude //│ class TypingUnit5 { //│ #TestLang; @@ -412,8 +414,8 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) TestLang.eval(mk(0)) -//│ fun mk: forall 'E. anything -> 'E -//│ int +//│ fun mk: forall 'E. Object -> 'E +//│ Int //│ where //│ 'E :> Add['E] | Lit | Neg['E] //│ // Prelude @@ -427,7 +429,7 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:410 +//│ ┌ Block at Mixin.mls:412 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ class TypingUnit6 {} @@ -453,36 +455,35 @@ TestLang.eval(mk(0)) //│ = [Function: mk] -class Foo(x: int) -//│ class Foo(x: int) +class Foo(x: Int) +//│ class Foo(x: Int) +class Bar(x: Int, y: Int) extends Foo(x + y) +//│ class Bar(x: Int, y: Int) extends Foo -class Bar(x: int, y: int) extends Foo(x + y) -//│ class Bar(x: int, y: int) extends Foo - -mixin AA(a: int) { +mixin AA(a: Int) { } -//│ mixin AA(a: int) +//│ mixin AA(a: Int) mixin BB {} //│ mixin BB() -class C(x: int) extends BB -//│ class C(x: int) +class C(x: Int) extends BB +//│ class C(x: Int) -class D(x: int) extends AA(x) -//│ class D(x: int) +class D(x: Int) extends AA(x) +//│ class D(x: Int) -class E(x: int) extends BB, AA(x) -//│ class E(x: int) +class E(x: Int) extends BB, AA(x) +//│ class E(x: Int) :js -mixin Fooo(x: int) { fun f = [x, this.x] } -//│ mixin Fooo(x: int) { +mixin Fooo(x: Int) { fun f = [x, this.x] } +//│ mixin Fooo(x: Int) { //│ this: {x: 'x} -//│ fun f: (int, 'x,) +//│ fun f: (Int, 'x,) //│ } //│ // Prelude //│ class TypingUnit14 { @@ -513,8 +514,8 @@ mixin Fooo(x: int) { fun f = [x, this.x] } //│ // End of generated code :js -mixin Bazz(y: int) -//│ mixin Bazz(y: int) +mixin Bazz(y: Int) +//│ mixin Bazz(y: Int) //│ // Prelude //│ class TypingUnit15 { //│ constructor() { @@ -538,7 +539,7 @@ mixin Bazz(y: int) :js module Barr extends Fooo(0), Bazz(1) //│ module Barr { -//│ fun f: (int, 0,) +//│ fun f: (Int, 0,) //│ } //│ // Prelude //│ class TypingUnit16 { @@ -579,7 +580,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.579: fun x = y +//│ ║ l.580: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error @@ -597,12 +598,12 @@ module Test extends Base //│ ReferenceError: Base is not defined -mixin MA(a: int) -mixin MB(b1: int, b2: int) -mixin MC(c: int) -//│ mixin MA(a: int) -//│ mixin MB(b1: int, b2: int) -//│ mixin MC(c: int) +mixin MA(a: Int) +mixin MB(b1: Int, b2: Int) +mixin MC(c: Int) +//│ mixin MA(a: Int) +//│ mixin MB(b1: Int, b2: Int) +//│ mixin MC(c: Int) :js module MM extends MA(1), MB(2, 3), MC(4) diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 0e88c0ff4e..9b619d7076 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -4,13 +4,13 @@ :js module A { let a = 42 - class B(x: int) { + class B(x: Int) { fun b = x + 1 } } //│ module A { -//│ class B(x: int) { -//│ fun b: int +//│ class B(x: Int) { +//│ fun b: Int //│ } //│ let a: 42 //│ } @@ -85,12 +85,12 @@ bb.b :e -class B(x: int) { +class B(x: Int) { let outer = 42 - class C(y: int) { + class C(y: Int) { let outer1 = outer + outer } - class D(outer: int) + class D(outer: Int) } let b = B(1) b.outer @@ -104,11 +104,11 @@ d.outer //│ ╔══[ERROR] access to class member not yet supported //│ ║ l.99: let d = b.D(1) //│ ╙── ^^ -//│ class B(x: int) { -//│ class C(y: int) { -//│ let outer1: int +//│ class B(x: Int) { +//│ class C(y: Int) { +//│ let outer1: Int //│ } -//│ class D(outer: int) +//│ class D(outer: Int) //│ let outer: 42 //│ } //│ let b: B @@ -174,12 +174,12 @@ mixin C() { :js module D { - class E(x: int) {} - fun createE(x: int) = E(x + 1) + class E(x: Int) {} + fun createE(x: Int) = E(x + 1) } //│ module D { -//│ class E(x: int) -//│ fun createE: (x: int,) -> E +//│ class E(x: Int) +//│ fun createE: (x: Int,) -> E //│ } //│ // Prelude //│ class TypingUnit4 { @@ -227,7 +227,7 @@ module D { let ee = D.createE(42) ee.x //│ let ee: E -//│ int +//│ Int //│ // Prelude //│ class TypingUnit5 {} //│ const typing_unit5 = new TypingUnit5; @@ -242,20 +242,20 @@ ee.x //│ = 43 :js -class E(x: int) { - class F(y: int) { +class E(x: Int) { + class F(y: Int) { fun sum = x + y - class G(z: int) { + class G(z: Int) { fun sum = x + y + z } } } -//│ class E(x: int) { -//│ class F(y: int) { -//│ class G(z: int) { -//│ fun sum: int +//│ class E(x: Int) { +//│ class F(y: Int) { +//│ class G(z: Int) { +//│ fun sum: Int //│ } -//│ fun sum: int +//│ fun sum: Int //│ } //│ } //│ // Prelude @@ -366,7 +366,7 @@ class F() { } //│ class F() { //│ class G() { -//│ let x1: int +//│ let x1: Int //│ } //│ let x: 42 //│ } @@ -416,22 +416,22 @@ class F() { :js module G { - class I(x: int) {} + class I(x: Int) {} module H { - fun i1(x: int) = I(x + 1) - class J(x: int) { - fun ii(a: int) = I(x + a) + fun i1(x: Int) = I(x + 1) + class J(x: Int) { + fun ii(a: Int) = I(x + a) } } } //│ module G { //│ module H { -//│ class J(x: int) { -//│ fun ii: (a: int,) -> I +//│ class J(x: Int) { +//│ fun ii: (a: Int,) -> I //│ } -//│ fun i1: (x: int,) -> I +//│ fun i1: (x: Int,) -> I //│ } -//│ class I(x: int) +//│ class I(x: Int) //│ } //│ // Prelude //│ class TypingUnit9 { @@ -538,14 +538,14 @@ i.x :js module H { - class I(x: int) - class J(x: int) { + class I(x: Int) + class J(x: Int) { let i = I(x + 1) } } //│ module H { -//│ class I(x: int) -//│ class J(x: int) { +//│ class I(x: Int) +//│ class J(x: Int) { //│ let i: I //│ } //│ } @@ -632,9 +632,9 @@ j.i.x :js :e -class I(x: int) { +class I(x: Int) { let y = x + 1 - class J(x: int) { + class J(x: Int) { let y = x + 2 fun incY = y + 1 } @@ -645,12 +645,12 @@ ij.incY //│ ╔══[ERROR] access to class member not yet supported //│ ║ l.643: let ij = i.J(0) //│ ╙── ^^ -//│ class I(x: int) { -//│ class J(x: int) { -//│ fun incY: int -//│ let y: int +//│ class I(x: Int) { +//│ class J(x: Int) { +//│ fun incY: Int +//│ let y: Int //│ } -//│ let y: int +//│ let y: Int //│ } //│ let i: I //│ let ij: error @@ -724,16 +724,16 @@ ij.incY :js module J { - class K(x: int) {} + class K(x: Int) {} mixin L() {} class M() extends K(1) {} - class N(x: int) extends K(x + 2), L + class N(x: Int) extends K(x + 2), L } //│ module J { -//│ class K(x: int) +//│ class K(x: Int) //│ mixin L() //│ class M() extends K -//│ class N(x: int) extends K +//│ class N(x: Int) extends K //│ } //│ // Prelude //│ class TypingUnit14 { @@ -871,18 +871,18 @@ m.f //│ = 42 module L { - class M(x: int) {} + class M(x: Int) {} module N { module O { - class P(y: int) extends M(y + 1) {} + class P(y: Int) extends M(y + 1) {} } } } //│ module L { -//│ class M(x: int) +//│ class M(x: Int) //│ module N { //│ module O { -//│ class P(y: int) extends M +//│ class P(y: Int) extends M //│ } //│ } //│ } @@ -925,11 +925,11 @@ M.N.op(M.P()) //│ ╙── ^^ //│ module M { //│ module N { -//│ fun op: anything -> (0 | 1 | 2) +//│ fun op: Object -> (0 | 1 | 2) //│ } //│ class O() //│ class P() -//│ fun op: anything -> (0 | 1 | 2) +//│ fun op: Object -> (0 | 1 | 2) //│ } //│ error //│ // Prelude @@ -1083,9 +1083,9 @@ N.O.P() :js :e -class I(x: int) { +class I(x: Int) { let y = x + 1 - class J(z: int) { + class J(z: Int) { let a = [x, y, z] } } @@ -1093,11 +1093,11 @@ I(1).J(3).a //│ ╔══[ERROR] access to class member not yet supported //│ ║ l.1092: I(1).J(3).a //│ ╙── ^^ -//│ class I(x: int) { -//│ class J(z: int) { -//│ let a: (int, int, int,) +//│ class I(x: Int) { +//│ class J(z: Int) { +//│ let a: (Int, Int, Int,) //│ } -//│ let y: int +//│ let y: Int //│ } //│ error //│ // Prelude @@ -1160,12 +1160,12 @@ I(1).J(3).a :js fun main = - fun f(x: int): int = if x is + fun f(x: Int): Int = if x is 0 then 1 else g(x - 1) - fun g(x: int): int = f(x) + fun g(x: Int): Int = f(x) f -//│ fun main: (x: int,) -> int +//│ fun main: (x: Int,) -> Int //│ // Prelude //│ class TypingUnit24 {} //│ const typing_unit24 = new TypingUnit24; @@ -1181,7 +1181,7 @@ fun main = :js fun mian = - class A(x: int) + class A(x: Int) mixin B() module C A(42) @@ -1227,10 +1227,10 @@ fun mian = :js fun mian = mixin B() - class A(x: int) extends B + class A(x: Int) extends B module C extends B [A, C] -//│ fun mian: ((x: int,) -> A, C,) +//│ fun mian: ((x: Int,) -> A, C,) //│ // Prelude //│ class TypingUnit26 {} //│ const typing_unit26 = new TypingUnit26; @@ -1281,10 +1281,10 @@ fun mian = fun main(arg) = let x = arg + 1 fun foo(y) = x + y - class C(u: int) { fun z = [foo(u), bar] } + class C(u: Int) { fun z = [foo(u), bar] } fun bar = x C(123) -//│ fun main: int -> C +//│ fun main: Int -> C //│ // Prelude //│ class TypingUnit27 {} //│ const typing_unit27 = new TypingUnit27; @@ -1332,15 +1332,15 @@ module Test { //│ } :js -class Outer1(outer: int) { +class Outer1(outer: Int) { log(outer) - class Outer2(x: int) { + class Outer2(x: Int) { let outer = x + 1 } } -//│ class Outer1(outer: int) { -//│ class Outer2(x: int) { -//│ let outer: int +//│ class Outer1(outer: Int) { +//│ class Outer2(x: Int) { +//│ let outer: Int //│ } //│ } //│ // Prelude diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index 96951c1d21..6a204fec73 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -1,10 +1,10 @@ :NewDefs :js -class Test(n: int) { +class Test(n: Int) { fun inc = Test(n + 1) } -//│ class Test(n: int) { +//│ class Test(n: Int) { //│ fun inc: Test //│ } //│ // Prelude @@ -38,25 +38,25 @@ class Test(n: int) { //│ // End of generated code Test(0).inc.n -//│ int +//│ Int //│ res //│ = 1 -class Test2(n: int) { +class Test2(n: Int) { fun inc = Test3.inc(n) } module Test3 { fun inc(n) = Test2(n + 1) } -//│ class Test2(n: int) { +//│ class Test2(n: Int) { //│ fun inc: Test2 //│ } //│ module Test3 { -//│ fun inc: int -> Test2 +//│ fun inc: Int -> Test2 //│ } Test2(0).inc.n -//│ int +//│ Int //│ res //│ = 1 @@ -70,10 +70,10 @@ class C[A](n: A) { //│ } :e -let a = C[int](42) +let a = C[Int](42) a.f //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.73: let a = C[int](42) +//│ ║ l.73: let a = C[Int](42) //│ ╙── ^^^^^^ //│ let a: error //│ error @@ -93,15 +93,15 @@ module Foo { //│ } -mixin M0(n: int) { +mixin M0(n: Int) { let m = n // this refers to specifically the `n` we had in parameter, not necessarily this.n fun bar = m fun foo = [n, m, bar] // should this be the same as `[this.n, this.m, this.bar]`? } -//│ mixin M0(n: int) { -//│ fun bar: int -//│ fun foo: (int, int, int,) -//│ let m: int +//│ mixin M0(n: Int) { +//│ fun bar: Int +//│ fun foo: (Int, Int, Int,) +//│ let m: Int //│ } module M1 extends M0(123) { @@ -111,7 +111,7 @@ module M1 extends M0(123) { } //│ module M1 { //│ fun bar: "bar" -//│ fun foo: (int, int, int,) +//│ fun foo: (Int, Int, Int,) //│ fun m: "m" //│ fun n: "n" //│ } @@ -123,7 +123,7 @@ module M1 extends M0(123) { // FIXME typing/runtime mismatch M1.foo -//│ (int, int, int,) +//│ (Int, Int, Int,) //│ res //│ = [ 123, 'm', 'bar' ] @@ -139,7 +139,7 @@ module M2 { //│ ║ l.135: fun bar(x) = x + y + this.m //│ ╙── ^^ //│ module M2 { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ let m: 100 //│ } //│ // Prelude @@ -176,7 +176,7 @@ module M2 { //│ // End of generated code M2.foo(1) -//│ int +//│ Int //│ res //│ = 111 diff --git a/shared/src/test/diff/codegen/NuFuns.mls b/shared/src/test/diff/codegen/NuFuns.mls index 5734ec7342..120f061347 100644 --- a/shared/src/test/diff/codegen/NuFuns.mls +++ b/shared/src/test/diff/codegen/NuFuns.mls @@ -5,7 +5,7 @@ fun foo = fun bar(x) = x + 1 bar(10) -//│ fun foo: int +//│ fun foo: Int //│ // Prelude //│ let res; //│ class TypingUnit {} @@ -20,21 +20,44 @@ fun foo = //│ // End of generated code fun foo = - class C(a: int) { fun bar(x) = a + x + 1 } + class C(a: Int) { fun bar(x) = a + x + 1 } C(100).bar(10) foo -//│ fun foo: int -//│ int +//│ fun foo: Int +//│ Int //│ res //│ = [Function: foo1] + +// FIXME: returns a thunk +fun main = + log("Hello") +main +//│ fun main: undefined +//│ undefined +//│ res +//│ = [Function: main] + +fun main = + log("Hello") +//│ fun main: undefined + +main +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ Hello + + fun main = mixin B { log(1) } log(0) module M extends B log(2) main -//│ fun main: unit -//│ unit +//│ fun main: undefined +//│ undefined //│ res -//│ = [Function: main] +//│ = [Function: main2] + diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index bf9a1ca001..9ba6a8ace8 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -2,8 +2,8 @@ :NewDefs :js -class A(x: int) {} -//│ class A(x: int) +class A(x: Int) {} +//│ class A(x: Int) //│ // Prelude //│ let res; //│ class TypingUnit { @@ -53,7 +53,7 @@ class B {} :js class C { - constructor(x: int) + constructor(x: Int) } //│ class C //│ // Prelude @@ -87,13 +87,13 @@ let c = new C(1) //│ = C {} :js -class D(x: int) { - constructor(y: int) { +class D(x: Int) { + constructor(y: Int) { x = y + 1 } log(x) } -//│ class D(x: int) +//│ class D(x: Int) //│ // Prelude //│ function log(x) { //│ return console.info(x); @@ -127,7 +127,7 @@ class D(x: int) { let dd = new D(41) dd.x //│ let dd: D -//│ int +//│ Int //│ dd //│ = D {} //│ // Output @@ -137,8 +137,8 @@ dd.x :pe class E { - constructor(x: int) - constructor(y: int) + constructor(x: Int) + constructor(y: Int) } //│ ╔══[PARSE ERROR] A class may only have at most one explicit constructor //│ ║ l.139: class E { @@ -146,9 +146,9 @@ class E { //│ class E :e -constructor(x: int) +constructor(x: Int) //│ ╔══[ERROR] constructor must be in a class. -//│ ║ l.149: constructor(x: int) +//│ ║ l.149: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ () //│ Code generation encountered an error: @@ -156,16 +156,16 @@ constructor(x: int) :e :js -class F(x: int) extends C(x + 1) {} +class F(x: Int) extends C(x + 1) {} class G extends C(2) {} class H extends B {} //│ ╔══[ERROR] class C expects 0 parameter(s); got 1 -//│ ║ l.159: class F(x: int) extends C(x + 1) {} +//│ ║ l.159: class F(x: Int) extends C(x + 1) {} //│ ╙── ^^^^^^^ //│ ╔══[ERROR] class C expects 0 parameter(s); got 1 //│ ║ l.160: class G extends C(2) {} //│ ╙── ^^^ -//│ class F(x: int) extends C +//│ class F(x: Int) extends C //│ class G extends C //│ class H extends B //│ // Prelude @@ -228,7 +228,7 @@ fun f(c) = F(x) then x G() then 2 _ then 0 -//│ fun f: anything -> int +//│ fun f: Object -> Int //│ // Prelude //│ class TypingUnit8 {} //│ const typing_unit8 = new TypingUnit8; @@ -243,7 +243,7 @@ fun f(c) = f(F(12)) f(new G()) -//│ int +//│ Int //│ res //│ = 12 //│ res @@ -253,7 +253,7 @@ f(new G()) :e module I { class J { - constructor(x: int) + constructor(x: Int) } module K { class L extends J(0) @@ -326,15 +326,15 @@ module I { //│ // End of generated code :js -fun g(x: int) = - class L(y: int) { - constructor(z: int) { +fun g(x: Int) = + class L(y: Int) { + constructor(z: Int) { y = z + 1 } fun ll = x + y } L -//│ fun g: (x: int,) -> (y: int,) -> L +//│ fun g: (x: Int,) -> (y: Int,) -> L //│ // Prelude //│ class TypingUnit11 {} //│ const typing_unit11 = new TypingUnit11; @@ -368,9 +368,9 @@ fun g(x: int) = let m = g(1) let n = m(2) n.ll -//│ let m: (y: int,) -> L +//│ let m: (y: Int,) -> L //│ let n: L -//│ int +//│ Int //│ // Prelude //│ class TypingUnit12 {} //│ const typing_unit12 = new TypingUnit12; @@ -403,14 +403,14 @@ let mm = new M() //│ mm //│ = M {} -fun h(z: int) = +fun h(z: Int) = class N { - constructor(x: int) { + constructor(x: Int) { log(x + z) } } N -//│ fun h: (z: int,) -> () -> N +//│ fun h: (z: Int,) -> () -> N :e // TODO: typing let hh = h(1) @@ -432,16 +432,16 @@ new hh(1) :e module O { - constructor(x: int) + constructor(x: Int) } mixin P { - constructor(x: int) + constructor(x: Int) } //│ ╔══[ERROR] Explicit module constructors are not supported -//│ ║ l.435: constructor(x: int) +//│ ║ l.435: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Explicit mixin constructors are not supported -//│ ║ l.438: constructor(x: int) +//│ ║ l.438: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ module O //│ mixin P() diff --git a/shared/src/test/diff/codegen/Shadowing.mls b/shared/src/test/diff/codegen/Shadowing.mls index 0bd6862c08..7dd871dbb4 100644 --- a/shared/src/test/diff/codegen/Shadowing.mls +++ b/shared/src/test/diff/codegen/Shadowing.mls @@ -5,7 +5,7 @@ x => x => x + 1 -//│ anything -> int -> int +//│ anything -> Int -> Int //│ // Prelude //│ let res; //│ class TypingUnit {} diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index bd1d71b43b..a3f3a881cf 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -159,7 +159,7 @@ class Foo extends Foo0 { fun foo0(n) = [super.foo0, super.foo0 + n] } //│ class Foo { -//│ fun foo0: int -> (0, int,) +//│ fun foo0: Int -> (0, Int,) //│ } diff --git a/shared/src/test/diff/codegen/TraitMethods.mls b/shared/src/test/diff/codegen/TraitMethods.mls index 5c011bc2c0..40db75fe69 100644 --- a/shared/src/test/diff/codegen/TraitMethods.mls +++ b/shared/src/test/diff/codegen/TraitMethods.mls @@ -210,4 +210,3 @@ fun x -> x.Foo //│ = [Function: res] - diff --git a/shared/src/test/diff/contys/AbstractBounds.mls b/shared/src/test/diff/contys/AbstractBounds.mls index b63a15ce62..42be5d3fde 100644 --- a/shared/src/test/diff/contys/AbstractBounds.mls +++ b/shared/src/test/diff/contys/AbstractBounds.mls @@ -111,7 +111,7 @@ fun x -> fun y -> x.Bar4 y id //│ = [Function: res] fun x -> fun y -> x.Baz4 y -//│ res: 'a -> (forall 'A 'B. ('A & 'B) -> 'B +//│ res: 'a -> (forall 'B 'A. ('A & 'B) -> 'B //│ where //│ 'a <: Test4['A, 'B]) //│ where diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index 25ce5d2e7f..469de032ef 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -5,9 +5,9 @@ class Add(lhs: E, rhs: E) -class Lit(n: int) +class Lit(n: Int) //│ class Add[E](lhs: E, rhs: E) -//│ class Lit(n: int) +//│ class Lit(n: Int) fun add11 = Add(Lit(1), Lit(2)) //│ fun add11: Add[Lit] @@ -17,7 +17,7 @@ fun eval(e) = if e is Lit(n) then n Add(l, r) then eval(l) + eval(r) -//│ fun eval: forall 'a. 'a -> int +//│ fun eval: forall 'a. 'a -> Int //│ where //│ 'a <: Add['a] | Lit @@ -25,31 +25,31 @@ fun eval(e) = mixin EvalBase { fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n: Int Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit) -> int +//│ this: {eval: 'lhs -> Int} +//│ fun eval: (Add['lhs] | Lit) -> Int //│ } module TestLang extends EvalBase //│ module TestLang { -//│ fun eval: (Add['E] | Lit) -> int +//│ fun eval: (Add['E] | Lit) -> Int //│ } //│ where //│ 'E <: Add['E] | Lit TestLang.eval -//│ (Add['E] | Lit) -> int +//│ (Add['E] | Lit) -> Int //│ where //│ 'E <: Add['E] | Lit //│ res //│ = [Function: eval] TestLang.eval(add11) -//│ int +//│ Int //│ res //│ = 3 @@ -60,7 +60,7 @@ mixin EvalNothing { mixin EvalAddLit { fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n: Int Add(l, r) then this.eval(l) + this.eval(r) else super.eval(e) } @@ -70,24 +70,24 @@ module TestLang extends EvalNothing, EvalAddLit //│ } //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} -//│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit | 'a & ~#Add & ~#Lit) -> (int | 'b) +//│ this: {eval: 'lhs -> Int} +//│ fun eval: (Add['lhs] | Lit | Object & 'a & ~#Add & ~#Lit) -> (Int | 'b) //│ } //│ module TestLang { -//│ fun eval: (Add['E] | Lit) -> int +//│ fun eval: (Add['E] | Lit) -> Int //│ } //│ where //│ 'E <: Add['E] | Lit TestLang.eval -//│ (Add['E] | Lit) -> int +//│ (Add['E] | Lit) -> Int //│ where //│ 'E <: Add['E] | Lit //│ res //│ = [Function: eval] TestLang.eval(add11) -//│ int +//│ Int //│ res //│ = 3 @@ -108,58 +108,58 @@ mixin EvalNeg { } //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} -//│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) +//│ this: {eval: 'expr -> Int} +//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> (Int | 'b) //│ } module TestLang extends EvalBase, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> int +//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'expr <: Neg['expr] | 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit +//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit TestLang.eval -//│ (Neg['expr] | 'a & ~#Neg) -> int +//│ (Neg['expr] | Object & 'a & ~#Neg) -> Int //│ where -//│ 'expr <: Neg['expr] | 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit +//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit //│ res //│ = [Function: eval] TestLang.eval(add11) -//│ int +//│ Int //│ res //│ = 3 TestLang.eval(Neg(add11)) -//│ int +//│ Int //│ res //│ = -3 TestLang.eval(Add(Lit(2), Neg(Lit(1)))) -//│ int +//│ Int //│ res //│ = 1 TestLang.eval(Neg(Neg(add11))) -//│ int +//│ Int //│ res //│ = 3 TestLang.eval(add2negadd11) -//│ int +//│ Int //│ res //│ = -1 // add11 TestLang.eval(Add(Lit(2), Neg(add11))) -//│ int +//│ Int //│ res //│ = -1 @@ -177,7 +177,7 @@ mixin EvalNegNeg_0 { //│ mixin EvalNegNeg_0() { //│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | Object & ~#Neg] | Object & 'a & ~#Neg) -> 'b //│ } // * Concise alternative, usign syntax sugar: @@ -187,33 +187,37 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | Object & ~#Neg] | Object & 'a & ~#Neg) -> 'b //│ } module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang { -//│ fun eval: 'a -> int +//│ fun eval: 'a -> Int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] +//│ 'a <: Neg['A] | Object & 'b & ~#Neg +//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit | Neg['a] fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ fun mk: forall 'E. anything -> 'E +//│ fun mk: forall 'E. Object -> 'E //│ where //│ 'E :> Add['E] | Lit | Neg['E] TestLang.eval -//│ 'a -> int +//│ 'a -> Int //│ where -//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] +//│ 'a <: Neg['A] | Object & 'b & ~#Neg +//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit | Neg['a] //│ res //│ = [Function: eval] TestLang.eval(mk(0)) -//│ int +//│ Int //│ res //│ = 0 diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index d0a4519e42..a8014956b1 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -16,15 +16,15 @@ mixin ComparePoint { (lhs.x === rhs.x) && (lhs.y === rhs.y) } //│ mixin ComparePoint() { -//│ fun compare: ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b},) -> bool +//│ fun compare: ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b},) -> Bool //│ } -class Color(str: string) { +class Color(str: Str) { fun equals(that) = str === that.str } -//│ class Color(str: string) { -//│ fun equals: {str: string} -> bool +//│ class Color(str: Str) { +//│ fun equals: {str: anything} -> Bool //│ } let Red = Color("red") @@ -38,8 +38,8 @@ mixin CompareColored { super.compare(lhs, rhs) && lhs.color.equals(rhs.color) } //│ mixin CompareColored() { -//│ super: {compare: ('a, 'b,) -> bool} -//│ fun compare: ({color: {equals: 'color -> bool}} & 'a, {color: 'color} & 'b,) -> bool +//│ super: {compare: ('a, 'b,) -> Bool} +//│ fun compare: ({color: {equals: 'color -> Bool}} & 'a, {color: 'color} & 'b,) -> Bool //│ } @@ -62,22 +62,22 @@ mixin CompareColored { // * Implicit version: mixin CompareNested { - fun compare(lhs, rhs): bool = + fun compare(lhs, rhs): Bool = super.compare(lhs, rhs) && if lhs.parent is Some(p) then rhs.parent is Some(q) and this.compare(p, q) else rhs.parent is None } //│ mixin CompareNested() { -//│ super: {compare: ('a, 'b,) -> bool} -//│ this: {compare: ('value, 'value0,) -> bool} -//│ fun compare: ({parent: Some['value] | ~Some[anything]} & 'a, {parent: Some['value0] | ~Some[anything]} & 'b,) -> bool +//│ super: {compare: ('a, 'b,) -> Bool} +//│ this: {compare: ('value, 'value0,) -> Bool} +//│ fun compare: ({parent: Object & ~#Some | Some['value]} & 'a, {parent: Object & ~#Some | Some['value0]} & 'b,) -> Bool //│ } // * Alternatively: // mixin CompareNested { -// fun compare(lhs, rhs): bool = +// fun compare(lhs, rhs): Bool = // super.compare(lhs, rhs) && // if lhs.parent is // Some(p) then rhs.parent is Some(q) and this.compare(p, q) @@ -86,17 +86,17 @@ mixin CompareNested { -class MyPoint(x: int, y: int, color: Color, parent: Some[MyPoint] | None) -//│ class MyPoint(x: int, y: int, color: Color, parent: Some[MyPoint] | None) +class MyPoint(x: Int, y: Int, color: Color, parent: Some[MyPoint] | None) +//│ class MyPoint(x: Int, y: Int, color: Color, parent: None | Some[MyPoint]) module CompareMyPoint extends ComparePoint, CompareColored, CompareNested //│ module CompareMyPoint { -//│ fun compare: ('a, 'b,) -> bool +//│ fun compare: ('a, 'b,) -> Bool //│ } //│ where -//│ 'b <: {color: 'color, parent: Some['b] | ~Some[anything], x: 'c, y: 'd} -//│ 'a <: {color: {equals: 'color -> bool}, parent: Some['a] | ~Some[anything], x: Eql['c], y: Eql['d]} +//│ 'b <: {color: 'color, parent: Object & ~#Some | Some['b], x: 'c, y: 'd} +//│ 'a <: {color: {equals: 'color -> Bool}, parent: Object & ~#Some | Some['a], x: Eql['c], y: Eql['d]} let p0 = MyPoint(0, 0, Red, None) @@ -126,22 +126,22 @@ let p5 = MyPoint(0, 1, Red, Some(p3)) CompareMyPoint.compare(p0, p1) -//│ bool +//│ Bool //│ res //│ = false CompareMyPoint.compare(p1, p2) -//│ bool +//│ Bool //│ res //│ = true CompareMyPoint.compare(p3, p4) -//│ bool +//│ Bool //│ res //│ = true CompareMyPoint.compare(p3, p5) -//│ bool +//│ Bool //│ res //│ = false diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 28c838e1b6..6bc4df3fcb 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -27,10 +27,10 @@ fun list_assoc(s, l) = Nil then NotFound() //│ fun list_assoc: forall 'a 'A. (Eql['a], Cons[{_1: 'a, _2: 'A}] | Nil,) -> (NotFound | Success['A]) -// fun list_assoc(s: string, l: Cons[{ _1: string, _2: 'b }] | Nil): NotFound | Success['b] +// fun list_assoc(s: Str, l: Cons[{ _1: Str, _2: 'b }] | Nil): NotFound | Success['b] -class Var(s: string) -//│ class Var(s: string) +class Var(s: Str) +//│ class Var(s: Str) mixin EvalVar { fun eval(sub, v) = @@ -40,19 +40,19 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (Cons[{_1: string, _2: 'A}] | Nil, Var,) -> ('A | Var) +//│ fun eval: (Cons[{_1: anything, _2: 'A}] | Nil, Var,) -> ('A | Var) //│ } -class Abs[A](x: string, t: A) +class Abs[A](x: Str, t: A) class App[A](s: A, t: A) -//│ class Abs[A](x: string, t: A) +//│ class Abs[A](x: Str, t: A) //│ class App[A](s: A, t: A) -fun gensym(): string = "fun" -//│ fun gensym: () -> string +fun gensym(): Str = "fun" +//│ fun gensym: () -> Str -fun int_to_string(x: int): string = "0" -//│ fun int_to_string: (x: int,) -> string +fun int_to_string(x: Int): Str = "0" +//│ fun int_to_string: (x: Int,) -> Str mixin EvalLambda { fun eval(sub, v) = @@ -72,13 +72,13 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b,) -> 'c} -//│ this: {eval: ('a, 's,) -> ('A & 'd) & (Cons[(string, 'd,)], 't,) -> 'c & (Cons[(string, Var,) | 'A0], 't0,) -> 'A1} -//│ fun eval: ('a & (Cons['A0] | Nil), Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'b & ~#Abs & ~#App,) -> (Abs['A1] | App['A] | 'c) +//│ this: {eval: ('a, 's,) -> ('A & 'd) & (Cons[(Str, 'd,)], 't,) -> 'c & (Cons[(Str, Var,) | 'A0], 't0,) -> 'A1} +//│ fun eval: ('a & (Cons['A0] | Nil), Abs['t0] | App['s & (Abs['t] | Object & ~#Abs)] | Object & 'b & ~#Abs & ~#App,) -> (Abs['A1] | App['A] | 'c) //│ } module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'A}] | Nil, Abs['t] | App['A0] | Var,) -> ('b | 'a) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'A}] | Nil, Abs['t] | App['A0] | Var,) -> ('b | 'a) //│ } //│ where //│ 't <: Abs['t] | App['A0] | Var @@ -123,20 +123,20 @@ Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c" //│ res //│ = Var {} -class Num(n: int) +class Numb(n: Int) class Add[A](l: A, r: A) class Mul[A](l: A, r: A) -//│ class Num(n: int) +//│ class Numb(n: Int) //│ class Add[A](l: A, r: A) //│ class Mul[A](l: A, r: A) fun map_expr(f, v) = if v is Var then v - Num then v + Numb then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) +//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Numb | Var,) -> (Add['A] | Mul['A0] | Numb | Var) mixin EvalExpr { fun eval(sub, v) = @@ -144,35 +144,35 @@ mixin EvalExpr { let vv = map_expr(eta, v) if vv is Var then super.eval(sub, vv) - Add(Num(l), Num(r)) then Num(l + r) - Mul(Num(l), Num(r)) then Num(l * r) + Add(Numb(l), Numb(r)) then Numb(l + r) + Mul(Numb(l), Numb(r)) then Numb(l * r) else v } //│ mixin EvalExpr() { //│ super: {eval: ('a, Var,) -> 'b} -//│ this: {eval: ('a, 'c,) -> anything} -//│ fun eval: ('a, 'b & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'b) +//│ this: {eval: ('a, 'c,) -> Object} +//│ fun eval: ('a, 'b & (Add['c] | Mul['c] | Numb | Var),) -> (Numb | 'b) //│ } module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'A}] | Nil, 'a & (Add['b] | Mul['b] | Num | Var),) -> ('A | Num | Var | 'a) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: Object & 'A}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> ('A | Numb | Var | 'a) //│ } //│ where -//│ 'b <: Add['b] | Mul['b] | Num | Var +//│ 'b <: Add['b] | Mul['b] | Numb | Var Test2.eval(Nil, Var("a")) -//│ Num | Var +//│ Numb | Var //│ res //│ = Var {} Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Var("a")) -//│ Abs[Var] | Num | Var +//│ Abs[Var] | Numb | Var //│ res //│ = Var {} -Test2.eval(Cons(("a", Num(1)), Nil), Var("a")) -//│ Num | Var +Test2.eval(Cons(("a", Numb(1)), Nil), Var("a")) +//│ Numb | Var //│ res //│ = Var {} @@ -182,7 +182,7 @@ Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.181: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` +//│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` //│ ║ l.181: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: @@ -191,66 +191,68 @@ Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╟── from reference: //│ ║ l.144: let vv = map_expr(eta, v) //│ ╙── ^ -//│ Abs[Var] | Num | Var | error +//│ Abs[Var] | Numb | Var | error //│ res //│ Runtime error: //│ Error: non-exhaustive case expression -Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Num(1), Var("a"))) -//│ Abs[Var] | Add[Num | Var] | Num | Var +Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Numb(1), Var("a"))) +//│ Abs[Var] | Add[Numb | Var] | Numb | Var //│ res //│ = Add {} module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'A 'a. (Cons[{_1: string, _2: 'A0}] | Nil, Abs['t] | App['A] | 'b & ~#Abs & ~#App,) -> ('c | 'a) +//│ fun eval: forall 'A 'a. (Cons[{_1: anything, _2: 'A0}] | Nil, Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App,) -> ('c | 'a) //│ } //│ where //│ 'A0 :> 'c | 'a -//│ 'c :> 'A0 | Num | Var | 'b | 'a +//│ <: Object +//│ 'c :> 'A0 | Numb | Var | 'b | 'a //│ 'a :> App['c | 'a] | Abs['c | 'a] -//│ 'b <: Add['d] | Mul['d] | Num | Var -//│ 'd <: Abs['t] | App['A] | 'b & ~#Abs & ~#App -//│ 't <: Abs['t] | App['A] | 'b & ~#Abs & ~#App -//│ 'A <: Abs['t & (Abs['t] | App['A] | 'b & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | 'b & ~#Abs & ~#App +//│ 'b <: Add['d] | Mul['d] | Numb | Var +//│ 'd <: Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App +//│ 't <: Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App +//│ 'A <: Abs['t & (Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | Object & 'b & ~#Abs & ~#App Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Num | Var +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Numb | Var //│ res //│ = Abs {} -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Num | Var] | Num | Var +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Numb | Var] | Numb | Var //│ res //│ = Var {} // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: forall 'a. (Cons[{_1: string, _2: 'A}] | Nil, 'a & (Add['b] | Mul['b] | Num | Var),) -> ('a | 'c) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'A}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> ('a | 'c) //│ } //│ where -//│ 'b <: Add['b] | Mul['b] | Num | Var +//│ 'b <: Add['b] | Mul['b] | Numb | Var //│ 'A :> 'c -//│ 'c :> 'A | Abs[Num | 'c] | App[Num | 'c] | Num | Var +//│ <: Object +//│ 'c :> 'A | Abs[Numb | 'c] | App[Numb | 'c] | Numb | Var // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.248: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.250: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Num | Var` -//│ ║ l.248: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` +//│ ║ l.250: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.134: if v is @@ -260,7 +262,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╙── ^ //│ error | 'a //│ where -//│ 'a :> Abs[Var] | Num | Var | Abs['a] | App['a] +//│ 'a :> Abs[Var] | Numb | Var | Abs['a] | App['a] //│ res //│ Runtime error: //│ Error: non-exhaustive case expression diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 36551ae44b..65d2176f88 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -6,15 +6,15 @@ // ******************* Initial System ******************* -class Vector(x: int, y: int) -//│ class Vector(x: int, y: int) +class Vector(x: Int, y: Int) +//│ class Vector(x: Int, y: Int) -class Circle(radius: int) +class Circle(radius: Int) class Outside[Region](a: Region) class Union[Region](a: Region, b: Region) class Intersect[Region](a: Region, b: Region) class Translate[Region](v: Vector, a: Region) -//│ class Circle(radius: int) +//│ class Circle(radius: Int) //│ class Outside[Region](a: Region) //│ class Union[Region](a: Region, b: Region) //│ class Intersect[Region](a: Region, b: Region) @@ -30,21 +30,21 @@ mixin SizeBase { Translate(_, a) then this.size(a) + 1 } //│ mixin SizeBase() { -//│ this: {size: ('a | 'a0 | 'a1 | 'a2) -> int} -//│ fun size: (Circle | Intersect['a1] | Outside['a] | Translate['a2] | Union['a0]) -> int +//│ this: {size: ('a | 'a0 | 'a1 | 'a2) -> Int} +//│ fun size: (Circle | Intersect['a2] | Outside['a0] | Translate['a] | Union['a1]) -> Int //│ } // ******************* Linguistic Reuse and Meta-Language Optimizations ******************* -fun round(n: number): int = 0 -//│ fun round: (n: number,) -> int +fun round(n: Num): Int = 0 +//│ fun round: (n: Num,) -> Int fun go(x, offset) = if x is 0 then Circle(1) else let shared = go(x - 1, round(offset / 2)) Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) -//│ fun go: forall 'Region. (0 | int & ~0, int,) -> 'Region +//│ fun go: forall 'Region. (0 | Int & ~0, Int,) -> 'Region //│ where //│ 'Region :> Circle | Union[Translate['Region]] @@ -75,39 +75,39 @@ mixin SizeExt { } //│ mixin SizeExt() { //│ super: {size: 'b -> 'c} -//│ this: {size: 'a -> int} -//│ fun size: (Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ) -> (int | 'c) +//│ this: {size: 'a -> Int} +//│ fun size: (Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ) -> (Int | 'c) //│ } module TestSize extends SizeBase, SizeExt //│ module TestSize { -//│ fun size: (Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ) -> int +//│ fun size: (Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ) -> Int //│ } //│ where -//│ 'a <: Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ -//│ 'b <: Circle | Intersect[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a] | Univ | 'b & ~#Empty & ~#Scale & ~#Univ] +//│ 'b <: Circle | Intersect[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Outside[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Translate[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Union[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] +//│ 'a <: Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ TestSize.size(Empty()) -//│ int +//│ Int //│ res //│ = 1 TestSize.size(circles) -//│ int +//│ Int //│ res //│ = 13 TestSize.size(Scale(Vector(1, 1), circles)) -//│ int +//│ Int //│ res //│ = 14 // ******************* Adding a New Interpretation ******************* -// a stupid power (int ** int) implementation +// a stupid power (Int ** Int) implementation fun pow(x, a) = if a is 0 then 1 else x * pow(x, a - 1) -//│ fun pow: (int, 0 | int & ~0,) -> int +//│ fun pow: (Int, 0 | Int & ~0,) -> Int mixin Contains { fun contains(a, p) = @@ -119,41 +119,41 @@ mixin Contains { Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) } //│ mixin Contains() { -//│ this: {contains: ('a | 'a0 | 'a1, 'b,) -> bool & ('a2, Vector,) -> 'c} -//│ fun contains: (Circle | Intersect['a1] | Outside['a] | Translate['a2] | Union['a0], {x: int, y: int} & 'b,) -> (bool | 'c) +//│ this: {contains: ('a | 'a0 | 'a1, 'b,) -> Bool & ('a2, Vector,) -> 'c} +//│ fun contains: (Circle | Intersect['a1] | Outside['a] | Translate['a2] | Union['a0], {x: Int, y: Int} & 'b,) -> (Bool | 'c) //│ } module TestContains extends Contains //│ module TestContains { -//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region], {x: int, y: int},) -> bool +//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: Int, y: Int},) -> Bool //│ } //│ where -//│ 'Region0 <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] -//│ 'a <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] -//│ 'a0 <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] -//│ 'Region <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] +//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] TestContains.contains(Translate(Vector(0, 0), Circle(1)), Vector(0, 0)) -//│ bool +//│ Bool //│ res //│ = true TestContains.contains(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1)), Vector(0, 0)) -//│ bool +//│ Bool //│ res //│ = true TestContains.contains(circles, Vector(0, 0)) -//│ bool +//│ Bool //│ res //│ = false // ******************* Dependencies, Complex Interpretations, and Domain-Specific Optimizations ******************* -fun toString(a: int): string = "foo" -fun concat(a: string, b: string): string = a -//│ fun toString: (a: int,) -> string -//│ fun concat: (a: string, b: string,) -> string +fun toString(a: Int): Str = "foo" +fun concat(a: Str, b: Str): Str = a +//│ fun toString: (a: Int,) -> Str +//│ fun concat: (a: Str, b: Str,) -> Str mixin Text { fun text(e) = @@ -165,33 +165,33 @@ mixin Text { Translate then concat("a translated region of size ", toString(this.size(e))) } //│ mixin Text() { -//│ this: {size: (Intersect[nothing] | Translate['Region] | Union[nothing] | 'a) -> int} -//│ fun text: (Circle | Intersect[anything] | Outside['a] | Translate['Region] | Union[anything]) -> string +//│ this: {size: (Intersect[nothing] | Translate['Region] | Union[nothing] | 'a) -> Int} +//│ fun text: (Circle | Intersect[anything] | Outside['a] | Translate['Region] | Union[anything]) -> Str //│ } :e module SizeText extends Text -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?c -> (?d | ?e | ?a | ?b | ?f)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?d -> (?e | ?a | ?b | ?c | ?f)}` does not contain member `size` //│ ║ l.165: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?b | ?a | ?f | ?d | ?c)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?d -> (?b | ?f | ?e | ?c | ?a)}` does not contain member `size` //│ ║ l.164: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?a -> (?d | ?e | ?f | ?b | ?c)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?b -> (?e | ?f | ?a | ?c | ?d)}` does not contain member `size` //│ ║ l.163: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?c -> (?d | ?b | ?a | ?f | ?e)}` does not contain member `size` +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?b | ?a | ?f | ?d | ?c)}` does not contain member `size` //│ ║ l.162: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText { -//│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> string +//│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> Str //│ } // * Note: this inferred type got *much worse* after this commit (field access type refinement) module SizeText extends SizeBase, Text //│ module SizeText { -//│ fun size: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]) -> int -//│ fun text: forall 'Region 'Region0. (Circle | Intersect[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Outside[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Translate[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Union[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]]) -> string +//│ fun size: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]) -> Int +//│ fun text: forall 'Region 'Region0. (Circle | Intersect[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Outside[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Translate[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Union[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]]) -> Str //│ } //│ where //│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] @@ -200,22 +200,22 @@ module SizeText extends SizeBase, Text //│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] SizeText.text(circles) -//│ string +//│ Str //│ res //│ = 'the union of two regions of size ' SizeText.size(circles) -//│ int +//│ Int //│ res //│ = 13 SizeText.text(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) -//│ string +//│ Str //│ res //│ = 'the intersection of two regions of size ' SizeText.size(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) -//│ int +//│ Int //│ res //│ = 4 @@ -231,8 +231,8 @@ mixin IsUniv { else false } //│ mixin IsUniv() { -//│ this: {isEmpty: 'a -> 'b, isUniv: ('a0 | 'a1) -> bool & ('a2 | 'a3) -> 'b} -//│ fun isUniv: (Intersect['a1] | Outside['a] | Scale['a3] | Translate['a2] | Union['a0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ this: {isEmpty: 'a -> 'b, isUniv: ('a0 | 'a1) -> Bool & ('a2 | 'a3) -> 'b} +//│ fun isUniv: (Intersect['a1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a3] | Translate['a2] | Union['a0] | Univ) -> (Bool | 'b) //│ } mixin IsEmpty { @@ -247,58 +247,58 @@ mixin IsEmpty { else false } //│ mixin IsEmpty() { -//│ this: {isEmpty: ('a | 'a0) -> bool & ('a1 | 'a2) -> 'b, isUniv: 'a3 -> 'b} -//│ fun isEmpty: (Intersect['a0] | Outside['a3] | Scale['a2] | Translate['a1] | Union['a] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ this: {isEmpty: ('a | 'a0) -> Bool & ('a1 | 'a2) -> 'b, isUniv: 'a3 -> 'b} +//│ fun isEmpty: (Intersect['a0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a3] | Scale['a2] | Translate['a1] | Union['a] | Univ) -> (Bool | 'b) //│ } module IsUnivIsEmpty extends IsUniv, IsEmpty //│ module IsUnivIsEmpty { -//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) -//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ) -> (Bool | 'b) +//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ) -> (Bool | 'b) //│ } //│ where -//│ 'Region0 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region1 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a3 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a4 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region2 <: Intersect['Region1] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a2 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a0 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a1 <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region <: Intersect['Region0] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region0 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ +//│ 'a <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ +//│ 'Region2 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ +//│ 'a3 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ +//│ 'a4 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ +//│ 'Region1 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ +//│ 'a2 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ +//│ 'a0 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ +//│ 'a1 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ +//│ 'Region <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ module IsUnivIsEmpty extends IsEmpty, IsUniv //│ module IsUnivIsEmpty { -//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) -//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'b) +//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ) -> (Bool | 'b) +//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ) -> (Bool | 'b) //│ } //│ where -//│ 'Region <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region2 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a3 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a4 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region1 <: Intersect['Region2] | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a2 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a1 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region0 <: Intersect['Region] | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'Region <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ +//│ 'a <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ +//│ 'Region1 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ +//│ 'a3 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ +//│ 'a4 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ +//│ 'Region2 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ +//│ 'a2 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ +//│ 'a0 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ +//│ 'a1 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ +//│ 'Region0 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ IsUnivIsEmpty.isUniv(circles) -//│ bool | 'a +//│ Bool | 'a //│ res //│ = false IsUnivIsEmpty.isEmpty(circles) -//│ bool | 'a +//│ Bool | 'a //│ res //│ = false class Foo() IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) //│ class Foo() -//│ bool | 'a +//│ Bool | 'a //│ res //│ = false @@ -315,28 +315,28 @@ mixin Eliminate { } //│ mixin Eliminate() { //│ this: {eliminate: 'a -> 'b & 'a0 -> 'Region & 'a1 -> 'Region0 & 'a2 -> 'Region1 & 'a3 -> 'Region2 & 'a4 -> 'Region3} -//│ fun eliminate: (Intersect['a2] | Outside['a0 & (Outside['a] | ~#Outside)] | Scale['a4] | Translate['a3] | Union['a1] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> (Intersect['Region1] | Outside['Region] | Scale['Region3] | Translate['Region2] | Union['Region0] | 'b) +//│ fun eliminate: (Intersect['a2] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a])] | Scale['a4] | Translate['a3] | Union['a1]) -> (Intersect['Region1] | Outside['Region] | Scale['Region3] | Translate['Region2] | Union['Region0] | 'b) //│ } module TestElim extends Eliminate //│ module TestElim { -//│ fun eliminate: forall 'Region 'b 'Region0 'c. (Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> ('d | 'b | 'c) +//│ fun eliminate: forall 'b 'Region 'c 'Region0. (Intersect['Region] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0]) -> ('d | 'c | 'b) //│ } //│ where -//│ 'd :> 'b | 'e -//│ 'b :> Outside['d | 'b | 'f] | Translate['d | 'b | 'g] | Scale['d | 'b | 'h] | Union['d | 'b | 'i | 'j] | Intersect['d | 'b | 'k | 'l] -//│ 'Region <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'k & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a0 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a1 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a2 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'g & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'Region0 <: Intersect['Region] | Outside['a & (Outside['a0] | ~#Outside)] | Scale['a1] | Translate['a2] | Union['Region0] | 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union +//│ 'd :> 'c | 'e +//│ 'c :> Outside['d | 'c | 'f] | Union['d | 'c | 'g | 'h] | Intersect['d | 'c | 'i | 'j] | Translate['d | 'c | 'k] | Scale['d | 'c | 'l] +//│ 'Region <: Intersect['Region] | Object & 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] +//│ 'a <: Intersect['Region] | Object & 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] +//│ 'a0 <: Intersect['Region] | Object & 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] +//│ 'a1 <: Intersect['Region] | Object & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] +//│ 'a2 <: Intersect['Region] | Object & 'k & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] +//│ 'Region0 <: Intersect['Region] | Object & 'g & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] TestElim.eliminate(Outside(Outside(Univ()))) //│ forall 'a. 'b | 'a //│ where //│ 'b :> forall 'a. Univ | 'a -//│ 'a :> Outside[forall 'a. Univ | 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] | Scale[forall 'a. 'b | 'a] +//│ 'a :> Outside[forall 'a. Univ | 'b | 'a] | Scale[forall 'a. 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] //│ res //│ = Univ {} @@ -354,7 +354,7 @@ fun mk(n) = if n is 3 then Intersect(mk(n), mk(n)) 4 then Translate(Vector(0, 0), mk(n)) _ then Scale(Vector(0, 0), mk(n)) -//│ fun mk: forall 'Region. anything -> 'Region +//│ fun mk: forall 'Region. Object -> 'Region //│ where //│ 'Region :> Intersect['Region] | Outside['Region] | Scale['Region] | Translate['Region] | Union['Region] @@ -372,72 +372,72 @@ TestElim.eliminate(mk(100)) module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate //│ module Lang { -//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region], {x: int, y: int},) -> bool -//│ fun eliminate: forall 'Region1 'b 'Region2 'c. (Intersect['Region2] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region1] | 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union) -> ('d | 'c | 'b) -//│ fun isEmpty: forall 'Region3 'Region4. (Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'e) -//│ fun isUniv: forall 'Region5 'Region6. (Intersect['Region5] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ) -> (bool | 'e) -//│ fun size: (Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ) -> int -//│ fun text: (Circle | Intersect[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ]) -> string +//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: Int, y: Int},) -> Bool +//│ fun eliminate: forall 'Region1 'b 'Region2 'c. (Intersect['Region2] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1]) -> ('d | 'c | 'b) +//│ fun isEmpty: forall 'Region3 'Region4. (Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ) -> (Bool | 'e) +//│ fun isUniv: forall 'Region5 'Region6. (Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ) -> (Bool | 'e) +//│ fun size: (Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ) -> Int +//│ fun text: (Circle | Intersect[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Outside[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Translate[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Union[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ]) -> Str //│ } //│ where -//│ 'a11 <: Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ -//│ 'f <: Circle | Intersect[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Outside[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Translate[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] | Union[Empty | Scale['a11] | Univ | 'f & ~#Empty & ~#Scale & ~#Univ] -//│ 'Region3 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a5 <: Intersect['Region5] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region5 <: Intersect['Region5] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a9 <: Intersect['Region5] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a10 <: Intersect['Region5] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region6 <: Intersect['Region5] | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a8 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a6 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'a7 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ -//│ 'Region4 <: Intersect['Region3] | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region4] | Univ | ~Intersect[anything] & ~Outside[anything] & ~Scale[anything] & ~Translate[anything] & ~Union[anything] & ~Univ +//│ 'f <: Circle | Intersect[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Outside[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Translate[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Union[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] +//│ 'a11 <: Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ +//│ 'Region4 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ +//│ 'a5 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ +//│ 'Region5 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ +//│ 'a9 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ +//│ 'a10 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ +//│ 'Region6 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ +//│ 'a8 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ +//│ 'a6 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ +//│ 'a7 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ +//│ 'Region3 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ //│ 'd :> 'c | 'g //│ 'c :> Outside['d | 'c | 'h] | Union['d | 'c | 'i | 'j] | Intersect['d | 'c | 'k | 'l] | Translate['d | 'c | 'm] | Scale['d | 'c | 'n] -//│ 'Region2 <: Intersect['Region2] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region1] | 'k & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a1 <: Intersect['Region2] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region1] | 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a2 <: Intersect['Region2] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region1] | 'g & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a3 <: Intersect['Region2] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region1] | 'n & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'a4 <: Intersect['Region2] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region1] | 'm & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'Region1 <: Intersect['Region2] | Outside['a1 & (Outside['a2] | ~#Outside)] | Scale['a3] | Translate['a4] | Union['Region1] | 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union -//│ 'Region0 <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] -//│ 'a <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] -//│ 'a0 <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] -//│ 'Region <: Circle | Intersect['Region0] | Outside['a] | Translate['a0] | Union['Region] +//│ 'Region2 <: Intersect['Region2] | Object & 'k & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] +//│ 'a1 <: Intersect['Region2] | Object & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] +//│ 'a2 <: Intersect['Region2] | Object & 'g & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] +//│ 'a3 <: Intersect['Region2] | Object & 'n & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] +//│ 'a4 <: Intersect['Region2] | Object & 'm & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] +//│ 'Region1 <: Intersect['Region2] | Object & 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] +//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] Lang.size(circles) -//│ int +//│ Int //│ res //│ = 13 Lang.contains(circles, Vector(0, 0)) -//│ bool +//│ Bool //│ res //│ = false Lang.text(circles) -//│ string +//│ Str //│ res //│ = 'the union of two regions of size ' Lang.isUniv(circles) -//│ bool | 'a +//│ Bool | 'a //│ res //│ = false Lang.isEmpty(circles) -//│ bool | 'a +//│ Bool | 'a //│ res //│ = false Lang.size(Lang.eliminate(circles)) -//│ int +//│ Int //│ res //│ = 13 :re Lang.size(mk(100)) -//│ int +//│ Int //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -477,28 +477,28 @@ Lang.text(mk(100)) //│ ╟── Note: constraint arises from reference: //│ ║ l.160: if e is //│ ╙── ^ -//│ error | string +//│ Str | error //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded :re Lang.isUniv(mk(100)) -//│ bool | 'a +//│ Bool | 'a //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded :re Lang.isEmpty(mk(100)) -//│ bool | 'a +//│ Bool | 'a //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded :re Lang.size(Lang.eliminate(mk(100))) -//│ int +//│ Int //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded diff --git a/shared/src/test/diff/fcp-lit/CPS_LB.mls b/shared/src/test/diff/fcp-lit/CPS_LB.mls index a140270b59..47e7e1560d 100644 --- a/shared/src/test/diff/fcp-lit/CPS_LB.mls +++ b/shared/src/test/diff/fcp-lit/CPS_LB.mls @@ -80,7 +80,7 @@ def f t = (s x x t x x e) // (* If the token is used twice, we must reveive two arguments *) def g t1 t2 = (s x x t1 x (s x t2 x e) e) -//│ g: (() -> List["x"] -> (forall 'a 'b. () -> List['a] -> (() -> List["x" | 'a] -> 'b) -> 'b) -> 'c -> (forall 'a0 'd. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'd) -> 'd) -> 'e) -> (() -> List["x"] -> (forall 'f 'a. () -> List['a] -> (() -> List["x" | 'a] -> 'f) -> 'f) -> (forall 'g 'a0. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'g) -> 'g) -> 'c) -> 'e +//│ g: (() -> List["x"] -> (forall 'a 'b. () -> List['a] -> (() -> List["x" | 'a] -> 'b) -> 'b) -> 'c -> (forall 'a0 'd. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'd) -> 'd) -> 'e) -> (() -> List["x"] -> (forall 'a 'f. () -> List['a] -> (() -> List["x" | 'a] -> 'f) -> 'f) -> (forall 'a0 'g. () -> List[string] -> () -> List['a0] -> (() -> List['a0 | string] -> 'g) -> 'g) -> 'c) -> 'e // (* This does not type. It requires first-class polymorphism. *) def h t = g t t diff --git a/shared/src/test/diff/fcp-lit/MLF.mls b/shared/src/test/diff/fcp-lit/MLF.mls index 238eb9fcb1..91c9d6d738 100644 --- a/shared/src/test/diff/fcp-lit/MLF.mls +++ b/shared/src/test/diff/fcp-lit/MLF.mls @@ -144,7 +144,7 @@ let f = choose id in (f auto, f succ) //│ res: (forall 'b 'a. (forall 'a0. 'a0 -> 'a0 & 'b) -> ('a -> 'a | 'b), forall 'b. (int & 'b) -> (int | 'b),) let f = choose id in (f auto2, f succ) -//│ res: (forall 'a 'b 'c. ('a -> 'b & 'a & 'c) -> ('b | 'c), forall 'c. (int & 'c) -> (int | 'c),) +//│ res: (forall 'a 'b 'c. ('c -> 'a & 'c & 'b) -> ('a | 'b), forall 'b. (int & 'b) -> (int | 'b),) // ------------ Sec 6 ------------ @@ -198,12 +198,12 @@ let tmp = I I in K K fun z -> (z omegad) fun z -> (z omega) //│ res: ((forall 'a. (forall 'a0. 'a0 -> 'a0) -> 'a -> 'a) -> 'b) -> 'b -//│ res: ((forall 'a 'b. ('a -> 'b & 'a) -> 'b) -> 'c) -> 'c +//│ res: ((forall 'a 'b. ('b -> 'a & 'b) -> 'a) -> 'c) -> 'c (fun y -> fun z -> z y) omegad (fun y -> fun z -> z y) omega //│ res: ((forall 'a. (forall 'a0. 'a0 -> 'a0) -> 'a -> 'a) -> 'b) -> 'b -//│ res: ((forall 'a 'b. ('a -> 'b & 'a) -> 'b) -> 'c) -> 'c +//│ res: ((forall 'a 'b. ('b -> 'a & 'b) -> 'a) -> 'c) -> 'c fun z -> omegad z fun z -> omega z diff --git a/shared/src/test/diff/fcp-lit/PolyML.mls b/shared/src/test/diff/fcp-lit/PolyML.mls index 07b3ca2f28..f65e3e37a7 100644 --- a/shared/src/test/diff/fcp-lit/PolyML.mls +++ b/shared/src/test/diff/fcp-lit/PolyML.mls @@ -76,7 +76,7 @@ def mem[a]: a -> List[a] -> bool :RecursiveTypes // needed for this recursive def rec def mem x l = match_list l false (fun head -> fun tail -> if eq head x then true else mem x tail) -//│ anything -> List[?] -> bool +//│ anything -> List[?] -> Bool //│ <: mem: //│ anything -> List[?] -> bool :NoRecursiveTypes diff --git a/shared/src/test/diff/fcp-lit/PolyML2.mls b/shared/src/test/diff/fcp-lit/PolyML2.mls index 92a67cfbc7..f2737e8ee7 100644 --- a/shared/src/test/diff/fcp-lit/PolyML2.mls +++ b/shared/src/test/diff/fcp-lit/PolyML2.mls @@ -26,7 +26,7 @@ rec def mem x l = case l of { Nil -> false | Cons -> if eq l.head x then true else mem x l.tail } -//│ mem: anything -> 'a -> bool +//│ mem: anything -> 'a -> Bool //│ where //│ 'a <: (Cons[?] with {tail: 'a}) | Nil @@ -46,11 +46,11 @@ class Collection[a]: { l: List[a] } method Mem x = mem x this.l method Fold f x = fold_left f x this.l //│ Defined class Collection[+a] -//│ Defined Collection.Mem: Collection[?] -> anything -> bool +//│ Defined Collection.Mem: Collection[?] -> anything -> Bool //│ Defined Collection.Fold: Collection['a] -> ('b -> 'a -> 'b) -> 'b -> 'b def coll_mem c x = c.Mem x -//│ coll_mem: Collection[?] -> anything -> bool +//│ coll_mem: Collection[?] -> anything -> Bool // typo in the paper? it was `fun x -> fun y -> ...` def simple_and_double c = diff --git a/shared/src/test/diff/fcp-lit/QML.mls b/shared/src/test/diff/fcp-lit/QML.mls index be62497912..1c9e437474 100644 --- a/shared/src/test/diff/fcp-lit/QML.mls +++ b/shared/src/test/diff/fcp-lit/QML.mls @@ -202,7 +202,7 @@ def sstep = fun xx -> xx (fun (xinit, xsub) -> then xsub r1 (div i 2) else xsub r2 (div i 2) in fun f -> f (init, sub)) -//│ ((forall 'a 'b 'c 'd 'e. ('c -> 'e, 'b -> int -> 'a,) -> (('c -> ('e, 'e,), ('b, 'b,) -> (int & number) -> 'a,) -> 'd) -> 'd) -> 'f) -> 'f +//│ ((forall 'a 'b 'c 'd 'e. ('a -> 'b, 'd -> int -> 'e,) -> (('a -> ('b, 'b,), ('d, 'd,) -> (int & number) -> 'e,) -> 'c) -> 'c) -> 'f) -> 'f //│ <: sstep: //│ ExSmall -> ExSmall //│ ╔══[ERROR] Type error in def definition @@ -440,7 +440,7 @@ def step = fun xx -> xx (fun ((((xinit, xsub), xupdate), xfold),) -> else (fst r, xupdate (snd r) (div i 2) a) in let fold f b r = xfold f (xfold f b (fst r)) (snd r) in fun f -> f ((((init, sub), update), fold),) ) -//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm 'n 'o 'p. ((('c -> 'o, 'm -> int -> 'b,), 'g -> int -> 'k -> 'l & 'a -> int -> 'k -> 'e,), 'h -> ('d -> 'p -> 'n & 'i -> 'f -> 'd),) -> (((('c -> ('o, 'o,), ('m, 'm,) -> (int & number) -> 'b,), forall 'q 'r. ('g & 'q, 'a & 'r,) -> (int & number) -> 'k -> ('l | 'q, 'r | 'e,),), 'h -> 'i -> ('f, 'p,) -> 'n,) -> 'j) -> 'j) -> 's) -> 's +//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm 'n 'o 'p. ((('h -> 'e, 'o -> int -> 'm,), 'k -> int -> 'b -> 'f & 'i -> int -> 'b -> 'j,), 'a -> ('d -> 'g -> 'c & 'n -> 'l -> 'd),) -> (((('h -> ('e, 'e,), ('o, 'o,) -> (int & number) -> 'm,), forall 'q 'r. ('k & 'q, 'i & 'r,) -> (int & number) -> 'b -> ('f | 'q, 'r | 'j,),), 'a -> 'n -> ('l, 'g,) -> 'c,) -> 'p) -> 'p) -> 's) -> 's //│ <: step: //│ ExSig -> ExSig //│ ╔══[ERROR] Type error in def definition diff --git a/shared/src/test/diff/fcp/Church_CT.mls b/shared/src/test/diff/fcp/Church_CT.mls index 6965026c3a..01a9aea278 100644 --- a/shared/src/test/diff/fcp/Church_CT.mls +++ b/shared/src/test/diff/fcp/Church_CT.mls @@ -37,10 +37,10 @@ def succ: (forall 'N. ('N -> 'N) -> ('N -> 'N)) -> (forall 'M. ('M -> 'M) -> ('M :e // * Since "sound extrusion" def succ n f x = f (n f x) -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'b <: 'c -> 'd -//│ 'a <: 'b -> 'e -> 'c)) +//│ 'b <: 'd -> 'e +//│ 'a <: 'b -> 'c -> 'd)) //│ <: succ: //│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -67,10 +67,10 @@ def succ: ChurchInt -> ChurchInt :e // * Since "sound extrusion" def succ n f x = f (n f x) -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'd -> 'c //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'a <: 'b -> 'd -> 'e +//│ 'b <: 'e -> 'c)) //│ <: succ: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -93,10 +93,10 @@ def succD: forall 'M. ChurchInt -> ('M -> 'M) -> ('M -> 'M) def succD n f x = f (n f x) //│ succD: ChurchInt -> ('M -> 'M) -> 'M -> 'M //│ = -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'a <: 'b -> 'e -> 'c -//│ 'b <: 'c -> 'd)) +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'd -> 'e)) //│ <: succD: //│ ChurchInt -> ('M -> 'M) -> 'M -> 'M //│ = [Function: succD] @@ -284,8 +284,8 @@ def z f x = x def s n f x = f (n f x) //│ s: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'd -> 'e)) //│ = [Function: s] zero = z @@ -359,33 +359,33 @@ s: ChurchInt -> ChurchInt n1 = s z -//│ n1: 'a -> (forall 'b 'c 'd. 'b -> 'd +//│ n1: 'a -> (forall 'b 'c 'd. 'd -> 'c //│ where -//│ 'a <: 'c -> 'd -//│ anything -> (forall 'e. 'e -> 'e) <: 'a -> 'b -> 'c) +//│ anything -> (forall 'e. 'e -> 'e) <: 'a -> 'd -> 'b +//│ 'a <: 'b -> 'c) //│ = [Function (anonymous)] n2 = s (s z) -//│ n2: 'a -> (forall 'b 'c 'd. 'b -> 'd +//│ n2: 'a -> (forall 'b 'c 'd. 'c -> 'b //│ where +//│ 'a <: 'd -> 'b //│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h //│ where //│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g -//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c -//│ 'a <: 'c -> 'd) +//│ 'e <: 'g -> 'h) <: 'a -> 'c -> 'd) //│ = [Function (anonymous)] n3 = s (s (s z)) //│ n3: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ 'a <: 'c -> 'd +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'h -> 'g //│ where -//│ forall 'i. 'i -> (forall 'j 'k 'l. 'k -> 'j +//│ forall 'i. 'i -> (forall 'j 'k 'l. 'j -> 'l //│ where -//│ 'i <: 'l -> 'j -//│ anything -> (forall 'm. 'm -> 'm) <: 'i -> 'k -> 'l) <: 'e -> 'f -> 'g -//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c -//│ 'a <: 'c -> 'd) +//│ anything -> (forall 'm. 'm -> 'm) <: 'i -> 'j -> 'k +//│ 'i <: 'k -> 'l) <: 'e -> 'h -> 'f +//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] @@ -396,8 +396,8 @@ wrap x = { x } n1w = n1 wrap //│ n1w: 'a -> 'b //│ where -//│ forall 'c. 'c -> {x: 'c} <: 'd -> 'b -//│ anything -> (forall 'e. 'e -> 'e) <: (forall 'c. 'c -> {x: 'c}) -> 'a -> 'd +//│ anything -> (forall 'c. 'c -> 'c) <: (forall 'd. 'd -> {x: 'd}) -> 'a -> 'e +//│ forall 'd. 'd -> {x: 'd} <: 'e -> 'b //│ = [Function (anonymous)] n1w 0 @@ -478,8 +478,8 @@ res.x.x.x + 1 sz = s zero //│ sz: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ ChurchInt <: 'a -> 'b -> 'c -//│ 'a <: 'c -> 'd) +//│ 'a <: 'c -> 'd +//│ ChurchInt <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] :ns @@ -517,21 +517,21 @@ s zero : ChurchInt sz1 = sz 1 //│ sz1: 'a -> 'b //│ where -//│ 1 <: 'c -> 'b //│ ChurchInt <: 1 -> 'a -> 'c +//│ 1 <: 'c -> 'b //│ = [Function (anonymous)] :ns sz1 -//│ res: forall 'a 'b 'c. 'a +//│ res: forall 'a 'b 'c. 'c //│ where -//│ 'a :> forall 'd 'e 'f 'g. 'e -> 'g +//│ 'c :> forall 'd 'e 'f 'g. 'e -> 'g //│ where -//│ 'c <: 'f -> 'g -//│ 'b <: 'c -> 'd +//│ 'b <: 'f -> 'g +//│ 'a <: 'b -> 'd //│ 'd <: 'e -> 'f -//│ 'b :> ChurchInt -//│ 'c :> 1 +//│ 'a :> ChurchInt +//│ 'b :> 1 //│ = [Function (anonymous)] :e // * Since inconsistent constrained types (delayed error from above) @@ -588,10 +588,10 @@ rec def to_ch_s n = else s (to_ch_s (n - 1)) //│ to_ch_s: int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'b 'd 'e 'f. ('d & 'f) -> ('d | 'e) +//│ 'a :> forall 'b. 'b -> (forall 'b 'c 'd 'e 'f. ('c & 'f) -> ('c | 'e) //│ where -//│ 'b <: 'c -> 'e -//│ 'a <: 'b -> 'f -> 'c) +//│ 'a <: 'b -> 'f -> 'd +//│ 'b <: 'd -> 'e) //│ = [Function: to_ch_s] rec def to_ch n = @@ -599,20 +599,20 @@ rec def to_ch n = else s (to_ch (n - 1)) //│ to_ch: int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'c 'd 'e 'b 'f. ('e & 'd) -> ('e | 'f) +//│ 'a :> forall 'b. 'b -> (forall 'c 'b 'd 'e 'f. ('c & 'f) -> ('c | 'd) //│ where -//│ 'a <: 'b -> 'd -> 'c -//│ 'b <: 'c -> 'f) +//│ 'a <: 'b -> 'f -> 'e +//│ 'b <: 'e -> 'd) //│ = [Function: to_ch] :e // * Needs distrib (see below) to_church_ty = to_ch //│ int -> 'a //│ where -//│ 'a :> forall 'b. 'b -> (forall 'b 'c 'd 'e 'f. ('f & 'd) -> ('f | 'e) +//│ 'a :> forall 'b. 'b -> (forall 'b 'c 'd 'e 'f. ('d & 'f) -> ('d | 'e) //│ where -//│ 'b <: 'c -> 'e -//│ 'a <: 'b -> 'd -> 'c) +//│ 'a <: 'b -> 'f -> 'c +//│ 'b <: 'c -> 'e) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -710,10 +710,10 @@ rec def to_ch_A1 n = //│ ╟── Note: constraint arises from application: //│ ║ l.284: def s n f x = f (n f x) //│ ╙── ^^^^^ -//│ to_ch_A1: int -> (forall 'a. 'a -> (forall 'b 'c 'a 'd 'e. ('b & 'c) -> ('c | 'd) +//│ to_ch_A1: int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('d & 'e) -> ('e | 'b) //│ where -//│ 'a <: 'e -> 'd -//│ ChurchInt <: 'a -> 'b -> 'e)) +//│ ChurchInt <: 'a -> 'd -> 'c +//│ 'a <: 'c -> 'b)) //│ = [Function: to_ch_A1] :precise-rec-typing @@ -722,10 +722,10 @@ rec def to_ch_A1 n = else s (to_ch_A1 (n - 1) : ChurchInt) //│ to_ch_A1: 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'a 'd 'e. ('b & 'd) -> ('d | 'e) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('d & 'c) -> ('c | 'b) //│ where -//│ 'a <: 'c -> 'e -//│ ChurchInt <: 'a -> 'b -> 'c)) +//│ ChurchInt <: 'a -> 'd -> 'e +//│ 'a <: 'e -> 'b)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ = [Function: to_ch_A11] @@ -735,10 +735,10 @@ rec def to_ch_A1 n = to_church_ty = to_ch_A1 //│ 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('d & 'e) -> ('e | 'b) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd 'e. ('b & 'c) -> ('c | 'd) //│ where -//│ 'a <: 'c -> 'b -//│ ChurchInt <: 'a -> 'd -> 'c)) +//│ 'a <: 'e -> 'd +//│ ChurchInt <: 'a -> 'b -> 'e)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ <: to_church_ty: @@ -856,18 +856,18 @@ to_church_ty = to_ch_A2 def to_church_mix n = if n == 0 then z else s (to_church (n - 1)) -//│ to_church_mix: int -> (forall 'a. 'a -> (forall 'b 'c 'd 'a 'e. ('c & 'e) -> ('e | 'd) +//│ to_church_mix: int -> (forall 'a. 'a -> (forall 'b 'c 'd 'e 'a. ('e & 'b) -> ('b | 'c) //│ where -//│ ChurchInt <: 'a -> 'c -> 'b -//│ 'a <: 'b -> 'd)) +//│ ChurchInt <: 'a -> 'e -> 'd +//│ 'a <: 'd -> 'c)) //│ = [Function: to_church_mix] :e to_church_ty = to_church_mix -//│ int -> (forall 'a. 'a -> (forall 'b 'a 'c 'd 'e. ('e & 'b) -> ('b | 'c) +//│ int -> (forall 'a. 'a -> (forall 'b 'c 'a 'd 'e. ('c & 'd) -> ('d | 'e) //│ where -//│ ChurchInt <: 'a -> 'e -> 'd -//│ 'a <: 'd -> 'c)) +//│ ChurchInt <: 'a -> 'c -> 'b +//│ 'a <: 'b -> 'e)) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -944,10 +944,10 @@ to_church_ty = to_ch //│ 'd <: 'a -> 'b -> 'e //│ 'a <: 'e -> 'c) //│ where -//│ 'd :> forall 'f 'g 'h 'i 'j. 'f -> (('g & 'j) -> ('g | 'h) +//│ 'd :> forall 'f 'g 'h 'i 'j. 'g -> (('h & 'i) -> ('h | 'j) //│ where -//│ 'f <: 'i -> 'h -//│ 'd <: 'f -> 'j -> 'i) +//│ 'd <: 'g -> 'i -> 'f +//│ 'g <: 'f -> 'j) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -960,13 +960,13 @@ to_church_ty = to_ch to_church_ty = to_ch_simplif //│ anything -> 'a -> ('b -> 'c //│ where -//│ 'd <: 'a -> 'b -> 'e -//│ 'a <: 'e -> 'c) +//│ 'a <: 'd -> 'c +//│ 'e <: 'a -> 'b -> 'd) //│ where -//│ 'd :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i //│ where //│ 'f <: 'h -> 'i -//│ 'd <: 'f -> 'g -> 'h) +//│ 'e <: 'f -> 'g -> 'h) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -979,13 +979,13 @@ to_church_ty = to_ch_simplif rec def to_ch_simplif n = s (to_ch_simplif n) //│ to_ch_simplif: anything -> 'a -> ('b -> 'c //│ where -//│ 'd <: 'a -> 'b -> 'e -//│ 'a <: 'e -> 'c) +//│ 'a <: 'd -> 'c +//│ 'e <: 'a -> 'b -> 'd) //│ where -//│ 'd :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i //│ where //│ 'f <: 'h -> 'i -//│ 'd <: 'f -> 'g -> 'h) +//│ 'e <: 'f -> 'g -> 'h) //│ = [Function: to_ch_simplif1] :e // * Since the removal of "recursive definition hacks" @@ -995,10 +995,10 @@ to_church_ty = to_ch_simplif //│ 'a <: 'd -> 'c //│ 'e <: 'a -> 'b -> 'd) //│ where -//│ 'e :> forall 'f 'g 'h 'i. 'g -> ('h -> 'f +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i //│ where -//│ 'g <: 'i -> 'f -//│ 'e <: 'g -> 'h -> 'i) +//│ 'e <: 'f -> 'g -> 'h +//│ 'f <: 'h -> 'i) //│ <: to_church_ty: //│ int -> ChurchInt //│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) @@ -1012,10 +1012,10 @@ to_church_ty = to_ch_simplif to_church_ty = to_ch_A1 //│ 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. 'd -> (('c & 'e) -> ('e | 'a) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. 'e -> (('a & 'b) -> ('b | 'c) //│ where -//│ 'd <: 'b -> 'a -//│ ChurchInt <: 'd -> 'c -> 'b)) +//│ ChurchInt <: 'e -> 'a -> 'd +//│ 'e <: 'd -> 'c)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ <: to_church_ty: @@ -1030,8 +1030,8 @@ to_church_ty = to_ch_A1 to_church_ty = to_church_mix //│ int -> 'a -> ('b -> ('b | 'c) //│ where -//│ 'a <: 'd -> 'c -//│ ChurchInt <: 'a -> 'b -> 'd) +//│ ChurchInt <: 'a -> 'b -> 'd +//│ 'a <: 'd -> 'c) //│ <: to_church_ty: //│ int -> ChurchInt //│ = [Function: to_church_mix] diff --git a/shared/src/test/diff/fcp/Church_ST.mls b/shared/src/test/diff/fcp/Church_ST.mls index d7e7374430..5159f066cf 100644 --- a/shared/src/test/diff/fcp/Church_ST.mls +++ b/shared/src/test/diff/fcp/Church_ST.mls @@ -62,13 +62,13 @@ def succ n f x = f (n f x) // * This explicit annotation makes it type check; like in MLF: def succ (n: (forall 'N. ('N -> 'N) -> ('N -> 'N))) = fun f -> fun x -> f (n f x) -//│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'a 'N0 'N1. ('N0 -> ('N0 & 'N1) & 'N1 -> 'a) -> ('N0 & 'N1) -> 'a) +//│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'N0 'N1 'a. ('N0 -> ('N0 & 'N1) & 'N1 -> 'a) -> ('N0 & 'N1) -> 'a) //│ <: succ: //│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ = [Function: succ2] def succ (n: ChurchInt) f x = f (n f x) -//│ ChurchInt -> (forall 'a 'N 'N0. ('N -> ('N & 'N0) & 'N0 -> 'a) -> ('N & 'N0) -> 'a) +//│ ChurchInt -> (forall 'N 'N0 'a. ('N -> ('N & 'N0) & 'N0 -> 'a) -> ('N & 'N0) -> 'a) //│ <: succ: //│ (forall 'N. ('N -> 'N) -> 'N -> 'N) -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ = [Function: succ3] @@ -493,16 +493,16 @@ sz = s zero :ns sz -//│ res: forall 'a 'b 'c 'd 'N. 'c +//│ res: forall 'N 'a 'b 'c 'd. 'd //│ where -//│ 'c :> forall 'e 'f 'g. 'e -> (forall 'h 'i. 'h -> 'i) +//│ 'd :> forall 'e 'f 'g. 'e -> (forall 'h 'i. 'h -> 'i) //│ 'i :> 'g -//│ 'h <: 'a -//│ 'a <: 'N -//│ 'e <: 'f -> 'g & 'd -//│ 'd <: 'N -> 'N -//│ 'N <: 'b -//│ 'f :> 'b +//│ 'h <: 'b +//│ 'b <: 'N +//│ 'e <: 'f -> 'g & 'a +//│ 'a <: 'N -> 'N +//│ 'N <: 'c +//│ 'f :> 'c //│ = [Function (anonymous)] sz: ChurchInt @@ -611,7 +611,7 @@ rec def to_ch_s_A1 n = //│ = [Function: to_ch_s_A1] to_church_ty = to_ch_s_A1 -//│ int -> (forall 'N 'N0 'a. ('N -> ('N & 'N0) & 'N0 -> 'a) -> (forall 'b. ('N & 'N0 & 'b) -> ('b | 'a))) +//│ int -> (forall 'a 'N 'N0. ('N -> ('N & 'N0) & 'N0 -> 'a) -> (forall 'b. ('N & 'N0 & 'b) -> ('b | 'a))) //│ <: to_church_ty: //│ int -> ChurchInt //│ = [Function: to_ch_s_A1] diff --git a/shared/src/test/diff/fcp/ConstrainedTypes1.mls b/shared/src/test/diff/fcp/ConstrainedTypes1.mls index 1d3d61ba61..21956fa1af 100644 --- a/shared/src/test/diff/fcp/ConstrainedTypes1.mls +++ b/shared/src/test/diff/fcp/ConstrainedTypes1.mls @@ -11,7 +11,7 @@ foo x = foo x = let _ = log (succ x.prop) in x -//│ foo: forall 'a 'prop. 'a -> 'a +//│ foo: forall 'prop 'a. 'a -> 'a //│ where //│ 'a <: {prop: 'prop} //│ 'prop <: int diff --git a/shared/src/test/diff/fcp/ConstrainedTypes2.mls b/shared/src/test/diff/fcp/ConstrainedTypes2.mls index 6c1e88ca44..68aa1e37dc 100644 --- a/shared/src/test/diff/fcp/ConstrainedTypes2.mls +++ b/shared/src/test/diff/fcp/ConstrainedTypes2.mls @@ -111,8 +111,8 @@ def test extr x = //│ 'a <: 0 -> 'b //│ 'd <: 'b -> 'c)) -> anything) -> 'd -> (anything -> 'e //│ where -//│ 'd <: 'f -> 'e -//│ 0 <: 0 -> 'f) +//│ 0 <: 0 -> 'f +//│ 'd <: 'f -> 'e) //│ = [Function: test1] :e @@ -128,8 +128,8 @@ test 0 //│ ╙── ^^^^^^ //│ res: 'a -> (anything -> 'b //│ where -//│ 0 <: 0 -> 'c -//│ 'a <: 'c -> 'b) | error +//│ 'a <: 'c -> 'b +//│ 0 <: 0 -> 'c) | error //│ = [Function (anonymous)] def test extr x = @@ -137,8 +137,8 @@ def test extr x = in f 0 //│ test: anything -> 'a -> (anything -> 'b //│ where -//│ 0 <: 0 -> 'c -//│ 'a <: 'c -> 'b) +//│ 'a <: 'c -> 'b +//│ 0 <: 0 -> 'c) //│ = [Function: test2] // Error delayed by inconsistent constrained types diff --git a/shared/src/test/diff/fcp/FCPTony.mls b/shared/src/test/diff/fcp/FCPTony.mls index 0c50732ff2..a33b5bb635 100644 --- a/shared/src/test/diff/fcp/FCPTony.mls +++ b/shared/src/test/diff/fcp/FCPTony.mls @@ -142,13 +142,13 @@ add :ns def f x y = add x y -//│ f: forall 'a. 'a -> (forall 'b 'c 'd 'e 'f. 'e -> 'f +//│ f: forall 'a. 'a -> (forall 'b 'c 'd 'e 'f. 'c -> 'd //│ where -//│ 'a <: (ChurchInt -> ChurchInt) -> 'b) +//│ 'a <: (ChurchInt -> ChurchInt) -> 'e) //│ where -//│ 'e <: 'c -//│ 'b <: 'c -> 'd -//│ 'd <: 'f +//│ 'c <: 'f +//│ 'e <: 'f -> 'b +//│ 'b <: 'd //│ = [Function: f] // :ds diff --git a/shared/src/test/diff/fcp/FunnyId.mls b/shared/src/test/diff/fcp/FunnyId.mls index e0f434b95a..9f524947cd 100644 --- a/shared/src/test/diff/fcp/FunnyId.mls +++ b/shared/src/test/diff/fcp/FunnyId.mls @@ -188,14 +188,14 @@ rec def id1 x = if true then x else id1 id1 x id1 id //│ res: 'a -> 'b | 'id //│ where -//│ 'a :> forall 'c 'id 'd. 'a -> 'b | 'id +//│ 'a :> forall 'id 'c 'd. 'a -> 'b | 'id //│ <: 'b -//│ 'b :> forall 'c 'id 'd. 'id +//│ 'b :> forall 'id 'c 'd. 'id //│ <: 'a -> 'b -//│ 'id :> 'd -> 'c -//│ 'd :> 'id -//│ <: 'c +//│ 'id :> 'c -> 'd //│ 'c :> 'id -//│ <: 'd -> 'c +//│ <: 'd +//│ 'd :> 'id +//│ <: 'c -> 'd diff --git a/shared/src/test/diff/fcp/MoreChurch.mls b/shared/src/test/diff/fcp/MoreChurch.mls index 2317d48416..0ce07cfe66 100644 --- a/shared/src/test/diff/fcp/MoreChurch.mls +++ b/shared/src/test/diff/fcp/MoreChurch.mls @@ -68,7 +68,7 @@ def add n m = n succ m // * Note: cycle check fails when generalizing curried lambdas add_ty = add -//│ ((forall 'a 'b 'c 'd. ('b -> 'c -> 'd) -> ('d -> 'a & 'b) -> 'c -> 'a) -> 'e -> 'f) -> 'e -> 'f +//│ ((forall 'a 'b 'c 'd. ('a -> 'b -> 'c) -> ('c -> 'd & 'a) -> 'b -> 'd) -> 'e -> 'f) -> 'e -> 'f //│ <: add_ty: //│ ChurchInt -> ChurchInt -> ChurchInt //│ = [Function: add] @@ -90,12 +90,12 @@ def mul_ty: ChurchInt -> ChurchInt -> ChurchInt //│ = def mul n m = n (add m) zero -//│ mul: ((forall 'a 'b 'c 'd 'e. ('c -> 'd -> 'e & 'a) -> (('e -> ('e & 'b) & 'c) -> 'd -> 'b | 'a)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g +//│ mul: ((forall 'a 'b 'c 'd 'e. ('b -> 'a -> 'c & 'd) -> (('c -> ('c & 'e) & 'b) -> 'a -> 'e | 'd)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g //│ = [Function: mul] // * Note: cycle check fails when generalizing curried lambdas mul_ty = mul -//│ ((forall 'a 'b 'c 'd 'e. ('c -> 'b -> 'd & 'e) -> (('d -> ('d & 'a) & 'c) -> 'b -> 'a | 'e)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g +//│ ((forall 'a 'b 'c 'd 'e. ('e -> 'd -> 'b & 'a) -> (('b -> ('b & 'c) & 'e) -> 'd -> 'c | 'a)) -> (forall 'f. anything -> 'f -> 'f) -> 'g) -> ChurchInt -> 'g //│ <: mul_ty: //│ ChurchInt -> ChurchInt -> ChurchInt //│ = [Function: mul] @@ -230,11 +230,11 @@ def pred n = let s p = pair (snd p) (succ (snd p)) in let z = pair zero zero in fst (n s z) -//│ pred: ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('e -> 'd -> 'a & 'b)) -> ('b -> (('a -> 'c & 'e) -> 'd -> 'c) -> 'f) -> 'f) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k +//│ pred: ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('a -> 'e -> 'd & 'c)) -> ('c -> (('d -> 'b & 'a) -> 'e -> 'b) -> 'f) -> 'f) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k //│ = [Function: pred1] // * Note: cycle check fails when generalizing curried lambdas pred_ty = pred -//│ ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('f -> 'e -> 'c & 'a)) -> ('a -> (('c -> 'b & 'f) -> 'e -> 'b) -> 'd) -> 'd) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k +//│ ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('d -> 'b -> 'f & 'e)) -> ('e -> (('f -> 'c & 'd) -> 'b -> 'c) -> 'a) -> 'a) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k //│ <: pred_ty: //│ ChurchInt -> ChurchInt //│ = [Function: pred1] diff --git a/shared/src/test/diff/fcp/NestedDataTypes.mls b/shared/src/test/diff/fcp/NestedDataTypes.mls index d81f219abd..58f8a9bfbd 100644 --- a/shared/src/test/diff/fcp/NestedDataTypes.mls +++ b/shared/src/test/diff/fcp/NestedDataTypes.mls @@ -230,11 +230,11 @@ rec def map f tree = case tree of { } //│ map: 'map //│ where -//│ 'map :> forall 'value 'value0 'subTree 'A 'a 'subTree0. 'a -> ((Leaf[?] & {value: 'value0} | (Node[?] with {subTree: 'subTree0})) -> (Leaf['value] | (Node['A] with {subTree: 'subTree})) +//│ 'map :> forall 'subTree 'a 'A 'value 'subTree0 'value0. 'a -> ((Leaf[?] & {value: 'value0} | (Node[?] with {subTree: 'subTree})) -> (Leaf['value] | (Node['A] with {subTree: 'subTree0})) //│ where //│ 'map <: (forall 'b 'c 'd 'e. ('b, 'd,) -> ('c, 'e,) //│ where -//│ 'a <: 'b -> 'c & 'd -> 'e) -> 'subTree0 -> (PerfectTree[Two['A]] & 'subTree) +//│ 'a <: 'b -> 'c & 'd -> 'e) -> 'subTree -> (PerfectTree[Two['A]] & 'subTree0) //│ 'a <: 'value0 -> 'value) //│ = [Function: map1] diff --git a/shared/src/test/diff/fcp/Proofs.mls b/shared/src/test/diff/fcp/Proofs.mls index 2ee3205792..07e68c5a20 100644 --- a/shared/src/test/diff/fcp/Proofs.mls +++ b/shared/src/test/diff/fcp/Proofs.mls @@ -456,7 +456,7 @@ def DNE_to_EM dne = dne (fun not_em -> not_em (Right { v = fun a -> not_em (Left { v = a }) })) //│ DNE_to_EM: ((forall 'a 'b. ((Right & {v: forall 'v 'c. 'v -> 'c //│ where -//│ 'a <: (Left with {v: 'v}) -> 'c}) -> 'b & 'a) -> 'b) -> 'd) -> 'd +//│ 'b <: (Left with {v: 'v}) -> 'c}) -> 'a & 'b) -> 'a) -> 'd) -> 'd :e // * Still needs distrib! (after "sound extrusion") DNE_to_EM: DNE -> EM diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls b/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls index b90da69a6c..71d094d0d7 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_CT.mls @@ -48,9 +48,9 @@ baseImpl = ArraysImpl { update = fun r -> fun (i : int) -> fun a -> a; fold = fun f -> fun b -> fun r -> f r b } -//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c 'd. 'a -> 'b -> ('c -> 'd +//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c 'd. 'c -> 'd -> ('a -> 'b //│ where -//│ 'a <: 'c -> 'b -> 'd), init: forall 'e. 'e -> 'e, sub: forall 'f. 'f -> int -> 'f, update: forall 'g. anything -> int -> 'g -> 'g} +//│ 'c <: 'a -> 'd -> 'b), init: forall 'e. 'e -> 'e, sub: forall 'f. 'f -> int -> 'f, update: forall 'g. anything -> int -> 'g -> 'g} //│ = ArraysImpl { //│ init: [Function: init], //│ sub: [Function: sub], @@ -84,7 +84,7 @@ def simpleStepImpl arrImpl = ArraysImpl { //│ where //│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 //│ where -//│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'A7 'Rep6. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) +//│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where //│ 'c <: ArraysRep['A7, 'Rep6])}) //│ where @@ -107,35 +107,35 @@ def simpleStepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> Arrays def simpleStepImpl2 arr = arr simpleStepImpl -//│ simpleStepImpl2: ((forall 'A 'a 'c 'Rep 'Rep0 'Rep1 'A0 'A1 'A2 'A3 'Rep2. (ArraysRep[in 'A3 | 'A2 & 'A | 'A1 | 'A & 'A0 out 'A3 & 'A2 & 'A1 & 'A0, in 'a & 'Rep2 & 'Rep | 'Rep2 | 'Rep1 out 'Rep & 'a & 'Rep2 & ('a | 'Rep1)] & 'c) -> (ArraysImpl['A, 'Rep0] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b +//│ simpleStepImpl2: ((forall 'A 'Rep 'Rep0 'A0 'Rep1 'a 'A1 'Rep2 'A2 'A3 'c. (ArraysRep[in 'A0 | 'A1 & 'A3 | 'A2 | 'A3 & 'A out 'A0 & 'A1 & 'A2 & 'A, in 'a & 'Rep0 & 'Rep2 | 'Rep0 | 'Rep out 'Rep2 & 'a & 'Rep0 & ('a | 'Rep)] & 'c) -> (ArraysImpl['A3, 'Rep1] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b //│ where -//│ 'c <: ArraysRep['A4, 'Rep3] -//│ 'd <: 'A4 -> 'b -> 'b), init: forall 'Rep4 'A5. 'A5 -> ('Rep4, "initialized",) +//│ 'd <: 'A4 -> 'b -> 'b +//│ 'c <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) //│ where -//│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 +//│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'A6 'Rep5. ('Rep5, anything,) -> (int -> 'A6 //│ where //│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where //│ 'c <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e //│ where -//│ 'Rep0 :> ('a, "initialized" | "updated",) +//│ 'Rep1 :> ('a, "initialized" | "updated",) //│ <: (nothing, anything,) -//│ 'A <: nothing +//│ 'A3 <: nothing //│ = [Function: simpleStepImpl2] simpleStepImpl2_ty = simpleStepImpl2 -//│ ((forall 'a 'A 'Rep 'A0 'A1 'A2 'c 'Rep0 'Rep1 'Rep2 'A3. (ArraysRep[in 'A3 | 'A1 & 'A | 'A0 | 'A & 'A2 out 'A3 & 'A1 & 'A0 & 'A2, in 'a & 'Rep & 'Rep0 | 'Rep | 'Rep1 out 'Rep0 & 'a & 'Rep & ('a | 'Rep1)] & 'c) -> (ArraysImpl['A, 'Rep2] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b +//│ ((forall 'Rep 'A 'a 'Rep0 'A0 'c 'Rep1 'A1 'A2 'A3 'Rep2. (ArraysRep[in 'A1 | 'A3 & 'A | 'A0 | 'A & 'A2 out 'A1 & 'A3 & 'A0 & 'A2, in 'c & 'Rep1 & 'Rep0 | 'Rep1 | 'Rep out 'Rep0 & 'c & 'Rep1 & ('c | 'Rep)] & 'a) -> (ArraysImpl['A, 'Rep2] with {fold: forall 'd 'b 'A4 'Rep3. 'd -> 'b -> (('Rep3, anything,) -> 'b //│ where //│ 'd <: 'A4 -> 'b -> 'b -//│ 'c <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) +//│ 'a <: ArraysRep['A4, 'Rep3]), init: forall 'A5 'Rep4. 'A5 -> ('Rep4, "initialized",) //│ where -//│ 'c <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 +//│ 'a <: ArraysRep['A5, 'Rep4], sub: forall 'Rep5 'A6. ('Rep5, anything,) -> (int -> 'A6 //│ where -//│ 'c <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) +//│ 'a <: ArraysRep['A6, 'Rep5]), update: forall 'Rep6 'A7. ('Rep6, anything,) -> int -> ('A7 -> ('Rep6, "updated",) //│ where -//│ 'c <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e +//│ 'a <: ArraysRep['A7, 'Rep6])})) -> 'e) -> 'e //│ where -//│ 'Rep2 :> ('a, "initialized" | "updated",) +//│ 'Rep2 :> ('c, "initialized" | "updated",) //│ <: (nothing, anything,) //│ 'A <: nothing //│ <: simpleStepImpl2_ty: @@ -183,20 +183,20 @@ def simpleStep: Arrays['a] -> Arrays['a] def simpleStep arr f = f (simpleStepImpl2 arr) //│ 'a -> (('c -> 'd) -> 'd //│ where -//│ 'a <: (forall 'e 'f 'A 'A0 'Rep. (ArraysRep[in anything out nothing, in 'A0 out nothing] & 'e) -> (ArraysImpl['A, 'Rep] with {fold: forall 'b 'A1 'Rep0 'g. 'g -> 'b -> (('Rep0, 'A0,) -> 'b +//│ 'a <: (forall 'Rep 'A 'e 'f 'A0. (ArraysRep[in anything out nothing, in 'A out nothing] & 'e) -> (ArraysImpl['A0, 'Rep] with {fold: forall 'Rep0 'g 'b 'A1. 'g -> 'b -> (('Rep0, 'A,) -> 'b //│ where -//│ 'e <: ArraysRep['A1, 'Rep0] -//│ 'g <: 'A1 -> 'b -> 'b), init: forall 'A2 'Rep1. 'A2 -> ('Rep1, "initialized",) +//│ 'g <: 'A1 -> 'b -> 'b +//│ 'e <: ArraysRep['A1, 'Rep0]), init: forall 'A2 'Rep1. 'A2 -> ('Rep1, "initialized",) //│ where -//│ 'e <: ArraysRep['A2, 'Rep1], sub: forall 'Rep2 'A3. ('Rep2, 'A0,) -> (int -> 'A3 +//│ 'e <: ArraysRep['A2, 'Rep1], sub: forall 'Rep2 'A3. ('Rep2, 'A,) -> (int -> 'A3 //│ where -//│ 'e <: ArraysRep['A3, 'Rep2]), update: forall 'Rep3 'A4. ('Rep3, 'A0,) -> int -> ('A4 -> ('Rep3, "updated",) +//│ 'e <: ArraysRep['A3, 'Rep2]), update: forall 'Rep3 'A4. ('Rep3, 'A,) -> int -> ('A4 -> ('Rep3, "updated",) //│ where //│ 'e <: ArraysRep['A4, 'Rep3])})) -> 'c) //│ where //│ 'Rep :> ('f, "initialized" | "updated",) -//│ <: (nothing, 'A0,) -//│ 'A <: nothing +//│ <: (nothing, 'A,) +//│ 'A0 <: nothing //│ <: simpleStep: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -314,7 +314,7 @@ sb (fun arr -> let r2 = arr.Update (arr.Init true) 1 false in (arr.Sub r2 0, arr.Sub r2 1) ) -//│ res: (bool, bool,) +//│ res: (Bool, Bool,) //│ = [ false, false ] @@ -355,19 +355,19 @@ def stepImpl arrImpl = ArraysImpl { else (r0, arrImpl.Update r1 (div i 2) a); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f (arrImpl.Fold f b r0) r1 } -//│ stepImpl: (ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 & 'A4 | 'A3 & 'A5 | 'A3 & ('A6 | 'A7) out 'A & 'A0 & 'A6 & 'A7 & 'A1 & 'A2 & 'A4 & 'A5, in 'Rep | 'Rep0 | 'Rep1 | 'Rep2 out 'Rep3 & 'a & 'Rep4 & 'c & ('a | 'Rep1) & ('c | 'Rep2)] & 'd) -> (ArraysImpl['A3, 'Rep5] with {fold: forall 'Rep6 'A8 'e 'b 'A9 'b0 'Rep7 'f. 'f -> 'e -> (('Rep7, 'Rep6,) -> ('e | 'b) +//│ stepImpl: (ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 & 'A4 | 'A3 & 'A5 | 'A3 & ('A6 | 'A7) out 'A & 'A0 & 'A6 & 'A7 & 'A1 & 'A2 & 'A4 & 'A5, in 'a & 'Rep & 'Rep0 | 'Rep | 'c & 'Rep1 & 'Rep2 | 'Rep1 | 'Rep3 | 'Rep4 out 'Rep0 & 'a & 'Rep & 'Rep2 & 'c & 'Rep1 & ('a | 'Rep3) & ('c | 'Rep4)] & 'd) -> (ArraysImpl['A3, 'Rep5] with {fold: forall 'b 'e 'Rep6 'b0 'A8 'f 'Rep7 'A9. 'e -> 'f -> (('Rep7, 'Rep6,) -> ('f | 'b0) //│ where -//│ 'f <: 'A9 -> ('e | 'b) -> 'b & 'A8 -> ('b0 | 'e) -> ('b & 'b0) -//│ 'd <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7]), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) +//│ 'd <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7] +//│ 'e <: 'A9 -> ('f | 'b0) -> 'b0 & 'A8 -> ('b | 'f) -> ('b0 & 'b)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) //│ where -//│ 'd <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'Rep10 'Rep11 'A12 'g 'A13. ('Rep11, 'Rep10,) -> (int -> 'g +//│ 'd <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'g 'A12 'Rep10 'Rep11 'A13. ('Rep11, 'Rep10,) -> (int -> 'g //│ where -//│ 'd <: ArraysRep['A13, 'Rep11] & ArraysRep['A12, 'Rep10]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) +//│ 'd <: ArraysRep['A12, 'Rep11] & ArraysRep['A13, 'Rep10]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where //│ 'd <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])}) //│ where -//│ 'A12 <: 'g //│ 'A13 <: 'g +//│ 'A12 <: 'g //│ 'Rep5 :> ('a, 'c,) //│ <: (nothing, nothing,) //│ 'A3 <: nothing @@ -378,41 +378,41 @@ def stepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl[' //│ = def stepImpl2 arr = arr stepImpl -//│ stepImpl2: ((forall 'Rep 'A 'A0 'A1 'Rep0 'A2 'A3 'Rep1 'A4 'A5 'A6 'Rep2 'Rep3 'Rep4 'a 'A7 'c 'Rep5 'd. (ArraysRep[in 'A6 | 'A7 | 'A | 'A1 | 'A5 & 'A3 | 'A5 & 'A0 | 'A5 & ('A2 | 'A4) out 'A6 & 'A7 & 'A2 & 'A4 & 'A & 'A1 & 'A3 & 'A0, in 'Rep3 | 'Rep1 | 'Rep0 | 'Rep out 'Rep2 & 'd & 'Rep5 & 'c & ('d | 'Rep0) & ('c | 'Rep)] & 'a) -> (ArraysImpl['A5, 'Rep4] with {fold: forall 'A8 'b 'Rep6 'e 'A9 'f 'Rep7 'b0. 'e -> 'f -> (('Rep7, 'Rep6,) -> ('f | 'b) +//│ stepImpl2: ((forall 'A 'Rep 'A0 'A1 'A2 'Rep0 'Rep1 'A3 'Rep2 'a 'A4 'Rep3 'c 'A5 'Rep4 'Rep5 'd 'A6 'A7. (ArraysRep[in 'A7 | 'A | 'A6 | 'A5 | 'A2 & 'A0 | 'A2 & 'A3 | 'A2 & ('A4 | 'A1) out 'A7 & 'A & 'A4 & 'A1 & 'A6 & 'A5 & 'A0 & 'A3, in 'a & 'Rep3 & 'Rep1 | 'Rep3 | 'c & 'Rep2 & 'Rep5 | 'Rep2 | 'Rep0 | 'Rep out 'Rep1 & 'a & 'Rep3 & 'Rep5 & 'c & 'Rep2 & ('a | 'Rep0) & ('c | 'Rep)] & 'd) -> (ArraysImpl['A2, 'Rep4] with {fold: forall 'A8 'b 'A9 'Rep6 'b0 'Rep7 'e 'f. 'f -> 'e -> (('Rep7, 'Rep6,) -> ('e | 'b0) //│ where -//│ 'a <: ArraysRep['A8, 'Rep6] & ArraysRep['A9, 'Rep7] -//│ 'e <: 'A8 -> ('f | 'b) -> 'b & 'A9 -> ('b0 | 'f) -> ('b & 'b0)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) +//│ 'd <: ArraysRep['A9, 'Rep6] & ArraysRep['A8, 'Rep7] +//│ 'f <: 'A9 -> ('e | 'b0) -> 'b0 & 'A8 -> ('b | 'e) -> ('b0 & 'b)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) //│ where -//│ 'a <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'g 'Rep10 'A12 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g +//│ 'd <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'A12 'Rep10 'A13 'Rep11 'g. ('Rep10, 'Rep11,) -> (int -> 'g //│ where -//│ 'a <: ArraysRep['A13, 'Rep10] & ArraysRep['A12, 'Rep11]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) +//│ 'd <: ArraysRep['A12, 'Rep10] & ArraysRep['A13, 'Rep11]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where -//│ 'a <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h +//│ 'd <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h //│ where -//│ 'A12 <: 'g //│ 'A13 <: 'g -//│ 'Rep4 :> ('d, 'c,) +//│ 'A12 <: 'g +//│ 'Rep4 :> ('a, 'c,) //│ <: (nothing, nothing,) -//│ 'A5 <: nothing +//│ 'A2 <: nothing //│ = [Function: stepImpl2] stepImpl2_ty = stepImpl2 -//│ ((forall 'Rep 'Rep0 'Rep1 'a 'A 'A0 'A1 'A2 'c 'Rep2 'A3 'A4 'Rep3 'A5 'Rep4 'Rep5 'A6 'A7 'd. (ArraysRep[in 'A4 | 'A3 | 'A7 | 'A5 | 'A2 & 'A0 | 'A2 & 'A6 | 'A2 & ('A1 | 'A) out 'A4 & 'A3 & 'A1 & 'A & 'A7 & 'A5 & 'A0 & 'A6, in 'Rep5 | 'Rep4 | 'Rep | 'Rep0 out 'Rep1 & 'a & 'Rep2 & 'd & ('a | 'Rep) & ('d | 'Rep0)] & 'c) -> (ArraysImpl['A2, 'Rep3] with {fold: forall 'A8 'Rep6 'Rep7 'e 'b 'f 'b0 'A9. 'e -> 'f -> (('Rep6, 'Rep7,) -> ('f | 'b0) +//│ ((forall 'Rep 'Rep0 'Rep1 'A 'a 'A0 'A1 'Rep2 'A2 'Rep3 'A3 'A4 'Rep4 'A5 'c 'd 'A6 'A7 'Rep5. (ArraysRep[in 'A1 | 'A5 | 'A | 'A3 | 'A4 & 'A7 | 'A4 & 'A0 | 'A4 & ('A2 | 'A6) out 'A1 & 'A5 & 'A2 & 'A6 & 'A & 'A3 & 'A7 & 'A0, in 'c & 'Rep1 & 'Rep2 | 'Rep1 | 'd & 'Rep4 & 'Rep3 | 'Rep4 | 'Rep | 'Rep0 out 'Rep2 & 'c & 'Rep1 & 'Rep3 & 'd & 'Rep4 & ('c | 'Rep) & ('d | 'Rep0)] & 'a) -> (ArraysImpl['A4, 'Rep5] with {fold: forall 'Rep6 'Rep7 'e 'b 'A8 'b0 'f 'A9. 'f -> 'e -> (('Rep7, 'Rep6,) -> ('e | 'b0) //│ where -//│ 'c <: ArraysRep['A9, 'Rep7] & ArraysRep['A8, 'Rep6] -//│ 'e <: 'A9 -> ('f | 'b0) -> 'b0 & 'A8 -> ('b | 'f) -> ('b0 & 'b)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A11 & 'A10) -> ('Rep9, 'Rep8,) +//│ 'a <: ArraysRep['A8, 'Rep6] & ArraysRep['A9, 'Rep7] +//│ 'f <: 'A8 -> ('e | 'b0) -> 'b0 & 'A9 -> ('b | 'e) -> ('b0 & 'b)), init: forall 'A10 'Rep8 'A11 'Rep9. ('A10 & 'A11) -> ('Rep8, 'Rep9,) //│ where -//│ 'c <: ArraysRep['A11, 'Rep9] & ArraysRep['A10, 'Rep8], sub: forall 'A12 'g 'Rep10 'A13 'Rep11. ('Rep10, 'Rep11,) -> (int -> 'g +//│ 'a <: ArraysRep['A10, 'Rep8] & ArraysRep['A11, 'Rep9], sub: forall 'A12 'Rep10 'A13 'g 'Rep11. ('Rep11, 'Rep10,) -> (int -> 'g //│ where -//│ 'c <: ArraysRep['A12, 'Rep10] & ArraysRep['A13, 'Rep11]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) +//│ 'a <: ArraysRep['A13, 'Rep11] & ArraysRep['A12, 'Rep10]), update: forall 'Rep12 'Rep13 'A14 'A15. ('Rep12, 'Rep13,) -> int -> (('A14 & 'A15) -> ('Rep12, 'Rep13,) //│ where -//│ 'c <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h +//│ 'a <: ArraysRep['A14, 'Rep12] & ArraysRep['A15, 'Rep13])})) -> 'h) -> 'h //│ where -//│ 'A13 <: 'g //│ 'A12 <: 'g -//│ 'Rep3 :> ('a, 'd,) +//│ 'A13 <: 'g +//│ 'Rep5 :> ('c, 'd,) //│ <: (nothing, nothing,) -//│ 'A2 <: nothing +//│ 'A4 <: nothing //│ <: stepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, 'Rep,)] //│ = [Function: stepImpl2] @@ -426,19 +426,19 @@ def step: Arrays['a] -> Arrays['a] def step arr f = f (stepImpl2 arr) //│ 'a -> (('c -> 'd) -> 'd //│ where -//│ 'a <: (forall 'A 'e 'f 'g. (ArraysRep[in anything out nothing, in anything out 'e & 'f] & 'g) -> (ArraysImpl['A, ('e, 'f,)] with {fold: forall 'Rep 'b 'h 'A0 'i 'Rep0 'A1 'b0. 'i -> 'h -> (('Rep0, 'Rep,) -> ('h | 'b0) +//│ 'a <: (forall 'A 'e 'f 'g. (ArraysRep[in anything out nothing, in anything out 'e & 'f] & 'g) -> (ArraysImpl['A, ('e, 'f,)] with {fold: forall 'b 'Rep 'A0 'Rep0 'A1 'h 'i 'b0. 'i -> 'h -> (('Rep0, 'Rep,) -> ('h | 'b) //│ where -//│ 'g <: ArraysRep['A1, 'Rep] & ArraysRep['A0, 'Rep0] -//│ 'i <: 'A1 -> ('h | 'b0) -> 'b0 & 'A0 -> ('b | 'h) -> ('b0 & 'b)), init: forall 'A2 'Rep1 'A3 'Rep2. ('A2 & 'A3) -> ('Rep1, 'Rep2,) +//│ 'g <: ArraysRep['A0, 'Rep] & ArraysRep['A1, 'Rep0] +//│ 'i <: 'A0 -> ('h | 'b) -> 'b & 'A1 -> ('b0 | 'h) -> ('b & 'b0)), init: forall 'A2 'Rep1 'A3 'Rep2. ('A2 & 'A3) -> ('Rep1, 'Rep2,) //│ where -//│ 'g <: ArraysRep['A2, 'Rep1] & ArraysRep['A3, 'Rep2], sub: forall 'Rep3 'A4 'Rep4 'j 'A5. ('Rep4, 'Rep3,) -> (int -> 'j +//│ 'g <: ArraysRep['A2, 'Rep1] & ArraysRep['A3, 'Rep2], sub: forall 'j 'A4 'Rep3 'A5 'Rep4. ('Rep4, 'Rep3,) -> (int -> 'j //│ where -//│ 'g <: ArraysRep['A5, 'Rep4] & ArraysRep['A4, 'Rep3]), update: forall 'Rep5 'Rep6 'A6 'A7. ('Rep5, 'Rep6,) -> int -> (('A6 & 'A7) -> ('Rep5, 'Rep6,) +//│ 'g <: ArraysRep['A4, 'Rep4] & ArraysRep['A5, 'Rep3]), update: forall 'A6 'A7 'Rep5 'Rep6. ('Rep5, 'Rep6,) -> int -> (('A6 & 'A7) -> ('Rep5, 'Rep6,) //│ where //│ 'g <: ArraysRep['A6, 'Rep5] & ArraysRep['A7, 'Rep6])})) -> 'c) //│ where -//│ 'A4 <: 'j //│ 'A5 <: 'j +//│ 'A4 <: 'j //│ 'A <: nothing //│ <: step: //│ Arrays['a] -> Arrays['a] @@ -585,7 +585,7 @@ ssb (fun arr -> let r2 = arr.Update (arr.Init true) 1 false in (arr.Sub r2 0, arr.Sub r2 1) ) -//│ res: (bool, bool,) +//│ res: (Bool, Bool,) //│ = [ true, false ] diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls b/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls index 7fe726a3f9..5cb80d1ce2 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_ST.mls @@ -48,7 +48,7 @@ baseImpl = ArraysImpl { update = fun r -> fun (i : int) -> fun a -> a; fold = fun f -> fun b -> fun r -> f r b } -//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> int -> 'e, update: forall 'f. anything -> int -> 'f -> 'f} +//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c. ('c -> 'a -> 'b) -> 'a -> 'c -> 'b, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> int -> 'e, update: forall 'f. anything -> int -> 'f -> 'f} //│ = ArraysImpl { //│ init: [Function: init], //│ sub: [Function: sub], @@ -88,20 +88,20 @@ def simpleStepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> Arrays def simpleStepImpl2 arr = arr simpleStepImpl -//│ simpleStepImpl2: ((forall 'Rep 'A 'A0 'Rep0 'A1 'Rep1 'A2 'A3 'Rep2. ArraysRep[in 'A | 'A2 | 'A1 | 'A3 & 'A0 out 'A2 & 'A3, in 'Rep2 | 'Rep0 out nothing] -> (ArraysImpl['A0, 'Rep] with {fold: forall 'b. ('A3 -> 'b -> 'b) -> 'b -> ('Rep0, anything,) -> 'b, init: 'A -> (nothing, "initialized",), sub: ('Rep2, anything,) -> int -> 'A2, update: forall 'a. ('Rep1 & 'a, anything,) -> int -> 'A1 -> ('a, "updated",)})) -> 'c) -> 'c +//│ simpleStepImpl2: ((forall 'A 'Rep 'A0 'A1 'Rep0 'A2 'A3 'Rep1 'Rep2. ArraysRep[in 'A1 | 'A0 | 'A | 'A3 & 'A2 out 'A0 & 'A3, in 'Rep1 | 'Rep out nothing] -> (ArraysImpl['A2, 'Rep0] with {fold: forall 'b. ('A3 -> 'b -> 'b) -> 'b -> ('Rep, anything,) -> 'b, init: 'A1 -> (nothing, "initialized",), sub: ('Rep1, anything,) -> int -> 'A0, update: forall 'a. ('Rep2 & 'a, anything,) -> int -> 'A -> ('a, "updated",)})) -> 'c) -> 'c //│ where -//│ 'Rep :> (nothing, "initialized" | "updated",) -//│ <: (nothing, anything,) -//│ 'A0 :> 'A2 +//│ 'Rep0 :> (nothing, "initialized" | "updated",) +//│ <: (nothing, anything,) +//│ 'A2 :> 'A0 //│ <: nothing //│ = [Function: simpleStepImpl2] simpleStepImpl2_ty = simpleStepImpl2 -//│ ((forall 'A 'A0 'Rep 'Rep0 'A1 'Rep1 'Rep2 'A2 'A3. ArraysRep[in 'A3 | 'A1 | 'A0 | 'A & 'A2 out 'A1 & 'A, in 'Rep0 | 'Rep2 out nothing] -> (ArraysImpl['A2, 'Rep1] with {fold: forall 'b. ('A -> 'b -> 'b) -> 'b -> ('Rep2, anything,) -> 'b, init: 'A3 -> (nothing, "initialized",), sub: ('Rep0, anything,) -> int -> 'A1, update: forall 'a. ('Rep & 'a, anything,) -> int -> 'A0 -> ('a, "updated",)})) -> 'c) -> 'c +//│ ((forall 'A 'Rep 'A0 'A1 'Rep0 'A2 'Rep1 'Rep2 'A3. ArraysRep[in 'A0 | 'A | 'A3 | 'A2 & 'A1 out 'A & 'A2, in 'Rep | 'Rep2 out nothing] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b. ('A2 -> 'b -> 'b) -> 'b -> ('Rep2, anything,) -> 'b, init: 'A0 -> (nothing, "initialized",), sub: ('Rep, anything,) -> int -> 'A, update: forall 'a. ('Rep0 & 'a, anything,) -> int -> 'A3 -> ('a, "updated",)})) -> 'c) -> 'c //│ where //│ 'Rep1 :> (nothing, "initialized" | "updated",) //│ <: (nothing, anything,) -//│ 'A2 :> 'A1 +//│ 'A1 :> 'A //│ <: nothing //│ <: simpleStepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, string,)] @@ -149,11 +149,11 @@ def simpleStep: Arrays['a] -> Arrays['a] :e // * Since "sound extrusion" def simpleStep arr f = f (simpleStepImpl2 arr) -//│ ((forall 'Rep 'Rep0 'A 'A0 'Rep1 'A1 'A2 'Rep2 'A3. ArraysRep[in 'A3 | 'A | 'A1 | 'A0 & 'A2 out 'A & 'A0, in 'Rep2 | 'Rep out nothing] -> (ArraysImpl['A2, 'Rep1] with {fold: forall 'b. ('A0 -> 'b -> 'b) -> 'b -> ('Rep, anything,) -> 'b, init: 'A3 -> (nothing, "initialized",), sub: ('Rep2, anything,) -> int -> 'A, update: forall 'a. ('Rep0 & 'a, anything,) -> int -> 'A1 -> ('a, "updated",)})) -> 'c) -> ('c -> 'd) -> 'd +//│ ((forall 'Rep 'A 'Rep0 'A0 'Rep1 'Rep2 'A1 'A2 'A3. ArraysRep[in 'A3 | 'A | 'A1 | 'A2 & 'A0 out 'A & 'A2, in 'Rep0 | 'Rep1 out nothing] -> (ArraysImpl['A0, 'Rep] with {fold: forall 'b. ('A2 -> 'b -> 'b) -> 'b -> ('Rep1, anything,) -> 'b, init: 'A3 -> (nothing, "initialized",), sub: ('Rep0, anything,) -> int -> 'A, update: forall 'a. ('Rep2 & 'a, anything,) -> int -> 'A1 -> ('a, "updated",)})) -> 'c) -> ('c -> 'd) -> 'd //│ where -//│ 'Rep1 :> (nothing, "initialized" | "updated",) -//│ <: (nothing, anything,) -//│ 'A2 :> 'A +//│ 'Rep :> (nothing, "initialized" | "updated",) +//│ <: (nothing, anything,) +//│ 'A0 :> 'A //│ <: nothing //│ <: simpleStep: //│ Arrays['a] -> Arrays['a] @@ -279,7 +279,7 @@ sb (fun arr -> let r2 = arr.Update (arr.Init true) 1 false in (arr.Sub r2 0, arr.Sub r2 1) ) -//│ res: (bool, bool,) +//│ res: (Bool, Bool,) //│ = [ false, false ] @@ -319,7 +319,7 @@ def stepImpl arrImpl = ArraysImpl { else (r0, arrImpl.Update r1 (div i 2) a); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f (arrImpl.Fold f b r0) r1 } -//│ stepImpl: ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 | 'A4 | 'A5 & ('A6 | 'A7) out 'A1 & 'A2 & 'A6 & 'A7, in 'Rep | 'Rep0 | 'Rep1 | 'Rep2 out nothing] -> (ArraysImpl['A5, 'Rep3] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A7 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep2, 'Rep1,) -> 'b, init: ('A & 'A0) -> (nothing, nothing,), sub: ('Rep, 'Rep0,) -> int -> ('A1 | 'A2), update: forall 'a 'c. ('Rep4 & 'c, 'Rep5 & 'a,) -> int -> ('A3 & 'A4) -> ('c, 'a,)}) +//│ stepImpl: ArraysRep[in 'A | 'A0 | 'A1 | 'A2 | 'A3 | 'A4 | 'A5 & ('A6 | 'A7) out 'A1 & 'A2 & 'A6 & 'A7, in 'Rep | 'Rep0 | 'Rep1 | 'Rep2 out nothing] -> (ArraysImpl['A5, 'Rep3] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A7 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep2, 'Rep1,) -> 'b, init: ('A & 'A0) -> (nothing, nothing,), sub: ('Rep, 'Rep0,) -> int -> ('A1 | 'A2), update: forall 'a 'c. ('Rep4 & 'a, 'Rep5 & 'c,) -> int -> ('A3 & 'A4) -> ('a, 'c,)}) //│ where //│ 'Rep3 :> ('d, 'e,) //│ <: (nothing, nothing,) @@ -332,21 +332,21 @@ def stepImpl2_ty: (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl[' //│ = def stepImpl2 arr = arr stepImpl -//│ stepImpl2: ((forall 'A 'A0 'A1 'Rep 'Rep0 'A2 'A3 'Rep1 'Rep2 'A4 'a 'Rep3 'A5 'Rep4 'Rep5 'A6 'c 'A7. ArraysRep[in 'A2 | 'A4 | 'A7 | 'A0 | 'A5 | 'A3 | 'A1 & ('A6 | 'A) out 'A7 & 'A0 & 'A6 & 'A, in 'Rep | 'Rep1 | 'Rep3 | 'Rep5 out nothing] -> (ArraysImpl['A1, 'Rep4] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep5, 'Rep3,) -> 'b, init: ('A2 & 'A4) -> (nothing, nothing,), sub: ('Rep, 'Rep1,) -> int -> ('A7 | 'A0), update: forall 'd 'e. ('Rep2 & 'd, 'Rep0 & 'e,) -> int -> ('A5 & 'A3) -> ('d, 'e,)})) -> 'f) -> 'f +//│ stepImpl2: ((forall 'Rep 'Rep0 'A 'Rep1 'A0 'A1 'A2 'Rep2 'a 'A3 'A4 'c 'Rep3 'Rep4 'A5 'A6 'A7 'Rep5. ArraysRep[in 'A7 | 'A6 | 'A1 | 'A3 | 'A0 | 'A | 'A4 & ('A2 | 'A5) out 'A1 & 'A3 & 'A2 & 'A5, in 'Rep4 | 'Rep0 | 'Rep1 | 'Rep2 out nothing] -> (ArraysImpl['A4, 'Rep5] with {fold: forall 'b 'b0. ('A2 -> 'b -> 'b & 'A5 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep2, 'Rep1,) -> 'b, init: ('A7 & 'A6) -> (nothing, nothing,), sub: ('Rep4, 'Rep0,) -> int -> ('A1 | 'A3), update: forall 'd 'e. ('Rep & 'd, 'Rep3 & 'e,) -> int -> ('A0 & 'A) -> ('d, 'e,)})) -> 'f) -> 'f //│ where -//│ 'Rep4 :> ('a, 'c,) +//│ 'Rep5 :> ('a, 'c,) //│ <: (nothing, nothing,) -//│ 'A1 :> anything +//│ 'A4 :> anything //│ <: nothing //│ = [Function: stepImpl2] stepImpl2_ty = stepImpl2 -//│ ((forall 'A 'A0 'a 'Rep 'A1 'A2 'A3 'c 'A4 'A5 'Rep0 'Rep1 'A6 'A7 'Rep2 'Rep3 'Rep4 'Rep5. ArraysRep[in 'A3 | 'A1 | 'A4 | 'A7 | 'A0 | 'A2 | 'A5 & ('A6 | 'A) out 'A4 & 'A7 & 'A6 & 'A, in 'Rep0 | 'Rep3 | 'Rep | 'Rep5 out nothing] -> (ArraysImpl['A5, 'Rep2] with {fold: forall 'b 'b0. ('A6 -> 'b -> 'b & 'A -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep5, 'Rep,) -> 'b, init: ('A3 & 'A1) -> (nothing, nothing,), sub: ('Rep0, 'Rep3,) -> int -> ('A4 | 'A7), update: forall 'd 'e. ('Rep4 & 'd, 'Rep1 & 'e,) -> int -> ('A0 & 'A2) -> ('d, 'e,)})) -> 'f) -> 'f +//│ ((forall 'Rep 'A 'Rep0 'A0 'A1 'A2 'A3 'A4 'Rep1 'A5 'a 'Rep2 'A6 'A7 'c 'Rep3 'Rep4 'Rep5. ArraysRep[in 'A7 | 'A5 | 'A2 | 'A0 | 'A3 | 'A6 | 'A & ('A1 | 'A4) out 'A2 & 'A0 & 'A1 & 'A4, in 'Rep2 | 'Rep | 'Rep1 | 'Rep3 out nothing] -> (ArraysImpl['A, 'Rep4] with {fold: forall 'b 'b0. ('A1 -> 'b -> 'b & 'A4 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep3, 'Rep1,) -> 'b, init: ('A7 & 'A5) -> (nothing, nothing,), sub: ('Rep2, 'Rep,) -> int -> ('A2 | 'A0), update: forall 'd 'e. ('Rep0 & 'd, 'Rep5 & 'e,) -> int -> ('A3 & 'A6) -> ('d, 'e,)})) -> 'f) -> 'f //│ where -//│ 'Rep2 :> ('a, 'c,) +//│ 'Rep4 :> ('a, 'c,) //│ <: (nothing, nothing,) -//│ 'A5 :> anything -//│ <: nothing +//│ 'A :> anything +//│ <: nothing //│ <: stepImpl2_ty: //│ (forall 'r. (ArraysRep['A, 'Rep] -> 'r) -> 'r) -> ArraysImpl['A, ('Rep, 'Rep,)] //│ = [Function: stepImpl2] @@ -358,11 +358,11 @@ def step: Arrays['a] -> Arrays['a] :e // * Since "sound extrusion" def step arr f = f (stepImpl2 arr) -//│ ((forall 'A 'Rep 'A0 'A1 'Rep0 'Rep1 'Rep2 'A2 'Rep3 'A3 'Rep4 'A4 'A5 'Rep5 'a 'c 'A6 'A7. ArraysRep[in 'A6 | 'A7 | 'A0 | 'A5 | 'A3 | 'A | 'A1 & ('A2 | 'A4) out 'A0 & 'A5 & 'A2 & 'A4, in 'Rep | 'Rep0 | 'Rep2 | 'Rep4 out nothing] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b 'b0. ('A2 -> 'b -> 'b & 'A4 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep4, 'Rep2,) -> 'b, init: ('A6 & 'A7) -> (nothing, nothing,), sub: ('Rep, 'Rep0,) -> int -> ('A0 | 'A5), update: forall 'd 'e. ('Rep5 & 'd, 'Rep3 & 'e,) -> int -> ('A3 & 'A) -> ('d, 'e,)})) -> 'f) -> ('f -> 'g) -> 'g +//│ ((forall 'Rep 'A 'A0 'Rep0 'A1 'a 'Rep1 'Rep2 'c 'A2 'Rep3 'Rep4 'A3 'Rep5 'A4 'A5 'A6 'A7. ArraysRep[in 'A1 | 'A5 | 'A6 | 'A7 | 'A | 'A3 | 'A2 & ('A4 | 'A0) out 'A6 & 'A7 & 'A4 & 'A0, in 'Rep2 | 'Rep4 | 'Rep | 'Rep0 out nothing] -> (ArraysImpl['A2, 'Rep5] with {fold: forall 'b 'b0. ('A4 -> 'b -> 'b & 'A0 -> 'b0 -> ('b & 'b0)) -> ('b & 'b0) -> ('Rep0, 'Rep,) -> 'b, init: ('A1 & 'A5) -> (nothing, nothing,), sub: ('Rep2, 'Rep4,) -> int -> ('A6 | 'A7), update: forall 'd 'e. ('Rep3 & 'd, 'Rep1 & 'e,) -> int -> ('A & 'A3) -> ('d, 'e,)})) -> 'f) -> ('f -> 'g) -> 'g //│ where -//│ 'Rep1 :> ('a, 'c,) +//│ 'Rep5 :> ('c, 'a,) //│ <: (nothing, nothing,) -//│ 'A1 :> anything +//│ 'A2 :> anything //│ <: nothing //│ <: step: //│ Arrays['a] -> Arrays['a] @@ -473,7 +473,7 @@ ssb (fun arr -> let r2 = arr.Update (arr.Init true) 1 false in (arr.Sub r2 0, arr.Sub r2 1) ) -//│ res: (bool, bool,) +//│ res: (Bool, Bool,) //│ = [ true, false ] diff --git a/shared/src/test/diff/fcp/QML_exist_Records.mls b/shared/src/test/diff/fcp/QML_exist_Records.mls index 16693ec681..1254334a73 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records.mls @@ -207,7 +207,7 @@ stepImpl_ty = stepImpl_Ann_4 // def stepImpl2 (arr: Arrays['a]) = arr stepImpl def stepImpl2 arr = arr stepImpl -//│ stepImpl2: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'j -> 'm -> 'a -> 'e, init: 'h -> 'k, sub: 'g -> 'd -> 'b, update: 'l -> 'i -> 'f -> 'c} -> {fold: 'j -> 'm -> ('a, anything,) -> 'e, init: 'h -> ('k, "hi",), sub: ('g, anything,) -> 'd -> 'b, update: ('l, anything,) -> 'i -> 'f -> ('c, "hey",)}) -> 'n) -> 'n +//│ stepImpl2: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'b -> 'f -> 'j -> 'm, init: 'a -> 'e, sub: 'h -> 'k -> 'g, update: 'd -> 'c -> 'l -> 'i} -> {fold: 'b -> 'f -> ('j, anything,) -> 'm, init: 'a -> ('e, "hi",), sub: ('h, anything,) -> 'k -> 'g, update: ('d, anything,) -> 'c -> 'l -> ('i, "hey",)}) -> 'n) -> 'n //│ = [Function: stepImpl2] def stepImpl2_ arr = arr stepImpl_ty @@ -222,7 +222,7 @@ def stepImpl2_Ann_2 arr = arr stepImpl_Ann_2 //│ = [Function: stepImpl2_Ann_2] def stepImpl2_Ann_3 arr = arr stepImpl_Ann_3 -//│ stepImpl2_Ann_3: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'a -> 'd, sub: 'g -> 'c -> 'i, update: 'b -> 'h -> 'f -> 'e} -> {fold: Fold[nothing, (anything, string,)], init: 'a -> ('d, "hi",), sub: ('g, anything,) -> 'c -> 'i, update: ('b, anything,) -> 'h -> 'f -> ('e, "hey",)}) -> 'j) -> 'j +//│ stepImpl2_Ann_3: ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'f -> 'g, sub: 'a -> 'd -> 'e, update: 'c -> 'i -> 'b -> 'h} -> {fold: Fold[nothing, (anything, string,)], init: 'f -> ('g, "hi",), sub: ('a, anything,) -> 'd -> 'e, update: ('c, anything,) -> 'i -> 'b -> ('h, "hey",)}) -> 'j) -> 'j //│ = [Function: stepImpl2_Ann_3] def stepImpl2_Ann_4 arr = arr stepImpl_Ann_4 @@ -249,7 +249,7 @@ def step: Arrays['a] -> Arrays['a] // * But this problem actually disappeared after fixing a subtle bug in type freshening...! :e // * Since "sound extrusion" def step arr f = f (stepImpl2 arr) -//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'f -> 'k -> 'a -> 'd, init: 'm -> 'j, sub: 'e -> 'l -> 'h, update: 'b -> 'c -> 'i -> 'g} -> {fold: 'f -> 'k -> ('a, anything,) -> 'd, init: 'm -> ('j, "hi",), sub: ('e, anything,) -> 'l -> 'h, update: ('b, anything,) -> 'c -> 'i -> ('g, "hey",)}) -> 'n) -> ('n -> 'o) -> 'o +//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm. {fold: 'i -> 'g -> 'f -> 'k, init: 'a -> 'd, sub: 'm -> 'j -> 'e, update: 'l -> 'h -> 'b -> 'c} -> {fold: 'i -> 'g -> ('f, anything,) -> 'k, init: 'a -> ('d, "hi",), sub: ('m, anything,) -> 'j -> 'e, update: ('l, anything,) -> 'h -> 'b -> ('c, "hey",)}) -> 'n) -> ('n -> 'o) -> 'o //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -330,7 +330,7 @@ def step arr f = f (stepImpl2_Ann_2 arr) :e def step arr f = f (stepImpl2_Ann_3 arr) -//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'f -> 'd, sub: 'b -> 'i -> 'g, update: 'a -> 'c -> 'e -> 'h} -> {fold: Fold[nothing, (anything, string,)], init: 'f -> ('d, "hi",), sub: ('b, anything,) -> 'i -> 'g, update: ('a, anything,) -> 'c -> 'e -> ('h, "hey",)}) -> 'j) -> ('j -> 'k) -> 'k +//│ ((forall 'a 'b 'c 'd 'e 'f 'g 'h 'i. {fold: (??a -> ??b -> ??b0) -> ??b0 -> ??rep -> ??b, init: 'b -> 'h, sub: 'f -> 'e -> 'c, update: 'i -> 'g -> 'a -> 'd} -> {fold: Fold[nothing, (anything, string,)], init: 'b -> ('h, "hi",), sub: ('f, anything,) -> 'e -> 'c, update: ('i, anything,) -> 'g -> 'a -> ('d, "hey",)}) -> 'j) -> ('j -> 'k) -> 'k //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -407,7 +407,7 @@ def step arr f = f (stepImpl2_Ann_2_Ann arr) :e // * Since "sound extrusion" def step (arr: Arrays['a]) f = f (stepImpl2_Ann_2_Ann arr) -//│ Arrays['a] -> ((forall 'a0 'r. {fold: forall 'b. ('a0 -> 'b -> 'b) -> 'b -> (??Rep & 'r, anything,) -> 'b, init: 'a0 -> ('r | ??Rep0, "hi",), sub: (??Rep & 'r, anything,) -> int -> 'a0, update: (??Rep & 'r, anything,) -> int -> 'a0 -> ('r | ??Rep0, "hey",)}) -> 'c) -> 'c +//│ Arrays['a] -> ((forall 'r 'a0. {fold: forall 'b. ('a0 -> 'b -> 'b) -> 'b -> (??Rep & 'r, anything,) -> 'b, init: 'a0 -> ('r | ??Rep0, "hi",), sub: (??Rep & 'r, anything,) -> int -> 'a0, update: (??Rep & 'r, anything,) -> int -> 'a0 -> ('r | ??Rep0, "hey",)}) -> 'c) -> 'c //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition @@ -478,7 +478,7 @@ ssb (fun arr -> let r2 = arr.update (arr.init true) 1 false in (arr.sub r2 0, arr.sub r2 1) ) -//│ res: (bool, bool,) +//│ res: (Bool, Bool,) //│ = [ false, false ] diff --git a/shared/src/test/diff/fcp/SystemF.mls b/shared/src/test/diff/fcp/SystemF.mls index 72e3f9c073..1e4bc85667 100644 --- a/shared/src/test/diff/fcp/SystemF.mls +++ b/shared/src/test/diff/fcp/SystemF.mls @@ -399,7 +399,7 @@ E q = q id // shallow (not (not true)) -- Shallow encoding. // λid.id(λb t f.b f t)(id(λb t f.b f t)(λx y.x)) sh id = (id not) ((id not) tru) -//│ sh: ((forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c) -> ('d -> 'e & (forall 'f. 'f -> anything -> 'f) -> 'd)) -> 'e +//│ sh: ((forall 'a 'b 'c. ('b -> 'c -> 'a) -> 'c -> 'b -> 'a) -> ('d -> 'e & (forall 'f. 'f -> anything -> 'f) -> 'd)) -> 'e //│ = [Function: sh] // E[forall X.X->X->X](shallow (not( not true))) diff --git a/shared/src/test/diff/fcp/SystemF_2.mls b/shared/src/test/diff/fcp/SystemF_2.mls index 18c18c73a3..9d5284af39 100644 --- a/shared/src/test/diff/fcp/SystemF_2.mls +++ b/shared/src/test/diff/fcp/SystemF_2.mls @@ -145,17 +145,17 @@ iter2 f x = f(f x) iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'f -> 'e //│ where -//│ 'c <: 'd -> 'e & 'e -> 'f) <: 'a -> 'g & 'g -> 'b +//│ 'c <: 'f -> 'd & 'd -> 'e) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] id iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'f -> 'e +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where -//│ 'c <: 'f -> 'd & 'd -> 'e) <: 'a -> 'g & 'g -> 'b +//│ 'c <: 'd -> 'e & 'e -> 'f) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] @@ -196,19 +196,19 @@ n0 = n0_ succ_ n s z = s (n s z) def succ: (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X. ('X -> 'X) -> 'X -> 'X) -//│ succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'b <: 'c -> 'd +//│ 'a <: 'b -> 'e -> 'c)) //│ = [Function: succ_1] //│ succ: (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X0. ('X0 -> 'X0) -> 'X0 -> 'X0) //│ = :e // * Needs distrib succ = succ_ -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'b <: 'c -> 'd +//│ 'a <: 'b -> 'e -> 'c)) //│ <: succ: //│ (forall 'X. ('X -> 'X) -> 'X -> 'X) -> (forall 'X0. ('X0 -> 'X0) -> 'X0 -> 'X0) //│ ╔══[ERROR] Type error in def definition @@ -245,117 +245,117 @@ c2 c2 K c2_ = succ_ (succ_ n0) //│ c2_: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. 'g -> 'f +//│ 'a <: 'c -> 'd +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'g -> 'h -//│ 'e <: 'h -> 'f) <: 'a -> 'b -> 'c -//│ 'a <: 'c -> 'd) +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'f -> 'g +//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c) //│ = [Function (anonymous)] c2_ c2_ //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'f -> 'e //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f) <: (forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ 'c <: 'd -> 'e +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'c -> 'f -> 'd) <: (forall 'g. 'g -> (forall 'h 'i 'j. 'j -> 'i //│ where -//│ 'g <: 'i -> 'j -//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n +//│ 'g <: 'h -> 'i +//│ forall 'k. 'k -> (forall 'l 'm 'n. 'n -> 'm //│ where -//│ 'k <: 'm -> 'n -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm) <: 'g -> 'h -> 'i)) -> 'a -> 'o -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ 'k <: 'l -> 'm +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'n -> 'l) <: 'g -> 'j -> 'h)) -> 'a -> 'o +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'j -> 'i //│ where -//│ 'g <: 'i -> 'j -//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n +//│ 'g <: 'h -> 'i +//│ forall 'k. 'k -> (forall 'l 'm 'n. 'n -> 'm //│ where -//│ 'k <: 'm -> 'n -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm) <: 'g -> 'h -> 'i) <: 'o -> 'b +//│ 'k <: 'l -> 'm +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'n -> 'l) <: 'g -> 'j -> 'h) <: 'o -> 'b //│ = [Function (anonymous)] c2_ c2_ K //│ res: 'a -> 'b //│ where -//│ forall 'c 'd 'e. 'c -> 'e +//│ forall 'c 'd 'e. 'e -> 'd //│ where -//│ forall 'f. 'f -> (forall 'g 'h 'i. 'g -> 'i +//│ forall 'f. 'f -> (forall 'g 'h 'i. 'i -> 'h //│ where -//│ 'f <: 'h -> 'i -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'g -> 'h) <: 'j -> 'c -> 'd -//│ 'j <: 'd -> 'e <: 'k -> 'b -//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'i -> 'g +//│ 'f <: 'g -> 'h) <: 'j -> 'e -> 'c +//│ 'j <: 'c -> 'd <: 'k -> 'b +//│ forall 'l. 'l -> (forall 'm 'n 'o. 'o -> 'n //│ where -//│ 'l <: 'n -> 'o -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'm -> 'n) <: (forall 'c 'd 'e. 'c -> 'e +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'l -> 'o -> 'm +//│ 'l <: 'm -> 'n) <: (forall 'c 'd 'e. 'e -> 'd //│ where -//│ forall 'f. 'f -> (forall 'g 'h 'i. 'g -> 'i +//│ forall 'f. 'f -> (forall 'g 'h 'i. 'i -> 'h //│ where -//│ 'f <: 'h -> 'i -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'g -> 'h) <: 'j -> 'c -> 'd -//│ 'j <: 'd -> 'e) -> 'a -> 'k +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'i -> 'g +//│ 'f <: 'g -> 'h) <: 'j -> 'e -> 'c +//│ 'j <: 'c -> 'd) -> 'a -> 'k //│ where -//│ 'j :> forall 'p 'q 'r 's. ('p & 's) -> (anything -> 's | 'r) +//│ 'j :> forall 'p 'q 'r 's. ('p & 'q) -> (anything -> 'q | 's) //│ where -//│ 'j <: 'q -> 'r -//│ forall 't. 't -> (forall 'u 'v 'w. 'u -> 'w +//│ 'j <: 'r -> 's +//│ forall 't. 't -> (forall 'u 'v 'w. 'w -> 'v //│ where -//│ 't <: 'v -> 'w -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'u -> 'v) <: 'j -> 'p -> 'q +//│ 't <: 'u -> 'v +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'w -> 'u) <: 'j -> 'p -> 'r //│ = [Function (anonymous)] c2__ = succ_ (succ_ n0_) -//│ c2__: 'a -> (forall 'b 'c 'd. 'c -> 'b +//│ c2__: 'a -> (forall 'b 'c 'd. 'd -> 'c //│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ 'a <: 'b -> 'c +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'h -> 'g //│ where -//│ 'e <: 'g -> 'h -//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g) <: 'a -> 'c -> 'd -//│ 'a <: 'd -> 'b) +//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'h -> 'f +//│ 'e <: 'f -> 'g) <: 'a -> 'd -> 'b) //│ = [Function (anonymous)] c2__ c2__ //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'f -> 'e //│ where -//│ 'c <: 'e -> 'f -//│ anything -> (forall 'g. 'g -> 'g) <: 'c -> 'd -> 'e) <: (forall 'h. 'h -> (forall 'i 'j 'k. 'i -> 'k +//│ 'c <: 'd -> 'e +//│ anything -> (forall 'g. 'g -> 'g) <: 'c -> 'f -> 'd) <: (forall 'h. 'h -> (forall 'i 'j 'k. 'j -> 'i //│ where -//│ 'h <: 'j -> 'k -//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o +//│ forall 'l. 'l -> (forall 'm 'n 'o. 'o -> 'n //│ where -//│ 'l <: 'n -> 'o -//│ anything -> (forall 'g. 'g -> 'g) <: 'l -> 'm -> 'n) <: 'h -> 'i -> 'j)) -> 'a -> 'p -//│ forall 'h. 'h -> (forall 'i 'j 'k. 'i -> 'k +//│ 'l <: 'm -> 'n +//│ anything -> (forall 'g. 'g -> 'g) <: 'l -> 'o -> 'm) <: 'h -> 'j -> 'k +//│ 'h <: 'k -> 'i)) -> 'a -> 'p +//│ forall 'h. 'h -> (forall 'i 'j 'k. 'j -> 'i //│ where -//│ 'h <: 'j -> 'k -//│ forall 'l. 'l -> (forall 'm 'n 'o. 'm -> 'o +//│ forall 'l. 'l -> (forall 'm 'n 'o. 'o -> 'n //│ where -//│ 'l <: 'n -> 'o -//│ anything -> (forall 'g. 'g -> 'g) <: 'l -> 'm -> 'n) <: 'h -> 'i -> 'j) <: 'p -> 'b +//│ 'l <: 'm -> 'n +//│ anything -> (forall 'g. 'g -> 'g) <: 'l -> 'o -> 'm) <: 'h -> 'j -> 'k +//│ 'h <: 'k -> 'i) <: 'p -> 'b //│ = [Function (anonymous)] c2__ c2__ K //│ res: 'a -> 'b //│ where -//│ forall 'c 'd 'e. 'd -> 'c +//│ forall 'c 'd 'e. 'e -> 'd //│ where -//│ forall 'f. 'f -> anything -> 'f <: 'e -> 'c -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ forall 'f. 'f -> (forall 'g 'h 'i. 'i -> 'h //│ where -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i -//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'd -> 'e <: 'l -> 'b +//│ anything -> (forall 'j. 'j -> 'j) <: 'f -> 'i -> 'g +//│ 'f <: 'g -> 'h) <: (forall 'k. 'k -> anything -> 'k) -> 'e -> 'c +//│ forall 'k. 'k -> anything -> 'k <: 'c -> 'd <: 'l -> 'b //│ forall 'm. 'm -> (forall 'n 'o 'p. 'n -> 'p //│ where -//│ 'm <: 'o -> 'p -//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'n -> 'o) <: (forall 'c 'd 'e. 'd -> 'c +//│ anything -> (forall 'j. 'j -> 'j) <: 'm -> 'n -> 'o +//│ 'm <: 'o -> 'p) <: (forall 'c 'd 'e. 'e -> 'd //│ where -//│ forall 'f. 'f -> anything -> 'f <: 'e -> 'c -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j +//│ forall 'f. 'f -> (forall 'g 'h 'i. 'i -> 'h //│ where -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i -//│ 'g <: 'i -> 'j) <: (forall 'f. 'f -> anything -> 'f) -> 'd -> 'e) -> 'a -> 'l +//│ anything -> (forall 'j. 'j -> 'j) <: 'f -> 'i -> 'g +//│ 'f <: 'g -> 'h) <: (forall 'k. 'k -> anything -> 'k) -> 'e -> 'c +//│ forall 'k. 'k -> anything -> 'k <: 'c -> 'd) -> 'a -> 'l //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls index 2c6689163a..99e0fec3f4 100644 --- a/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls +++ b/shared/src/test/diff/fcp/ToChurchSimplif_CT.mls @@ -197,9 +197,9 @@ rec def to_ch n = :e to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'b -> 'c +//│ int -> (forall 'a. 'a -> (forall 'b 'c. 'c -> 'b //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c) | ChurchInt) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'c -> 'b) | ChurchInt) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -236,9 +236,9 @@ def to_ch n = :e // * Since "sound extrusion" to_church = to_ch -//│ int -> (forall 'a. 'a -> (forall 'b 'a 'c 'd. ('c & 'b) -> ('b | 'd) +//│ int -> (forall 'a. 'a -> (forall 'a 'b 'c 'd. ('b & 'd) -> ('d | 'c) //│ where -//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'c -> 'd)) +//│ forall 'M. ('M -> 'M) -> 'M -> 'M <: 'a -> 'b -> 'c)) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Type error in def definition @@ -541,9 +541,9 @@ to_church = to_ch //│ where //│ 'd <: 'a -> 'b -> 'c) //│ where -//│ 'd :> forall 'e 'f 'g 'h. 'g -> (('f & 'h) -> ('f | 'e) +//│ 'd :> forall 'e 'f 'g 'h. 'e -> (('h & 'f) -> ('h | 'g) //│ where -//│ 'd <: 'g -> 'h -> 'e) +//│ 'd <: 'e -> 'f -> 'g) //│ <: to_church: //│ int -> (forall 'M. ('M -> 'M) -> 'M -> 'M) //│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch. ?to_ch <: int -> (forall 'M. ('M -> 'M) -> 'M -> 'M)` exceeded recursion depth limit (250) diff --git a/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls b/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls index 5ab48ba9f4..9cbee0f52c 100644 --- a/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls +++ b/shared/src/test/diff/fcp/ToChurchSimplif_ST.mls @@ -37,13 +37,13 @@ def s n f x = (n f x) :ns s -//│ res: forall 'a 'b 'c 'd 'e. 'e -> (forall 'f. 'f -> (forall 'g 'h. 'g -> 'h)) +//│ res: forall 'a 'b 'c 'd 'e. 'c -> (forall 'f. 'f -> (forall 'g 'h. 'g -> 'h)) //│ where -//│ 'h :> 'b -//│ 'g <: 'c -//│ 'f <: 'a +//│ 'h :> 'd +//│ 'g <: 'a +//│ 'f <: 'b +//│ 'c <: 'b -> 'e //│ 'e <: 'a -> 'd -//│ 'd <: 'c -> 'b //│ = [Function: s] :e // * Works with CT diff --git a/shared/src/test/diff/fcp/Vec.mls b/shared/src/test/diff/fcp/Vec.mls index 6f0ce19b90..6a8f4285a2 100644 --- a/shared/src/test/diff/fcp/Vec.mls +++ b/shared/src/test/diff/fcp/Vec.mls @@ -419,7 +419,7 @@ sum v1_ty //│ ╟── type `Cons[int, Z]` is not a function //│ ║ l.198: v1_ty = v1_ : Cons[int, Z] //│ ║ ^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `(forall ?a ?b. ?b -> ?a) -> ?c` +//│ ╟── but it flows into reference with expected type `(forall ?a ?b. ?a -> ?b) -> ?c` //│ ║ l.+1: sum v1_ty //│ ║ ^^^^^ //│ ╟── Note: constraint arises from application: diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 805f0cde47..e12732e385 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -2,10 +2,10 @@ class Exp[A]: Pair | Lit -class Lit(n: int) extends Exp[int] +class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[anything, anything] -//│ class Lit(n: int) extends Exp +//│ class Lit(n: Int) extends Exp //│ class Pair[L, R](lhs: L, rhs: R) extends Exp @@ -22,10 +22,10 @@ fun f(e) = if e is fun f(e) = if e is Pair(l, r) then [l, r] Lit(n) then n -//│ fun f: forall 'lhs 'rhs. (Lit | Pair['lhs, 'rhs]) -> (('lhs, 'rhs,) | int) +//│ fun f: forall 'lhs 'rhs. (Lit | Pair['lhs, 'rhs]) -> (('lhs, 'rhs,) | Int) (e: Exp['X]) => f(e) -//│ (e: Exp['X],) -> ((??L, ??R,) | int) +//│ (e: Exp['X],) -> ((??L, ??R,) | Int) //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index 9d2850a9ac..de6e1f8424 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -2,15 +2,15 @@ class Exp[A]: Pair | Lit -class Lit(n: int) extends Exp[int] +class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[?, ?] -//│ class Lit(n: int) extends Exp +//│ class Lit(n: Int) extends Exp //│ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp fun f(p: Pair['a, 'b]) = p.lhs -//│ fun f: forall 'L 'a 'b. (p: Pair['a, 'b],) -> Exp['L] +//│ fun f: forall 'a 'b 'L. (p: Pair['a, 'b],) -> Exp['L] //│ where //│ 'L := 'a @@ -24,7 +24,7 @@ fun f(e) = if e is fun f(e) = if e is Pair(l, r) then [l, r] Lit(n) then n -//│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> ((Exp['L], Exp['R],) | int) +//│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> ((Exp['L], Exp['R],) | Int) :e (e: Exp['X]) => f(e) @@ -34,7 +34,7 @@ fun f(e) = if e is //│ ╟── type variable `L` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ -//│ (e: Exp['X],) -> ((Exp['L], Exp['R],) | error | int) +//│ (e: Exp['X],) -> ((Exp['L], Exp['R],) | Int | error) //│ where //│ 'R :> ??R //│ <: ??R0 @@ -68,7 +68,7 @@ fun f(e) = if e is //│ ╟── type variable `R` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ -//│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> int +//│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> Int //│ where //│ 'R :> ??R //│ <: ??R0 diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index 6cdfc607f9..7ca2e9fe91 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -23,9 +23,9 @@ Dummy.introspect //│ = 'duh!' -class Funny: int { fun test = this + 1 } -//│ class Funny: int { -//│ fun test: int +class Funny: Int { fun test = this + 1 } +//│ class Funny: Int | 'a { +//│ fun test: Int | 'a //│ } :e @@ -33,11 +33,11 @@ class Unfunny { fun test = this + 1 } //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.32: class Unfunny { fun test = this + 1 } //│ ║ ^^^^^^ -//│ ╟── reference of type `#Unfunny` is not an instance of type `int` +//│ ╟── reference of type `#Unfunny` is not an instance of type `Int` //│ ║ l.32: class Unfunny { fun test = this + 1 } //│ ╙── ^^^^ //│ class Unfunny { -//│ fun test: error | int +//│ fun test: Int | error //│ } @@ -46,12 +46,12 @@ class Exp: Pair | Lit { Lit then 0 Pair then 1 } -class Lit(n: int) extends Exp +class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { //│ fun test: 0 | 1 //│ } -//│ class Lit(n: int) extends Exp { +//│ class Lit(n: Int) extends Exp { //│ fun test: 0 | 1 //│ } //│ class Pair(lhs: Exp, rhs: Exp) extends Exp { @@ -64,12 +64,12 @@ class Exp: Pair | Lit { Lit then 0 Pair(l, r) then 1 } -class Lit(n: int) extends Exp +class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { //│ fun test: 0 | 1 //│ } -//│ class Lit(n: int) extends Exp { +//│ class Lit(n: Int) extends Exp { //│ fun test: 0 | 1 //│ } //│ class Pair(lhs: Exp, rhs: Exp) extends Exp { @@ -88,7 +88,7 @@ class Exp: Pair | Lit { Lit then 0 Pair(l, r) then l.test + r.test } -class Lit(n: int) extends Exp +class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.89: Pair(l, r) then l.test + r.test @@ -97,32 +97,32 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ ║ l.89: Pair(l, r) then l.test + r.test //│ ╙── ^^^^^ //│ class Exp: Lit | Pair { -//│ fun test: int +//│ fun test: Int //│ } -//│ class Lit(n: int) extends Exp { -//│ fun test: int +//│ class Lit(n: Int) extends Exp { +//│ fun test: Int //│ } //│ class Pair(lhs: Exp, rhs: Exp) extends Exp { -//│ fun test: int +//│ fun test: Int //│ } class Exp: Pair | Lit { - fun test : int + fun test : Int fun test = if this is Lit then 0 Pair(l, r) then l.test + r.test } -class Lit(n: int) extends Exp +class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { -//│ fun test: int +//│ fun test: Int //│ } -//│ class Lit(n: int) extends Exp { -//│ fun test: int +//│ class Lit(n: Int) extends Exp { +//│ fun test: Int //│ } //│ class Pair(lhs: Exp, rhs: Exp) extends Exp { -//│ fun test: int +//│ fun test: Int //│ } @@ -132,7 +132,7 @@ class Exp[A]: Pair | Lit { Lit then 0 Pair then 1 } -class Lit(n: int) extends Exp[int] +class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ ╔══[ERROR] Unhandled cyclic definition //│ ║ l.130: class Exp[A]: Pair | Lit { @@ -156,7 +156,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[anything, anything] { //│ fun test: 0 | 1 //│ } -//│ class Lit(n: int) extends Exp { +//│ class Lit(n: Int) extends Exp { //│ fun test: 0 | 1 //│ } //│ class Pair[L, R](lhs: L, rhs: R) extends Exp diff --git a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls index 2f1ca425c9..126ee9901f 100644 --- a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls +++ b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls @@ -523,14 +523,14 @@ def succ (n: ChurchInt) = fun f -> fun x -> f (n f x) def succ' n = fun f -> fun x -> f (n f x) //│ succ_ty: ChurchInt -> ChurchInt //│ = -//│ succ: ChurchInt -> (forall 'b. 'b -> (forall 'c 'a. 'a -> 'c +//│ succ: ChurchInt -> (forall 'b. 'b -> (forall 'a 'c. 'a -> 'c //│ where //│ 'b <: 'a -> 'a & 'a -> 'c)) //│ = [Function: succ1] -//│ succ': 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ succ': 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'b <: 'c -> 'd +//│ 'a <: 'b -> 'e -> 'c)) //│ = [Function: succ$1] // * Note: without constrained types we wouldn't get the principal type of succ' @@ -546,10 +546,10 @@ succ_ty = succ // * Still requires distributivity even with CT :e succ_ty = succ' -//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'a <: 'b -> 'e -> 'c +//│ 'b <: 'c -> 'd)) //│ <: succ_ty: //│ ChurchInt -> ChurchInt //│ ╔══[ERROR] Type error in def definition @@ -573,33 +573,33 @@ succ_ty = succ' succ_ty = succ' //│ 'a -> 'b -> ('c -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'e -//│ 'b <: 'e -> 'd) +//│ 'b <: 'e -> 'd +//│ 'a <: 'b -> 'c -> 'e) //│ <: succ_ty: //│ ChurchInt -> ChurchInt //│ = [Function: succ$1] :DontDistributeForalls succ' -//│ res: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ res: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e)) +//│ 'a <: 'b -> 'e -> 'c +//│ 'b <: 'c -> 'd)) //│ = [Function: succ$1] // :e // * Error delayed by inconsistent constrained types succ' {} -//│ res: 'a -> (forall 'b 'c 'd. 'c -> 'b +//│ res: 'a -> (forall 'b 'c 'd. 'd -> 'c //│ where -//│ anything <: 'a -> 'c -> 'd -//│ 'a <: 'd -> 'b) +//│ 'a <: 'b -> 'c +//│ anything <: 'a -> 'd -> 'b) //│ = [Function (anonymous)] // :e // * Error delayed by inconsistent constrained types succ' {} {} //│ res: 'a -> 'b //│ where -//│ anything <: anything -> 'a -> 'c & 'c -> 'b +//│ anything <: 'c -> 'b & anything -> 'a -> 'c //│ = [Function (anonymous)] :e @@ -609,10 +609,10 @@ succ' {} {} {} //│ ║ ^^^^^^^^^^^^^^ //│ ╟── record literal of type `anything` is not a function //│ ║ l.606: succ' {} {} {} -//│ ║ ^^ +//│ ║ ^^ //│ ╟── Note: constraint arises from application: //│ ║ l.523: def succ' n = fun f -> fun x -> f (n f x) -//│ ╙── ^^^ +//│ ╙── ^^^^^^^^^ //│ res: error //│ Runtime error: //│ TypeError: n is not a function diff --git a/shared/src/test/diff/mlf-examples/ex_demo.mls b/shared/src/test/diff/mlf-examples/ex_demo.mls index 03a5ea2622..48fa0873d1 100644 --- a/shared/src/test/diff/mlf-examples/ex_demo.mls +++ b/shared/src/test/diff/mlf-examples/ex_demo.mls @@ -363,19 +363,19 @@ id1 id1 // * TODO type pp – inline id1? :ns id1 -//│ res: forall 'a 'b 'c 'id1 'd 'e. 'id1 +//│ res: forall 'a 'b 'c 'd 'e 'id1. 'id1 //│ where -//│ 'id1 := 'e -> 'c -//│ 'e :> 'e -> 'c -//│ <: 'a -//│ 'c :> 'e -> 'c -//│ <: 'b & 'd -//│ 'd :> 'e -> 'c -//│ <: 'e -> 'b -//│ 'b :> 'e -> 'c -//│ <: 'a -//│ 'a :> 'e -> 'c -//│ <: 'c +//│ 'id1 := 'b -> 'd +//│ 'b :> 'b -> 'd +//│ <: 'e +//│ 'd :> 'b -> 'd +//│ <: 'c & 'a +//│ 'a :> 'b -> 'd +//│ <: 'b -> 'c +//│ 'c :> 'b -> 'd +//│ <: 'e +//│ 'e :> 'b -> 'd +//│ <: 'd //│ = [Function: id13] :e @@ -476,7 +476,7 @@ ex_list1 = cons (make_ex1 (("A String", print_string))) ex_list2 = cons (make_ex2 (("String", "String", eqstring))) (cons (make_ex2 ((1250, 4890, eqint))) (cons (make_ex2 ((true, false, eqbool))) nil)) -//│ ex_list2: List[forall 'b. (forall 'a 'a0 'a1. ('a, 'a, 'a -> 'a -> bool,) -> 'b & ('a0, 'a0, 'a0 -> 'a0 -> (bool | false),) -> 'b & ('a1, 'a1, 'a1 -> 'a1 -> bool,) -> 'b) -> 'b] +//│ ex_list2: List[forall 'b. (forall 'a 'a0 'a1. ('a1, 'a1, 'a1 -> 'a1 -> bool,) -> 'b & ('a, 'a, 'a -> 'a -> (bool | false),) -> 'b & ('a0, 'a0, 'a0 -> 'a0 -> bool,) -> 'b) -> 'b] //│ = Cons { //│ head: [Function (anonymous)], //│ tail: Cons { @@ -487,7 +487,7 @@ ex_list2 = cons (make_ex2 (("String", "String", eqstring))) h = head ex_list1 -//│ h: (forall 'a 'a0 'a1. ('a1, 'a1 -> unit,) -> 'b & ('a, 'a -> unit,) -> 'b & ('a0, 'a0 -> unit,) -> 'b) -> 'b +//│ h: (forall 'a 'a0 'a1. ('a, 'a -> unit,) -> 'b & ('a0, 'a0 -> unit,) -> 'b & ('a1, 'a1 -> unit,) -> 'b) -> 'b //│ = [Function (anonymous)] h (fun ((x, f)) -> f x) @@ -876,7 +876,7 @@ def c_add n (m: Fint) = m c_succ n //│ = [Function: c_add] def c_add_ n m = m c_succ_ n -//│ c_add_: 'a -> (forall 'b. ((forall 'c 'd 'e. ('e -> 'c -> 'd) -> (forall 'f. ('f -> 'c & 'e) -> 'f -> 'd)) -> 'a -> 'b) -> 'b) +//│ c_add_: 'a -> (forall 'b. ((forall 'c 'd 'e. ('c -> 'd -> 'e) -> (forall 'f. ('f -> 'd & 'c) -> 'f -> 'e)) -> 'a -> 'b) -> 'b) //│ = [Function: c_add_] // let c_mul n (m:Int) = m (c_add n) c_i0 @@ -918,7 +918,7 @@ def c_pred_ n = let s = fun p -> c_pair (c_2_2_ p) (c_succ_ (c_2_2_ p)) in let z = c_pair c_i0 c_i0 in c_1_2_ (n s z) -//│ c_pred_: ((forall 'a 'b 'c 'd. ((anything -> (forall 'e. 'e -> 'e)) -> ('d -> 'a -> 'b & 'c)) -> (forall 'f. ('c -> (forall 'g. ('g -> 'a & 'd) -> 'g -> 'b) -> 'f) -> 'f)) -> (forall 'h. ((anything -> (forall 'i. 'i -> 'i)) -> (anything -> (forall 'i. 'i -> 'i)) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k +//│ c_pred_: ((forall 'a 'b 'c 'd. ((anything -> (forall 'e. 'e -> 'e)) -> ('b -> 'c -> 'd & 'a)) -> (forall 'f. ('a -> (forall 'g. ('g -> 'c & 'b) -> 'g -> 'd) -> 'f) -> 'f)) -> (forall 'h. ((anything -> (forall 'i. 'i -> 'i)) -> (anything -> (forall 'i. 'i -> 'i)) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k //│ = [Function: c_pred_] @@ -1036,7 +1036,7 @@ rec def c_fact_ n = (fun _ -> c_mul_ n (c_fact_ (c_pred_ n))) //│ c_fact_: 'a -> 'b //│ where -//│ 'a <: (anything -> anything -> (forall 'c. ((forall 'd. 'd -> 'd) -> 'c) -> 'c)) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (anything -> (forall 'f 'g. ('f -> 'g) -> 'f -> 'g)) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l. ('l -> 'j -> 'k) -> (forall 'm. ('m -> 'j & 'l) -> 'm -> 'k)) -> 'b -> 'i) -> 'i) -> (anything -> (forall 'n. 'n -> 'n)) -> 'h & (forall 'o 'p 'q 'r. ((anything -> (forall 's. 's -> 's)) -> ('o -> 'p -> 'q & 'r)) -> (forall 't. ('r -> (forall 'u. ('u -> 'p & 'o) -> 'u -> 'q) -> 't) -> 't)) -> (forall 'v. ((anything -> (forall 'n. 'n -> 'n)) -> (anything -> (forall 'n. 'n -> 'n)) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a +//│ 'a <: (anything -> anything -> (forall 'c. ((forall 'd. 'd -> 'd) -> 'c) -> 'c)) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (anything -> (forall 'f 'g. ('f -> 'g) -> 'f -> 'g)) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l. ('j -> 'k -> 'l) -> (forall 'm. ('m -> 'k & 'j) -> 'm -> 'l)) -> 'b -> 'i) -> 'i) -> (anything -> (forall 'n. 'n -> 'n)) -> 'h & (forall 'o 'p 'q 'r. ((anything -> (forall 's. 's -> 's)) -> ('o -> 'p -> 'q & 'r)) -> (forall 't. ('r -> (forall 'u. ('u -> 'p & 'o) -> 'u -> 'q) -> 't) -> 't)) -> (forall 'v. ((anything -> (forall 'n. 'n -> 'n)) -> (anything -> (forall 'n. 'n -> 'n)) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a //│ = [Function: c_fact_] @@ -1146,7 +1146,7 @@ this_should_be_98_ = //│ ║ l.1140: let c_i10_ = c_mul_ c_i5_ c_i2_ in //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b. ?a -> ?b <: (forall ?c. ?c) -> ?d` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b. ?b -> ?a <: (forall ?c. ?c) -> ?d` exceeded recursion depth limit (250) //│ ║ l.1141: let c_i9_ = c_pred_ c_i10_ in //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -1164,7 +1164,7 @@ c_i5_ = c_add_ c_i3_ c_i2_ //│ = [Function (anonymous)] //│ constrain calls : 175 //│ annoying calls : 0 -//│ subtyping calls : 662 +//│ subtyping calls : 666 :stats :e @@ -1175,11 +1175,11 @@ c_i10_ = c_mul_ c_i5_ c_i2_ //│ ╙── Note: use flag `:ex` to see internal error info. //│ c_i10_: ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'p -> 'o & 'q -> 'p & 'r -> 'q & (forall 's. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'p -> 'o & 's -> 'p & 't & 'u & 'v & 'w & 'x & 'y) -> 's -> 'h | 'z) -> ('a1 & 'b1) & (forall 'c1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'c1 -> 'o & 'u & 'v & 'w & 'x & 'y) -> 'c1 -> 'g | 'd1) -> ('e1 -> 'q -> 'i & 'z) & (forall 'f1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'f1 -> 'n & 'v & 'w & 'x & 'y) -> 'f1 -> 'f | 'g1) -> ('t -> 'p -> ('h & 'i) & 'd1) & (forall 'h1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'h1 -> 'm & 'w & 'x & 'y) -> 'h1 -> 'e | 'i1) -> ('u -> 'o -> ('g & 'h & 'i) & 'g1) & (forall 'j1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'j1 -> 'l & 'x & 'y) -> 'j1 -> 'd | 'k1) -> ('v -> 'n -> ('f & 'g & 'h & 'i) & 'i1) & (forall 'l1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l1 -> 'k & 'y) -> 'l1 -> 'c | 'm1) -> ('w -> 'm -> ('e & 'f & 'g & 'h & 'i) & 'k1) & (forall 'n1. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'n1 -> 'j) -> 'n1 -> 'b | 'o1) -> ('x -> 'l -> ('d & 'e & 'f & 'g & 'h & 'i) & 'm1) & 'p1 -> ('y -> 'k -> ('c & 'd & 'e & 'f & 'g & 'h & 'i) & 'o1) & 'e1 & 't & 'u & 'v & 'w & 'x & 'y) -> ('r & 'p1) -> (forall 'r. ('a -> ('b & 'c & 'd & 'e & 'f & 'g & 'h & 'i) & 'j -> 'a & 'k -> 'j & 'l -> 'k & 'm -> 'l & 'n -> 'm & 'o -> 'n & 'p -> 'o & 'q -> 'p & 'r -> 'q & 'e1 & 't & 'u & 'v & 'w & 'x & 'y) -> 'r -> 'i | 'i | 'a1) | error //│ where -//│ 'b1 <: (forall 'q1 'r1 's1. ('q1 -> 'r1 -> 's1) -> (forall 't1. ('t1 -> 'r1 & 'q1) -> 't1 -> 's1)) -> (forall 'u1 'v1 'w1. ('w1 -> 'u1 & 'v1 -> 'w1) -> 'v1 -> 'u1) -> 'b1 +//│ 'b1 <: (forall 'q1 'r1 's1. ('q1 -> 'r1 -> 's1) -> (forall 't1. ('t1 -> 'r1 & 'q1) -> 't1 -> 's1)) -> (forall 'u1 'v1 'w1. ('u1 -> 'v1 & 'w1 -> 'u1) -> 'w1 -> 'v1) -> 'b1 //│ = [Function (anonymous)] //│ constrain calls : 1756 //│ annoying calls : 0 -//│ subtyping calls : 15854 +//│ subtyping calls : 15895 :stats // * This one works: c_i10_ = c_mul c_i5_ c_i2_ @@ -1187,7 +1187,7 @@ c_i10_ = c_mul c_i5_ c_i2_ //│ = [Function (anonymous)] //│ constrain calls : 706 //│ annoying calls : 0 -//│ subtyping calls : 5071 +//│ subtyping calls : 5075 // * Ouchie (cf stats) :stats @@ -1196,7 +1196,7 @@ c_i9_ = c_pred_ c_i10_ //│ = [Function (anonymous)] //│ constrain calls : 1903 //│ annoying calls : 0 -//│ subtyping calls : 15736 +//│ subtyping calls : 15745 :stats :e @@ -1209,7 +1209,7 @@ c_99_ = c_add_ (c_mul_ c_i9_ c_i10_) c_i9_ //│ = [Function (anonymous)] //│ constrain calls : 3427 //│ annoying calls : 0 -//│ subtyping calls : 27283 +//│ subtyping calls : 27287 :stats // * Works again: c_99_ = c_add_ (c_mul c_i9_ c_i10_) c_i9_ @@ -1217,7 +1217,7 @@ c_99_ = c_add_ (c_mul c_i9_ c_i10_) c_i9_ //│ = [Function (anonymous)] //│ constrain calls : 2732 //│ annoying calls : 0 -//│ subtyping calls : 29552 +//│ subtyping calls : 29582 // * Ouchie++ :stats @@ -1227,7 +1227,7 @@ c_98_ = c_pred_ c_99_ //│ = [Function (anonymous)] //│ constrain calls : 13601 //│ annoying calls : 0 -//│ subtyping calls : 132287 +//│ subtyping calls : 132357 :ResetFuel @@ -1299,17 +1299,17 @@ def c_succ_ n = fun f -> fun x -> n f (f x) //│ where //│ 'b <: 'a -> 'a & 'c -> 'a)) //│ = [Function: c_succ1] -//│ c_succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd +//│ c_succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e //│ where -//│ 'b <: 'e -> 'c -//│ 'a <: 'b -> 'c -> 'd)) +//│ 'b <: 'c -> 'd +//│ 'a <: 'b -> 'd -> 'e)) //│ = [Function: c_succ_1] def c_add_ n m = m c_succ_ n //│ c_add_: 'a -> (forall 'b. ((forall 'c. 'c -> (forall 'd. 'd -> (forall 'e 'f 'g. 'g -> 'f //│ where -//│ 'd <: 'g -> 'e -//│ 'c <: 'd -> 'e -> 'f))) -> 'a -> 'b) -> 'b) +//│ 'c <: 'd -> 'e -> 'f +//│ 'd <: 'g -> 'e))) -> 'a -> 'b) -> 'b) //│ = [Function: c_add_1] // let c_i1 = fun f x -> f x @@ -1328,10 +1328,10 @@ def c_i2_ = c_succ_ c_i1 //│ = [Function: c_i22] //│ c_i2_: 'a -> (forall 'b 'c 'd. 'd -> 'c //│ where -//│ 'a <: 'd -> 'b //│ forall 'e. 'e -> (forall 'f 'g. 'f -> 'g //│ where -//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c) +//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c +//│ 'a <: 'd -> 'b) //│ = [Function: c_i2_1] // let c_i3 = c_succ c_i2 @@ -1357,13 +1357,13 @@ c_i5_ = c_add_ c_i3_ c_i2 //│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'f -> 'e //│ where //│ 'c <: 'f -> 'd & 'f -> 'g +//│ 'b <: 'c -> 'd -> 'e //│ forall 'h. 'h -> (forall 'i 'j 'k. 'k -> 'j //│ where -//│ 'h <: 'k -> 'i //│ forall 'l. 'l -> (forall 'a 'm. 'm -> 'a //│ where -//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j) <: 'c -> 'g -> 'e -//│ 'b <: 'c -> 'd -> 'e) +//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j +//│ 'h <: 'k -> 'i) <: 'c -> 'g -> 'e) //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/mlf-examples/ex_hashtbl.mls b/shared/src/test/diff/mlf-examples/ex_hashtbl.mls index 7a471c52cf..c5d9ef7eed 100644 --- a/shared/src/test/diff/mlf-examples/ex_hashtbl.mls +++ b/shared/src/test/diff/mlf-examples/ex_hashtbl.mls @@ -119,30 +119,30 @@ rec def find table key = :ns find -//│ res: forall 'a 'a0 'b 'c 'val 'd 'e 'a1 'f 'find 'g 'h 'i 'j 'k 'l 'a2. 'find +//│ res: forall 'b 'a 'c 'a0 'd 'e 'f 'g 'val 'h 'i 'j 'k 'find 'a1 'a2 'l. 'find //│ where -//│ 'find := 'b -> 'h -> 'g +//│ 'find := 'l -> 'h -> 'g //│ 'g :> (forall 'm. 'm) | (forall 'n. 'n) -//│ <: 'd -//│ 'd :> (forall 'm. 'm) | (forall 'n. 'n) //│ <: 'k //│ 'k :> (forall 'm. 'm) | (forall 'n. 'n) -//│ <: 'e -//│ 'e :> (forall 'm. 'm) | (forall 'n. 'n) +//│ <: 'b +//│ 'b :> (forall 'm. 'm) | (forall 'n. 'n) +//│ <: 'd +//│ 'd :> (forall 'm. 'm) | (forall 'n. 'n) //│ <: 'i //│ 'i :> (forall 'm. 'm) | (forall 'n. 'n) //│ <: 'g //│ 'n :> #None -//│ 'm :> #Some & {val: 'val, Some#a = 'a0} +//│ 'm :> #Some & {val: 'val, Some#a = 'a2} //│ 'h <: 'c -//│ 'b :> List['a] -//│ <: List['a] & List['a2] & List['a1] -//│ 'a <: 'a1 & 'a2 -//│ 'a2 <: {_2: 'f} & {_1: 'j} +//│ 'l :> List['a1] +//│ <: List['a1] & List['a] & List['a0] +//│ 'a1 <: 'a0 & 'a +//│ 'a <: {_2: 'f} & {_1: 'j} //│ 'j <: 'c -//│ 'f <: 'l -//│ 'l <: 'val -//│ 'val <: 'a0 +//│ 'f <: 'e +//│ 'e <: 'val +//│ 'val <: 'a2 //│ = [Function: find1] :ng @@ -218,7 +218,7 @@ table = hashtbl_add table "two" (fun f -> fun x -> f (f x)) //│ = Nil {} //│ table: List[("one", forall 'a 'b. ('a -> 'b) -> 'a -> 'b,)] //│ = Cons { head: [ 'one', [Function (anonymous)] ], tail: Nil {} } -//│ table: List[("one" | "two", forall 'a 'b 'c. ('a -> 'b & 'b -> 'c & 'a -> 'c) -> 'a -> 'c,)] +//│ table: List[("one" | "two", forall 'a 'b 'c. ('b -> 'c & 'c -> 'a & 'b -> 'a) -> 'b -> 'a,)] //│ = Cons { //│ head: [ 'two', [Function (anonymous)] ], //│ tail: Cons { head: [ 'one', [Function (anonymous)] ], tail: Nil {} } diff --git a/shared/src/test/diff/mlf-examples/ex_predicative.mls b/shared/src/test/diff/mlf-examples/ex_predicative.mls index b6d8aa1ab4..3bb4f9060f 100644 --- a/shared/src/test/diff/mlf-examples/ex_predicative.mls +++ b/shared/src/test/diff/mlf-examples/ex_predicative.mls @@ -221,7 +221,7 @@ t id succ 0 :e def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) two -//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b ?c ?d. ?b -> ?c -> ?d) -> ?e` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b ?c ?d. ?d -> ?b -> ?c) -> ?e` exceeded recursion depth limit (250) //│ ║ l.223: def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) two //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -243,23 +243,23 @@ def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) //│ 'k <: 'm -> 'n)) -> 'i) -> 'i //│ where //│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'h)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'r & 's -> 'c -> 'd -//│ forall 't 'u. ((forall 'v. anything -> anything -> 'v -> 'v) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'y 'z 'a1 'b1 'c1. 'c1 -> ('z -> 'b1 +//│ forall 't 'u. ((forall 'v. anything -> anything -> 'v -> 'v) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'y 'z 'a1 'b1 'c1. 'y -> ('b1 -> 'a1 //│ where //│ 'u <: (forall 'd1 'j 'e1. 'j -> (('d1 -> (forall 'k 'l 'm 'n. 'k -> ('l -> 'n //│ where //│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'k -> 'l -> 'm //│ 'k <: 'm -> 'n)) -> 'e1) -> 'e1 //│ where -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'd1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'a1 & 'y -> 'z -> 'b1 -//│ forall 'f1 'g1. ((forall 'h1. anything -> anything -> 'h1 -> 'h1) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'i1 'j1 'k1 'l1 'm1. 'l1 -> ('i1 -> 'k1 +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'd1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'z & 'c1 -> 'b1 -> 'a1 +//│ forall 'f1 'g1. ((forall 'h1. anything -> anything -> 'h1 -> 'h1) -> (forall 'q. 'q -> anything -> 'q) -> (forall 'w 'x. ('w -> 'x) -> 'w -> 'x) -> (forall 'i1 'j1 'k1 'l1 'm1. 'm1 -> ('j1 -> 'l1 //│ where -//│ 'g1 <: (forall 'n1 'o1 'j. 'j -> (('n1 -> (forall 'k 'l 'm 'n. 'k -> ('l -> 'n +//│ 'g1 <: (forall 'n1 'j 'o1. 'j -> (('o1 -> (forall 'k 'l 'm 'n. 'k -> ('l -> 'n //│ where //│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'k -> 'l -> 'm -//│ 'k <: 'm -> 'n)) -> 'o1) -> 'o1 +//│ 'k <: 'm -> 'n)) -> 'n1) -> 'n1 //│ where -//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'n1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'j1 & 'm1 -> 'i1 -> 'k1 -//│ anything -> 'a <: 'j1 -> 'l1 -> 'm1)) -> 'f1 & 'g1) -> 'f1 <: 'a1 -> 'c1 -> 'y)) -> 't & 'u) -> 't <: 'r -> 'b -> 's) +//│ 'j <: (forall 'o. anything -> 'o -> 'o) -> 'o1)) -> (forall 'p. ((forall 'o. anything -> 'o -> 'o) -> (forall 'o. anything -> 'o -> 'o) -> 'p) -> 'p) -> (forall 'q. 'q -> anything -> 'q) -> 'k1 & 'i1 -> 'j1 -> 'l1 +//│ anything -> 'a <: 'k1 -> 'm1 -> 'i1)) -> 'f1 & 'g1) -> 'f1 <: 'z -> 'y -> 'c1)) -> 't & 'u) -> 't <: 'r -> 'b -> 's) //│ = [Function: t22] :NoConstrainedTypes @@ -311,12 +311,12 @@ def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) //│ ║ l.276: def t2 y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) three //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ t2: ('a -> ('b -> 'c & 'd & 'e & 'f)) -> (('a & 'g) -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> ('k -> 'k | 'j) | 'e) -> (forall 'p 'q 'r 's. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 's) -> ('s -> 's | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v) & 'b & 't & 'w & 'x) -> ('c | 'u) | error) +//│ t2: ('a -> ('b -> 'c & 'd & 'e & 'f)) -> (('a & 'g) -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('j -> 'n -> 'k & 'm)) -> ('m -> (forall 'o. ('k -> 'o & 'j) -> 'n -> 'o) -> 'l) -> ('i -> 'i | 'l) | 'e) -> (forall 'p 'q 'r 's. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 's) -> ('s -> 's | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v) & 'b & 't & 'w & 'x) -> ('c | 'u) | error) //│ where -//│ 'b :> forall 'r 'y 'p 'q 'z. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'y) -> ('z -> ('y | 'z) | 'p | 'q | 'y) | 'c | 'u +//│ 'b :> forall 'r 'y 'q 'z 'p. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'y) -> ('z -> ('y | 'z) | 'p | 'q | 'y) | 'c | 'u //│ <: (forall 'h. anything -> 'h -> 'h) -> nothing -> nothing -> anything -//│ 'c <: (forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> ('k -> 'k | 'j) | 'e) -> (forall 'p 'q 'r 'a1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'a1) -> ('a1 -> 'a1 | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v & 'b1) -//│ 'b1 <: (forall 'c1. anything -> anything -> 'c1 -> 'c1) -> (forall 'd1. 'd1 -> anything -> 'd1) -> (forall 'e1 'f1. ('e1 -> 'f1) -> 'e1 -> 'f1) -> ('a -> ('b & 't & 'w) -> 'c) -> 'g -> ((forall 'g1 'h1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'g1 & 'h1) -> (anything -> 'h1 | 'g1) | 'x | 'c | 'u) -> 'i1 & 'i1 -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> ('k -> 'k | 'j) | 'e) -> (forall 'p 'q 'r 'j1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'j1) -> ('j1 -> 'j1 | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v) & 'u)) & (forall 'i 'j 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('l -> 'i -> 'n & 'm)) -> ('m -> (forall 'o. ('n -> 'o & 'l) -> 'i -> 'o) -> 'j) -> 'j) -> (forall 'q. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q) -> 'q) -> (forall 'd1. 'd1 -> anything -> 'd1) -> anything & 'd -> 'f +//│ 'c <: (forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('j -> 'n -> 'k & 'm)) -> ('m -> (forall 'o. ('k -> 'o & 'j) -> 'n -> 'o) -> 'l) -> ('i -> 'i | 'l) | 'e) -> (forall 'p 'q 'r 'a1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'a1) -> ('a1 -> 'a1 | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v & 'b1) +//│ 'b1 <: (forall 'c1. anything -> anything -> 'c1 -> 'c1) -> (forall 'd1. 'd1 -> anything -> 'd1) -> (forall 'e1 'f1. ('e1 -> 'f1) -> 'e1 -> 'f1) -> ('a -> ('b & 't & 'w) -> 'c) -> 'g -> ((forall 'g1 'h1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'g1 & 'h1) -> (anything -> 'h1 | 'g1) | 'x | 'c | 'u) -> 'i1 & 'i1 -> ((forall 'h. anything -> 'h -> 'h) -> ((forall 'i 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('j -> 'n -> 'k & 'm)) -> ('m -> (forall 'o. ('k -> 'o & 'j) -> 'n -> 'o) -> 'l) -> ('i -> 'i | 'l) | 'e) -> (forall 'p 'q 'r 'j1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'j1) -> ('j1 -> 'j1 | 'p | 'q) | 't | 'c | 'u) -> 'b & 'v) & 'u)) & (forall 'j 'k 'l 'm 'n. ((forall 'h. anything -> 'h -> 'h) -> ('j -> 'n -> 'k & 'm)) -> ('m -> (forall 'o. ('k -> 'o & 'j) -> 'n -> 'o) -> 'l) -> 'l) -> (forall 'q. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q) -> 'q) -> (forall 'd1. 'd1 -> anything -> 'd1) -> anything & 'd -> 'f //│ 'f <: (forall 'p 'q 'r 'k1. ((forall 'h. anything -> 'h -> 'h) -> (forall 'h. anything -> 'h -> 'h) -> 'q & 'r & 'k1) -> ('k1 -> 'k1 | 'p | 'q) | 'w | 'c | 'u) -> 'c //│ 'i1 :> forall 'p 'l1 'r. 'r -> ('l1 -> 'l1 | 'p) | 'c //│ <: (forall 'h. anything -> 'h -> 'h) -> (nothing -> nothing -> anything & 'b1) & 'b & 't & 'w diff --git a/shared/src/test/diff/mlf-examples/ex_propagate.mls b/shared/src/test/diff/mlf-examples/ex_propagate.mls index 759c7ede61..945305e1bf 100644 --- a/shared/src/test/diff/mlf-examples/ex_propagate.mls +++ b/shared/src/test/diff/mlf-examples/ex_propagate.mls @@ -38,7 +38,7 @@ fun x -> ((fun y -> y y) : 'a -> Sid) fun x_ -> (fun y -> y y) //│ res: anything -> ('a -> Sid & 'a) -> Sid //│ = [Function: res] -//│ res: anything -> (forall 'a 'b. ('a -> 'b & 'a) -> 'b) +//│ res: anything -> (forall 'a 'b. ('b -> 'a & 'b) -> 'a) //│ = [Function: res] // let (delta:sid -> sid) = fun x -> x x diff --git a/shared/src/test/diff/mlf-examples/ex_selfapp.mls b/shared/src/test/diff/mlf-examples/ex_selfapp.mls index cf87cc3dcf..47bcff7c19 100644 --- a/shared/src/test/diff/mlf-examples/ex_selfapp.mls +++ b/shared/src/test/diff/mlf-examples/ex_selfapp.mls @@ -129,7 +129,7 @@ b = error: Baa def build_ = fun g -> g (fun x -> fun xs -> Cons (x, xs)) Nil -//│ build_: ((forall 'b. 'b -> (forall 'tail 'a. (List['a] & 'tail) -> (Cons['a | 'b] with {head: 'b, tail: 'tail}))) -> Nil -> 'c) -> 'c +//│ build_: ((forall 'b. 'b -> (forall 'a 'tail. (List['a] & 'tail) -> (Cons['a | 'b] with {head: 'b, tail: 'tail}))) -> Nil -> 'c) -> 'c //│ = [Function: build_] :e // * Expected: List is a structural equirecursive types and recursive types are disabled @@ -423,7 +423,7 @@ def k: int -> Baa -> Baa :e def k = fun x -> fun (xs: Baa) -> fun c -> fun n -> c (x + 1) (xs k z c n) -//│ int -> Baa -> (forall 'a 'b. (int -> 'b -> 'a) -> 'b -> 'a) +//│ int -> Baa -> (forall 'a 'b. (int -> 'a -> 'b) -> 'a -> 'b) //│ <: k: //│ int -> Baa -> Baa //│ ╔══[ERROR] Type mismatch in def definition: diff --git a/shared/src/test/diff/mlf-examples/ex_shallow.mls b/shared/src/test/diff/mlf-examples/ex_shallow.mls index 765ec7078d..d3ef3c8df9 100644 --- a/shared/src/test/diff/mlf-examples/ex_shallow.mls +++ b/shared/src/test/diff/mlf-examples/ex_shallow.mls @@ -324,11 +324,11 @@ def a2_ (x: A1) = //│ = [Function: a31] //│ a2: A1 -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) +//│ forall 'b 'c 'd 'e. ('d -> 'e -> 'b) -> ('b -> 'c & 'd) -> 'e -> 'c <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a21] //│ a2_: A1 -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) +//│ forall 'b 'c 'd 'e. ('d -> 'e -> 'b) -> ('b -> 'c & 'd) -> 'e -> 'c <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a2_1] def a0 = a2 a1 @@ -340,7 +340,7 @@ def a0 = a2 a1 def a0_ = a2_ a1 //│ a0_: anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a +//│ forall 'b 'c 'd 'e. ('d -> 'e -> 'b) -> ('b -> 'c & 'd) -> 'e -> 'c <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a //│ = [Function: a0_1] def a1' = fun f -> fun x -> f (f (either id x)) @@ -357,7 +357,7 @@ def a2' (x: A1') = ) a3 //│ a2': A1' -> (forall 'a. anything -> 'a //│ where -//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) +//│ forall 'b 'c 'd 'e. ('d -> 'e -> 'b) -> ('b -> 'c & 'd) -> 'e -> 'c <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a) //│ = [Function: a2$1] def a2'_ x = @@ -423,7 +423,7 @@ def a0'_ = a2'_ a1' //│ ╙── Note: use flag `:ex` to see internal error info. //│ a0'_: anything -> 'a | error //│ where -//│ forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('d -> 'e & 'b) -> 'c -> 'e <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a +//│ forall 'b 'c 'd 'e. ('e -> 'b -> 'c) -> ('c -> 'd & 'e) -> 'b -> 'd <: (forall 'f 'g 'h. ('f -> 'g & 'g -> 'h) -> 'f -> 'h) -> 'a //│ = [Function: a0$_2] // * ^ Strangely, this one works with recursive types: diff --git a/shared/src/test/diff/mlf-examples/ex_validate.mls b/shared/src/test/diff/mlf-examples/ex_validate.mls index 9272443f84..e73dbd09e5 100644 --- a/shared/src/test/diff/mlf-examples/ex_validate.mls +++ b/shared/src/test/diff/mlf-examples/ex_validate.mls @@ -812,7 +812,7 @@ def a = fun f -> f id //│ = [Function: church_succ] //│ f: Sa -> Sid //│ = [Function: f] -//│ f_: ((forall 'a 'b. ('b -> 'a & 'b) -> 'a) -> 'c & (forall 'd 'e. ((forall 'f. anything -> 'f -> 'f) -> 'd -> anything) -> 'd -> 'e -> 'e) -> anything) -> 'c +//│ f_: ((forall 'a 'b. ('a -> 'b & 'a) -> 'b) -> 'c & (forall 'd 'e. ((forall 'f. anything -> 'f -> 'f) -> 'd -> anything) -> 'd -> 'e -> 'e) -> anything) -> 'c //│ = [Function: f_] //│ a: ((forall 'a. 'a -> 'a) -> 'b) -> 'b //│ = [Function: a] diff --git a/shared/src/test/diff/mlscript/Addable.mls b/shared/src/test/diff/mlscript/Addable.mls index 10f9e12a85..e08d70a831 100644 --- a/shared/src/test/diff/mlscript/Addable.mls +++ b/shared/src/test/diff/mlscript/Addable.mls @@ -4,26 +4,26 @@ class Addable[A] //│ Defined class Addable[=A] //│ Declared Addable.Add: Addable['A] -> 'A -> 'A -class Num: Addable[Num] & { val: int } - method Add that = Num { val = this.val + that.val } -//│ Defined class Num -//│ Defined Num.Add: Num -> {val: int} -> Num +class Numb: Addable[Numb] & { val: int } + method Add that = Numb { val = this.val + that.val } +//│ Defined class Numb +//│ Defined Numb.Add: Numb -> {val: int} -> Numb -class Str: Addable[Str] & { val: string } - method Add that = Str { val = concat this.val that.val } -//│ Defined class Str -//│ Defined Str.Add: Str -> {val: string} -> Str +class Stri: Addable[Stri] & { val: string } + method Add that = Stri { val = concat this.val that.val } +//│ Defined class Stri +//│ Defined Stri.Add: Stri -> {val: string} -> Stri -n = Num { val = 1 } -//│ n: Num & {val: 1} -//│ = Num { val: 1 } +n = Numb { val = 1 } +//│ n: Numb & {val: 1} +//│ = Numb { val: 1 } n.Add n -//│ res: Num -//│ = Num { val: 2 } +//│ res: Numb +//│ = Numb { val: 2 } n.Add -//│ res: Num -> Num +//│ res: Numb -> Numb //│ = [Function: Add] @@ -33,20 +33,20 @@ def addTwo a0 a1 = a0.Add a1 addTwo n n -//│ res: Num -//│ = Num { val: 2 } +//│ res: Numb +//│ = Numb { val: 2 } -s = Str { val = "hey" } -//│ s: Str & {val: "hey"} -//│ = Str { val: 'hey' } +s = Stri { val = "hey" } +//│ s: Stri & {val: "hey"} +//│ = Stri { val: 'hey' } s.Add s -//│ res: Str -//│ = Str { val: 'heyhey' } +//│ res: Stri +//│ = Stri { val: 'heyhey' } addTwo s s -//│ res: Str -//│ = Str { val: 'heyhey' } +//│ res: Stri +//│ = Stri { val: 'heyhey' } @@ -55,8 +55,8 @@ def addSame a = a.Add a //│ = [Function: addSame] addSame n -//│ res: Num -//│ = Num { val: 2 } +//│ res: Numb +//│ = Numb { val: 2 } rec def addNTimes a n = @@ -65,12 +65,12 @@ rec def addNTimes a n = //│ = [Function: addNTimes] addNTimes n 12 -//│ res: Num -//│ = Num { val: 12 } +//│ res: Numb +//│ = Numb { val: 12 } addNTimes s 5 -//│ res: Str -//│ = Str { val: 'heyheyheyheyhey' } +//│ res: Stri +//│ = Stri { val: 'heyheyheyheyhey' } @@ -91,12 +91,12 @@ addNTimes n 12 //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+3: addNTimes n 12 //│ ║ ^^^^^^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `Num` +//│ ╟── integer literal of type `0` is not an instance of type `Numb` //│ ║ l.+2: if n < 0 then 0 else a.Add (addNTimes a (n - 1)) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.7: class Num: Addable[Num] & { val: int } -//│ ╙── ^^^ +//│ ║ l.7: class Numb: Addable[Numb] & { val: int } +//│ ╙── ^^^^ //│ res: error rec def addNTimes a n = @@ -113,23 +113,23 @@ addNTimes n 12 //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+1: addNTimes n 12 //│ ║ ^^^^^^^^^^^ -//│ ╟── function of type `?a -> ?b -> ?c` is not an instance of type `Num` +//│ ╟── function of type `?a -> ?b -> ?c` is not an instance of type `Numb` //│ ║ l.102: rec def addNTimes a n = //│ ║ ^^^^^ //│ ║ l.103: if n <= 0 then 0 else a.Add addNTimes a (n - 1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.7: class Num: Addable[Num] & { val: int } -//│ ╙── ^^^ +//│ ║ l.7: class Numb: Addable[Numb] & { val: int } +//│ ╙── ^^^^ //│ res: error addSame n n //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+1: addSame n n //│ ║ ^^^^^^^^^^^ -//│ ╟── application of type `Num & {val: ?val}` is not a function -//│ ║ l.17: n = Num { val = 1 } -//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── application of type `Numb & {val: ?val}` is not a function +//│ ║ l.17: n = Numb { val = 1 } +//│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(forall ?a. ?a) -> ?b` //│ ║ l.+1: addSame n n //│ ╙── ^ @@ -139,15 +139,15 @@ addTwo s n //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+1: addTwo s n //│ ║ ^^^^^^^^^^ -//│ ╟── application of type `Num & {val: ?val}` is not an instance of type `Str` -//│ ║ l.17: n = Num { val = 1 } -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `Str` +//│ ╟── application of type `Numb & {val: ?val}` is not an instance of type `Stri` +//│ ║ l.17: n = Numb { val = 1 } +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `Stri` //│ ║ l.+1: addTwo s n //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: class Str: Addable[Str] & { val: string } -//│ ║ ^^^ +//│ ║ l.12: class Stri: Addable[Stri] & { val: string } +//│ ║ ^^^^ //│ ╟── from reference: //│ ║ l.30: def addTwo a0 a1 = a0.Add a1 //│ ╙── ^^ diff --git a/shared/src/test/diff/mlscript/Arrays.mls b/shared/src/test/diff/mlscript/Arrays.mls index 68e9c914ff..b31887f9c5 100644 --- a/shared/src/test/diff/mlscript/Arrays.mls +++ b/shared/src/test/diff/mlscript/Arrays.mls @@ -135,7 +135,7 @@ ty1A = ty1B //│ ╙── ^^^^^ //│ constrain calls : 5 //│ annoying calls : 5 -//│ subtyping calls : 61 +//│ subtyping calls : 69 :e :stats @@ -154,7 +154,7 @@ ty1B = ty1A //│ ╙── ^^^^^ //│ constrain calls : 5 //│ annoying calls : 5 -//│ subtyping calls : 51 +//│ subtyping calls : 59 :e diff --git a/shared/src/test/diff/mlscript/Baber.mls b/shared/src/test/diff/mlscript/Baber.mls index 3058bff92e..bc1217dacd 100644 --- a/shared/src/test/diff/mlscript/Baber.mls +++ b/shared/src/test/diff/mlscript/Baber.mls @@ -13,11 +13,11 @@ def f e = case e of :ns f -//│ res: forall 'y 'z 'a 'b 'c 'd. 'a -> ('y | 'z | 'b) +//│ res: forall 'a 'z 'y 'b 'c 'd. 'a -> ('y | 'z | 'd) //│ where -//│ 'a <: #Foo & 'c | (#Foo & 'd | 'b & ~#Foo) & ~#Foo -//│ 'd <: {z: 'z} -//│ 'c <: {y: 'y} +//│ 'a <: #Foo & 'b | (#Foo & 'c | 'd & ~#Foo) & ~#Foo +//│ 'c <: {z: 'z} +//│ 'b <: {y: 'y} //│ = [Function: f] class Foo2: Foo[int] & { y: int } diff --git a/shared/src/test/diff/mlscript/David.mls b/shared/src/test/diff/mlscript/David.mls index eb8f58cb4c..081e345a75 100644 --- a/shared/src/test/diff/mlscript/David.mls +++ b/shared/src/test/diff/mlscript/David.mls @@ -124,14 +124,14 @@ addOneS "Two" // Attempt 1: def isInt = fun x -> case x of { int -> true | string -> false } -//│ isInt: (int | string) -> bool +//│ isInt: (int | string) -> Bool //│ = [Function: isInt1] isInt 1 isInt "Two" -//│ res: bool +//│ res: Bool //│ = true -//│ res: bool +//│ res: Bool //│ = false def addOne = fun x -> if isInt x then addOneI x else addOneS x diff --git a/shared/src/test/diff/mlscript/David2.mls b/shared/src/test/diff/mlscript/David2.mls index 9b25bc4025..3daa26b6ee 100644 --- a/shared/src/test/diff/mlscript/David2.mls +++ b/shared/src/test/diff/mlscript/David2.mls @@ -2,15 +2,15 @@ class Integer: { value: int; addOne: Integer -> Integer } //│ Defined class Integer -class Num: Integer & { addOne: Num -> Num } -//│ Defined class Num +class Numb: Integer & { addOne: Numb -> Numb } +//│ Defined class Numb -class Str: { value: string; addOne: Str -> Str } -//│ Defined class Str +class Stri: { value: string; addOne: Stri -> Stri } +//│ Defined class Stri addOne1 x = case x of { | Integer -> x.addOne x - | Num -> x.addOne x + | Numb -> x.addOne x } //│ addOne1: ((Integer\value with {addOne: 'a -> 'b}) & 'a) -> 'b //│ = [Function: addOne1] @@ -215,13 +215,13 @@ def mkIntegerPrecise3 = mkInteger :e -addOne1 (Str { value = ""; addOne = error }) +addOne1 (Stri { value = ""; addOne = error }) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.218: addOne1 (Str { value = ""; addOne = error }) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `Str & {addOne: ?addOne, value: ?value}` does not match type `Integer & ?a` -//│ ║ l.218: addOne1 (Str { value = ""; addOne = error }) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.218: addOne1 (Stri { value = ""; addOne = error }) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Stri & {addOne: ?addOne, value: ?value}` does not match type `Integer & ?a` +//│ ║ l.218: addOne1 (Stri { value = ""; addOne = error }) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.11: addOne1 x = case x of { //│ ╙── ^ @@ -232,10 +232,10 @@ addOne1 (Str { value = ""; addOne = error }) addOne2 x = case x of { | Integer -> x.addOne x - | Num -> x.addOne x - | Str -> x.addOne x + | Numb -> x.addOne x + | Stri -> x.addOne x } -//│ addOne2: ((Integer\value with {addOne: 'a -> 'b}) & 'a | (Str\value with {addOne: 'c -> 'b}) & 'c) -> 'b +//│ addOne2: ((Integer\value with {addOne: 'a -> 'b}) & 'a | (Stri\value with {addOne: 'c -> 'b}) & 'c) -> 'b //│ = [Function: addOne2] addOne2 (mkIntegerPrecise 42) @@ -243,35 +243,35 @@ addOne2 (mkIntegerPrecise 42) //│ = Integer { value: 43, addOne: [Function: addOne] } :re -addOne2 (Str { value = ""; addOne = error }) +addOne2 (Stri { value = ""; addOne = error }) //│ res: nothing //│ Runtime error: //│ Error: unexpected runtime error -def mkStr: string -> Str -rec def mkStr value = Str { value; addOne = fun s -> mkStr (concat s.value "1") } -//│ mkStr: string -> Str +def mkStr: string -> Stri +rec def mkStr value = Stri { value; addOne = fun s -> mkStr (concat s.value "1") } +//│ mkStr: string -> Stri //│ = //│ string -> 'a //│ where -//│ 'a :> Str with {addOne: {value: string} -> 'a} +//│ 'a :> Stri with {addOne: {value: string} -> 'a} //│ <: mkStr: -//│ string -> Str +//│ string -> Stri //│ = [Function: mkStr] addOne2 (mkStr "hello") -//│ res: Str -//│ = Str { value: 'hello1', addOne: [Function: addOne] } +//│ res: Stri +//│ = Stri { value: 'hello1', addOne: [Function: addOne] } union = if true then mkIntegerPrecise 42 else mkStr "hello" -//│ union: Integer & {value: 42} | Str +//│ union: Integer & {value: 42} | Stri //│ = Integer { value: 42, addOne: [Function: addOne] } union2 = addOne2 union -//│ union2: Integer | Str +//│ union2: Integer | Stri //│ = Integer { value: 43, addOne: [Function: addOne] } addOne2 union2 -//│ res: Integer | Str +//│ res: Integer | Stri //│ = Integer { value: 44, addOne: [Function: addOne] } diff --git a/shared/src/test/diff/mlscript/ExprProb.mls b/shared/src/test/diff/mlscript/ExprProb.mls index 77994518ce..ab58952555 100644 --- a/shared/src/test/diff/mlscript/ExprProb.mls +++ b/shared/src/test/diff/mlscript/ExprProb.mls @@ -50,13 +50,13 @@ rec def eval1_stub e = case e of { | Add -> eval1_stub e.lhs | _ -> 0 } -//│ eval1_stub: forall 'a 'b 'c 'eval1_stub 'd 'e 'lhs. 'eval1_stub +//│ eval1_stub: forall 'lhs 'a 'eval1_stub 'b 'c 'd 'e. 'eval1_stub //│ where -//│ 'eval1_stub := 'e -> (1 | 'd | 0) -//│ 'd :> 1 | 'd | 0 -//│ 'e <: #Lit & 'a | (#Add & 'b | 'c & ~#Add) & ~#Lit -//│ 'b <: {lhs: 'lhs} -//│ 'lhs <: 'e +//│ 'eval1_stub := 'b -> (1 | 'a | 0) +//│ 'a :> 1 | 'a | 0 +//│ 'b <: #Lit & 'c | (#Add & 'd | 'e & ~#Add) & ~#Lit +//│ 'd <: {lhs: 'lhs} +//│ 'lhs <: 'b //│ = [Function: eval1_stub2] eval1_stub @@ -78,22 +78,22 @@ rec def eval1 k e = case e of { //│ = [Function: eval1] //│ constrain calls : 79 //│ annoying calls : 0 -//│ subtyping calls : 313 +//│ subtyping calls : 334 :ns eval1 -//│ res: forall 'val 'a 'b 'lhs 'eval1 'c 'rhs 'd 'e 'f 'g. 'eval1 -//│ where -//│ 'eval1 := 'c -> 'e -> ('val | 'a | 'g) -//│ 'a := int -//│ 'e <: #Lit & 'b | (#Add & 'd | 'f & ~#Add) & ~#Lit -//│ 'd <: {rhs: 'rhs} & {lhs: 'lhs} -//│ 'lhs <: 'e -//│ 'rhs <: 'e -//│ 'b <: {val: 'val} +//│ res: forall 'a 'b 'c 'd 'rhs 'lhs 'e 'val 'f 'eval1 'g. 'eval1 +//│ where +//│ 'eval1 := 'g -> 'b -> ('val | 'd | 'f) +//│ 'd := int +//│ 'b <: #Lit & 'c | (#Add & 'a | 'e & ~#Add) & ~#Lit +//│ 'a <: {rhs: 'rhs} & {lhs: 'lhs} +//│ 'lhs <: 'b +//│ 'rhs <: 'b +//│ 'c <: {val: 'val} //│ 'val <: int -//│ 'c <: 'f -> 'g -//│ 'g <: int +//│ 'g <: 'e -> 'f +//│ 'f <: int //│ = [Function: eval1] :re @@ -154,7 +154,7 @@ def eval1_ty_ugly = eval1 //│ = [Function: eval1_ty_ugly] //│ constrain calls : 77 //│ annoying calls : 37 -//│ subtyping calls : 713 +//│ subtyping calls : 783 :ns def eval1_ty: ('a -> int) -> (Lit | Add['b] | 'a & ~lit & ~add as 'b) -> int @@ -182,7 +182,7 @@ def eval1_ty = eval1 //│ = [Function: eval1_ty] //│ constrain calls : 77 //│ annoying calls : 37 -//│ subtyping calls : 711 +//│ subtyping calls : 781 :stats eval1_ty_ugly = eval1_ty @@ -196,7 +196,7 @@ eval1_ty_ugly = eval1_ty //│ = [Function: eval1] //│ constrain calls : 36 //│ annoying calls : 33 -//│ subtyping calls : 442 +//│ subtyping calls : 540 :stats eval1_ty = eval1_ty_ugly @@ -210,7 +210,7 @@ eval1_ty = eval1_ty_ugly //│ = [Function: eval1] //│ constrain calls : 208 //│ annoying calls : 529 -//│ subtyping calls : 4578 +//│ subtyping calls : 4676 // Workaround: @@ -236,7 +236,7 @@ def eval1_ty = eval1 //│ = [Function: eval1_ty2] //│ constrain calls : 73 //│ annoying calls : 37 -//│ subtyping calls : 587 +//│ subtyping calls : 608 :stats @@ -251,7 +251,7 @@ rec def pretty1 k e = case e of { //│ = [Function: pretty1] //│ constrain calls : 87 //│ annoying calls : 0 -//│ subtyping calls : 350 +//│ subtyping calls : 371 :stats @@ -269,7 +269,7 @@ rec def prettier1 k ev e = case e of { //│ = [Function: prettier1] //│ constrain calls : 293 //│ annoying calls : 0 -//│ subtyping calls : 1016 +//│ subtyping calls : 1037 :stats rec def prettier11 k ev e = case e of { @@ -286,7 +286,7 @@ rec def prettier11 k ev e = case e of { //│ = [Function: prettier11] //│ constrain calls : 191 //│ annoying calls : 0 -//│ subtyping calls : 724 +//│ subtyping calls : 766 // Doesn't make much sense, but generates very ugly type unless aggressively simplified: :stats @@ -303,7 +303,7 @@ rec def prettier12 k ev e = case e of { //│ = [Function: prettier12] //│ constrain calls : 166 //│ annoying calls : 0 -//│ subtyping calls : 746 +//│ subtyping calls : 800 :stats @@ -330,7 +330,7 @@ prettier12 done (eval1 done) e1 //│ = '123' //│ constrain calls : 1315 //│ annoying calls : 500 -//│ subtyping calls : 13379 +//│ subtyping calls : 13397 e1 = add (lit 1) (add (lit 2) (lit 3)) @@ -388,7 +388,7 @@ rec def prettier2 k ev = prettier1 (fun x -> case x of { //│ = [Function: prettier2] //│ constrain calls : 136 //│ annoying calls : 0 -//│ subtyping calls : 599 +//│ subtyping calls : 630 :stats rec def prettier22 k ev = prettier12 (fun x -> case x of { @@ -403,7 +403,7 @@ rec def prettier22 k ev = prettier12 (fun x -> case x of { //│ = [Function: prettier22] //│ constrain calls : 208 //│ annoying calls : 0 -//│ subtyping calls : 970 +//│ subtyping calls : 1038 @@ -469,7 +469,7 @@ prettier2 done (eval1 done) //│ = [Function (anonymous)] //│ constrain calls : 101 //│ annoying calls : 0 -//│ subtyping calls : 554 +//│ subtyping calls : 585 @@ -496,7 +496,7 @@ prettier2 done (eval2 done) //│ = [Function (anonymous)] //│ constrain calls : 119 //│ annoying calls : 0 -//│ subtyping calls : 772 +//│ subtyping calls : 835 prettier2 done (eval2 done) e2 prettier2 done (eval2 done) d2 @@ -523,7 +523,7 @@ prettier22 done (eval2 done) d2 //│ = '-1' //│ constrain calls : 1198 //│ annoying calls : 390 -//│ subtyping calls : 10978 +//│ subtyping calls : 11073 @@ -608,7 +608,7 @@ prettier2 done (eval1 done) e2 //│ Error: non-exhaustive case expression //│ constrain calls : 714 //│ annoying calls : 238 -//│ subtyping calls : 9193 +//│ subtyping calls : 9197 :e :stats @@ -637,7 +637,7 @@ prettier2 done eval2 //│ = [Function (anonymous)] //│ constrain calls : 79 //│ annoying calls : 0 -//│ subtyping calls : 518 +//│ subtyping calls : 555 :e :stats @@ -675,7 +675,7 @@ prettier2 done eval2 e1 //│ = '123' //│ constrain calls : 410 //│ annoying calls : 108 -//│ subtyping calls : 4528 +//│ subtyping calls : 4540 :e :stats @@ -713,7 +713,7 @@ prettier2 done eval2 e2 //│ = '1-123' //│ constrain calls : 469 //│ annoying calls : 131 -//│ subtyping calls : 5068 +//│ subtyping calls : 5080 :e :stats @@ -751,7 +751,7 @@ prettier2 done eval2 d2 //│ = '-1-1' //│ constrain calls : 335 //│ annoying calls : 95 -//│ subtyping calls : 3042 +//│ subtyping calls : 3058 :e :stats @@ -789,5 +789,5 @@ prettier2 done eval1 e2 //│ = '1-123' //│ constrain calls : 457 //│ annoying calls : 131 -//│ subtyping calls : 4954 +//│ subtyping calls : 4966 diff --git a/shared/src/test/diff/mlscript/ExprProb2.mls b/shared/src/test/diff/mlscript/ExprProb2.mls index 66559127fc..f688819102 100644 --- a/shared/src/test/diff/mlscript/ExprProb2.mls +++ b/shared/src/test/diff/mlscript/ExprProb2.mls @@ -23,7 +23,7 @@ def eval1 eval1 e = case e of { //│ = [Function: eval1] //│ constrain calls : 36 //│ annoying calls : 0 -//│ subtyping calls : 179 +//│ subtyping calls : 193 :stats :js @@ -45,7 +45,7 @@ def eval1f eval1 e = case e of { //│ = [Function: eval1f] //│ constrain calls : 32 //│ annoying calls : 0 -//│ subtyping calls : 156 +//│ subtyping calls : 170 e1 = add (lit 1) (add (lit 2) (lit 3)) diff --git a/shared/src/test/diff/mlscript/ExprProb_Inv.mls b/shared/src/test/diff/mlscript/ExprProb_Inv.mls index 0e79410d89..8178ce60fa 100644 --- a/shared/src/test/diff/mlscript/ExprProb_Inv.mls +++ b/shared/src/test/diff/mlscript/ExprProb_Inv.mls @@ -52,13 +52,13 @@ rec def eval1_stub e = case e of { | Add -> eval1_stub e.lhs | _ -> 0 } -//│ eval1_stub: forall 'a 'b 'c 'd 'e 'lhs 'eval1_stub. 'eval1_stub +//│ eval1_stub: forall 'eval1_stub 'a 'b 'lhs 'c 'd 'e. 'eval1_stub //│ where -//│ 'eval1_stub := 'd -> (1 | 'e | 0) -//│ 'e :> 1 | 'e | 0 -//│ 'd <: #Lit & 'b | (#Add & 'a | 'c & ~#Add) & ~#Lit -//│ 'a <: {lhs: 'lhs} -//│ 'lhs <: 'd +//│ 'eval1_stub := 'b -> (1 | 'a | 0) +//│ 'a :> 1 | 'a | 0 +//│ 'b <: #Lit & 'e | (#Add & 'c | 'd & ~#Add) & ~#Lit +//│ 'c <: {lhs: 'lhs} +//│ 'lhs <: 'b //│ = [Function: eval1_stub2] eval1_stub @@ -80,21 +80,21 @@ rec def eval1 k e = case e of { //│ = [Function: eval1] //│ constrain calls : 79 //│ annoying calls : 0 -//│ subtyping calls : 334 +//│ subtyping calls : 353 :ns eval1 -//│ res: forall 'eval1 'a 'b 'rhs 'c 'lhs 'd 'e 'f 'val 'g. 'eval1 -//│ where -//│ 'eval1 := 'e -> 'c -> ('val | 'f | 'g) -//│ 'f := int -//│ 'c <: #Lit & 'b | (#Add & 'd | 'a & ~#Add) & ~#Lit -//│ 'd <: {rhs: 'rhs} & {lhs: 'lhs} -//│ 'lhs <: 'c -//│ 'rhs <: 'c -//│ 'b <: {val: 'val} +//│ res: forall 'a 'rhs 'b 'c 'd 'val 'e 'lhs 'f 'g 'eval1. 'eval1 +//│ where +//│ 'eval1 := 'b -> 'a -> ('val | 'd | 'g) +//│ 'd := int +//│ 'a <: #Lit & 'f | (#Add & 'c | 'e & ~#Add) & ~#Lit +//│ 'c <: {rhs: 'rhs} & {lhs: 'lhs} +//│ 'lhs <: 'a +//│ 'rhs <: 'a +//│ 'f <: {val: 'val} //│ 'val <: int -//│ 'e <: 'a -> 'g +//│ 'b <: 'e -> 'g //│ 'g <: int //│ = [Function: eval1] @@ -156,7 +156,7 @@ def eval1_ty_ugly = eval1 //│ = [Function: eval1_ty_ugly] //│ constrain calls : 77 //│ annoying calls : 37 -//│ subtyping calls : 756 +//│ subtyping calls : 824 :ns def eval1_ty: ('a -> int) -> (Lit | Add['b] | 'a & ~lit & ~add as 'b) -> int @@ -184,7 +184,7 @@ def eval1_ty = eval1 //│ = [Function: eval1_ty] //│ constrain calls : 77 //│ annoying calls : 37 -//│ subtyping calls : 748 +//│ subtyping calls : 816 :stats eval1_ty_ugly = eval1_ty @@ -198,7 +198,7 @@ eval1_ty_ugly = eval1_ty //│ = [Function: eval1] //│ constrain calls : 150 //│ annoying calls : 1810 -//│ subtyping calls : 4879 +//│ subtyping calls : 4977 :stats eval1_ty = eval1_ty_ugly @@ -212,7 +212,7 @@ eval1_ty = eval1_ty_ugly //│ = [Function: eval1] //│ constrain calls : 752 //│ annoying calls : 674 -//│ subtyping calls : 75734 +//│ subtyping calls : 75832 // Workaround: @@ -238,7 +238,7 @@ def eval1_ty = eval1 //│ = [Function: eval1_ty2] //│ constrain calls : 73 //│ annoying calls : 37 -//│ subtyping calls : 608 +//│ subtyping calls : 627 :stats @@ -253,7 +253,7 @@ rec def pretty1 k e = case e of { //│ = [Function: pretty1] //│ constrain calls : 87 //│ annoying calls : 0 -//│ subtyping calls : 371 +//│ subtyping calls : 390 :stats @@ -271,7 +271,7 @@ rec def prettier1 k ev e = case e of { //│ = [Function: prettier1] //│ constrain calls : 293 //│ annoying calls : 0 -//│ subtyping calls : 1043 +//│ subtyping calls : 1062 :stats rec def prettier11 k ev e = case e of { @@ -288,7 +288,7 @@ rec def prettier11 k ev e = case e of { //│ = [Function: prettier11] //│ constrain calls : 191 //│ annoying calls : 0 -//│ subtyping calls : 770 +//│ subtyping calls : 808 // Doesn't make much sense, but generates very ugly type unless aggressively simplified: :stats @@ -305,7 +305,7 @@ rec def prettier12 k ev e = case e of { //│ = [Function: prettier12] //│ constrain calls : 166 //│ annoying calls : 0 -//│ subtyping calls : 811 +//│ subtyping calls : 861 :stats @@ -335,7 +335,7 @@ prettier12 done (eval1 done) e1 //│ = '123' //│ constrain calls : 1315 //│ annoying calls : 500 -//│ subtyping calls : 13241 +//│ subtyping calls : 13254 e1 = add (lit 1) (add (lit 2) (lit 3)) @@ -396,7 +396,7 @@ rec def prettier2 k ev = prettier1 (fun x -> case x of { //│ = [Function: prettier2] //│ constrain calls : 136 //│ annoying calls : 0 -//│ subtyping calls : 653 +//│ subtyping calls : 682 :stats rec def prettier22 k ev = prettier12 (fun x -> case x of { @@ -411,7 +411,7 @@ rec def prettier22 k ev = prettier12 (fun x -> case x of { //│ = [Function: prettier22] //│ constrain calls : 208 //│ annoying calls : 0 -//│ subtyping calls : 1018 +//│ subtyping calls : 1083 @@ -483,7 +483,7 @@ prettier2 done (eval1 done) //│ = [Function (anonymous)] //│ constrain calls : 101 //│ annoying calls : 0 -//│ subtyping calls : 668 +//│ subtyping calls : 696 prettier22 done (eval1 done) @@ -509,7 +509,7 @@ prettier2 done (eval2 done) //│ = [Function (anonymous)] //│ constrain calls : 119 //│ annoying calls : 0 -//│ subtyping calls : 934 +//│ subtyping calls : 991 prettier2 done (eval2 done) e2 prettier2 done (eval2 done) d2 @@ -536,7 +536,7 @@ prettier22 done (eval2 done) d2 //│ = '-1' //│ constrain calls : 1198 //│ annoying calls : 390 -//│ subtyping calls : 11068 +//│ subtyping calls : 11159 @@ -621,7 +621,7 @@ prettier2 done (eval1 done) e2 //│ Error: non-exhaustive case expression //│ constrain calls : 714 //│ annoying calls : 238 -//│ subtyping calls : 9199 +//│ subtyping calls : 9203 :e :stats @@ -650,7 +650,7 @@ prettier2 done eval2 //│ = [Function (anonymous)] //│ constrain calls : 79 //│ annoying calls : 0 -//│ subtyping calls : 580 +//│ subtyping calls : 615 :e :stats @@ -688,7 +688,7 @@ prettier2 done eval2 e1 //│ = '123' //│ constrain calls : 410 //│ annoying calls : 108 -//│ subtyping calls : 4540 +//│ subtyping calls : 4552 :e :stats @@ -726,7 +726,7 @@ prettier2 done eval2 e2 //│ = '1-123' //│ constrain calls : 469 //│ annoying calls : 131 -//│ subtyping calls : 5078 +//│ subtyping calls : 5090 :e :stats @@ -764,7 +764,7 @@ prettier2 done eval2 d2 //│ = '-1-1' //│ constrain calls : 335 //│ annoying calls : 95 -//│ subtyping calls : 3052 +//│ subtyping calls : 3068 :e :stats @@ -802,5 +802,5 @@ prettier2 done eval1 e2 //│ = '1-123' //│ constrain calls : 457 //│ annoying calls : 131 -//│ subtyping calls : 4960 +//│ subtyping calls : 4972 diff --git a/shared/src/test/diff/mlscript/FunnySubsumptions.mls b/shared/src/test/diff/mlscript/FunnySubsumptions.mls index a5cae7751a..f8fa408a5c 100644 --- a/shared/src/test/diff/mlscript/FunnySubsumptions.mls +++ b/shared/src/test/diff/mlscript/FunnySubsumptions.mls @@ -24,7 +24,7 @@ A0 = B0 //│ D & {x: T} | {x: T, y: S} | C & {y: S} | C & D //│ constrain calls : 1 //│ annoying calls : 0 -//│ subtyping calls : 167 +//│ subtyping calls : 203 :stats B0 = A0 @@ -33,7 +33,7 @@ B0 = A0 //│ {x: T, y: S} | D & {x: T} | C & {y: S} //│ constrain calls : 2 //│ annoying calls : 32 -//│ subtyping calls : 282 +//│ subtyping calls : 318 def A1: C & {x : T} | D & {y : U} @@ -48,7 +48,7 @@ A1 = B1 //│ C & {x: T} | D & {y: U} //│ constrain calls : 2 //│ annoying calls : 13 -//│ subtyping calls : 251 +//│ subtyping calls : 276 :stats B1 = A1 @@ -57,6 +57,6 @@ B1 = A1 //│ C & {x: T} | D & {y: U} | C & D //│ constrain calls : 1 //│ annoying calls : 0 -//│ subtyping calls : 159 +//│ subtyping calls : 184 diff --git a/shared/src/test/diff/mlscript/MatchBool.mls b/shared/src/test/diff/mlscript/MatchBool.mls index 8f4b16a564..4f566be707 100644 --- a/shared/src/test/diff/mlscript/MatchBool.mls +++ b/shared/src/test/diff/mlscript/MatchBool.mls @@ -3,7 +3,7 @@ def absImpl lt x = case lt of { true -> x | false -> 0 - x } -//│ absImpl: bool -> int -> int +//│ absImpl: Bool -> int -> int //│ = [Function: absImpl] // * TODO support this @@ -29,6 +29,6 @@ def abs x = def neg b = case b of { true -> false | false -> true } -//│ neg: bool -> bool +//│ neg: Bool -> Bool //│ = [Function: neg] diff --git a/shared/src/test/diff/mlscript/Methods2.mls b/shared/src/test/diff/mlscript/Methods2.mls index d72f629530..dd9986dc5a 100644 --- a/shared/src/test/diff/mlscript/Methods2.mls +++ b/shared/src/test/diff/mlscript/Methods2.mls @@ -140,7 +140,7 @@ Cons.HeadOption l //│ TypeError: (intermediate value).HeadOption is not a function //│ constrain calls : 70 //│ annoying calls : 31 -//│ subtyping calls : 258 +//│ subtyping calls : 262 :stats o = l.(Cons.HeadOption) @@ -148,7 +148,7 @@ o = l.(Cons.HeadOption) //│ = undefined //│ constrain calls : 68 //│ annoying calls : 31 -//│ subtyping calls : 245 +//│ subtyping calls : 249 o = l.(Cons.HeadOption) //│ o: Some[0 | 1] diff --git a/shared/src/test/diff/mlscript/Misc.mls b/shared/src/test/diff/mlscript/Misc.mls index a41c1fc475..e000148d1e 100644 --- a/shared/src/test/diff/mlscript/Misc.mls +++ b/shared/src/test/diff/mlscript/Misc.mls @@ -46,27 +46,27 @@ def arg = if true then c else 0 :ns def arg = if true then C{x = 42} else C{x = 1} -//│ arg: forall 'x 'x0 'A 'A0 'a. 'a +//│ arg: forall 'x 'a 'x0 'A 'A0. 'a //│ where -//│ 'a :> #C & {x: 'x, C#A = 'A0} | #C & {x: 'x0, C#A = 'A} -//│ 'x0 :> 1 -//│ <: 'A -//│ 'A :> 1 -//│ 'x :> 42 +//│ 'a :> #C & {x: 'x0, C#A = 'A} | #C & {x: 'x, C#A = 'A0} +//│ 'x :> 1 //│ <: 'A0 -//│ 'A0 :> 42 +//│ 'A0 :> 1 +//│ 'x0 :> 42 +//│ <: 'A +//│ 'A :> 42 :ns arg -//│ res: forall 'x 'x0 'A 'A0 'a. 'a +//│ res: forall 'x 'a 'x0 'A 'A0. 'a //│ where -//│ 'a :> #C & {x: 'x, C#A = 'A0} | #C & {x: 'x0, C#A = 'A} -//│ 'x0 :> 1 -//│ <: 'A -//│ 'A :> 1 -//│ 'x :> 42 +//│ 'a :> #C & {x: 'x0, C#A = 'A} | #C & {x: 'x, C#A = 'A0} +//│ 'x :> 1 //│ <: 'A0 -//│ 'A0 :> 42 +//│ 'A0 :> 1 +//│ 'x0 :> 42 +//│ <: 'A +//│ 'A :> 42 arg //│ res: C[1 | 42] diff --git a/shared/src/test/diff/mlscript/NestedClassArgs.mls b/shared/src/test/diff/mlscript/NestedClassArgs.mls index bc607c757c..eb7ab5d80d 100644 --- a/shared/src/test/diff/mlscript/NestedClassArgs.mls +++ b/shared/src/test/diff/mlscript/NestedClassArgs.mls @@ -163,7 +163,7 @@ def c: 'a -> C6['a] //│ c: 'a -> C6['a] rec def c6 a = C6{ a = c5 (c6 a) } -//│ c6: anything -> (C6['A] with {a: forall 'a 'A0 'A1. 'a}) +//│ c6: anything -> (C6['A] with {a: forall 'A0 'A1 'a. 'a}) //│ where //│ 'a :> C5['A0] with {a: C2['A1] with {a: 'a}} //│ 'A1 :> C5['A0] | 'a @@ -180,7 +180,7 @@ c = c6 //│ 'a -> C6['a] //│ constrain calls : 70 //│ annoying calls : 34 -//│ subtyping calls : 417 +//│ subtyping calls : 423 // Reproduction of an issue found while trying out TypeRef ctor typing: @@ -286,16 +286,16 @@ def append ls elem = L { h = elem; t = S { v = ls } } :ns append -//│ res: forall 'a 'h 'b 'c 'T 't 'v 'T0. 'a -> 'c -> 'b +//│ res: forall 't 'T 'v 'h 'T0 'a 'b 'c. 'a -> 'c -> 'b //│ where -//│ 'b :> #L & {h: 'h, t: 't, L#T = 'T0} -//│ 't :> #S & {v: 'v, S#T = 'T} -//│ <: O[L['T0]] +//│ 'b :> #L & {h: 'h, t: 't, L#T = 'T} +//│ 't :> #S & {v: 'v, S#T = 'T0} +//│ <: O[L['T]] //│ 'c <: 'h -//│ 'h <: 'T0 +//│ 'h <: 'T //│ 'a <: 'v -//│ 'v <: L['T0] & 'T -//│ 'T := L['T0] +//│ 'v <: L['T] & 'T0 +//│ 'T0 := L['T] append error //│ res: ('h & 'T) -> (L['T] with {h: 'h, t: S[L['T]] & {v: nothing}}) diff --git a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls index a83eee4eab..9ec6cffb68 100644 --- a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls +++ b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls @@ -129,7 +129,7 @@ def eval_lambda eval_rec subst v = case v of { Abs { name = new_name; body = eval_rec (Cons (Tuple v.name (Var { name = new_name })) subst) v.body } } -//│ eval_lambda: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('body & 'result & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | App[?] & {lhs: 'lhs, rhs: 'lhs} | Var & 'result) -> (Abs['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | 'result) +//│ eval_lambda: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('result & 'body & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | App[?] & {lhs: 'lhs, rhs: 'lhs} | Var & 'result) -> (Abs['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | 'result) //│ where //│ 'b <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'b}) | Nil //│ = @@ -166,20 +166,20 @@ rec def eval1 subst = eval_lambda eval1 subst // ************************* Expr ****************************** -class Num: Expr & { num: int } +class Numb: Expr & { num: int } class Add[a]: Expr & { lhs: a; rhs: a } class Mul[a]: Expr & { lhs: a; rhs: a } -//│ Defined class Num +//│ Defined class Numb //│ Defined class Add[+a] //│ Defined class Mul[+a] def map_expr f v = case v of { | Var -> v - | Num -> v + | Numb -> v | Add -> Add { lhs = f v.lhs; rhs = f v.rhs } | Mul -> Mul { lhs = f v.lhs; rhs = f v.rhs } } -//│ map_expr: ('lhs -> 'lhs0) -> (Add[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | 'a & (Num | Var)) -> (Add['lhs0] | Mul['lhs0] | 'a) +//│ map_expr: ('lhs -> 'lhs0) -> (Add[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | 'a & (Numb | Var)) -> (Add['lhs0] | Mul['lhs0] | 'a) //│ = [Function: map_expr] rec def eval_expr eval_rec subst v = @@ -189,8 +189,8 @@ rec def eval_expr eval_rec subst v = | Add -> let vv1 = vv.lhs in let vv2 = vv.rhs in case vv1 of { - | Num -> case vv2 of { - | Num -> Num { num = vv1.num + vv2.num } + | Numb -> case vv2 of { + | Numb -> Numb { num = vv1.num + vv2.num } | _ -> vv } | _ -> vv @@ -198,15 +198,15 @@ rec def eval_expr eval_rec subst v = | Mul -> let vv1 = vv.lhs in let vv2 = vv.rhs in case vv1 of { - | Num -> case vv2 of { - | Num -> Num { num = vv1.num * vv2.num } + | Numb -> case vv2 of { + | Numb -> Numb { num = vv1.num * vv2.num } | _ -> vv } | _ -> vv } - | Num -> vv // _ -> vv + | Numb -> vv // _ -> vv } -//│ eval_expr: ('a -> 'rhs -> 'rhs0) -> ('a & 'b) -> (Add[?] & {lhs: 'rhs, rhs: 'rhs} | Mul[?] & {lhs: 'rhs, rhs: 'rhs} | Num & 'result | Var & 'result) -> (Add['rhs0] | Mul['rhs0] | Num | 'result) +//│ eval_expr: ('a -> 'rhs -> 'rhs0) -> ('a & 'b) -> (Add[?] & {lhs: 'rhs, rhs: 'rhs} | Mul[?] & {lhs: 'rhs, rhs: 'rhs} | Numb & 'result | Var & 'result) -> (Add['rhs0] | Mul['rhs0] | Numb | 'result) //│ where //│ 'b <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'b}) | Nil //│ = @@ -215,9 +215,9 @@ rec def eval_expr eval_rec subst v = rec def eval2 subst = eval_expr eval2 subst //│ eval2: 'a -> 'b -> 'result //│ where -//│ 'b <: Add[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Num & 'result | Var & 'result -//│ 'a <: (Cons[?] with {head: {_1: string, _2: 'result & (Num | ~#Num)}, tail: 'a}) | Nil -//│ 'result :> Num | Add['result] | Mul['result] +//│ 'b <: Add[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & 'result | Var & 'result +//│ 'a <: (Cons[?] with {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: 'a}) | Nil +//│ 'result :> Numb | Add['result] | Mul['result] //│ = //│ eval_expr, eval_var, list_assoc and eq are not implemented @@ -225,26 +225,26 @@ rec def eval2 subst = eval_expr eval2 subst // ------------- OCaml's type ------------- // val map_expr : // ('a -> 'b) -> -// [< `Add of 'a * 'a | `Mult of 'a * 'a | `Num of 'c | `Var of string ] -> -// [> `Add of 'b * 'b | `Mult of 'b * 'b | `Num of 'c | `Var of string ] = +// [< `Add of 'a * 'a | `Mult of 'a * 'a | `Numb of 'c | `Var of string ] -> +// [> `Add of 'b * 'b | `Mult of 'b * 'b | `Numb of 'c | `Var of string ] = // val eval_expr : // ((string * -// ([> `Add of ([> `Num of int ] as 'b) * 'b +// ([> `Add of ([> `Numb of int ] as 'b) * 'b // | `Mult of 'b * 'b -// | `Num of int +// | `Numb of int // | `Var of string ] // as 'a)) // list -> 'c -> 'b) -> // (string * 'a) list -> -// [< `Add of 'c * 'c | `Mult of 'c * 'c | `Num of int | `Var of string ] -> 'a = +// [< `Add of 'c * 'c | `Mult of 'c * 'c | `Numb of int | `Var of string ] -> 'a = // // val eval2 : // (string * -// ([> `Add of 'a * 'a | `Mult of 'a * 'a | `Num of int | `Var of string ] +// ([> `Add of 'a * 'a | `Mult of 'a * 'a | `Numb of int | `Var of string ] // as 'a)) // list -> -// ([< `Add of 'b * 'b | `Mult of 'b * 'b | `Num of int | `Var of string ] as 'b) -> +// ([< `Add of 'b * 'b | `Mult of 'b * 'b | `Numb of int | `Var of string ] as 'b) -> // 'a = @@ -254,7 +254,7 @@ def eval_lexpr eval_rec subst v = case v of { | Lambda -> eval_lambda eval_rec subst v | Expr -> eval_expr eval_rec subst v } -//│ eval_lexpr: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('result & 'body & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | Add[?] & {lhs: 'lhs, rhs: 'lhs} | App[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | Num & 'result | Var & 'result) -> (Abs['body] | Add['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | Mul['body] | Num | 'result) +//│ eval_lexpr: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('body & 'result & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | Add[?] & {lhs: 'lhs, rhs: 'lhs} | App[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | Mul['body] | Numb | 'result) //│ where //│ 'b <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'b}) | Nil //│ = @@ -264,17 +264,17 @@ rec def eval3 subst = eval_lexpr eval3 subst //│ eval3: (List[?] & 'tail) -> 'b -> 'rhs //│ where //│ 'tail <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'tail}) | Nil -//│ 'result :> Var | 'rhs | Num -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Num | ~#Abs & ~#Num)) +//│ 'result :> Var | 'rhs | Numb +//│ <: 'b & (Abs[?] & 'c | 'lhs & (Numb | ~#Abs & ~#Numb)) //│ 'rhs :> Abs['rhs] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | 'result | 'd | 'e //│ 'a :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | 'rhs -//│ 'lhs :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Num | Var +//│ 'lhs :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Numb | Var //│ <: 'b & 'a -//│ 'b <: Abs[?] & {body: 'b} | Add[?] & {lhs: 'b, rhs: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Num & (Add[?] & 'e | Mul[?] & 'e | Num & 'result | Var & 'd) | Var & 'd +//│ 'b <: Abs[?] & {body: 'b} | Add[?] & {lhs: 'b, rhs: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & (Add[?] & 'e | Mul[?] & 'e | Numb & 'result | Var & 'd) | Var & 'd //│ 'd :> Var -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Num & {name: string} | {name: string} & ~#Abs & ~#Num)) +//│ <: 'b & (Abs[?] & 'c | 'lhs & (Numb & {name: string} | {name: string} & ~#Abs & ~#Numb)) //│ 'e :> (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) -//│ <: 'b & (Abs[?] & {lhs: anything, rhs: anything} & 'c | 'lhs & (Num & {lhs: anything, rhs: anything} | {lhs: anything, rhs: anything} & ~#Abs & ~#Num)) +//│ <: 'b & (Abs[?] & {lhs: anything, rhs: anything} & 'c | 'lhs & (Numb & {lhs: anything, rhs: anything} | {lhs: anything, rhs: anything} & ~#Abs & ~#Numb)) //│ 'c <: {body: 'b, name: string} //│ = //│ eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented @@ -286,7 +286,7 @@ rec def eval3 subst = eval_lexpr eval3 subst // | `Add of 'a * 'a // | `App of 'a * 'a // | `Mult of 'a * 'a -// | `Num of int +// | `Numb of int // | `Var of string ] // as 'a)) // list -> 'a -> 'a) -> @@ -295,7 +295,7 @@ rec def eval3 subst = eval_lexpr eval3 subst // | `Add of 'a * 'a // | `App of 'a * 'a // | `Mult of 'a * 'a -// | `Num of int +// | `Numb of int // | `Var of string ] -> // 'a = // @@ -305,7 +305,7 @@ rec def eval3 subst = eval_lexpr eval3 subst // | `Add of 'a * 'a // | `App of 'a * 'a // | `Mult of 'a * 'a -// | `Num of int +// | `Numb of int // | `Var of string ] as 'a)) // list -> 'a -> 'a = @@ -314,9 +314,9 @@ rec def eval3 subst = eval_lexpr eval3 subst eval3 Nil (Var { name = "s" }) //│ res: 'result //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b +//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b +//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented @@ -325,7 +325,7 @@ eval3 Nil (Var { name = "s" }) // | `Add of 'a * 'a // | `App of 'a * 'a // | `Mult of 'a * 'a -// | `Num of int +// | `Numb of int // | `Var of string ] as 'a // = `Var "s" @@ -333,46 +333,46 @@ eval3 Nil (Var { name = "s" }) eval3 Nil (Abs { name = "s"; body = Var { name = "s" } }) //│ res: 'result //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b +//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b +//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented -eval2 Nil (Num { num = 1 }) +eval2 Nil (Numb { num = 1 }) //│ res: 'rhs //│ where -//│ 'rhs :> Num | Add['rhs] | Mul['rhs] +//│ 'rhs :> Numb | Add['rhs] | Mul['rhs] //│ = //│ eval2, eval_expr, eval_var, list_assoc and eq are not implemented -eval3 Nil (Num { num = 1 }) +eval3 Nil (Numb { num = 1 }) //│ res: 'result //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b +//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b +//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented -eval3 Nil (App { lhs = Num {num = 0}; rhs = Num {num = 0}}) +eval3 Nil (App { lhs = Numb {num = 0}; rhs = Numb {num = 0}}) //│ res: 'result //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b +//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b +//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented -eval3 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Num { num = 1 } } }) +eval3 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Numb { num = 1 } } }) //│ res: 'result //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b +//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b +//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented @@ -388,11 +388,11 @@ def eval_lexpr' eval_rec subst v = case v of { | Var -> eval_var subst v | Abs -> eval_lambda eval_rec subst v | App -> eval_lambda eval_rec subst v - | Num -> eval_expr eval_rec subst v + | Numb -> eval_expr eval_rec subst v | Add -> eval_expr eval_rec subst v | Mul -> eval_expr eval_rec subst v } -//│ eval_lexpr': (((Cons[('b, Var | 'body,) | 'A] with {head: ('b, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'body0 -> ('body & 'result & ((Abs[?] with {body: 'body0, name: 'b}) | 'lhs & 'a & ((Abs[?] with {body: 'body0, name: 'b}) & ~#Abs | 'lhs & 'a & ~#Abs)))) -> (List['A] & 'c & 'tail) -> ((Abs[?] with {body: 'body0, name: 'b}) | Add[?] & {lhs: 'body0, rhs: 'body0} | App[?] & {lhs: 'body0, rhs: 'body0} | Mul[?] & {lhs: 'body0, rhs: 'body0} | Num & 'result | Var & 'result) -> (Abs['body] | Add['body] | (App['a | 'body] with {lhs: 'lhs, rhs: 'body}) | Mul['body] | Num | 'result) +//│ eval_lexpr': (((Cons[('b, Var | 'body,) | 'A] with {head: ('b, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'body0 -> ('body & 'result & ((Abs[?] with {body: 'body0, name: 'b}) | 'lhs & 'a & ((Abs[?] with {body: 'body0, name: 'b}) & ~#Abs | 'lhs & 'a & ~#Abs)))) -> (List['A] & 'c & 'tail) -> ((Abs[?] with {body: 'body0, name: 'b}) | Add[?] & {lhs: 'body0, rhs: 'body0} | App[?] & {lhs: 'body0, rhs: 'body0} | Mul[?] & {lhs: 'body0, rhs: 'body0} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | (App['a | 'body] with {lhs: 'lhs, rhs: 'body}) | Mul['body] | Numb | 'result) //│ where //│ 'c <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'c}) | Nil //│ = @@ -406,9 +406,9 @@ rec def eval4 subst = eval_lexpr' eval4 subst //│ ╙── Note: use flag `:ex` to see internal error info. //│ eval4: (List[?] & 'a) -> 'b -> 'result //│ where -//│ 'b <: Abs[?] | Add[?] & {lhs: 'b, rhs: 'b} | App[?] | Mul[?] & {lhs: 'b, rhs: 'b} | Num & 'result | Var -//│ 'a <: (Cons[?] with {head: {_1: string, _2: 'result & (Num | ~#Num)}, tail: 'a}) | Nil -//│ 'result :> Mul['result] | Add['result] | Abs[nothing] | App[nothing] | Num | Var +//│ 'b <: Abs[?] | Add[?] & {lhs: 'b, rhs: 'b} | App[?] | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & 'result | Var +//│ 'a <: (Cons[?] with {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: 'a}) | Nil +//│ 'result :> Mul['result] | Add['result] | Abs[nothing] | App[nothing] | Numb | Var //│ = //│ eval_lexpr', eval_var, list_assoc and eq are not implemented @@ -419,34 +419,34 @@ rec def eval4 subst = eval_lexpr' eval4 subst //│ eval4: (List[?] & 'tail) -> 'b -> 'rhs //│ where //│ 'tail <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'tail}) | Nil -//│ 'result :> Var | 'rhs | Num -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Abs[?] & 'c & ~#Abs | 'lhs0 & (Num | ~#Abs & ~#Num))) +//│ 'result :> Var | 'rhs | Numb +//│ <: 'b & (Abs[?] & 'c | 'lhs & (Abs[?] & 'c & ~#Abs | 'lhs0 & (Numb | ~#Abs & ~#Numb))) //│ 'rhs :> Abs['rhs] | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | 'result | 'd | 'e | (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) //│ 'a :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | 'rhs -//│ 'lhs :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Num | Var +//│ 'lhs :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Numb | Var //│ <: 'b & 'a -//│ 'lhs0 :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Num | Var +//│ 'lhs0 :> (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (App['a] with {lhs: 'lhs | 'lhs0, rhs: 'rhs}) | (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | Numb | Var //│ <: 'b & 'a -//│ 'b <: Abs[?] & {body: 'b} | Add[?] & {lhs: 'b, rhs: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Num & (Add[?] & 'e | Mul[?] & 'e | Num & 'result | Var & 'd) | Var & 'd +//│ 'b <: Abs[?] & {body: 'b} | Add[?] & {lhs: 'b, rhs: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & (Add[?] & 'e | Mul[?] & 'e | Numb & 'result | Var & 'd) | Var & 'd //│ 'd :> Var -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Abs[?] & 'c & ~#Abs | 'lhs0 & (Num & {name: string} | {name: string} & ~#Abs & ~#Num))) +//│ <: 'b & (Abs[?] & 'c | 'lhs & (Abs[?] & 'c & ~#Abs | 'lhs0 & (Numb & {name: string} | {name: string} & ~#Abs & ~#Numb))) //│ 'e :> (Mul['rhs] with {lhs: 'rhs, rhs: 'rhs}) | (Add['rhs] with {lhs: 'rhs, rhs: 'rhs}) -//│ <: 'b & (Abs[?] & {lhs: anything, rhs: anything} & 'c | 'lhs & (Abs[?] & {lhs: anything, rhs: anything} & 'c & ~#Abs | 'lhs0 & (Num & {lhs: anything, rhs: anything} | {lhs: anything, rhs: anything} & ~#Abs & ~#Num))) +//│ <: 'b & (Abs[?] & {lhs: anything, rhs: anything} & 'c | 'lhs & (Abs[?] & {lhs: anything, rhs: anything} & 'c & ~#Abs | 'lhs0 & (Numb & {lhs: anything, rhs: anything} | {lhs: anything, rhs: anything} & ~#Abs & ~#Numb))) //│ 'c <: {body: 'b, name: string} //│ = //│ eval_lexpr', eval_var, list_assoc and eq are not implemented //│ constrain calls : 16185 //│ annoying calls : 2300 -//│ subtyping calls : 595519 +//│ subtyping calls : 596394 :ResetFuel -eval4 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Num { num = 1 } } }) +eval4 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Numb { num = 1 } } }) //│ res: 'result //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Num | Var | 'b +//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b +//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b +//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b //│ 'b :> Add['result] | Mul['result] //│ = //│ eval4, eval_lexpr', eval_var, list_assoc and eq are not implemented diff --git a/shared/src/test/diff/mlscript/RecursiveTypes.mls b/shared/src/test/diff/mlscript/RecursiveTypes.mls index 2ccaf21359..210b30d1aa 100644 --- a/shared/src/test/diff/mlscript/RecursiveTypes.mls +++ b/shared/src/test/diff/mlscript/RecursiveTypes.mls @@ -206,7 +206,7 @@ class C[A]: { a: A } :ns rec def foo (c: C['a]) = foo (c.a) -//│ foo: forall 'a 'a0 'b 'foo. 'foo +//│ foo: forall 'b 'foo 'a 'a0. 'foo //│ where //│ 'foo := C['a] -> 'b //│ 'a <: 'a0 @@ -411,19 +411,19 @@ f 1 :ns rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x -//│ f: forall 'b 'c 'd 'f 'e 'g 'a. 'f -//│ where -//│ 'f := 'e -> 'g -//│ 'e :> 'e\a & {a: 'c} -//│ <: ({a: 'a} | ~{a: 'c} | ~{})\a & ({a: 'a} | ~{a: 'c})\a & (number | ~{a: 'c} | ~{})\a & (number | ~{a: 'c})\a & (int | ~{a: 'c} | ~{})\a & (int | ~{a: 'c})\a & 'd & int & number -//│ 'a <: 'd -//│ 'd :> 'e\a & {a: 'c} -//│ <: 'g -//│ 'g :> 'e\a & {a: 'c} +//│ f: forall 'f 'b 'c 'a 'd 'e 'g. 'f +//│ where +//│ 'f := 'c -> 'b +//│ 'c :> 'c\a & {a: 'e} +//│ <: ({a: 'a} | ~{a: 'e} | ~{})\a & ({a: 'a} | ~{a: 'e})\a & (number | ~{a: 'e} | ~{})\a & (number | ~{a: 'e})\a & (int | ~{a: 'e} | ~{})\a & (int | ~{a: 'e})\a & 'g & int & number +//│ 'a <: 'g +//│ 'g :> 'c\a & {a: 'e} //│ <: 'b -//│ 'b :> 'e\a & {a: 'c} +//│ 'b :> 'c\a & {a: 'e} +//│ <: 'd +//│ 'd :> 'c\a & {a: 'e} //│ <: {a: 'a} -//│ 'c :> int +//│ 'e :> int f //│ res: 'a -> 'b diff --git a/shared/src/test/diff/mlscript/RecursiveTypes2.mls b/shared/src/test/diff/mlscript/RecursiveTypes2.mls index 88615bb3fc..0e061e5ba3 100644 --- a/shared/src/test/diff/mlscript/RecursiveTypes2.mls +++ b/shared/src/test/diff/mlscript/RecursiveTypes2.mls @@ -42,7 +42,7 @@ f.x //│ 'a :> T3 & {x: T1 & 'a} //│ constrain calls : 4 //│ annoying calls : 4 -//│ subtyping calls : 136 +//│ subtyping calls : 148 g = error : T1 & { x: T2 | 'a } as 'a //│ g: 'a @@ -56,7 +56,7 @@ g.x //│ 'a :> T1 & {x: 'a | T2} //│ constrain calls : 4 //│ annoying calls : 4 -//│ subtyping calls : 78 +//│ subtyping calls : 94 :stats f = g @@ -69,6 +69,6 @@ f = g //│ 'a :> T3 & {x: T1 & 'a} //│ constrain calls : 48 //│ annoying calls : 60 -//│ subtyping calls : 2389 +//│ subtyping calls : 2393 diff --git a/shared/src/test/diff/mlscript/SelfNeg.mls b/shared/src/test/diff/mlscript/SelfNeg.mls index 410c38b874..bdd07ee710 100644 --- a/shared/src/test/diff/mlscript/SelfNeg.mls +++ b/shared/src/test/diff/mlscript/SelfNeg.mls @@ -56,11 +56,11 @@ def foo: ('a -> (~'a -> anything) -> anything) -> MutArray['a] :ns r = foo (fun a -> fun f -> f a) -//│ r: forall 'b 'a 'c. 'b +//│ r: forall 'b 'c 'a. 'c //│ where -//│ 'b :> MutArray['a] -//│ 'a <: 'c -//│ 'c <: ~'a +//│ 'c :> MutArray['a] +//│ 'a <: 'b +//│ 'b <: ~'a //│ = //│ foo is not implemented diff --git a/shared/src/test/diff/mlscript/SelfNegs.mls b/shared/src/test/diff/mlscript/SelfNegs.mls index 2313cff065..3cae854b7d 100644 --- a/shared/src/test/diff/mlscript/SelfNegs.mls +++ b/shared/src/test/diff/mlscript/SelfNegs.mls @@ -12,7 +12,7 @@ def foo(fa: ((~'a) -> 'a, 'a)) = :ns foo -//│ res: forall 'a 'b 'c. (~'a -> 'a, 'a,) -> 'c +//│ res: forall 'b 'c 'a. (~'a -> 'a, 'a,) -> 'c //│ where //│ 'a <: 'c & 'b //│ 'b <: ~'a diff --git a/shared/src/test/diff/mlscript/Stress.mls b/shared/src/test/diff/mlscript/Stress.mls index 9a072791e3..1bbec3bbf2 100644 --- a/shared/src/test/diff/mlscript/Stress.mls +++ b/shared/src/test/diff/mlscript/Stress.mls @@ -31,7 +31,7 @@ def foo x = case x of { //│ foo: (A[?] & {fA: 'fA} | B[?] & {fB: 'fA} | C[?] & {fC: 'fA} | D[?] & {fD: 'fA} | E[?] & {fE: 'fA} | F[?] & {fF: 'fA} | G[?] & {fG: 'fA} | H[?] & {fH: 'fA}) -> 'fA //│ constrain calls : 26 //│ annoying calls : 0 -//│ subtyping calls : 987 +//│ subtyping calls : 1078 // ====== 1 & all ====== // @@ -64,7 +64,7 @@ foo arg //│ res: int //│ constrain calls : 38 //│ annoying calls : 20 -//│ subtyping calls : 305 +//│ subtyping calls : 321 // ====== 3 ====== // @@ -82,7 +82,7 @@ foo arg //│ res: int //│ constrain calls : 51 //│ annoying calls : 30 -//│ subtyping calls : 572 +//│ subtyping calls : 606 // ====== 4 ====== // @@ -101,7 +101,7 @@ foo arg //│ res: int //│ constrain calls : 64 //│ annoying calls : 40 -//│ subtyping calls : 940 +//│ subtyping calls : 994 :stats foo (arg with { x = 1} with { y = 2 }) @@ -135,7 +135,7 @@ foo arg //│ res: int //│ constrain calls : 77 //│ annoying calls : 50 -//│ subtyping calls : 1423 +//│ subtyping calls : 1499 // ====== 6 ====== // @@ -156,7 +156,7 @@ foo arg //│ res: int //│ constrain calls : 90 //│ annoying calls : 60 -//│ subtyping calls : 2035 +//│ subtyping calls : 2135 // ====== 7 ====== // @@ -178,7 +178,7 @@ foo arg //│ res: int //│ constrain calls : 103 //│ annoying calls : 70 -//│ subtyping calls : 2790 +//│ subtyping calls : 2916 // ====== 8 ====== // @@ -201,6 +201,6 @@ foo arg //│ res: int //│ constrain calls : 116 //│ annoying calls : 80 -//│ subtyping calls : 3702 +//│ subtyping calls : 3856 diff --git a/shared/src/test/diff/mlscript/StressDNF.mls b/shared/src/test/diff/mlscript/StressDNF.mls index 122156bd08..1072afd76c 100644 --- a/shared/src/test/diff/mlscript/StressDNF.mls +++ b/shared/src/test/diff/mlscript/StressDNF.mls @@ -16,12 +16,12 @@ def ty0: ('a & 'b & A | 'b & 'c & B | 'c & 'd & C | 'd & 'e & D | 'e & 'f & E) - :stats ty0 = ty0 -//│ (C & 'c & 'd | 'b & (A & 'a | B & 'c) | 'e & (D & 'd | E & 'f)) -> ('a, 'b, 'c, 'd, 'e, 'f,) +//│ (E & 'e & 'f | 'd & (C & 'c | D & 'e) | 'b & (A & 'a | B & 'c)) -> ('a, 'b, 'c, 'd, 'e, 'f,) //│ <: ty0: -//│ (A & 'a & 'b | 'e & (D & 'd | E & 'f) | 'c & (B & 'b | C & 'd)) -> ('a, 'b, 'c, 'd, 'e, 'f,) +//│ (C & 'c & 'd | 'b & (A & 'a | B & 'c) | 'e & (D & 'd | E & 'f)) -> ('a, 'b, 'c, 'd, 'e, 'f,) //│ constrain calls : 1 //│ annoying calls : 0 -//│ subtyping calls : 181 +//│ subtyping calls : 279 def ty1: ('a & A | 'b & B | 'c & C | 'd & D | 'e & E) -> ('a, 'b, 'c, 'd, 'e, 'f) //│ ty1: (A & 'a | B & 'b | C & 'c | D & 'd | E & 'e) -> ('a, 'b, 'c, 'd, 'e, nothing,) @@ -33,7 +33,7 @@ ty0 = ty1 //│ (E & 'e & 'f | 'd & (C & 'c | D & 'e) | 'b & (A & 'a | B & 'c)) -> ('a, 'b, 'c, 'd, 'e, 'f,) //│ constrain calls : 45 //│ annoying calls : 25 -//│ subtyping calls : 1120 +//│ subtyping calls : 1215 :stats :e @@ -52,6 +52,6 @@ ty1 = ty0 //│ ╙── ^^ //│ constrain calls : 70 //│ annoying calls : 51 -//│ subtyping calls : 1255 +//│ subtyping calls : 1350 diff --git a/shared/src/test/diff/mlscript/StressTraits.mls b/shared/src/test/diff/mlscript/StressTraits.mls index c752de1117..d2ba45c571 100644 --- a/shared/src/test/diff/mlscript/StressTraits.mls +++ b/shared/src/test/diff/mlscript/StressTraits.mls @@ -31,7 +31,7 @@ def foo x = case x of { //│ foo: ({fA: 'fA} & #A | ~#A & ({fB: 'fA} & #B | ~#B & ({fC: 'fA} & #C | ~#C & ({fD: 'fA} & #D | ~#D & ({fE: 'fA} & #E | ~#E & ({fF: 'fA} & #F | ~#F & ({fG: 'fA} & #G | {fH: 'fA} & #H & ~#G))))))) -> 'fA //│ constrain calls : 26 //│ annoying calls : 0 -//│ subtyping calls : 659 +//│ subtyping calls : 715 // ====== 1 & all ====== // @@ -63,7 +63,7 @@ foo arg //│ res: error | int //│ constrain calls : 39 //│ annoying calls : 31 -//│ subtyping calls : 1533 +//│ subtyping calls : 1549 :stats :e @@ -83,7 +83,7 @@ foo arg //│ res: error | int //│ constrain calls : 71 //│ annoying calls : 90 -//│ subtyping calls : 4291 +//│ subtyping calls : 4371 :stats :e @@ -103,7 +103,7 @@ foo arg //│ res: error //│ constrain calls : 94 //│ annoying calls : 216 -//│ subtyping calls : 17284 +//│ subtyping calls : 17471 // ====== 2 ====== // @@ -131,7 +131,7 @@ foo arg //│ res: error | int //│ constrain calls : 47 //│ annoying calls : 31 -//│ subtyping calls : 516 +//│ subtyping calls : 540 // ====== 3 ====== // @@ -160,7 +160,7 @@ foo arg //│ res: error | int //│ constrain calls : 82 //│ annoying calls : 90 -//│ subtyping calls : 2915 +//│ subtyping calls : 3026 // ====== 4 ====== // @@ -190,7 +190,7 @@ foo arg //│ res: error //│ constrain calls : 102 //│ annoying calls : 131 -//│ subtyping calls : 3957 +//│ subtyping calls : 4104 :stats :e @@ -208,7 +208,7 @@ foo (arg with { x = 1} with { y = 2 }) //│ res: error //│ constrain calls : 77 //│ annoying calls : 128 -//│ subtyping calls : 3370 +//│ subtyping calls : 3474 :stats :e @@ -226,7 +226,7 @@ foo (arg with { x = 1; y = 2; z = 3 }) //│ res: error //│ constrain calls : 77 //│ annoying calls : 128 -//│ subtyping calls : 3358 +//│ subtyping calls : 3433 // ====== 5 ====== // @@ -257,7 +257,7 @@ foo arg //│ res: error //│ constrain calls : 106 //│ annoying calls : 131 -//│ subtyping calls : 4388 +//│ subtyping calls : 4546 // ====== 6 ====== // @@ -289,7 +289,7 @@ foo arg //│ res: error //│ constrain calls : 110 //│ annoying calls : 131 -//│ subtyping calls : 4953 +//│ subtyping calls : 5113 // ====== 7 ====== // @@ -322,7 +322,7 @@ foo arg //│ res: error //│ constrain calls : 114 //│ annoying calls : 131 -//│ subtyping calls : 5673 +//│ subtyping calls : 5868 def foo_manual: ({fA: 'a} & a | {fB: 'a} & b & ~a | {fC: 'a} & c & ~a & ~b | {fD: 'a} & d & ~a & ~b & ~c | {fE: 'a} & e & ~a & ~b & ~c & ~d | {fF: 'a} & f & ~a & ~b & ~c & ~d & ~e | {fG: 'a} & g & ~a & ~b & ~c & ~d & ~e & ~f) -> 'a //│ foo_manual: ({fA: 'a} & #A | ~#A & ({fB: 'a} & #B | ~#B & ({fC: 'a} & #C | ~#C & ({fD: 'a} & #D | ~#D & ({fE: 'a} & #E | ~#E & ({fF: 'a} & #F | {fG: 'a} & #G & ~#F)))))) -> 'a @@ -345,7 +345,7 @@ foo_manual arg //│ res: error //│ constrain calls : 24 //│ annoying calls : 67 -//│ subtyping calls : 5262 +//│ subtyping calls : 5646 :stats foo_manual = foo @@ -354,7 +354,7 @@ foo_manual = foo //│ ({fA: 'a} & #A | ~#A & ({fB: 'a} & #B | ~#B & ({fC: 'a} & #C | ~#C & ({fD: 'a} & #D | ~#D & ({fE: 'a} & #E | ~#E & ({fF: 'a} & #F | {fG: 'a} & #G & ~#F)))))) -> 'a //│ constrain calls : 98 //│ annoying calls : 183 -//│ subtyping calls : 6065 +//│ subtyping calls : 6161 // ====== 8 ====== // @@ -388,6 +388,6 @@ foo arg //│ res: error //│ constrain calls : 118 //│ annoying calls : 131 -//│ subtyping calls : 6569 +//│ subtyping calls : 6778 diff --git a/shared/src/test/diff/mlscript/StressUgly.mls b/shared/src/test/diff/mlscript/StressUgly.mls index 8a4aff8795..e0a1bfd4ad 100644 --- a/shared/src/test/diff/mlscript/StressUgly.mls +++ b/shared/src/test/diff/mlscript/StressUgly.mls @@ -46,5 +46,5 @@ eval1_ty = eval1_ty_ugly //│ eval1_ty_ugly is not implemented //│ constrain calls : 49 //│ annoying calls : 42 -//│ subtyping calls : 451 +//│ subtyping calls : 477 diff --git a/shared/src/test/diff/mlscript/Tony.mls b/shared/src/test/diff/mlscript/Tony.mls index 99c0b3962a..4cb8c784a5 100644 --- a/shared/src/test/diff/mlscript/Tony.mls +++ b/shared/src/test/diff/mlscript/Tony.mls @@ -21,7 +21,7 @@ flatMap3 (fun x -> add x.value x.payload) arg //│ = 65 //│ constrain calls : 94 //│ annoying calls : 23 -//│ subtyping calls : 539 +//│ subtyping calls : 545 arg = if true then Some{value = 42} else None {} diff --git a/shared/src/test/diff/mlscript/TrickyExtrusion.mls b/shared/src/test/diff/mlscript/TrickyExtrusion.mls index 4de41a0a19..6da31841a4 100644 --- a/shared/src/test/diff/mlscript/TrickyExtrusion.mls +++ b/shared/src/test/diff/mlscript/TrickyExtrusion.mls @@ -110,13 +110,13 @@ not (test id)._1 test f = let r x = f x in (r 0, r True) -//│ test: forall 'a 'b 'c 'd 'e 'f 'g. 'c -> ('f, 'g,) +//│ test: forall 'a 'b 'c 'd 'e 'f 'g. 'a -> ('c, 'd,) //│ where -//│ 'c <: 'a -> 'b & 'd -> 'e -//│ 'e <: 'f -//│ 'd :> 0 -//│ 'b <: 'g -//│ 'a :> true +//│ 'a <: 'e -> 'g & 'b -> 'f +//│ 'f <: 'c +//│ 'b :> 0 +//│ 'g <: 'd +//│ 'e :> true //│ = [Function: test3] // * Q: why does this type *appear* approximated after simplification? diff --git a/shared/src/test/diff/mlscript/Trio.mls b/shared/src/test/diff/mlscript/Trio.mls index b0700ea276..7eb461be34 100644 --- a/shared/src/test/diff/mlscript/Trio.mls +++ b/shared/src/test/diff/mlscript/Trio.mls @@ -39,7 +39,7 @@ foo arg //│ arg is not implemented //│ constrain calls : 40 //│ annoying calls : 30 -//│ subtyping calls : 414 +//│ subtyping calls : 423 :stats foo (arg with { fC = true }) @@ -48,7 +48,7 @@ foo (arg with { fC = true }) //│ arg is not implemented //│ constrain calls : 33 //│ annoying calls : 28 -//│ subtyping calls : 331 +//│ subtyping calls : 340 def foo x = case x of { | A -> add x.fA x.payload @@ -81,7 +81,7 @@ foo arg //│ arg is not implemented //│ constrain calls : 53 //│ annoying calls : 40 -//│ subtyping calls : 513 +//│ subtyping calls : 528 :stats foo (arg with { payload = 1 }) @@ -90,5 +90,5 @@ foo (arg with { payload = 1 }) //│ arg is not implemented //│ constrain calls : 47 //│ annoying calls : 38 -//│ subtyping calls : 411 +//│ subtyping calls : 420 diff --git a/shared/src/test/diff/mlscript/TypeClasses.mls b/shared/src/test/diff/mlscript/TypeClasses.mls index b3578ce409..ae23c188f9 100644 --- a/shared/src/test/diff/mlscript/TypeClasses.mls +++ b/shared/src/test/diff/mlscript/TypeClasses.mls @@ -16,15 +16,15 @@ def IntMonoid = IntMonoid {} //│ IntMonoid: IntMonoid //│ = [Function: IntMonoid1] -class Num: { val: int } -//│ Defined class Num +class Numb: { val: int } +//│ Defined class Numb -class NumMonoid: Monoid[Num] - method Empty = Num { val = 1 } - method Add this that = Num { val = this.val * that.val } +class NumMonoid: Monoid[Numb] + method Empty = Numb { val = 1 } + method Add this that = Numb { val = this.val * that.val } //│ Defined class NumMonoid -//│ Defined NumMonoid.Empty: NumMonoid -> (Num & {val: 1}) -//│ Defined NumMonoid.Add: NumMonoid -> {val: int} -> {val: int} -> Num +//│ Defined NumMonoid.Empty: NumMonoid -> (Numb & {val: 1}) +//│ Defined NumMonoid.Add: NumMonoid -> {val: int} -> {val: int} -> Numb class Complex[A]: { real: A; imaginary: A } method Map f = Complex { real = f this.real; imaginary = f this.imaginary } diff --git a/shared/src/test/diff/mlscript/TypeTags.mls b/shared/src/test/diff/mlscript/TypeTags.mls index d9624307dc..fdbafec742 100644 --- a/shared/src/test/diff/mlscript/TypeTags.mls +++ b/shared/src/test/diff/mlscript/TypeTags.mls @@ -71,8 +71,11 @@ foo = Foo +:e 1 : #Eql -//│ res: Eql[?] +//│ ╔══[ERROR] type identifier not found: eql +//│ ╙── +//│ res: error //│ = 1 diff --git a/shared/src/test/diff/mlscript/Variant-sub-ad-hoc.mls b/shared/src/test/diff/mlscript/Variant-sub-ad-hoc.mls index 684cd71633..d37b7e572d 100644 --- a/shared/src/test/diff/mlscript/Variant-sub-ad-hoc.mls +++ b/shared/src/test/diff/mlscript/Variant-sub-ad-hoc.mls @@ -53,7 +53,7 @@ rec def evalOpt = fun x -> case x of { //│ = [Function: evalOpt] //│ constrain calls : 630 //│ annoying calls : 156 -//│ subtyping calls : 4767 +//│ subtyping calls : 4810 :stats evalOpt (Plus{} with {lhs = Lit{} with {v=2}; rhs = Lit{} with {v=2}}) @@ -61,5 +61,5 @@ evalOpt (Plus{} with {lhs = Lit{} with {v=2}; rhs = Lit{} with {v=2}}) //│ = Some { v: 4 } //│ constrain calls : 105 //│ annoying calls : 34 -//│ subtyping calls : 1153 +//│ subtyping calls : 1163 diff --git a/shared/src/test/diff/mlscript/Variant-sub.mls b/shared/src/test/diff/mlscript/Variant-sub.mls index 6a026dbeb9..1c59e43f8f 100644 --- a/shared/src/test/diff/mlscript/Variant-sub.mls +++ b/shared/src/test/diff/mlscript/Variant-sub.mls @@ -80,7 +80,7 @@ rec def evalOpt x = case x of { //│ = [Function: evalOpt] //│ constrain calls : 649 //│ annoying calls : 105 -//│ subtyping calls : 5362 +//│ subtyping calls : 5401 :stats evalOpt (Plus{lhs = Lit{v=2}; rhs = Lit{v=3}}) @@ -88,4 +88,4 @@ evalOpt (Plus{lhs = Lit{v=2}; rhs = Lit{v=3}}) //│ = Some { v: 5 } //│ constrain calls : 153 //│ annoying calls : 37 -//│ subtyping calls : 1224 +//│ subtyping calls : 1230 diff --git a/shared/src/test/diff/mlscript/Yicong.mls b/shared/src/test/diff/mlscript/Yicong.mls index 9080a3a452..c01470ed0d 100644 --- a/shared/src/test/diff/mlscript/Yicong.mls +++ b/shared/src/test/diff/mlscript/Yicong.mls @@ -319,11 +319,11 @@ two = Two {fst=(1,2,3); snd=(true,false)} two.fst tk (two.snd) //│ Defined class Two[+A, +B] -//│ two: Two[1 | 2 | 3, bool] & {fst: (1, 2, 3,), snd: (true, false,)} +//│ two: Two[1 | 2 | 3, Bool] & {fst: (1, 2, 3,), snd: (true, false,)} //│ = Two { fst: [ 1, 2, 3 ], snd: [ true, false ] } //│ res: (1, 2, 3,) //│ = [ 1, 2, 3 ] -//│ res: Wrapped[bool] +//│ res: Wrapped[Bool] //│ = //│ tk is not implemented diff --git a/shared/src/test/diff/mlscript/i56.mls b/shared/src/test/diff/mlscript/i56.mls index 5470a1d944..c0fca82382 100644 --- a/shared/src/test/diff/mlscript/i56.mls +++ b/shared/src/test/diff/mlscript/i56.mls @@ -6,12 +6,12 @@ def test3 x = case x of | true -> true | _ -> false } -//│ test3: anything -> bool +//│ test3: anything -> Bool //│ = [Function: test3] :ns test3 -//│ res: forall 'a 'b 'c 'd. 'a -> (true | false) +//│ res: forall 'a 'b 'c 'd. 'a -> Bool //│ where //│ 'a <: 1 & 'b | (true & 'c | 'd & ~true) & ~1 //│ = [Function: test3] @@ -22,7 +22,7 @@ def test3 x = case x of | true -> true | _ -> false } -//│ test3: (1 & 'a | ~1) -> (false | true | 'a) +//│ test3: (1 & 'a | ~1) -> (Bool | 'a) //│ = [Function: test31] @@ -31,7 +31,7 @@ def ty_1: (1 & 'a | true | ~1 & ~true) -> (false | true | 'a) //│ = ty_1 = test3 -//│ (1 & 'a | ~1) -> (false | true | 'a) +//│ (1 & 'a | ~1) -> (Bool | 'a) //│ <: ty_1: //│ (1 & 'a | true | ~1 & ~true) -> ('a | false | true) //│ = [Function: test31] diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index 6c5606b219..c693dfdf28 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -2,11 +2,11 @@ -abstract class Foo(x: int) { - fun f(y: int) = x + y +abstract class Foo(x: Int) { + fun f(y: Int) = x + y } -//│ abstract class Foo(x: int) { -//│ fun f: (y: int,) -> int +//│ abstract class Foo(x: Int) { +//│ fun f: (y: Int,) -> Int //│ } :e @@ -28,11 +28,11 @@ new Foo(1) //│ = Foo {} -abstract class Foo(x: int) { - fun f: int -> int +abstract class Foo(x: Int) { + fun f: Int -> Int } -//│ abstract class Foo(x: int) { -//│ fun f: int -> int +//│ abstract class Foo(x: Int) { +//│ fun f: Int -> Int //│ } :e @@ -56,7 +56,7 @@ new Foo(1) { fun f = id } abstract class Bar extends Foo(1) //│ abstract class Bar extends Foo { -//│ fun f: int -> int +//│ fun f: Int -> Int //│ } :e @@ -66,12 +66,12 @@ Baz.f(1) //│ ║ l.63: module Baz extends Bar //│ ║ ^^^ //│ ╟── Declared here: -//│ ║ l.32: fun f: int -> int +//│ ║ l.32: fun f: Int -> Int //│ ╙── ^^^^^^^^^^^^^ //│ module Baz extends Bar, Foo { -//│ fun f: int -> int +//│ fun f: Int -> Int //│ } -//│ int +//│ Int //│ res //│ Runtime error: //│ TypeError: Baz.f is not a function @@ -81,22 +81,22 @@ module Baz extends Bar { } Baz.f(1) //│ module Baz extends Bar, Foo { -//│ fun f: int -> int +//│ fun f: Int -> Int //│ } -//│ int +//│ Int //│ res //│ = 2 -abstract class C1 { fun x: int | string } +abstract class C1 { fun x: Int | string } //│ abstract class C1 { -//│ fun x: int | string +//│ fun x: Int | string //│ } -trait T1 { fun x: int | bool } +trait T1 { fun x: Int | Bool } //│ trait T1 { -//│ fun x: bool | int +//│ fun x: Int | false | true //│ } :e @@ -105,10 +105,10 @@ class C2 extends C1, T1 //│ ║ l.103: class C2 extends C1, T1 //│ ║ ^^ //│ ╟── Declared here: -//│ ║ l.92: abstract class C1 { fun x: int | string } +//│ ║ l.92: abstract class C1 { fun x: Int | string } //│ ╙── ^^^^^^^^^^^^^^^ //│ class C2 extends C1, T1 { -//│ fun x: int +//│ fun x: Int //│ } class C2 extends C1, T1 { fun x = 1 } @@ -118,7 +118,7 @@ class C2 extends C1, T1 { fun x = 1 } abstract class C2 extends C1, T1 //│ abstract class C2 extends C1, T1 { -//│ fun x: int +//│ fun x: Int //│ } :e @@ -127,10 +127,10 @@ class C3 extends C2 //│ ║ l.125: class C3 extends C2 //│ ║ ^^ //│ ╟── Declared here: -//│ ║ l.92: abstract class C1 { fun x: int | string } +//│ ║ l.92: abstract class C1 { fun x: Int | string } //│ ╙── ^^^^^^^^^^^^^^^ //│ class C3 extends C1, C2, T1 { -//│ fun x: int +//│ fun x: Int //│ } class C3 extends C2 { fun x = 1 } @@ -142,28 +142,28 @@ class C3 extends C2 { fun x = 1 } :ge // TODO report this as a type error abstract class C { - fun x : int + fun x : Int fun foo0 = x fun foo1 = this.x } //│ abstract class C { -//│ fun foo0: int -//│ fun foo1: int -//│ fun x: int +//│ fun foo0: Int +//│ fun foo1: Int +//│ fun x: Int //│ } //│ Code generation encountered an error: //│ unresolved symbol x :ge // TODO report this as a type error class C { - val x : int + val x : Int fun foo0 = x fun foo1 = this.x } //│ class C { -//│ fun foo0: int -//│ fun foo1: int -//│ let x: int +//│ fun foo0: Int +//│ fun foo1: Int +//│ let x: Int //│ } //│ Code generation encountered an error: //│ unresolved symbol x diff --git a/shared/src/test/diff/nu/Ascription.mls b/shared/src/test/diff/nu/Ascription.mls index 9c85bf03ad..7c52b8fe6e 100644 --- a/shared/src/test/diff/nu/Ascription.mls +++ b/shared/src/test/diff/nu/Ascription.mls @@ -1,38 +1,38 @@ :NewDefs -1: int -//│ int +1: Int +//│ Int //│ res //│ = 1 -1 : int -//│ int +1 : Int +//│ Int //│ res //│ = 1 // TODO? :e -1 : int : int +1 : Int : Int //│ ╔══[ERROR] not a recognized type -//│ ║ l.15: 1 : int : int +//│ ║ l.15: 1 : Int : Int //│ ╙── ^^^ //│ anything //│ res //│ = 1 -fun foo(x: int) = x + 1 -//│ fun foo: (x: int,) -> int +fun foo(x: Int) = x + 1 +//│ fun foo: (x: Int,) -> Int -fun foo(x : int) = x + 1 -//│ fun foo: int -> int +fun foo(x : Int) = x + 1 +//│ fun foo: Int -> Int -foo(123 : int) : int -//│ int +foo(123 : Int) : Int +//│ Int //│ res //│ = 124 -foo(123:int):int -//│ int +foo(123:Int):Int +//│ Int //│ res //│ = 124 diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index 5189ed837a..be31dbdd99 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -8,8 +8,8 @@ type A = A // TODO check cyclicity // :e -type A = A | int -//│ type A = int | A +type A = A | Int +//│ type A = Int | A // TODO check regularity // :e @@ -26,12 +26,12 @@ type Test //│ type Test = error :e -type Test(n: int) = n +type Test(n: Int) = n //│ ╔══[ERROR] Type alias definitions cannot have value parameters -//│ ║ l.29: type Test(n: int) = n +//│ ║ l.29: type Test(n: Int) = n //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] type identifier not found: n -//│ ║ l.29: type Test(n: int) = n +//│ ║ l.29: type Test(n: Int) = n //│ ╙── ^ //│ type Test = error @@ -51,12 +51,12 @@ type Test: Base :pe :e -type Test: Base = int +type Test: Base = Int //│ ╔══[PARSE ERROR] Expected end of input; found ':' instead -//│ ║ l.54: type Test: Base = int +//│ ║ l.54: type Test: Base = Int //│ ╙── ^ //│ ╔══[ERROR] Type alias definition requires a right-hand side -//│ ║ l.54: type Test: Base = int +//│ ║ l.54: type Test: Base = Int //│ ╙── ^^^^^^^^^ //│ type Test = error @@ -72,24 +72,24 @@ type Test extends Base :pe :e -type Test extends Base = int +type Test extends Base = Int //│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.75: type Test extends Base = int +//│ ║ l.75: type Test extends Base = Int //│ ╙── ^ //│ ╔══[ERROR] Type alias definitions cannot extend parents -//│ ║ l.75: type Test extends Base = int +//│ ║ l.75: type Test extends Base = Int //│ ╙── ^^^^ //│ ╔══[ERROR] Type alias definition requires a right-hand side -//│ ║ l.75: type Test extends Base = int +//│ ║ l.75: type Test extends Base = Int //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ type Test = error :e -type Test = int extends Base +type Test = Int extends Base //│ ╔══[ERROR] Type alias definitions cannot extend parents -//│ ║ l.88: type Test = int extends Base +//│ ║ l.88: type Test = Int extends Base //│ ╙── ^^^^ -//│ type Test = int +//│ type Test = Int :pe diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index a0be7b9424..c7fcd31f28 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -1,42 +1,42 @@ :NewDefs -class C1(x: int) -//│ class C1(x: int) +class C1(x: Int) +//│ class C1(x: Int) :e -class C2(x: int) extends C1(y) { +class C2(x: Int) extends C1(y) { val y = x } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.8: class C2(x: int) extends C1(y) { +//│ ║ l.8: class C2(x: Int) extends C1(y) { //│ ╙── ^ -//│ class C2(x: int) extends C1 { -//│ let y: int +//│ class C2(x: Int) extends C1 { +//│ let y: Int //│ } :e class C2 extends C1(y) { - val y: int + val y: Int } //│ ╔══[ERROR] identifier not found: y //│ ║ l.19: class C2 extends C1(y) { //│ ╙── ^ //│ class C2 extends C1 { -//│ let y: int +//│ let y: Int //│ } //│ Code generation encountered an error: //│ unresolved symbol y :e class C2 extends C1(this.y) { - val y: int + val y: Int } //│ ╔══[ERROR] identifier not found: this //│ ║ l.32: class C2 extends C1(this.y) { //│ ╙── ^^^^ //│ class C2 extends C1 { -//│ let y: int +//│ let y: Int //│ } @@ -51,9 +51,9 @@ class C2 extends C1(this) //│ class C2 extends C1 -class Foo { fun x: int = 1 } +class Foo { fun x: Int = 1 } //│ class Foo { -//│ fun x: int +//│ fun x: Int //│ } :e @@ -61,17 +61,17 @@ class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in definition of method x: //│ ║ l.60: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `int` +//│ ╟── reference of type `false` is not an instance of type `Int` //│ ║ l.60: class Bar extends Foo { fun x = false } //│ ║ ^^^^^ -//│ ╟── but it flows into definition of method x with expected type `int` +//│ ╟── but it flows into definition of method x with expected type `Int` //│ ║ l.60: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ l.54: class Foo { fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ l.54: class Foo { fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ fun x: false @@ -79,26 +79,26 @@ class Bar extends Foo { fun x = false } :e class Bar extends Foo { - fun x: bool + fun x: Bool fun x = false } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.82: fun x: bool +//│ ║ l.82: fun x: Bool //│ ║ ^^^^^^^ -//│ ╟── type `bool` is not an instance of `int` -//│ ║ l.82: fun x: bool +//│ ╟── type `Bool` is not an instance of `Int` +//│ ║ l.82: fun x: Bool //│ ║ ^^^^ -//│ ╟── but it flows into signature of member `x` with expected type `int` -//│ ║ l.82: fun x: bool +//│ ╟── but it flows into signature of member `x` with expected type `Int` +//│ ║ l.82: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ l.54: class Foo { fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ l.54: class Foo { fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { -//│ fun x: bool +//│ fun x: Bool //│ } mixin M { fun x = false } @@ -111,17 +111,17 @@ class Bar extends Foo, M //│ ╔══[ERROR] Type mismatch in definition of method x: //│ ║ l.104: mixin M { fun x = false } //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `int` +//│ ╟── reference of type `false` is not an instance of type `Int` //│ ║ l.104: mixin M { fun x = false } //│ ║ ^^^^^ -//│ ╟── but it flows into definition of method x with expected type `int` +//│ ╟── but it flows into definition of method x with expected type `Int` //│ ║ l.104: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ l.54: class Foo { fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.54: class Foo { fun x: int = 1 } +//│ ║ l.54: class Foo { fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ fun x: false diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 4b87fa23e1..30237c7f44 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -2,8 +2,8 @@ -mixin M0(x: int) -//│ mixin M0(x: int) +mixin M0(x: Int) +//│ mixin M0(x: Int) :e class C0 extends M0 @@ -24,11 +24,11 @@ class C0 extends M0(true) //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.23: class C0 extends M0(true) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` +//│ ╟── reference of type `true` is not an instance of type `Int` //│ ║ l.23: class C0 extends M0(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: mixin M0(x: int) +//│ ║ l.5: mixin M0(x: Int) //│ ╙── ^^^ //│ class C0 @@ -56,10 +56,10 @@ class Foo { module Bar { fun hello = 0 - type I = int + type I = Int } //│ module Bar { -//│ type I = int +//│ type I = Int //│ fun hello: 0 //│ } @@ -105,22 +105,22 @@ class C1 { fun oops = this.x } :e -class C { fun x: int } +class C { fun x: Int } //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C` -//│ ║ l.108: class C { fun x: int } +//│ ║ l.108: class C { fun x: Int } //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.108: class C { fun x: int } +//│ ║ l.108: class C { fun x: Int } //│ ╙── ^^^^^^ //│ class C { -//│ fun x: int +//│ fun x: Int //│ } // FIXME should error // :e -class C { val x: int } +class C { val x: Int } //│ class C { -//│ let x: int +//│ let x: Int //│ } diff --git a/shared/src/test/diff/nu/BadScopes.mls b/shared/src/test/diff/nu/BadScopes.mls index 555e7ce4a9..515e23bf16 100644 --- a/shared/src/test/diff/nu/BadScopes.mls +++ b/shared/src/test/diff/nu/BadScopes.mls @@ -2,36 +2,36 @@ :e -mixin Foo(x: int) +mixin Foo(x: Int) x //│ ╔══[ERROR] identifier not found: x //│ ║ l.6: x //│ ╙── ^ -//│ mixin Foo(x: int) +//│ mixin Foo(x: Int) //│ error //│ Code generation encountered an error: //│ unresolved symbol x :e -class Foo(x: int) +class Foo(x: Int) x //│ ╔══[ERROR] identifier not found: x //│ ║ l.18: x //│ ╙── ^ -//│ class Foo(x: int) +//│ class Foo(x: Int) //│ error //│ Code generation encountered an error: //│ unresolved symbol x :e -class Foo(x: int) +class Foo(x: Int) class Bar { x } //│ ╔══[ERROR] identifier not found: x //│ ║ l.30: class Bar { x } //│ ╙── ^ -//│ class Foo(x: int) +//│ class Foo(x: Int) //│ class Bar //│ Code generation encountered an error: //│ unresolved symbol x diff --git a/shared/src/test/diff/nu/BadSignatures.mls b/shared/src/test/diff/nu/BadSignatures.mls index 596f12a8c4..96d8d07ab0 100644 --- a/shared/src/test/diff/nu/BadSignatures.mls +++ b/shared/src/test/diff/nu/BadSignatures.mls @@ -3,14 +3,14 @@ :e trait T { - fun x : int + fun x : Int fun x = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.7: fun x = false //│ ╙── ^^^^^^^^^ //│ trait T { -//│ fun x: int +//│ fun x: Int //│ } @@ -21,16 +21,16 @@ class A { fun x = 1 } :e class B() extends A { - fun x: int + fun x: Int } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.24: fun x: int +//│ ║ l.24: fun x: Int //│ ║ ^^^^^^ -//│ ╟── type `int` does not match type `1` -//│ ║ l.24: fun x: int +//│ ╟── type `Int` does not match type `1` +//│ ║ l.24: fun x: Int //│ ║ ^^^ //│ ╟── but it flows into signature of member `x` with expected type `1` -//│ ║ l.24: fun x: int +//│ ║ l.24: fun x: Int //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from integer literal: //│ ║ l.17: class A { fun x = 1 } @@ -39,11 +39,11 @@ class B() extends A { //│ ║ l.17: class A { fun x = 1 } //│ ╙── ^^^^^ //│ class B() extends A { -//│ fun x: int +//│ fun x: Int //│ } B().x -//│ int +//│ Int //│ res //│ = 1 @@ -64,17 +64,17 @@ class C() extends B { fun x = 0 } :e class B() extends A { - fun x: int + fun x: Int fun x = 1 } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.67: fun x: int +//│ ║ l.67: fun x: Int //│ ║ ^^^^^^ -//│ ╟── type `int` does not match type `1` -//│ ║ l.67: fun x: int +//│ ╟── type `Int` does not match type `1` +//│ ║ l.67: fun x: Int //│ ║ ^^^ //│ ╟── but it flows into signature of member `x` with expected type `1` -//│ ║ l.67: fun x: int +//│ ║ l.67: fun x: Int //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from integer literal: //│ ║ l.17: class A { fun x = 1 } @@ -83,19 +83,19 @@ class B() extends A { //│ ║ l.17: class A { fun x = 1 } //│ ╙── ^^^^^ //│ class B() extends A { -//│ fun x: int +//│ fun x: Int //│ } :e -mixin M { fun x : int } +mixin M { fun x : Int } //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `M` -//│ ║ l.91: mixin M { fun x : int } +//│ ║ l.91: mixin M { fun x : Int } //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.91: mixin M { fun x : int } +//│ ║ l.91: mixin M { fun x : Int } //│ ╙── ^^^^^^^ //│ mixin M() { -//│ fun x: int +//│ fun x: Int //│ } diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index 9b419feec6..5571412bb5 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -107,4 +107,4 @@ fun join(xs) = Nil then "" Cons(x, Nil) then toString(x) Cons(x, xs') then concat(toString(x))(concat(", ")(join(xs'))) -//│ fun join: (Cons[anything] | Nil) -> string +//│ fun join: (Cons[anything] | Nil) -> Str diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index d7d67468a7..56c569f4dc 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -4,30 +4,30 @@ class A //│ class A -class B(m: int) extends A -//│ class B(m: int) extends A +class B(m: Int) extends A +//│ class B(m: Int) extends A -class A(n: int) -//│ class A(n: int) +class A(n: Int) +//│ class A(n: Int) -class B(m: int) extends A(m + 1) -//│ class B(m: int) extends A +class B(m: Int) extends A(m + 1) +//│ class B(m: Int) extends A class A { - fun a1: int + fun a1: Int fun a1 = 1 fun a2 = 2 } //│ class A { -//│ fun a1: int +//│ fun a1: Int //│ fun a2: 2 //│ } class B extends A //│ class B extends A { -//│ fun a1: int +//│ fun a1: Int //│ fun a2: 2 //│ } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index d74913aaf4..4169c5cbd4 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -1,11 +1,11 @@ :NewDefs -class A(n: int) -//│ class A(n: int) +class A(n: Int) +//│ class A(n: Int) A -//│ (n: int,) -> A +//│ (n: Int,) -> A //│ res //│ = [Function (anonymous)] { class: [class A] } @@ -15,42 +15,42 @@ let a = A(42) //│ = A {} a.n -//│ int +//│ Int //│ res //│ = 42 fun f(x: A) = x.n -//│ fun f: (x: A,) -> int +//│ fun f: (x: A,) -> Int fun f(x: A) = if x is A then x.n -//│ fun f: (x: A,) -> int +//│ fun f: (x: A,) -> Int fun f(x: A | 'b) = if x is A then x.n else 0 -//│ fun f: (x: anything,) -> int +//│ fun f: (x: Object,) -> Int fun f(x) = x.n //│ fun f: forall 'n. {n: 'n} -> 'n f(a) -//│ int +//│ Int //│ res //│ = 42 fun f(x) = if x is A then x.n -//│ fun f: A -> int +//│ fun f: A -> Int f(a) -//│ int +//│ Int //│ res //│ = 42 fun f(x) = if x is A then x.n else 0 -//│ fun f: anything -> int +//│ fun f: Object -> Int f(a) -//│ int +//│ Int //│ res //│ = 42 @@ -101,7 +101,7 @@ let n1 = b1.n // TODO n1 + 1 -//│ int +//│ Int //│ res //│ = 43 @@ -117,30 +117,30 @@ let n2 = b2.n -class Base1(base: int) { +class Base1(base: Int) { fun getBase1 = base fun getBase2 = this.base fun foo(x) = this.base + x } -//│ class Base1(base: int) { -//│ fun foo: int -> int -//│ fun getBase1: int -//│ fun getBase2: int +//│ class Base1(base: Int) { +//│ fun foo: Int -> Int +//│ fun getBase1: Int +//│ fun getBase2: Int //│ } -class Base1(base: int) { +class Base1(base: Int) { fun getBase1 = base fun me = this fun foo(x) = base + x } -//│ class Base1(base: int) { -//│ fun foo: int -> int -//│ fun getBase1: int -//│ fun me: Base1 & {base: int} +//│ class Base1(base: Int) { +//│ fun foo: Int -> Int +//│ fun getBase1: Int +//│ fun me: Base1 & {base: Int} //│ } Base1 -//│ (base: int,) -> Base1 +//│ (base: Int,) -> Base1 //│ res //│ = [Function (anonymous)] { class: [class Base1] } @@ -150,18 +150,18 @@ let b = Base1(1) //│ = Base1 {} b.base -//│ int +//│ Int //│ res //│ = 1 b.getBase1 -//│ int +//│ Int //│ res //│ = 1 // :d b.me -//│ Base1 & {base: int} +//│ Base1 & {base: Int} //│ res //│ = Base1 {} @@ -181,33 +181,33 @@ b : Base1 //│ = Base1 {} -class Rec(n: int) { +class Rec(n: Int) { fun go = Rec(n + 1) } -//│ class Rec(n: int) { +//│ class Rec(n: Int) { //│ fun go: Rec //│ } let r = Rec(0) r.n //│ let r: Rec -//│ int +//│ Int //│ r //│ = Rec {} //│ res //│ = 0 r.go.n -//│ int +//│ Int //│ res //│ = 1 -// TODO treat `a: int` as a signature +// TODO treat `a: Int` as a signature class Annots(base: 0 | 1) { - a: int + a: Int fun a = base } //│ class Annots(base: 0 | 1) { diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 62eb9efe9b..915c7a88d1 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -35,16 +35,16 @@ Base0.test :e -class Base1(base: int) extends BaseTest { +class Base1(base: Int) extends BaseTest { fun test2 = [base, this.base] } //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.38: class Base1(base: int) extends BaseTest { +//│ ║ l.38: class Base1(base: Int) extends BaseTest { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.39: fun test2 = [base, this.base] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.38: class Base1(base: int) extends BaseTest { +//│ ║ l.38: class Base1(base: Int) extends BaseTest { //│ ║ ^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.12: fun test = super.base @@ -52,17 +52,17 @@ class Base1(base: int) extends BaseTest { //│ ╟── from reference: //│ ║ l.12: fun test = super.base //│ ╙── ^^^^^ -//│ class Base1(base: int) { +//│ class Base1(base: Int) { //│ fun test: nothing -//│ fun test2: (int, int,) +//│ fun test2: (Int, Int,) //│ } -mixin BaseOf(base: int) { +mixin BaseOf(base: Int) { fun original = base } -//│ mixin BaseOf(base: int) { -//│ fun original: int +//│ mixin BaseOf(base: Int) { +//│ fun original: Int //│ } mixin BaseInc { @@ -70,42 +70,42 @@ mixin BaseInc { fun test2 = [this.original, this.base] } //│ mixin BaseInc() { -//│ super: {base: int} +//│ super: {base: Int} //│ this: {base: 'base, original: 'original} -//│ fun base: int +//│ fun base: Int //│ fun test2: ('original, 'base,) //│ } -class Base2(x: int) extends BaseOf(x + 1), BaseTest, BaseInc { +class Base2(x: Int) extends BaseOf(x + 1), BaseTest, BaseInc { fun base = x fun overridden = super.base } -//│ class Base2(x: int) { -//│ fun base: int -//│ fun original: int -//│ fun overridden: int -//│ fun test: int -//│ fun test2: (int, int,) +//│ class Base2(x: Int) { +//│ fun base: Int +//│ fun original: Int +//│ fun overridden: Int +//│ fun test: Int +//│ fun test2: (Int, Int,) //│ } Base2(11).base -//│ int +//│ Int //│ res //│ = 11 Base2(11).overridden -//│ int +//│ Int //│ res //│ = 13 Base2(11).test -//│ int +//│ Int //│ res //│ = 12 Base2(11).test2 -//│ (int, int,) +//│ (Int, Int,) //│ res //│ = [ 12, 11 ] @@ -116,19 +116,19 @@ class Base2(x) extends BaseOf(x + 1), BaseTest //│ ║ l.114: class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╙── ^ //│ class Base2(x: error) { -//│ fun original: int -//│ fun test: int +//│ fun original: Int +//│ fun test: Int //│ } :e -class Base1(x: int): BaseTest +class Base1(x: Int): BaseTest //│ ╔══[ERROR] mixin BaseTest cannot be used as a type -//│ ║ l.124: class Base1(x: int): BaseTest +//│ ║ l.124: class Base1(x: Int): BaseTest //│ ╙── ^^^^^^^^ -//│ class Base1(x: int): BaseTest +//│ class Base1(x: Int): BaseTest Base1 -//│ (x: int,) -> (Base1 & BaseTest) +//│ (x: Int,) -> Base1 //│ res //│ = [Function (anonymous)] { class: [class Base1] } @@ -157,20 +157,20 @@ mixin Foo { fun test(x) = [super.base + x, x, super.misc] } //│ mixin Foo() { -//│ super: {base: int, misc: 'misc} -//│ fun test: (int & 'a) -> (int, 'a, 'misc,) +//│ super: {base: Int, misc: 'misc} +//│ fun test: (Int & 'a) -> (Int, 'a, 'misc,) //│ } :e -module Base1(base: int, misc: string) extends Foo +module Base1(base: Int, misc: string) extends Foo //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.165: module Base1(base: int, misc: string) extends Foo +//│ ║ l.165: module Base1(base: Int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.165: module Base1(base: int, misc: string) extends Foo +//│ ║ l.165: module Base1(base: Int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'misc' -//│ ║ l.165: module Base1(base: int, misc: string) extends Foo +//│ ║ l.165: module Base1(base: Int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.157: fun test(x) = [super.base + x, x, super.misc] @@ -179,10 +179,10 @@ module Base1(base: int, misc: string) extends Foo //│ ║ l.157: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.165: module Base1(base: int, misc: string) extends Foo +//│ ║ l.165: module Base1(base: Int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.165: module Base1(base: int, misc: string) extends Foo +//│ ║ l.165: module Base1(base: Int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.157: fun test(x) = [super.base + x, x, super.misc] @@ -190,25 +190,25 @@ module Base1(base: int, misc: string) extends Foo //│ ╟── from reference: //│ ║ l.157: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ -//│ module Base1(base: int, misc: string) { -//│ fun test: forall 'a. (int & 'a) -> (int, 'a, nothing,) +//│ module Base1(base: Int, misc: string) { +//│ fun test: forall 'a. (Int & 'a) -> (Int, 'a, nothing,) //│ } Base1.test -//│ forall 'a. (int & 'a) -> (int, 'a, nothing,) +//│ forall 'a. (Int & 'a) -> (Int, 'a, nothing,) //│ res //│ = [Function: test] mixin WrapBase { // fun wrap(x) = x - // fun wrap(x) = x : int - fun wrapA(x: int) = x : int + // fun wrap(x) = x : Int + fun wrapA(x: Int) = x : Int fun wrap(x) = x } //│ mixin WrapBase() { //│ fun wrap: 'a -> 'a -//│ fun wrapA: (x: int,) -> int +//│ fun wrapA: (x: Int,) -> Int //│ } // :d @@ -228,7 +228,7 @@ mixin Wrap { module WrapBase1 extends WrapBase, Wrap //│ module WrapBase1 { //│ fun wrap: 'a -> ('a,) -//│ fun wrapA: int -> (int,) +//│ fun wrapA: Int -> (Int,) //│ } @@ -239,7 +239,7 @@ WrapBase1 // :d WrapBase1.wrapA -//│ int -> (int,) +//│ Int -> (Int,) //│ res //│ = [Function: wrapA] @@ -264,7 +264,7 @@ WrapBase1.wrap("ok") WrapBase1.wrapA(1) -//│ (int,) +//│ (Int,) //│ res //│ = [ 1 ] @@ -273,16 +273,13 @@ WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.272: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"ok"` is not an instance of type `int` +//│ ╟── string literal of type `"ok"` is not an instance of type `Int` //│ ║ l.272: WrapBase1.wrapA("ok") //│ ║ ^^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.206: fun wrapA(x: int) = x : int -//│ ║ ^^^ -//│ ╟── from reference: +//│ ╟── Note: constraint arises from reference: //│ ║ l.216: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ -//│ (int,) | error +//│ (Int,) | error //│ res //│ = [ 'ok' ] @@ -291,7 +288,7 @@ WrapBase1.wrapA("ok") module WrapBase2 extends WrapBase, Wrap, Wrap, Wrap //│ module WrapBase2 { //│ fun wrap: 'a -> ((('a,),),) -//│ fun wrapA: int -> (((int,),),) +//│ fun wrapA: Int -> (((Int,),),) //│ } let w = WrapBase2.wrap @@ -306,7 +303,7 @@ let wd = w(1) // TODO implement _1 wd._1._1._1 + 1 -//│ int +//│ Int //│ res //│ Runtime error: //│ TypeError: Cannot read properties of undefined (reading '_1') diff --git a/shared/src/test/diff/nu/ClassField.mls b/shared/src/test/diff/nu/ClassField.mls index dd6f6ec421..98945a4457 100644 --- a/shared/src/test/diff/nu/ClassField.mls +++ b/shared/src/test/diff/nu/ClassField.mls @@ -2,16 +2,16 @@ -class Foo(x: int) -//│ class Foo(x: int) +class Foo(x: Int) +//│ class Foo(x: Int) Foo -//│ (x: int,) -> Foo +//│ (x: Int,) -> Foo //│ res //│ = [Function (anonymous)] { class: [class Foo] } typeof(Foo) -//│ string +//│ Str //│ res //│ = 'function' @@ -21,7 +21,7 @@ let f = Foo(123) //│ = Foo {} typeof(f) -//│ string +//│ Str //│ res //│ = 'object' @@ -30,7 +30,7 @@ let cls = Foo.class //│ ╔══[ERROR] Type mismatch in field selection: //│ ║ l.29: let cls = Foo.class //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `(x: int,) -> Foo` does not have field 'class' +//│ ╟── reference of type `(x: Int,) -> Foo` does not have field 'class' //│ ║ l.29: let cls = Foo.class //│ ╙── ^^^ //│ let cls: error @@ -38,7 +38,7 @@ let cls = Foo.class //│ = [class Foo] typeof(cls) -//│ string +//│ Str //│ res //│ = 'function' @@ -69,7 +69,7 @@ let cls = Derived.class //│ = [Function: Derived] typeof(cls) -//│ string +//│ Str //│ res //│ = 'function' diff --git a/shared/src/test/diff/nu/ClassSignatures.mls b/shared/src/test/diff/nu/ClassSignatures.mls index afa6733de1..0c57079ebd 100644 --- a/shared/src/test/diff/nu/ClassSignatures.mls +++ b/shared/src/test/diff/nu/ClassSignatures.mls @@ -11,10 +11,10 @@ class Foo(): {} { //│ fun x: 0 //│ } -class Foo(): { x: int } { +class Foo(): { x: Int } { fun x = 0 } -//│ class Foo(): {x: int} { +//│ class Foo(): {x: Int} { //│ fun x: 0 //│ } @@ -30,10 +30,13 @@ not(Foo().x) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.29: not(Foo().x) //│ ║ ^^^^^^^^^^^^ -//│ ╟── field selection of type `0 & ??FigureItOut` is not an instance of type `bool` +//│ ╟── integer literal of type `0` is not an instance of type `Bool` +//│ ║ l.22: fun x = 0 +//│ ║ ^ +//│ ╟── but it flows into field selection with expected type `Bool` //│ ║ l.29: not(Foo().x) //│ ╙── ^^^^^^^ -//│ bool | error +//│ error | false | true //│ res //│ = true @@ -42,3 +45,52 @@ not(Foo().x) //│ res //│ = [Function: res] + +trait B +//│ trait B + +// :e // TODO check classes against their signatures +class A(): B +//│ class A(): B + +:e +A() : B +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.57: A() : B +//│ ║ ^^^ +//│ ╟── application of type `A` is not an instance of type `B` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.57: A() : B +//│ ╙── ^ +//│ B +//│ res +//│ = A {} + +abstract class A(): B +//│ abstract class A(): B + +:e +A() : B +//│ ╔══[ERROR] Class A is abstract and cannot be instantiated +//│ ║ l.73: A() : B +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.73: A() : B +//│ ║ ^^^ +//│ ╟── application of type `A` is not an instance of type `B` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.73: A() : B +//│ ╙── ^ +//│ B +//│ res +//│ = A {} + +module C extends A, B +//│ module C extends A, B + +C : B +//│ B +//│ res +//│ = C { class: [class C extends A] } + + diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 8da5ce8bb8..b442086b74 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -3,17 +3,17 @@ mixin Test { - class Foo(n: int) + class Foo(n: Int) let f = Foo(123) } //│ mixin Test() { -//│ class Foo(n: int) +//│ class Foo(n: Int) //│ let f: Foo //│ } module M extends Test //│ module M { -//│ class Foo(n: int) +//│ class Foo(n: Int) //│ let f: Foo //│ } @@ -23,7 +23,7 @@ M.f //│ = Foo {} M.f.n -//│ int +//│ Int //│ res //│ = 123 @@ -70,7 +70,7 @@ mixin Test3 { fun f(x) = if x is Foo then 1 } mixin Test { - class Lit(n: int) + class Lit(n: Int) class Add(lhs: A, rhs: A) { let cached = size(this) } @@ -78,12 +78,12 @@ mixin Test { Add(l, r) then this.size(l) + this.size(r) } //│ mixin Test() { -//│ this: {size: 'lhs -> int} +//│ this: {size: 'lhs -> Int} //│ class Add[A](lhs: A, rhs: A) { -//│ let cached: int +//│ let cached: Int //│ } -//│ class Lit(n: int) -//│ fun size: Add['lhs] -> int +//│ class Lit(n: Int) +//│ fun size: Add['lhs] -> Int //│ } diff --git a/shared/src/test/diff/nu/CtorStatements.mls b/shared/src/test/diff/nu/CtorStatements.mls index 9a59b4de2a..e131cca827 100644 --- a/shared/src/test/diff/nu/CtorStatements.mls +++ b/shared/src/test/diff/nu/CtorStatements.mls @@ -2,7 +2,7 @@ log("Hello!") -//│ unit +//│ undefined //│ res //│ = undefined //│ // Output diff --git a/shared/src/test/diff/nu/Dates.mls b/shared/src/test/diff/nu/Dates.mls index b4393f8549..1f28bc5c39 100644 --- a/shared/src/test/diff/nu/Dates.mls +++ b/shared/src/test/diff/nu/Dates.mls @@ -2,13 +2,13 @@ declare class Date { - constructor(date: number) - fun toString(): string - fun toLocaleString(locales: string | Array[string], options: anything): string + constructor(date: Num) + fun toString(): Str + fun toLocaleString(locales: Str | Array[Str], options: anything): Str } //│ declare class Date { -//│ fun toLocaleString: (locales: Array[string] | string, options: anything,) -> string -//│ fun toString: () -> string +//│ fun toLocaleString: (locales: Array[Str] | Str, options: anything,) -> Str +//│ fun toString: () -> Str //│ } :e // TODO ctor typing @@ -24,7 +24,7 @@ let date1 = new Date(12345678) //│ = 1970-01-01T03:25:45.678Z date1.toLocaleString("en-US", { timeZone: "America/New_York" }) -//│ error | string +//│ Str | error //│ res //│ = '12/31/1969, 10:25:45 PM' diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index 1c1b3f1a95..8fd6e062d2 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -18,10 +18,10 @@ atob(str) declare module console { - fun error: string -> unit + fun error: Str -> unit } //│ declare module console { -//│ fun error: string -> unit +//│ fun error: Str -> unit //│ } console.error("hello") @@ -43,22 +43,22 @@ console.log("hello") declare module Foo { - fun foo: int + fun foo: Int } //│ declare module Foo { -//│ fun foo: int +//│ fun foo: Int //│ } :re Foo.foo -//│ int +//│ Int //│ res //│ Runtime error: //│ ReferenceError: Foo is not defined -declare type A = int -//│ type A = int +declare type A = Int +//│ type A = Int 42 : A //│ A @@ -68,10 +68,10 @@ declare type A = int declare class Sanitizer { - fun sanitizeFor(element: string, input: string): string + fun sanitizeFor(element: Str, input: Str): Str } //│ declare class Sanitizer { -//│ fun sanitizeFor: (element: string, input: string,) -> string +//│ fun sanitizeFor: (element: Str, input: Str,) -> Str //│ } :re @@ -87,19 +87,19 @@ let s = Sanitizer() // :d declare module Buffer { class Buffer2 { - val length: int + val length: Int } - fun bar: int - fun from(a: Array[int]): Buffer2 = from(a) - // fun from1(a: Array[int]): this.Buffer2 = from1(a) // FIXME - // fun from2(a: Array[int]): Buffer.Buffer2 = from2(a) // FIXME + fun bar: Int + fun from(a: Array[Int]): Buffer2 = from(a) + // fun from1(a: Array[Int]): this.Buffer2 = from1(a) // FIXME + // fun from2(a: Array[Int]): Buffer.Buffer2 = from2(a) // FIXME } //│ declare module Buffer { //│ class Buffer2 { -//│ let length: int +//│ let length: Int //│ } -//│ fun bar: int -//│ fun from: (a: Array[int],) -> Buffer2 +//│ fun bar: Int +//│ fun from: (a: Array[Int],) -> Buffer2 //│ } let b = Buffer.from([0, 1, 2]) @@ -108,7 +108,7 @@ let b = Buffer.from([0, 1, 2]) //│ = b.length -//│ int +//│ Int //│ res //│ = 3 diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index 5cde0b8516..f1a2222243 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -8,7 +8,7 @@ trait Foo[A] { fun foo: A } //│ fun foo: A //│ } -module Bar extends Foo[int | bool], Foo[int | string] { +module Bar extends Foo[Int | Bool], Foo[Int | Str] { fun foo = 123 } //│ module Bar extends Foo { @@ -23,12 +23,12 @@ Bar.foo Bar : Foo['X] //│ Foo['X] //│ where -//│ 'X := int | string +//│ 'X := Int | Str //│ res //│ = Bar { class: [class Bar extends Object] } (Bar : Foo['X]).foo -//│ int | string +//│ Int | Str //│ res //│ = 123 @@ -39,7 +39,7 @@ trait Foo[A] { fun foo: A; fun bar: A -> A } //│ fun foo: A //│ } -module Bar extends Foo[int | bool], Foo[int | string] { +module Bar extends Foo[Int | Bool], Foo[Int | Str] { fun foo = 123 fun bar = id } @@ -56,20 +56,20 @@ Bar.bar Bar : Foo['X] //│ Foo['X] //│ where -//│ 'X := int | string +//│ 'X := Int | Str //│ res //│ = Bar { class: [class Bar extends Object] } -trait T1 extends Foo[int | bool] +trait T1 extends Foo[Int | Bool] //│ trait T1 extends Foo { //│ fun bar: 'A -> 'A //│ fun foo: 'A //│ } //│ where -//│ 'A := bool | int +//│ 'A := in Bool | Int out Int | false | true -module Bar extends T1, Foo[int | string] { +module Bar extends T1, Foo[Int | Str] { fun foo = 123 fun bar = id } @@ -79,39 +79,39 @@ module Bar extends T1, Foo[int | string] { //│ } (Bar : Foo['X]).foo -//│ int | string +//│ Int | Str //│ res //│ = 123 (Bar : Foo['X]).bar -//│ ('A & (int | string)) -> ('A | int | string) +//│ ('A & (Int | Str)) -> ('A | Int | Str) //│ res //│ = [Function: id] (Bar : T1).foo -//│ bool | int +//│ Int | false | true //│ res //│ = 123 let f = (Bar : T1).bar f(true) -//│ let f: ('A & (bool | int)) -> ('A | bool | int) -//│ bool | int +//│ let f: ('A & (Bool | Int)) -> ('A | Int | false | true) +//│ Int | false | true //│ f //│ = [Function: id] //│ res //│ = true :e -module Bar extends T1, Foo[int | string] { +module Bar extends T1, Foo[Int | Str] { fun foo = 123 fun bar(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method bar: //│ ║ l.108: fun bar(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.64: trait T1 extends Foo[int | bool] +//│ ╟── type `Bool` is not an instance of `Int` +//│ ║ l.64: trait T1 extends Foo[Int | Bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.108: fun bar(x) = x + 1 @@ -119,21 +119,21 @@ module Bar extends T1, Foo[int | string] { //│ ╔══[ERROR] Type mismatch in definition of method bar: //│ ║ l.108: fun bar(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `string` is not an instance of type `int` -//│ ║ l.106: module Bar extends T1, Foo[int | string] { -//│ ║ ^^^^^^ +//│ ╟── type `Str` is not an instance of `Int` +//│ ║ l.106: module Bar extends T1, Foo[Int | Str] { +//│ ║ ^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.108: fun bar(x) = x + 1 //│ ╙── ^ //│ module Bar extends Foo, T1 { -//│ fun bar: int -> int +//│ fun bar: Int -> Int //│ fun foo: 123 //│ } trait Base[A] { fun foo: A; fun bar: A -> A } trait Derived1[A] extends Base[A] -trait Derived2 extends Base[(int | string, int | string)] +trait Derived2 extends Base[(Int | Str, Int | Str)] //│ trait Base[A] { //│ fun bar: A -> A //│ fun foo: A @@ -147,10 +147,10 @@ trait Derived2 extends Base[(int | string, int | string)] //│ fun foo: 'A0 //│ } //│ where -//│ 'A0 := (int | string, int | string,) +//│ 'A0 := (Int | Str, Int | Str,) //│ 'A := A -class Final extends Derived1[(int, int)], Derived2 { +class Final extends Derived1[(Int, Int)], Derived2 { fun foo = (123, 456) fun bar([x, y]) = [error, error] } @@ -160,24 +160,24 @@ class Final extends Derived1[(int, int)], Derived2 { //│ } :e -class Final extends Derived1[(int, int)], Derived2 { +class Final extends Derived1[(Int, Int)], Derived2 { fun foo = (123, 456) fun bar([x, y]) = [y, x] } //│ ╔══[ERROR] Type mismatch in definition of method bar: //│ ║ l.165: fun bar([x, y]) = [y, x] //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` -//│ ║ l.136: trait Derived2 extends Base[(int | string, int | string)] -//│ ║ ^^^^^^ +//│ ╟── type `Str` is not an instance of `Int` +//│ ║ l.136: trait Derived2 extends Base[(Int | Str, Int | Str)] +//│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.163: class Final extends Derived1[(int, int)], Derived2 { +//│ ║ l.163: class Final extends Derived1[(Int, Int)], Derived2 { //│ ║ ^^^ //│ ╟── from reference: //│ ║ l.165: fun bar([x, y]) = [y, x] //│ ╙── ^ //│ class Final extends Base, Derived1, Derived2 { -//│ fun bar: (int, int,) -> (int | string, int | string,) +//│ fun bar: (Int, Int,) -> (Int | Str, Int | Str,) //│ fun foo: (123, 456,) //│ } diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index a65ddd43d7..64b3aba183 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -14,15 +14,15 @@ let Cons: (head: 'a, tail: List<'a>) => List<'a> //│ let Nil: List[nothing] //│ let Cons: forall 'a. (head: 'a, tail: List['a],) -> List['a] -let x: List -//│ let x: List[int] +let x: List +//│ let x: List[Int] // FIXME x: List //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.21: x: List //│ ║ ^ -//│ ╙── expression of type `anything` does not match type `int` +//│ ╙── expression of type `anything` does not match type `Int` //│ List[anything] diff --git a/shared/src/test/diff/nu/Eql.mls b/shared/src/test/diff/nu/Eql.mls index 911d30a66d..33d7b0fe4c 100644 --- a/shared/src/test/diff/nu/Eql.mls +++ b/shared/src/test/diff/nu/Eql.mls @@ -1,13 +1,13 @@ :NewDefs -let x: Eql[int] -//│ let x: Eql[int] +let x: Eql[Int] +//│ let x: Eql[Int] //│ x //│ = x === 1 -//│ bool +//│ Bool //│ res //│ = //│ x is not implemented @@ -17,13 +17,13 @@ x === 1 //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.16: 1 === x //│ ║ ^^^^^^^ -//│ ╟── type `#Eql & {Eql#A :> int}` is not an instance of type `number` -//│ ║ l.4: let x: Eql[int] +//│ ╟── type `#Eql` is not an instance of type `Num` +//│ ║ l.4: let x: Eql[Int] //│ ║ ^^^^^^^^ -//│ ╟── but it flows into reference with expected type `number` +//│ ╟── but it flows into reference with expected type `Num` //│ ║ l.16: 1 === x //│ ╙── ^ -//│ bool | error +//│ error | false | true //│ res //│ = //│ x is not implemented @@ -33,16 +33,13 @@ x === x //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.32: x === x //│ ║ ^^^^^^^ -//│ ╟── type `#Eql & {Eql#A :> int}` is not an instance of type `int` -//│ ║ l.4: let x: Eql[int] +//│ ╟── type `#Eql` does not match type `?A | Int` +//│ ║ l.4: let x: Eql[Int] //│ ║ ^^^^^^^^ -//│ ╟── but it flows into reference with expected type `int` +//│ ╟── but it flows into reference with expected type `?A0 | Int` //│ ║ l.32: x === x -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.4: let x: Eql[int] -//│ ╙── ^^^ -//│ bool | error +//│ ╙── ^ +//│ error | false | true //│ res //│ = //│ x is not implemented @@ -50,20 +47,20 @@ x === x fun test1(x) = x === x -//│ fun test1: forall 'a. (Eql['a] & 'a) -> bool +//│ fun test1: forall 'a. (Eql['a] & 'a) -> Bool fun test2(x, y) = x === y -//│ fun test2: forall 'a. (Eql['a], 'a,) -> bool +//│ fun test2: forall 'a. (Eql['a], 'a,) -> Bool 1 : Eql['a] -//│ Eql[number] +//│ Eql[Num] //│ res //│ = 1 -1 : Eql[int] -//│ Eql[int] +1 : Eql[Int] +//│ Eql[Int] //│ res //│ = 1 @@ -73,81 +70,97 @@ fun test2(x, y) = //│ = 1 test1(1) -//│ bool +//│ Bool //│ res //│ = true +:e +test1(x) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.78: test1(x) +//│ ║ ^^^^^^^^ +//│ ╟── type `#Eql` does not match type `?A | Int` +//│ ║ l.4: let x: Eql[Int] +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into reference with expected type `?A0 | Int` +//│ ║ l.78: test1(x) +//│ ╙── ^ +//│ error | false | true +//│ res +//│ = +//│ x is not implemented + -let n: int = 1 -//│ let n: int +let n: Int = 1 +//│ let n: Int //│ n //│ = 1 n : Eql['a] -//│ Eql[number] +//│ Eql[anything] //│ res //│ = 1 test1(n) -//│ bool +//│ Bool //│ res //│ = true -let n: number -//│ let n: number +let n: Num +//│ let n: Num //│ n //│ = test1(n) -//│ bool +//│ Bool //│ res //│ = //│ n is not implemented let d = 1/2 -//│ let d: number +//│ let d: Num //│ d //│ = 0.5 test1(d) -//│ bool +//│ Bool //│ res //│ = true test1("hello") -//│ bool +//│ Bool //│ res //│ = true test2(0, 1) -//│ bool +//│ Bool //│ res //│ = false test2(0, d) -//│ bool +//│ Bool //│ res //│ = false x => test2(0, x) -//│ number -> bool +//│ Num -> Bool //│ res //│ = [Function: res] x => test2(x, 0) -//│ Eql[0] -> bool +//│ Eql[0] -> Bool //│ res //│ = [Function: res] x => test2(d, x) -//│ number -> bool +//│ anything -> Bool //│ res //│ = [Function: res] x => test2(x, d) -//│ Eql[number] -> bool +//│ Eql[Num] -> Bool //│ res //│ = [Function: res] @@ -155,69 +168,69 @@ x => test2(x, d) :e test2(1, "oops") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.156: test2(1, "oops") +//│ ║ l.169: test2(1, "oops") //│ ║ ^^^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"oops"` is not an instance of type `number` -//│ ║ l.156: test2(1, "oops") +//│ ╟── string literal of type `"oops"` is not an instance of type `Num` +//│ ║ l.169: test2(1, "oops") //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.56: x === y +//│ ║ l.53: x === y //│ ╙── ^ -//│ bool | error +//│ error | false | true //│ res //│ = false :e test2("oops", 1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.171: test2("oops", 1) +//│ ║ l.184: test2("oops", 1) //│ ║ ^^^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `string` -//│ ║ l.171: test2("oops", 1) +//│ ╟── integer literal of type `1` is not an instance of type `Str` +//│ ║ l.184: test2("oops", 1) //│ ║ ^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.56: x === y +//│ ║ l.53: x === y //│ ╙── ^ -//│ bool | error +//│ error | false | true //│ res //│ = false :e test2(1, {}) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.186: test2(1, {}) +//│ ║ l.199: test2(1, {}) //│ ║ ^^^^^^^^^^^^ -//│ ╟── record literal of type `anything` is not an instance of type `number` +//│ ╟── record literal of type `anything` is not an instance of type `Num` //│ ╟── Note: constraint arises from reference: -//│ ║ l.56: x === y +//│ ║ l.53: x === y //│ ╙── ^ -//│ bool | error +//│ error | false | true //│ res //│ = false :e test2({}, 1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.199: test2({}, 1) +//│ ║ l.212: test2({}, 1) //│ ║ ^^^^^^^^^^^^ //│ ╟── record literal of type `anything` is not an instance of type `Eql` //│ ╟── Note: constraint arises from reference: -//│ ║ l.56: x === y +//│ ║ l.53: x === y //│ ╙── ^ -//│ bool | error +//│ error | false | true //│ res //│ = false :e test2({}, {}) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.212: test2({}, {}) +//│ ║ l.225: test2({}, {}) //│ ║ ^^^^^^^^^^^^^ //│ ╟── record literal of type `anything` is not an instance of type `Eql` //│ ╟── Note: constraint arises from reference: -//│ ║ l.56: x === y +//│ ║ l.53: x === y //│ ╙── ^ -//│ bool | error +//│ error | false | true //│ res //│ = false diff --git a/shared/src/test/diff/nu/EqlClasses.mls b/shared/src/test/diff/nu/EqlClasses.mls index 1810e05aa5..dd4c6663b5 100644 --- a/shared/src/test/diff/nu/EqlClasses.mls +++ b/shared/src/test/diff/nu/EqlClasses.mls @@ -6,7 +6,7 @@ module Mod //│ module Mod Mod === Mod -//│ bool +//│ Bool //│ res //│ = true @@ -15,16 +15,16 @@ class Cls1() //│ class Cls1() Cls1() === Cls1() -//│ bool +//│ Bool //│ res //│ = false -class Cls2(x: int) -//│ class Cls2(x: int) +class Cls2(x: Int) +//│ class Cls2(x: Int) Cls2(0) === Cls2(1) -//│ bool +//│ Bool //│ res //│ = false @@ -40,23 +40,23 @@ let p = Pair(1, 2) //│ = Pair {} p === p -//│ bool +//│ Bool //│ res //│ = true x => p === x -//│ {fst: Eql[1 | 2], snd: Eql[1 | 2]} -> bool +//│ {fst: Eql[1 | 2], snd: Eql[1 | 2]} -> Bool //│ res //│ = [Function: res] x => x === p -//│ Eql[Pair[1 | 2]] -> bool +//│ Eql[Pair[1 | 2]] -> Bool //│ res //│ = [Function: res] p === { fst: 1, snd: 2 } -//│ bool +//│ Bool //│ res //│ = false @@ -68,7 +68,7 @@ p === { fst: 1, snd: 2 } //│ ╟── record literal of type `{fst: 1, snd: 2}` is not an instance of type `Eql` //│ ║ l.64: { fst: 1, snd: 2 } === p //│ ╙── ^^^^^^^^^ -//│ bool | error +//│ error | false | true //│ res //│ = false @@ -77,8 +77,8 @@ let r = {x: 42, y: y => y} //│ r //│ = { x: 42, y: [Function: y] } -r : {x: int} -//│ {x: int} +r : {x: Int} +//│ {x: Int} //│ res //│ = { x: 42, y: [Function: y] } @@ -91,13 +91,13 @@ x => { a: 0 } === x //│ ╟── record literal of type `{a: 0}` is not an instance of type `Eql` //│ ║ l.87: x => { a: 0 } === x //│ ╙── ^ -//│ anything -> (bool | error) +//│ anything -> (error | false | true) //│ res //│ Syntax error: //│ Unexpected token '===' x => x === { a: 0 } -//│ Eql[{a: 0}] -> bool +//│ Eql[{a: 0}] -> Bool //│ res //│ = [Function: res] @@ -113,10 +113,10 @@ q === q //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.112: q === q //│ ║ ^^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `string` +//│ ╟── integer literal of type `1` is not an instance of type `Str` //│ ║ l.106: let q = Pair(1, "oops") //│ ╙── ^ -//│ bool | error +//│ error | false | true //│ res //│ = true @@ -130,7 +130,7 @@ let q = Pair2(1, "oops") //│ = Pair2 {} q === q -//│ bool +//│ Bool //│ res //│ = true diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index 6e0182c576..1855b788c0 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -2,20 +2,20 @@ class Add(lhs: E, rhs: E) -class Lit(n: int) +class Lit(n: Int) //│ class Add[E](lhs: E, rhs: E) -//│ class Lit(n: int) +//│ class Lit(n: Int) mixin EvalBase { fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n: Int Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit) -> int +//│ this: {eval: 'lhs -> Int} +//│ fun eval: (Add['lhs] | Lit) -> Int //│ } @@ -30,8 +30,8 @@ mixin EvalNeg { } //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} -//│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) +//│ this: {eval: 'expr -> Int} +//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> (Int | 'b) //│ } @@ -43,33 +43,35 @@ mixin EvalNegNeg { //│ mixin EvalNegNeg() { //│ super: {eval: (Neg[nothing] | 'a) -> 'b} //│ this: {eval: 'expr -> 'b} -//│ fun eval: (Neg[Neg['expr] | ~Neg[anything]] | 'a & ~#Neg) -> 'b +//│ fun eval: (Neg[Neg['expr] | Object & ~#Neg] | Object & 'a & ~#Neg) -> 'b //│ } module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang { -//│ fun eval: 'a -> int +//│ fun eval: 'a -> Int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | ~#Neg)] +//│ 'a <: Neg['A] | Object & 'b & ~#Neg +//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit | Neg['a] fun mk(n) = if n is 0 then Lit(3) 1 then Neg(mk(n - 1)) _ then Add(mk(n - 1), mk(n - 1)) -//│ fun mk: forall 'E. (0 | 1 | int & ~0 & ~1) -> 'E +//│ fun mk: forall 'E. (0 | 1 | Int & ~0 & ~1) -> 'E //│ where //│ 'E :> Add['E] | Lit | Neg['E] TestLang.eval(mk(0)) -//│ int +//│ Int //│ res //│ = 3 TestLang.eval(mk(11)) -//│ int +//│ Int //│ res //│ = -3072 diff --git a/shared/src/test/diff/nu/ExplicitVariance.mls b/shared/src/test/diff/nu/ExplicitVariance.mls index 5bbf93099d..a7e7da9023 100644 --- a/shared/src/test/diff/nu/ExplicitVariance.mls +++ b/shared/src/test/diff/nu/ExplicitVariance.mls @@ -5,41 +5,41 @@ class Foo[out A](x: A) //│ class Foo[A](x: A) -fun foo(x: Foo[int]): Foo[number] = x -//│ fun foo: (x: Foo[int],) -> Foo[number] +fun foo(x: Foo[Int]): Foo[Num] = x +//│ fun foo: (x: Foo[Int],) -> Foo[Num] :e -fun foo(x: Foo[number]): Foo[int] = x +fun foo(x: Foo[Num]): Foo[Int] = x //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.12: fun foo(x: Foo[number]): Foo[int] = x -//│ ║ ^ -//│ ╟── type `number` is not an instance of `int` -//│ ║ l.12: fun foo(x: Foo[number]): Foo[int] = x -//│ ║ ^^^^^^ +//│ ║ l.12: fun foo(x: Foo[Num]): Foo[Int] = x +//│ ║ ^ +//│ ╟── type `Num` is not an instance of `Int` +//│ ║ l.12: fun foo(x: Foo[Num]): Foo[Int] = x +//│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: fun foo(x: Foo[number]): Foo[int] = x -//│ ╙── ^^^ -//│ fun foo: (x: Foo[number],) -> Foo[int] +//│ ║ l.12: fun foo(x: Foo[Num]): Foo[Int] = x +//│ ╙── ^^^ +//│ fun foo: (x: Foo[Num],) -> Foo[Int] -class Foo[in A](x: A -> int) -//│ class Foo[A](x: A -> int) +class Foo[in A](x: A -> Int) +//│ class Foo[A](x: A -> Int) -fun foo(x: Foo[number]): Foo[int] = x -//│ fun foo: (x: Foo[number],) -> Foo[int] +fun foo(x: Foo[Num]): Foo[Int] = x +//│ fun foo: (x: Foo[Num],) -> Foo[Int] :e -fun foo(x: Foo[int]): Foo[number] = x +fun foo(x: Foo[Int]): Foo[Num] = x //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.32: fun foo(x: Foo[int]): Foo[number] = x -//│ ║ ^ -//│ ╟── type `number` is not an instance of `int` -//│ ║ l.32: fun foo(x: Foo[int]): Foo[number] = x -//│ ║ ^^^^^^ +//│ ║ l.32: fun foo(x: Foo[Int]): Foo[Num] = x +//│ ║ ^ +//│ ╟── type `Num` is not an instance of `Int` +//│ ║ l.32: fun foo(x: Foo[Int]): Foo[Num] = x +//│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.32: fun foo(x: Foo[int]): Foo[number] = x +//│ ║ l.32: fun foo(x: Foo[Int]): Foo[Num] = x //│ ╙── ^^^ -//│ fun foo: (x: Foo[int],) -> Foo[number] +//│ fun foo: (x: Foo[Int],) -> Foo[Num] @@ -52,8 +52,8 @@ class Oops0[in A](x: A) //│ class Oops0[A](x: A) // :e // TODO check variance annotations! -class Oops0[out A](x: A -> int) -//│ class Oops0[A](x: A -> int) +class Oops0[out A](x: A -> Int) +//│ class Oops0[A](x: A -> Int) let o = Oops0(id) //│ let o: Oops0[nothing] @@ -63,13 +63,13 @@ let o = Oops0(id) // * What happens is `Oops9{ A = nothing..'? }` is inferred for `o` (consistent with `A`'s covariance), // * so all negative occurrences of `o.A` are viewed as `nothing` from the outside. o.x -//│ nothing -> int +//│ nothing -> Int //│ res //│ = [Function: id] -// * Similarly, `Oops0[int]` here will expand to the equivalent `Oops0{ A = nothing..int }` -(o : Oops0[int]).x -//│ nothing -> int +// * Similarly, `Oops0[Int]` here will expand to the equivalent `Oops0{ A = nothing..Int }` +(o : Oops0[Int]).x +//│ nothing -> Int //│ res //│ = [Function: id] @@ -82,24 +82,24 @@ o.x(123) //│ ║ l.77: o.x(123) //│ ║ ^^^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.55: class Oops0[out A](x: A -> int) +//│ ║ l.55: class Oops0[out A](x: A -> Int) //│ ╙── ^ -//│ error | int +//│ Int | error //│ res //│ = 123 :e -(o : Oops0[int]).x(123) +(o : Oops0[Int]).x(123) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.92: (o : Oops0[int]).x(123) +//│ ║ l.92: (o : Oops0[Int]).x(123) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `123` does not match type `nothing` -//│ ║ l.92: (o : Oops0[int]).x(123) +//│ ║ l.92: (o : Oops0[Int]).x(123) //│ ║ ^^^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.55: class Oops0[out A](x: A -> int) +//│ ║ l.55: class Oops0[out A](x: A -> Int) //│ ╙── ^ -//│ error | int +//│ Int | error //│ res //│ = 123 @@ -134,7 +134,7 @@ o.x(123) :re o.x(error) + 1 -//│ int +//│ Int //│ res //│ Runtime error: //│ Error: unexpected runtime error @@ -188,7 +188,7 @@ o.x(o.y) :re o.x(error) + 1 -//│ int +//│ Int //│ res //│ Runtime error: //│ Error: unexpected runtime error diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index 5dea218d65..807fe3dc8f 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -12,18 +12,18 @@ fun eval(e) = if e is Add0(l) then eval(l) class Add(lhs: E, rhs: E) -class Lit(value: int) +class Lit(value: Int) //│ class Add[E](lhs: E, rhs: E) -//│ class Lit(value: int) +//│ class Lit(value: Int) let add11 = Add(Lit(1), Lit(2)) //│ let add11: Add[Lit] fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n: Int Add(l, r) then eval(l) + eval(r) -//│ fun eval: forall 'a. 'a -> int +//│ fun eval: forall 'a. 'a -> Int //│ where //│ 'a <: Add['a] | Lit @@ -34,14 +34,14 @@ mixin EvalLit { Lit(n) then n } //│ mixin EvalLit() { -//│ fun eval: Lit -> int +//│ fun eval: Lit -> Int //│ } mixin EvalLit { fun eval(e: Lit) = e.value } //│ mixin EvalLit() { -//│ fun eval: (e: Lit,) -> int +//│ fun eval: (e: Lit,) -> Int //│ } @@ -72,24 +72,24 @@ TestLang.eval mixin EvalBase { fun eval(e) = if e is - Lit(n) then n: int + Lit(n) then n: Int Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit) -> int +//│ this: {eval: 'lhs -> Int} +//│ fun eval: (Add['lhs] | Lit) -> Int //│ } module TestLang extends EvalBase //│ module TestLang { -//│ fun eval: (Add['E] | Lit) -> int +//│ fun eval: (Add['E] | Lit) -> Int //│ } //│ where //│ 'E <: Add['E] | Lit TestLang.eval -//│ (Add['E] | Lit) -> int +//│ (Add['E] | Lit) -> Int //│ where //│ 'E <: Add['E] | Lit @@ -99,13 +99,13 @@ add11 //│ Add[Lit] TestLang.eval(add11) -//│ int +//│ Int add11 //│ Add[Lit] TestLang.eval(add11) -//│ int +//│ Int add11 //│ Add[Lit] @@ -126,43 +126,43 @@ mixin EvalNeg { } //│ mixin EvalNeg() { //│ super: {eval: 'a -> 'b} -//│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> (int | 'b) +//│ this: {eval: 'expr -> Int} +//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> (Int | 'b) //│ } module TestLang extends EvalBase, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> int +//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'expr <: Neg['expr] | 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit +//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit TestLang.eval -//│ (Neg['expr] | 'a & ~#Neg) -> int +//│ (Neg['expr] | Object & 'a & ~#Neg) -> Int //│ where -//│ 'expr <: Neg['expr] | 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit +//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit TestLang.eval(add11) -//│ int +//│ Int TestLang.eval(Neg(add11)) -//│ int +//│ Int TestLang.eval(Add(Lit(2), Neg(Lit(1)))) -//│ int +//│ Int TestLang.eval(Neg(Neg(add11))) -//│ int +//│ Int TestLang.eval(add2negadd11) -//│ int +//│ Int TestLang.eval(Add(Lit(2), Neg(add11))) -//│ int +//│ Int diff --git a/shared/src/test/diff/nu/ExpressionProblem_small.mls b/shared/src/test/diff/nu/ExpressionProblem_small.mls index 63117d1691..d98c2ab370 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_small.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_small.mls @@ -4,10 +4,10 @@ class Neg[A](expr: A) class Add[E](lhs: E, rhs: E) -class Lit(n: int) +class Lit(n: Int) //│ class Neg[A](expr: A) //│ class Add[E](lhs: E, rhs: E) -//│ class Lit(n: int) +//│ class Lit(n: Int) let add11 = Add(Lit(1), Lit(2)) let add2negadd11 = Add(Lit(2), Neg(add11)) @@ -34,27 +34,27 @@ mixin EvalNeg { //│ } //│ mixin EvalAddLit() { //│ super: {eval: 'a -> 'b} -//│ this: {eval: 'lhs -> int} -//│ fun eval: (Add['lhs] | Lit | 'a & ~#Add & ~#Lit) -> (int | 'b) +//│ this: {eval: 'lhs -> Int} +//│ fun eval: (Add['lhs] | Lit | Object & 'a & ~#Add & ~#Lit) -> (Int | 'b) //│ } //│ mixin EvalNeg() { //│ super: {eval: 'c -> 'd} -//│ this: {eval: 'expr -> int} -//│ fun eval: (Neg['expr] | 'c & ~#Neg) -> (int | 'd) +//│ this: {eval: 'expr -> Int} +//│ fun eval: (Neg['expr] | Object & 'c & ~#Neg) -> (Int | 'd) //│ } module TestLang extends EvalNothing, EvalAddLit, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['expr] | 'a & ~#Neg) -> int +//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'expr <: Neg['expr] | 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit +//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit TestLang.eval -//│ (Neg['expr] | 'a & ~#Neg) -> int +//│ (Neg['expr] | Object & 'a & ~#Neg) -> Int //│ where -//│ 'expr <: Neg['expr] | 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | 'a & ~#Neg] | Lit +//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg +//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit diff --git a/shared/src/test/diff/nu/FieldRefinement.mls b/shared/src/test/diff/nu/FieldRefinement.mls index 6c5dee5364..03eaaa2970 100644 --- a/shared/src/test/diff/nu/FieldRefinement.mls +++ b/shared/src/test/diff/nu/FieldRefinement.mls @@ -2,17 +2,17 @@ :NoJS -class Foo(x: int) { +class Foo(x: Int) { fun bar = x fun baz: 1 | 2 = 1 } -//│ class Foo(x: int) { -//│ fun bar: int +//│ class Foo(x: Int) { +//│ fun bar: Int //│ fun baz: 1 | 2 //│ } -let foo: Foo & { x: 0 | 1, bar: 0 | 1, baz: 0 | 1, y: bool } -//│ let foo: Foo & {y: bool, bar: 0 | 1, baz: 0 | 1, x: 0 | 1} +let foo: Foo & { x: 0 | 1, bar: 0 | 1, baz: 0 | 1, y: Bool } +//│ let foo: Foo & {y: Bool, bar: 0 | 1, baz: 0 | 1, x: 0 | 1} foo.x //│ 0 | 1 @@ -24,11 +24,11 @@ foo.baz //│ 1 foo.y -//│ bool +//│ Bool :e foo.z -//│ ╔══[ERROR] Type `Foo & {y: bool, bar: 0 | 1, baz: 0 | 1, x: 0 | 1}` does not contain member `z` +//│ ╔══[ERROR] Type `Foo & {y: Bool, bar: 0 | 1, baz: 0 | 1, x: 0 | 1}` does not contain member `z` //│ ║ l.30: foo.z //│ ╙── ^^ //│ error diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 351964999e..c5f1171268 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -3,9 +3,9 @@ // * From https://arxiv.org/abs/2302.12783 -// 1 -spec filtermap ( fun (( T ) -> boolean ()) , [ T ]) -> [ T ] +// 1 -spec filtermap ( fun (( T ) -> Boolean ()) , [ T ]) -> [ T ] // 2 ; ( fun (( T ) -> { true , U } | false ) , [ T ]) -> [ U ] -// 3 ; ( fun (( T ) -> { true , U } | boolean ()) , [ T ]) -> [ T | U ]. +// 3 ; ( fun (( T ) -> { true , U } | Boolean ()) , [ T ]) -> [ T | U ]. // 4 filtermap ( _F , []) -> []; // 5 filtermap (F , [ X | XS ]) -> // 6 case F ( X ) of @@ -30,15 +30,15 @@ fun filtermap(f, xs) = if xs is [true, z] then Cons(y, filtermap(f, ys)) //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── -//│ fun filtermap: ((Cons[nothing] | Nil) -> (error | false | true), Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) +//│ fun filtermap: ((Cons[nothing] | Nil) -> nothing, Cons[anything] | Nil,) -> (Cons[nothing] | Nil | error) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 -module True -module False -//│ module True -//│ module False +module Tru +module Fals +//│ module Tru +//│ module Fals class Pair[A, B](lhs: A, rhs: B) //│ class Pair[A, B](lhs: A, rhs: B) @@ -46,10 +46,10 @@ class Pair[A, B](lhs: A, rhs: B) fun filtermap(f, xs) = if xs is Nil then Nil Cons(y, ys) then if f(y) is - True then filtermap(f, ys) - False then Cons(y, filtermap(f, ys)) - Pair(True, z) then Cons(z, filtermap(f, ys)) -//│ fun filtermap: forall 'head 'A. ('head -> (False | Pair[True, 'A] | True), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) + Tru then filtermap(f, ys) + Fals then Cons(y, filtermap(f, ys)) + Pair(Tru, z) then Cons(z, filtermap(f, ys)) +//│ fun filtermap: forall 'head 'A. ('head -> (Fals | Pair[Tru, 'A] | Tru), Cons['head & 'A] | Nil,) -> (Cons['A] | Nil) fun mkString(xs) = if xs is @@ -57,24 +57,24 @@ fun mkString(xs) = Cons(x, xs') and xs' is Nil then toString(x) else concat(toString(x))(concat(", ")(mkString(xs'))) -//│ fun mkString: (Cons[anything] | Nil) -> string +//│ fun mkString: (Cons[anything] | Nil) -> Str let list = Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Cons(6, Cons(7, Nil))))))) mkString of list //│ let list: Cons[1 | 2 | 3 | 4 | 5 | 6 | 7] -//│ string +//│ Str //│ list //│ = Cons {} //│ res //│ = '1, 2, 3, 4, 5, 6, 7' -mkString of filtermap(x => if x % 2 == 0 then True else False, list) -mkString of filtermap(x => if x % 2 == 0 then False else True, list) +mkString of filtermap(x => if x % 2 == 0 then Tru else Fals, list) +mkString of filtermap(x => if x % 2 == 0 then Fals else Tru, list) mkString of filtermap(x => (if - x % 2 == 0 then False - x % 3 == 0 then Pair(True, x / 3) - else True), list) -//│ string + x % 2 == 0 then Fals + x % 3 == 0 then Pair(Tru, x / 3) + else Tru), list) +//│ Str //│ res //│ = '1, 3, 5, 7' //│ res diff --git a/shared/src/test/diff/nu/FunPatterns.mls b/shared/src/test/diff/nu/FunPatterns.mls index 414a848b1e..9c84d6caf6 100644 --- a/shared/src/test/diff/nu/FunPatterns.mls +++ b/shared/src/test/diff/nu/FunPatterns.mls @@ -3,19 +3,19 @@ fun f(x, y) = x + y -//│ fun f: (int, int,) -> int +//│ fun f: (Int, Int,) -> Int // FIXME array pattern...?! fun f1([x, y]) = x + y fun f2([x, y],) = x + y fun f3([(x, y,),],) = x + y -//│ fun f1: (int, int,) -> int -//│ fun f2: (int, int,) -> int -//│ fun f3: (int, int,) -> int +//│ fun f1: (Int, Int,) -> Int +//│ fun f2: (Int, Int,) -> Int +//│ fun f3: (Int, Int,) -> Int -class Pair(lhs: int, rhs: int) -//│ class Pair(lhs: int, rhs: int) +class Pair(lhs: Int, rhs: Int) +//│ class Pair(lhs: Int, rhs: Int) // TODO fun f(Pair(x, y)) = x + y @@ -28,6 +28,6 @@ fun f(Pair(x, y)) = x + y //│ ╔══[ERROR] identifier not found: y //│ ║ l.21: fun f(Pair(x, y)) = x + y //│ ╙── ^ -//│ fun f: error -> int +//│ fun f: error -> Int diff --git a/shared/src/test/diff/nu/FunPoly.mls b/shared/src/test/diff/nu/FunPoly.mls index 630ec7e5bd..9e3f041e80 100644 --- a/shared/src/test/diff/nu/FunPoly.mls +++ b/shared/src/test/diff/nu/FunPoly.mls @@ -11,7 +11,7 @@ fun id(x) = x //│ = [ 1, true ] not(id(true)) -//│ bool +//│ Bool //│ res //│ = false @@ -30,8 +30,8 @@ fun id(x) = x // * later we should try to separate mutually-recursive components and generalize them independently. fun test = [id(1), id(true)] fun id(x) = x -//│ fun test: forall 'a 'b. (1 | true | 'a, 1 | true | 'b,) -//│ fun id: forall 'a 'b. ('b & 'a) -> (1 | true | 'a) +//│ fun test: forall 'a 'b. (1 | true | 'b, 1 | true | 'a,) +//│ fun id: forall 'a 'b. ('a & 'b) -> (1 | true | 'b) [id(1), id(true)] //│ (1 | true, 1 | true,) @@ -43,13 +43,13 @@ not(id(true)) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.42: not(id(true)) //│ ║ ^^^^^^^^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` +//│ ╟── integer literal of type `1` is not an instance of type `Bool` //│ ║ l.31: fun test = [id(1), id(true)] //│ ║ ^ -//│ ╟── but it flows into application with expected type `bool` +//│ ╟── but it flows into application with expected type `Bool` //│ ║ l.42: not(id(true)) //│ ╙── ^^^^^^^^ -//│ bool | error +//│ error | false | true //│ res //│ = false diff --git a/shared/src/test/diff/nu/FunSigs.mls b/shared/src/test/diff/nu/FunSigs.mls index c6ade5fc26..c5026fb409 100644 --- a/shared/src/test/diff/nu/FunSigs.mls +++ b/shared/src/test/diff/nu/FunSigs.mls @@ -1,8 +1,8 @@ :NewDefs -fun log(msg: string): unit -//│ fun log: (msg: string,) -> unit +fun log(msg: Str): unit +//│ fun log: (msg: Str,) -> unit let f = log("ok") @@ -12,11 +12,11 @@ let f = //│ = //│ log is not implemented -fun log: string -> unit -//│ fun log: string -> unit +fun log: Str -> unit +//│ fun log: Str -> unit -fun log: string => unit -//│ fun log: string -> unit +fun log: Str => unit +//│ fun log: Str -> unit log("ok") //│ unit @@ -25,10 +25,10 @@ log("ok") //│ log is not implemented -fun con: string => string => string -//│ fun con: string -> string -> string +fun con: Str => Str => Str +//│ fun con: Str -> Str -> Str fun con = concat -//│ fun con: string -> string -> string +//│ fun con: Str -> Str -> Str diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 8c45f673a7..f57d6f4482 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -1,18 +1,18 @@ :NewDefs trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd -class LitInt(n: int) extends Expr[int] -class LitBool(b: bool) extends Expr[bool] -class Add(x: Expr[int], y: Expr[int]) extends Expr[int] -class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) extends Expr[T] +class LitInt(n: Int) extends Expr[Int] +class LitBool(b: Bool) extends Expr[Bool] +class Add(x: Expr[Int], y: Expr[Int]) extends Expr[Int] +class Cond[T](p: Expr[Bool], t: Expr[T], e: Expr[T]) extends Expr[T] class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr[(S, T)] class Fst[S, T](p: Expr[(S, T)]) extends Expr[S] class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] //│ trait Expr[A]: Add | Cond[?] | Fst[?, ?] | LitBool | LitInt | Pair[?, ?] | Snd[?, ?] -//│ class LitInt(n: int) extends Expr -//│ class LitBool(b: bool) extends Expr -//│ class Add(x: Expr[int], y: Expr[int]) extends Expr -//│ class Cond[T](p: Expr[bool], t: Expr[T], e: Expr[T]) extends Expr +//│ class LitInt(n: Int) extends Expr +//│ class LitBool(b: Bool) extends Expr +//│ class Add(x: Expr[Int], y: Expr[Int]) extends Expr +//│ class Cond[T](p: Expr[Bool], t: Expr[T], e: Expr[T]) extends Expr //│ class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr //│ class Fst[S, T](p: Expr[(S, T,)]) extends Expr //│ class Snd[S, T](p: Expr[(S, T,)]) extends Expr @@ -29,23 +29,23 @@ class Exp[type A] //│ ╙── ^^^^ //│ class Exp -l1: Expr[int] -//│ Expr[int] +l1: Expr[Int] +//│ Expr[Int] //│ res //│ = LitInt {} :e -l1: Expr[bool] +l1: Expr[Bool] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.38: l1: Expr[bool] +//│ ║ l.38: l1: Expr[Bool] //│ ║ ^^ -//│ ╟── type `int` is not an instance of `bool` -//│ ║ l.4: class LitInt(n: int) extends Expr[int] +//│ ╟── type `Int` is not an instance of `Bool` +//│ ║ l.4: class LitInt(n: Int) extends Expr[Int] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.38: l1: Expr[bool] +//│ ║ l.38: l1: Expr[Bool] //│ ╙── ^^^^ -//│ Expr[bool] +//│ Expr[Bool] //│ res //│ = LitInt {} @@ -62,10 +62,10 @@ fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `Cond[?]` does not match type `Add | LitBool | LitInt | ~#Expr` -//│ ║ l.3: trait Expr[A]: LitInt | LitBool | Add | Cond | Pair | Fst | Snd -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt | ~#Expr` +//│ ╟── type `#Expr & (Add & {Expr#A = ?A} | Cond[?] & {Expr#A = ?A} | Fst[?, ?] & {Expr#A = ?A} | LitBool & {Expr#A = ?A} | LitInt & {Expr#A = ?A} | Pair[?, ?] & {Expr#A = ?A} | Snd[?, ?] & {Expr#A = ?A})` does not match type `Add | LitBool | LitInt` +//│ ║ l.53: fun eval[A](e: Expr[A]): A = +//│ ║ ^^^^^^^ +//│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt` //│ ║ l.55: e is LitInt(n) then n //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition: @@ -79,34 +79,14 @@ fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `bool` is not an instance of `int` -//│ ║ l.5: class LitBool(b: bool) extends Expr[bool] +//│ ╟── type `Bool` is not an instance of `Int` +//│ ║ l.5: class LitBool(b: Bool) extends Expr[Bool] //│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `int` +//│ ╟── but it flows into reference with expected type `Int` //│ ║ l.55: e is LitInt(n) then n //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.6: class Add(x: Expr[int], y: Expr[int]) extends Expr[int] +//│ ║ l.6: class Add(x: Expr[Int], y: Expr[Int]) extends Expr[Int] //│ ╙── ^^^ -//│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.53: fun eval[A](e: Expr[A]): A = -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.54: if -//│ ║ ^^^^^^^ -//│ ║ l.55: e is LitInt(n) then n -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.56: e is LitBool(b) then b -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.5: class LitBool(b: bool) extends Expr[bool] -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `int` -//│ ║ l.55: e is LitInt(n) then n -//│ ║ ^ -//│ ╟── Note: constraint arises from application: -//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) -//│ ╙── ^^^^^^^ -//│ fun eval: (e: Expr[out bool | int],) -> (bool | int) +//│ fun eval: (e: Expr[out Int | false | true],) -> (Int | false | true) diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index a9475ca190..f834c1e146 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -1,70 +1,72 @@ :NewDefs -class Room[A](name: string) { +class Room[A](name: Str) { fun foo(x: A) = x } -//│ class Room[A](name: string) { +//│ class Room[A](name: Str) { //│ fun foo: (x: A,) -> A //│ } -class BigRoom extends Room[bool]("big") +class BigRoom extends Room[Bool]("big") //│ class BigRoom extends Room { //│ fun foo: (x: 'A,) -> 'A //│ } //│ where -//│ 'A := bool +//│ 'A := Bool // * Note that this essentially infers Room[Bool] class InferredRoom extends Room("infer") { fun foo(x) = x && true } //│ class InferredRoom extends Room { -//│ fun foo: bool -> bool +//│ fun foo: Bool -> Bool //│ } (new InferredRoom) : Room['X] -//│ Room[bool] +//│ Room['X] +//│ where +//│ 'X := Bool //│ res //│ = InferredRoom {} :e -class TooManyRoom extends Room[int, string]("too many") +class TooManyRoom extends Room[Int, Str]("too many") //│ ╔══[ERROR] class Room expects 1 type parameter(s); got 2 -//│ ║ l.31: class TooManyRoom extends Room[int, string]("too many") -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ║ l.33: class TooManyRoom extends Room[Int, Str]("too many") +//│ ╙── ^^^^^^^^^^^^^ //│ class TooManyRoom extends Room { //│ fun foo: (x: 'A,) -> 'A //│ } //│ where -//│ 'A := int +//│ 'A := Int :e -class WrongRoom extends Room[bool]("wrong") { +class WrongRoom extends Room[Bool]("wrong") { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.43: fun foo(x) = x + 1 +//│ ║ l.45: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.42: class WrongRoom extends Room[bool]("wrong") { +//│ ╟── type `Bool` is not an instance of `Int` +//│ ║ l.44: class WrongRoom extends Room[Bool]("wrong") { //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.43: fun foo(x) = x + 1 +//│ ║ l.45: fun foo(x) = x + 1 //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.43: fun foo(x) = x + 1 +//│ ║ l.45: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── operator application of type `int` is not an instance of type `bool` -//│ ║ l.43: fun foo(x) = x + 1 +//│ ╟── operator application of type `Int` is not an instance of `Bool` +//│ ║ l.45: fun foo(x) = x + 1 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.42: class WrongRoom extends Room[bool]("wrong") { +//│ ║ l.44: class WrongRoom extends Room[Bool]("wrong") { //│ ║ ^^^^ //│ ╟── from reference: //│ ║ l.4: fun foo(x: A) = x //│ ╙── ^ //│ class WrongRoom extends Room { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } @@ -80,19 +82,19 @@ class C1[A] extends C0[A] { val a = a } :pe :e -new C1 : C1[int] +new C1 : C1[Int] //│ ╔══[PARSE ERROR] Unexpected type ascription after `new` keyword -//│ ║ l.83: new C1 : C1[int] +//│ ║ l.85: new C1 : C1[Int] //│ ╙── ^^ //│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.83: new C1 : C1[int] +//│ ║ l.85: new C1 : C1[Int] //│ ╙── ^^^ //│ error //│ res //│ = {} -((new C1) : C1[int]) : C0['X] -//│ C0[int] +((new C1) : C1[Int]) : C0['X] +//│ C0[Int] //│ res //│ = C1 {} @@ -112,10 +114,10 @@ mixin M1[A] { //│ } class A1 extends M1 { - fun f1(x: int) = x + fun f1(x: Int) = x } //│ class A1 { -//│ fun f1: (x: int,) -> int +//│ fun f1: (x: Int,) -> Int //│ fun f2: (x: 'A,) -> ('A, 'A,) //│ } @@ -125,8 +127,8 @@ class A2[S, T] extends M1[(S, T)] //│ fun f2: (x: (S, T,),) -> ((S, T,), (S, T,),) //│ } -class A3(f1: bool => bool) extends M1 -//│ class A3(f1: bool -> bool) { +class A3(f1: Bool => Bool) extends M1 +//│ class A3(f1: Bool -> Bool) { //│ fun f1: (x: 'A,) -> 'A //│ fun f2: (x: 'A,) -> ('A, 'A,) //│ } @@ -139,28 +141,28 @@ mixin M2[A] { //│ fun m: A //│ } -class B1(a: int) extends M2[int] -//│ class B1(a: int) { -//│ fun m: int +class B1(a: Int) extends M2[Int] +//│ class B1(a: Int) { +//│ fun m: Int //│ } -class B2[A](a: int => A) extends M2 -//│ class B2[A](a: int -> A) { -//│ fun m: int -> A +class B2[A](a: Int => A) extends M2 +//│ class B2[A](a: Int -> A) { +//│ fun m: Int -> A //│ } :e -class E1(a: int) extends M2[bool] +class E1(a: Int) extends M2[Bool] //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.153: class E1(a: int) extends M2[bool] +//│ ║ l.155: class E1(a: Int) extends M2[Bool] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int` is not an instance of type `bool` +//│ ╟── expression of type `Int` is not an instance of type `Bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.153: class E1(a: int) extends M2[bool] +//│ ║ l.155: class E1(a: Int) extends M2[Bool] //│ ║ ^^^^ //│ ╟── from field selection: -//│ ║ l.135: fun m: A = this.a +//│ ║ l.137: fun m: A = this.a //│ ╙── ^^^^^^ -//│ class E1(a: int) { -//│ fun m: bool +//│ class E1(a: Int) { +//│ fun m: Bool //│ } diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 2639ef6b7e..084587917c 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -85,7 +85,7 @@ s.map //│ = [Function: map] s.map(succ) -//│ Some[int] +//│ Some[Int] //│ res //│ = Some {} @@ -96,7 +96,7 @@ s.map_A //│ = [Function: map_A] s.map_A(succ) -//│ Some[int] +//│ Some[Int] //│ res //│ = Some {} @@ -123,7 +123,7 @@ None.toArray type Option = Some | None -//│ type Option[A] = Some[A] | None +//│ type Option[A] = None | Some[A] @@ -139,17 +139,17 @@ opt.toArray opt.map(succ) -//│ None | Some[int] +//│ None | Some[Int] //│ res //│ = Some {} opt.map_A(succ) -//│ None | Some[int] +//│ None | Some[Int] //│ res //│ = Some {} opt.map(x => x > 0) -//│ None | Some[bool] +//│ None | Some[Bool] //│ res //│ = Some {} @@ -172,12 +172,12 @@ fun map(x, f) = if x is //│ fun map: forall 'value 'A. (None | Some['value], 'value -> 'A,) -> (None | Some['A]) let mo = map(opt, succ) -//│ let mo: None | Some[int] +//│ let mo: None | Some[Int] //│ mo //│ = Some {} mo.toArray -//│ Array[int] +//│ Array[Int] //│ res //│ = [ 124 ] @@ -193,7 +193,7 @@ class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error -//│ fun foo: int +//│ fun foo: Int //│ } Test(1) @@ -215,14 +215,14 @@ class Test(n: A) { //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.213: fun foo = n + 1 //│ ║ ^^^ -//│ ╟── reference of type `A` is not an instance of type `int` +//│ ╟── reference of type `A` is not an instance of type `Int` //│ ║ l.213: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: //│ ║ l.212: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { -//│ fun foo: error | int +//│ fun foo: Int | error //│ } Test(1) @@ -298,7 +298,7 @@ class TestBad() { //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.296: fun foo2(x: A) = x + 1 //│ ║ ^^^ -//│ ╟── reference of type `A` is not an instance of type `int` +//│ ╟── reference of type `A` is not an instance of type `Int` //│ ║ l.296: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: @@ -306,7 +306,7 @@ class TestBad() { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A,) -> A -//│ fun foo2: (x: A,) -> (error | int) +//│ fun foo2: (x: A,) -> (Int | error) //│ } TestBad().foo1 @@ -351,22 +351,22 @@ t //│ = TestBad {} -fun foo(x: TestBad) = x.foo1 -//│ fun foo: (x: TestBad[int],) -> (x: int,) -> int +fun foo(x: TestBad) = x.foo1 +//│ fun foo: (x: TestBad[Int],) -> (x: Int,) -> Int foo(t) -//│ (x: int,) -> int +//│ (x: Int,) -> Int //│ res //│ = [Function: foo1] foo(t)(1) -//│ int +//│ Int //│ res //│ = 1 TestBad().foo2 -//│ (x: anything,) -> (error | int) +//│ (x: anything,) -> (Int | error) //│ res //│ = [Function: foo2] @@ -386,7 +386,7 @@ w.x //│ = C {} not(w.x.n) -//│ bool +//│ Bool //│ res //│ = true @@ -395,7 +395,7 @@ not(w.x.a) //│ ╔══[ERROR] Type `C['a]` does not contain member `a` //│ ║ l.394: not(w.x.a) //│ ╙── ^^ -//│ bool +//│ Bool //│ res //│ = false diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 441096f83d..b60c4921d8 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -10,9 +10,9 @@ foo1(42) //│ = 42 :e -foo1[int](42) +foo1[Int](42) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.13: foo1[int](42) +//│ ║ l.13: foo1[Int](42) //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -28,9 +28,9 @@ foo2(42) //│ = 42 :e -foo2(42) +foo2(42) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.31: foo2(42) +//│ ║ l.31: foo2(42) //│ ╙── ^^^^^^^^^ //│ error //│ res @@ -46,9 +46,9 @@ foo3(42) //│ = 42 :e -foo3[int](42) +foo3[Int](42) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.49: foo3[int](42) +//│ ║ l.49: foo3[Int](42) //│ ╙── ^^^^^^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index fe2cd5fcfd..f09d90c859 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -56,24 +56,24 @@ C.foo(false) //│ res //│ = false -module C extends Test[int] { +module C extends Test[Int] { fun baz1 = this.foo(0) fun baz2 = this.bar(this.foo) } //│ module C { -//│ fun bar: (int -> int) -> int -> int -//│ fun baz1: int -//│ fun baz2: int -> int -//│ fun foo: int -> int +//│ fun bar: (Int -> Int) -> Int -> Int +//│ fun baz1: Int +//│ fun baz2: Int -> Int +//│ fun foo: Int -> Int //│ } C.baz1 -//│ int +//│ Int //│ res //│ = 0 C.foo(1) -//│ int +//│ Int //│ res //│ = 1 @@ -82,16 +82,16 @@ C.foo(false) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.81: C.foo(false) //│ ║ ^^^^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `int` +//│ ╟── reference of type `false` is not an instance of type `Int` //│ ║ l.81: C.foo(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.59: module C extends Test[int] { +//│ ║ l.59: module C extends Test[Int] { //│ ║ ^^^ //│ ╟── Note: type parameter A is defined at: //│ ║ l.22: mixin Test[A] { //│ ╙── ^ -//│ error | int +//│ Int | error //│ res //│ = false @@ -122,17 +122,17 @@ mixin Test[A] { //│ fun foo: A -> A //│ } -class C(arg: int) extends Test -//│ class C(arg: int) { -//│ fun bar: ('A | int, 'A | int,) -//│ fun baz: int -//│ fun foo: 'A -> ('A | int) +class C(arg: Int) extends Test +//│ class C(arg: Int) { +//│ fun bar: ('A | Int, 'A | Int,) +//│ fun baz: Int +//│ fun foo: 'A -> ('A | Int) //│ } let c = C(1) [c.foo(false), c.bar] //│ let c: C -//│ (false | int, (int, int,),) +//│ (Int | false, (Int, Int,),) //│ c //│ = C {} //│ res @@ -146,13 +146,13 @@ module D extends C(0) { //│ ║ l.143: this.foo(false) //│ ╙── ^^^^ //│ module D extends C { -//│ fun bar: forall 'A. ('A | int, 'A | int,) -//│ fun baz: int -//│ fun foo: forall 'A. 'A -> ('A | int) +//│ fun bar: forall 'A. ('A | Int, 'A | Int,) +//│ fun baz: Int +//│ fun foo: forall 'A. 'A -> ('A | Int) //│ } :e // TODO support or produce better error (arg is not actually recursive) -class C extends Test { // it also fails with Test[int]... +class C extends Test { // it also fails with Test[Int]... fun arg = 123 } //│ ╔══[ERROR] Type `#C & {bar: (?A, ?A,), baz: ?a, foo: ?A -> ?A}` does not contain member `arg` @@ -174,14 +174,14 @@ class C extends Test { // it also fails with Test[int]... //│ } class C extends Test { - fun arg: int + fun arg: Int fun arg = 123 } //│ class C { -//│ fun arg: int -//│ fun bar: ('A | int, 'A | int,) -//│ fun baz: int -//│ fun foo: 'A -> ('A | int) +//│ fun arg: Int +//│ fun bar: ('A | Int, 'A | Int,) +//│ fun baz: Int +//│ fun foo: 'A -> ('A | Int) //│ } diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 3c7518fa48..3806d2916b 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -88,25 +88,25 @@ Test.foo(error) + 1 //│ ╟── type variable `A` leaks out of its scope //│ ║ l.84: Test.foo(error) + 1 //│ ║ ^^^^^^^^^^^^^^^ -//│ ╙── into type `int` -//│ error | int +//│ ╙── into expression of type `Int` +//│ Int | error //│ res //│ Runtime error: //│ Error: unexpected runtime error :e -Test .foo +Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.98: Test .foo +//│ ║ l.98: Test .foo //│ ╙── ^^^^^^^^^ //│ error //│ res //│ = undefined :e -(Test).foo +(Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.107: (Test).foo +//│ ║ l.107: (Test).foo //│ ╙── ^^^^^^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/Huawei1.mls b/shared/src/test/diff/nu/Huawei1.mls index fad5cc1830..dfd8163338 100644 --- a/shared/src/test/diff/nu/Huawei1.mls +++ b/shared/src/test/diff/nu/Huawei1.mls @@ -30,10 +30,10 @@ fun bar(c) = if c is C(y) then y + 1 B then 0 else 1 -//│ fun bar: (C[int] | ~C[anything]) -> int +//│ fun bar: (C[Int] | Object & ~#C) -> Int bar(c) -//│ int +//│ Int //│ res //│ = 124 @@ -42,7 +42,7 @@ bar(C(true)) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.41: bar(C(true)) //│ ║ ^^^^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` +//│ ╟── reference of type `true` is not an instance of type `Int` //│ ║ l.41: bar(C(true)) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: @@ -54,7 +54,7 @@ bar(C(true)) //│ ╟── Note: type parameter A is defined at: //│ ║ l.4: class C[A](x: A) { //│ ╙── ^ -//│ error | int +//│ Int | error //│ res //│ = 2 diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 0a340d9246..60353a5eb7 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -173,24 +173,24 @@ module M extends C { //│ ╔══[ERROR] Type mismatch in definition of method id1: //│ ║ l.171: fun id1 = succ //│ ║ ^^^^^^^^^^ -//│ ╟── application of type `?a` does not match type `int | ~(?b & ?c)` +//│ ╟── application of type `?a` does not match type `Int | ~(?b & ?c)` //│ ║ l.108: fun f = (id1(true), id1(0)) //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method id1: //│ ║ l.171: fun id1 = succ //│ ║ ^^^^^^^^^^ -//│ ╟── type `int` does not match type `0 | true | ?a` +//│ ╟── expression of type `Int` does not match type `0 | true | ?a` //│ ╟── Note: constraint arises from reference: //│ ║ l.107: fun id1(x) = x //│ ╙── ^ //│ module M extends C { //│ fun f: (0 | true, 0 | true,) -//│ fun id1: int -> int +//│ fun id1: Int -> Int //│ fun id2: forall 'a. 'a -> 'a //│ } M.id1 -//│ int -> int +//│ Int -> Int //│ res //│ = [Function: succ] diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 5774dd2fce..a72f6288b9 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -10,9 +10,9 @@ mixin Test[A] { //│ fun bar: (A, A,) //│ } -class A(a: int) extends Test -//│ class A(a: int) { -//│ fun bar: (int, int,) +class A(a: Int) extends Test +//│ class A(a: Int) { +//│ fun bar: (Int, Int,) //│ } mixin Test2[S, T] { @@ -27,52 +27,52 @@ mixin Test2[S, T] { //│ fun x: (S, T,) //│ } -class A1[B](s: bool, t: B) extends Test2[bool, B] -//│ class A1[B](s: bool, t: B) { -//│ fun fb: bool -> (bool, bool,) -//│ fun x: (bool, B,) +class A1[B](s: Bool, t: B) extends Test2[Bool, B] +//│ class A1[B](s: Bool, t: B) { +//│ fun fb: (Bool & 'S) -> ('S | false | true, 'S | false | true,) +//│ fun x: ('S | false | true, B,) //│ } // TODO: Investigate type of fb -class A2[A](s: A, t: int) extends Test2 -//│ class A2[A](s: A, t: int) { +class A2[A](s: A, t: Int) extends Test2 +//│ class A2[A](s: A, t: Int) { //│ fun fb: 'S -> (A | 'S, A | 'S,) -//│ fun x: (A | 'S, int,) +//│ fun x: (A | 'S, Int,) //│ } // TODO: Investigate type of fb -class A3(s: int, t: bool) extends Test2 -//│ class A3(s: int, t: bool) { -//│ fun fb: 'S -> ('S | int, 'S | int,) -//│ fun x: ('S | int, bool,) +class A3(s: Int, t: Bool) extends Test2 +//│ class A3(s: Int, t: Bool) { +//│ fun fb: 'S -> (Int | 'S, Int | 'S,) +//│ fun x: (Int | 'S, Bool,) //│ } -class P(p: int) { +class P(p: Int) { fun foo(x) = x + p } -//│ class P(p: int) { -//│ fun foo: int -> int +//│ class P(p: Int) { +//│ fun foo: Int -> Int //│ } :e // FIXME -class C1(a: int) extends P(a) { fun bar = this.foo(0) } +class C1(a: Int) extends P(a) { fun bar = this.foo(0) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.58: class C1(a: int) extends P(a) { fun bar = this.foo(0) } +//│ ║ l.58: class C1(a: Int) extends P(a) { fun bar = this.foo(0) } //│ ╙── ^^^^ -//│ class C1(a: int) extends P { +//│ class C1(a: Int) extends P { //│ fun bar: error -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } :e // FIXME -class C2(a: int, b: int) extends P(a + b) { +class C2(a: Int, b: Int) extends P(a + b) { fun foo(x) = x * this.p + a * b } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.69: fun foo(x) = x * this.p + a * b //│ ╙── ^^ -//│ class C2(a: int, b: int) extends P { -//│ fun foo: int -> int +//│ class C2(a: Int, b: Int) extends P { +//│ fun foo: Int -> Int //│ } let c2 = C2(1, 2) @@ -81,12 +81,12 @@ let c2 = C2(1, 2) //│ = C2 {} c2.foo(2) -//│ int +//│ Int //│ res //│ = 8 c2.p -//│ int +//│ Int //│ res //│ = 3 @@ -94,8 +94,8 @@ c2.p class Test[A](x: A) //│ class Test[A](x: A) -class A(a: int) extends Test(a) -//│ class A(a: int) extends Test +class A(a: Int) extends Test(a) +//│ class A(a: Int) extends Test let a1 = A(1) //│ let a1: A @@ -105,12 +105,12 @@ let a1 = A(1) a1: Test['x] //│ Test['x] //│ where -//│ 'x :> int +//│ 'x :> Int //│ res //│ = A {} a1.x -//│ int +//│ Int //│ res //│ = 1 @@ -147,16 +147,16 @@ B.foo(1) module B extends Foo { fun foo(x) = x + 1 } //│ module B extends Foo { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } B : Foo['X] -//│ Foo[int] +//│ Foo[Int] //│ res //│ = B { class: [class B extends Object] } B.foo -//│ int -> int +//│ Int -> Int //│ res //│ = [Function: foo] @@ -236,7 +236,7 @@ class B extends Foo { fun foo(x) = x + 1 } //│ ╟── type variable `A` leaks out of its scope //│ ║ l.207: trait Foo[A] { fun foo[A](x: A): A } //│ ║ ^ -//│ ╟── into reference of type `int` +//│ ╟── into reference of type `Int` //│ ║ l.232: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^ //│ ╔══[ERROR] Type error in definition of method foo @@ -250,6 +250,6 @@ class B extends Foo { fun foo(x) = x + 1 } //│ ║ l.232: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^^^^^ //│ class B extends Foo { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } diff --git a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls index 9933ce198c..1dcc932356 100644 --- a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls +++ b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls @@ -29,11 +29,11 @@ mixin Foo { fun f = this.x } //│ } module Bar { - class C(x: int) extends Foo + class C(x: Int) extends Foo } //│ module Bar { -//│ class C(x: int) { -//│ fun f: int +//│ class C(x: Int) { +//│ fun f: Int //│ } //│ } diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index 7ddeb26405..242e26917a 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -2,77 +2,69 @@ :NoJS trait Into[T] { - fun into: T + fun Into: T } //│ trait Into[T] { -//│ fun into: T +//│ fun Into: T //│ } -trait Nat extends Into[int] +trait Nat extends Into[Int] //│ trait Nat extends Into { -//│ fun into: 'T +//│ fun Into: 'T //│ } //│ where -//│ 'T := int +//│ 'T := Int trait Product[A, B] extends Into[A] { let pair: (A, B) } //│ trait Product[A, B] extends Into { -//│ fun into: 'T +//│ fun Into: 'T //│ let pair: (A, B,) //│ } //│ where //│ 'T := A -class TwoInts(pair: (int, int)) extends Product[int, int] { - fun into = pair._1 + pair._2 +class TwoInts(pair: (Int, Int)) extends Product[Int, Int] { + fun Into = pair._1 + pair._2 } -//│ class TwoInts(pair: (int, int,)) extends Into, Product { -//│ fun into: int +//│ class TwoInts(pair: (Int, Int,)) extends Into, Product { +//│ fun Into: Int //│ } let i2 = TwoInts((1,2)) //│ let i2: TwoInts -i2: Product[int, int] -//│ Product[int, int] +i2: Product[Int, Int] +//│ Product[Int, Int] -i2: Into[int] -//│ Into[int] +i2: Into[Int] +//│ Into[Int] i2.pair -//│ (int, int,) +//│ (Int, Int,) -i2.into -//│ int +i2.Into +//│ Int -let p1: Product[int, int] -//│ let p1: Product[int, int] +let p1: Product[Int, Int] +//│ let p1: Product[Int, Int] :e -p1: Product[bool, int] +p1: Product[Bool, Int] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.54: p1: Product[bool, int] +//│ ║ l.54: p1: Product[Bool, Int] //│ ║ ^^ -//│ ╟── expression of type `int & ?A` is not an instance of type `bool` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.54: p1: Product[bool, int] -//│ ╙── ^^^^ -//│ Product[bool, int] +//│ ╙── expression of type `Int & ?A` is not an instance of type `Bool` +//│ Product[Bool, Int] -p1: Into[int] -//│ Into[int] +p1: Into[Int] +//│ Into[Int] :e -p1: Into[bool] +p1: Into[Bool] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.68: p1: Into[bool] +//│ ║ l.65: p1: Into[Bool] //│ ║ ^^ -//│ ╟── type `int` is not an instance of type `bool` -//│ ║ l.50: let p1: Product[int, int] -//│ ║ ^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.68: p1: Into[bool] -//│ ╙── ^^^^ -//│ Into[bool] +//│ ╙── expression of type `Int` is not an instance of type `Bool` +//│ Into[Bool] diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 97393c6150..de1ada7f01 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -1,11 +1,11 @@ :NewDefs -:NoJS + trait Showable { - fun toString: string + fun toString: Str } //│ trait Showable { -//│ fun toString: string +//│ fun toString: Str //│ } :e @@ -15,17 +15,17 @@ trait What0 extends woooo //│ ╙── ^^^^^ //│ trait What0 -class Point(x: int, y: int) extends Showable { +class PoInt(x: Int, y: Int) extends Showable { fun mlen = x + y - fun toString = "I'm a point" + fun toString = "I'm a poInt" } -//│ class Point(x: int, y: int) extends Showable { -//│ fun mlen: int -//│ fun toString: "I'm a point" +//│ class PoInt(x: Int, y: Int) extends Showable { +//│ fun mlen: Int +//│ fun toString: "I'm a poInt" //│ } -class What1(toString: string) extends Showable -//│ class What1(toString: string) extends Showable +class What1(toString: Str) extends Showable +//│ class What1(toString: Str) extends Showable :e trait NoShow extends What1("hi") @@ -39,71 +39,71 @@ class ErrC1 extends Showable class ErrC2 extends Showable { fun toString = 114 } -class ErrC3(toString: string -> string) extends Showable +class ErrC3(toString: Str -> Str) extends Showable //│ ╔══[ERROR] Member `toString` is declared in parent but not implemented in `ErrC1` //│ ║ l.38: class ErrC1 extends Showable //│ ║ ^^^^^ //│ ╟── Declared here: -//│ ║ l.5: fun toString: string -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ║ l.5: fun toString: Str +//│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method toString: //│ ║ l.40: fun toString = 114 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `114` is not an instance of type `string` +//│ ╟── integer literal of type `114` is not an instance of type `Str` //│ ║ l.40: fun toString = 114 //│ ║ ^^^ -//│ ╟── but it flows into definition of method toString with expected type `string` +//│ ╟── but it flows into definition of method toString with expected type `Str` //│ ║ l.40: fun toString = 114 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: fun toString: string -//│ ║ ^^^^^^ +//│ ║ l.5: fun toString: Str +//│ ║ ^^^ //│ ╟── from signature of member `toString`: -//│ ║ l.5: fun toString: string -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ║ l.5: fun toString: Str +//│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in function type: -//│ ║ l.42: class ErrC3(toString: string -> string) extends Showable -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ╟── type `string -> string` is not an instance of type `string` +//│ ║ l.42: class ErrC3(toString: Str -> Str) extends Showable +//│ ║ ^^^^^^^^^^ +//│ ╟── type `Str -> Str` is not an instance of type `Str` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: fun toString: string -//│ ║ ^^^^^^ +//│ ║ l.5: fun toString: Str +//│ ║ ^^^ //│ ╟── from signature of member `toString`: -//│ ║ l.5: fun toString: string -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ║ l.5: fun toString: Str +//│ ╙── ^^^^^^^^^^^^^ //│ class ErrC1 extends Showable { -//│ fun toString: string +//│ fun toString: Str //│ } //│ class ErrC2 extends Showable { //│ fun toString: 114 //│ } -//│ class ErrC3(toString: string -> string) extends Showable +//│ class ErrC3(toString: Str -> Str) extends Showable trait Stadt { - let name: string + let name: Str } //│ trait Stadt { -//│ let name: string +//│ let name: Str //│ } trait RefinedStadt extends Stadt { - let size: int - fun foo: bool -> int + let size: Int + fun foo: Bool -> Int } //│ trait RefinedStadt extends Stadt { -//│ fun foo: bool -> int -//│ let name: string -//│ let size: int +//│ fun foo: Bool -> Int +//│ let name: Str +//│ let size: Int //│ } trait SizedStadt extends RefinedStadt { let size: 1 | 2 | 3 - fun bar: int -> int + fun bar: Int -> Int } //│ trait SizedStadt extends RefinedStadt, Stadt { -//│ fun bar: int -> int -//│ fun foo: bool -> int -//│ let name: string +//│ fun bar: Int -> Int +//│ fun foo: Bool -> Int +//│ let name: Str //│ let size: 1 | 2 | 3 //│ } @@ -114,12 +114,12 @@ class Goodstatt(size: 1 | 2) extends RefinedStadt { } //│ class Goodstatt(size: 1 | 2) extends RefinedStadt, Stadt { //│ fun bar: 'a -> 'a -//│ fun foo: bool -> (0 | 1 | 2) +//│ fun foo: Bool -> (0 | 1 | 2) //│ let name: "good" //│ } :e -class Errcity(size: int) extends SizedStadt { +class Errcity(size: Int) extends SizedStadt { fun bar = "hahaha" } //│ ╔══[ERROR] Type mismatch in definition of method bar: @@ -128,19 +128,19 @@ class Errcity(size: int) extends SizedStadt { //│ ╟── string literal of type `"hahaha"` is not a function //│ ║ l.123: fun bar = "hahaha" //│ ║ ^^^^^^^^ -//│ ╟── but it flows into definition of method bar with expected type `int -> int` +//│ ╟── but it flows into definition of method bar with expected type `Int -> Int` //│ ║ l.123: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.101: fun bar: int -> int +//│ ║ l.101: fun bar: Int -> Int //│ ║ ^^^^^^^^^^ //│ ╟── from signature of member `bar`: -//│ ║ l.101: fun bar: int -> int +//│ ║ l.101: fun bar: Int -> Int //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.122: class Errcity(size: int) extends SizedStadt { +//│ ║ l.122: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^ -//│ ╟── type `int` does not match type `1 | 2 | 3` +//│ ╟── type `Int` does not match type `1 | 2 | 3` //│ ╟── Note: constraint arises from union type: //│ ║ l.100: let size: 1 | 2 | 3 //│ ║ ^^^^^^^^^ @@ -148,21 +148,21 @@ class Errcity(size: int) extends SizedStadt { //│ ║ l.100: let size: 1 | 2 | 3 //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `name` is declared in parent but not implemented in `Errcity` -//│ ║ l.122: class Errcity(size: int) extends SizedStadt { +//│ ║ l.122: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.83: let name: string -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.83: let name: Str +//│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Errcity` -//│ ║ l.122: class Errcity(size: int) extends SizedStadt { +//│ ║ l.122: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.91: fun foo: bool -> int +//│ ║ l.91: fun foo: Bool -> Int //│ ╙── ^^^^^^^^^^^^^^^^ -//│ class Errcity(size: int) extends RefinedStadt, SizedStadt, Stadt { +//│ class Errcity(size: Int) extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: "hahaha" -//│ fun foo: bool -> int -//│ let name: string +//│ fun foo: Bool -> Int +//│ let name: Str //│ } module Omg extends Stadt { @@ -170,7 +170,7 @@ module Omg extends Stadt { fun cool(x) = x + x } //│ module Omg extends Stadt { -//│ fun cool: int -> int +//│ fun cool: Int -> Int //│ fun name: "omg!!!" //│ } @@ -181,7 +181,7 @@ mixin More { } //│ mixin More() { //│ fun bar: 'a -> 'a -//│ fun more: number -> bool +//│ fun more: Num -> Bool //│ fun size: 1 //│ } @@ -196,7 +196,7 @@ class Grassberg(name: "grass" | "GRASS") extends More, SizedStadt, Fooo //│ class Grassberg(name: "GRASS" | "grass") extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 -//│ fun more: number -> bool +//│ fun more: Num -> Bool //│ fun size: 1 //│ } @@ -223,22 +223,22 @@ class Dirtberg extends More, SizedStadt, Fooo { //│ class Dirtberg extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 -//│ fun more: number -> bool +//│ fun more: Num -> Bool //│ let name: "dirt" //│ fun size: 4 //│ } -class Iceburg(name: string) extends RefinedStadt, More, Fooo -//│ class Iceburg(name: string) extends RefinedStadt, Stadt { +class Iceburg(name: Str) extends RefinedStadt, More, Fooo +//│ class Iceburg(name: Str) extends RefinedStadt, Stadt { //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 -//│ fun more: number -> bool +//│ fun more: Num -> Bool //│ fun size: 1 //│ } -class A { fun x: int = 1 } +class A { fun x: Int = 1 } //│ class A { -//│ fun x: int +//│ fun x: Int //│ } :e @@ -246,17 +246,17 @@ class B extends A { fun x = "A" } //│ ╔══[ERROR] Type mismatch in definition of method x: //│ ║ l.245: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ -//│ ╟── string literal of type `"A"` is not an instance of type `int` +//│ ╟── string literal of type `"A"` is not an instance of type `Int` //│ ║ l.245: class B extends A { fun x = "A" } //│ ║ ^^^ -//│ ╟── but it flows into definition of method x with expected type `int` +//│ ╟── but it flows into definition of method x with expected type `Int` //│ ║ l.245: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.239: class A { fun x: int = 1 } +//│ ║ l.239: class A { fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.239: class A { fun x: int = 1 } +//│ ║ l.239: class A { fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class B extends A { //│ fun x: "A" @@ -267,14 +267,14 @@ class C1[A] { fun a: A = a } //│ fun a: A //│ } -class C2 extends C1[int] { fun a = 1 } +class C2 extends C1[Int] { fun a = 1 } //│ class C2 extends C1 { //│ fun a: 1 //│ } // trait MyTrait[A] { type MyTrait#A = A; fun a: A = a } // freshen/subst -// trait MyTrait[int] { type MyTrait#A = int; fun a: int = a } +// trait MyTrait[Int] { type MyTrait#A = Int; fun a: Int = a } trait MyTrait[A] { fun a: A } //│ trait MyTrait[A] { @@ -284,24 +284,24 @@ trait MyTrait[A] { fun a: A } // :ns // :d // :ds -class C extends MyTrait[int] { fun a = 1 } +class C extends MyTrait[Int] { fun a = 1 } //│ class C extends MyTrait { //│ fun a: 1 //│ } :e -class C extends MyTrait[int] { fun a = false } +class C extends MyTrait[Int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.293: class C extends MyTrait[int] { fun a = false } +//│ ║ l.293: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.293: class C extends MyTrait[int] { fun a = false } +//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ║ l.293: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^ -//│ ╟── but it flows into definition of method a with expected type `int` -//│ ║ l.293: class C extends MyTrait[int] { fun a = false } +//│ ╟── but it flows into definition of method a with expected type `Int` +//│ ║ l.293: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.293: class C extends MyTrait[int] { fun a = false } +//│ ║ l.293: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^ //│ ╟── from signature of member `a`: //│ ║ l.279: trait MyTrait[A] { fun a: A } @@ -313,18 +313,18 @@ class C extends MyTrait[int] { fun a = false } trait T1 { let foo : 1 | 2 | 3 - fun bar : string | bool + fun bar : Str | Bool } trait T2 { let foo : 2 | 3 | 4 - let bar : int | bool + let bar : Int | Bool } //│ trait T1 { -//│ fun bar: bool | string +//│ fun bar: Str | false | true //│ let foo: 1 | 2 | 3 //│ } //│ trait T2 { -//│ let bar: bool | int +//│ let bar: Int | false | true //│ let foo: 2 | 3 | 4 //│ } @@ -332,7 +332,7 @@ trait T4 extends T1, T2 { fun foo: 2 } //│ trait T4 extends T1, T2 { -//│ fun bar: bool +//│ fun bar: Bool //│ fun foo: 2 //│ } @@ -365,11 +365,11 @@ class C3 extends T4{ //│ } :e -class C2(foo: int, bar: string) extends T4 +class C2(foo: Int, bar: Str) extends T4 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.368: class C2(foo: int, bar: string) extends T4 +//│ ║ l.368: class C2(foo: Int, bar: Str) extends T4 //│ ║ ^^^ -//│ ╟── type `int` does not match type `2` +//│ ╟── type `Int` does not match type `2` //│ ╟── Note: constraint arises from literal type: //│ ║ l.332: fun foo: 2 //│ ║ ^ @@ -377,16 +377,16 @@ class C2(foo: int, bar: string) extends T4 //│ ║ l.332: fun foo: 2 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.368: class C2(foo: int, bar: string) extends T4 -//│ ║ ^^^^^^ -//│ ╟── type `string` does not match type `bool | int` +//│ ║ l.368: class C2(foo: Int, bar: Str) extends T4 +//│ ║ ^^^ +//│ ╟── type `Str` does not match type `Bool | Int` //│ ╟── Note: constraint arises from union type: -//│ ║ l.320: let bar : int | bool +//│ ║ l.320: let bar : Int | Bool //│ ║ ^^^^^^^^^^ //│ ╟── from signature of member `bar`: -//│ ║ l.320: let bar : int | bool +//│ ║ l.320: let bar : Int | Bool //│ ╙── ^^^^^^^^^^^^^^^^ -//│ class C2(foo: int, bar: string) extends T1, T2, T4 +//│ class C2(foo: Int, bar: Str) extends T1, T2, T4 :e trait T5 extends T4 { @@ -408,7 +408,7 @@ trait T5 extends T4 { //│ ║ l.332: fun foo: 2 //│ ╙── ^^^^^^ //│ trait T5 extends T1, T2, T4 { -//│ fun bar: bool +//│ fun bar: Bool //│ let foo: 4 //│ } @@ -447,6 +447,6 @@ trait T3 extends T1, T2 { //│ ║ l.319: let foo : 2 | 3 | 4 //│ ╙── ^^^^^^^^^^^^^^^ //│ trait T3 extends T1, T2 { -//│ fun bar: bool +//│ fun bar: Bool //│ let foo: true //│ } diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 1507888e51..b703190b78 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -2,16 +2,16 @@ trait Test { - fun foo: int - fun bar: bool -> bool + fun foo: Int + fun bar: Bool -> Bool } //│ trait Test { -//│ fun bar: bool -> bool -//│ fun foo: int +//│ fun bar: Bool -> Bool +//│ fun foo: Int //│ } fun ts(x: Test) = x.foo -//│ fun ts: (x: Test,) -> int +//│ fun ts: (x: Test,) -> Int module M extends Test { @@ -19,7 +19,7 @@ module M extends Test { fun bar = not } //│ module M extends Test { -//│ fun bar: bool -> bool +//│ fun bar: Bool -> Bool //│ fun foo: 0 //│ } @@ -29,19 +29,19 @@ M: Test //│ = M { class: [class M extends Object] } ts(M) -//│ int +//│ Int //│ res //│ = 0 trait Oth extends Test { - let a : int - fun cool : int -> bool + let a : Int + fun cool : Int -> Bool } //│ trait Oth extends Test { -//│ let a: int -//│ fun bar: bool -> bool -//│ fun cool: int -> bool -//│ fun foo: int +//│ let a: Int +//│ fun bar: Bool -> Bool +//│ fun cool: Int -> Bool +//│ fun foo: Int //│ } let oth1: Oth @@ -50,7 +50,7 @@ let oth1: Oth //│ = oth1.bar(true) -//│ bool +//│ Bool //│ res //│ = //│ oth1 is not implemented @@ -92,28 +92,28 @@ oth1: M trait Geo { let v: 2 | 3 - fun get: int | bool - fun ter: int + fun get: Int | Bool + fun ter: Int } trait Anemo { let v: 1 | 2 - fun get: bool | string - fun ter: bool + fun get: Bool | string + fun ter: Bool } //│ trait Geo { -//│ fun get: bool | int -//│ fun ter: int +//│ fun get: Int | false | true +//│ fun ter: Int //│ let v: 2 | 3 //│ } //│ trait Anemo { -//│ fun get: bool | string -//│ fun ter: bool +//│ fun get: false | string | true +//│ fun ter: Bool //│ let v: 1 | 2 //│ } trait Mixed extends Geo, Anemo //│ trait Mixed extends Anemo, Geo { -//│ fun get: bool +//│ fun get: Bool //│ fun ter: nothing //│ let v: 2 //│ } @@ -124,7 +124,7 @@ class C() extends Test { fun bar(x) = x } //│ class C() extends Test { -//│ fun bar: bool -> bool +//│ fun bar: Bool -> Bool //│ fun foo: 1 //│ } @@ -136,7 +136,7 @@ mixin M { //│ } class F() extends Oth, M, Mixed { - fun cool(x) = x == 1 + fun cool(x) = x === 1 fun foo = 2 fun bar(x) = x fun get = true @@ -146,8 +146,8 @@ class F() extends Oth, M, Mixed { } //│ class F() extends Anemo, Geo, Mixed, Oth, Test { //│ let a: 3 -//│ fun bar: bool -> bool -//│ fun cool: number -> bool +//│ fun bar: Bool -> Bool +//│ fun cool: Eql[1] -> Bool //│ fun foo: 2 //│ fun get: true //│ fun m1: 3 @@ -226,7 +226,7 @@ c.foo //│ = 1 c.bar(true) -//│ bool +//│ Bool //│ res //│ = true @@ -298,13 +298,13 @@ fts(c) //│ = [Function: fts] fts(oth1) -//│ int +//│ Int //│ res //│ = //│ oth1 is not implemented fts(c1) -//│ int +//│ Int //│ res //│ = 1 @@ -362,10 +362,10 @@ class E1 extends Test { //│ ║ l.358: class E1 extends Test { //│ ║ ^^ //│ ╟── Declared here: -//│ ║ l.6: fun bar: bool -> bool +//│ ║ l.6: fun bar: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class E1 extends Test { -//│ fun bar: bool -> bool +//│ fun bar: Bool -> Bool //│ fun foo: 2 //│ } @@ -380,8 +380,8 @@ trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1 extends C, Test //│ trait TE2 extends Test { -//│ fun bar: bool -> bool -//│ fun foo: int +//│ fun bar: Bool -> Bool +//│ fun foo: Int //│ } :e @@ -392,46 +392,46 @@ class E2 extends Test { //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.389: fun foo = true //│ ║ ^^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` +//│ ╟── reference of type `true` is not an instance of type `Int` //│ ║ l.389: fun foo = true //│ ║ ^^^^ -//│ ╟── but it flows into definition of method foo with expected type `int` +//│ ╟── but it flows into definition of method foo with expected type `Int` //│ ║ l.389: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: fun foo: int +//│ ║ l.5: fun foo: Int //│ ║ ^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.5: fun foo: int +//│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ class E2 extends Test { -//│ fun bar: bool -> bool +//│ fun bar: Bool -> Bool //│ fun foo: true //│ } :e -class D extends Test[int], Test[bool] +class D extends Test[Int], Test[Bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.413: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[Int], Test[Bool] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.413: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[Int], Test[Bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `D` -//│ ║ l.413: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[Int], Test[Bool] //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.5: fun foo: int +//│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `D` -//│ ║ l.413: class D extends Test[int], Test[bool] +//│ ║ l.413: class D extends Test[Int], Test[Bool] //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.6: fun bar: bool -> bool +//│ ║ l.6: fun bar: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class D extends Test { -//│ fun bar: bool -> bool -//│ fun foo: int +//│ fun bar: Bool -> Bool +//│ fun foo: Int //│ } @@ -647,11 +647,11 @@ e: ZL & WP //│ = //│ g is not implemented -class Bs(a: bool) { +class Bs(a: Bool) { fun foo(x) = x + 1 } -//│ class Bs(a: bool) { -//│ fun foo: int -> int +//│ class Bs(a: Bool) { +//│ fun foo: Int -> Int //│ } class Ih() extends Bs(false) { @@ -691,14 +691,23 @@ class Eh2 extends Bs(true), Ele { //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.688: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ??_` is not an instance of type `bool` +//│ ╟── expression of type `Int & ??_` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: //│ ║ l.688: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.688: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ??_` +//│ ╟── operator application of type `Bool` does not match type `Int | ??_` +//│ ║ l.688: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from operator application: +//│ ║ l.651: fun foo(x) = x + 1 +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.688: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── operator application of type `Bool` does not match type `Int | ??_` //│ ║ l.688: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: @@ -706,7 +715,7 @@ class Eh2 extends Bs(true), Ele { //│ ╙── ^^^^^ //│ class Eh2 extends Bs, Ele { //│ fun ce: (Test & 'a) -> (Oth | 'a) -//│ fun foo: bool -> bool +//│ fun foo: Bool -> Bool //│ } :e @@ -714,63 +723,63 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.713: class Eh extends Bs(1) +//│ ║ l.722: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.713: class Eh extends Bs(1) +//│ ╟── integer literal of type `1` is not an instance of type `Bool` +//│ ║ l.722: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.650: class Bs(a: bool) { +//│ ║ l.650: class Bs(a: Bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.714: class Eh1 extends Bs +//│ ║ l.723: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.651: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `int` +//│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `Int` //│ ║ l.651: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ -//│ ╟── but it flows into definition of method foo with expected type `int` +//│ ╟── but it flows into definition of method foo with expected type `Int` //│ ║ l.651: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.5: fun foo: int +//│ ║ l.5: fun foo: Int //│ ║ ^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.5: fun foo: int +//│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Eh3` -//│ ║ l.715: class Eh3 extends Bs(false), Test +//│ ║ l.724: class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: -//│ ║ l.6: fun bar: bool -> bool +//│ ║ l.6: fun bar: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class Eh extends Bs { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } //│ class Eh1 extends Bs { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } //│ class Eh3 extends Bs, Test { -//│ fun bar: bool -> bool -//│ fun foo: int -> int +//│ fun bar: Bool -> Bool +//│ fun foo: Int -> Int //│ } -class Ca(a: int) extends Oth { +class Ca(a: Int) extends Oth { fun foo = 1 fun cool(x) = false fun bar(x) = x } -//│ class Ca(a: int) extends Oth, Test { -//│ fun bar: bool -> bool +//│ class Ca(a: Int) extends Oth, Test { +//│ fun bar: Bool -> Bool //│ fun cool: anything -> false //│ fun foo: 1 //│ } -class Cx(a: 1 | 2, b: bool) extends Ca(a) -//│ class Cx(a: 1 | 2, b: bool) extends Ca, Oth, Test { -//│ fun bar: bool -> bool +class Cx(a: 1 | 2, b: Bool) extends Ca(a) +//│ class Cx(a: 1 | 2, b: Bool) extends Ca, Oth, Test { +//│ fun bar: Bool -> Bool //│ fun cool: anything -> false //│ fun foo: 1 //│ } @@ -781,7 +790,7 @@ let cx1 = Cx(2, true) //│ = Cx {} cx1.bar(cx1.b) -//│ bool +//│ Bool //│ res //│ = true @@ -795,27 +804,27 @@ cx1: Ca //│ res //│ = Cx {} -class Bc1(foo: int) -class Bc2(bar: bool) +class Bc1(foo: Int) +class Bc2(bar: Bool) class Bc3 { - let baz : int + let baz : Int } -//│ class Bc1(foo: int) -//│ class Bc2(bar: bool) +//│ class Bc1(foo: Int) +//│ class Bc2(bar: Bool) //│ class Bc3 { -//│ let baz: int +//│ let baz: Int //│ } :e class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.810: class Bc12() extends Bc1(1), Bc2(true) +//│ ║ l.819: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: //│ unexpected parent symbol new class Bc2. -class Bc02() extends Bc1(1:int) { +class Bc02() extends Bc1(1:Int) { let foo = 2 } //│ class Bc02() extends Bc1 { @@ -828,29 +837,29 @@ Bc02().foo //│ = 2 :e -class Bc31(baz: bool) extends Bc3 +class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.831: class Bc31(baz: bool) extends Bc3 +//│ ║ l.840: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ -//│ ╟── type `bool` is not an instance of `int` +//│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.801: let baz : int +//│ ║ l.810: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.801: let baz : int +//│ ║ l.810: let baz : Int //│ ╙── ^^^^^^^^^ -//│ class Bc31(baz: bool) extends Bc3 +//│ class Bc31(baz: Bool) extends Bc3 :e class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.846: let foo = true +//│ ║ l.855: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.845: class Bc11 extends Bc1(1) { +//│ ║ l.854: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ class Bc11 extends Bc1 { //│ let foo: true @@ -862,9 +871,9 @@ trait Base[A] { fun f: A -> A } //│ fun f: A -> A //│ } -class Der1 extends Base[int] { fun f(x) = x + 1 } +class Der1 extends Base[Int] { fun f(x) = x + 1 } //│ class Der1 extends Base { -//│ fun f: int -> int +//│ fun f: Int -> Int //│ } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } @@ -873,50 +882,45 @@ class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ } :e -trait BInt extends Base[int] { +trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.877: fun f = error +//│ ║ l.886: fun f = error //│ ╙── ^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing //│ } -trait BPar[T] extends Base[(int,T)] +trait BPar[T] extends Base[(Int,T)] //│ trait BPar[T] extends Base { //│ fun f: 'A -> 'A //│ } //│ where -//│ 'A := (int, T,) +//│ 'A := (Int, T,) let bi: BInt -let bp: BPar[bool] +let bp: BPar[Bool] //│ let bi: BInt -//│ let bp: BPar[bool] +//│ let bp: BPar[Bool] //│ bi //│ = //│ bp //│ = -bp: Base[(int, bool)] -//│ Base[(int, bool,)] +bp: Base[(Int, Bool)] +//│ Base[(Int, Bool,)] //│ res //│ = //│ bp is not implemented :e -bp: Base[(int, int)] +bp: Base[(Int, Int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.909: bp: Base[(int, int)] +//│ ║ l.918: bp: Base[(Int, Int)] //│ ║ ^^ -//│ ╟── type `bool` is not an instance of type `int` -//│ ║ l.894: let bp: BPar[bool] -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.909: bp: Base[(int, int)] -//│ ╙── ^^^ -//│ Base[(int, int,)] +//│ ╙── expression of type `true` is not an instance of type `Int` +//│ Base[(Int, Int,)] //│ res //│ = //│ bp is not implemented @@ -928,25 +932,25 @@ bi.f(1) //│ bi is not implemented bp.f -//│ ((int, bool,) & 'A) -> ((int, bool,) | 'A) +//│ ((Int, Bool & 'T,) & 'A) -> ((Int, 'T | false | true,) | 'A) //│ res //│ = //│ bp is not implemented -fun fb[T](x: Base[(int, T)], y: T) = x.f((1, y)) -//│ fun fb: forall 'T. (x: Base[(int, 'T,)], y: 'T,) -> (int, 'T,) +fun fb[T](x: Base[(Int, T)], y: T) = x.f((1, y)) +//│ fun fb: forall 'T. (x: Base[(Int, 'T,)], y: 'T,) -> (Int, 'T,) fb(bp, false) -//│ (int, bool,) +//│ (Int, Bool,) //│ res //│ = //│ bp is not implemented -class CP() extends BPar[int] { +class CP() extends BPar[Int] { fun f(x) = (x._2, x._1) } //│ class CP() extends BPar, Base { -//│ fun f: {_1: int, _2: int} -> (int, int,) +//│ fun f: {_1: Int, _2: Int} -> (Int, Int,) //│ } let cp1 = CP() @@ -955,7 +959,7 @@ let cp1 = CP() //│ = CP {} fb(cp1, 2) -//│ (int, int,) +//│ (Int, Int,) //│ res //│ = [ undefined, undefined ] @@ -965,112 +969,112 @@ trait BInfer1 extends Base //│ } trait BInfer2 extends Base { - fun f: int -> int + fun f: Int -> Int } //│ trait BInfer2 extends Base { -//│ fun f: int -> int +//│ fun f: Int -> Int //│ } :e -class DerBad1 extends Base[int, int] +class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.975: class DerBad1 extends Base[int, int] +//│ ║ l.979: class DerBad1 extends Base[Int, Int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `DerBad1` -//│ ║ l.975: class DerBad1 extends Base[int, int] +//│ ║ l.979: class DerBad1 extends Base[Int, Int] //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.860: trait Base[A] { fun f: A -> A } +//│ ║ l.869: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^ //│ class DerBad1 extends Base { //│ fun f: 'A -> 'A //│ } //│ where -//│ 'A := int +//│ 'A := Int :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.992: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ fun f: (B & 'a, A & 'b,) -> (B | 'b, A | 'a,) //│ } trait Ta[T] { - let p: bool + let p: Bool let g: T } class K[A](k: Ta[A]) //│ trait Ta[T] { //│ let g: T -//│ let p: bool +//│ let p: Bool //│ } //│ class K[A](k: Ta[A]) -let ta1: Ta[int] -//│ let ta1: Ta[int] +let ta1: Ta[Int] +//│ let ta1: Ta[Int] //│ ta1 //│ = let k1 = K(ta1) -//│ let k1: K[int] +//│ let k1: K[Int] //│ k1 //│ = //│ ta1 is not implemented -k1.k : Ta[int] -//│ Ta[int] +k1.k : Ta[Int] +//│ Ta[Int] //│ res //│ = //│ k1 and ta1 are not implemented k1.k.g -//│ int +//│ Int //│ res //│ = //│ k1 and ta1 are not implemented k1.k.p -//│ bool +//│ Bool //│ res //│ = //│ k1 and ta1 are not implemented :e -trait Tb extends Ta[int] { +trait Tb extends Ta[Int] { let p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1063: let p = false +//│ ║ l.1067: let p = false //│ ╙── ^^^^^^^^^ //│ trait Tb extends Ta { //│ let g: 'T //│ let p: false //│ } //│ where -//│ 'T := int +//│ 'T := Int class Ctb extends Tb { let p = false @@ -1084,29 +1088,29 @@ class Ctb extends Tb { class G1[A](x: A) //│ class G1[A](x: A) -class GI(x: int) extends G1[int](x) -//│ class GI(x: int) extends G1 +class GI(x: Int) extends G1[Int](x) +//│ class GI(x: Int) extends G1 trait Oz { - let age: int + let age: Int } //│ trait Oz { -//│ let age: int +//│ let age: Int //│ } :e -class Fischl(age: bool) extends Oz +class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1098: class Fischl(age: bool) extends Oz +//│ ║ l.1102: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ -//│ ╟── type `bool` is not an instance of `int` +//│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1091: let age: int +//│ ║ l.1095: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1091: let age: int +//│ ║ l.1095: let age: Int //│ ╙── ^^^^^^^^ -//│ class Fischl(age: bool) extends Oz +//│ class Fischl(age: Bool) extends Oz class Klee(age: 1 | 2 | 3) extends Oz //│ class Klee(age: 1 | 2 | 3) extends Oz @@ -1115,7 +1119,7 @@ class Fate { fun foo(x) = x + 1 } //│ class Fate { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } :e @@ -1123,43 +1127,52 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1123: fun foo(x) = x && true +//│ ║ l.1127: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── expression of type `int & ??_` is not an instance of type `bool` +//│ ╟── expression of type `Int & ??_` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1123: fun foo(x) = x && true +//│ ║ l.1127: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1123: fun foo(x) = x && true +//│ ║ l.1127: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── operator application of type `Bool` does not match type `Int | ??_` +//│ ║ l.1127: fun foo(x) = x && true +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from operator application: +//│ ║ l.1119: fun foo(x) = x + 1 +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.1127: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── operator application of type `bool` does not match type `int | ??_` -//│ ║ l.1123: fun foo(x) = x && true +//│ ╟── operator application of type `Bool` does not match type `Int | ??_` +//│ ║ l.1127: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1115: fun foo(x) = x + 1 +//│ ║ l.1119: fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { -//│ fun foo: bool -> bool +//│ fun foo: Bool -> Bool //│ } -class Ha { let x: int = 1 } +class Ha { let x: Int = 1 } //│ class Ha { -//│ let x: int +//│ let x: Int //│ } class Haha(x: 1 | 2) extends Ha //│ class Haha(x: 1 | 2) extends Ha :e -class Ohhh(x: bool) extends Ha +class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1154: class Ohhh(x: bool) extends Ha +//│ ║ l.1167: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ -//│ ╟── type `bool` is not an instance of `int` +//│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1145: class Ha { let x: int = 1 } +//│ ║ l.1158: class Ha { let x: Int = 1 } //│ ╙── ^^^ -//│ class Ohhh(x: bool) extends Ha +//│ class Ohhh(x: Bool) extends Ha trait TA[A] { let a : A } //│ trait TA[A] { @@ -1169,7 +1182,7 @@ trait TA[A] { let a : A } class G1[A, B](a: A, b: B) extends TA[A] //│ class G1[A, B](a: A, b: B) extends TA -class G2[T](x: T) extends G1[T, int](x, 1) +class G2[T](x: T) extends G1[T, Int](x, 1) //│ class G2[T](x: T) extends G1, TA let g21 = G2(false) @@ -1177,17 +1190,17 @@ let g21 = G2(false) //│ g21 //│ = G2 {} -g21: G1[bool, int] -//│ G1[bool, int] +g21: G1[Bool, Int] +//│ G1[Bool, Int] //│ res //│ = G2 {} g21.a -//│ bool +//│ Bool //│ res //│ = false -g21: TA[bool] -//│ TA[bool] +g21: TA[Bool] +//│ TA[Bool] //│ res //│ = G2 {} diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index da3ec4fb28..9d3e7fb6b0 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -3,7 +3,7 @@ :js fun f(x) = x > 0 && f(x - 1) -//│ fun f: int -> bool +//│ fun f: Int -> Bool //│ // Prelude //│ let res; //│ class TypingUnit {} @@ -15,13 +15,13 @@ fun f(x) = x > 0 && f(x - 1) //│ // End of generated code f(12) -//│ bool +//│ Bool //│ res //│ = false :js let rec f(x) = x > 0 && f(x - 1) -//│ let rec f: int -> bool +//│ let rec f: Int -> Bool //│ // Prelude //│ class TypingUnit2 {} //│ const typing_unit2 = new TypingUnit2; @@ -34,7 +34,7 @@ let rec f(x) = x > 0 && f(x - 1) //│ = [Function: f1] f(12) -//│ bool +//│ Bool //│ res //│ = false @@ -105,7 +105,7 @@ let rec f = let foo = 1 let foo = foo + 1 //│ let foo: 1 -//│ let foo: int +//│ let foo: Int //│ foo //│ = 1 //│ foo diff --git a/shared/src/test/diff/nu/ListConsNil.mls b/shared/src/test/diff/nu/ListConsNil.mls index 56cdd8c248..0185d46768 100644 --- a/shared/src/test/diff/nu/ListConsNil.mls +++ b/shared/src/test/diff/nu/ListConsNil.mls @@ -14,10 +14,10 @@ module Nil // TODO should better simplify these types (reduce the List refinement) :ng -let test0: Cons[int] & List[number] -let test1: Nil & List[int] -//│ let test0: Cons[int] & List[number] -//│ let test1: List[int] & Nil +let test0: Cons[Int] & List[Num] +let test1: Nil & List[Int] +//│ let test0: Cons[Int] & List[Num] +//│ let test1: Nil & List[Int] diff --git a/shared/src/test/diff/nu/LitMatch.mls b/shared/src/test/diff/nu/LitMatch.mls new file mode 100644 index 0000000000..d4ac5e886b --- /dev/null +++ b/shared/src/test/diff/nu/LitMatch.mls @@ -0,0 +1,39 @@ +:NewDefs + + +false : Bool +//│ Bool +//│ res +//│ = false + +// FIXME parsing! +let b = true | false : Bool +//│ let b: (Bool,) +//│ b +//│ = 1 + +let b = false : Bool +//│ let b: Bool +//│ b +//│ = false + +b : true | false +//│ Bool +//│ res +//│ = false + +if false is false then 0 +//│ 0 +//│ res +//│ = 0 + +fun foo(x) = if x is + false then 0 +//│ fun foo: nothing -> 0 + +fun foo(x) = if x is + false then 0 + true then 1 +//│ fun foo: nothing -> (0 | 1) + + diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index 5dea8fafce..e844caebc0 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -9,9 +9,9 @@ let f = //│ = 123 -let x : int | string +let x : Int | string let x = 1 -//│ let x: int | string +//│ let x: Int | string //│ let x: 1 //│ x //│ = diff --git a/shared/src/test/diff/nu/MemberConfusion.mls b/shared/src/test/diff/nu/MemberConfusion.mls index d627b04a4a..262e0a1a4b 100644 --- a/shared/src/test/diff/nu/MemberConfusion.mls +++ b/shared/src/test/diff/nu/MemberConfusion.mls @@ -6,8 +6,8 @@ mixin T { fun a = "hi" } //│ fun a: "hi" //│ } -class C(a: int) extends T -//│ class C(a: int) { +class C(a: Int) extends T +//│ class C(a: Int) { //│ fun a: "hi" //│ } @@ -17,15 +17,15 @@ class B { let a = "hi" } //│ } :e -class C(a: int) extends B +class C(a: Int) extends B //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.20: class C(a: int) extends B +//│ ║ l.20: class C(a: Int) extends B //│ ║ ^^^ -//│ ╟── type `int` does not match type `"hi"` +//│ ╟── type `Int` does not match type `"hi"` //│ ╟── Note: constraint arises from string literal: //│ ║ l.14: class B { let a = "hi" } //│ ╙── ^^^^ -//│ class C(a: int) extends B +//│ class C(a: Int) extends B mixin M { let b = "hi" } @@ -33,42 +33,42 @@ mixin M { let b = "hi" } //│ let b: "hi" //│ } -class B { let a = 1 : int } +class B { let a = 1 : Int } //│ class B { -//│ let a: int +//│ let a: Int //│ } -class C(a: int, b: int) extends B, M -//│ class C(a: int, b: int) extends B { +class C(a: Int, b: Int) extends B, M +//│ class C(a: Int, b: Int) extends B { //│ let b: "hi" //│ } let c = C(2, 3) (c.a, c.b) //│ let c: C -//│ (int, "hi",) +//│ (Int, "hi",) //│ c //│ = C {} //│ res //│ = [ 2, 3 ] -class C(a: int) { let a = 1 } -//│ class C(a: int) { +class C(a: Int) { let a = 1 } +//│ class C(a: Int) { //│ let a: 1 //│ } -class C(a: int) { fun a = 1 } -//│ class C(a: int) { +class C(a: Int) { fun a = 1 } +//│ class C(a: Int) { //│ fun a: 1 //│ } -class C(a: int) { fun a = a } -//│ class C(a: int) { +class C(a: Int) { fun a = a } +//│ class C(a: Int) { //│ fun a: nothing //│ } -class C(a: int, b: int) extends B, M { let b = "hi" } -//│ class C(a: int, b: int) extends B { +class C(a: Int, b: Int) extends B, M { let b = "hi" } +//│ class C(a: Int, b: Int) extends B { //│ let b: "hi" //│ } diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index 22df6ca42e..c4ce8d6832 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -54,27 +54,27 @@ trait S3 extends S1, S2 //│ trait S3 extends S1, S2 -trait S1 { val f: int -> int } +trait S1 { val f: Int -> Int } //│ trait S1 { -//│ let f: int -> int +//│ let f: Int -> Int //│ } trait S2 extends T1, S1 //│ trait S2 extends S1, T1 { -//│ fun f: forall 'A. 'A -> 'A & int -> int +//│ fun f: forall 'A. 'A -> 'A & Int -> Int //│ } trait S3 extends S1, T1 //│ trait S3 extends S1, T1 { -//│ fun f: forall 'A. int -> int & 'A -> 'A +//│ fun f: forall 'A. Int -> Int & 'A -> 'A //│ } -class C1(x: int | bool) -trait T1 { val x: int | string } -//│ class C1(x: bool | int) +class C1(x: Int | Bool) +trait T1 { val x: Int | string } +//│ class C1(x: Int | false | true) //│ trait T1 { -//│ let x: int | string +//│ let x: Int | string //│ } class C2 extends C1(0), T1 @@ -88,12 +88,12 @@ class C2 extends C1(false), T1 //│ ╔══[ERROR] Type mismatch in reference: //│ ║ l.87: class C2 extends C1(false), T1 //│ ║ ^^^^^ -//│ ╟── reference of type `false` does not match type `int | string` +//│ ╟── reference of type `false` does not match type `Int | string` //│ ╟── Note: constraint arises from union type: -//│ ║ l.74: trait T1 { val x: int | string } +//│ ║ l.74: trait T1 { val x: Int | string } //│ ║ ^^^^^^^^^^^^ //│ ╟── from signature of member `x`: -//│ ║ l.74: trait T1 { val x: int | string } +//│ ║ l.74: trait T1 { val x: Int | string } //│ ╙── ^^^^^^^^^^^^^^^ //│ class C2 extends C1, T1 @@ -102,12 +102,22 @@ class C2 extends C1("oops"), T1 //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.101: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"oops"` does not match type `bool | int` +//│ ╟── string literal of type `"oops"` does not match type `Bool | Int` //│ ║ l.101: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.73: class C1(x: int | bool) +//│ ║ l.73: class C1(x: Int | Bool) //│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in string literal: +//│ ║ l.101: class C2 extends C1("oops"), T1 +//│ ║ ^^^^^^ +//│ ╟── string literal of type `"oops"` does not match type `Int | string` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.74: trait T1 { val x: Int | string } +//│ ║ ^^^^^^^^^^^^ +//│ ╟── from signature of member `x`: +//│ ║ l.74: trait T1 { val x: Int | string } +//│ ╙── ^^^^^^^^^^^^^^^ //│ class C2 extends C1, T1 diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index 46f9405afc..067fe03588 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -18,22 +18,22 @@ mixin WithUid { fun unwrap(x) = super.unwrap(x).underlying fun rewrap(x, f) = super.rewrap(x, y => { underlying: f(y.underlying), uid: y.uid }) fun getUid(x) = super.unwrap(x).uid - fun setUid(x, uid: int) = super.rewrap(x, y => { + fun setUid(x, uid: Int) = super.rewrap(x, y => { underlying: y.underlying, uid }) } //│ mixin WithUid() { -//│ super: {rewrap: ('a, forall 'uid. {uid: 'uid, underlying: 'underlying} -> {uid: 'uid, underlying: 'b},) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {uid: int, underlying: 'underlying0},) -> 'e, unwrap: 'f -> {underlying: 'underlying1} & 'g -> {uid: 'uid0}} +//│ super: {rewrap: ('a, forall 'uid. {uid: 'uid, underlying: 'underlying} -> {uid: 'uid, underlying: 'b},) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {uid: Int, underlying: 'underlying0},) -> 'e, unwrap: 'f -> {underlying: 'underlying1} & 'g -> {uid: 'uid0}} //│ fun getUid: 'g -> 'uid0 //│ fun rewrap: ('a, 'underlying -> 'b,) -> 'c -//│ fun setUid: ('d, uid: int,) -> 'e +//│ fun setUid: ('d, uid: Int,) -> 'e //│ fun unwrap: 'f -> 'underlying1 //│ } -class Type(name: string) -//│ class Type(name: string) +class Type(name: Str) +//│ class Type(name: Str) mixin WithType { fun unwrap(x) = super.unwrap(x).underlying @@ -57,15 +57,15 @@ module Test0 extends Base, WithUid //│ module Test0 { //│ fun getUid: {uid: 'uid} -> 'uid //│ fun rewrap: ({uid: 'uid0, underlying: 'underlying}, 'underlying -> 'a,) -> {uid: 'uid0, underlying: 'a} -//│ fun setUid: ({underlying: 'underlying0}, uid: int,) -> {uid: int, underlying: 'underlying0} +//│ fun setUid: ({underlying: 'underlying0}, uid: Int,) -> {uid: Int, underlying: 'underlying0} //│ fun unwrap: {underlying: 'underlying1} -> 'underlying1 //│ } module Test0 extends Base, WithUid, WithUid //│ module Test0 { //│ fun getUid: {underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, 'underlying1 -> 'underlying0,) -> {uid: 'uid0, underlying: {uid: int | 'uid1, underlying: 'underlying0}} -//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, uid: int,) -> {uid: 'uid0, underlying: {uid: int | 'uid1, underlying: 'underlying0}} +//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, 'underlying1 -> 'underlying0,) -> {uid: 'uid0, underlying: {uid: Int | 'uid1, underlying: 'underlying0}} +//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, uid: Int,) -> {uid: 'uid0, underlying: {uid: Int | 'uid1, underlying: 'underlying0}} //│ fun unwrap: {underlying: {uid: 'uid, underlying: 'underlying}} -> 'underlying //│ } @@ -76,7 +76,7 @@ module Test1 extends Base, WithUid, WithType //│ fun getUid: {uid: 'uid} -> 'uid //│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1}}, 'underlying1 -> 'underlying0,) -> {uid: 'uid0, underlying: {ty: Type | 'ty0, underlying: 'underlying0}} //│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1}}, ty: Type,) -> {uid: 'uid0, underlying: {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun setUid: ({underlying: 'underlying2}, uid: int,) -> {uid: int, underlying: 'underlying2} +//│ fun setUid: ({underlying: 'underlying2}, uid: Int,) -> {uid: Int, underlying: 'underlying2} //│ fun unwrap: {underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying //│ } @@ -108,17 +108,17 @@ Test1.getUid(a) //│ = 0 Test1.setUid(a, 1) -//│ {uid: int, underlying: {ty: Type, underlying: 42}} +//│ {uid: Int, underlying: {ty: Type, underlying: 42}} //│ res //│ = { underlying: { ty: Type {}, underlying: 42 }, uid: 1 } Test1.getType(a).name -//│ string +//│ Str //│ res //│ = 'A' a.underlying.ty.name -//│ string +//│ Str //│ res //│ = 'A' @@ -128,12 +128,12 @@ let b = Test1.setType(a, Type("B")) //│ = { underlying: { underlying: 42, ty: Type {} }, uid: 0 } Test1.getType(b).name -//│ string +//│ Str //│ res //│ = 'B' b.underlying.ty.name -//│ string +//│ Str //│ res //│ = 'B' diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index a34a8096d4..262605747e 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -3,30 +3,30 @@ module Oops { - fun a : int + fun a : Int fun a = 2 } //│ module Oops { -//│ fun a: int +//│ fun a: Int //│ } :e module Oops { - fun a : int + fun a : Int } //│ ╔══[ERROR] Member `a` is declared in parent but not implemented in `Oops` //│ ║ l.14: module Oops { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.15: fun a : int +//│ ║ l.15: fun a : Int //│ ╙── ^^^^^^^ //│ module Oops { -//│ fun a: int +//│ fun a: Int //│ } :e module Oops { - fun a : int + fun a : Int fun a : string fun a = a } @@ -39,26 +39,26 @@ module Oops { :e module Oops { - fun a : int + fun a : Int fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: //│ ║ l.43: fun a = false //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `int` +//│ ╟── reference of type `false` is not an instance of type `Int` //│ ║ l.43: fun a = false //│ ║ ^^^^^ -//│ ╟── but it flows into definition of method a with expected type `int` +//│ ╟── but it flows into definition of method a with expected type `Int` //│ ║ l.43: fun a = false //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.42: fun a : int +//│ ║ l.42: fun a : Int //│ ║ ^^^ //│ ╟── from signature of member `a`: -//│ ║ l.42: fun a : int +//│ ║ l.42: fun a : Int //│ ╙── ^^^^^^^ //│ module Oops { -//│ fun a: int +//│ fun a: Int //│ } :e diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index dc97625632..23275e7b7c 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -7,7 +7,7 @@ //│ = 1 2 + 2 -//│ int +//│ Int //│ res //│ = 4 @@ -17,13 +17,13 @@ let r = { x: 1 } //│ = { x: 1 } r.x + 1 -//│ int +//│ Int //│ res //│ = 2 x => x + 1 -//│ int -> int +//│ Int -> Int //│ res //│ = [Function: res] @@ -45,12 +45,12 @@ f({y: 1}) let f = (x, y) => x + y -//│ let f: (int, int,) -> int +//│ let f: (Int, Int,) -> Int //│ f //│ = [Function: f2] f(1, 2) -//│ int +//│ Int //│ res //│ = 3 @@ -65,14 +65,14 @@ f([1, 2]) //│ ╟── Note: constraint arises from tuple literal: //│ ║ l.47: let f = (x, y) => x + y //│ ╙── ^^^^ -//│ error | int +//│ Int | error //│ res //│ = '1,2undefined' let f = ((x, y)) => x + y -//│ let f: (int, int,) -> int +//│ let f: (Int, Int,) -> Int //│ f //│ = [Function: f3] @@ -84,7 +84,7 @@ f(1, 2) //│ ╟── argument list of type `(1, 2,)` does not match type `((?a, ?b,),)` //│ ║ l.80: f(1, 2) //│ ╙── ^^^^^^ -//│ error | int +//│ Int | error //│ res //│ Runtime error: //│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) @@ -92,34 +92,34 @@ f(1, 2) f((1, 2)) -//│ int +//│ Int //│ res //│ = 3 f([1, 2]) -//│ int +//│ Int //│ res //│ = 3 let f = (((x, y))) => x + y -//│ let f: (int, int,) -> int +//│ let f: (Int, Int,) -> Int //│ f //│ = [Function: f4] // TODO parse as tuple arg! let f = [x, y] => x + y -//│ let f: (int, int,) -> int +//│ let f: (Int, Int,) -> Int //│ f //│ = [Function: f5] f(1, 2) -//│ int +//│ Int //│ res //│ = 3 // TODO... let f = [[[x, y]]] => x + y -//│ let f: (int, int,) -> int +//│ let f: (Int, Int,) -> Int //│ f //│ = [Function: f6] diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index f4143ab9b3..21dbc683b0 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -1,11 +1,11 @@ :NewDefs -mixin BaseTest(x: int) { +mixin BaseTest(x: Int) { fun test = x } -//│ mixin BaseTest(x: int) { -//│ fun test: int +//│ mixin BaseTest(x: Int) { +//│ fun test: Int //│ } // TODO diff --git a/shared/src/test/diff/nu/ModuleParameters.mls b/shared/src/test/diff/nu/ModuleParameters.mls index afe26a519d..a005806e52 100644 --- a/shared/src/test/diff/nu/ModuleParameters.mls +++ b/shared/src/test/diff/nu/ModuleParameters.mls @@ -2,21 +2,21 @@ :e -module A(x: int) { fun y = x } +module A(x: Int) { fun y = x } //│ ╔══[ERROR] module parameters are not supported -//│ ║ l.5: module A(x: int) { fun y = x } +//│ ║ l.5: module A(x: Int) { fun y = x } //│ ╙── ^ -//│ module A(x: int) { -//│ fun y: int +//│ module A(x: Int) { +//│ fun y: Int //│ } A.x -//│ int +//│ Int //│ res //│ = undefined A.y -//│ int +//│ Int //│ res //│ = undefined diff --git a/shared/src/test/diff/nu/Mut.mls b/shared/src/test/diff/nu/Mut.mls index 0bb919b622..7b425d62b6 100644 --- a/shared/src/test/diff/nu/Mut.mls +++ b/shared/src/test/diff/nu/Mut.mls @@ -10,11 +10,26 @@ let v1: {mut 1} //│ v1 //│ = -let v1: {mut int} -//│ let v1: {mut int: int} +:e +let v1: {mut Int} +//│ ╔══[ERROR] Field identifiers must start with a small letter +//│ ║ l.14: let v1: {mut Int} +//│ ╙── ^^^ +//│ let v1: {Int = Int} //│ v1 //│ = +:e +let v1 = {mut Int: 0} +//│ ╔══[ERROR] Field identifiers must start with a small letter +//│ ║ l.23: let v1 = {mut Int: 0} +//│ ╙── ^ +//│ let v1: {Int = 'Int} +//│ where +//│ 'Int :> 0 +//│ v1 +//│ = { Int: 0 } + let v1 = {mut int: 0} //│ let v1: {mut int: 'int} //│ where @@ -23,15 +38,15 @@ let v1 = {mut int: 0} //│ = { int: 0 } -let v1: {mut x: int} -//│ let v1: {mut x: int} +let v1: {mut x: Int} +//│ let v1: {mut x: Int} //│ v1 //│ = :pe let v1 = {mut 1} //│ ╔══[PARSE ERROR] Record field should have a name -//│ ║ l.32: let v1 = {mut 1} +//│ ║ l.47: let v1 = {mut 1} //│ ╙── ^ //│ let v1: {mut : '} //│ where @@ -50,7 +65,7 @@ let v1 = {mut x: 1} :pe v1.x = 1 //│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.51: v1.x = 1 +//│ ║ l.66: v1.x = 1 //│ ╙── ^ //│ 1 //│ res @@ -61,13 +76,13 @@ v1.x = 1 :ng v1.x <- 1 //│ ╔══[ERROR] identifier not found: <- -//│ ║ l.62: v1.x <- 1 +//│ ║ l.77: v1.x <- 1 //│ ╙── ^^ //│ error -let v2: (mut int) -//│ let v2: (mut int,) +let v2: (mut Int) +//│ let v2: (mut Int,) //│ v2 //│ = @@ -78,8 +93,8 @@ let v2 = (mut 1) //│ v2 //│ = [ 1 ] -let v2: (mut x: int) -//│ let v2: (mut x: int,) +let v2: (mut x: Int) +//│ let v2: (mut x: Int,) //│ v2 //│ = diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 90131a0398..69acffd94b 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -244,10 +244,10 @@ Test2_1.n module Test2_1 { fun t2 = Test2_2 - fun a: int + fun a: Int fun a = Test2_2.b fun d = Test2_2.e - fun n: int + fun n: Int fun n = 456 } module Test2_2 { @@ -256,15 +256,15 @@ module Test2_2 { fun e = Test2_1.n } //│ module Test2_1 { -//│ fun a: int -//│ fun d: int -//│ fun n: int +//│ fun a: Int +//│ fun d: Int +//│ fun n: Int //│ fun t2: Test2_2 //│ } //│ module Test2_2 { //│ fun b: 123 -//│ fun c: int -//│ fun e: int +//│ fun c: Int +//│ fun e: Int //│ } Test2_1.t2.b @@ -273,28 +273,28 @@ Test2_1.t2.b //│ = 123 Test2_1.a -//│ int +//│ Int //│ res //│ = 123 Test2_1.d -//│ int +//│ Int //│ res //│ = 456 Test2_1.n -//│ int +//│ Int //│ res //│ = 456 -class Test2(n: int) { +class Test2(n: Int) { fun inc = Test3.inc(this) } module Test3 { fun inc(t: Test2) = Test2(t.n + 1) } -//│ class Test2(n: int) { +//│ class Test2(n: Int) { //│ fun inc: Test2 //│ } //│ module Test3 { diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index 2288b313c6..0c6c00c2b4 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -1,8 +1,8 @@ :NewDefs -class Foo(x: int) -//│ class Foo(x: int) +class Foo(x: Int) +//│ class Foo(x: Int) Foo(1) //│ Foo diff --git a/shared/src/test/diff/nu/New.mls b/shared/src/test/diff/nu/New.mls index bcddd0e045..b29b06ab62 100644 --- a/shared/src/test/diff/nu/New.mls +++ b/shared/src/test/diff/nu/New.mls @@ -40,11 +40,11 @@ test(f) //│ res: 1 //│ = 1 -class Point(x, y) -//│ Defined class Point -//│ Point: ('x, 'y,) -> (Point & {x: 'x, y: 'y}) -//│ = [Function: Point1] - -let origin = new Point(0, 0) -//│ origin: Point & {x: 0, y: 0} -//│ = Point { x: 0, y: 0 } +class PoInt(x, y) +//│ Defined class PoInt +//│ PoInt: ('x, 'y,) -> (PoInt & {x: 'x, y: 'y}) +//│ = [Function: PoInt1] + +let origin = new PoInt(0, 0) +//│ origin: PoInt & {x: 0, y: 0} +//│ = PoInt { x: 0, y: 0 } diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index 2bc6ff6a4d..c30d4efe3c 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -1,8 +1,8 @@ :NewDefs -class Foo(x: int) -//│ class Foo(x: int) +class Foo(x: Int) +//│ class Foo(x: Int) let f = Foo(1) //│ let f: Foo @@ -20,35 +20,35 @@ if f is Foo then 1 else 0 //│ = 1 if f is Foo(a) then a else 0 -//│ int +//│ Int //│ res //│ = 1 -class Point[A](x: A, y: A) -//│ class Point[A](x: A, y: A) +class PoInt[A](x: A, y: A) +//│ class PoInt[A](x: A, y: A) -let origin = new Point(0, 0) -//│ let origin: Point[0] +let origin = new PoInt(0, 0) +//│ let origin: PoInt[0] //│ origin -//│ = Point {} +//│ = PoInt {} // TODO -let origin = Point[int](0, 0) +let origin = PoInt[Int](0, 0) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.37: let origin = Point[int](0, 0) +//│ ║ l.37: let origin = PoInt[Int](0, 0) //│ ╙── ^^^^^^^^^^ //│ let origin: error //│ origin -//│ = Point {} +//│ = PoInt {} // TODO -let origin = new Point[int](0, 0) +let origin = new PoInt[Int](0, 0) //│ ╔══[PARSE ERROR] Unexpected application after `new` keyword -//│ ║ l.46: let origin = new Point[int](0, 0) +//│ ║ l.46: let origin = new PoInt[Int](0, 0) //│ ╙── ^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.46: let origin = new Point[int](0, 0) +//│ ║ l.46: let origin = new PoInt[Int](0, 0) //│ ╙── ^^^ //│ let origin: error //│ origin diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index db2ada0199..539c23787c 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,2 +1,3 @@ :NewDefs + diff --git a/shared/src/test/diff/nu/Numbers.mls b/shared/src/test/diff/nu/Numbers.mls index abeaf04369..ed817f72de 100644 --- a/shared/src/test/diff/nu/Numbers.mls +++ b/shared/src/test/diff/nu/Numbers.mls @@ -1,23 +1,64 @@ :NewDefs +let n = 123 +let m = n : Int +let o = m : Num +let p = o : Object +let o = n : Num +let p = n : Object +let p = m : Object +//│ let n: 123 +//│ let m: Int +//│ let o: Num +//│ let p: Object +//│ let o: Num +//│ let p: Object +//│ let p: Object +//│ n +//│ = 123 +//│ m +//│ = 123 +//│ o +//│ = 123 +//│ p +//│ = 123 +//│ o +//│ = 123 +//│ p +//│ = 123 +//│ p +//│ = 123 + + let x = NaN -//│ let x: number +//│ let x: Num //│ x //│ = NaN -// TODO polymorphic number operations +// TODO polymorphic Num operations x + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.10: x + 1 +//│ ║ l.40: x + 1 //│ ║ ^^^ -//│ ╟── reference of type `number` is not an instance of type `int` -//│ ║ l.4: let x = NaN -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `int` -//│ ║ l.10: x + 1 +//│ ╟── reference of type `Num` is not an instance of `Int` +//│ ║ l.34: let x = NaN +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `Int` +//│ ║ l.40: x + 1 //│ ╙── ^ -//│ error | int +//│ Int | error //│ res //│ = NaN + +true : Bool +//│ Bool +//│ res +//│ = true + +true : Bool | Str +//│ Str | false | true +//│ res +//│ = true + diff --git a/shared/src/test/diff/nu/Object.mls b/shared/src/test/diff/nu/Object.mls new file mode 100644 index 0000000000..a307d83e5a --- /dev/null +++ b/shared/src/test/diff/nu/Object.mls @@ -0,0 +1,143 @@ +:NewDefs + + + +class A() +class B() +//│ class A() +//│ class B() + +let a: Object = A() +//│ let a: Object +//│ a +//│ = A {} + + +module M +//│ module M + +M: Object +//│ Object +//│ res +//│ = M { class: [class M] } + + + +fun foo(x) = if x is A then true +//│ fun foo: A -> true + +fun foo(x) = if x is A then true else false +//│ fun foo: Object -> Bool + + +:e +fun foo(x: anything) = if x is A then true +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.34: fun foo(x: anything) = if x is A then true +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── type `anything` is not an instance of type `Object` +//│ ║ l.34: fun foo(x: anything) = if x is A then true +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into reference with expected type `Object` +//│ ║ l.34: fun foo(x: anything) = if x is A then true +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.34: fun foo(x: anything) = if x is A then true +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── type `anything` is not an instance of type `A` +//│ ║ l.34: fun foo(x: anything) = if x is A then true +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into reference with expected type `A` +//│ ║ l.34: fun foo(x: anything) = if x is A then true +//│ ║ ^ +//│ ╟── Note: constraint arises from class pattern: +//│ ║ l.34: fun foo(x: anything) = if x is A then true +//│ ╙── ^ +//│ fun foo: (x: anything,) -> true + +:e +fun foo(x: anything) = if x is A then true else false +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.59: fun foo(x: anything) = if x is A then true else false +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `anything` is not an instance of type `Object` +//│ ║ l.59: fun foo(x: anything) = if x is A then true else false +//│ ║ ^^^^^^^^ +//│ ╟── but it flows into reference with expected type `Object` +//│ ║ l.59: fun foo(x: anything) = if x is A then true else false +//│ ╙── ^ +//│ fun foo: (x: anything,) -> Bool + + +fun foo(x: Object) = if x is A then true else false +//│ fun foo: (x: Object,) -> Bool + + +// TODO make this a rigid type variable! +// :e +fun foo = forall 'a; (x: 'a) => if x is A then true else false +//│ ╔══[ERROR] Type mismatch in `case` expression: +//│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── rigid type variable of type `'a` is not an instance of type `Object` +//│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false +//│ ║ ^^ +//│ ╟── but it flows into reference with expected type `Object` +//│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false +//│ ╙── ^ +//│ fun foo: (x: anything,) -> Bool + + + +:ge +Object +//│ () -> Object +//│ Code generation encountered an error: +//│ unresolved symbol Object + +:ge +Object() +//│ Object +//│ Code generation encountered an error: +//│ unresolved symbol Object + + + +// TODO +class B() extends Object +//│ class B() extends Object +//│ Code generation encountered an error: +//│ unresolved parent Object. + +// TODO +class C() extends A +//│ class C() extends A + +let o: Object = C() +//│ let o: Object +//│ o +//│ = C {} + +fun foo(x) = if x is + A then true + B then true + else false +//│ fun foo: Object -> Bool + +foo(0) +//│ Bool +//│ res +//│ = false + +foo(o) +//│ Bool +//│ res +//│ = true + + +(0 : Int) : Object +//│ Object +//│ res +//│ = 0 + + diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls index a7b1c2a0c9..4cff720319 100644 --- a/shared/src/test/diff/nu/OverrideShorthand.mls +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -2,8 +2,8 @@ -class Pair(lhs: int, rhs: int) -//│ class Pair(lhs: int, rhs: int) +class Pair(lhs: Int, rhs: Int) +//│ class Pair(lhs: Int, rhs: Int) :p @@ -14,7 +14,7 @@ fun f(override Pair(x, y)) = x + y //│ ╔══[ERROR] identifier not found: super //│ ║ l.11: fun f(override Pair(x, y)) = x + y //│ ╙── ^^^^^^^^ -//│ fun f: anything -> (error | int) +//│ fun f: Object -> (Int | error) //│ Syntax error: //│ 'super' keyword unexpected here @@ -24,7 +24,7 @@ mixin Test { } //│ mixin Test() { //│ super: {f: 'a -> 'b} -//│ fun f: (Pair | 'a & ~#Pair) -> (int | 'b) +//│ fun f: (Object & 'a & ~#Pair | Pair) -> (Int | 'b) //│ } @@ -43,13 +43,13 @@ fun f(override Pair(x, y), z) = x + y //│ ╔══[ERROR] identifier not found: y //│ ║ l.33: fun f(override Pair(x, y), z) = x + y //│ ╙── ^ -//│ fun f: (error, anything,) -> int +//│ fun f: (error, anything,) -> Int //│ Code generation encountered an error: //│ term App(Var(Pair), Tup(_: Var(x), _: Var(y))) is not a valid pattern // TODO // :pe -// fun f(override Pair(x, y)): int +// fun f(override Pair(x, y)): Int diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls index ce4094559a..f06046af0a 100644 --- a/shared/src/test/diff/nu/ParamImplementing.mls +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -1,34 +1,35 @@ :NewDefs -trait T { fun x: int } -mixin M(x: bool) +trait T { fun x: Int } //│ trait T { -//│ fun x: int +//│ fun x: Int //│ } -//│ mixin M(x: bool) + +mixin M(x: Bool) +//│ mixin M(x: Bool) :e class C extends T, M(false) //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.12: class C extends T, M(false) +//│ ║ l.13: class C extends T, M(false) //│ ║ ^^^^^ -//│ ╟── reference of type `false` is not an instance of type `int` +//│ ╟── reference of type `false` is not an instance of type `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.4: trait T { fun x: int } +//│ ║ l.4: trait T { fun x: Int } //│ ║ ^^^ //│ ╟── from signature of member `x`: -//│ ║ l.4: trait T { fun x: int } +//│ ║ l.4: trait T { fun x: Int } //│ ╙── ^^^^^^ //│ class C extends T -trait T { fun x: int } -mixin M(x: number) +trait T { fun x: Int } +mixin M(x: Num) //│ trait T { -//│ fun x: int +//│ fun x: Int //│ } -//│ mixin M(x: number) +//│ mixin M(x: Num) class C extends T, M(0) //│ class C extends T diff --git a/shared/src/test/diff/nu/ParamOverride.mls b/shared/src/test/diff/nu/ParamOverride.mls index 87a1bec749..9cb6e06336 100644 --- a/shared/src/test/diff/nu/ParamOverride.mls +++ b/shared/src/test/diff/nu/ParamOverride.mls @@ -1,47 +1,47 @@ :NewDefs -class Base0(n: number) -//│ class Base0(n: number) +class Base0(n: Num) +//│ class Base0(n: Num) // TODO -class Derived0(n: int) extends Base +class Derived0(n: Int) extends Base //│ ╔══[ERROR] Could not find definition `Base` -//│ ║ l.8: class Derived0(n: int) extends Base +//│ ║ l.8: class Derived0(n: Int) extends Base //│ ╙── ^^^^ -//│ class Derived0(n: int) +//│ class Derived0(n: Int) //│ Code generation encountered an error: //│ unresolved parent Base. -mixin Base1(n: number) { +mixin Base1(n: Num) { fun original = n } -//│ mixin Base1(n: number) { -//│ fun original: number +//│ mixin Base1(n: Num) { +//│ fun original: Num //│ } :e -mixin DerivedBad(n: int) extends Base +mixin DerivedBad(n: Int) extends Base //│ ╔══[ERROR] mixin definitions cannot yet extend parents -//│ ║ l.25: mixin DerivedBad(n: int) extends Base +//│ ║ l.25: mixin DerivedBad(n: Int) extends Base //│ ╙── ^^^^ -//│ mixin DerivedBad(n: int) +//│ mixin DerivedBad(n: Int) -mixin Derived1(n: int) { +mixin Derived1(n: Int) { fun foo = [n, this.n, super.n] } -//│ mixin Derived1(n: int) { +//│ mixin Derived1(n: Int) { //│ super: {n: 'n} //│ this: {n: 'n0} -//│ fun foo: (int, 'n0, 'n,) +//│ fun foo: (Int, 'n0, 'n,) //│ } class Test0() extends Base1(1/2), Derived1(1) //│ class Test0() { -//│ fun foo: (int, 1, number,) -//│ fun original: number +//│ fun foo: (Int, 1, Num,) +//│ fun original: Num //│ } let t = Test0() @@ -55,12 +55,12 @@ t.n //│ = 1 t.original -//│ number +//│ Num //│ res //│ = 0.5 t.foo -//│ (int, 1, number,) +//│ (Int, 1, Num,) //│ res //│ = [ 1, 1, 0.5 ] @@ -69,9 +69,9 @@ module Test1 extends Base1(1/2), Derived1(1) { fun n = this.n } //│ module Test1 { -//│ fun foo: (int, 1, number,) +//│ fun foo: (Int, 1, Num,) //│ fun n: 1 -//│ fun original: number +//│ fun original: Num //│ } :re @@ -82,31 +82,31 @@ Test1.n //│ RangeError: Maximum call stack size exceeded -class Test2(n: string) extends Base1(1/2), Derived1(1) { +class Test2(n: Str) extends Base1(1/2), Derived1(1) { fun bar = [this.foo, n, this.n, this.original] } -//│ class Test2(n: string) { -//│ fun bar: ((int, string, number,), string, string, number,) -//│ fun foo: (int, string, number,) -//│ fun original: number +//│ class Test2(n: Str) { +//│ fun bar: ((Int, Str, Num,), Str, Str, Num,) +//│ fun foo: (Int, Str, Num,) +//│ fun original: Num //│ } Test2("test").bar -//│ ((int, string, number,), string, string, number,) +//│ ((Int, Str, Num,), Str, Str, Num,) //│ res //│ = [ [ 1, 'test', 0.5 ], 'test', 'test', 0.5 ] -class Test3(n: string) extends Base1(1/2), Derived1(length(n)) { +class Test3(n: Str) extends Base1(1/2), Derived1(length(n)) { fun foo = [super.foo, n, this.original] } -//│ class Test3(n: string) { -//│ fun foo: ((int, string, number,), string, number,) -//│ fun original: number +//│ class Test3(n: Str) { +//│ fun foo: ((Int, Str, Num,), Str, Num,) +//│ fun original: Num //│ } Test3("test").foo -//│ ((int, string, number,), string, number,) +//│ ((Int, Str, Num,), Str, Num,) //│ res //│ = [ [ 4, 'test', 0.5 ], 'test', 0.5 ] diff --git a/shared/src/test/diff/nu/ParamOverriding.mls b/shared/src/test/diff/nu/ParamOverriding.mls index 07f5129860..2d04f6747f 100644 --- a/shared/src/test/diff/nu/ParamOverriding.mls +++ b/shared/src/test/diff/nu/ParamOverriding.mls @@ -9,24 +9,24 @@ mixin Over { //│ } -class Base1(p: int) extends Over { +class Base1(p: Int) extends Over { fun test = [p, this.p] fun test2 = super.p } -//│ class Base1(p: int) { +//│ class Base1(p: Int) { //│ fun p: "hi" -//│ fun test: (int, int,) -//│ fun test2: int +//│ fun test: (Int, Int,) +//│ fun test2: Int //│ } Base1(123).test -//│ (int, int,) +//│ (Int, Int,) //│ res //│ = [ 123, 123 ] Base1(123).test2 -//│ int +//│ Int //│ res //│ = 'hi' diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 8635dc6424..17735352f4 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -1,30 +1,30 @@ :NewDefs -class Foo(x: int) -//│ class Foo(x: int) +class Foo(x: Int) +//│ class Foo(x: Int) +class Bar(x: Int, y: Int) extends Foo(x + y) +//│ class Bar(x: Int, y: Int) extends Foo -class Bar(x: int, y: int) extends Foo(x + y) -//│ class Bar(x: int, y: int) extends Foo -mixin AA(a: int) { +mixin AA(a: Int) { } -//│ mixin AA(a: int) +//│ mixin AA(a: Int) mixin BB {} //│ mixin BB() -class C(x: int) extends BB -//│ class C(x: int) +class C(x: Int) extends BB +//│ class C(x: Int) -class D(x: int) extends AA(x) -//│ class D(x: int) +class D(x: Int) extends AA(x) +//│ class D(x: Int) -class E(x: int) extends BB, AA(x) -//│ class E(x: int) +class E(x: Int) extends BB, AA(x) +//│ class E(x: Int) diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 1b15627aca..f0058011e8 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -6,9 +6,9 @@ // * This time with a List class. // FIXME: -// - simplification problem or constraint bug: `'result :> anything <: Num` +// - simplification problem or constraInt bug: `'result :> anything <: Numb` // - constraining loop with unannotated `list_assoc` ascription -// - still a number of quite ugly types +// - still a Numb of quite ugly types class List { @@ -28,8 +28,8 @@ class Success(result: A) //│ class NotFound //│ class Success[A](result: A) -fun eq(l: string, r: string): bool -//│ fun eq: (l: string, r: string,) -> bool +fun eq(l: Str, r: Str): Bool +//│ fun eq: (l: Str, r: Str,) -> Bool // * Annotation currently needed to avoid later ascription loop (due to excessive TV refreshing?) // fun list_assoc(s, l) = @@ -40,18 +40,18 @@ fun list_assoc(s, l: List<'a>) = if eq(s, h._1) then Success(h._2) else list_assoc(s, t) ) -//│ fun list_assoc: forall 'a 'A. (string, l: List['a],) -> (NotFound | Success['A]) +//│ fun list_assoc: forall 'a 'A. (Str, l: List['a],) -> (NotFound | Success['A]) //│ where -//│ 'a <: {_1: string, _2: 'A} +//│ 'a <: {_1: Str, _2: 'A} -list_assoc : (string, List<{ _1: string, _2: 'b }>) => (NotFound | Success['b]) -//│ (string, List[{_1: string, _2: 'b}],) -> (NotFound | Success['b]) +list_assoc : (Str, List<{ _1: Str, _2: 'b }>) => (NotFound | Success['b]) +//│ (Str, List[{_1: Str, _2: 'b}],) -> (NotFound | Success['b]) -fun list_assoc(s: string, l: List<{ _1: string, _2: 'b }>): NotFound | Success['b] -//│ fun list_assoc: forall 'b. (s: string, l: List[{_1: string, _2: 'b}],) -> (NotFound | Success['b]) +fun list_assoc(s: Str, l: List<{ _1: Str, _2: 'b }>): NotFound | Success['b] +//│ fun list_assoc: forall 'b. (s: Str, l: List[{_1: Str, _2: 'b}],) -> (NotFound | Success['b]) -class Var(s: string) -//│ class Var(s: string) +class Var(s: Str) +//│ class Var(s: Str) mixin EvalVar { fun eval(sub, v) = @@ -61,22 +61,22 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (List[{_1: string, _2: 'b}], Var,) -> ('b | Var) +//│ fun eval: (List[{_1: Str, _2: 'b}], Var,) -> ('b | Var) //│ } -class Abs(x: string, t: A) +class Abs(x: Str, t: A) class App(s: A, t: A) -//│ class Abs[A](x: string, t: A) +//│ class Abs[A](x: Str, t: A) //│ class App[A](s: A, t: A) -fun incr(x: {a: int}): unit -//│ fun incr: (x: {a: int},) -> unit +fun incr(x: {a: Int}): unit +//│ fun incr: (x: {a: Int},) -> unit -fun gensym(): string -//│ fun gensym: () -> string +fun gensym(): Str +//│ fun gensym: () -> Str -fun int_to_string(x: int): string -//│ fun int_to_string: (x: int,) -> string +fun Int_to_string(x: Int): Str +//│ fun Int_to_string: (x: Int,) -> Str mixin EvalLambda { fun eval(sub, v) = @@ -96,15 +96,15 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c,) -> 'd} -//│ this: {eval: ('b, 's,) -> ('A & 'e) & (List[in 'a out 'a | (string, 'e,)], 't,) -> 'd & (List['a0], 't0,) -> 'A0} -//│ fun eval: (List['a0] & 'b, Abs['t0] | App['s & (Abs['t] | ~#Abs)] | 'c & ~#Abs & ~#App,) -> (Abs['A0] | App['A] | 'd) +//│ this: {eval: ('b, 's,) -> ('A & 'e) & (List[in 'a out 'a | (Str, 'e,)], 't,) -> 'd & (List['a0], 't0,) -> 'A0} +//│ fun eval: (List['a0] & 'b, Abs['t0] | App['s & (Abs['t] | Object & ~#Abs)] | Object & 'c & ~#Abs & ~#App,) -> (Abs['A0] | App['A] | 'd) //│ } //│ where -//│ 'a0 :> (string, Var,) +//│ 'a0 :> (Str, Var,) module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (List[{_1: string, _2: 'b}], Abs['t] | App['A] | Var,) -> ('c | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: 'b}], Abs['t] | App['A] | Var,) -> ('c | 'a) //│ } //│ where //│ 't <: Abs['t] | App['A] | Var @@ -142,20 +142,20 @@ Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var(" //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] //│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Var -class Num(n: int) +class Numb(n: Int) class Add(l: A, r: A) class Mul(l: A, r: A) -//│ class Num(n: int) +//│ class Numb(n: Int) //│ class Add[A](l: A, r: A) //│ class Mul[A](l: A, r: A) fun map_expr(f, v) = if v is Var then v - Num then v + Numb then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Num | Var,) -> (Add['A] | Mul['A0] | Num | Var) +//│ fun map_expr: forall 'l 'A 'l0 'A0. ('l -> 'A & 'l0 -> 'A0, Add['l] | Mul['l0] | Numb | Var,) -> (Add['A] | Mul['A0] | Numb | Var) mixin EvalExpr { fun eval(sub, v) = @@ -163,70 +163,73 @@ mixin EvalExpr { let vv = map_expr(eta, v) if vv is Var then super.eval(sub, vv) - Add(Num(l), Num(r)) then Num(l + r) - Mul(Num(l), Num(r)) then Num(l * r) + Add(Numb(l), Numb(r)) then Numb(l + r) + Mul(Numb(l), Numb(r)) then Numb(l * r) else v } //│ mixin EvalExpr() { //│ super: {eval: ('a, Var,) -> 'b} -//│ this: {eval: ('a, 'c,) -> anything} -//│ fun eval: ('a, 'b & (Add['c] | Mul['c] | Num | Var),) -> (Num | 'b) +//│ this: {eval: ('a, 'c,) -> Object} +//│ fun eval: ('a, 'b & (Add['c] | Mul['c] | Numb | Var),) -> (Numb | 'b) //│ } module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (List[{_1: string, _2: 'b}], 'a & (Add['c] | Mul['c] | Num | Var),) -> ('b | Num | Var | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: 'b}], 'a & (Add['c] | Mul['c] | Numb | Var),) -> ('b | Numb | Var | 'a) //│ } //│ where -//│ 'c <: Add['c] | Mul['c] | Num | Var +//│ 'c <: Add['c] | Mul['c] | Numb | Var +//│ 'b <: Object Test2.eval(Nil(), Var("a")) -//│ Num | Var +//│ Numb | Var Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Var("a")) -//│ Abs[Var] | Num | Var +//│ Abs[Var] | Numb | Var -Test2.eval(Cons(("a", Num(1)), Nil()), Var("a")) -//│ Num | Var +Test2.eval(Cons(("a", Numb(1)), Nil()), Var("a")) +//│ Numb | Var -Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Num(1), Var("a"))) -//│ Abs[Var] | Add[Num | Var] | Num | Var +Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Numb(1), Var("a"))) +//│ Abs[Var] | Add[Numb | Var] | Numb | Var module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'A 'a. (List[{_1: string, _2: 'b}], Abs['t] | App['A] | 'c & ~#Abs & ~#App,) -> ('d | 'a) +//│ fun eval: forall 'A 'a. (List[{_1: Str, _2: 'b}], Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App,) -> ('d | 'a) //│ } //│ where //│ 'b :> Var | 'e +//│ <: Object //│ 'e :> 'd | 'a -//│ 'd :> 'b | Num | Var | 'c | 'a +//│ 'd :> 'b | Numb | Var | 'c | 'a //│ 'a :> App['e | 'd | 'a] | Abs['d | 'a] -//│ 'c <: Add['f] | Mul['f] | Num | Var -//│ 'f <: Abs['t] | App['A] | 'c & ~#Abs & ~#App -//│ 't <: Abs['t] | App['A] | 'c & ~#Abs & ~#App -//│ 'A <: Abs['t & (Abs['t] | App['A] | 'c & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | 'c & ~#Abs & ~#App +//│ 'c <: Add['f] | Mul['f] | Numb | Var +//│ 'f <: Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App +//│ 't <: Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App +//│ 'A <: Abs['t & (Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | Object & 'c & ~#Abs & ~#App Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Num | Var +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Numb | Var -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Num(1), Var("c")))) +Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Num | Var] | Num | Var +//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Numb | Var] | Numb | Var module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: forall 'a. (List[{_1: string, _2: 'b}], 'a & (Add['c] | Mul['c] | Num | Var),) -> ('a | 'd) +//│ fun eval: forall 'a. (List[{_1: Str, _2: 'b}], 'a & (Add['c] | Mul['c] | Numb | Var),) -> ('a | 'd) //│ } //│ where -//│ 'c <: Add['c] | Mul['c] | Num | Var +//│ 'c <: Add['c] | Mul['c] | Numb | Var //│ 'b :> Var | 'e +//│ <: Object //│ 'e :> 'd -//│ 'd :> 'b | Abs[Num | 'd] | App[Num | 'e | 'd] | Num | Var +//│ 'd :> 'b | Abs[Numb | 'd] | App[Numb | 'e | 'd] | Numb | Var diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index 3d9478c9b0..d844781a54 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -40,26 +40,26 @@ trait Base1: Foo //│ = [Function: res] :e -1 : Foo[int] +1 : Foo[Int] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.43: 1 : Foo[int] +//│ ║ l.43: 1 : Foo[Int] //│ ║ ^ //│ ╟── integer literal of type `1` is not an instance of type `Foo` //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.43: 1 : Foo[int] +//│ ║ l.43: 1 : Foo[Int] //│ ╙── ^^^^^^^^ -//│ Foo[int] +//│ Foo[Int] //│ res //│ = 1 -trait Base1: Foo { val x: int } +trait Base1: Foo { val x: Int } //│ trait Base1: #Foo { -//│ let x: int +//│ let x: Int //│ } (b: Base1) => b.x -//│ (b: Base1,) -> (int & ??A) +//│ (b: Base1,) -> (Int & ??A) //│ res //│ = [Function: res] @@ -141,7 +141,7 @@ Impl() : Base2 //│ res //│ = 1 -class Impl2() extends Base2, Foo[int] { +class Impl2() extends Base2, Foo[Int] { fun x = 1 } //│ class Impl2() extends Base2, Foo { @@ -162,8 +162,8 @@ trait Test2[A]: Test1[(A, A)] //│ } //│ trait Test2[A]: Test1[(A, A,)] -(t: Test2[int]) => t.x -//│ (t: Test2[int],) -> (int, int,) +(t: Test2[Int]) => t.x +//│ (t: Test2[Int],) -> (Int, Int,) //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 855aa6f756..d5f64389fb 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -2,11 +2,11 @@ -class Foo1(x: int) { +class Foo1(x: Int) { fun test = Foo1(1).x } -//│ class Foo1(x: int) { -//│ fun test: int +//│ class Foo1(x: Int) { +//│ fun test: Int //│ } class Foo2[A](x: A) { @@ -61,13 +61,13 @@ class Foo4 { //│ } :e -class Foo5(x: int) { +class Foo5(x: Int) { fun test = [Foo5(5).test] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.65: fun test = [Foo5(5).test] //│ ╙── ^^^^^ -//│ class Foo5(x: int) { +//│ class Foo5(x: Int) { //│ fun test: (error,) //│ } @@ -127,13 +127,13 @@ class Foo7_A2[A](head: A, tail: Foo7_A[A] | N) { //│ fun test1: A //│ } -class Foo7_2_A[A](head: A, tail: Foo7_A[int] | N) { - fun test1: int | A = if tail is +class Foo7_2_A[A](head: A, tail: Foo7_A[Int] | N) { + fun test1: Int | A = if tail is N then head _ then tail.test1 } -//│ class Foo7_2_A[A](head: A, tail: Foo7_A[int] | N) { -//│ fun test1: A | int +//│ class Foo7_2_A[A](head: A, tail: Foo7_A[Int] | N) { +//│ fun test1: A | Int //│ } :e diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index 61a045e689..59b78c4fcb 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -341,7 +341,7 @@ class C2 extends T2 trait T3[A] { val r = C2().x } -class C2 extends T3[int] +class C2 extends T3[Int] //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.342: val r = C2().x //│ ╙── ^^^^^^^^^^ @@ -367,13 +367,13 @@ C2() : T3['X] //│ where //│ 'X :> error -class C3 extends T3[int] +class C3 extends T3[Int] //│ class C3 extends T3 { //│ let r: error //│ } C3() : T3['X] -//│ T3[int] +//│ T3[Int] @@ -414,7 +414,7 @@ class B extends Foo { fun foo(x) = x + 1 } //│ ╟── type variable `'A` leaks out of its scope //│ ║ l.380: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } //│ ║ ^^ -//│ ╟── into reference of type `int` +//│ ╟── into reference of type `Int` //│ ║ l.410: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^ //│ ╔══[ERROR] Type error in definition of method foo @@ -428,7 +428,7 @@ class B extends Foo { fun foo(x) = x + 1 } //│ ║ l.410: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^^^^^ //│ class B extends Foo { -//│ fun foo: int -> int +//│ fun foo: Int -> Int //│ } diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 9c75a7eead..871b742a14 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -18,11 +18,11 @@ class Foo { fun test = this.x } :e -class Foo(n: int) { fun test = this.x } -//│ ╔══[ERROR] Type `#Foo & {n: int}` does not contain member `x` -//│ ║ l.21: class Foo(n: int) { fun test = this.x } +class Foo(n: Int) { fun test = this.x } +//│ ╔══[ERROR] Type `#Foo & {n: Int}` does not contain member `x` +//│ ║ l.21: class Foo(n: Int) { fun test = this.x } //│ ╙── ^^ -//│ class Foo(n: int) { +//│ class Foo(n: Int) { //│ fun test: error //│ } @@ -51,12 +51,12 @@ class Foo { // TODO // * All on one line: -class Test { this: { x: int}; fun test = this.x } +class Test { this: { x: Int}; fun test = this.x } //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.54: class Test { this: { x: int}; fun test = this.x } +//│ ║ l.54: class Test { this: { x: Int}; fun test = this.x } //│ ╙── ^^ //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.54: class Test { this: { x: int}; fun test = this.x } +//│ ║ l.54: class Test { this: { x: Int}; fun test = this.x } //│ ╙── ^ //│ class Test { //│ fun test: error diff --git a/shared/src/test/diff/nu/TraitParameters.mls b/shared/src/test/diff/nu/TraitParameters.mls index 44a4f36ad3..4673437023 100644 --- a/shared/src/test/diff/nu/TraitParameters.mls +++ b/shared/src/test/diff/nu/TraitParameters.mls @@ -2,9 +2,9 @@ :e -trait Base1(x: int) +trait Base1(x: Int) //│ ╔══[ERROR] trait parameters are not yet supported -//│ ║ l.5: trait Base1(x: int) +//│ ║ l.5: trait Base1(x: Int) //│ ╙── ^^^^^^^^ //│ trait Base1 diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index c0a657ee9a..c02d2fbd4a 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -10,17 +10,17 @@ trait T1[A] { //│ } class C1 extends T1 { - fun f(x: int) = x + fun f(x: Int) = x } //│ class C1 extends T1 { -//│ fun f: (x: int,) -> int +//│ fun f: (x: Int,) -> Int //│ } class C1 extends T1['FigureItOut] { - fun f(x: int) = x + fun f(x: Int) = x } //│ class C1 extends T1 { -//│ fun f: (x: int,) -> int +//│ fun f: (x: Int,) -> Int //│ } let c1 = new C1 @@ -29,7 +29,7 @@ let c1 = new C1 //│ = C1 {} c1.f -//│ (x: int,) -> int +//│ (x: Int,) -> Int //│ res //│ = [Function: f] @@ -39,7 +39,7 @@ c1.f //│ = [Function: f] (c1 : T1['X]).f -//│ int -> int +//│ Int -> Int //│ res //│ = [Function: f] @@ -58,10 +58,10 @@ c1.f //│ where //│ 'f :> 'A -> 'A //│ 'A := 'X -//│ 'X :> int +//│ 'X :> Int //│ <: 'FigureItOut -//│ 'FigureItOut :> int -//│ <: 'X & int +//│ 'FigureItOut :> Int +//│ <: 'X & Int //│ res //│ = [Function: f] @@ -75,7 +75,7 @@ trait T2[A] { val r = C2().f(false) } class C2 extends T2['FigureItOut] { - fun f(x: int) = x + fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.75: val r = C2().f(false) @@ -90,59 +90,59 @@ class C2 extends T2['FigureItOut] { //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.75: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `int` +//│ ╟── reference of type `false` is not an instance of type `Int` //│ ║ l.75: val r = C2().f(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.78: fun f(x: int) = x +//│ ║ l.78: fun f(x: Int) = x //│ ╙── ^^^ //│ trait T2[A] { //│ fun f: A -> A -//│ let r: error | int +//│ let r: Int | error //│ } //│ class C2 extends T2 { -//│ fun f: (x: int,) -> int +//│ fun f: (x: Int,) -> Int //│ } :e -trait T2[A] { +trait T3[A] { fun f: A -> A - val r = (C2() : T2['X]).f(false) + val r = (C3() : T3['X]).f(false) } -class C2 extends T2['FigureItOut] { - fun f(x: int) = x +class C3 extends T3['FigureItOut] { + fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.110: val r = (C2() : T2['X]).f(false) +//│ ║ l.110: val r = (C3() : T3['X]).f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.108: trait T2[A] { +//│ ║ l.108: trait T3[A] { //│ ║ ^^^^^^^^^^^^^ //│ ║ l.109: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.110: val r = (C2() : T2['X]).f(false) +//│ ║ l.110: val r = (C3() : T3['X]).f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.108: trait T2[A] { +//│ ╔══[ERROR] Type `C3` does not contain member `T3#A` +//│ ║ l.108: trait T3[A] { //│ ╙── ^ -//│ trait T2[A] { +//│ trait T3[A] { //│ fun f: A -> A //│ let r: error | false //│ } -//│ class C2 extends T2 { -//│ fun f: (x: int,) -> int +//│ class C3 extends T3 { +//│ fun f: (x: Int,) -> Int //│ } :e // FIXME -C2() : T2['X] -//│ ╔══[ERROR] Type `C2` does not contain member `T2#A` -//│ ║ l.108: trait T2[A] { +C3() : T3['X] +//│ ╔══[ERROR] Type `C3` does not contain member `T3#A` +//│ ║ l.108: trait T3[A] { //│ ╙── ^ -//│ T2['X] +//│ T3['X] //│ where //│ 'X :> error //│ res //│ Runtime error: -//│ TypeError: Class constructor C2 cannot be invoked without 'new' +//│ TypeError: Class constructor C3 cannot be invoked without 'new' diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index 3e909ec9ad..d2b0291346 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -1,25 +1,25 @@ :NewDefs -type I = int -//│ type I = int +type I = Int +//│ type I = Int class CI1 //│ class CI1 // :e -type AI1 = Array[int] -//│ type AI1 = Array[int] +type AI1 = Array[Int] +//│ type AI1 = Array[Int] -type AI2 = Array -//│ type AI2 = Array[int] +type AI2 = Array +//│ type AI2 = Array[Int] :e -type AI3(n) = Array[int] +type AI3(n) = Array[Int] //│ ╔══[ERROR] Type alias definitions cannot have value parameters -//│ ║ l.18: type AI3(n) = Array[int] +//│ ║ l.18: type AI3(n) = Array[Int] //│ ╙── ^^^ -//│ type AI3 = Array[int] +//│ type AI3 = Array[Int] // :e type AI3[A] = Array @@ -53,13 +53,13 @@ a : AI2 //│ res //│ = [ 123, 123, 123 ] -a : AI3[int] -//│ AI3[int] +a : AI3[Int] +//│ AI3[Int] //│ res //│ = [ 123, 123, 123 ] -a : AI4 -//│ AI4[int] +a : AI4 +//│ AI4[Int] //│ res //│ = [ 123, 123, 123 ] diff --git a/shared/src/test/diff/nu/TypeSelections.mls b/shared/src/test/diff/nu/TypeSelections.mls index 8b842f6fe8..4fdae42892 100644 --- a/shared/src/test/diff/nu/TypeSelections.mls +++ b/shared/src/test/diff/nu/TypeSelections.mls @@ -2,18 +2,18 @@ module M { - type T = int -> int - class C(n: int) + type T = Int -> Int + class C(n: Int) fun mkC = C } //│ module M { -//│ class C(n: int) -//│ type T = int -> int -//│ fun mkC: (n: int,) -> C +//│ class C(n: Int) +//│ type T = Int -> Int +//│ fun mkC: (n: Int,) -> C //│ } let x: M.T = id -//│ let x: int -> int +//│ let x: Int -> Int //│ x //│ = [Function: id] diff --git a/shared/src/test/diff/nu/TypeVariables.mls b/shared/src/test/diff/nu/TypeVariables.mls index 642989389a..c7364f1e6b 100644 --- a/shared/src/test/diff/nu/TypeVariables.mls +++ b/shared/src/test/diff/nu/TypeVariables.mls @@ -2,14 +2,14 @@ fun x: 'a -> 'a = succ -//│ fun x: int -> int +//│ fun x: Int -> Int :e fun x: forall 'a; 'a -> 'a = succ //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ //│ ║ ^^^^ -//│ ╟── type `'a` is not an instance of type `int` +//│ ╟── type `'a` is not an instance of type `Int` //│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ //│ ║ ^^ //│ ╟── Note: quantified type variable 'a is defined at: @@ -17,7 +17,7 @@ fun x: forall 'a; 'a -> 'a = succ //│ ╙── ^^ //│ fun x: forall 'a. 'a -> 'a -fun x: [int -> int,] = [id : forall 'a; 'a -> 'a,] -//│ fun x: (int -> int,) +fun x: [Int -> Int,] = [id : forall 'a; 'a -> 'a,] +//│ fun x: (Int -> Int,) diff --git a/shared/src/test/diff/nu/Uninstantiable.mls b/shared/src/test/diff/nu/Uninstantiable.mls new file mode 100644 index 0000000000..5feffb31cc --- /dev/null +++ b/shared/src/test/diff/nu/Uninstantiable.mls @@ -0,0 +1,28 @@ +:NewDefs + + +// FIXME forbid statically +Int +//│ () -> Int +//│ Code generation encountered an error: +//│ unresolved symbol Int + +// FIXME forbid statically +Int() +//│ Int +//│ Code generation encountered an error: +//│ unresolved symbol Int + +// FIXME forbid statically +new Int +//│ Int +//│ Code generation encountered an error: +//│ unresolved symbol Int + +// FIXME forbid statically +module A extends Int +//│ module A extends Int, Num +//│ Code generation encountered an error: +//│ unresolved parent Int. + + diff --git a/shared/src/test/diff/nu/Vals.mls b/shared/src/test/diff/nu/Vals.mls index 7e9a5826b9..4377d8b517 100644 --- a/shared/src/test/diff/nu/Vals.mls +++ b/shared/src/test/diff/nu/Vals.mls @@ -4,7 +4,7 @@ val a = 1 val b = a + 1 //│ let a: 1 -//│ let b: int +//│ let b: Int //│ a //│ = 1 //│ b @@ -15,7 +15,7 @@ val b = a + 1 :ge val c = d + 1 val d = 1 -//│ let c: int +//│ let c: Int //│ let d: 1 //│ Code generation encountered an error: //│ unresolved symbol d diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index a0666a42ad..1c769482d7 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -2,10 +2,10 @@ class Add(lhs: E, rhs: E) -class Lit(n: int) +class Lit(n: Int) class Neg(expr: A) //│ class Add[E](lhs: E, rhs: E) -//│ class Lit(n: int) +//│ class Lit(n: Int) //│ class Neg[A](expr: A) @@ -19,36 +19,36 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ this: {eval: 'expr -> 'a & ('expr0 | 'lhs) -> int} -//│ fun eval: (Add['lhs] | Lit | Neg['expr0 & (Neg['expr] | ~#Neg)]) -> (int | 'a) +//│ this: {eval: 'expr -> 'a & ('expr0 | 'lhs) -> Int} +//│ fun eval: (Add['lhs] | Lit | Neg['expr0 & (Neg['expr] | Object & ~#Neg)]) -> (Int | 'a) //│ } // module TestLang extends EvalBase, EvalNeg module TestLang extends EvalBase //│ module TestLang { -//│ fun eval: forall 'E. (Add['E] | Lit | Neg['expr & (Neg['expr0] | ~#Neg)]) -> int +//│ fun eval: forall 'E. (Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)]) -> Int //│ } //│ where -//│ 'E <: Add['E] | Lit | Neg['expr & (Neg['expr0] | ~#Neg)] -//│ 'expr <: Add['E] | Lit | Neg['expr & (Neg['expr0] | ~#Neg)] -//│ 'expr0 <: Add['E] | Lit | Neg['expr & (Neg['expr0] | ~#Neg)] +//│ 'E <: Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)] +//│ 'expr <: Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)] +//│ 'expr0 <: Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)] fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ fun mk: forall 'E. anything -> 'E +//│ fun mk: forall 'E. Object -> 'E //│ where //│ 'E :> Add['E] | Lit | Neg['E] :stats TestLang.eval(mk(0)) -//│ int +//│ Int //│ res //│ = 0 -//│ constrain calls : 374 +//│ constrain calls : 441 //│ annoying calls : 160 -//│ subtyping calls : 4154 +//│ subtyping calls : 4646 diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls index 3e13cc3cfc..4f291b69e3 100644 --- a/shared/src/test/diff/tapl/NuSimplyTyped.mls +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -10,22 +10,22 @@ fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) fun par(a) = concat3("(", a, ")") -//│ let str: anything -> string -//│ fun concat2: (string, string,) -> string -//│ fun concat3: (string, string, string,) -> string -//│ fun concat4: (string, string, string, string,) -> string -//│ fun concat5: (string, string, string, string, string,) -> string -//│ fun concat6: (string, string, string, string, string, string,) -> string -//│ fun concat7: (string, string, string, string, string, string, string,) -> string -//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string -//│ fun par: string -> string +//│ let str: anything -> Str +//│ fun concat2: (Str, Str,) -> Str +//│ fun concat3: (Str, Str, Str,) -> Str +//│ fun concat4: (Str, Str, Str, Str,) -> Str +//│ fun concat5: (Str, Str, Str, Str, Str,) -> Str +//│ fun concat6: (Str, Str, Str, Str, Str, Str,) -> Str +//│ fun concat7: (Str, Str, Str, Str, Str, Str, Str,) -> Str +//│ fun concat8: (Str, Str, Str, Str, Str, Str, Str, Str,) -> Str +//│ fun par: Str -> Str //│ str //│ = [Function: toString] type Option[A] = Some[A] | None class Some[A](value: A) module None -//│ type Option[A] = Some[A] | None +//│ type Option[A] = None | Some[A] //│ class Some[A](value: A) //│ module None @@ -37,35 +37,35 @@ class Err[A](message: A) //│ class Err[A](message: A) type Type = FunctionType | PrimitiveType -class PrimitiveType(name: string) +class PrimitiveType(name: Str) class FunctionType(lhs: Type, rhs: Type) //│ type Type = FunctionType | PrimitiveType -//│ class PrimitiveType(name: string) +//│ class PrimitiveType(name: Str) //│ class FunctionType(lhs: Type, rhs: Type) // Helpers. fun _f(lhs, rhs) = FunctionType(lhs, rhs) fun _t(name) = PrimitiveType(name) //│ fun _f: (Type, Type,) -> FunctionType -//│ fun _t: string -> PrimitiveType +//│ fun _t: Str -> PrimitiveType type Term = Lit | Var | Abs | App -class Lit(tag: string, ty: Type) -class Var(name: string) +class Lit(tag: Str, ty: Type) +class Var(name: Str) class Abs(lhs: Var, lty: Type, rhs: Term) class App(lhs: Term, rhs: Term) // class App(lhs: Term, rhs: Term): Term //│ type Term = Abs | App | Lit | Var -//│ class Lit(tag: string, ty: Type) -//│ class Var(name: string) +//│ class Lit(tag: Str, ty: Type) +//│ class Var(name: Str) //│ class Abs(lhs: Var, lty: Type, rhs: Term) //│ class App(lhs: Term, rhs: Term) type TreeMap[A] = Node[A] | Empty -class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) +class Node[A](key: Str, value: A, left: TreeMap[A], right: TreeMap[A]) module Empty -//│ type TreeMap[A] = Node[A] | Empty -//│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) +//│ type TreeMap[A] = Empty | Node[A] +//│ class Node[A](key: Str, value: A, left: TreeMap[A], right: TreeMap[A]) //│ module Empty fun insert(t, k, v) = @@ -82,21 +82,21 @@ fun find(t, k) = sgt(k)(k') then find(r, k) _ then Some(v) Empty then None -//│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] -//│ fun find: forall 'A0. (Empty | Node['A0], string,) -> (None | Some['A0]) +//│ fun insert: forall 'A. (Empty | Node['A], Str, 'A,) -> Node['A] +//│ fun find: forall 'A0. (Empty | Node['A0], Str,) -> (None | Some['A0]) fun showType(ty) = if ty is FunctionType(PrimitiveType(name), rhs) then concat3(name, " -> ", showType(rhs)) FunctionType(lhs, rhs) then concat4("(", showType(lhs), ") -> ", showType(rhs)) PrimitiveType(name) then name -//│ fun showType: (FunctionType | PrimitiveType) -> string +//│ fun showType: (FunctionType | PrimitiveType) -> Str showType(_t("int")) showType(_f(_t("int"), _t("bool"))) showType(_f(_f(_t("int"), _t("bool")), _t("bool"))) showType(_f(_t("bool"), _f(_t("int"), _t("bool")))) -//│ string +//│ Str //│ res //│ = 'int' //│ res @@ -112,7 +112,7 @@ fun typeEqual(t1, t2) = t1 is FunctionType(lhs1, rhs1) and t2 is FunctionType(lhs2, rhs2) then typeEqual(lhs1, lhs2) and typeEqual(rhs1, rhs2) _ then false -//│ fun typeEqual: (anything, anything,) -> bool +//│ fun typeEqual: (Object, Object,) -> Bool fun showTerm(t) = if t is @@ -122,13 +122,13 @@ fun showTerm(t) = App(Abs(lhs0, ty, lhs1), rhs) then concat5("((", showTerm(Abs(lhs0, ty, rhs)), ") ", showTerm(rhs), ")") App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) -//│ fun showTerm: (Abs | App | Lit | Var) -> string +//│ fun showTerm: (Abs | App | Lit | Var) -> Str showTerm(Var("x")) showTerm(Abs(Var("x"), _t("int"), Var("y"))) showTerm(App(Var("x"), Var("y"))) showTerm(App(Abs(Var("x"), _t("int"), Var("y")), Var("z"))) -//│ string +//│ Str //│ res //│ = 'x' //│ res @@ -139,7 +139,7 @@ showTerm(App(Abs(Var("x"), _t("int"), Var("y")), Var("z"))) //│ = '((&x: int => z) z)' // Removing the return type annotation causes stack overflow. -fun typeTerm(t: Term, ctx: TreeMap[Type]): Result[Type, string] = +fun typeTerm(t: Term, ctx: TreeMap[Type]): Result[Type, Str] = if t is Lit(_, ty) then Ok(ty) Var(name) and find(ctx, name) is @@ -156,20 +156,20 @@ fun typeTerm(t: Term, ctx: TreeMap[Type]): Result[Type, string] = Err(message) then Err(message) Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) Err(message) then Err(message) -//│ fun typeTerm: (t: Term, ctx: TreeMap[Type],) -> Result[Type, string] +//│ fun typeTerm: (t: Term, ctx: TreeMap[Type],) -> Result[Type, Str] fun showTypeTerm(t, ctx) = if typeTerm(t, ctx) is Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) Err(message) then concat2("Type error: ", message) -//│ fun showTypeTerm: (Term, TreeMap[Type],) -> string +//│ fun showTypeTerm: (Term, TreeMap[Type],) -> Str showTypeTerm(Var("x"), Empty) showTypeTerm(Abs(Var("x"), _t("int"), Var("x")), Empty) showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _f(_t("int"), _t("int")))) showTypeTerm(App(Var("f"), Lit("0.2", _t("float"))), insert(Empty, "f", _f(_t("int"), _t("int")))) -showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _t("string"))) -//│ string +showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _t("Str"))) +//│ Str //│ res //│ = 'Type error: unbound variable `x`' //│ res @@ -179,4 +179,4 @@ showTypeTerm(App(Var("f"), Lit("0", _t("int"))), insert(Empty, "f", _t("string") //│ res //│ = 'Type error: expect the argument to be of type `int` but found `float`' //│ res -//│ = 'Type error: cannot apply primitive type `string`' +//│ = 'Type error: cannot apply primitive type `Str`' diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index 7de1184217..4c144e641e 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -9,22 +9,22 @@ fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) fun par(a) = concat3("(", a, ")") -//│ fun concat2: (string, string,) -> string -//│ fun concat3: (string, string, string,) -> string -//│ fun concat4: (string, string, string, string,) -> string -//│ fun concat5: (string, string, string, string, string,) -> string -//│ fun concat6: (string, string, string, string, string, string,) -> string -//│ fun concat7: (string, string, string, string, string, string, string,) -> string -//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string -//│ fun par: string -> string +//│ fun concat2: (Str, Str,) -> Str +//│ fun concat3: (Str, Str, Str,) -> Str +//│ fun concat4: (Str, Str, Str, Str,) -> Str +//│ fun concat5: (Str, Str, Str, Str, Str,) -> Str +//│ fun concat6: (Str, Str, Str, Str, Str, Str,) -> Str +//│ fun concat7: (Str, Str, Str, Str, Str, Str, Str,) -> Str +//│ fun concat8: (Str, Str, Str, Str, Str, Str, Str, Str,) -> Str +//│ fun par: Str -> Str :escape let String: nothing -let makeString: anything => { length: int, charCodeAt: int => int } = String -let StringInstance: { fromCharCode: int => string } = String +let makeString: anything => { length: Int, charCodeAt: Int => Int } = String +let StringInstance: { fromCharCode: Int => Str } = String //│ let String: nothing -//│ let makeString: anything -> {charCodeAt: int -> int, length: int} -//│ let StringInstance: {fromCharCode: int -> string} +//│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} +//│ let StringInstance: {fromCharCode: Int -> Str} //│ String //│ = //│ makeString @@ -34,13 +34,13 @@ let StringInstance: { fromCharCode: int => string } = String let anythingToString = toString -fun fromCharCode(n: int) = StringInstance.fromCharCode(n) -fun stringCharCodeAt(s: string, i) = makeString(s).charCodeAt(i) -fun stringLength(s: string) = makeString(s).length -//│ let anythingToString: anything -> string -//│ fun fromCharCode: (n: int,) -> string -//│ fun stringCharCodeAt: (s: string, int,) -> int -//│ fun stringLength: (s: string,) -> int +fun fromCharCode(n: Int) = StringInstance.fromCharCode(n) +fun stringCharCodeAt(s: Str, i) = makeString(s).charCodeAt(i) +fun stringLength(s: Str) = makeString(s).length +//│ let anythingToString: anything -> Str +//│ fun fromCharCode: (n: Int,) -> Str +//│ fun stringCharCodeAt: (s: Str, Int,) -> Int +//│ fun stringLength: (s: Str,) -> Int //│ anythingToString //│ = [Function: toString] @@ -51,9 +51,9 @@ class Some[A](value: A) { module None { fun toString() = "None" } -//│ type Option[A] = Some[A] | None +//│ type Option[A] = None | Some[A] //│ class Some[A](value: A) { -//│ fun toString: () -> string +//│ fun toString: () -> Str //│ } //│ module None { //│ fun toString: () -> "None" @@ -89,7 +89,7 @@ fun findFirst(list, p) = Cons(x, xs) and p(x) then Some(x) else findFirst(xs, p) -//│ fun findFirst: forall 'A. (Cons['A] | Nil, 'A -> anything,) -> (None | Some['A]) +//│ fun findFirst: forall 'A. (Cons['A] | Nil, 'A -> Object,) -> (None | Some['A]) fun listConcat(xs, ys) = if xs is @@ -105,7 +105,7 @@ fun listContains(xs, x) = Cons(x', xs') and eq(x)(x') then true _ then listContains(xs', x) -//│ fun listContains: forall 'A. (Cons['A] | Nil, anything,) -> bool +//│ fun listContains: forall 'A. (Cons['A] | Nil, anything,) -> Bool // Remove all occurrences of x from xs. fun listWithout(xs, x) = @@ -130,19 +130,19 @@ fun listJoin(xs, sep) = Cons(x, xs') and xs' is Nil then toString(x) _ then concat3(toString(x), sep, listJoin(xs', sep)) -//│ fun listJoin: forall 'A. (Cons['A] | Nil, string,) -> string +//│ fun listJoin: forall 'A. (Cons['A] | Nil, Str,) -> Str listJoin(list3("x", "y", "z"), ", ") -//│ string +//│ Str //│ res //│ = 'x, y, z' type Term = Var | Abs | App -class Var(name: string) +class Var(name: Str) class Abs(lhs: Var, rhs: Term) class App(lhs: Term, rhs: Term) //│ type Term = Abs | App | Var -//│ class Var(name: string) +//│ class Var(name: Str) //│ class Abs(lhs: Var, rhs: Term) //│ class App(lhs: Term, rhs: Term) @@ -153,13 +153,13 @@ fun showTerm(t) = App(Abs(lhs0, lhs1), rhs) then concat8("((", "&", showTerm(lhs0), ". ", showTerm(lhs1), ") ", showTerm(rhs), ")") App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) -//│ fun showTerm: (Abs | App | Var) -> string +//│ fun showTerm: (Abs | App | Var) -> Str showTerm(Var("x")) showTerm(Abs(Var("x"), Var("y"))) showTerm(App(Var("x"), Var("y"))) showTerm(App(Abs(Var("x"), Var("y")), Var("z"))) -//│ string +//│ Str //│ res //│ = 'x' //│ res @@ -174,12 +174,12 @@ fun isValue(t) = Var then true Abs then true App then false -//│ fun isValue: (Abs | App | Var) -> bool +//│ fun isValue: (Abs | App | Var) -> Bool isValue(Var("x")) isValue(Abs(Var("x"), Var("y"))) isValue(App(Var("x"), Var("y"))) -//│ bool +//│ Bool //│ res //│ = true //│ res @@ -195,11 +195,11 @@ fun hasFree(t, n) = Abs(Var(name), body) then hasFree(body, n) App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) _ then false -//│ fun hasFree: (anything, anything,) -> bool +//│ fun hasFree: (Object, anything,) -> Bool fun showHasFree(t, n) = concat4(showTerm(t), if hasFree(t, n) then " has " else " DOES NOT have ", "free variable ", n) -//│ fun showHasFree: (Abs | App | Var, string,) -> string +//│ fun showHasFree: (Abs | App | Var, Str,) -> Str showHasFree(Var("x"), "x") showHasFree(Var("x"), "y") @@ -213,7 +213,7 @@ showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "x") showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") showHasFree(App(Abs(Var("x"), Var("x")), Var("y")), "y") showHasFree(App(Abs(Var("x"), Var("x")), Var("x")), "y") -//│ string +//│ Str //│ res //│ = 'x has free variable x' //│ res @@ -246,21 +246,21 @@ fun fv(t) = App(lhs, rhs) then listConcat(fv(lhs), fv(rhs)) //│ fun fv: forall 'A. (Abs | App | Var) -> (Cons['A] | Nil) //│ where -//│ 'A :> string +//│ 'A :> Str fun showFv(t) = concat2(showTerm(t), if fv(t) is Nil then " DOES NOT have free variables" _ then concat2(" has free variables: ", listJoin(fv(t), ", ")) ) -//│ fun showFv: (Abs | App | Var) -> string +//│ fun showFv: (Abs | App | Var) -> Str showFv(Var("x")) showFv(Abs(Var("x"), Var("x"))) showFv(Abs(Var("x"), Var("y"))) showFv(App(Var("x"), Var("y"))) showFv(App(Abs(Var("x"), Var("x")), Var("x"))) -//│ string +//│ Str //│ res //│ = 'x has free variables: x' //│ res @@ -280,14 +280,14 @@ fun tryNextAlphabet(initialCode, currentCode, freeNames) = let name = fromCharCode(currentCode) listContains(freeNames, name) then tryNextAlphabet(initialCode, currentCode + 1, freeNames) _ then Some(name) -//│ fun tryNextAlphabet: forall 'A. (number, int, Cons['A] | Nil,) -> (None | Some[string]) +//│ fun tryNextAlphabet: forall 'A. (Num, Int, Cons['A] | Nil,) -> (None | Some[Str]) toString(tryNextAlphabet(97, 97, list1("a"))) toString(tryNextAlphabet(97, 98, list1("a"))) toString(tryNextAlphabet(97, 98, list2("a", "b"))) toString(tryNextAlphabet(121, 122, list1("y"))) toString(tryNextAlphabet(121, 122, list2("y", "z"))) -//│ string +//│ Str //│ res //│ = 'None' //│ res @@ -305,7 +305,7 @@ fun tryAppendDigits(name, index, freeNames) = listContains(freeNames, currentName) then tryAppendDigits(name, index + 1, freeNames) _ then currentName -//│ fun tryAppendDigits: forall 'A. (string, int, Cons['A] | Nil,) -> string +//│ fun tryAppendDigits: forall 'A. (Str, Int, Cons['A] | Nil,) -> Str // Note: some weird behavior here... Just try the commented code. fun findFreshName(name, freeNames) = @@ -315,12 +315,12 @@ fun findFreshName(name, freeNames) = tryNextAlphabet(charCode, charCode + 1, freeNames) is Some(newName) then newName _ then tryAppendDigits(name, 0, freeNames) -//│ fun findFreshName: forall 'A 'A0 'A1. (string, Cons[in 'A1 | 'A | 'A0 out 'A1 & 'A & 'A0] | Nil,) -> string +//│ fun findFreshName: forall 'A 'A0 'A1. (Str, Cons[in 'A | 'A0 | 'A1 out 'A & 'A0 & 'A1] | Nil,) -> Str // Find a fresh name to replace `name` that does not conflict with any bound // variables in the `body`. fun freshName(name, body) = findFreshName(name, fv(body)) -//│ fun freshName: (string, Abs | App | Var,) -> string +//│ fun freshName: (Str, Abs | App | Var,) -> Str fun subst(t, n, v) = if t is @@ -331,11 +331,11 @@ fun subst(t, n, v) = _ then Abs(Var(name), subst(body, n, v)) App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t -//│ fun subst: forall 'a. (Abs | App | Var | Term & 'a & ~#Abs & ~#App & ~#Var, anything, Term & 'a,) -> (Abs | App | Var | 'a) +//│ fun subst: forall 'a. (Abs | App | Term & Object & 'a & ~#Abs & ~#App & ~#Var | Var, anything, Term & Object & 'a,) -> (Abs | App | Var | 'a) fun showSubst(t, n, v) = concat8(showTerm(t), " [", n, " / ", showTerm(v), "]", " => ", showTerm(subst(t, n, v))) -//│ fun showSubst: (Abs | App | Var, string, Abs & Term | App & Term | Var & Term,) -> string +//│ fun showSubst: (Abs | App | Var, Str, Abs & Term | App & Term | Var & Term,) -> Str showSubst(Var("x"), "x", Var("y")) showSubst(Abs(Var("x"), Var("x")), "x", Var("z")) @@ -343,7 +343,7 @@ showSubst(App(Var("x"), Var("y")), "x", Abs(Var("x"), Var("x"))) showSubst(App(Abs(Var("x"), Var("x")), Var("x")), "x", Abs(Var("y"), Var("y"))) showSubst(Abs(Var("x"), App(Var("x"), Var("y"))), "y", Var("x")) showSubst(Abs(Var("z"), Abs(Var("x"), App(Var("z"), App(Var("x"), Var("y"))))), "y", Var("x")) -//│ string +//│ Str //│ res //│ = 'x [x / y] => y' //│ res @@ -369,13 +369,13 @@ class Stepped(from: Term, to: Term) { } //│ type Result = Normal | Stepped | Stuck //│ class Normal(term: Term) { -//│ fun toString: () -> string +//│ fun toString: () -> Str //│ } //│ class Stuck(term: Term, part: Term) { -//│ fun toString: () -> string +//│ fun toString: () -> Str //│ } //│ class Stepped(from: Term, to: Term) { -//│ fun toString: () -> string +//│ fun toString: () -> Str //│ } fun stepByValue(t) = @@ -398,7 +398,7 @@ toString of stepByValue of Abs(Var("x"), Var("y")) toString of stepByValue of App(Var("x"), Var("y")) toString of stepByValue of App(Abs(Var("x"), Var("x")), Var("x")) toString of stepByValue of App(Abs(Var("x"), Var("x")), Abs(Var("y"), Var("y"))) -//│ string +//│ Str //│ res //│ = 'Stuck: x in x' //│ res @@ -427,7 +427,7 @@ toString of stepByValue of App(succ, zero) //│ let zero: Abs //│ let one: Abs //│ let succ: Abs -//│ string +//│ Str //│ zero //│ = Abs {} //│ one @@ -445,7 +445,7 @@ toString of stepByValue of App(succ, zero) toString of evalByValue of App(succ, App(succ, zero)) toString of evalByValue of App(succ, App(succ, App(succ, App(succ, zero)))) -//│ string +//│ Str //│ res //│ = 'Normal form: &f. &x. (f (((&f. &x. (f (((&f. &x. x) f) x))) f) x))' //│ res @@ -457,4 +457,4 @@ fun equalTerm(a, b) = Abs(la, ra) and b is Abs(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) App(la, ra) and b is App(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) _ then false -//│ fun equalTerm: (anything, anything,) -> bool +//│ fun equalTerm: (Object, Object,) -> Bool diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls index 4dbba3420c..0d3b14e0ea 100644 --- a/shared/src/test/diff/tapl/Untyped.mls +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -113,7 +113,7 @@ fun listContains(xs, x) = Cons(x', xs') and eq(x)(x') then true _ then listContains(xs', x) -//│ listContains: ('tail, anything,) -> bool +//│ listContains: ('tail, anything,) -> Bool //│ where //│ 'tail <: Cons & {tail: 'tail} | Nil //│ = [Function: listContains] @@ -192,17 +192,17 @@ fun isValue(t) = Var then true Abs then true App then false -//│ isValue: (Abs | App | Var) -> bool +//│ isValue: (Abs | App | Var) -> Bool //│ = [Function: isValue] isValue(Var("x")) isValue(Abs(Var("x"), Var("y"))) isValue(App(Var("x"), Var("y"))) -//│ res: bool +//│ res: Bool //│ = true -//│ res: bool +//│ res: Bool //│ = true -//│ res: bool +//│ res: Bool //│ = false fun hasFree(t, n) = @@ -396,13 +396,13 @@ fun showSubst(t, n, v) = //│ where //│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var //│ 'rhs0 <: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var -//│ 'a <: 'lhs & 'rhs2 & 'rhs1 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'b | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'c | {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'c <: 'lhs & 'rhs2 & 'rhs1 & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'd <: 'lhs & 'rhs2 & 'rhs1 & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) +//│ 'a <: 'rhs2 & 'rhs1 & 'lhs & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'b | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'c | {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'c <: 'rhs2 & 'rhs1 & 'lhs & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) +//│ 'd <: 'rhs2 & 'rhs1 & 'lhs & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) //│ 'b <: {lhs: 'rhs0, rhs: 'rhs0} //│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var -//│ 'lhs <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | ~Abs //│ 'rhs2 <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | App & {lhs: 'lhs & 'rhs2, rhs: 'rhs2} | Var +//│ 'lhs <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | ~Abs //│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var //│ = [Function: showSubst] diff --git a/shared/src/test/diff/typegen/TypegenTerms.mls b/shared/src/test/diff/typegen/TypegenTerms.mls index cfa6f9b1bd..880ab62f9f 100644 --- a/shared/src/test/diff/typegen/TypegenTerms.mls +++ b/shared/src/test/diff/typegen/TypegenTerms.mls @@ -66,7 +66,7 @@ rec def l (a: int) = l rec def m (a: int) (b: int) = m def f: ('c -> 'a as 'a) -> 'c -> int // recursion type functions -//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α111,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))))),α111),Top))) List() +//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α109,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))))),α109),Top))) List() :ts :e @@ -152,6 +152,6 @@ def weird: ((int, int) -> 'a) as 'a def weird: ('a -> (int, int)) as 'a def weird: ((int, 'a) as 'a) -> int def weird: ((int, bool) | 'a) -> 'a -//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α234,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))), (None,Field(None,TypeName(int))))),α234),Top))) List() +//│ /!!!\ Uncaught error: mlscript.codegen.CodeGenError: Cannot generate type for `where` clause List((α232,Bounds(Function(Tuple(List((None,Field(None,TypeName(int))), (None,Field(None,TypeName(int))))),α232),Top))) List() diff --git a/shared/src/test/diff/ucs/DirectLines.mls b/shared/src/test/diff/ucs/DirectLines.mls index ec7cad0909..ccfa61f7d1 100644 --- a/shared/src/test/diff/ucs/DirectLines.mls +++ b/shared/src/test/diff/ucs/DirectLines.mls @@ -22,7 +22,7 @@ class None: Option //│ = [Function: None1] fun isValid(x) = if x then false else true -//│ isValid: anything -> bool +//│ isValid: anything -> Bool //│ = [Function: isValid] fun f(x, allowNone) = diff --git a/shared/src/test/diff/ucs/ElseIf.mls b/shared/src/test/diff/ucs/ElseIf.mls index 54d3585433..3a7d47bdcd 100644 --- a/shared/src/test/diff/ucs/ElseIf.mls +++ b/shared/src/test/diff/ucs/ElseIf.mls @@ -3,69 +3,69 @@ -fun f(x, y) = if x == +fun f(x, y) = if x === 0 then true 1 then false - else if y == + else if y === 0 then true 1 then false else false -//│ fun f: (number, number,) -> bool +//│ fun f: (Eql[nothing], Eql[nothing],) -> Bool -fun f(x, y) = if x == +fun f(x, y) = if x === 0 then true 1 then false - else if y == + else if y === 0 then true _ then false -//│ fun f: (number, number,) -> bool +//│ fun f: (Eql[nothing], Eql[0],) -> Bool -module True -module False -//│ module True -//│ module False +module Tru +module Fals +//│ module Tru +//│ module Fals :e :ge fun f(x, y) = if x is - True and y is True then true - False and y is False then false + Tru and y is Tru then true + Fals and y is Fals then false //│ ╔══[ERROR] The match is not exhaustive. -//│ ║ l.31: True and y is True then true -//│ ║ ^^^^^^^^^ +//│ ║ l.31: Tru and y is Tru then true +//│ ║ ^^^^^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.31: True and y is True then true -//│ ║ ^ -//│ ╟── [Missing Case 1/1] `False` +//│ ║ l.31: Tru and y is Tru then true +//│ ║ ^ +//│ ╟── [Missing Case 1/1] `Fals` //│ ╟── It first appears here. -//│ ║ l.32: False and y is False then false -//│ ╙── ^^^^^ +//│ ║ l.32: Fals and y is Fals then false +//│ ╙── ^^^^ //│ fun f: (anything, anything,) -> error //│ Code generation encountered an error: //│ if expression was not desugared // The base case. fun f(x, y) = if x is - True and y is True then true - False and y is False then false - True and y is False then true - False and y is True then true -//│ fun f: (False | True, False | True,) -> bool + Tru and y is Tru then true + Fals and y is Fals then false + Tru and y is Fals then true + Fals and y is Tru then true +//│ fun f: (Fals | Tru, Fals | Tru,) -> Bool -// Replace the `x is False` with `_` +// Replace the `x is Fals` with `_` fun f(x, y) = if x is - True and y is True then true - False and y is False then false + Tru and y is Tru then true + Fals and y is Fals then false _ and y is - True then true - False then false -//│ fun f: (anything, False | True,) -> bool + Tru then true + Fals then false +//│ fun f: (Object, Fals | Tru,) -> Bool -f(True, True) -f(True, False) -f(False, True) -f(False, False) -//│ bool +f(Tru, Tru) +f(Tru, Fals) +f(Fals, Tru) +f(Fals, Fals) +//│ Bool //│ res //│ = true //│ res @@ -82,28 +82,28 @@ fun g(x, y) = if x is _ and y is true then true false then false -//│ fun g: (anything, bool,) -> bool +//│ fun g: (Object, nothing,) -> Bool // Chained UCS terms fun f(x, y) = if x is - True and y is True then true - False and y is False then false + Tru and y is Tru then true + Fals and y is Fals then false else if y is - True then true - False then false -//│ fun f: (anything, False | True,) -> bool + Tru then true + Fals then false +//│ fun f: (Object, Fals | Tru,) -> Bool fun f(x, y) = if x is - True and y is True then true - False and y is False then false + Tru and y is Tru then true + Fals and y is Fals then false else if y is - True and x is False then true - False and x is True then false -//│ fun f: (False | True, False | True,) -> bool + Tru and x is Fals then true + Fals and x is Tru then false +//│ fun f: (Fals | Tru, Fals | Tru,) -> Bool fun h(x, y, p) = if x and p(x) then 0 y is - True then 1 - False then 2 -//│ fun h: (anything, False | True, true -> anything,) -> (0 | 1 | 2) + Tru then 1 + Fals then 2 +//│ fun h: (Object, Fals | Tru, true -> Object,) -> (0 | 1 | 2) diff --git a/shared/src/test/diff/ucs/Exhaustiveness.mls b/shared/src/test/diff/ucs/Exhaustiveness.mls index 4f80c223fb..6011dd48bc 100644 --- a/shared/src/test/diff/ucs/Exhaustiveness.mls +++ b/shared/src/test/diff/ucs/Exhaustiveness.mls @@ -57,7 +57,7 @@ class Node[A](value: int, left: Tree[A], right: Tree[A]) { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.49: == value then true //│ ╙── ^^^^^^^^^^^^ -//│ type Tree[A] = Node[A] | Empty +//│ type Tree[A] = Empty | Node[A] //│ module Empty { //│ fun contains: anything -> false //│ } diff --git a/shared/src/test/diff/ucs/Hygiene.mls b/shared/src/test/diff/ucs/Hygiene.mls index 9dbe128a34..8929c672d1 100644 --- a/shared/src/test/diff/ucs/Hygiene.mls +++ b/shared/src/test/diff/ucs/Hygiene.mls @@ -11,7 +11,7 @@ class Right[T](value: T) fun foo(x) = if x is Some(Left(y)) then x Some(x) then x -//│ fun foo: forall 'value. Some['value & (Left[anything] | ~#Left)] -> 'value +//│ fun foo: forall 'value. Some['value & (Left[anything] | Object & ~#Left)] -> 'value foo(Some(Left(1))) //│ Left[1] diff --git a/shared/src/test/diff/ucs/HygienicBindings.mls b/shared/src/test/diff/ucs/HygienicBindings.mls index 724fd49dea..c0553e08a0 100644 --- a/shared/src/test/diff/ucs/HygienicBindings.mls +++ b/shared/src/test/diff/ucs/HygienicBindings.mls @@ -3,7 +3,7 @@ type Option[out T] = None | Some[T] module None class Some[out T](value: T) -//│ type Option[T] = Some[T] | None +//│ type Option[T] = None | Some[T] //│ module None //│ class Some[T](value: T) @@ -120,7 +120,7 @@ fun h2(a) = //│ ╔══[ERROR] identifier not found: y //│ ║ l.114: let y' = y //│ ╙── ^ -//│ fun h2: forall 'leftValue. (None | Some[Left['leftValue] | ~Left[anything]]) -> (0 | error | 'leftValue) +//│ fun h2: forall 'leftValue. (None | Some[Left['leftValue] | Object & ~#Left]) -> (0 | error | 'leftValue) //│ Code generation encountered an error: //│ unresolved symbol y @@ -133,7 +133,7 @@ fun h3(x, y, f, p) = h3("anything", "not me", _ => "should be me", _ => true) h3(None, "should be me", _ => "not me", _ => false) h3("anything", "anything", _ => "not me", _ => false) -//│ fun h3: forall 'a 'b. (None | 'a & ~#None, 'b, (None | 'a) -> anything, (None | 'a) -> anything,) -> ("anyway" | 'b) +//│ fun h3: forall 'a 'b. (None | Object & 'b & ~#None, 'a, (None | 'b) -> anything, (None | 'b) -> Object,) -> ("anyway" | 'a) //│ "anything" | "anyway" //│ res //│ = [Function: h3] @@ -152,7 +152,7 @@ h4("should be me", "not me", _ => true) // WRONG! h4(None, "not me", _ => true) // WRONG! h4(None, "should be me", _ => false) h4("anything", "not me", _ => false) -//│ fun h4: forall 'a 'b. (None | 'a & ~#None, 'b, (None | 'a) -> anything,) -> ("default" | 'b) +//│ fun h4: forall 'a 'b. (None | Object & 'a & ~#None, 'b, (None | 'a) -> Object,) -> ("default" | 'b) //│ "default" | "not me" //│ res //│ = [Function: h4] diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index 0fa5c29a92..b118c5d72f 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -4,14 +4,14 @@ :escape // We need to use some native methods on `String`. let String: nothing -let asNativeString: anything => { length: int, charCodeAt: int => int, charAt: int => string, slice: int => string } = String -let StringInstance: { fromCharCode: int => string } = String +let asNativeString: anything => { length: Int, charCodeAt: Int => Int, charAt: Int => Str, slice: Int => Str } = String +let StringInstance: { fromCharCode: Int => Str } = String // We will validate our implementation with the built-in `JSON.parse`. -let JSON: { parse: string => anything, stringify: anything => string } +let JSON: { parse: Str => anything, stringify: anything => Str } //│ let String: nothing -//│ let asNativeString: anything -> {charAt: int -> string, charCodeAt: int -> int, length: int, slice: int -> string} -//│ let StringInstance: {fromCharCode: int -> string} -//│ let JSON: {parse: string -> anything, stringify: anything -> string} +//│ let asNativeString: anything -> {charAt: Int -> Str, charCodeAt: Int -> Int, length: Int, slice: Int -> Str} +//│ let StringInstance: {fromCharCode: Int -> Str} +//│ let JSON: {parse: Str -> anything, stringify: anything -> Str} //│ String //│ = //│ asNativeString @@ -33,13 +33,13 @@ fun getCharAtIndex(s, i) = asNativeString(s).charAt(i) fun strlen(s) = asNativeString(s).length fun stringHead(s) = asNativeString(s).charAt(0) fun stringTail(s) = asNativeString(s).slice(1) -//│ let getStringOf: anything -> string -//│ fun fromCharCode: int -> string -//│ fun firstCharCode: anything -> int -//│ fun getCharAtIndex: (anything, int,) -> string -//│ fun strlen: anything -> int -//│ fun stringHead: anything -> string -//│ fun stringTail: anything -> string +//│ let getStringOf: anything -> Str +//│ fun fromCharCode: Int -> Str +//│ fun firstCharCode: anything -> Int +//│ fun getCharAtIndex: (anything, Int,) -> Str +//│ fun strlen: anything -> Int +//│ fun stringHead: anything -> Str +//│ fun stringTail: anything -> Str //│ getStringOf //│ = [Function: toString] @@ -49,12 +49,12 @@ fun isWhiteSpace(ch) = 10 then true // linefeed 32 then true // space _ then false -//│ fun isWhiteSpace: anything -> bool +//│ fun isWhiteSpace: anything -> Bool fun isDigit(ch) = let n = firstCharCode of ch if 48 <= n and n <= 57 then true else false -//│ fun isDigit: anything -> bool +//│ fun isDigit: anything -> Bool fun isAlphabet(ch) = let n = firstCharCode of ch @@ -62,7 +62,7 @@ fun isAlphabet(ch) = 90 and n >= 65 then true 122 and n >= 97 then true else false -//│ fun isAlphabet: anything -> bool +//│ fun isAlphabet: anything -> Bool fun concat2(a, b) = concat(a)(b) fun concat3(a, b, c) = concat2(a, concat2(b, c)) @@ -72,19 +72,19 @@ fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) fun par(a) = concat3("(", a, ")") -//│ fun concat2: (string, string,) -> string -//│ fun concat3: (string, string, string,) -> string -//│ fun concat4: (string, string, string, string,) -> string -//│ fun concat5: (string, string, string, string, string,) -> string -//│ fun concat6: (string, string, string, string, string, string,) -> string -//│ fun concat7: (string, string, string, string, string, string, string,) -> string -//│ fun concat8: (string, string, string, string, string, string, string, string,) -> string -//│ fun par: string -> string +//│ fun concat2: (Str, Str,) -> Str +//│ fun concat3: (Str, Str, Str,) -> Str +//│ fun concat4: (Str, Str, Str, Str,) -> Str +//│ fun concat5: (Str, Str, Str, Str, Str,) -> Str +//│ fun concat6: (Str, Str, Str, Str, Str, Str,) -> Str +//│ fun concat7: (Str, Str, Str, Str, Str, Str, Str,) -> Str +//│ fun concat8: (Str, Str, Str, Str, Str, Str, Str, Str,) -> Str +//│ fun par: Str -> Str type Option[A] = Some[A] | None module None class Some[A](value: A) -//│ type Option[A] = Some[A] | None +//│ type Option[A] = None | Some[A] //│ module None //│ class Some[A](value: A) @@ -105,13 +105,13 @@ fun listJoin(xs, sep) = //│ module Nil //│ class Cons[A](head: A, tail: List[A]) //│ fun listConcat: forall 'A 'A0 'a. (Cons['A] | Nil, List['A0] & 'a,) -> (Cons['A0] | 'a) -//│ fun listJoin: forall 'A1. (Cons['A1] | Nil, string,) -> string +//│ fun listJoin: forall 'A1. (Cons['A1] | Nil, Str,) -> Str //│ where //│ 'A <: 'A0 type TreeMap[A] = Node[A] | Empty module Empty -class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) +class Node[A](key: Str, value: A, left: TreeMap[A], right: TreeMap[A]) fun insert(t, k, v) = if t is Node(k', _, l, r) and @@ -131,24 +131,24 @@ fun traverse(t, f) = Empty then Nil Node(key, value, left, right) then listConcat(traverse(left, f), Cons(f(key, value), traverse(right, f))) -//│ type TreeMap[A] = Node[A] | Empty +//│ type TreeMap[A] = Empty | Node[A] //│ module Empty -//│ class Node[A](key: string, value: A, left: TreeMap[A], right: TreeMap[A]) -//│ fun insert: forall 'A. (Empty | Node['A], string, 'A,) -> Node['A] -//│ fun find: forall 'A0. (Empty | Node['A0], string,) -> (None | Some['A0]) -//│ fun traverse: forall 'A1 'A2. (Empty | Node['A1], (string, 'A1,) -> 'A2,) -> (Cons['A2] | Nil) +//│ class Node[A](key: Str, value: A, left: TreeMap[A], right: TreeMap[A]) +//│ fun insert: forall 'A. (Empty | Node['A], Str, 'A,) -> Node['A] +//│ fun find: forall 'A0. (Empty | Node['A0], Str,) -> (None | Some['A0]) +//│ fun traverse: forall 'A1 'A2. (Empty | Node['A1], (Str, 'A1,) -> 'A2,) -> (Cons['A2] | Nil) type JsonValue = JsonNull | JsonNumber | JsonString | JsonBoolean | JsonObject | JsonArray module JsonNull { fun toString() = "null" } -class JsonBoolean(value: bool) { +class JsonBoolean(value: Bool) { fun toString() = getStringOf(value) } -class JsonNumber(value: number) { +class JsonNumber(value: Num) { fun toString() = getStringOf(value) } -class JsonString(value: string) { +class JsonString(value: Str) { fun toString() = JSON.stringify(value) } class JsonObject(entries: TreeMap[JsonValue]) { @@ -159,24 +159,24 @@ class JsonObject(entries: TreeMap[JsonValue]) { class JsonArray(elements: List[JsonValue]) { fun toString() = concat3("[", listJoin(elements, ", "), "]") } -//│ type JsonValue = JsonArray | JsonBoolean | JsonNumber | JsonObject | JsonString | JsonNull +//│ type JsonValue = JsonArray | JsonBoolean | JsonNull | JsonNumber | JsonObject | JsonString //│ module JsonNull { //│ fun toString: () -> "null" //│ } -//│ class JsonBoolean(value: bool) { -//│ fun toString: () -> string +//│ class JsonBoolean(value: Bool) { +//│ fun toString: () -> Str //│ } -//│ class JsonNumber(value: number) { -//│ fun toString: () -> string +//│ class JsonNumber(value: Num) { +//│ fun toString: () -> Str //│ } -//│ class JsonString(value: string) { -//│ fun toString: () -> string +//│ class JsonString(value: Str) { +//│ fun toString: () -> Str //│ } //│ class JsonObject(entries: TreeMap[JsonValue]) { -//│ fun toString: () -> string +//│ fun toString: () -> Str //│ } //│ class JsonArray(elements: List[JsonValue]) { -//│ fun toString: () -> string +//│ fun toString: () -> Str //│ } toString of JsonNull @@ -187,7 +187,7 @@ toString of JsonArray of Nil toString of JsonArray of Cons(JsonNumber(0), Cons(JsonNull, Cons(JsonNumber(1), Nil))) toString of JsonObject of Empty toString of JsonObject of insert(Empty, "hello", JsonString("world")) -//│ string +//│ Str //│ res //│ = 'null' //│ res @@ -205,8 +205,8 @@ toString of JsonObject of insert(Empty, "hello", JsonString("world")) //│ res //│ = '{ hello: "world" }' -class Scanner(source: string, at: int) { - fun peek: Option[string] = +class Scanner(source: Str, at: Int) { + fun peek: Option[Str] = if at < strlen(source) then Some(getCharAtIndex(source, at)) else None fun advance: Scanner = if at < strlen(source) then Scanner(source, at + 1) else this @@ -217,26 +217,26 @@ fun skipWhiteSpace(s: Scanner) = skipWhiteSpace(s.advance) else s -//│ class Scanner(source: string, at: int) { +//│ class Scanner(source: Str, at: Int) { //│ fun advance: Scanner -//│ fun peek: Option[string] +//│ fun peek: Option[Str] //│ } -//│ fun scan: string -> Scanner +//│ fun scan: Str -> Scanner //│ fun skipWhiteSpace: (s: Scanner,) -> Scanner type ParseResult[T] = ParseSuccess[T] | ParseFailure class ParseSuccess[T](value: T, scanner: Scanner) { fun toString() = concat2("Success: ", getStringOf(value)) } -class ParseFailure(message: string, scanner: Scanner) { +class ParseFailure(message: Str, scanner: Scanner) { fun toString() = concat4("Failure at ", getStringOf(scanner.at), ": ", message) } //│ type ParseResult[T] = ParseFailure | ParseSuccess[T] //│ class ParseSuccess[T](value: T, scanner: Scanner) { -//│ fun toString: () -> string +//│ fun toString: () -> Str //│ } -//│ class ParseFailure(message: string, scanner: Scanner) { -//│ fun toString: () -> string +//│ class ParseFailure(message: Str, scanner: Scanner) { +//│ fun toString: () -> Str //│ } fun expect(scanner, ch) = @@ -245,7 +245,7 @@ fun expect(scanner, ch) = eq(ch)(ch') then ParseSuccess((), scanner.advance) else ParseFailure(concat4("expect '", ch, "' but found ", ch'), scanner) None then ParseFailure(concat3("expect '", ch, "' but found EOF"), scanner) -//│ fun expect: (Scanner & {advance: Scanner}, string,) -> (ParseFailure | ParseSuccess[()]) +//│ fun expect: (Scanner & {advance: Scanner}, Str,) -> (ParseFailure | ParseSuccess[()]) fun expectWord(scanner, word, result) = if @@ -260,7 +260,7 @@ fun expectWord(scanner, word, result) = ParseFailure(concat3("there should not be other alphabets after\"", word, "\""), scanner) else ParseSuccess(result, scanner) -//│ fun expectWord: forall 'T. (Scanner & {peek: anything, advance: Scanner}, string, 'T,) -> (ParseFailure | ParseSuccess['T]) +//│ fun expectWord: forall 'T. (Scanner & {peek: Object & ~#Some | Some[anything], advance: Scanner}, Str, 'T,) -> (ParseFailure | ParseSuccess['T]) // If we put this function together with the next block, there will be type // mismatch errors. @@ -270,7 +270,7 @@ fun parseMatched(scanner, closingSymbol, parse, fn) = ParseSuccess(_, scanner) then ParseSuccess(fn(outcome), scanner) ParseFailure(message, scanner) then ParseFailure(message, scanner) ParseFailure(message, scanner) then ParseFailure(message, scanner) -//│ fun parseMatched: forall 'advance 'value 'T. ({advance: 'advance}, string, 'advance -> (ParseFailure | ParseSuccess['value]), 'value -> 'T,) -> (ParseFailure | ParseSuccess['T]) +//│ fun parseMatched: forall 'advance 'value 'T. ({advance: 'advance}, Str, 'advance -> (ParseFailure | ParseSuccess['value]), 'value -> 'T,) -> (ParseFailure | ParseSuccess['T]) :ng fun parseEntries(scanner): ParseResult[TreeMap[JsonValue]] = error @@ -287,7 +287,7 @@ fun parseElements(scanner): ParseResult[List[JsonValue]] = _ then ParseFailure("expect ']' or ',' instead of EOF", scanner') ParseFailure(m, s) then ParseFailure(m, s) None then ParseFailure("unexpected EOF", scanner) -fun parseStringContent(scanner): ParseResult[string] = error +fun parseStringContent(scanner): ParseResult[Str] = error fun parseNumber(scanner): ParseResult[JsonNumber] = error fun parse(scanner) = let scanner' = skipWhiteSpace(scanner) @@ -305,7 +305,7 @@ fun parse(scanner) = ParseFailure(concat3("unrecognized character '", ch, "'"), scanner) //│ fun parseEntries: anything -> ParseResult[TreeMap[JsonValue]] //│ fun parseElements: Scanner -> ParseResult[List[JsonValue]] -//│ fun parseStringContent: anything -> ParseResult[string] +//│ fun parseStringContent: anything -> ParseResult[Str] //│ fun parseNumber: anything -> ParseResult[JsonNumber] //│ fun parse: Scanner -> (ParseFailure | ParseSuccess[JsonArray | JsonBoolean | JsonNull | JsonObject | JsonString] | ParseResult[JsonNumber]) @@ -314,4 +314,4 @@ toString of parse of scan of " true" toString of parse of scan of " false" toString of parse of scan of " null" toString of parse of scan of "[null]" -//│ string +//│ Str diff --git a/shared/src/test/diff/ucs/LeadingAnd.mls b/shared/src/test/diff/ucs/LeadingAnd.mls index 194cbe59de..7578eff00e 100644 --- a/shared/src/test/diff/ucs/LeadingAnd.mls +++ b/shared/src/test/diff/ucs/LeadingAnd.mls @@ -24,7 +24,7 @@ fun f(a, b) = if a is Some(av) then av + bv //│ |#fun| |f|(|a|,| |b|)| |#=| |#if| |a| |is| |Some|(|av|)|→|and| |b| |is| |Some|(|bv|)|↵|#then| |av| |+| |bv|←| //│ Parsed: fun f = (a, b,) => if a is Some (av,) ‹· and (is (b,) (Some (bv,),)) then + (av,) (bv,)›; -//│ fun f: (Some[int], Some[int],) -> int +//│ fun f: (Some[Int], Some[Int],) -> Int // TODO :p diff --git a/shared/src/test/diff/ucs/MultiwayIf.mls b/shared/src/test/diff/ucs/MultiwayIf.mls index e7d8c01ebe..6add8f28e5 100644 --- a/shared/src/test/diff/ucs/MultiwayIf.mls +++ b/shared/src/test/diff/ucs/MultiwayIf.mls @@ -1,4 +1,4 @@ -:NewParser +:NewDefs fun f(x) = @@ -6,8 +6,7 @@ fun f(x) = x > 0 then 0 x == 0 then 1 _ then 2 -//│ f: number -> (0 | 1 | 2) -//│ = [Function: f] +//│ fun f: Num -> (0 | 1 | 2) fun f(x) = @@ -17,24 +16,24 @@ fun f(x) = _ then false x == 0 then true _ then false -//│ f: int -> bool -//│ = [Function: f1] +//│ fun f: Int -> Bool f(0) f(2) f(3) f(0 - 1) f(0 - 2) -//│ res: bool -//│ = true -//│ res: bool -//│ = true -//│ res: bool -//│ = false -//│ res: bool -//│ = false -//│ res: bool -//│ = false +//│ Bool +//│ res +//│ = true +//│ res +//│ = true +//│ res +//│ = false +//│ res +//│ = false +//│ res +//│ = false fun f(x) = if @@ -43,18 +42,18 @@ fun f(x) = else false x == 0 then true else false -//│ f: int -> bool -//│ = [Function: f2] +//│ fun f: Int -> Bool f(0) f(2) f(1) f(0 - 1) -//│ res: bool -//│ = true -//│ res: bool -//│ = true -//│ res: bool -//│ = false -//│ res: bool -//│ = false +//│ Bool +//│ res +//│ = true +//│ res +//│ = true +//│ res +//│ = false +//│ res +//│ = false diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index 059b0fa627..8cc54c1647 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -32,7 +32,7 @@ let zeroToThree = Cons(0, Cons(1, Cons(2, Cons(3, Nil)))) //│ = Cons {} fun f(x) = if x % 2 == 0 then Left(x) else Right(x) -//│ fun f: forall 'A. (int & 'A) -> (Left['A] | Right['A]) +//│ fun f: forall 'A. (Int & 'A) -> (Left['A] | Right['A]) fun mapPartition(f, xs) = if xs is Nil then Pair(Nil, Nil) @@ -44,7 +44,7 @@ fun mapPartition(f, xs) = if xs is mapPartition(x => Left(x + 1), zeroToThree) //│ Pair[Cons['A] | Nil, Cons['A0] | Nil] //│ where -//│ 'A :> int +//│ 'A :> Int //│ res //│ = Pair {} @@ -85,7 +85,7 @@ fun mapPartition(f, xs) = if xs is Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ fun mapPartition: forall 'A 'head 'A0. ('head -> (Left['A0] | Right['A]), Cons['head] | Nil,) -> Pair[Cons['A0] | Nil, Cons['A] | Nil] +//│ fun mapPartition: forall 'head 'A 'A0. ('head -> (Left['A] | Right['A0]), Cons['head] | Nil,) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(f, zeroToThree) //│ Pair[Cons['A] | Nil, Cons['A0] | Nil] @@ -136,6 +136,30 @@ fun mapPartition(f, xs) = if xs is //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.124: fun mapPartition(f, xs) = if xs is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.125: Nil then (Nil, Nil) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.126: Cons(x, xs) and mapPartition(f, xs) is (l, r) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.127: and f(x) is Left(v) then (Cons(v, l), r) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.128: Right(v) then (l, Cons(v, r)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── tuple literal of type `(Nil, Nil,)` is not an instance of type `Object` +//│ ║ l.125: Nil then (Nil, Nil) +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from `case` expression: +//│ ║ l.126: Cons(x, xs) and mapPartition(f, xs) is (l, r) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.127: and f(x) is Left(v) then (Cons(v, l), r) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.128: Right(v) then (l, Cons(v, r)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from application: +//│ ║ l.126: Cons(x, xs) and mapPartition(f, xs) is (l, r) +//│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun mapPartition: forall 'A. (anything, Cons['A] | Nil,) -> ((Nil, Nil,) | error) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 diff --git a/shared/src/test/diff/ucs/PlainConditionals.mls b/shared/src/test/diff/ucs/PlainConditionals.mls index 21c0a7d659..50eaa488a0 100644 --- a/shared/src/test/diff/ucs/PlainConditionals.mls +++ b/shared/src/test/diff/ucs/PlainConditionals.mls @@ -9,24 +9,24 @@ class Pair(fst, snd) Pair(0, 1) is Pair -//│ res: bool +//│ res: Bool //│ = true Pair(0, 1) is Pair(a, b) -//│ res: bool +//│ res: Bool //│ = true Pair(0, 1) is Pair(0, _) -//│ res: bool +//│ res: Bool //│ = true if Pair(0, 1) is Pair(a, b) then true else false -//│ res: bool +//│ res: Bool //│ = true fun foo(x) = x is Pair(a, b) -//│ foo: anything -> bool +//│ foo: anything -> Bool //│ = [Function: foo] diff --git a/shared/src/test/diff/ucs/SimpleUCS.mls b/shared/src/test/diff/ucs/SimpleUCS.mls index f30b1e29e8..888dfc7c80 100644 --- a/shared/src/test/diff/ucs/SimpleUCS.mls +++ b/shared/src/test/diff/ucs/SimpleUCS.mls @@ -193,7 +193,7 @@ fun f(x, y) = //│ if expression was not desugared fun isValid(x) = if x then false else true -//│ isValid: anything -> bool +//│ isValid: anything -> Bool //│ = [Function: isValid] fun f(x, allowNone) = diff --git a/shared/src/test/diff/ucs/SplitAroundOp.mls b/shared/src/test/diff/ucs/SplitAroundOp.mls index 86dfebdc77..4edc257780 100644 --- a/shared/src/test/diff/ucs/SplitAroundOp.mls +++ b/shared/src/test/diff/ucs/SplitAroundOp.mls @@ -12,7 +12,7 @@ fun f(x, b) = "1" then "s1" "2" then "s2" else ":p" -//│ fun f: (Eql["0" | "1" | "2" | 0 | 1 | 2], anything,) -> (":p" | "n0" | "n1" | "n2" | "s0" | "s1" | "s2") +//│ fun f: (Eql[nothing], Object,) -> (":p" | "n0" | "n1" | "n2" | "s0" | "s1" | "s2") fun f(x, y, a, b) = if x === 0 diff --git a/shared/src/test/diff/ucs/Tree.mls b/shared/src/test/diff/ucs/Tree.mls index e66b2dac07..3c7f34938f 100644 --- a/shared/src/test/diff/ucs/Tree.mls +++ b/shared/src/test/diff/ucs/Tree.mls @@ -3,16 +3,16 @@ type Option[A] = Some[A] | None class Some[A](value: A) module None -//│ type Option[A] = Some[A] | None +//│ type Option[A] = None | Some[A] //│ class Some[A](value: A) //│ module None type Tree[A] = Node[A] | Empty module Empty -class Node[A](value: int, left: Tree[A], right: Tree[A]) -//│ type Tree[A] = Node[A] | Empty +class Node[A](value: Int, left: Tree[A], right: Tree[A]) +//│ type Tree[A] = Empty | Node[A] //│ module Empty -//│ class Node[A](value: int, left: Tree[A], right: Tree[A]) +//│ class Node[A](value: Int, left: Tree[A], right: Tree[A]) fun find(t, v) = if t is Node(v', l, r) and @@ -20,7 +20,7 @@ fun find(t, v) = if t is v > v' then find(r, v) _ then Some(v) Empty then None -//│ fun find: forall 'A 'A0. (Empty | Node['A], number & 'A0,) -> (None | Some['A0]) +//│ fun find: forall 'A 'A0. (Empty | Node['A], Num & 'A0,) -> (None | Some['A0]) fun insert(t, v) = if t is Node(v', l, r) and @@ -28,7 +28,7 @@ fun insert(t, v) = if t is v > v' then Node(v', l, insert(r, v)) _ then t Empty then Node(v, Empty, Empty) -//│ fun insert: forall 'A. (Empty | Node['A], int,) -> Node['A] +//│ fun insert: forall 'A. (Empty | Node['A], Int,) -> Node['A] find(Empty, 0) find(Node(0, Empty, Empty), 0) diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index bda4d5a855..c094ec36f5 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -1,4 +1,4 @@ -:NewParser +:NewDefs // Should report duplicated else branches. :w @@ -20,36 +20,36 @@ else 1 //│ ╟── is subsumed by the branch here. //│ ║ l.6: _ then 0 //│ ╙── ^ -//│ res: 0 -//│ = 0 +//│ 0 +//│ res +//│ = 0 :w if else 0 else 1 //│ ╔══[WARNING] Found a duplicated branch //│ ╟── This branch -//│ ║ l.27: if else 0 else 1 +//│ ║ l.28: if else 0 else 1 //│ ║ ^ //│ ╟── is subsumed by the branch here. -//│ ║ l.27: if else 0 else 1 +//│ ║ l.28: if else 0 else 1 //│ ╙── ^ -//│ res: 0 -//│ = 0 +//│ 0 +//│ res +//│ = 0 :w fun f(x) = if x is else 0 else 1 //│ ╔══[WARNING] Found a duplicated branch //│ ╟── This branch -//│ ║ l.39: fun f(x) = if x is else 0 else 1 +//│ ║ l.41: fun f(x) = if x is else 0 else 1 //│ ║ ^ //│ ╟── is subsumed by the branch here. -//│ ║ l.39: fun f(x) = if x is else 0 else 1 +//│ ║ l.41: fun f(x) = if x is else 0 else 1 //│ ╙── ^ -//│ f: anything -> 0 -//│ = [Function: f] +//│ fun f: anything -> 0 fun f(x) = if x is else 0 -//│ f: anything -> 0 -//│ = [Function: f1] +//│ fun f: anything -> 0 :e :ge @@ -58,7 +58,7 @@ if true //│ ╔══[ERROR] The case when this is false is not handled: true //│ ║ l.56: if true //│ ╙── ^^^^ -//│ res: error +//│ error //│ Code generation encountered an error: //│ if expression was not desugared @@ -67,7 +67,7 @@ if true :e :ge fun f(x) = - if x == + if x === else "bruh" //│ ╔══[PARSE ERROR] Unexpected indented block in expression position //│ ║ l.71: else "bruh" @@ -76,39 +76,38 @@ fun f(x) = //│ ║ l.71: else "bruh" //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead -//│ ║ l.70: if x == -//│ ║ ^^^^ +//│ ║ l.70: if x === +//│ ║ ^^^^^ //│ ║ l.71: else "bruh" //│ ║ ^^^^ //│ ╟── Note: 'if' expression started here: -//│ ║ l.70: if x == +//│ ║ l.70: if x === //│ ╙── ^^ -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (undefined,) -//│ ║ l.70: if x == -//│ ║ ^^^^ +//│ ╔══[ERROR] The case when this is false is not handled: === (x,) (undefined,) +//│ ║ l.70: if x === +//│ ║ ^^^^^ //│ ║ l.71: else "bruh" //│ ╙── ^^^^ -//│ f: anything -> error +//│ fun f: anything -> error //│ Code generation encountered an error: //│ if expression was not desugared // But this works. fun f(x) = - if x == + if x === _ then "bruh" -//│ f: anything -> "bruh" -//│ = [Function: f3] +//│ fun f: anything -> "bruh" fun boolToStr(x) = if x is true then "yah" false then "nah" -//│ boolToStr: bool -> ("nah" | "yah") -//│ = [Function: boolToStr] +//│ fun boolToStr: nothing -> ("nah" | "yah") boolToStr of true boolToStr of false -//│ res: "nah" | "yah" -//│ = 'yah' -//│ res: "nah" | "yah" -//│ = 'nah' +//│ "nah" | "yah" +//│ res +//│ = 'yah' +//│ res +//│ = 'nah' diff --git a/shared/src/test/diff/ucs/Wildcard.mls b/shared/src/test/diff/ucs/Wildcard.mls index 5f39eb4917..cb8507cbaf 100644 --- a/shared/src/test/diff/ucs/Wildcard.mls +++ b/shared/src/test/diff/ucs/Wildcard.mls @@ -4,7 +4,7 @@ type Option[T] = None | Some[T] module None class Some[T](value: T) -//│ type Option[T] = Some[T] | None +//│ type Option[T] = None | Some[T] //│ module None //│ class Some[T](value: T) @@ -23,13 +23,13 @@ fun w1(x, e_0, e_1) = Left(Some(lv)) then concat("Left of Some of ")(toString(lv)) _ and e_1 is y_1 and x is Right(Some(rv)) then concat("Right of Some of ")(toString(rv)) -//│ fun w1: (Left[None | Some[anything]] | Right[None | Some[anything]], anything, anything,) -> string +//│ fun w1: (Left[None | Some[anything]] | Right[None | Some[anything]], anything, anything,) -> Str w1(Left(None), "a", "b") w1(Right(None), "a", "b") w1(Left(Some(0)), "a", "b") w1(Right(Some(0)), "a", "b") -//│ string +//│ Str //│ res //│ = 'Left of None' //│ res @@ -45,7 +45,7 @@ fun w2(x, p) = _ and p(x) then 2 None then 3 _ then 4 -//│ fun w2: forall 'a. (None | Some[anything] | 'a & ~#None & ~#Some, (None | 'a) -> anything,) -> (1 | 2 | 3 | 4) +//│ fun w2: forall 'a. (None | Object & 'a & ~#None & ~#Some | Some[anything], (None | 'a) -> Object,) -> (1 | 2 | 3 | 4) w2(Some(0), x => true) w2(None, x => true) @@ -66,13 +66,13 @@ fun w3(x, p) = if x is Some(xv) then concat("r2: ")(toString(xv)) None then "r3" _ then "r4" -//│ fun w3: forall 'a. (None | Some[anything] | 'a & ~#None & ~#Some, (None | Some[nothing] | 'a) -> anything,) -> string +//│ fun w3: forall 'a. (None | Object & 'a & ~#None & ~#Some | Some[anything], (None | Some[nothing] | 'a) -> Object,) -> Str // Expect "r1" w3(0, _ => true) w3(None, _ => true) w3(Some(0), _ => true) -//│ string +//│ Str //│ res //│ = 'r1' //│ res @@ -82,19 +82,19 @@ w3(Some(0), _ => true) // Expect "r2" w3(Some(0), _ => false) -//│ string +//│ Str //│ res //│ = 'r2: 0' // Expect "r3" w3(None, _ => false) -//│ string +//│ Str //│ res //│ = 'r3' // Expect "r4" w3(0, _ => false) -//│ string +//│ Str //│ res //│ = 'r4' @@ -127,7 +127,7 @@ fun w3_1_1(x, f) = w3_1_1(0, x => x) w3_1_1(0, x => x + 1) -//│ int +//│ Int //│ res //│ = 0 //│ res @@ -142,14 +142,14 @@ fun w4(x, p) = if x is Some(xv) then concat("r2: ")(toString(xv)) None then "r3" _ then "r4" -//│ fun w4: forall 'a. (None | Some[anything] | 'a & ~#None & ~#Some, (None | Some[nothing] | 'a) -> anything,) -> string +//│ fun w4: forall 'a. (None | Object & 'a & ~#None & ~#Some | Some[anything], (None | Some[nothing] | 'a) -> Object,) -> Str // Expect "r1" w4(0, _ => true) w4(None, _ => true) w4(Some(0), _ => true) -//│ string +//│ Str //│ res //│ = 'r1' //│ res @@ -159,19 +159,19 @@ w4(Some(0), _ => true) // Expect "r2" w4(Some(0), _ => false) -//│ string +//│ Str //│ res //│ = 'r2: 0' // Expect "r3" w4(None, _ => false) -//│ string +//│ Str //│ res //│ = 'r3' // Expect "r4" w4(0, _ => false) -//│ string +//│ Str //│ res //│ = 'r4' @@ -196,7 +196,7 @@ fun w5(y) = _ and y is Delta then "delta" _ then "unknown" -//│ fun w5: anything -> ("alpha" | "beta" | "delta" | "gamma" | "unknown") +//│ fun w5: Object -> ("alpha" | "beta" | "delta" | "gamma" | "unknown") w5(0) w5(Alpha()) @@ -221,7 +221,7 @@ fun w6(x, y) = Some(z) then z None then 0 else x -//│ fun w6: forall 'value. ('value, Some['value] | ~Some[anything],) -> (0 | 'value) +//│ fun w6: forall 'value. ('value, Object & ~#Some | Some['value],) -> (0 | 'value) w6("42", Some(42)) w6("42", None) @@ -243,14 +243,14 @@ fun w7(x, f) = None then x Left(x) then x + 1 Right(x) then x + 2 -//│ fun w7: forall 'a 'value. (Left[int] | Right[int] | 'a & ~#Left & ~#Right, 'a -> (None | Some['value]),) -> (int | 'value | 'a) +//│ fun w7: forall 'a 'value. (Left[Int] | Object & 'a & ~#Left & ~#Right | Right[Int], 'a -> (None | Some['value]),) -> (Int | 'value | 'a) // The results are wrong: w7(Left(99), _ => Some(0)) // => 0 w7(Left(99), _ => None) // => Left(99) w7(Right(99), _ => Some(0)) // => 0 w7(Right(99), _ => None) // => Right(99) -//│ int +//│ Int //│ res //│ = 100 //│ res diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index e444ff198a..9ad552a6d8 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -93,7 +93,7 @@ fun zipWith_wrong(f, xs, ys) = if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith_wrong(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) else None -//│ fun zipWith_wrong: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A]]) +//│ fun zipWith_wrong: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (None | Some[Cons['A]]) // * Notice the result is wrong (duh) zipWith_wrong(pairup, Nil, Nil) @@ -108,7 +108,7 @@ fun zipWith(f, xs, ys) = Cons(x, xs) and ys is Cons(y, ys) and zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) Nil and ys is Nil then Some(Nil) else None -//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) +//│ fun zipWith: forall 'head 'A 'head0. (('head0, 'head,) -> 'A, Cons['head0] | Object & ~#Cons, Cons['head] | Object & ~#Cons,) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray //│ Array[anything] @@ -121,7 +121,7 @@ fun zipWith(f, xs, ys) = Cons(x, xs) and ys is Cons(y, ys) and zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) Nil and ys is Nil then Some(Nil) else None -//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray //│ Array[anything] @@ -133,7 +133,7 @@ fun zipWith(f, xs, ys) = if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) else if xs is Nil and ys is Nil then Some(Nil) else None -//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray //│ Array[anything] @@ -147,7 +147,7 @@ fun zipWith(f, xs, ys) = else None else if xs is Nil and ys is Nil then Some(Nil) else None -//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (None | Some[Cons['A] | Nil]) +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray //│ Array[anything] @@ -200,7 +200,7 @@ fun zipWith_wrong2(f, xs, ys) = if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith_wrong2(f, xs, ys) is Some(tail) then Cons(Some(f(x, y)), tail) else if xs is Nil and ys is Nil then Some(Nil) else None -//│ fun zipWith_wrong2: forall 'A 'head 'head0. (('head, 'head0,) -> 'A, Cons['head] | ~Cons[anything], Cons['head0] | ~Cons[anything],) -> (Cons[Some['A]] | None | Some[Nil]) +//│ fun zipWith_wrong2: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (Cons[Some['A]] | None | Some[Nil]) // * No type error! The definition and use are well-typed... zipWith_wrong2(pairup, Cons(0, Cons(1, Nil)), Cons("0", Cons("1", Nil))) diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 425fad04ab..f6a8990ae0 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -119,12 +119,16 @@ class DiffTests str.splitSane('\n').foreach(l => out.println(outputMarker + l)) def outputSourceCode(code: SourceCode) = code.lines.foreach{line => out.println(outputMarker + line.toString())} val allStatements = mutable.Buffer.empty[DesugaredStatement] - val typer = new Typer(dbg = false, verbose = false, explainErrors = false) { - override def funkyTuples = file.ext =:= "fun" - // override def emitDbg(str: String): Unit = if (stdout) System.out.println(str) else output(str) - override def emitDbg(str: String): Unit = output(str) - } - var ctx: typer.Ctx = typer.Ctx.init + var newDefs = false + trait MyTyper extends Typer { var ctx: Ctx } + lazy val typer = + new Typer(dbg = false, verbose = false, explainErrors = false, newDefs = newDefs) with MyTyper { + var ctx: Ctx = Ctx.init + override def funkyTuples = file.ext =:= "fun" + // override def emitDbg(str: String): Unit = if (stdout) System.out.println(str) else output(str) + override def emitDbg(str: String): Unit = output(str) + } + def ctx = typer.ctx var declared: Map[Str, typer.ST] = Map.empty val failures = mutable.Buffer.empty[Int] val unmergedChanges = mutable.Buffer.empty[Int] @@ -180,8 +184,6 @@ class DiffTests var generalizeArguments = false var newParser = basePath.headOption.contains("parser") || basePath.headOption.contains("compiler") - var newDefs = false - val backend = new JSTestBackend() val host = ReplHost() val codeGenTestHelpers = new CodeGenTestHelpers(file, output) @@ -606,7 +608,7 @@ class DiffTests } } - ctx = + typer.ctx = // if (newParser) typer.typeTypingUnit(tu) // else typer.processTypeDefs(typeDefs)(ctx, raise) From 4f373ec65267b6f59d31d077548c5b509a14e78d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 6 Jun 2023 14:05:56 +0800 Subject: [PATCH 349/498] Rename namespace/Nms -> module/Mod --- shared/src/main/scala/mlscript/JSBackend.scala | 4 ++-- shared/src/main/scala/mlscript/MLParser.scala | 2 +- shared/src/main/scala/mlscript/NewParser.scala | 4 ++-- .../src/main/scala/mlscript/NuTypeDefs.scala | 10 +++++----- shared/src/main/scala/mlscript/TypeDefs.scala | 12 ++++++------ shared/src/main/scala/mlscript/Typer.scala | 16 ++++++++-------- .../src/main/scala/mlscript/TyperHelpers.scala | 6 +++--- .../main/scala/mlscript/codegen/Scope.scala | 4 ++-- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/main/scala/mlscript/syntax.scala | 2 +- .../main/scala/mlscript/ucs/Desugarer.scala | 2 +- .../src/test/diff/nu/BasicClassInheritance.mls | 18 ++++++++++++++++++ .../js/src/main/scala/ts2mls/TSNamespace.scala | 2 +- ts2mls/js/src/test/diff/Dec.d.mls | 4 ++-- ts2mls/js/src/test/diff/Heritage.d.mls | 4 ++-- ts2mls/js/src/test/diff/MultiFiles.d.mls | 4 ++-- ts2mls/js/src/test/diff/Namespace.d.mls | 10 +++++----- ts2mls/js/src/test/diff/Overload.d.mls | 4 ++-- ts2mls/js/src/test/diff/Type.d.mls | 4 ++-- ts2mls/js/src/test/diff/Variables.d.mls | 6 +++--- 20 files changed, 69 insertions(+), 51 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index d72d63b27e..c3701a8f0d 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -903,7 +903,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case TypeDef(Cls, TypeName(name), tparams, baseType, _, members, _) => classes += topLevelScope.declareClass(name, tparams map { _.name }, baseType, members) case TypeDef(Mxn, _, _, _, _, _, _) => throw CodeGenError("Mixins are not supported yet.") - case TypeDef(Nms, _, _, _, _, _, _) => throw CodeGenError("Namespaces are not supported yet.") + case TypeDef(Mod, _, _, _, _, _, _) => throw CodeGenError("Namespaces are not supported yet.") } (traits.toList, classes.toList) } @@ -954,7 +954,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val sym = MixinSymbol(mxName, tps map { _._2.name }, body, members, stmts, nested, isNested).tap(scope.register) if (!td.isDecl) mixins += sym } - case td @ NuTypeDef(Nms, TypeName(nme), tps, tup, ctor, sig, pars, sup, ths, unit) => { + case td @ NuTypeDef(Mod, TypeName(nme), tps, tup, ctor, sig, pars, sup, ths, unit) => { val (body, members, stmts, nested) = prepare(nme, tup.getOrElse(Tup(Nil)).fields, pars, unit) val sym = ModuleSymbol(nme, tps map { _._2.name }, body, members, stmts, pars, nested, isNested).tap(scope.register) if (!td.isDecl) modules += sym diff --git a/shared/src/main/scala/mlscript/MLParser.scala b/shared/src/main/scala/mlscript/MLParser.scala index 356ad15f05..da4e17a884 100644 --- a/shared/src/main/scala/mlscript/MLParser.scala +++ b/shared/src/main/scala/mlscript/MLParser.scala @@ -213,7 +213,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { ms.collect { case R(md) => md }, ms.collect{ case L(md) => md }, Nil) } case (k @ Als, id, ts) => "=" ~ ty map (bod => TypeDef(k, id, ts, bod, Nil, Nil, Nil)) - case (k @ Nms, _, _) => throw new NotImplementedError("Namespaces are not supported yet.") + case (k @ Mod, _, _) => throw new NotImplementedError("Namespaces are not supported yet.") case (k @ Mxn, _, _) => throw new NotImplementedError("Mixins are not supported yet.") }) def tyParams[p: P]: P[Ls[TypeName]] = diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 0abb4756df..41ac4e86fb 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -321,7 +321,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D } case c => val t = c match { - case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "namespace" | "module")), l0) :: c) => + case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "module")), l0) :: c) => consume val (isDecl, mods2) = mods.handle("declare") val (isAbs, mods3) = mods2.handle("abstract") @@ -331,7 +331,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], raiseFun: D case "trait" => Trt case "mixin" => Mxn case "type" => Als - case "namespace" | "module" => Nms + case "module" => Mod case _ => die } val (tn, success) = yeetSpaces match { diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 1de8a2f035..dbf553afde 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -432,7 +432,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // TODO check this is not misused def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, selfTy: ST, ihtags: Set[TypeName]) : ST = td.kind match { - case Nms => + case Mod => ClassTag(Var(td.nme.name), ihtags + TN("Object") )(provTODO) @@ -732,7 +732,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => tags case (p, Var(nm), lti, _, _) :: ps => lti match { case lti: DelayedTypeInfo => lti.kind match { - case Trt | Cls | Nms => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) + case Trt | Cls | Mod => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) case Val | Mxn | Als => lookupTags(ps, tags) } case CompletedTypeInfo(trt: TypedNuTrt) => @@ -1046,7 +1046,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - if (((td.kind is Nms) || (td.kind is Mxn)) && td.ctor.isDefined) + if (((td.kind is Mod) || (td.kind is Mxn)) && td.ctor.isDefined) err(msg"Explicit ${td.kind.str} constructors are not supported", td.ctor.fold[Opt[Loc]](N)(c => c.toLoc)) @@ -1161,11 +1161,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => TypedNuAls(outerCtx.lvl, td, tparams, body_ty) - case Cls | Nms => + case Cls | Mod => ctx.nest.nextLevel { implicit ctx => - if ((td.kind is Nms) && typedParams.nonEmpty) + if ((td.kind is Mod) && typedParams.nonEmpty) // * Can we do better? (Memoization semantics?) err(msg"${td.kind.str} parameters are not supported", Loc(typedParams.iterator.map(_._1))) diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 9c24cea802..d9c064f180 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -111,7 +111,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => Var(clsNme.name + "#" + tparamNme.name) def clsNameToNomTag(td: NuTypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { - require((td.kind is Cls) || (td.kind is Nms), td.kind) + require((td.kind is Cls) || (td.kind is Mod), td.kind) ClassTag(Var(td.nme.name), if(newDefs) Set.single(TN("Object")) @@ -120,7 +120,7 @@ class TypeDefs extends NuTypeDefs { self: Typer => )(prov) } def clsNameToNomTag(td: TypeDef)(prov: TypeProvenance, ctx: Ctx): ClassTag = { - require((td.kind is Cls) || (td.kind is Nms), td.kind) + require((td.kind is Cls) || (td.kind is Mod), td.kind) if (newDefs && td.kind.str.isCapitalized) ClassTag(Var(td.nme.name), if(newDefs) Set.single(TN("Object")) @@ -257,8 +257,8 @@ class TypeDefs extends NuTypeDefs { self: Typer => // }() val rightParents = td.kind match { case Als => checkCycle(td.bodyTy)(Set.single(L(td.nme))) - case Nms => - err(msg"a namespace cannot inherit from others", prov.loco) + case Mod => + err(msg"modules cannot inherit from other types", prov.loco) false case k: ObjDefKind => val parentsClasses = MutSet.empty[TypeRef] @@ -279,8 +279,8 @@ class TypeDefs extends NuTypeDefs { self: Typer => } else checkParents(tr.expand) case Trt => checkParents(tr.expand) - case Nms => - err(msg"cannot inherit from a namespace", prov.loco) + case Mod => + err(msg"cannot inherit from a module", prov.loco) false case Als => err(msg"cannot inherit from a type alias", prov.loco) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 88f6f1ccae..c7512b2d94 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -229,8 +229,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne NuTypeDef(Cls, TN("Num"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Cls, TN("Int"), Nil, N, N, N, Var("Num") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Cls, TN("Bool"), Nil, N, N, S(Union(TN("true"), TN("false"))), Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), - NuTypeDef(Nms, TN("true"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), - NuTypeDef(Nms, TN("false"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Mod, TN("true"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Mod, TN("false"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Cls, TN("Str"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), ) val builtinTypes: Ls[TypeDef] = @@ -382,7 +382,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne // val outerCtxLvl = MinLevel + 1 val outerCtxLvl = ctx.lvl def checkKind(k: DeclKind, nme: Str, loc: Opt[Loc]): Unit = k match { - case Cls | Nms | Als | Trt => () + case Cls | Mod | Als | Trt => () case _ => err(msg"${k.str} ${nme} cannot be used as a type", loc); () } def typeNamed(loc: Opt[Loc], name: Str): (() => ST) \/ (TypeDefKind, Int) = @@ -395,7 +395,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne case ti: DelayedTypeInfo => checkKind(ti.decl.kind, ti.decl.name, loc) ti.decl match { - case NuTypeDef(k @ (Cls | Nms | Als | Trt), _, tps, _, _, _, _, _, _, _) => + case NuTypeDef(k @ (Cls | Mod | Als | Trt), _, tps, _, _, _, _, _, _, _) => S(k, tps.size) case NuTypeDef(k @ Mxn, nme, tps, _, _, _, _, _, _, _) => S(k, tps.size) @@ -484,7 +484,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne else ctx.tyDefs2.get(name) match { case S(lti) => lti.decl match { - case NuTypeDef(Cls | Nms, _, _, _, _, _, _, _, _, _) => + case NuTypeDef(Cls | Mod, _, _, _, _, _, _, _, _, _) => clsNameToNomTag(ctx.tyDefs2(name).decl.asInstanceOf[NuTypeDef])(tyTp(tyLoc, "class tag"), ctx) case NuTypeDef(Trt, _, _, _, _, _, _, _, _, _) => trtNameToNomTag(ctx.tyDefs2(name).decl.asInstanceOf[NuTypeDef])(tyTp(tyLoc, "class tag"), ctx) @@ -500,7 +500,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne case Trt => trtNameToNomTag(td)(tyTp(tyLoc, "trait tag"), ctx) case Als => err( msg"Type alias ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) - case Nms => err( + case Mod => err( msg"Module ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) case Mxn => err( msg"Mixin ${name.capitalize} cannot be used as a type tag", tyLoc)(raise) @@ -1190,7 +1190,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne } ctx.get(nme) match { case S(lti: LazyTypeInfo) => - if ((lti.kind isnt Cls) && (lti.kind isnt Nms) && (lti.kind isnt Trt)) + if ((lti.kind isnt Cls) && (lti.kind isnt Mod) && (lti.kind isnt Trt)) err(msg"can only match on classes and traits", pat.toLoc)(raise) val prov = tp(pat.toLoc, "class pattern") @@ -1227,7 +1227,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne } case Some(td) => td.kind match { - case Als | Nms | Mxn => val t = err(msg"can only match on classes and traits", pat.toLoc)(raise); t -> t + case Als | Mod | Mxn => val t = err(msg"can only match on classes and traits", pat.toLoc)(raise); t -> t case Cls => val t = clsNameToNomTag(td)(tp(pat.toLoc, "class pattern"), ctx); t -> t case Trt => val t = trtNameToNomTag(td)(tp(pat.toLoc, "trait pattern"), ctx); t -> t } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 34b1b81e75..ca6fb82f13 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1085,7 +1085,7 @@ abstract class TyperHelpers { Typer: Typer => else TopType subst(td.kind match { case Als => td.bodyTy - case Nms => throw new NotImplementedError("Namespaces are not supported yet.") + case Mod => throw new NotImplementedError("Namespaces are not supported yet.") case Cls => clsNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags case Trt => trtNameToNomTag(td)(prov, ctx) & td.bodyTy & tparamTags case Mxn => lastWords("mixins cannot be used as types") @@ -1095,13 +1095,13 @@ abstract class TyperHelpers { Typer: Typer => def expansionFallback(implicit ctx: Ctx): Opt[ST] = mkClsTag def mkClsTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { val res = ctx.tyDefs.get(defn.name) match { - case S(td: TypeDef) if (td.kind is Cls) || (td.kind is Nms) => + case S(td: TypeDef) if (td.kind is Cls) || (td.kind is Mod) => S(clsNameToNomTag(td)(noProv, ctx)) case S(td: TypeDef) if td.kind is Trt => N case _ => ctx.tyDefs2.get(defn.name) match { case S(lti) => lti.decl match { - case td: NuTypeDef if (td.kind is Cls) || (td.kind is Nms) => + case td: NuTypeDef if (td.kind is Cls) || (td.kind is Mod) => S(clsNameToNomTag(td)(noProv, ctx)) case _ => N } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index e0f42bbae6..051612307e 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -4,7 +4,7 @@ import mlscript.utils.shorthands._ import mlscript.{JSStmt, JSExpr, JSLetDecl} import mlscript.Type import scala.reflect.ClassTag -import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls, Nms, Mxn} +import mlscript.{TypeName, Top, Bot, TypeDef, Als, Trt, Cls, Mod, Mxn} import mlscript.{MethodDef, Var} import mlscript.{Term, Statement, Record} import mlscript.utils.{AnyOps, lastWords} @@ -235,7 +235,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { declareClass(name, tparams map { _.name }, baseType, members) case TypeDef(Mxn, _, _, _, _, _, _) => throw CodeGenError("Mixins are not supported yet.") - case TypeDef(Nms, _, _, _, _, _, _) => + case TypeDef(Mod, _, _, _, _, _, _) => throw CodeGenError("Namespaces are not supported yet.") } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 9bae3ba303..7029534899 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -746,7 +746,7 @@ trait StatementImpl extends Located { self: Statement => (diags ::: diags2 ::: diags3) -> (TypeDef(Als, TypeName(v.name).withLocOf(v), targs, dataDefs.map(td => AppliedType(td.nme, td.tparams)).reduceOption(Union).getOrElse(Bot), Nil, Nil, Nil ).withLocOf(hd) :: cs) - case NuTypeDef(Nms, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => + case NuTypeDef(Mod, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => ??? // TODO case NuTypeDef(Mxn, nme, tps, tup, ctor, sig, pars, sup, ths, unit) => ??? // TODO diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 8abb92debf..6c587a1c36 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -54,7 +54,7 @@ case object Cls extends TypeDefKind("class") with ClsLikeKind case object Trt extends TypeDefKind("trait") with ObjDefKind case object Mxn extends TypeDefKind("mixin") case object Als extends TypeDefKind("type alias") -case object Nms extends TypeDefKind("module") with ClsLikeKind +case object Mod extends TypeDefKind("module") with ClsLikeKind sealed abstract class Term extends Terms with TermImpl sealed abstract class Lit extends SimpleTerm with LitImpl diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index de9b5297c1..c9b81dd7c9 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -224,7 +224,7 @@ class Desugarer extends TypeDefs { self: Typer => // x is A case classNameVar @ Var(className) => ctx.tyDefs.get(className).orElse(ctx.get(className)) match { - case S(ti: LazyTypeInfo) if (ti.kind is Cls) || (ti.kind is Nms) => + case S(ti: LazyTypeInfo) if (ti.kind is Cls) || (ti.kind is Mod) => case S(ti: LazyTypeInfo) if (ti.kind is Trt) => throw new DesugaringException({ msg"Cannot match on trait `$className`" }, classNameVar.toLoc) diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 56c569f4dc..3d083b3d25 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -32,3 +32,21 @@ class B extends A //│ } +// * Interestingly, we can currently inherit from modules... + +module C { fun test = 0 } +//│ module C { +//│ fun test: 0 +//│ } + +class D() extends C +//│ class D() extends C { +//│ fun test: 0 +//│ } + +D().test +//│ 0 +//│ res +//│ = 0 + + diff --git a/ts2mls/js/src/main/scala/ts2mls/TSNamespace.scala b/ts2mls/js/src/main/scala/ts2mls/TSNamespace.scala index 4bb94bcf5a..bd54aa5685 100644 --- a/ts2mls/js/src/main/scala/ts2mls/TSNamespace.scala +++ b/ts2mls/js/src/main/scala/ts2mls/TSNamespace.scala @@ -38,7 +38,7 @@ class TSNamespace(name: String, parent: Option[TSNamespace]) { def generate(writer: JSWriter, indent: String): Unit = order.toList.foreach((p) => p match { case Left(subName) => { - writer.writeln(s"${indent}namespace $subName {") + writer.writeln(s"${indent}module $subName {") subSpace(subName).generate(writer, indent + " ") writer.writeln(s"$indent}") } diff --git a/ts2mls/js/src/test/diff/Dec.d.mls b/ts2mls/js/src/test/diff/Dec.d.mls index 1527f227f4..6da63ddece 100644 --- a/ts2mls/js/src/test/diff/Dec.d.mls +++ b/ts2mls/js/src/test/diff/Dec.d.mls @@ -8,7 +8,7 @@ trait Get() { class Person(name: string, age: number) { fun getName(id: number): string } -namespace OOO { +module OOO { } -//│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |=>| |unit|)| ||| |(|#undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#namespace| |OOO| |{|↵|}| +//│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |=>| |unit|)| ||| |(|#undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#module| |OOO| |{|↵|}| //│ Parsed: {fun getName: (id: string | number,) -> string; fun render: (callback: unit -> unit | undefined,) -> string; trait Get() {fun __call: (id: string,) -> string}; class Person(name: string, age: number,) {fun getName: (id: number,) -> string}; module OOO() {}} diff --git a/ts2mls/js/src/test/diff/Heritage.d.mls b/ts2mls/js/src/test/diff/Heritage.d.mls index 68dba08a1a..070033fd3d 100644 --- a/ts2mls/js/src/test/diff/Heritage.d.mls +++ b/ts2mls/js/src/test/diff/Heritage.d.mls @@ -33,12 +33,12 @@ trait O() { class OR(): O { fun xx(x: R): R } -namespace Five { +module Five { class ROTK() { let wu: string } class Y(): Five.ROTK {} } class Y(): Five.ROTK {} -//│ |#class| |A|(||)| |{|→|#fun| |foo|(||)|#:| |unit|←|↵|}|↵|#class| |B|(||)|#:| |A| |{||}|↵|#class| |C|‹|T|›|(||)| |{|→|#fun| |set|(|x|#:| |T|)|#:| |unit|↵|#fun| |get|(||)|#:| |T|←|↵|}|↵|#class| |D|(||)|#:| |C|‹|number|›| |{||}|↵|#trait| |Wu|(||)| |{|→|#let| |x|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#class| |WuWu|(||)|#:| |Wu| |{|→|#let| |y|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |WuWuWu|(||)|#:| |WuWu| |{|→|#let| |z|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |Never|(||)|#:| |WuWuWu| |{|→|#fun| |w|(||)|#:| |nothing|←|↵|}|↵|#class| |VG|‹|T|›|(||)| |{|→|#let| |x|#:| |T|←|↵|}|↵|#class| |Home|‹|T|›|(||)|#:| |VG|‹|string|›| |{|→|#let| |y|#:| |T|←|↵|}|↵|#trait| |O|‹|I|›|(||)| |{|→|#fun| |xx|(|x|#:| |I|)|#:| |I|←|↵|}|↵|#class| |OR|‹|R|›|(||)|#:| |O|‹|R|›| |{|→|#fun| |xx|(|x|#:| |R|)|#:| |R|←|↵|}|↵|#namespace| |Five| |{|→|#class| |ROTK|(||)| |{|→|#let| |wu|#:| |string|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}| +//│ |#class| |A|(||)| |{|→|#fun| |foo|(||)|#:| |unit|←|↵|}|↵|#class| |B|(||)|#:| |A| |{||}|↵|#class| |C|‹|T|›|(||)| |{|→|#fun| |set|(|x|#:| |T|)|#:| |unit|↵|#fun| |get|(||)|#:| |T|←|↵|}|↵|#class| |D|(||)|#:| |C|‹|number|›| |{||}|↵|#trait| |Wu|(||)| |{|→|#let| |x|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#class| |WuWu|(||)|#:| |Wu| |{|→|#let| |y|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |WuWuWu|(||)|#:| |WuWu| |{|→|#let| |z|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |Never|(||)|#:| |WuWuWu| |{|→|#fun| |w|(||)|#:| |nothing|←|↵|}|↵|#class| |VG|‹|T|›|(||)| |{|→|#let| |x|#:| |T|←|↵|}|↵|#class| |Home|‹|T|›|(||)|#:| |VG|‹|string|›| |{|→|#let| |y|#:| |T|←|↵|}|↵|#trait| |O|‹|I|›|(||)| |{|→|#fun| |xx|(|x|#:| |I|)|#:| |I|←|↵|}|↵|#class| |OR|‹|R|›|(||)|#:| |O|‹|R|›| |{|→|#fun| |xx|(|x|#:| |R|)|#:| |R|←|↵|}|↵|#module| |Five| |{|→|#class| |ROTK|(||)| |{|→|#let| |wu|#:| |string|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}| //│ Parsed: {class A() {fun foo: () -> unit}; class B(): A {}; class C‹T›() {fun set: (x: T,) -> unit; fun get: () -> T}; class D(): C[number] {}; trait Wu() {let x: bool}; class WuWu(): Wu {let y: bool}; trait WuWuWu(): WuWu {let z: bool}; trait Never(): WuWuWu {fun w: () -> nothing}; class VG‹T›() {let x: T}; class Home‹T›(): VG[string] {let y: T}; trait O‹I›() {fun xx: (x: I,) -> I}; class OR‹R›(): O[R] {fun xx: (x: R,) -> R}; module Five() {class ROTK() {let wu: string}; class Y(): Five.ROTK {}}; class Y(): Five.ROTK {}} diff --git a/ts2mls/js/src/test/diff/MultiFiles.d.mls b/ts2mls/js/src/test/diff/MultiFiles.d.mls index 21007ede73..d3633fe5b7 100644 --- a/ts2mls/js/src/test/diff/MultiFiles.d.mls +++ b/ts2mls/js/src/test/diff/MultiFiles.d.mls @@ -6,7 +6,7 @@ class Foo(): Base {} trait AnotherBase() { let y: string } -namespace N { +module N { fun f(): unit fun g(): unit fun h(): unit @@ -18,5 +18,5 @@ trait Base() { } class AnotherFoo(): AnotherBase {} fun multi5(): unit -//│ |#fun| |multi1|(|x|#:| |number|)|#:| |number|↵|#fun| |multi3|(||)|#:| |unit|↵|#class| |Foo|(||)|#:| |Base| |{||}|↵|#trait| |AnotherBase|(||)| |{|→|#let| |y|#:| |string|←|↵|}|↵|#namespace| |N| |{|→|#fun| |f|(||)|#:| |unit|↵|#fun| |g|(||)|#:| |unit|↵|#fun| |h|(||)|#:| |unit|←|↵|}|↵|#fun| |multi2|(|x|#:| |string|)|#:| |string|↵|#fun| |multi4|(||)|#:| |unit|↵|#trait| |Base|(||)| |{|→|#let| |a|#:| |number|←|↵|}|↵|#class| |AnotherFoo|(||)|#:| |AnotherBase| |{||}|↵|#fun| |multi5|(||)|#:| |unit| +//│ |#fun| |multi1|(|x|#:| |number|)|#:| |number|↵|#fun| |multi3|(||)|#:| |unit|↵|#class| |Foo|(||)|#:| |Base| |{||}|↵|#trait| |AnotherBase|(||)| |{|→|#let| |y|#:| |string|←|↵|}|↵|#module| |N| |{|→|#fun| |f|(||)|#:| |unit|↵|#fun| |g|(||)|#:| |unit|↵|#fun| |h|(||)|#:| |unit|←|↵|}|↵|#fun| |multi2|(|x|#:| |string|)|#:| |string|↵|#fun| |multi4|(||)|#:| |unit|↵|#trait| |Base|(||)| |{|→|#let| |a|#:| |number|←|↵|}|↵|#class| |AnotherFoo|(||)|#:| |AnotherBase| |{||}|↵|#fun| |multi5|(||)|#:| |unit| //│ Parsed: {fun multi1: (x: number,) -> number; fun multi3: () -> unit; class Foo(): Base {}; trait AnotherBase() {let y: string}; module N() {fun f: () -> unit; fun g: () -> unit; fun h: () -> unit}; fun multi2: (x: string,) -> string; fun multi4: () -> unit; trait Base() {let a: number}; class AnotherFoo(): AnotherBase {}; fun multi5: () -> unit} diff --git a/ts2mls/js/src/test/diff/Namespace.d.mls b/ts2mls/js/src/test/diff/Namespace.d.mls index 1f0901ea63..38f2dedb92 100644 --- a/ts2mls/js/src/test/diff/Namespace.d.mls +++ b/ts2mls/js/src/test/diff/Namespace.d.mls @@ -1,6 +1,6 @@ :NewParser :ParseOnly -namespace N1 { +module N1 { fun f(x: anything): number fun ff(y: anything): number class C() { @@ -9,13 +9,13 @@ namespace N1 { trait I() { fun f(): number } - namespace N2 { + module N2 { fun fff(x: (false) | (true)): number fun gg(c: N1.C): N1.C class BBB(): N1.C {} } } -namespace AA { +module AA { fun f(x: anything): string class C() { fun f(): unit @@ -23,10 +23,10 @@ namespace AA { trait I() { fun f(): number } - namespace N2 { + module N2 { } } fun f1(x: N1.C): N1.C fun f2(x: AA.C): AA.C -//│ |#namespace| |N1| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |number|↵|#fun| |ff|(|y|#:| |anything|)|#:| |number|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#namespace| |N2| |{|→|#fun| |fff|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |number|↵|#fun| |gg|(|c|#:| |N1|.C|)|#:| |N1|.C|↵|#class| |BBB|(||)|#:| |N1|.C| |{||}|←|↵|}|←|↵|}|↵|#namespace| |AA| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |string|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#namespace| |N2| |{|↵|}|←|↵|}|↵|#fun| |f1|(|x|#:| |N1|.C|)|#:| |N1|.C|↵|#fun| |f2|(|x|#:| |AA|.C|)|#:| |AA|.C| +//│ |#module| |N1| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |number|↵|#fun| |ff|(|y|#:| |anything|)|#:| |number|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#module| |N2| |{|→|#fun| |fff|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |number|↵|#fun| |gg|(|c|#:| |N1|.C|)|#:| |N1|.C|↵|#class| |BBB|(||)|#:| |N1|.C| |{||}|←|↵|}|←|↵|}|↵|#module| |AA| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |string|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#module| |N2| |{|↵|}|←|↵|}|↵|#fun| |f1|(|x|#:| |N1|.C|)|#:| |N1|.C|↵|#fun| |f2|(|x|#:| |AA|.C|)|#:| |AA|.C| //│ Parsed: {module N1() {fun f: (x: anything,) -> number; fun ff: (y: anything,) -> number; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2() {fun fff: (x: bool,) -> number; fun gg: (c: N1.C,) -> N1.C; class BBB(): N1.C {}}}; module AA() {fun f: (x: anything,) -> string; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2() {}}; fun f1: (x: N1.C,) -> N1.C; fun f2: (x: AA.C,) -> AA.C} diff --git a/ts2mls/js/src/test/diff/Overload.d.mls b/ts2mls/js/src/test/diff/Overload.d.mls index c3ef1b83fb..c604ba3734 100644 --- a/ts2mls/js/src/test/diff/Overload.d.mls +++ b/ts2mls/js/src/test/diff/Overload.d.mls @@ -15,12 +15,12 @@ fun op: ((number) => ((number) | (undefined)) => unit) & ((number) => (((false) fun swap: (((number, string, )) => (number, string, )) & (((string, number, )) => (number, string, )) fun u: ((((number) | (false)) | (true)) => string) & ((object) => string) fun doSome(x: anything): unit /* warning: the overload of function doSome is not supported yet. */ -namespace XX { +module XX { fun f(x: T, n: anything): string /* warning: the overload of function f is not supported yet. */ } class WWW() { fun F(x: T): anything /* warning: the overload of function F is not supported yet. */ } fun baz(): anything /* warning: the overload of function baz is not supported yet. */ -//│ |#fun| |f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |=>| |unit|)| |=>| |(|number|)| |=>| |unit|)| |&| |(|(|(|string|)| |=>| |unit|)| |=>| |(|string|)| |=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |=>| |unit|)| |&| |(|(|N|)| |=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |=>| |(|(|number|)| ||| |(|#undefined|)|)| |=>| |unit|)| |&| |(|(|number|)| |=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|#undefined|)|)| |=>| |unit|)|↵|#fun| |swap|#:| |(|(|(|number|,| |string|,| |)|)| |=>| |(|number|,| |string|,| |)|)| |&| |(|(|(|string|,| |number|,| |)|)| |=>| |(|number|,| |string|,| |)|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#namespace| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| +//│ |#fun| |f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |=>| |unit|)| |=>| |(|number|)| |=>| |unit|)| |&| |(|(|(|string|)| |=>| |unit|)| |=>| |(|string|)| |=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |=>| |unit|)| |&| |(|(|N|)| |=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |=>| |(|(|number|)| ||| |(|#undefined|)|)| |=>| |unit|)| |&| |(|(|number|)| |=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|#undefined|)|)| |=>| |unit|)|↵|#fun| |swap|#:| |(|(|(|number|,| |string|,| |)|)| |=>| |(|number|,| |string|,| |)|)| |&| |(|(|(|string|,| |number|,| |)|)| |=>| |(|number|,| |string|,| |)|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#module| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| //│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | undefined) -> unit & number -> (false | true | undefined) -> unit; fun swap: (number, string,) -> (number, string,) & (string, number,) -> (number, string,); fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything,) -> unit; module XX() {fun f: (x: T, n: anything,) -> string}; class WWW() {fun F: (x: T,) -> anything}; fun baz: () -> anything} diff --git a/ts2mls/js/src/test/diff/Type.d.mls b/ts2mls/js/src/test/diff/Type.d.mls index de7bc27730..e8995d2864 100644 --- a/ts2mls/js/src/test/diff/Type.d.mls +++ b/ts2mls/js/src/test/diff/Type.d.mls @@ -18,7 +18,7 @@ type SomeInterface = {x: number,y: number,} class ABC() {} type DEF = ABC type TP = (A, B, C, ) -namespace NA { +module NA { fun fb(b: string): unit type B = string } @@ -28,5 +28,5 @@ class NC() { type G = ABC let none: {_tag: "None",} fun some(a: A): (None) | (Some) -//│ |#trait| |None|(||)| |{|→|#let| |_tag|#:| |"None"|←|↵|}|↵|#trait| |Some|‹|A|›|(||)| |{|→|#let| |_tag|#:| |"Some"|↵|#let| |value|#:| |A|←|↵|}|↵|#type| |Option|‹|A|›| |#=| |(|None|)| ||| |(|Some|‹|A|›|)|↵|#type| |Func| |#=| |(|number|)| |=>| |number|↵|#type| |S2| |#=| |(|string|,| |string|,| |)|↵|#trait| |I1|(||)| |{||}|↵|#trait| |I2|(||)| |{||}|↵|#type| |I3| |#=| |(|I1|)| |&| |(|I2|)|↵|#type| |StringArray| |#=| |Array|‹|string|›|↵|#type| |SomeInterface| |#=| |{|x|#:| |number|,|y|#:| |number|,|}|↵|#class| |ABC|(||)| |{||}|↵|#type| |DEF| |#=| |ABC|↵|#type| |TP|‹|A|,| |B|,| |C|›| |#=| |(|A|,| |B|,| |C|,| |)|↵|#namespace| |NA| |{|→|#fun| |fb|(|b|#:| |string|)|#:| |unit|↵|#type| |B| |#=| |string|←|↵|}|↵|#class| |NC|(||)| |{|→|#let| |b|#:| |string|←|↵|}|↵|#type| |G| |#=| |ABC|↵|#let| |none|#:| |{|_tag|#:| |"None"|,|}|↵|#fun| |some|‹|A|›|(|a|#:| |A|)|#:| |(|None|)| ||| |(|Some|‹|A|›|)| +//│ |#trait| |None|(||)| |{|→|#let| |_tag|#:| |"None"|←|↵|}|↵|#trait| |Some|‹|A|›|(||)| |{|→|#let| |_tag|#:| |"Some"|↵|#let| |value|#:| |A|←|↵|}|↵|#type| |Option|‹|A|›| |#=| |(|None|)| ||| |(|Some|‹|A|›|)|↵|#type| |Func| |#=| |(|number|)| |=>| |number|↵|#type| |S2| |#=| |(|string|,| |string|,| |)|↵|#trait| |I1|(||)| |{||}|↵|#trait| |I2|(||)| |{||}|↵|#type| |I3| |#=| |(|I1|)| |&| |(|I2|)|↵|#type| |StringArray| |#=| |Array|‹|string|›|↵|#type| |SomeInterface| |#=| |{|x|#:| |number|,|y|#:| |number|,|}|↵|#class| |ABC|(||)| |{||}|↵|#type| |DEF| |#=| |ABC|↵|#type| |TP|‹|A|,| |B|,| |C|›| |#=| |(|A|,| |B|,| |C|,| |)|↵|#module| |NA| |{|→|#fun| |fb|(|b|#:| |string|)|#:| |unit|↵|#type| |B| |#=| |string|←|↵|}|↵|#class| |NC|(||)| |{|→|#let| |b|#:| |string|←|↵|}|↵|#type| |G| |#=| |ABC|↵|#let| |none|#:| |{|_tag|#:| |"None"|,|}|↵|#fun| |some|‹|A|›|(|a|#:| |A|)|#:| |(|None|)| ||| |(|Some|‹|A|›|)| //│ Parsed: {trait None() {let _tag: "None"}; trait Some‹A›() {let _tag: "Some"; let value: A}; type alias Option‹A›(): None | Some[A] {}; type alias Func(): number -> number {}; type alias S2(): (string, string,) {}; trait I1() {}; trait I2() {}; type alias I3(): I1 & I2 {}; type alias StringArray(): Array[string] {}; type alias SomeInterface(): {x: number, y: number} {}; class ABC() {}; type alias DEF(): ABC {}; type alias TP‹A, B, C›(): (A, B, C,) {}; module NA() {fun fb: (b: string,) -> unit; type alias B(): string {}}; class NC() {let b: string}; type alias G(): ABC {}; let none: {_tag: "None"}; fun some: (a: A,) -> (None | Some[A])} diff --git a/ts2mls/js/src/test/diff/Variables.d.mls b/ts2mls/js/src/test/diff/Variables.d.mls index fbe763c783..9e16907875 100644 --- a/ts2mls/js/src/test/diff/Variables.d.mls +++ b/ts2mls/js/src/test/diff/Variables.d.mls @@ -6,13 +6,13 @@ let foo: number let bar: false class FooBar() {} let fb: FooBar -namespace ABC { +module ABC { class DEF() {} } let d: ABC.DEF -namespace DD { +module DD { let foo: number let bar: number } -//│ |#let| |URI|#:| |string|↵|#let| |URI2|#:| |string|↵|#let| |foo|#:| |number|↵|#let| |bar|#:| |false|↵|#class| |FooBar|(||)| |{||}|↵|#let| |fb|#:| |FooBar|↵|#namespace| |ABC| |{|→|#class| |DEF|(||)| |{||}|←|↵|}|↵|#let| |d|#:| |ABC|.DEF|↵|#namespace| |DD| |{|→|#let| |foo|#:| |number|↵|#let| |bar|#:| |number|←|↵|}| +//│ |#let| |URI|#:| |string|↵|#let| |URI2|#:| |string|↵|#let| |foo|#:| |number|↵|#let| |bar|#:| |false|↵|#class| |FooBar|(||)| |{||}|↵|#let| |fb|#:| |FooBar|↵|#module| |ABC| |{|→|#class| |DEF|(||)| |{||}|←|↵|}|↵|#let| |d|#:| |ABC|.DEF|↵|#module| |DD| |{|→|#let| |foo|#:| |number|↵|#let| |bar|#:| |number|←|↵|}| //│ Parsed: {let URI: string; let URI2: string; let foo: number; let bar: false; class FooBar() {}; let fb: FooBar; module ABC() {class DEF() {}}; let d: ABC.DEF; module DD() {let foo: number; let bar: number}} From 3a521dc49aa7a84718011791dd5c1411863c1830 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 6 Jun 2023 14:25:32 +0800 Subject: [PATCH 350/498] Clean up constraint solver, removing unused def --- .../scala/mlscript/ConstraintSolver.scala | 127 +----------------- shared/src/test/diff/nu/TypreMembers.mls | 29 ++++ 2 files changed, 34 insertions(+), 122 deletions(-) create mode 100644 shared/src/test/diff/nu/TypreMembers.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index f8298a1b9b..7af9bd4c71 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -51,6 +51,7 @@ class ConstraintSolver extends NormalForms { self: Typer => } + /** Note: `mkType` is just for reporting errors. */ def lookupField(mkType: () => ST, clsNme: Opt[Str], rfnt: Var => Opt[FieldType], tags: SortedSet[AbstractTag], fld: Var) (implicit ctx: Ctx, raise: Raise) @@ -83,8 +84,6 @@ class ConstraintSolver extends NormalForms { self: Typer => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => S(p.ty) - // case S(p: NuTypeParam) => - // S(p.ty) case S(m) => S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) case N => N @@ -104,8 +103,6 @@ class ConstraintSolver extends NormalForms { self: Typer => val freshenedRaw = raw.map { raw => - // TODO dedup with below logic from `lookupNuTypeDef` - implicit val freshened: MutMap[TV, ST] = MutMap.empty implicit val shadows: Shadows = Shadows.empty @@ -136,13 +133,10 @@ class ConstraintSolver extends NormalForms { self: Typer => case tv: TypeVarOrRigidVar => println(s"Immediate $tv := $targ"); tv case _ => println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) println(s"Set ${tv} ~> ${_tv}") assert(tv.assignedTo.isEmpty) tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") tv }) @@ -182,91 +176,6 @@ class ConstraintSolver extends NormalForms { self: Typer => }() - // def lookupNuTypeDef(clsNme: Str, rfnt: Map[Var, FieldType]) - def lookupNuTypeDef(clsNme: Str, rfnt: Var => Opt[FieldType]) - // (implicit raise: Raise, cctx: ConCtx, ctx: Ctx, shadows: Shadows) - (implicit ctx: Ctx, raise: Raise) - : TypedNuCls = { - val info = ctx.tyDefs2.getOrElse(clsNme, die/*TODO*/) - - info.complete() match { - case td: TypedNuCls => - implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty - // freshened ++= td.tparams.map(tp => tp._2 -> TopType) - - // /* - td.tparams.foreach { case (tn, _tv, vi) => - // val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint) - val targ = rfnt(Var(td.nme.name + "#" + tn.name)) match { - case S(fty) => - TypeBounds( - fty.lb.getOrElse(BotType), - fty.ub, - )(_tv.prov) - case N => - // FIXME type bounds are kind of wrong for this - TypeBounds( - // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), - // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), - _tv.lowerBounds.foldLeft( - Extruded(false, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST - // ^ TODO provide extrusion reason? - )(_ | _), - _tv.upperBounds.foldLeft( - Extruded(true, SkolemTag(_tv.level, _tv)(provTODO))(provTODO, Nil): ST - // ^ TODO provide extrusion reason? - )(_ & _), - )(_tv.prov) - } - // println(s"Assigning ${_tv} ~> $tv := $targ where ${ - // targ.ub.showBounds}${targ.showBounds}") - // // targ.ub.showBounds}${targ.lb.fold("")(_.showBounds)}") - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = - freshVar(_tv.prov, N, _tv.nameHint)(targ.level) // TODO safe not to set original?! - // freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) // TODO safe not to set original?! - println(s"Set ${_tv} ~> $tv") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - // println(s"Assigned ${tv.assignedTo}") - freshened += _tv -> tv - } - // */ - /* - td.tparams.foreach { case (tn, tv) => - assert(tv.assignedTo.isEmpty) - val targ = rfnt.get(Var(td.nme.name + "#" + tn.name)) match { - case S(fty) => - TypeBounds( - fty.lb.getOrElse(BotType), - fty.ub, - )(tv.prov) - case N => - // FIXME type bounds are kind of wrong for this - TypeBounds( - tv.lowerBounds.foldLeft(BotType: ST)(_ | _), - tv.upperBounds.foldLeft(TopType: ST)(_ & _), - )(tv.prov) - } - println(s"Type param $tv := ${targ}") - freshened += tv -> targ - } - */ - - // println(td) - // val res = td.freshenAbove(td.level + 1, rigidify = true).asInstanceOf[TypedNuCls] - val res = - // td.freshenAbove(td.level, rigidify = true).asInstanceOf[TypedNuCls] - td.freshenAbove(td.level, rigidify = false) - // println(res) - // println(res.members.map(_._2.asInstanceOf[TypedNuFun].ty.showBounds)) - res - case _ => ??? - } - } - - type ShadowSet = Set[ST -> ST] case class Shadows(current: ShadowSet, previous: ShadowSet) { def size: Int = current.size + previous.size @@ -646,15 +555,9 @@ class ConstraintSolver extends NormalForms { self: Typer => )(provTODO).toUpper(provTODO) :: Nil)(provTODO), false) } } else { - // val lti = ctx.tyDefs2(nme) - // if (lti.isComputing) - // annoying(Nil, LhsRefined(N, ts, r, trs0), Nil, done_rs) // TODO maybe pick a parent class here instead? - // else { - // val fty = lookupNuTypeDefField(lookupNuTypeDef(nme, r.fields.toMap.get), fldNme) - val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, fldNme) - rec(fty.ub, fldTy.ub, false) - recLb(fldTy, fty) - // } + val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, fldNme) + rec(fty.ub, fldTy.ub, false) + recLb(fldTy, fty) } case (LhsRefined(S(pt: ClassTag), ts, r, trs), RhsBases(pts, bf, trs2)) => println(s"class checking $pt $pts") @@ -717,26 +620,6 @@ class ConstraintSolver extends NormalForms { self: Typer => } }() - /* - def lookupNuTypeDefField(cls: TypedNuCls, fld: Var): FieldType = { - // println(fld.name, cls.members) - // println(s"Looking up $fld in ${cls.td.nme}") - val res = cls.members.get(fld.name) match { - case S(d: TypedNuFun) => - d.typeSignature.toUpper(provTODO) - case S(p: NuParam) => - p.ty - case N => - err(msg"${cls.td.kind.str} `${cls.td.nme.name}` does not contain member `${fld.name}`", - // ttp(fld)) - fld.toLoc).toUpper(noProv) - case _ => ??? // TODO - } - println(s"Lookup ${cls.td.nme.name}.${fld.name} : $res where ${res.ub.showBounds}") - res - } - */ - /** Helper function to constrain Field lower bounds. */ def recLb(lhs: FieldType, rhs: FieldType) (implicit raise: Raise, cctx: ConCtx, prevCctxs: Ls[ConCtx], ctx: Ctx, shadows: Shadows): Unit = { diff --git a/shared/src/test/diff/nu/TypreMembers.mls b/shared/src/test/diff/nu/TypreMembers.mls new file mode 100644 index 0000000000..69ac693444 --- /dev/null +++ b/shared/src/test/diff/nu/TypreMembers.mls @@ -0,0 +1,29 @@ +:NewDefs + + +class Test { type T = Int } +//│ class Test { +//│ type T = Int +//│ } + +1 : Test.T +//│ Int +//│ res +//│ = 1 + + +trait Test { type T = Int } +//│ trait Test { +//│ type T = Int +//│ } + +:e +1 : Test.T +//│ ╔══[ERROR] Illegal prefix of type selection: Test +//│ ║ l.21: 1 : Test.T +//│ ╙── ^^^^ +//│ error +//│ res +//│ = 1 + + From 0bddddee5becde9022d34bd55eb9e35520e42388 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 6 Jun 2023 14:36:57 +0800 Subject: [PATCH 351/498] Refactor abstract instantiation check --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 - shared/src/main/scala/mlscript/Typer.scala | 37 +++++++++++-------- shared/src/test/diff/nu/Uninstantiable.mls | 16 ++++++-- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index dbf553afde..895961283b 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -429,7 +429,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - // TODO check this is not misused def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, selfTy: ST, ihtags: Set[TypeName]) : ST = td.kind match { case Mod => @@ -437,7 +436,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ihtags + TN("Object") )(provTODO) case Cls => - // TODO deal with classes without parameter lists (ie needing `new`) PolymorphicType.mk(level, FunctionType( TupleType(params.mapKeys(some))(provTODO), diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index c7512b2d94..c61709a17b 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -229,8 +229,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne NuTypeDef(Cls, TN("Num"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Cls, TN("Int"), Nil, N, N, N, Var("Num") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Cls, TN("Bool"), Nil, N, N, S(Union(TN("true"), TN("false"))), Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), - NuTypeDef(Mod, TN("true"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), - NuTypeDef(Mod, TN("false"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), + NuTypeDef(Mod, TN("true"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, N), + NuTypeDef(Mod, TN("false"), Nil, N, N, N, Var("Bool") :: Nil, N, N, TypingUnit(Nil))(N, N), NuTypeDef(Cls, TN("Str"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), ) val builtinTypes: Ls[TypeDef] = @@ -825,21 +825,28 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne ) ) case VarSymbol(ty, _) => ty - case ti: CompletedTypeInfo => - ti.member match { - case ti: TypedNuFun => - ti.typeSignature - case p: NuParam => - p.typeSignature - case ti: TypedNuCls => - if (ti.decl.isAbstract) - err(msg"Class ${ti.nme} is abstract and cannot be instantiated", term.toLoc) + case lti: LazyTypeInfo => + // TODO deal with classes without parameter lists (ie needing `new`) + def checkNotAbstract(decl: NuDecl) = + if (decl.isAbstract) + err(msg"Class ${decl.name} is abstract and cannot be instantiated", term.toLoc) + lti match { + case ti: CompletedTypeInfo => + ti.member match { + case ti: TypedNuFun => + ti.typeSignature + case p: NuParam => + p.typeSignature + case ti: TypedNuCls => + checkNotAbstract(ti.decl) + ti.typeSignature + case ti: TypedNuDecl => + err(msg"${ti.kind.str} ${ti.name} cannot be used in term position", prov.loco) + } + case ti: DelayedTypeInfo => + checkNotAbstract(ti.decl) ti.typeSignature - case ti: TypedNuDecl => - err(msg"${ti.kind.str} ${ti.name} cannot be used in term position", prov.loco) } - case ti: DelayedTypeInfo => - ti.typeSignature } mkProxy(ty, prov) // ^ TODO maybe use a description passed in param? diff --git a/shared/src/test/diff/nu/Uninstantiable.mls b/shared/src/test/diff/nu/Uninstantiable.mls index 5feffb31cc..a9a683fab7 100644 --- a/shared/src/test/diff/nu/Uninstantiable.mls +++ b/shared/src/test/diff/nu/Uninstantiable.mls @@ -1,24 +1,34 @@ :NewDefs -// FIXME forbid statically +:e Int +//│ ╔══[ERROR] Class Int is abstract and cannot be instantiated +//│ ║ l.5: Int +//│ ╙── ^^^ //│ () -> Int //│ Code generation encountered an error: //│ unresolved symbol Int -// FIXME forbid statically +:e Int() +//│ ╔══[ERROR] Class Int is abstract and cannot be instantiated +//│ ║ l.14: Int() +//│ ╙── ^^^ //│ Int //│ Code generation encountered an error: //│ unresolved symbol Int -// FIXME forbid statically +:e new Int +//│ ╔══[ERROR] Class Int is abstract and cannot be instantiated +//│ ║ l.23: new Int +//│ ╙── ^^^ //│ Int //│ Code generation encountered an error: //│ unresolved symbol Int + // FIXME forbid statically module A extends Int //│ module A extends Int, Num From e2d140b11b1ad40644404afb6a375e0f4865cd03 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 9 Jun 2023 17:31:56 +0800 Subject: [PATCH 352/498] Improve type inference with variant type definitions --- .../scala/mlscript/ConstraintSolver.scala | 18 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 6 +- .../main/scala/mlscript/TypeSimplifier.scala | 53 +++-- .../main/scala/mlscript/TyperDatatypes.scala | 20 +- .../main/scala/mlscript/TyperHelpers.scala | 17 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 63 +++--- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 181 ++++++++---------- shared/src/test/diff/gadt/Exp2.mls | 18 +- shared/src/test/diff/nu/DiamondInherit.mls | 2 +- shared/src/test/diff/nu/EncodedLists.mls | 2 +- shared/src/test/diff/nu/Eql.mls | 8 +- shared/src/test/diff/nu/ExplicitVariance.mls | 88 ++------- shared/src/test/diff/nu/GenericModules.mls | 8 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 2 +- shared/src/test/diff/nu/Interfaces.mls | 2 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 86 ++++----- .../test/diff/nu/TrickyGenericInheritance.mls | 52 +++-- shared/src/test/diff/nu/WeirdUnions.mls | 60 ++++++ shared/src/test/diff/nu/repro0.mls | 23 +++ shared/src/test/diff/nu/repro1.mls | 47 +++++ shared/src/test/diff/nu/repro_EvalNegNeg.mls | 4 +- shared/src/test/diff/ucs/HygienicBindings.mls | 2 +- shared/src/test/diff/ucs/NestedBranches.mls | 2 +- shared/src/test/diff/ucs/zipWith.mls | 4 +- 24 files changed, 421 insertions(+), 347 deletions(-) create mode 100644 shared/src/test/diff/nu/WeirdUnions.mls create mode 100644 shared/src/test/diff/nu/repro0.mls create mode 100644 shared/src/test/diff/nu/repro1.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 7af9bd4c71..a4376f9e5e 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -108,13 +108,16 @@ class ConstraintSolver extends NormalForms { self: Typer => info.tparams.foreach { case (tn, _tv, vi) => val targ = rfnt(Var(info.decl.name + "#" + tn.name)) match { + // * TODO to avoid infinite recursion due to ever-expanding type args, + // * we should set the shadows of the targ to be the same as that of the parameter it replaces... + case S(fty) if vi === S(VarianceInfo.co) => fty.ub + case S(fty) if vi === S(VarianceInfo.contra) => fty.lb.getOrElse(BotType) case S(fty) => TypeBounds.mk( fty.lb.getOrElse(BotType), fty.ub, ) case N => - // FIXME type bounds are kind of wrong for this TypeBounds( // _tv.lowerBounds.foldLeft(BotType: ST)(_ | _), // _tv.upperBounds.foldLeft(TopType: ST)(_ & _), @@ -128,18 +131,7 @@ class ConstraintSolver extends NormalForms { self: Typer => )(_ & _), )(_tv.prov) } - - freshened += _tv -> (targ match { - case tv: TypeVarOrRigidVar => println(s"Immediate $tv := $targ"); tv - case _ => - println(s"Assigning ${_tv} := $targ where ${targ.showBounds}") - val tv = freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) - println(s"Set ${tv} ~> ${_tv}") - assert(tv.assignedTo.isEmpty) - tv.assignedTo = S(targ) - tv - }) - + freshened += _tv -> targ } raw.freshenAbove(info.level, rigidify = false) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 895961283b..34b7f32fe3 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -245,17 +245,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case S(res) => res case N => trace(s"Computing variances of ${this.name}") { val store = VarianceStore.empty + val traversed = MutSet.empty[Pol -> TV] + object Trav extends Traverser2.InvariantFields { override def apply(pol: PolMap)(ty: ST): Unit = trace(s"Trav($pol)($ty)") { ty match { - case tv: TypeVariable => + case tv: TypeVariable => if (traversed.add(pol(tv) -> tv)) { store(tv) = store.getOrElse(tv, VarianceInfo.bi) && (pol(tv) match { case S(true) => VarianceInfo.co case S(false) => VarianceInfo.contra case N => VarianceInfo.in }) super.apply(pol)(ty) + } case ty @ RecordType(fs) => // Ignore type param members such as `C#A` in `{C#A: mut A30'..A30'}` super.apply(pol)(RecordType(fs.filterNot(_._1.name.contains('#')))(ty.prov)) @@ -1335,6 +1338,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inheritedTags, tparamMembers )(thisType) + .tap(_.variances) // * Force variance computation } case Mxn => diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index ed51b0016d..d088eba871 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -491,6 +491,9 @@ trait TypeSimplifier { self: Typer => def simplifyType(st: TypeLike, pol: Opt[Bool] = S(true), removePolarVars: Bool = true, inlineBounds: Bool = true)(implicit ctx: Ctx): TypeLike = { + // * There are two main analyses, which are quite subtle. + // * TODO: add assertion to check that their results are consistent! + // * * Analysis 1: count number of TV occurrences at each polarity // * and find whether they're used in invariant positions @@ -518,13 +521,17 @@ trait TypeSimplifier { self: Typer => } tv.assignedTo match { case S(ty) => - if (pol.base =/= S(false)) - analyzed1.setAndIfUnset(tv -> true) { apply(pol)(ty) } - if (pol.base =/= S(true)) - analyzed1.setAndIfUnset(tv -> false) { apply(pol.contravar)(ty) } - // * Note: in principle this should also do it, - // * but it currently leads to a couple worse-looking simplified types: - // analyzed1.setAndIfUnset(tv -> true) { apply(pol)(ty) } + // * This is quite subtle! + // * We should traverse assigned type variables as though they weren't there, + // * but they may appear in their own assignment, + // * so we still need to check they haven't been traversed yet. + // * Moreover, traversing them at different polarities may produce different results + // * (think of `'A# -> 'A#` where 'A# := 'X`), + // * so we should remember the traversal polarity in the cache. + // * Thanks to the invariant that the assignment shouldn't have a higher level than + // * the type variable itself, I think it is fine to never re-traverse the assignment + // * at the same polarity *even though the polmap may be different*. + analyzed1.setAndIfUnset(tv -> pol(tv).getOrElse(false)) { apply(pol)(ty) } case N => if (pol(tv) =/= S(false)) analyzed1.setAndIfUnset(tv -> true) { tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) } @@ -548,7 +555,7 @@ trait TypeSimplifier { self: Typer => // * * Analysis 2: find the polar co-occurrences of each TV - // * TODO what about negatively quantified vars? the notion of co-occurrence would be reversed (wrt unions/inters) + // * Note: for negatively quantified vars, the notion of co-occurrence is reversed (wrt unions/inters)... val coOccurrences: MutMap[(Bool, TypeVariable), MutSet[SimpleType]] = LinkedHashMap.empty @@ -730,7 +737,16 @@ trait TypeSimplifier { self: Typer => // val allVars = st.getVars val allVars = analyzed1.iterator.map(_._1).toSortedSet - var recVars = MutSet.from(allVars.iterator.filter(_.isRecursive_$)) + def computeRecVars = + allVars.iterator.filter(v => !varSubst.contains(v) && ( + v.isRecursive_$ + // * Note: a more precise version could be the following, + // * but it doesn't seem to change anything in our test suite, so I left if commented for now: + // // * Only consider recursive those variables that recursive in their *reachable* bounds: + // occNums.contains(true -> v) && v.isPosRecursive_$ || occNums.contains(false -> v) && v.isNegRecursive_$ + )).toSet + + var recVars = computeRecVars println(s"[vars] ${allVars}") println(s"[rec] ${recVars}") @@ -890,7 +906,7 @@ trait TypeSimplifier { self: Typer => // * applying the var substitution and simplifying some things on the fly. // * The recursive vars may have changed due to the previous phase! - recVars = MutSet.from(allVars.iterator.filter(v => !varSubst.contains(v) && v.isRecursive_$)) + recVars = computeRecVars println(s"[rec] ${recVars}") val renewals = MutMap.empty[TypeVariable, TypeVariable] @@ -962,25 +978,27 @@ trait TypeSimplifier { self: Typer => pol(tv) match { case S(p) if inlineBounds && !occursInvariantly(tv) && !recVars.contains(tv) => // * Inline the bounds of non-rec non-invar-occ type variables - println(s"Inlining bounds of $tv (~> $res) ${printPol(p)}") + println(s"Inlining [${printPol(p)}] bounds of $tv (~> $res)") // if (p) mergeTransform(true, pol, tv, Set.single(tv), canDistribForall) | res // else mergeTransform(false, pol.contravar, tv, Set.single(tv), canDistribForall) & res if (p) mergeTransform(true, pol, tv, Set.single(tv), canDistribForall) | res else mergeTransform(false, pol, tv, Set.single(tv), canDistribForall) & res - case _ if (!wasDefined) => + case poltv if (!wasDefined) => def setBounds = { - trace(s"Setting bounds of $res...") { + trace(s"Setting [±] bounds of $res... (failing ${printPol(poltv)}, inlineBounds $inlineBounds, !occursInvariantly ${!occursInvariantly(tv)}, !recVars.contains(tv) ${!recVars.contains(tv)})") { tv.assignedTo match { case S(ty) => res.assignedTo = S(transform(ty, pol.invar, semp, canDistribForall)) case N => - res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) - res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) + if (occNums.contains(true -> tv)) + res.lowerBounds = tv.lowerBounds.map(transform(_, pol.at(tv.level, true), Set.single(tv))) + if (occNums.contains(false -> tv)) + res.upperBounds = tv.upperBounds.map(transform(_, pol.at(tv.level, false), Set.single(tv))) } res }() } - pol(tv) match { + poltv match { case polo @ S(p) if coOccurrences.get(!p -> tv).isEmpty // * If tv is polar... && tv.assignedTo.isEmpty // TODO handle? @@ -1230,6 +1248,9 @@ trait TypeSimplifier { self: Typer => def apply(st: TypeLike, all: Bool = true)(implicit ctx: Ctx): TypeLike = { var cur = st + debugOutput(s"⬤ Initial: ${cur}") + debugOutput(s" where: ${cur.showBounds}") + cur = removeIrrelevantBounds(cur, inPlace = false) debugOutput(s"⬤ Cleaned up: ${cur}") debugOutput(s" where: ${cur.showBounds}") diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index cfc741984c..673f08defe 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -515,15 +515,6 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => private lazy val trueOriginal: Opt[TV] = originalTV.flatMap(_.trueOriginal.orElse(originalTV)) - override def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) - : TypeVarOrRigidVar = - super.freshenAbove(lim, rigidify) match { - case tv: TypeVarOrRigidVar => - tv // * Note that type variables can be refreshed as rigid variables (trait tags) - case _ => die - } - def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = if (level <= ub) level else { if (cache(this)) MinLevel else { @@ -554,10 +545,15 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => }) + (if (assignedTo.isDefined) "#" else "") private[mlscript] def mkStr = nameHint.getOrElse("α") + uid - def isRecursive_$(implicit ctx: Ctx) : Bool = (lbRecOccs_$, ubRecOccs_$) match { - case (S(N | S(true)), _) | (_, S(N | S(false))) => true + final def isRecursive_$(implicit ctx: Ctx) : Bool = isPosRecursive_$ || isNegRecursive_$ + final def isPosRecursive_$(implicit ctx: Ctx) : Bool = lbRecOccs_$ match { + case S(N | S(true)) => true case _ => false - } + } + final def isNegRecursive_$(implicit ctx: Ctx) : Bool = ubRecOccs_$ match { + case S(N | S(false)) => true + case _ => false + } /** None: not recursive in this bound; Some(Some(pol)): polarly-recursive; Some(None): nonpolarly-recursive. * Note that if we have something like 'a :> Bot <: 'a -> Top, 'a is not truly recursive * and its bounds can actually be inlined. */ diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index ca6fb82f13..994173245b 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -79,9 +79,12 @@ abstract class TyperHelpers { Typer: Typer => def subst(ts: PolymorphicType, map: Map[SimpleType, SimpleType]): PolymorphicType = PolymorphicType(ts.polymLevel, subst(ts.body, map)) - def substLike(ty: TL, map: Map[SimpleType, SimpleType], substInMap: Bool): TL = ty match { + def substLike(ty: TL, map: Map[SimpleType, SimpleType], substInMap: Bool)(implicit ctx: Ctx): TL = ty match { case ty: ST => subst(ty, map, substInMap) - case _ => ??? // TODO + case OtherTypeLike(ot) => + TypedTypingUnit( + ot.implementedMembers.map(_.map(subst(_, map, substInMap))), + ot.result.map(subst(_, map, substInMap))) } def subst(st: SimpleType, map: Map[SimpleType, SimpleType], substInMap: Bool = false) (implicit cache: MutMap[TypeVariable, SimpleType] = MutMap.empty): SimpleType = @@ -758,8 +761,9 @@ abstract class TyperHelpers { Typer: Typer => case tv @ AssignedVariable(ty) => pol -> ty :: Nil case tv: TypeVariable => - (if (pol(tv) =/= S(false)) tv.lowerBounds.map(pol.at(tv.level, true) -> _) else Nil) ::: - (if (pol(tv) =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) + val poltv = pol(tv) + (if (poltv =/= S(false)) tv.lowerBounds.map(pol.at(tv.level, true) -> _) else Nil) ::: + (if (poltv =/= S(true)) tv.upperBounds.map(pol.at(tv.level, false) -> _) else Nil) case FunctionType(l, r) => pol.contravar -> l :: pol.covar -> r :: Nil case Overload(as) => as.map(pol -> _) case ComposedType(_, l, r) => pol -> l :: pol -> r :: Nil @@ -1244,8 +1248,9 @@ abstract class TyperHelpers { Typer: Typer => def apply(pol: PolMap)(st: ST): Unit = st match { case tv @ AssignedVariable(ty) => apply(pol)(ty) case tv: TypeVariable => - if (pol(tv) =/= S(false)) tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) - if (pol(tv) =/= S(true)) tv.upperBounds.foreach(apply(pol.at(tv.level, false))) + val poltv = pol(tv) + if (poltv =/= S(false)) tv.lowerBounds.foreach(apply(pol.at(tv.level, true))) + if (poltv =/= S(true)) tv.upperBounds.foreach(apply(pol.at(tv.level, false))) case FunctionType(l, r) => apply(pol.contravar)(l); apply(pol)(r) case Overload(as) => as.foreach(apply(pol)) case ComposedType(_, l, r) => apply(pol)(l); apply(pol)(r) diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 6bc4df3fcb..955948ef7d 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -40,7 +40,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (Cons[{_1: anything, _2: 'A}] | Nil, Var,) -> ('A | Var) +//│ fun eval: (Cons[{_1: anything, _2: 'result}] | Nil, Var,) -> (Var | 'result) //│ } class Abs[A](x: Str, t: A) @@ -78,21 +78,20 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'A}] | Nil, Abs['t] | App['A0] | Var,) -> ('b | 'a) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'result}] | Nil, Abs['t] | App['A] | Var,) -> ('result | 'a) //│ } //│ where -//│ 't <: Abs['t] | App['A0] | Var -//│ 'A0 <: Abs['t & (Abs['t] | App['A0] | Var)] | Abs['t] & ~#Abs | App['A0] | Var -//│ 'A :> 'b | 'a -//│ 'b :> 'A | Var | 'a -//│ 'a :> App['b | 'a] | Abs['b | 'a] +//│ 't <: Abs['t] | App['A] | Var +//│ 'A <: Abs['t & (Abs['t] | App['A] | Var)] | Abs['t] & ~#Abs | App['A] | Var +//│ 'result :> 'a | Var +//│ 'a :> App['result | 'a] | Abs['result | 'a] Test1.eval(Nil, Var("a")) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Var | 'b | 'a //│ res //│ = Var {} @@ -101,7 +100,7 @@ Test1.eval(Nil, Abs("b", Var("a"))) //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Var | 'b | 'a //│ res //│ = Abs {} @@ -110,7 +109,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Var | 'b | 'a //│ res //│ = Var {} @@ -119,7 +118,7 @@ Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c" //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Abs[Var] | Var | 'b | 'a //│ res //│ = Var {} @@ -156,7 +155,7 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: Object & 'A}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> ('A | Numb | Var | 'a) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: Object & 'result}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> (Numb | Var | 'result | 'a) //│ } //│ where //│ 'b <: Add['b] | Mul['b] | Numb | Var @@ -180,16 +179,16 @@ Test2.eval(Cons(("a", Numb(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.181: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.180: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.181: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.180: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.134: if v is +//│ ║ l.133: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.144: let vv = map_expr(eta, v) +//│ ║ l.143: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Numb | Var | error //│ res @@ -203,12 +202,12 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'A 'a. (Cons[{_1: anything, _2: 'A0}] | Nil, Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App,) -> ('c | 'a) +//│ fun eval: forall 'A 'a. (Cons[{_1: anything, _2: 'result}] | Nil, Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App,) -> ('c | 'a) //│ } //│ where -//│ 'A0 :> 'c | 'a -//│ <: Object -//│ 'c :> 'A0 | Numb | Var | 'b | 'a +//│ 'result :> 'c | 'a +//│ <: Object +//│ 'c :> Numb | Var | 'result | 'b | 'a //│ 'a :> App['c | 'a] | Abs['c | 'a] //│ 'b <: Add['d] | Mul['d] | Numb | Var //│ 'd <: Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App @@ -220,7 +219,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Numb | Var +//│ 'c :> Abs[Var] | Numb | Var | 'b //│ res //│ = Abs {} @@ -229,40 +228,40 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Num //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Numb | Var] | Numb | Var +//│ 'c :> Abs[Var] | Add[Numb | Var] | Numb | Var | 'b //│ res //│ = Var {} // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'A}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> ('a | 'c) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'result}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> ('a | 'c) //│ } //│ where //│ 'b <: Add['b] | Mul['b] | Numb | Var -//│ 'A :> 'c -//│ <: Object -//│ 'c :> 'A | Abs[Numb | 'c] | App[Numb | 'c] | Numb | Var +//│ 'result :> 'c +//│ <: Object +//│ 'c :> Abs[Numb | 'c] | App[Numb | 'c] | Numb | Var | 'result // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.250: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.249: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.250: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.249: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.134: if v is +//│ ║ l.133: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.144: let vv = map_expr(eta, v) +//│ ║ l.143: let vv = map_expr(eta, v) //│ ╙── ^ -//│ error | 'a +//│ Abs[Var] | error | 'a //│ where -//│ 'a :> Abs[Var] | Numb | Var | Abs['a] | App['a] +//│ 'a :> Abs[Numb | 'a] | App[Numb | 'a] | Numb | Var //│ res //│ Runtime error: //│ Error: non-exhaustive case expression diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 65d2176f88..569a84d813 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -10,10 +10,10 @@ class Vector(x: Int, y: Int) //│ class Vector(x: Int, y: Int) class Circle(radius: Int) -class Outside[Region](a: Region) -class Union[Region](a: Region, b: Region) -class Intersect[Region](a: Region, b: Region) -class Translate[Region](v: Vector, a: Region) +class Outside[out Region](a: Region) +class Union[out Region](a: Region, b: Region) +class Intersect[out Region](a: Region, b: Region) +class Translate[out Region](v: Vector, a: Region) //│ class Circle(radius: Int) //│ class Outside[Region](a: Region) //│ class Union[Region](a: Region, b: Region) @@ -30,8 +30,8 @@ mixin SizeBase { Translate(_, a) then this.size(a) + 1 } //│ mixin SizeBase() { -//│ this: {size: ('a | 'a0 | 'a1 | 'a2) -> Int} -//│ fun size: (Circle | Intersect['a2] | Outside['a0] | Translate['a] | Union['a1]) -> Int +//│ this: {size: 'a -> Int} +//│ fun size: (Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a]) -> Int //│ } // ******************* Linguistic Reuse and Meta-Language Optimizations ******************* @@ -60,7 +60,7 @@ let circles = go(2, 1024) class Univ() class Empty() -class Scale[Region](v: Vector, a: Region) +class Scale[out Region](v: Vector, a: Region) //│ class Univ() //│ class Empty() //│ class Scale[Region](v: Vector, a: Region) @@ -81,11 +81,11 @@ mixin SizeExt { module TestSize extends SizeBase, SizeExt //│ module TestSize { -//│ fun size: (Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ) -> Int +//│ fun size: 'a -> Int //│ } //│ where -//│ 'b <: Circle | Intersect[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Outside[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Translate[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Union[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] //│ 'a <: Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ +//│ 'b <: Circle | Intersect[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Outside[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Translate[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Union[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] TestSize.size(Empty()) //│ Int @@ -119,19 +119,16 @@ mixin Contains { Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) } //│ mixin Contains() { -//│ this: {contains: ('a | 'a0 | 'a1, 'b,) -> Bool & ('a2, Vector,) -> 'c} -//│ fun contains: (Circle | Intersect['a1] | Outside['a] | Translate['a2] | Union['a0], {x: Int, y: Int} & 'b,) -> (Bool | 'c) +//│ this: {contains: ('a, 'b,) -> Bool & ('a0, Vector,) -> 'c} +//│ fun contains: (Circle | Intersect['a] | Outside['a] | Translate['a0] | Union['a], {x: Int, y: Int} & 'b,) -> (Bool | 'c) //│ } module TestContains extends Contains //│ module TestContains { -//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: Int, y: Int},) -> Bool +//│ fun contains: ('a, {x: Int, y: Int},) -> Bool //│ } //│ where -//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] TestContains.contains(Translate(Vector(0, 0), Circle(1)), Vector(0, 0)) //│ Bool @@ -171,17 +168,17 @@ mixin Text { :e module SizeText extends Text -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?d -> (?e | ?a | ?b | ?c | ?f)}` does not contain member `size` -//│ ║ l.165: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?b -> (?d | ?f | ?a | ?c | ?e)}` does not contain member `size` +//│ ║ l.162: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?d -> (?b | ?f | ?e | ?c | ?a)}` does not contain member `size` -//│ ║ l.164: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?a | ?b | ?c | ?f | ?d)}` does not contain member `size` +//│ ║ l.161: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?b -> (?e | ?f | ?a | ?c | ?d)}` does not contain member `size` -//│ ║ l.163: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?b -> (?e | ?d | ?c | ?a | ?f)}` does not contain member `size` +//│ ║ l.160: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?b | ?a | ?f | ?d | ?c)}` does not contain member `size` -//│ ║ l.162: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?d | ?f | ?c | ?a | ?b)}` does not contain member `size` +//│ ║ l.159: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> Str @@ -190,14 +187,11 @@ module SizeText extends Text // * Note: this inferred type got *much worse* after this commit (field access type refinement) module SizeText extends SizeBase, Text //│ module SizeText { -//│ fun size: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]) -> Int -//│ fun text: forall 'Region 'Region0. (Circle | Intersect[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Outside[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Translate[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]] | Union[Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0]]) -> Str +//│ fun size: 'a -> Int +//│ fun text: (Circle | Intersect['a] | Outside[Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a]] | Translate['a] | Union['a]) -> Str //│ } //│ where -//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] SizeText.text(circles) //│ Str @@ -231,8 +225,8 @@ mixin IsUniv { else false } //│ mixin IsUniv() { -//│ this: {isEmpty: 'a -> 'b, isUniv: ('a0 | 'a1) -> Bool & ('a2 | 'a3) -> 'b} -//│ fun isUniv: (Intersect['a1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a3] | Translate['a2] | Union['a0] | Univ) -> (Bool | 'b) +//│ this: {isEmpty: 'a -> 'b, isUniv: 'a0 -> Bool & 'a1 -> 'b} +//│ fun isUniv: (Intersect['a0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a1] | Translate['a1] | Union['a0] | Univ) -> (Bool | 'b) //│ } mixin IsEmpty { @@ -247,43 +241,27 @@ mixin IsEmpty { else false } //│ mixin IsEmpty() { -//│ this: {isEmpty: ('a | 'a0) -> Bool & ('a1 | 'a2) -> 'b, isUniv: 'a3 -> 'b} -//│ fun isEmpty: (Intersect['a0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a3] | Scale['a2] | Translate['a1] | Union['a] | Univ) -> (Bool | 'b) +//│ this: {isEmpty: 'a -> Bool & 'a0 -> 'b, isUniv: 'a1 -> 'b} +//│ fun isEmpty: (Intersect['a] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a1] | Scale['a0] | Translate['a0] | Union['a] | Univ) -> (Bool | 'b) //│ } module IsUnivIsEmpty extends IsUniv, IsEmpty //│ module IsUnivIsEmpty { -//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ) -> (Bool | 'b) -//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ) -> (Bool | 'b) +//│ fun isEmpty: 'a -> (Bool | 'b) +//│ fun isUniv: 'a0 -> (Bool | 'c) //│ } //│ where -//│ 'Region0 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ -//│ 'a <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ -//│ 'Region2 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ -//│ 'a3 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ -//│ 'a4 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ -//│ 'Region1 <: Intersect['Region2] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region1] | Univ -//│ 'a2 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ -//│ 'a0 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ -//│ 'a1 <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ -//│ 'Region <: Intersect['Region0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region] | Univ +//│ 'a0 <: Intersect['a0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a0] | Scale['a0] | Translate['a0] | Union['a0] | Univ +//│ 'a <: Intersect['a] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ module IsUnivIsEmpty extends IsEmpty, IsUniv //│ module IsUnivIsEmpty { -//│ fun isEmpty: forall 'Region 'Region0. (Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ) -> (Bool | 'b) -//│ fun isUniv: forall 'Region1 'Region2. (Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ) -> (Bool | 'b) +//│ fun isEmpty: 'a -> (Bool | 'b) +//│ fun isUniv: 'a0 -> (Bool | 'c) //│ } //│ where -//│ 'Region <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ -//│ 'a <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ -//│ 'Region1 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ -//│ 'a3 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ -//│ 'a4 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ -//│ 'Region2 <: Intersect['Region1] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a2] | Scale['a3] | Translate['a4] | Union['Region2] | Univ -//│ 'a2 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ -//│ 'a0 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ -//│ 'a1 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ -//│ 'Region0 <: Intersect['Region] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a0] | Translate['a1] | Union['Region0] | Univ +//│ 'a0 <: Intersect['a0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a0] | Scale['a0] | Translate['a0] | Union['a0] | Univ +//│ 'a <: Intersect['a] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ IsUnivIsEmpty.isUniv(circles) //│ Bool | 'a @@ -320,23 +298,23 @@ mixin Eliminate { module TestElim extends Eliminate //│ module TestElim { -//│ fun eliminate: forall 'b 'Region 'c 'Region0. (Intersect['Region] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0]) -> ('d | 'c | 'b) +//│ fun eliminate: forall 'Region 'b 'Region0 'c. (Intersect['Region0] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region]) -> ('d | 'c | 'b) //│ } //│ where -//│ 'd :> 'c | 'e -//│ 'c :> Outside['d | 'c | 'f] | Union['d | 'c | 'g | 'h] | Intersect['d | 'c | 'i | 'j] | Translate['d | 'c | 'k] | Scale['d | 'c | 'l] -//│ 'Region <: Intersect['Region] | Object & 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] -//│ 'a <: Intersect['Region] | Object & 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] -//│ 'a0 <: Intersect['Region] | Object & 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] -//│ 'a1 <: Intersect['Region] | Object & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] -//│ 'a2 <: Intersect['Region] | Object & 'k & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] -//│ 'Region0 <: Intersect['Region] | Object & 'g & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region0] +//│ 'Region0 <: Intersect['Region0] | Object & 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] +//│ 'a <: Intersect['Region0] | Object & 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] +//│ 'a0 <: Intersect['Region0] | Object & 'd & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] +//│ 'a1 <: Intersect['Region0] | Object & 'g & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] +//│ 'a2 <: Intersect['Region0] | Object & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] +//│ 'Region <: Intersect['Region0] | Object & 'i & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] +//│ 'd :> 'c +//│ 'c :> Outside['d | 'c | 'f] | Union['d | 'c | 'i] | Intersect['d | 'c | 'e] | Translate['d | 'c | 'h] | Scale['d | 'c | 'g] TestElim.eliminate(Outside(Outside(Univ()))) //│ forall 'a. 'b | 'a //│ where //│ 'b :> forall 'a. Univ | 'a -//│ 'a :> Outside[forall 'a. Univ | 'b | 'a] | Scale[forall 'a. 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] +//│ 'a :> Outside[forall 'a. Univ | 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] | Scale[forall 'a. 'b | 'a] //│ res //│ = Univ {} @@ -372,38 +350,29 @@ TestElim.eliminate(mk(100)) module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate //│ module Lang { -//│ fun contains: forall 'Region 'Region0. (Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0], {x: Int, y: Int},) -> Bool -//│ fun eliminate: forall 'Region1 'b 'Region2 'c. (Intersect['Region2] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1]) -> ('d | 'c | 'b) -//│ fun isEmpty: forall 'Region3 'Region4. (Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ) -> (Bool | 'e) -//│ fun isUniv: forall 'Region5 'Region6. (Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ) -> (Bool | 'e) -//│ fun size: (Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ) -> Int -//│ fun text: (Circle | Intersect[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Outside[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Translate[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Union[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ]) -> Str +//│ fun contains: ('a, {x: Int, y: Int},) -> Bool +//│ fun eliminate: forall 'Region 'b 'c 'Region0. (Intersect['Region] | Object & 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0]) -> ('d | 'b | 'c) +//│ fun isEmpty: 'a4 -> (Bool | 'e) +//│ fun isUniv: 'a5 -> (Bool | 'f) +//│ fun size: 'Region1 -> Int +//│ fun text: 'g -> Str //│ } //│ where -//│ 'f <: Circle | Intersect[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Outside[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Translate[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] | Union[Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ] -//│ 'a11 <: Empty | Object & 'f & ~#Empty & ~#Scale & ~#Univ | Scale['a11] | Univ -//│ 'Region4 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ -//│ 'a5 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ -//│ 'Region5 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ -//│ 'a9 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ -//│ 'a10 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ -//│ 'Region6 <: Intersect['Region5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a8] | Scale['a9] | Translate['a10] | Union['Region6] | Univ -//│ 'a8 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ -//│ 'a6 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ -//│ 'a7 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ -//│ 'Region3 <: Intersect['Region4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a6] | Translate['a7] | Union['Region3] | Univ -//│ 'd :> 'c | 'g -//│ 'c :> Outside['d | 'c | 'h] | Union['d | 'c | 'i | 'j] | Intersect['d | 'c | 'k | 'l] | Translate['d | 'c | 'm] | Scale['d | 'c | 'n] -//│ 'Region2 <: Intersect['Region2] | Object & 'k & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] -//│ 'a1 <: Intersect['Region2] | Object & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] -//│ 'a2 <: Intersect['Region2] | Object & 'g & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] -//│ 'a3 <: Intersect['Region2] | Object & 'n & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] -//│ 'a4 <: Intersect['Region2] | Object & 'm & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] -//│ 'Region1 <: Intersect['Region2] | Object & 'i & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a1 & (Object & ~#Outside | Outside['a2])] | Scale['a3] | Translate['a4] | Union['Region1] -//│ 'Region <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'a0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] -//│ 'Region0 <: Circle | Intersect['Region] | Outside['a] | Translate['a0] | Union['Region0] +//│ 'g <: Circle | Intersect['Region2] | Outside[Empty | Object & 'g & ~#Empty & ~#Scale & ~#Univ | Scale['Region2] | Univ] | Translate['Region2] | Union['Region2] +//│ 'Region2 <: Empty | Object & 'g & ~#Empty & ~#Scale & ~#Univ | Scale['Region2] | Univ +//│ 'Region1 <: Empty | Object & 'h & ~#Empty & ~#Scale & ~#Univ | Scale['Region1] | Univ +//│ 'h <: Circle | Intersect['Region1] | Outside[Empty | Object & 'h & ~#Empty & ~#Scale & ~#Univ | Scale['Region1] | Univ] | Translate['Region1] | Union['Region1] +//│ 'a5 <: Intersect['a5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a5] | Translate['a5] | Union['a5] | Univ +//│ 'a4 <: Intersect['a4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a4] | Scale['a4] | Translate['a4] | Union['a4] | Univ +//│ 'Region <: Intersect['Region] | Object & 'i & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] +//│ 'a0 <: Intersect['Region] | Object & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] +//│ 'a1 <: Intersect['Region] | Object & 'd & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] +//│ 'a2 <: Intersect['Region] | Object & 'k & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] +//│ 'a3 <: Intersect['Region] | Object & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] +//│ 'Region0 <: Intersect['Region] | Object & 'm & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] +//│ 'd :> 'b +//│ 'b :> Outside['d | 'b | 'j] | Union['d | 'b | 'm] | Intersect['d | 'b | 'i] | Translate['d | 'b | 'l] | Scale['d | 'b | 'k] +//│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] Lang.size(circles) //│ Int @@ -446,17 +415,17 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.447: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.416: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.356: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.334: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.114: if a is //│ ║ ^ //│ ╟── Note: type parameter Region is defined at: -//│ ║ l.16: class Translate[Region](v: Vector, a: Region) -//│ ╙── ^^^^^^ +//│ ║ l.16: class Translate[out Region](v: Vector, a: Region) +//│ ╙── ^^^^^^ //│ error //│ res //│ Runtime error: @@ -466,16 +435,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.467: Lang.text(mk(100)) +//│ ║ l.436: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.356: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.334: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.467: Lang.text(mk(100)) +//│ ║ l.436: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.160: if e is +//│ ║ l.157: if e is //│ ╙── ^ //│ Str | error //│ res diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index de6e1f8424..b1e54e7ea0 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -10,9 +10,7 @@ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] fun f(p: Pair['a, 'b]) = p.lhs -//│ fun f: forall 'a 'b 'L. (p: Pair['a, 'b],) -> Exp['L] -//│ where -//│ 'L := 'a +//│ fun f: forall 'a 'b. (p: Pair['a, 'b],) -> Exp['a] fun f(e) = if e is @@ -29,7 +27,7 @@ fun f(e) = if e is :e (e: Exp['X]) => f(e) //│ ╔══[ERROR] Type error in application -//│ ║ l.30: (e: Exp['X]) => f(e) +//│ ║ l.28: (e: Exp['X]) => f(e) //│ ║ ^^^^ //│ ╟── type variable `L` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] @@ -49,21 +47,21 @@ fun f(e) = if e is Pair(l, r) then f(l) + f(r) Lit(n) then n //│ ╔══[ERROR] Type error in definition -//│ ║ l.48: fun f(e) = if e is +//│ ║ l.46: fun f(e) = if e is //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.49: Pair(l, r) then f(l) + f(r) +//│ ║ l.47: Pair(l, r) then f(l) + f(r) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.50: Lit(n) then n +//│ ║ l.48: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ //│ ╔══[ERROR] Type error in definition -//│ ║ l.48: fun f(e) = if e is +//│ ║ l.46: fun f(e) = if e is //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.49: Pair(l, r) then f(l) + f(r) +//│ ║ l.47: Pair(l, r) then f(l) + f(r) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.50: Lit(n) then n +//│ ║ l.48: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `R` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index f1a2222243..0ca7fd4926 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -84,7 +84,7 @@ module Bar extends T1, Foo[Int | Str] { //│ = 123 (Bar : Foo['X]).bar -//│ ('A & (Int | Str)) -> ('A | Int | Str) +//│ ('X & (Int | Str)) -> ('X | Int | Str) //│ res //│ = [Function: id] diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index 64b3aba183..80bb555066 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -22,7 +22,7 @@ x: List //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.21: x: List //│ ║ ^ -//│ ╙── expression of type `anything` does not match type `Int` +//│ ╙── expression of type `anything` is not an instance of type `Int` //│ List[anything] diff --git a/shared/src/test/diff/nu/Eql.mls b/shared/src/test/diff/nu/Eql.mls index 33d7b0fe4c..4d59e9dcc5 100644 --- a/shared/src/test/diff/nu/Eql.mls +++ b/shared/src/test/diff/nu/Eql.mls @@ -33,10 +33,10 @@ x === x //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.32: x === x //│ ║ ^^^^^^^ -//│ ╟── type `#Eql` does not match type `?A | Int` +//│ ╟── type `#Eql` is not an instance of type `Int` //│ ║ l.4: let x: Eql[Int] //│ ║ ^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?A0 | Int` +//│ ╟── but it flows into reference with expected type `Int` //│ ║ l.32: x === x //│ ╙── ^ //│ error | false | true @@ -79,10 +79,10 @@ test1(x) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.78: test1(x) //│ ║ ^^^^^^^^ -//│ ╟── type `#Eql` does not match type `?A | Int` +//│ ╟── type `#Eql` is not an instance of type `Int` //│ ║ l.4: let x: Eql[Int] //│ ║ ^^^^^^^^ -//│ ╟── but it flows into reference with expected type `?A0 | Int` +//│ ╟── but it flows into reference with expected type `Int` //│ ║ l.78: test1(x) //│ ╙── ^ //│ error | false | true diff --git a/shared/src/test/diff/nu/ExplicitVariance.mls b/shared/src/test/diff/nu/ExplicitVariance.mls index a7e7da9023..c874dd04c4 100644 --- a/shared/src/test/diff/nu/ExplicitVariance.mls +++ b/shared/src/test/diff/nu/ExplicitVariance.mls @@ -43,8 +43,8 @@ fun foo(x: Foo[Int]): Foo[Num] = x -// * Note that not checking variance annotations is actually sound in MLscript, -// * but can be surprising for users, who will find type errors at the use sites. +// * Note that not checking variance annotations can actually be made sound in MLscript, +// * but this would be surprising for users, who would find type errors at the definition's use sites. // :e // TODO check variance annotations! @@ -60,46 +60,30 @@ let o = Oops0(id) //│ o //│ = Oops0 {} -// * What happens is `Oops9{ A = nothing..'? }` is inferred for `o` (consistent with `A`'s covariance), -// * so all negative occurrences of `o.A` are viewed as `nothing` from the outside. +// * What used to happens is `Oops9{ A = nothing..'? }` was inferred for `o` (consistent with `A`'s covariance), +// * so all negative occurrences of `o.A` were viewed as `nothing` from the outside, resulting in `o.x : nothing -> Int` +// * No lomnger the case since I simplified substitution for variant type arguments, to improve inferred type simplification. o.x -//│ nothing -> Int +//│ Int -> Int //│ res //│ = [Function: id] -// * Similarly, `Oops0[Int]` here will expand to the equivalent `Oops0{ A = nothing..Int }` +// * Similarly, `Oops0[Int]` here used to expand to the equivalent `Oops0{ A = nothing..Int }`, giving `(o : Oops0[Int]).x : nothing -> Int` (o : Oops0[Int]).x -//│ nothing -> Int +//│ Int -> Int //│ res //│ = [Function: id] -:e +// * So code like this no longer reports an error: +// :e o.x(123) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.77: o.x(123) -//│ ║ ^^^^^^^^ -//│ ╟── integer literal of type `123` does not match type `nothing` -//│ ║ l.77: o.x(123) -//│ ║ ^^^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.55: class Oops0[out A](x: A -> Int) -//│ ╙── ^ -//│ Int | error +//│ Int //│ res //│ = 123 -:e +// :e (o : Oops0[Int]).x(123) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.92: (o : Oops0[Int]).x(123) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `123` does not match type `nothing` -//│ ║ l.92: (o : Oops0[Int]).x(123) -//│ ║ ^^^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.55: class Oops0[out A](x: A -> Int) -//│ ╙── ^ -//│ Int | error +//│ Int //│ res //│ = 123 @@ -113,22 +97,13 @@ let o = Oops1(id, 123) //│ = Oops1 {} o.x -//│ nothing -> 123 +//│ 'A -> (123 | 'A) //│ res //│ = [Function: id] -:e +// :e o.x(123) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.121: o.x(123) -//│ ║ ^^^^^^^^ -//│ ╟── integer literal of type `123` does not match type `nothing` -//│ ║ l.121: o.x(123) -//│ ║ ^^^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.107: class Oops1[out A](x: A -> A, y: A) -//│ ╙── ^ -//│ 123 | error +//│ 123 //│ res //│ = 123 @@ -149,40 +124,19 @@ let o = Oops2(id, 123) //│ = Oops2 {} o.x -//│ nothing -> 123 +//│ 'A -> (123 | 'A) //│ res //│ = [Function: id] -:e +// :e o.x(123) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.157: o.x(123) -//│ ║ ^^^^^^^^ -//│ ╟── integer literal of type `123` does not match type `nothing` -//│ ║ l.157: o.x(123) -//│ ║ ^^^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.143: class Oops2[out A](x: A -> A, y: A) -//│ ╙── ^ -//│ 123 | error +//│ 123 //│ res //│ = 123 -:e // * We will be able to make this work later, through `o.x : o.A -> o.A` and `o.y : o.A` +// :e // * We will be able to make this work later, through `o.x : o.A -> o.A` and `o.y : o.A` o.x(o.y) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.172: o.x(o.y) -//│ ║ ^^^^^^^^ -//│ ╟── integer literal of type `123` does not match type `nothing` -//│ ║ l.146: let o = Oops2(id, 123) -//│ ║ ^^^ -//│ ╟── but it flows into field selection with expected type `nothing` -//│ ║ l.172: o.x(o.y) -//│ ║ ^^^ -//│ ╟── Note: type parameter A is defined at: -//│ ║ l.143: class Oops2[out A](x: A -> A, y: A) -//│ ╙── ^ -//│ 123 | error +//│ 123 //│ res //│ = 123 diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 3806d2916b..77b83616c0 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -38,17 +38,17 @@ module Test { //│ } Test.foo -//│ (??A & 'A) -> ('A | ??A0) +//│ ??A -> ??A0 //│ res //│ = undefined Test.bar -//│ (??A & 'A) -> ('A | ??A0) +//│ ??A -> ??A0 //│ res //│ = [Function: id] Test.baz -//│ (x: ??A & 'A,) -> ('A | ??A0) +//│ (x: ??A,) -> ??A0 //│ res //│ = [Function: baz] @@ -175,7 +175,7 @@ module Test { //│ } Test.foo -//│ (??A & 'A) -> ('A | ??A0) +//│ ??A -> ??A0 //│ res //│ = [Function: id] diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index 242e26917a..c7442c6b2f 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -55,7 +55,7 @@ p1: Product[Bool, Int] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.54: p1: Product[Bool, Int] //│ ║ ^^ -//│ ╙── expression of type `Int & ?A` is not an instance of type `Bool` +//│ ╙── expression of type `Int` is not an instance of type `Bool` //│ Product[Bool, Int] p1: Into[Int] diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index b703190b78..ff72e53a8d 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -932,7 +932,7 @@ bi.f(1) //│ bi is not implemented bp.f -//│ ((Int, Bool & 'T,) & 'A) -> ((Int, 'T | false | true,) | 'A) +//│ ((Int, Bool,) & 'A) -> ((Int, Bool,) | 'A) //│ res //│ = //│ bp is not implemented diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index f0058011e8..cafbb77e39 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -3,15 +3,15 @@ // * Adapted example from Code reuse through polymorphic variants (FOSE 2000) -// * This time with a List class. +// * This time with an ML-style List data type encoding. -// FIXME: -// - simplification problem or constraInt bug: `'result :> anything <: Numb` + +// TODO improvements/things to investigate: // - constraining loop with unannotated `list_assoc` ascription -// - still a Numb of quite ugly types +// - still a number of quite ugly types -class List { +class List { fun match: forall 'res; (ifNil: () => 'res, ifCons: (A, List[A]) => 'res) => 'res fun match = error } @@ -20,11 +20,11 @@ let Cons: (head: 'a, tail: List<'a>) => List<'a> //│ class List[A] { //│ fun match: forall 'res. (ifNil: () -> 'res, ifCons: (A, List[A],) -> 'res,) -> 'res //│ } -//│ let Nil: forall 'a. () -> List['a] -//│ let Cons: forall 'a0. (head: 'a0, tail: List['a0],) -> List['a0] +//│ let Nil: () -> List[nothing] +//│ let Cons: forall 'a. (head: 'a, tail: List['a],) -> List['a] class NotFound -class Success(result: A) +class Success(result: A) //│ class NotFound //│ class Success[A](result: A) @@ -40,9 +40,7 @@ fun list_assoc(s, l: List<'a>) = if eq(s, h._1) then Success(h._2) else list_assoc(s, t) ) -//│ fun list_assoc: forall 'a 'A. (Str, l: List['a],) -> (NotFound | Success['A]) -//│ where -//│ 'a <: {_1: Str, _2: 'A} +//│ fun list_assoc: forall 'A. (Str, l: List[{_1: Str, _2: 'A}],) -> (NotFound | Success['A]) list_assoc : (Str, List<{ _1: Str, _2: 'b }>) => (NotFound | Success['b]) //│ (Str, List[{_1: Str, _2: 'b}],) -> (NotFound | Success['b]) @@ -61,11 +59,11 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (List[{_1: Str, _2: 'b}], Var,) -> ('b | Var) +//│ fun eval: (List[{_1: Str, _2: 'result}], Var,) -> (Var | 'result) //│ } -class Abs(x: Str, t: A) -class App(s: A, t: A) +class Abs(x: Str, t: A) +class App(s: A, t: A) //│ class Abs[A](x: Str, t: A) //│ class App[A](s: A, t: A) @@ -96,55 +94,51 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c,) -> 'd} -//│ this: {eval: ('b, 's,) -> ('A & 'e) & (List[in 'a out 'a | (Str, 'e,)], 't,) -> 'd & (List['a0], 't0,) -> 'A0} -//│ fun eval: (List['a0] & 'b, Abs['t0] | App['s & (Abs['t] | Object & ~#Abs)] | Object & 'c & ~#Abs & ~#App,) -> (Abs['A0] | App['A] | 'd) +//│ this: {eval: ('b, 's,) -> 'A & (List[(Str, 'A,)], 't,) -> 'd & (List['a | (Str, Var,)], 't0,) -> 'A0} +//│ fun eval: (List['a] & 'b, Abs['t0] | App['s & (Abs['t] | Object & ~#Abs)] | Object & 'c & ~#Abs & ~#App,) -> (Abs['A0] | App['A] | 'd) //│ } -//│ where -//│ 'a0 :> (Str, Var,) module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'b}], Abs['t] | App['A] | Var,) -> ('c | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: 'result}], 't,) -> ('result | 'a) //│ } //│ where //│ 't <: Abs['t] | App['A] | Var //│ 'A <: Abs['t & (Abs['t] | App['A] | Var)] | Abs['t] & ~#Abs | App['A] | Var -//│ 'b :> Var | 'd -//│ 'd :> 'c | 'a -//│ 'c :> 'b | Var | 'a -//│ 'a :> App['d | 'c | 'a] | Abs['c | 'a] +//│ 'result :> 'a | Var +//│ 'a :> App['result | 'a] | Abs['result | 'a] Test1.eval(Nil(), Var("a")) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Var | 'b | 'a Test1.eval(Nil(), Abs("b", Var("a"))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Var | 'b | 'a Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Var | 'b | 'a Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Var +//│ 'c :> forall 'a. Abs[Var] | Var | 'b | 'a class Numb(n: Int) -class Add(l: A, r: A) -class Mul(l: A, r: A) +class Add(l: A, r: A) +class Mul(l: A, r: A) //│ class Numb(n: Int) //│ class Add[A](l: A, r: A) //│ class Mul[A](l: A, r: A) @@ -175,11 +169,10 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'b}], 'a & (Add['c] | Mul['c] | Numb | Var),) -> ('b | Numb | Var | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: Object & 'result}], 'a & 'b,) -> (Numb | Var | 'result | 'a) //│ } //│ where -//│ 'c <: Add['c] | Mul['c] | Numb | Var -//│ 'b <: Object +//│ 'b <: Add['b] | Mul['b] | Numb | Var Test2.eval(Nil(), Var("a")) //│ Numb | Var @@ -195,16 +188,14 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'A 'a. (List[{_1: Str, _2: 'b}], Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App,) -> ('d | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: 'result}], 't,) -> ('b | 'a) //│ } //│ where -//│ 'b :> Var | 'e -//│ <: Object -//│ 'e :> 'd | 'a -//│ 'd :> 'b | Numb | Var | 'c | 'a -//│ 'a :> App['e | 'd | 'a] | Abs['d | 'a] -//│ 'c <: Add['f] | Mul['f] | Numb | Var -//│ 'f <: Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App +//│ 'result :> 'b | 'a +//│ <: Object +//│ 'b :> Numb | Var | 'result | 'c | 'a +//│ 'a :> App['b | 'a] | Abs['b | 'a] +//│ 'c <: Add['t] | Mul['t] | Numb | Var //│ 't <: Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App //│ 'A <: Abs['t & (Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | Object & 'c & ~#Abs & ~#App @@ -213,23 +204,22 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Numb | Var +//│ 'c :> Abs[Var] | Numb | Var | 'b Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) //│ forall 'a. 'b | 'a | 'c //│ where //│ 'b :> forall 'a. 'a | 'c //│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> (forall 'a. Abs[Var] | Var | 'b | 'a) | Add[Numb | Var] | Numb | Var +//│ 'c :> Abs[Var] | Add[Numb | Var] | Numb | Var | 'b module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'b}], 'a & (Add['c] | Mul['c] | Numb | Var),) -> ('a | 'd) +//│ fun eval: forall 'a. (List[{_1: Str, _2: 'result}], 'a & 'b,) -> ('a | 'c) //│ } //│ where -//│ 'c <: Add['c] | Mul['c] | Numb | Var -//│ 'b :> Var | 'e -//│ <: Object -//│ 'e :> 'd -//│ 'd :> 'b | Abs[Numb | 'd] | App[Numb | 'e | 'd] | Numb | Var +//│ 'b <: Add['b] | Mul['b] | Numb | Var +//│ 'result :> 'c +//│ <: Object +//│ 'c :> Abs[Numb | 'c] | App[Numb | 'c] | Numb | Var | 'result diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index c02d2fbd4a..41a7cb7713 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -34,7 +34,7 @@ c1.f //│ = [Function: f] (c1 : T1).f -//│ (??A & 'A) -> ('A | ??A0) +//│ ??A -> ??A0 //│ res //│ = [Function: f] @@ -47,8 +47,7 @@ c1.f (c1 : T1).f //│ 'f //│ where -//│ 'f :> 'A -> 'A -//│ 'A := in ??A out ??A0 +//│ 'f :> in ??A out ??A0 -> in ??A out ??A0 //│ res //│ = [Function: f] @@ -56,8 +55,7 @@ c1.f (c1 : T1['X]).f //│ 'f //│ where -//│ 'f :> 'A -> 'A -//│ 'A := 'X +//│ 'f :> 'X -> 'X //│ 'X :> Int //│ <: 'FigureItOut //│ 'FigureItOut :> Int @@ -65,6 +63,24 @@ c1.f //│ res //│ = [Function: f] +:e +(c1 : T1['X]).f(false) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.67: (c1 : T1['X]).f(false) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ║ l.67: (c1 : T1['X]).f(false) +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.20: fun f(x: Int) = x +//│ ║ ^^^ +//│ ╟── from type variable: +//│ ║ l.67: (c1 : T1['X]).f(false) +//│ ╙── ^^ +//│ Int | error | false +//│ res +//│ = false + // * The more tricky case: @@ -78,23 +94,23 @@ class C2 extends T2['FigureItOut] { fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.75: val r = C2().f(false) +//│ ║ l.91: val r = C2().f(false) //│ ╙── ^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.73: trait T2[A] { +//│ ║ l.89: trait T2[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.74: fun f: A -> A +//│ ║ l.90: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.75: val r = C2().f(false) +//│ ║ l.91: val r = C2().f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.75: val r = C2().f(false) +//│ ║ l.91: val r = C2().f(false) //│ ║ ^^^^^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.75: val r = C2().f(false) +//│ ║ l.91: val r = C2().f(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.78: fun f(x: Int) = x +//│ ║ l.94: fun f(x: Int) = x //│ ╙── ^^^ //│ trait T2[A] { //│ fun f: A -> A @@ -113,17 +129,17 @@ class C3 extends T3['FigureItOut] { fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.110: val r = (C3() : T3['X]).f(false) +//│ ║ l.126: val r = (C3() : T3['X]).f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.108: trait T3[A] { +//│ ║ l.124: trait T3[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.109: fun f: A -> A +//│ ║ l.125: fun f: A -> A //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.110: val r = (C3() : T3['X]).f(false) +//│ ║ l.126: val r = (C3() : T3['X]).f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type `C3` does not contain member `T3#A` -//│ ║ l.108: trait T3[A] { +//│ ║ l.124: trait T3[A] { //│ ╙── ^ //│ trait T3[A] { //│ fun f: A -> A @@ -136,7 +152,7 @@ class C3 extends T3['FigureItOut] { :e // FIXME C3() : T3['X] //│ ╔══[ERROR] Type `C3` does not contain member `T3#A` -//│ ║ l.108: trait T3[A] { +//│ ║ l.124: trait T3[A] { //│ ╙── ^ //│ T3['X] //│ where diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls new file mode 100644 index 0000000000..18b8564858 --- /dev/null +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -0,0 +1,60 @@ +:NewDefs + + + +// * There are strange parsing quirks here + +fun f: Str | [Str, Int] +//│ fun f: Array[Int | Str] & {_1: Str} + +// * ^ parses as: + +fun f: [Str] | [Str, Int] +//│ fun f: Array[Int | Str] & {_1: Str} + +fun f: (Str | [Str, Int]) +//│ fun f: Array[Int | Str] & {_1: Str} + +fun f: Str | (Str, Int) +//│ fun f: Array[Int | Str] & {_1: Str} + + +fun f: Str | ([Str, Int]) +//│ fun f: (Str, Int,) | Str + +fun f: Str | ((Str, Int)) +//│ fun f: (Str, Int,) | Str + + + +// * This type merges the input tuples, resulting in the union seen above: +fun f: (Str => Str) & ((Str, Int) => Str) +//│ fun f: (Array[Int | Str] & {_1: Str}) -> Str + +f("abc", "abc") +//│ Str +//│ res +//│ = +//│ f is not implemented + + +// * Note: the merge doesn't happen when the result type is different... +fun f: (Str => Str) & ((Str, Int) => Int) +//│ fun f: Str -> Str & (Str, Int,) -> Int + +// * ...resulting in approximation at call sites (we don't handle overloading) +:e +f("abc", "abc") +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.47: f("abc", "abc") +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── argument list of type `("abc", "abc",)` does not match type `nothing` +//│ ║ l.47: f("abc", "abc") +//│ ╙── ^^^^^^^^^^^^^^ +//│ Int | Str | error +//│ res +//│ = +//│ f is not implemented + + + diff --git a/shared/src/test/diff/nu/repro0.mls b/shared/src/test/diff/nu/repro0.mls new file mode 100644 index 0000000000..f7d1ce0132 --- /dev/null +++ b/shared/src/test/diff/nu/repro0.mls @@ -0,0 +1,23 @@ +:NewDefs +:NoJS + + +class Add[E](lhs: E) +val add11 = Add(add11) +module EvalAddLit { + fun eval(e: Add['A]) = + if e is Add then eval(e.lhs) +} +let res = EvalAddLit.eval(add11) +//│ class Add[E](lhs: E) +//│ let add11: 'E +//│ module EvalAddLit { +//│ fun eval: (e: 'lhs,) -> nothing +//│ } +//│ let res: nothing +//│ where +//│ 'lhs <: Add['A] +//│ 'A <: 'lhs +//│ 'E :> Add['E] + + diff --git a/shared/src/test/diff/nu/repro1.mls b/shared/src/test/diff/nu/repro1.mls new file mode 100644 index 0000000000..b7f0f9a1dc --- /dev/null +++ b/shared/src/test/diff/nu/repro1.mls @@ -0,0 +1,47 @@ +:NewDefs +:NoJS + + +class Union[out Region](a: Region) +// class Union[Region](a: Region) +//│ class Union[Region](a: Region) + +fun go(x) = Union(go(x)) +let circles = go(2) +//│ fun go: forall 'Region. anything -> 'Region +//│ let circles: forall 'Region0. 'Region0 +//│ where +//│ 'Region0 :> Union['Region0] +//│ 'Region :> Union['Region] + + +fun contains(a) = + if a is Union then contains(a.a) +//│ fun contains: forall 'a. 'a -> nothing +//│ where +//│ 'a <: Union['a] + +contains(circles) +//│ nothing + + +mixin Contains { + fun contains(a) = + if a is Union then this.contains(a.a) +} +//│ mixin Contains() { +//│ this: {contains: 'a -> 'b} +//│ fun contains: Union['a] -> 'b +//│ } + +module TestContains extends Contains +//│ module TestContains { +//│ fun contains: 'a -> nothing +//│ } +//│ where +//│ 'a <: Union['a] + +TestContains.contains(circles) +//│ nothing + + diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index 1c769482d7..c13bdd486a 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -47,8 +47,8 @@ TestLang.eval(mk(0)) //│ Int //│ res //│ = 0 -//│ constrain calls : 441 +//│ constrain calls : 416 //│ annoying calls : 160 -//│ subtyping calls : 4646 +//│ subtyping calls : 4427 diff --git a/shared/src/test/diff/ucs/HygienicBindings.mls b/shared/src/test/diff/ucs/HygienicBindings.mls index c0553e08a0..af009d577e 100644 --- a/shared/src/test/diff/ucs/HygienicBindings.mls +++ b/shared/src/test/diff/ucs/HygienicBindings.mls @@ -133,7 +133,7 @@ fun h3(x, y, f, p) = h3("anything", "not me", _ => "should be me", _ => true) h3(None, "should be me", _ => "not me", _ => false) h3("anything", "anything", _ => "not me", _ => false) -//│ fun h3: forall 'a 'b. (None | Object & 'b & ~#None, 'a, (None | 'b) -> anything, (None | 'b) -> Object,) -> ("anyway" | 'a) +//│ fun h3: forall 'a 'b. (None | Object & 'a & ~#None, 'b, (None | 'a) -> anything, (None | 'a) -> Object,) -> ("anyway" | 'b) //│ "anything" | "anyway" //│ res //│ = [Function: h3] diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index 8cc54c1647..3a6814f716 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -63,7 +63,7 @@ fun mapPartition(f, xs) = if xs is mapPartition(f, xs) is Pair(l, r) and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ fun mapPartition: forall 'head 'A 'A0. ('head -> (Left['A] | Right['A0]), Cons['head] | Nil,) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] +//│ fun mapPartition: forall 'A 'head 'A0. ('head -> (Left['A0] | Right['A]), Cons['head] | Nil,) -> Pair[Cons['A0] | Nil, Cons['A] | Nil] mapPartition(f, zeroToThree) //│ Pair[Cons['A] | Nil, Cons['A0] | Nil] diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index 9ad552a6d8..df42fe2512 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -93,7 +93,7 @@ fun zipWith_wrong(f, xs, ys) = if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith_wrong(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) else None -//│ fun zipWith_wrong: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (None | Some[Cons['A]]) +//│ fun zipWith_wrong: forall 'A 'head 'head0. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (None | Some[Cons['A]]) // * Notice the result is wrong (duh) zipWith_wrong(pairup, Nil, Nil) @@ -108,7 +108,7 @@ fun zipWith(f, xs, ys) = Cons(x, xs) and ys is Cons(y, ys) and zipWith(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) Nil and ys is Nil then Some(Nil) else None -//│ fun zipWith: forall 'head 'A 'head0. (('head0, 'head,) -> 'A, Cons['head0] | Object & ~#Cons, Cons['head] | Object & ~#Cons,) -> (None | Some[Cons['A] | Nil]) +//│ fun zipWith: forall 'head 'head0 'A. (('head, 'head0,) -> 'A, Cons['head] | Object & ~#Cons, Cons['head0] | Object & ~#Cons,) -> (None | Some[Cons['A] | Nil]) zipWith(pairup, Cons(0, Nil), Cons("0", Nil)).value.toArray //│ Array[anything] From 7c82d61e534e7c7449f5ba1885072b183e107b4b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 9 Jun 2023 18:03:28 +0800 Subject: [PATCH 353/498] Don't type inherited mixin implementations polymorphically when tying the knot This improves performance & the simplicity of inferred type --- .../src/main/scala/mlscript/NormalForms.scala | 4 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 9 +- .../test/diff/ecoop23/ExpressionProblem.mls | 12 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 97 ++++++------- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 129 ++++++++---------- .../test/diff/nu/ExpressionProblem_repro.mls | 12 +- .../test/diff/nu/ExpressionProblem_small.mls | 12 +- .../src/test/diff/nu/ImplicitMethodPolym.mls | 4 +- shared/src/test/diff/nu/MetaWrap.mls | 30 ++-- .../test/diff/nu/PolymorphicVariants_Alt.mls | 74 +++++----- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 13 +- 11 files changed, 187 insertions(+), 209 deletions(-) diff --git a/shared/src/main/scala/mlscript/NormalForms.scala b/shared/src/main/scala/mlscript/NormalForms.scala index 09324175e0..0297b7407b 100644 --- a/shared/src/main/scala/mlscript/NormalForms.scala +++ b/shared/src/main/scala/mlscript/NormalForms.scala @@ -402,9 +402,9 @@ class NormalForms extends TyperDatatypes { self: Typer => (vars.iterator ++ nvars).map(_.levelBelow(ub)).++(Iterator(lnf.levelBelow(ub), rnf.levelBelow(ub))).max def freshenAbove(lim: Int, rigidify: Bool)(implicit ctx: Ctx, freshened: MutMap[TV, ST], shadows: Shadows): Conjunct = { val (vars2, tags2) = vars.toBuffer[TV].partitionMap( - _.freshenAbove(lim, rigidify) match { case tv: TV => L(tv); case tt: AbstractTag => R(tt) }) + _.freshenAbove(lim, rigidify) match { case tv: TV => L(tv); case tt: AbstractTag => R(tt); case _ => die }) val (nvars2, ntags2) = nvars.toBuffer[TV].partitionMap( - _.freshenAbove(lim, rigidify) match { case tv: TV => L(tv); case tt: AbstractTag => R(tt) }) + _.freshenAbove(lim, rigidify) match { case tv: TV => L(tv); case tt: AbstractTag => R(tt); case _ => die }) Conjunct( tags2.foldLeft(lnf.freshenAbove(lim, rigidify))(_ & _), vars2.toSortedSet, ntags2.foldLeft(rnf.freshenAbove(lim, rigidify))(_ | _), nvars2.toSortedSet) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 34b7f32fe3..5c87d74336 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1218,7 +1218,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => RecordType( newMembs.collect { case m: NuParam => m.nme.toVar -> m.ty - case m: TypedNuFun => m.fd.nme -> m.typeSignature.toUpper(provTODO) + case m: TypedNuFun => + // val ty = m.typeSignature + // * ^ Note: this also works and is more precise (some types made more specific), + // * but it causes duplication of recursive type structures + // * in typical SuperOOP mixin compositions, so it's better to be less precise + // * but simpler/more efficient/more concise here. + val ty = m.bodyType + m.fd.nme -> ty.toUpper(provTODO) } )(provTODO) )(provTODO) diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index 469de032ef..e45c32888e 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -115,17 +115,17 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> Int +//│ fun eval: (Neg['a] | Object & 'b & ~#Neg) -> Int //│ } //│ where -//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit +//│ 'a <: Neg['a] | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit TestLang.eval -//│ (Neg['expr] | Object & 'a & ~#Neg) -> Int +//│ (Neg['a] | Object & 'b & ~#Neg) -> Int //│ where -//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit +//│ 'a <: Neg['a] | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit //│ res //│ = [Function: eval] diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 955948ef7d..21b0151379 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -78,47 +78,43 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'result}] | Nil, Abs['t] | App['A] | Var,) -> ('result | 'a) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'result}] | Nil, Abs['b] | App['A] | Var,) -> ('result | 'a) //│ } //│ where -//│ 't <: Abs['t] | App['A] | Var -//│ 'A <: Abs['t & (Abs['t] | App['A] | Var)] | Abs['t] & ~#Abs | App['A] | Var -//│ 'result :> 'a | Var -//│ 'a :> App['result | 'a] | Abs['result | 'a] +//│ 'b <: Abs['b] | App['A] | Var +//│ 'A <: 'b & (Abs['b] | Object & ~#Abs) +//│ 'result :> Var | 'a +//│ 'a :> App['result] | Abs['result] Test1.eval(Nil, Var("a")) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'A :> 'a | Var +//│ 'a :> App['A] | Abs['A] //│ res //│ = Var {} Test1.eval(Nil, Abs("b", Var("a"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'A :> Var | 'a +//│ 'a :> App['A] | Abs['A] //│ res //│ = Abs {} Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'A :> 'a | Var +//│ 'a :> App['A] | Abs['A] //│ res //│ = Var {} Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Abs[Var] | Var | 'b | 'a +//│ 'A :> 'a | Abs[Var] | Var +//│ 'a :> App['A] | Abs['A] //│ res //│ = Var {} @@ -155,7 +151,7 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: Object & 'result}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> (Numb | Var | 'result | 'a) +//│ fun eval: forall 'a. (Cons[{_1: anything, _2: Object & 'result}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> (Numb | Var | 'result | 'a | 'b) //│ } //│ where //│ 'b <: Add['b] | Mul['b] | Numb | Var @@ -179,16 +175,16 @@ Test2.eval(Cons(("a", Numb(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.180: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.180: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.133: if v is +//│ ║ l.129: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.143: let vv = map_expr(eta, v) +//│ ║ l.139: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Numb | Var | error //│ res @@ -202,66 +198,63 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'A 'a. (Cons[{_1: anything, _2: 'result}] | Nil, Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App,) -> ('c | 'a) +//│ fun eval: forall 'a 'A. (Cons[{_1: anything, _2: 'result}] | Nil, Abs['b] | App['A] | Object & 'c & ~#Abs & ~#App,) -> ('A0 | 'a) //│ } //│ where -//│ 'result :> 'c | 'a +//│ 'result :> 'A0 | Var //│ <: Object -//│ 'c :> Numb | Var | 'result | 'b | 'a -//│ 'a :> App['c | 'a] | Abs['c | 'a] -//│ 'b <: Add['d] | Mul['d] | Numb | Var -//│ 'd <: Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App -//│ 't <: Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App -//│ 'A <: Abs['t & (Abs['t] | App['A] | Object & 'b & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | Object & 'b & ~#Abs & ~#App +//│ 'A0 :> 'a | Numb | Var | 'result | 'c +//│ 'c <: Add['b] | Mul['b] | Numb | Var +//│ 'b <: Abs['b] | App['A] | Object & 'c & ~#Abs & ~#App +//│ 'A <: 'b & (Abs['b] | Object & ~#Abs) +//│ 'a :> App['A0] | Abs['A0] Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> Abs[Var] | Numb | Var | 'b +//│ 'A :> 'a | Abs[Var] | Numb | Var +//│ 'a :> App['A] | Abs['A] //│ res //│ = Abs {} Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> Abs[Var] | Add[Numb | Var] | Numb | Var | 'b +//│ 'A :> 'a | Abs[Var] | Add[Numb | Var] | Numb | Var +//│ 'a :> App['A] | Abs['A] //│ res //│ = Var {} // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'result}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var),) -> ('a | 'c) +//│ fun eval: (Cons[{_1: anything, _2: 'result}] | Nil, 'result & (Add['a] | Mul['a] | Numb | Var),) -> ('A | 'result | 'a) //│ } //│ where -//│ 'b <: Add['b] | Mul['b] | Numb | Var -//│ 'result :> 'c +//│ 'result :> 'A | Var | 'a //│ <: Object -//│ 'c :> Abs[Numb | 'c] | App[Numb | 'c] | Numb | Var | 'result +//│ 'a <: Add['a] | Mul['a] | Numb | Var +//│ 'A :> Numb | 'result | Abs['A] | App['A] | Var // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.249: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.242: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.249: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.242: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.133: if v is +//│ ║ l.129: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.143: let vv = map_expr(eta, v) +//│ ║ l.139: let vv = map_expr(eta, v) //│ ╙── ^ -//│ Abs[Var] | error | 'a +//│ 'A | Abs[Var] | Numb | error //│ where -//│ 'a :> Abs[Numb | 'a] | App[Numb | 'a] | Numb | Var +//│ 'A :> Abs[Var] | Numb | Abs['A] | App['A] | Var //│ res //│ Runtime error: //│ Error: non-exhaustive case expression diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 569a84d813..7f1d7afe6b 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -84,8 +84,7 @@ module TestSize extends SizeBase, SizeExt //│ fun size: 'a -> Int //│ } //│ where -//│ 'a <: Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ -//│ 'b <: Circle | Intersect[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Outside[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Translate[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] | Union[Empty | Object & 'b & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ] +//│ 'a <: Empty | Object & (Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a]) & ~#Empty & ~#Scale & ~#Univ | Scale['a] | Univ TestSize.size(Empty()) //│ Int @@ -168,17 +167,17 @@ mixin Text { :e module SizeText extends Text -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?b -> (?d | ?f | ?a | ?c | ?e)}` does not contain member `size` -//│ ║ l.162: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.161: Translate then concat("a translated region of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?a | ?b | ?c | ?f | ?d)}` does not contain member `size` -//│ ║ l.161: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.160: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?b -> (?e | ?d | ?c | ?a | ?f)}` does not contain member `size` -//│ ║ l.160: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.159: Union then concat("the union of two regions of size ", toString(this.size(e))) //│ ╙── ^^^^^ -//│ ╔══[ERROR] Type `#SizeText & {text: forall ?a ?b ?c ?d ?e ?f. ?e -> (?d | ?f | ?c | ?a | ?b)}` does not contain member `size` -//│ ║ l.159: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.158: Outside(a) then concat("outside a region of size ", toString(this.size(a))) //│ ╙── ^^^^^ //│ module SizeText { //│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> Str @@ -188,7 +187,7 @@ module SizeText extends Text module SizeText extends SizeBase, Text //│ module SizeText { //│ fun size: 'a -> Int -//│ fun text: (Circle | Intersect['a] | Outside[Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a]] | Translate['a] | Union['a]) -> Str +//│ fun text: 'a -> Str //│ } //│ where //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] @@ -247,36 +246,36 @@ mixin IsEmpty { module IsUnivIsEmpty extends IsUniv, IsEmpty //│ module IsUnivIsEmpty { -//│ fun isEmpty: 'a -> (Bool | 'b) -//│ fun isUniv: 'a0 -> (Bool | 'c) +//│ fun isEmpty: 'a -> Bool +//│ fun isUniv: 'b -> Bool //│ } //│ where -//│ 'a0 <: Intersect['a0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a0] | Scale['a0] | Translate['a0] | Union['a0] | Univ +//│ 'b <: Intersect['b] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['b] | Scale['b] | Translate['b] | Union['b] | Univ //│ 'a <: Intersect['a] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ module IsUnivIsEmpty extends IsEmpty, IsUniv //│ module IsUnivIsEmpty { -//│ fun isEmpty: 'a -> (Bool | 'b) -//│ fun isUniv: 'a0 -> (Bool | 'c) +//│ fun isEmpty: 'a -> Bool +//│ fun isUniv: 'b -> Bool //│ } //│ where -//│ 'a0 <: Intersect['a0] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a0] | Scale['a0] | Translate['a0] | Union['a0] | Univ +//│ 'b <: Intersect['b] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['b] | Scale['b] | Translate['b] | Union['b] | Univ //│ 'a <: Intersect['a] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['a] | Translate['a] | Union['a] | Univ IsUnivIsEmpty.isUniv(circles) -//│ Bool | 'a +//│ Bool //│ res //│ = false IsUnivIsEmpty.isEmpty(circles) -//│ Bool | 'a +//│ Bool //│ res //│ = false class Foo() IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) //│ class Foo() -//│ Bool | 'a +//│ Bool //│ res //│ = false @@ -298,31 +297,28 @@ mixin Eliminate { module TestElim extends Eliminate //│ module TestElim { -//│ fun eliminate: forall 'Region 'b 'Region0 'c. (Intersect['Region0] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region]) -> ('d | 'c | 'b) +//│ fun eliminate: forall 'a. 'b -> ('a | 'c) //│ } //│ where -//│ 'Region0 <: Intersect['Region0] | Object & 'e & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] -//│ 'a <: Intersect['Region0] | Object & 'f & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] -//│ 'a0 <: Intersect['Region0] | Object & 'd & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] -//│ 'a1 <: Intersect['Region0] | Object & 'g & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] -//│ 'a2 <: Intersect['Region0] | Object & 'h & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] -//│ 'Region <: Intersect['Region0] | Object & 'i & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a0])] | Scale['a1] | Translate['a2] | Union['Region] -//│ 'd :> 'c -//│ 'c :> Outside['d | 'c | 'f] | Union['d | 'c | 'i] | Intersect['d | 'c | 'e] | Translate['d | 'c | 'h] | Scale['d | 'c | 'g] +//│ 'b <: Intersect['b] | Object & 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['b & (Object & ~#Outside | Outside['b])] | Scale['b] | Translate['b] | Union['b] +//│ 'c :> 'a +//│ 'a :> Outside['c] | Union['c] | Intersect['c] | Translate['c] | Scale['c] TestElim.eliminate(Outside(Outside(Univ()))) //│ forall 'a. 'b | 'a //│ where -//│ 'b :> forall 'a. Univ | 'a -//│ 'a :> Outside[forall 'a. Univ | 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] | Scale[forall 'a. 'b | 'a] +//│ 'b :> Univ | 'a +//│ 'a :> Outside['Region] | Union['Region] | Intersect['Region] | Translate['Region] | Scale['Region] +//│ 'Region :> Univ | 'b //│ res //│ = Univ {} TestElim.eliminate(circles) -//│ forall 'a. Circle | 'b | 'a +//│ forall 'a. 'b | 'a //│ where -//│ 'b :> forall 'a. 'a -//│ 'a :> Outside[forall 'a. 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. Circle | 'b | 'a] | Scale[forall 'a. 'b | 'a] +//│ 'b :> Circle | 'a +//│ 'a :> Outside['Region] | Intersect['Region] | Translate['Region] | Scale['Region] | Union['Region] +//│ 'Region :> Circle | 'b //│ res //│ = Union {} @@ -338,10 +334,10 @@ fun mk(n) = if n is :re TestElim.eliminate(mk(100)) -//│ forall 'a. 'b | 'a +//│ forall 'a. 'a //│ where -//│ 'b :> forall 'a. 'a -//│ 'a :> Outside[forall 'a. 'b | 'a] | Union[forall 'a. 'b | 'a] | Intersect[forall 'a. 'b | 'a] | Translate[forall 'a. 'b | 'a] | Scale[forall 'a. 'b | 'a] +//│ 'a :> Outside['Region] | Union['Region] | Intersect['Region] | Translate['Region] | Scale['Region] +//│ 'Region :> 'a //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -351,27 +347,22 @@ TestElim.eliminate(mk(100)) module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate //│ module Lang { //│ fun contains: ('a, {x: Int, y: Int},) -> Bool -//│ fun eliminate: forall 'Region 'b 'c 'Region0. (Intersect['Region] | Object & 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0]) -> ('d | 'b | 'c) -//│ fun isEmpty: 'a4 -> (Bool | 'e) -//│ fun isUniv: 'a5 -> (Bool | 'f) -//│ fun size: 'Region1 -> Int -//│ fun text: 'g -> Str +//│ fun eliminate: forall 'b. 'c -> ('b | 'd) +//│ fun isEmpty: 'e -> Bool +//│ fun isUniv: 'f -> Bool +//│ fun size: 'g -> Int +//│ fun text: 'h -> Str //│ } //│ where -//│ 'g <: Circle | Intersect['Region2] | Outside[Empty | Object & 'g & ~#Empty & ~#Scale & ~#Univ | Scale['Region2] | Univ] | Translate['Region2] | Union['Region2] -//│ 'Region2 <: Empty | Object & 'g & ~#Empty & ~#Scale & ~#Univ | Scale['Region2] | Univ -//│ 'Region1 <: Empty | Object & 'h & ~#Empty & ~#Scale & ~#Univ | Scale['Region1] | Univ -//│ 'h <: Circle | Intersect['Region1] | Outside[Empty | Object & 'h & ~#Empty & ~#Scale & ~#Univ | Scale['Region1] | Univ] | Translate['Region1] | Union['Region1] -//│ 'a5 <: Intersect['a5] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a5] | Scale['a5] | Translate['a5] | Union['a5] | Univ -//│ 'a4 <: Intersect['a4] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a4] | Scale['a4] | Translate['a4] | Union['a4] | Univ -//│ 'Region <: Intersect['Region] | Object & 'i & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] -//│ 'a0 <: Intersect['Region] | Object & 'j & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] -//│ 'a1 <: Intersect['Region] | Object & 'd & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] -//│ 'a2 <: Intersect['Region] | Object & 'k & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] -//│ 'a3 <: Intersect['Region] | Object & 'l & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] -//│ 'Region0 <: Intersect['Region] | Object & 'm & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a0 & (Object & ~#Outside | Outside['a1])] | Scale['a2] | Translate['a3] | Union['Region0] +//│ 'h <: Circle | Intersect['i] | Outside['i] | Translate['i] | Union['i] +//│ 'i <: Empty | Object & 'h & ~#Empty & ~#Scale & ~#Univ | Scale['i] | Univ +//│ 'g <: Empty | Object & 'j & ~#Empty & ~#Scale & ~#Univ | Scale['g] | Univ +//│ 'j <: Circle | Intersect['g] | Outside['g] | Translate['g] | Union['g] +//│ 'f <: Intersect['f] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['f] | Scale['f] | Translate['f] | Union['f] | Univ +//│ 'e <: Intersect['e] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['e] | Scale['e] | Translate['e] | Union['e] | Univ +//│ 'c <: Intersect['c] | Object & 'd & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['c & (Object & ~#Outside | Outside['c])] | Scale['c] | Translate['c] | Union['c] //│ 'd :> 'b -//│ 'b :> Outside['d | 'b | 'j] | Union['d | 'b | 'm] | Intersect['d | 'b | 'i] | Translate['d | 'b | 'l] | Scale['d | 'b | 'k] +//│ 'b :> Outside['d] | Union['d] | Intersect['d] | Translate['d] | Scale['d] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] Lang.size(circles) @@ -390,12 +381,12 @@ Lang.text(circles) //│ = 'the union of two regions of size ' Lang.isUniv(circles) -//│ Bool | 'a +//│ Bool //│ res //│ = false Lang.isEmpty(circles) -//│ Bool | 'a +//│ Bool //│ res //│ = false @@ -415,18 +406,18 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.416: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.407: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.334: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.330: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.114: if a is +//│ ║ l.113: if a is //│ ║ ^ //│ ╟── Note: type parameter Region is defined at: -//│ ║ l.16: class Translate[out Region](v: Vector, a: Region) -//│ ╙── ^^^^^^ -//│ error +//│ ║ l.13: class Outside[out Region](a: Region) +//│ ╙── ^^^^^^ +//│ error | false | true //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -435,16 +426,16 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.436: Lang.text(mk(100)) +//│ ║ l.427: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.334: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.330: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.436: Lang.text(mk(100)) +//│ ║ l.427: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.157: if e is +//│ ║ l.156: if e is //│ ╙── ^ //│ Str | error //│ res @@ -453,14 +444,14 @@ Lang.text(mk(100)) :re Lang.isUniv(mk(100)) -//│ Bool | 'a +//│ Bool //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded :re Lang.isEmpty(mk(100)) -//│ Bool | 'a +//│ Bool //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index 807fe3dc8f..24eaf3de79 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -133,17 +133,17 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> Int +//│ fun eval: (Neg['a] | Object & 'b & ~#Neg) -> Int //│ } //│ where -//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit +//│ 'a <: Neg['a] | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit TestLang.eval -//│ (Neg['expr] | Object & 'a & ~#Neg) -> Int +//│ (Neg['a] | Object & 'b & ~#Neg) -> Int //│ where -//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit +//│ 'a <: Neg['a] | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/ExpressionProblem_small.mls b/shared/src/test/diff/nu/ExpressionProblem_small.mls index d98c2ab370..62c5dcf5a1 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_small.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_small.mls @@ -45,16 +45,16 @@ mixin EvalNeg { module TestLang extends EvalNothing, EvalAddLit, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['expr] | Object & 'a & ~#Neg) -> Int +//│ fun eval: (Neg['a] | Object & 'b & ~#Neg) -> Int //│ } //│ where -//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit +//│ 'a <: Neg['a] | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit TestLang.eval -//│ (Neg['expr] | Object & 'a & ~#Neg) -> Int +//│ (Neg['a] | Object & 'b & ~#Neg) -> Int //│ where -//│ 'expr <: Neg['expr] | Object & 'a & ~#Neg -//│ 'a <: Add[Neg['expr] | Object & 'a & ~#Neg] | Lit +//│ 'a <: Neg['a] | Object & 'b & ~#Neg +//│ 'b <: Add['a] | Lit diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 60353a5eb7..32bbbcf27b 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -52,8 +52,8 @@ module M extends Mx { val r = this.id1(0) } //│ module M { -//│ fun id1: forall 'a. 'a -> 'a -//│ let r: 0 +//│ fun id1: forall 'a. ('b & 'a) -> (0 | 'a) +//│ let r: 0 | 'b //│ } mixin Mx { diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index 067fe03588..d231440a70 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -55,29 +55,29 @@ mixin WithType { module Test0 extends Base, WithUid //│ module Test0 { -//│ fun getUid: {uid: 'uid} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: 'underlying}, 'underlying -> 'a,) -> {uid: 'uid0, underlying: 'a} -//│ fun setUid: ({underlying: 'underlying0}, uid: Int,) -> {uid: Int, underlying: 'underlying0} -//│ fun unwrap: {underlying: 'underlying1} -> 'underlying1 +//│ fun getUid: {uid: 'uid, underlying: 'underlying} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, 'underlying1 -> 'underlying0,) -> {uid: Int | 'uid0, underlying: 'underlying0} +//│ fun setUid: ({uid: 'uid0, underlying: 'underlying0 & 'underlying1}, uid: Int,) -> {uid: Int | 'uid0, underlying: 'underlying0} +//│ fun unwrap: {uid: 'uid, underlying: 'underlying} -> 'underlying //│ } module Test0 extends Base, WithUid, WithUid //│ module Test0 { -//│ fun getUid: {underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, 'underlying1 -> 'underlying0,) -> {uid: 'uid0, underlying: {uid: Int | 'uid1, underlying: 'underlying0}} -//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1}}, uid: Int,) -> {uid: 'uid0, underlying: {uid: Int | 'uid1, underlying: 'underlying0}} -//│ fun unwrap: {underlying: {uid: 'uid, underlying: 'underlying}} -> 'underlying +//│ fun getUid: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: Int | 'uid0, underlying: 'underlying2 | {uid: Int | 'uid1, underlying: 'underlying0}} +//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: Int,) -> {uid: Int | 'uid0, underlying: 'underlying2 | {uid: Int | 'uid1, underlying: 'underlying0}} +//│ fun unwrap: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'underlying //│ } module Test1 extends Base, WithUid, WithType //│ module Test1 { -//│ fun getType: {underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty -//│ fun getUid: {uid: 'uid} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1}}, 'underlying1 -> 'underlying0,) -> {uid: 'uid0, underlying: {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1}}, ty: Type,) -> {uid: 'uid0, underlying: {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun setUid: ({underlying: 'underlying2}, uid: Int,) -> {uid: Int, underlying: 'underlying2} -//│ fun unwrap: {underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying +//│ fun getType: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty +//│ fun getUid: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'uid +//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0,) -> {uid: Int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, ty: Type,) -> {uid: Int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun setUid: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: Int,) -> {uid: Int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun unwrap: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying //│ } let uid = 0 @@ -123,7 +123,7 @@ a.underlying.ty.name //│ = 'A' let b = Test1.setType(a, Type("B")) -//│ let b: {uid: 0, underlying: {ty: Type, underlying: 42}} +//│ let b: {uid: Int, underlying: {ty: Type, underlying: 42}} //│ b //│ = { underlying: { underlying: 42, ty: Type {} }, uid: 0 } diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index cafbb77e39..2fc48fa458 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -100,41 +100,36 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'result}], 't,) -> ('result | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: anything}], 'b,) -> ('A | 'a) //│ } //│ where -//│ 't <: Abs['t] | App['A] | Var -//│ 'A <: Abs['t & (Abs['t] | App['A] | Var)] | Abs['t] & ~#Abs | App['A] | Var -//│ 'result :> 'a | Var -//│ 'a :> App['result | 'a] | Abs['result | 'a] +//│ 'A :> 'a | Var +//│ 'a :> App['A] | Abs['A] +//│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Var Test1.eval(Nil(), Var("a")) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'A :> 'a | Var +//│ 'a :> App['A] | Abs['A] Test1.eval(Nil(), Abs("b", Var("a"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'A :> 'a | Var +//│ 'a :> App['A] | Abs['A] Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Var | 'b | 'a +//│ 'A :> 'a | Var +//│ 'a :> App['A] | Abs['A] Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> forall 'a. Abs[Var] | Var | 'b | 'a +//│ 'A :> 'a | Abs[Var] | Var +//│ 'a :> App['A] | Abs['A] class Numb(n: Int) class Add(l: A, r: A) @@ -169,7 +164,7 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: Object & 'result}], 'a & 'b,) -> (Numb | Var | 'result | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: anything}], 'a & (Add['b] | Mul['b] | Numb | Var),) -> (Numb | Var | 'a | 'b) //│ } //│ where //│ 'b <: Add['b] | Mul['b] | Numb | Var @@ -188,38 +183,31 @@ Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'result}], 't,) -> ('b | 'a) +//│ fun eval: forall 'a. (List[{_1: Str, _2: anything}], 'b,) -> ('A | 'a) //│ } //│ where -//│ 'result :> 'b | 'a -//│ <: Object -//│ 'b :> Numb | Var | 'result | 'c | 'a -//│ 'a :> App['b | 'a] | Abs['b | 'a] -//│ 'c <: Add['t] | Mul['t] | Numb | Var -//│ 't <: Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App -//│ 'A <: Abs['t & (Abs['t] | App['A] | Object & 'c & ~#Abs & ~#App)] | Abs['t] & ~#Abs | App['A] | Object & 'c & ~#Abs & ~#App +//│ 'A :> 'a | Numb | Var | 'c +//│ 'a :> App['A] | Abs['A] +//│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Object & 'c & ~#Abs & ~#App +//│ 'c <: Add['b] | Mul['b] | Numb | Var Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> Abs[Var] | Numb | Var | 'b +//│ 'A :> 'a | Abs[Var] | Numb | Var +//│ 'a :> App['A] | Abs['A] Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) -//│ forall 'a. 'b | 'a | 'c +//│ forall 'a. 'A | 'a //│ where -//│ 'b :> forall 'a. 'a | 'c -//│ 'a :> App[forall 'a. 'b | 'a | 'c] | Abs[forall 'a. 'b | 'a | 'c] -//│ 'c :> Abs[Var] | Add[Numb | Var] | Numb | Var | 'b +//│ 'A :> 'a | Abs[Var] | Add[Numb | Var] | Numb | Var +//│ 'a :> App['A] | Abs['A] module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'result}], 'a & 'b,) -> ('a | 'c) +//│ fun eval: (List[{_1: Str, _2: anything}], 'A & (Add['a] | Mul['a] | Numb | Var),) -> ('a | 'A) //│ } //│ where -//│ 'b <: Add['b] | Mul['b] | Numb | Var -//│ 'result :> 'c -//│ <: Object -//│ 'c :> Abs[Numb | 'c] | App[Numb | 'c] | Numb | Var | 'result +//│ 'A :> Abs['A] | App['A] | Var | 'a | Numb +//│ 'a <: Add['a] | Mul['a] | Numb | Var diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index c13bdd486a..9d8d96cfc9 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -26,12 +26,11 @@ mixin EvalBase { // module TestLang extends EvalBase, EvalNeg module TestLang extends EvalBase //│ module TestLang { -//│ fun eval: forall 'E. (Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)]) -> Int +//│ fun eval: forall 'E. (Add['E] | Lit | Neg['a & (Neg['a] | Object & ~#Neg)]) -> Int //│ } //│ where -//│ 'E <: Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)] -//│ 'expr <: Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)] -//│ 'expr0 <: Add['E] | Lit | Neg['expr & (Neg['expr0] | Object & ~#Neg)] +//│ 'E <: 'a +//│ 'a <: Add['E] | Lit | Neg['a & (Neg['a] | Object & ~#Neg)] fun mk(n) = if n is @@ -47,8 +46,8 @@ TestLang.eval(mk(0)) //│ Int //│ res //│ = 0 -//│ constrain calls : 416 -//│ annoying calls : 160 -//│ subtyping calls : 4427 +//│ constrain calls : 203 +//│ annoying calls : 64 +//│ subtyping calls : 1785 From b4420567d6bac026e96b52fd603465018e404669 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Fri, 9 Jun 2023 21:08:37 +0800 Subject: [PATCH 354/498] Fix `this` capture for mixins in `globalThis` (#169) --- .../src/main/scala/mlscript/JSBackend.scala | 29 ++++---- shared/src/test/diff/codegen/Mixin.mls | 22 +++--- shared/src/test/diff/codegen/MixinCapture.mls | 67 +++++++++++++++++++ shared/src/test/diff/codegen/Nested.mls | 2 +- shared/src/test/diff/codegen/Super.mls | 6 +- shared/src/test/diff/nu/BadMixins.mls | 4 +- 6 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 shared/src/test/diff/codegen/MixinCapture.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index c3701a8f0d..af5fb9232a 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -502,6 +502,19 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } else Nil + + protected def addNuTypeToGlobalThis(typeDef: NuTypeDef, moduleName: Str) = { + import JSCodeHelpers._ + typeDef match { + case NuTypeDef(Mxn, TypeName(nme), _, _, _, _, _, _, _, _) => + JSAssignExpr(id("globalThis").member(nme), JSArrowFn(param("base") :: Nil, L( + JSInvoke(id(moduleName).member(nme), id("base") :: Nil) + ))).stmt + case NuTypeDef(_, TypeName(nme), _, _, _, _, _, _, _, _) => + JSAssignExpr(id("globalThis").member(nme), id(moduleName).member(nme)).stmt + } + } + protected def translateLocalNewType(typeDef: NuTypeDef)(implicit scope: Scope): JSConstDecl = { // TODO: support traitSymbols val (traitSymbols, classSymbols, mixinSymbols, moduleSymbols) = declareNewTypeDefs(typeDef :: Nil, false) @@ -1118,13 +1131,7 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { val insDecl = JSConstDecl(moduleIns.runtimeName, JSNew(JSIdent(topModule.runtimeName))) - def include(typeName: Str, moduleName: Str) = - JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) - val includes = - typeDefs.filter(!_.isDecl).map { - case nu: NuTypeDef => - include(nu.nme.name, moduleIns.runtimeName) - } + val includes = typeDefs.filter(!_.isDecl).map(addNuTypeToGlobalThis(_, moduleIns.runtimeName)) val resultsIdent = JSIdent(resultsName) val resultNames = ListBuffer[Str]() @@ -1316,13 +1323,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { val insDecl = JSConstDecl(moduleIns.runtimeName, JSNew(JSIdent(topModule.runtimeName))) - def include(typeName: Str, moduleName: Str) = - JSExprStmt(JSAssignExpr(JSField(JSIdent("globalThis"), typeName), JSField(JSIdent(moduleName), typeName))) - val includes = - typeDefs.filter(!_.isDecl).map { - case nu: NuTypeDef => - include(nu.nme.name, moduleIns.runtimeName) - } + val includes = typeDefs.filter(!_.isDecl).map(addNuTypeToGlobalThis(_, moduleIns.runtimeName)) val zeroWidthSpace = JSLit("\"\\u200B\"") val catchClause = JSCatchClause( diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index b29e375114..813ed51986 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -137,7 +137,7 @@ mixin EvalBase { //│ } //│ } //│ const typing_unit1 = new TypingUnit1; -//│ globalThis.EvalBase = typing_unit1.EvalBase; +//│ globalThis.EvalBase = ((base) => typing_unit1.EvalBase(base)); //│ // End of generated code //│ ┌ Block at Mixin.mls:107 //│ ├─┬ Prelude @@ -164,9 +164,9 @@ mixin EvalBase { //│ │ │ } //│ │ │ } //│ │ │ const typing_unit1 = new TypingUnit1; -//│ │ │ globalThis.EvalBase = typing_unit1.EvalBase; +//│ │ │ globalThis.EvalBase = ((base) => typing_unit1.EvalBase(base)); //│ │ └── Reply -//│ │ [Function: EvalBase] +//│ │ [Function (anonymous)] //│ └── No queries :js @@ -258,7 +258,7 @@ mixin EvalNeg { //│ } //│ } //│ const typing_unit3 = new TypingUnit3; -//│ globalThis.EvalNeg = typing_unit3.EvalNeg; +//│ globalThis.EvalNeg = ((base) => typing_unit3.EvalNeg(base)); //│ // End of generated code //│ ┌ Block at Mixin.mls:231 //│ ├─┬ Prelude @@ -282,9 +282,9 @@ mixin EvalNeg { //│ │ │ } //│ │ │ } //│ │ │ const typing_unit3 = new TypingUnit3; -//│ │ │ globalThis.EvalNeg = typing_unit3.EvalNeg; +//│ │ │ globalThis.EvalNeg = ((base) => typing_unit3.EvalNeg(base)); //│ │ └── Reply -//│ │ [Function: EvalNeg] +//│ │ [Function (anonymous)] //│ └── No queries :js @@ -319,7 +319,7 @@ mixin EvalNegNeg { //│ } //│ } //│ const typing_unit4 = new TypingUnit4; -//│ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; +//│ globalThis.EvalNegNeg = ((base) => typing_unit4.EvalNegNeg(base)); //│ // End of generated code //│ ┌ Block at Mixin.mls:292 //│ ├─┬ Prelude @@ -343,9 +343,9 @@ mixin EvalNegNeg { //│ │ │ } //│ │ │ } //│ │ │ const typing_unit4 = new TypingUnit4; -//│ │ │ globalThis.EvalNegNeg = typing_unit4.EvalNegNeg; +//│ │ │ globalThis.EvalNegNeg = ((base) => typing_unit4.EvalNegNeg(base)); //│ │ └── Reply -//│ │ [Function: EvalNegNeg] +//│ │ [Function (anonymous)] //│ └── No queries :js @@ -510,7 +510,7 @@ mixin Fooo(x: Int) { fun f = [x, this.x] } //│ } //│ } //│ const typing_unit14 = new TypingUnit14; -//│ globalThis.Fooo = typing_unit14.Fooo; +//│ globalThis.Fooo = ((base) => typing_unit14.Fooo(base)); //│ // End of generated code :js @@ -533,7 +533,7 @@ mixin Bazz(y: Int) //│ } //│ } //│ const typing_unit15 = new TypingUnit15; -//│ globalThis.Bazz = typing_unit15.Bazz; +//│ globalThis.Bazz = ((base) => typing_unit15.Bazz(base)); //│ // End of generated code :js diff --git a/shared/src/test/diff/codegen/MixinCapture.mls b/shared/src/test/diff/codegen/MixinCapture.mls new file mode 100644 index 0000000000..05dafa5013 --- /dev/null +++ b/shared/src/test/diff/codegen/MixinCapture.mls @@ -0,0 +1,67 @@ +:NewDefs + +:js +class Lit(n: Int) +mixin EvalAddLit { + fun eval(e) = + if e is + Lit(n) then n +} +//│ class Lit(n: Int) +//│ mixin EvalAddLit() { +//│ fun eval: Lit -> Int +//│ } +//│ // Prelude +//│ let res; +//│ class TypingUnit { +//│ #Lit; +//│ constructor() { +//│ } +//│ EvalAddLit(base) { +//│ const outer = this; +//│ return (class EvalAddLit extends base { +//│ constructor(...rest) { +//│ super(...rest); +//│ } +//│ eval(e) { +//│ return ((() => { +//│ let a; +//│ return (a = e, a instanceof outer.Lit.class ? ((n) => n)(e.n) : (() => { +//│ throw new Error("non-exhaustive case expression"); +//│ })()); +//│ })()); +//│ } +//│ }); +//│ } +//│ get Lit() { +//│ const outer = this; +//│ if (this.#Lit === undefined) { +//│ class Lit { +//│ #n; +//│ get n() { return this.#n; } +//│ constructor(n) { +//│ this.#n = n; +//│ } +//│ }; +//│ this.#Lit = ((n) => Object.freeze(new Lit(n))); +//│ this.#Lit.class = Lit; +//│ } +//│ return this.#Lit; +//│ } +//│ } +//│ const typing_unit = new TypingUnit; +//│ globalThis.Lit = typing_unit.Lit; +//│ globalThis.EvalAddLit = ((base) => typing_unit.EvalAddLit(base)); +//│ // End of generated code + +module TestLang extends EvalAddLit +//│ module TestLang { +//│ fun eval: Lit -> Int +//│ } + +TestLang.eval(Lit(0)) +//│ Int +//│ res +//│ = 0 + + diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 9b619d7076..99cd7e7908 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -169,7 +169,7 @@ mixin C() { //│ } //│ } //│ const typing_unit3 = new TypingUnit3; -//│ globalThis.C = typing_unit3.C; +//│ globalThis.C = ((base) => typing_unit3.C(base)); //│ // End of generated code :js diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index a3f3a881cf..6b3594478b 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -28,7 +28,7 @@ mixin Foo0 { //│ } //│ } //│ const typing_unit = new TypingUnit; -//│ globalThis.Foo0 = typing_unit.Foo0; +//│ globalThis.Foo0 = ((base) => typing_unit.Foo0(base)); //│ // End of generated code :js @@ -63,7 +63,7 @@ mixin Foo1 { //│ } //│ } //│ const typing_unit1 = new TypingUnit1; -//│ globalThis.Foo1 = typing_unit1.Foo1; +//│ globalThis.Foo1 = ((base) => typing_unit1.Foo1(base)); //│ // End of generated code module Test0 extends Foo0, Foo1 @@ -108,7 +108,7 @@ mixin Foo2 { //│ } //│ } //│ const typing_unit4 = new TypingUnit4; -//│ globalThis.Foo2 = typing_unit4.Foo2; +//│ globalThis.Foo2 = ((base) => typing_unit4.Foo2(base)); //│ // End of generated code //│ Syntax error: //│ 'super' keyword unexpected here diff --git a/shared/src/test/diff/nu/BadMixins.mls b/shared/src/test/diff/nu/BadMixins.mls index ec475ed01d..34cf7fba43 100644 --- a/shared/src/test/diff/nu/BadMixins.mls +++ b/shared/src/test/diff/nu/BadMixins.mls @@ -10,7 +10,7 @@ M0 //│ mixin M0() //│ error //│ res -//│ = [Function: M0] +//│ = [Function (anonymous)] :e M0 @@ -19,5 +19,5 @@ M0 //│ ╙── ^^ //│ error //│ res -//│ = [Function: M0] +//│ = [Function (anonymous)] From 7e4aca761d699b02b4b3c6120e7fce241205691c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 6 Jun 2023 17:39:22 +0800 Subject: [PATCH 355/498] Update web demo examples and code --- index.html | 23 +++++++++-------------- js/src/main/scala/Main.scala | 7 +++---- local_testing.html | 6 +++--- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/index.html b/index.html index 100da6b69c..b857718d21 100644 --- a/index.html +++ b/index.html @@ -9,25 +9,20 @@

MLscript online demonstration

) f(x, y) = [x, y] +//│ let (-->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] +//│ f +//│ = [Function: f] + +:ge // FIXME +12 --> 34 +//│ [12, 34] +//│ Code generation encountered an error: +//│ unresolved symbol --> + + diff --git a/shared/src/test/diff/nu/Vals.mls b/shared/src/test/diff/nu/Vals.mls index 4377d8b517..14602aa1a5 100644 --- a/shared/src/test/diff/nu/Vals.mls +++ b/shared/src/test/diff/nu/Vals.mls @@ -28,4 +28,29 @@ val a = a //│ = 1 +val f(x) = x +//│ let f: forall 'a. 'a -> 'a +//│ f +//│ = [Function: f] + +f(123) +//│ 123 +//│ res +//│ = 123 + + +module M { + let tmp = 2 + val f(x) = x + tmp +} +//│ module M { +//│ let f: Int -> Int +//│ let tmp: 2 +//│ } + +M.f(123) +//│ Int +//│ res +//│ = 125 + From aea433dd9ef9e1cb212f56780a21d0a96cb8011c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 12 Sep 2023 18:18:47 +0800 Subject: [PATCH 435/498] Move test cases to correct file --- shared/src/test/diff/codegen/SymbolicOps.mls | 85 +++++++++++++++++++- shared/src/test/diff/nu/TypeOps.mls | 85 -------------------- 2 files changed, 84 insertions(+), 86 deletions(-) diff --git a/shared/src/test/diff/codegen/SymbolicOps.mls b/shared/src/test/diff/codegen/SymbolicOps.mls index 03338db92c..0f946dfbde 100644 --- a/shared/src/test/diff/codegen/SymbolicOps.mls +++ b/shared/src/test/diff/codegen/SymbolicOps.mls @@ -208,7 +208,7 @@ fun (??) oops(a, b) = a + b -// * Note: some misformed definitions +// * Note: some malformed definitions :pe :e @@ -240,4 +240,87 @@ fun compose(>>)(f, g) = x => g(f(x)) //│ fun compose: forall 'a 'b 'c. () -> ('a -> 'b, 'b -> 'c) -> 'a -> 'c +:pe +fun () foo(a, b) = a + b +//│ ╔══[PARSE ERROR] Expected a symbolic name between brackets, found nothing +//│ ║ l.244: fun () foo(a, b) = a + b +//│ ╙── ^^ +//│ fun foo: (Int, Int) -> Int + +:pe +fun ( ) foo(a, b) = a + b +//│ ╔══[PARSE ERROR] Expected a symbolic name, found space instead +//│ ║ l.251: fun ( ) foo(a, b) = a + b +//│ ╙── ^^^ +//│ fun foo: (Int, Int) -> Int + +:pe +fun ( +) foo(a, b) = a + b +//│ ╔══[PARSE ERROR] Expected a symbolic name, found newline instead +//│ ║ l.258: fun ( +//│ ║ ^ +//│ ║ l.259: ) foo(a, b) = a + b +//│ ╙── +//│ fun foo: (Int, Int) -> Int + +:pe +fun (1) foo(a, b) = a + b +//│ ╔══[PARSE ERROR] Expected a symbolic name, found literal instead +//│ ║ l.268: fun (1) foo(a, b) = a + b +//│ ╙── ^ +//│ fun foo: (Int, Int) -> Int + +:pe +fun (++ 1) foo(a, b) = a + b +//│ ╔══[PARSE ERROR] Unexpected literal after symbolic name +//│ ║ l.275: fun (++ 1) foo(a, b) = a + b +//│ ╙── ^ +//│ fun (++) foo: (Int, Int) -> Int + +:pe +fun (a ++ 1) foo(a, b) = a + b +//│ ╔══[PARSE ERROR] Expected a symbolic name, found identifier instead +//│ ║ l.282: fun (a ++ 1) foo(a, b) = a + b +//│ ╙── ^ +//│ fun foo: (Int, Int) -> Int +// should be `<<|+_+|>>`, but we got `<<|+` + + +:pe +fun (<<|+_+|>>) robot(a, b) = a + b +//│ ╔══[PARSE ERROR] Unexpected identifier after symbolic name +//│ ║ l.291: fun (<<|+_+|>>) robot(a, b) = a + b +//│ ╙── ^ +//│ fun (<<|+) robot: (Int, Int) -> Int + +fun (<<|+-+|>>) robot(a, b) = a + b +//│ fun (<<|+-+|>>) robot: (Int, Int) -> Int + +2 <<|+-+|>> 2 +//│ Int +//│ res +//│ = 4 + + +:pe +fun (:-D) dd(a, b) = a + b +//│ ╔══[PARSE ERROR] Unexpected identifier after symbolic name +//│ ║ l.307: fun (:-D) dd(a, b) = a + b +//│ ╙── ^ +//│ fun (:-) dd: (Int, Int) -> Int +// should be `:-D`, but we got `:-` + + +val (-->) f(x, y) = [x, y] +//│ let (-->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] +//│ f +//│ = [Function: f1] + +:ge // FIXME +12 --> 34 +//│ [12, 34] +//│ Code generation encountered an error: +//│ unresolved symbol --> + diff --git a/shared/src/test/diff/nu/TypeOps.mls b/shared/src/test/diff/nu/TypeOps.mls index 4de9f0222f..6f2363088c 100644 --- a/shared/src/test/diff/nu/TypeOps.mls +++ b/shared/src/test/diff/nu/TypeOps.mls @@ -38,88 +38,3 @@ fun x: Id[[[Int, Int]]] //│ fun x: Id[[[Int, Int]]] - -:pe -fun () foo(a, b) = a + b -//│ ╔══[PARSE ERROR] Expected a symbolic name between brackets, found nothing -//│ ║ l.43: fun () foo(a, b) = a + b -//│ ╙── ^^ -//│ fun foo: (Int, Int) -> Int - -:pe -fun ( ) foo(a, b) = a + b -//│ ╔══[PARSE ERROR] Expected a symbolic name, found space instead -//│ ║ l.50: fun ( ) foo(a, b) = a + b -//│ ╙── ^^^ -//│ fun foo: (Int, Int) -> Int - -:pe -fun ( -) foo(a, b) = a + b -//│ ╔══[PARSE ERROR] Expected a symbolic name, found newline instead -//│ ║ l.57: fun ( -//│ ║ ^ -//│ ║ l.58: ) foo(a, b) = a + b -//│ ╙── -//│ fun foo: (Int, Int) -> Int - -:pe -fun (1) foo(a, b) = a + b -//│ ╔══[PARSE ERROR] Expected a symbolic name, found literal instead -//│ ║ l.67: fun (1) foo(a, b) = a + b -//│ ╙── ^ -//│ fun foo: (Int, Int) -> Int - -:pe -fun (++ 1) foo(a, b) = a + b -//│ ╔══[PARSE ERROR] Unexpected literal after symbolic name -//│ ║ l.74: fun (++ 1) foo(a, b) = a + b -//│ ╙── ^ -//│ fun (++) foo: (Int, Int) -> Int - -:pe -fun (a ++ 1) foo(a, b) = a + b -//│ ╔══[PARSE ERROR] Expected a symbolic name, found identifier instead -//│ ║ l.81: fun (a ++ 1) foo(a, b) = a + b -//│ ╙── ^ -//│ fun foo: (Int, Int) -> Int -// should be `<<|+_+|>>`, but we got `<<|+` - - -:pe -fun (<<|+_+|>>) robot(a, b) = a + b -//│ ╔══[PARSE ERROR] Unexpected identifier after symbolic name -//│ ║ l.90: fun (<<|+_+|>>) robot(a, b) = a + b -//│ ╙── ^ -//│ fun (<<|+) robot: (Int, Int) -> Int - -fun (<<|+-+|>>) robot(a, b) = a + b -//│ fun (<<|+-+|>>) robot: (Int, Int) -> Int - -2 <<|+-+|>> 2 -//│ Int -//│ res -//│ = 4 - - -:pe -fun (:-D) dd(a, b) = a + b -//│ ╔══[PARSE ERROR] Unexpected identifier after symbolic name -//│ ║ l.106: fun (:-D) dd(a, b) = a + b -//│ ╙── ^ -//│ fun (:-) dd: (Int, Int) -> Int -// should be `:-D`, but we got `:-` - - -val (-->) f(x, y) = [x, y] -//│ let (-->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] -//│ f -//│ = [Function: f] - -:ge // FIXME -12 --> 34 -//│ [12, 34] -//│ Code generation encountered an error: -//│ unresolved symbol --> - - From fa2af756ffb96560831a5f99c6216aa5b06c615f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 13 Sep 2023 17:58:54 +0800 Subject: [PATCH 436/498] Clean up some tests by using new operator support --- shared/src/test/diff/tapl/NuSimplyTyped.mls | 47 ++++-------- shared/src/test/diff/tapl/NuUntyped.mls | 84 +++++++++------------ 2 files changed, 52 insertions(+), 79 deletions(-) diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls index 3f8e90a06b..bc71deb00d 100644 --- a/shared/src/test/diff/tapl/NuSimplyTyped.mls +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -1,26 +1,11 @@ :NewParser :NewDefs -let str = toString -fun concat2(a, b) = concat(a)(b) -fun concat3(a, b, c) = concat2(a, concat2(b, c)) -fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) -fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) -fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) -fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) -fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) -fun par(a) = concat3("(", a, ")") -//│ let str: anything -> Str -//│ fun concat2: (Str, Str) -> Str -//│ fun concat3: (Str, Str, Str) -> Str -//│ fun concat4: (Str, Str, Str, Str) -> Str -//│ fun concat5: (Str, Str, Str, Str, Str) -> Str -//│ fun concat6: (Str, Str, Str, Str, Str, Str) -> Str -//│ fun concat7: (Str, Str, Str, Str, Str, Str, Str) -> Str -//│ fun concat8: (Str, Str, Str, Str, Str, Str, Str, Str) -> Str +fun (++) concatOp(a, b) = concat(a)(b) +//│ fun (++) concatOp: (Str, Str) -> Str + +fun par(a) = "(" ++ a ++ ")" //│ fun par: Str -> Str -//│ str -//│ = [Function: toString] type Option[A] = Some[A] | None class Some[A](value: A) @@ -87,8 +72,8 @@ fun find(t, k) = fun showType(ty) = if ty is - FunctionType(PrimitiveType(name), rhs) then concat3(name, " -> ", showType(rhs)) - FunctionType(lhs, rhs) then concat4("(", showType(lhs), ") -> ", showType(rhs)) + FunctionType(PrimitiveType(name), rhs) then name ++ " -> " ++ showType(rhs) + FunctionType(lhs, rhs) then "(" ++ showType(lhs) ++ ") -> " ++ showType(rhs) PrimitiveType(name) then name //│ fun showType: (FunctionType | PrimitiveType) -> Str @@ -116,12 +101,12 @@ fun typeEqual(t1, t2) = fun showTerm(t) = if t is - Lit(tag, _) then toString(tag) - Var(name) then toString(name) - Abs(lhs, ty, rhs) then concat6("&", showTerm(lhs), ": ", showType(ty), " => ", showTerm(rhs)) + Lit(tag, _) then tag + Var(name) then name + Abs(lhs, ty, rhs) then "&" ++ showTerm(lhs) ++ ": " ++ showType(ty) ++ " => " ++ showTerm(rhs) App(Abs(lhs0, ty, lhs1), rhs) then - concat5("((", showTerm(Abs(lhs0, ty, rhs)), ") ", showTerm(rhs), ")") - App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) + "((" ++ showTerm(Abs(lhs0, ty, rhs)) ++ ") " ++ showTerm(rhs) ++ ")" + App(lhs, rhs) then par(showTerm(lhs) ++ " " ++ showTerm(rhs)) //│ fun showTerm: (Abs | App | Lit | Var) -> Str showTerm(Var("x")) @@ -144,7 +129,7 @@ fun typeTerm(t: Term, ctx: TreeMap[Type]): Result[Type, Str] = Lit(_, ty) then Ok(ty) Var(name) and find(ctx, name) is Some(ty) then Ok(ty) - None then Err(concat3("unbound variable `", name, "`")) + None then Err("unbound variable `" ++ name ++ "`") Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is Ok(resTy) then Ok(FunctionType(ty, resTy)) Err(message) then Err(message) @@ -152,16 +137,16 @@ fun typeTerm(t: Term, ctx: TreeMap[Type]): Result[Type, Str] = Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is Ok(aTy) and typeEqual(pTy, aTy) then Ok(resTy) - else Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) + else Err("expect the argument to be of type `" ++ showType(pTy) ++ "` but found `" ++ showType(aTy) ++ "`") Err(message) then Err(message) - Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) + Ok(PrimitiveType(name)) then Err("cannot apply primitive type `" ++ name ++ "`") Err(message) then Err(message) //│ fun typeTerm: (t: Term, ctx: TreeMap[Type]) -> Result[Type, Str] fun showTypeTerm(t, ctx) = if typeTerm(t, ctx) is - Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) - Err(message) then concat2("Type error: ", message) + Ok(ty) then showTerm(t) ++ " : " ++ showType(ty) + Err(message) then "Type error: " ++ message //│ fun showTypeTerm: (Term, TreeMap[Type]) -> Str showTypeTerm(Var("x"), Empty) diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index 187056858a..df42332b85 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -1,38 +1,23 @@ -:NewParser :NewDefs -fun concat2(a, b) = concat(a)(b) -fun concat3(a, b, c) = concat2(a, concat2(b, c)) -fun concat4(a, b, c, d) = concat2(a, concat3(b, c, d)) -fun concat5(a, b, c, d, e) = concat2(a, concat4(b, c, d, e)) -fun concat6(a, b, c, d, e, f) = concat2(a, concat5(b, c, d, e, f)) -fun concat7(a, b, c, d, e, f, g) = concat2(a, concat6(b, c, d, e, f, g)) -fun concat8(a, b, c, d, e, f, g, h) = concat2(a, concat7(b, c, d, e, f, g, h)) -fun par(a) = concat3("(", a, ")") -//│ fun concat2: (Str, Str) -> Str -//│ fun concat3: (Str, Str, Str) -> Str -//│ fun concat4: (Str, Str, Str, Str) -> Str -//│ fun concat5: (Str, Str, Str, Str, Str) -> Str -//│ fun concat6: (Str, Str, Str, Str, Str, Str) -> Str -//│ fun concat7: (Str, Str, Str, Str, Str, Str, Str) -> Str -//│ fun concat8: (Str, Str, Str, Str, Str, Str, Str, Str) -> Str +fun (++) concatOp(a, b) = concat(a)(b) +//│ fun (++) concatOp: (Str, Str) -> Str + +fun par(a) = "(" ++ a ++ ")" //│ fun par: Str -> Str -:escape -let String: nothing +declare fun String: nothing +//│ fun String: nothing + let makeString: anything => { length: Int, charCodeAt: Int => Int } = String let StringInstance: { fromCharCode: Int => Str } = String -//│ let String: nothing //│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} //│ let StringInstance: {fromCharCode: Int -> Str} -//│ String -//│ = //│ makeString //│ = [Function: String] //│ StringInstance //│ = [Function: String] - let anythingToString = toString fun fromCharCode(n: Int) = StringInstance.fromCharCode(n) fun stringCharCodeAt(s: Str, i) = makeString(s).charCodeAt(i) @@ -46,7 +31,7 @@ fun stringLength(s: Str) = makeString(s).length type Option[A] = Some[A] | None class Some[A](value: A) { - fun toString() = concat3("Some(", anythingToString(value), ")") + fun toString() = "Some(" ++ anythingToString(value) ++ ")" } module None { fun toString() = "None" @@ -66,6 +51,7 @@ module Nil //│ class Cons[A](head: A, tail: List[A]) //│ module Nil +// * We could define a shorthand for these, but let's leave them as useful tests fun list1(x) = Cons(x, Nil) fun list2(x, y) = Cons(x, list1(y)) fun list3(x, y, z) = Cons(x, list2(y, z)) @@ -118,18 +104,21 @@ fun listWithout(xs, x) = //│ where //│ 'A <: 'A0 -// fix this: -// fun listJoin(xs, sep) = -// if xs is -// Nil then "" -// Cons(x, Nil) then toString(x) -// Cons(x, xs') then concat3(toString(x), sep, listJoin(xs', sep)) + +// * FIXME? +fun listJoin(xs, sep) = + if xs is + Nil then "" + Cons(x, Nil) then toString(x) + Cons(x, xs') then toString(x) ++ sep ++ listJoin(xs', sep) +//│ fun listJoin: forall 'A. (Cons['A] | Nil, Str) -> Str + fun listJoin(xs, sep) = if xs is Nil then "" Cons(x, xs') and xs' is Nil then toString(x) - _ then concat3(toString(x), sep, listJoin(xs', sep)) + _ then toString(x) ++ sep ++ listJoin(xs', sep) //│ fun listJoin: forall 'A. (Cons['A] | Nil, Str) -> Str listJoin(list3("x", "y", "z"), ", ") @@ -149,10 +138,10 @@ class App(lhs: Term, rhs: Term) fun showTerm(t) = if t is Var(name) then toString(name) - Abs(lhs, rhs) then concat4("&", showTerm(lhs), ". ", showTerm(rhs)) + Abs(lhs, rhs) then "&" ++ showTerm(lhs) ++ ". " ++ showTerm(rhs) App(Abs(lhs0, lhs1), rhs) then - concat8("((", "&", showTerm(lhs0), ". ", showTerm(lhs1), ") ", showTerm(rhs), ")") - App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) + "((" ++ "&" ++ showTerm(lhs0) ++ ". " ++ showTerm(lhs1) ++ ") " ++ showTerm(rhs) ++ ")" + App(lhs, rhs) then par(showTerm(lhs) ++ " " ++ showTerm(rhs)) //│ fun showTerm: (Abs | App | Var) -> Str showTerm(Var("x")) @@ -198,7 +187,7 @@ fun hasFree(t, n) = //│ fun hasFree: (Object, anything) -> Bool fun showHasFree(t, n) = - concat4(showTerm(t), if hasFree(t, n) then " has " else " DOES NOT have ", "free variable ", n) + showTerm(t) ++ (if hasFree(t, n) then " has " else " DOES NOT have ") ++ "free variable " ++ n //│ fun showHasFree: (Abs | App | Var, Str) -> Str showHasFree(Var("x"), "x") @@ -249,10 +238,9 @@ fun fv(t) = //│ 'A :> Str fun showFv(t) = - concat2(showTerm(t), if fv(t) is + showTerm(t) ++ if fv(t) is Nil then " DOES NOT have free variables" - _ then concat2(" has free variables: ", listJoin(fv(t), ", ")) - ) + _ then " has free variables: " ++ listJoin(fv(t), ", ") //│ fun showFv: (Abs | App | Var) -> Str showFv(Var("x")) @@ -282,11 +270,11 @@ fun tryNextAlphabet(initialCode, currentCode, freeNames) = _ then Some(name) //│ fun tryNextAlphabet: forall 'A. (Num, Int, Cons['A] | Nil) -> (None | Some[Str]) -toString(tryNextAlphabet(97, 97, list1("a"))) -toString(tryNextAlphabet(97, 98, list1("a"))) -toString(tryNextAlphabet(97, 98, list2("a", "b"))) -toString(tryNextAlphabet(121, 122, list1("y"))) -toString(tryNextAlphabet(121, 122, list2("y", "z"))) +tryNextAlphabet(97, 97, list1("a")).toString() +tryNextAlphabet(97, 98, list1("a")).toString() +tryNextAlphabet(97, 98, list2("a", "b")).toString() +tryNextAlphabet(121, 122, list1("y")).toString() +tryNextAlphabet(121, 122, list2("y", "z")).toString() //│ Str //│ res //│ = 'None' @@ -301,7 +289,7 @@ toString(tryNextAlphabet(121, 122, list2("y", "z"))) fun tryAppendDigits(name, index, freeNames) = if - let currentName = concat2(name, toString(index)) + let currentName = name ++ toString(index) listContains(freeNames, currentName) then tryAppendDigits(name, index + 1, freeNames) _ then currentName @@ -315,7 +303,7 @@ fun findFreshName(name, freeNames) = tryNextAlphabet(charCode, charCode + 1, freeNames) is Some(newName) then newName _ then tryAppendDigits(name, 0, freeNames) -//│ fun findFreshName: forall 'A 'A0 'A1. (Str, Cons[in 'A1 | 'A | 'A0 out 'A1 & 'A & 'A0] | Nil) -> Str +//│ fun findFreshName: forall 'A 'A0 'A1. (Str, Cons[in 'A | 'A0 | 'A1 out 'A & 'A0 & 'A1] | Nil) -> Str // Find a fresh name to replace `name` that does not conflict with any bound // variables in the `body`. @@ -334,7 +322,7 @@ fun subst(t, n, v) = //│ fun subst: forall 'a. (Abs | App | Term & Object & 'a & ~#Abs & ~#App & ~#Var | Var, anything, Term & Object & 'a) -> (Abs | App | Var | 'a) fun showSubst(t, n, v) = - concat8(showTerm(t), " [", n, " / ", showTerm(v), "]", " => ", showTerm(subst(t, n, v))) + showTerm(t) ++ " [" ++ n ++ " / " ++ showTerm(v) ++ "]" ++ " => " ++ showTerm(subst(t, n, v)) //│ fun showSubst: (Abs | App | Var, Str, Abs & Term | App & Term | Var & Term) -> Str showSubst(Var("x"), "x", Var("y")) @@ -359,13 +347,13 @@ showSubst(Abs(Var("z"), Abs(Var("x"), App(Var("z"), App(Var("x"), Var("y"))))), type Result = Normal | Stuck | Stepped class Normal(term: Term) { - fun toString() = concat2("Normal form: ", showTerm(term)) + fun toString() = "Normal form: " ++ showTerm(term) } class Stuck(term: Term, part: Term) { - fun toString() = concat4("Stuck: ", showTerm(part), " in ", showTerm(term)) + fun toString() = "Stuck: " ++ showTerm(part) ++ " in " ++ showTerm(term) } class Stepped(from: Term, to: Term) { - fun toString() = concat3(showTerm(from), " => ", showTerm(to)) + fun toString() = showTerm(from) ++ " => " ++ showTerm(to) } //│ type Result = Normal | Stepped | Stuck //│ class Normal(term: Term) { From 781e90f3fc9b3879fb8c70a7a1a4d5fee0174dea Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 13 Sep 2023 18:06:03 +0800 Subject: [PATCH 437/498] Adjust the precedence of => and uncover some unrelated type inference bugs --- .../src/main/scala/mlscript/NewParser.scala | 10 +- shared/src/test/diff/nu/FlatMonads.mls | 156 +++++++++++++++++- shared/src/test/diff/nu/GenericMethods.mls | 22 ++- shared/src/test/diff/nu/LamPatterns.mls | 62 +++++++ shared/src/test/diff/nu/NuScratch.mls | 34 ++++ shared/src/test/diff/nu/OpLam.mls | 89 ++++++++++ shared/src/test/diff/parser/Lambdas.mls | 2 +- shared/src/test/diff/parser/Where.mls | 4 +- 8 files changed, 365 insertions(+), 14 deletions(-) create mode 100644 shared/src/test/diff/nu/LamPatterns.mls create mode 100644 shared/src/test/diff/nu/OpLam.mls diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index fea1cde99f..f2dfdb676c 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -135,8 +135,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case "and" => (3, 3) case "or" => (2, 2) case "=>" => - val eqPrec = prec('=') - (eqPrec, eqPrec - 1) + // * The lambda operator is special: + // * it should associate veyr strongly on the left and very loosely on the right + // * so that we can write things like `f() |> x => x is 0` ie `(f()) |> (x => (x is 0))` + val eqPrec = prec('.') // * We pick the tightest precedence + (eqPrec, 1) + // * Note: we used to do this instead which broke the example above on both sides: + // val eqPrec = prec('=') + // (eqPrec, eqPrec - 1) case _ if opStr.exists(_.isLetter) => (5, 5) case _ => diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index 2fd102aca4..d2eb8d2fa2 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -112,6 +112,160 @@ printLine("").bind of [] => error //│ = Bind {} +// * Using a shortand operator for `bind` + +fun (|>=) bindOp[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) +//│ fun (|>=) bindOp: forall 'A 'B. (x: IO['A], f: 'A -> IO['B]) -> IO['B] + +:e // FIXME why the errors? +val main = + printLine("Hi! Input two numbers: ") |>= _ => + readInt |>= n => + readInt |>= m => + val sum = n + m + printLine(concat("The sum is: ")(String of sum)) |>= _ => + Pure(sum) +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.124: readInt |>= m => +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.125: val sum = n + m +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.126: printLine(concat("The sum is: ")(String of sum)) |>= _ => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.127: Pure(sum) +//│ ║ ^^^^^^^^^^^ +//│ ╟── type `Int` does not match type `undefined` +//│ ║ l.32: module readInt extends IO[Int] { fun run = 42 } +//│ ║ ^^^ +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.33: class printLine(str: Str) extends IO[undefined] { fun run = log(str) } +//│ ║ ^^^^^^^^^ +//│ ╟── Note: method type parameter A is defined at: +//│ ║ l.117: fun (|>=) bindOp[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.123: readInt |>= n => +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.124: readInt |>= m => +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.125: val sum = n + m +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.126: printLine(concat("The sum is: ")(String of sum)) |>= _ => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.127: Pure(sum) +//│ ║ ^^^^^^^^^^^ +//│ ╟── type `Int` does not match type `undefined` +//│ ║ l.32: module readInt extends IO[Int] { fun run = 42 } +//│ ║ ^^^ +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.33: class printLine(str: Str) extends IO[undefined] { fun run = log(str) } +//│ ║ ^^^^^^^^^ +//│ ╟── Note: method type parameter A is defined at: +//│ ║ l.117: fun (|>=) bindOp[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.122: printLine("Hi! Input two numbers: ") |>= _ => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.123: readInt |>= n => +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.124: readInt |>= m => +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.125: val sum = n + m +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.126: printLine(concat("The sum is: ")(String of sum)) |>= _ => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.127: Pure(sum) +//│ ║ ^^^^^^^^^^^ +//│ ╟── type `undefined` is not an instance of type `Int` +//│ ║ l.33: class printLine(str: Str) extends IO[undefined] { fun run = log(str) } +//│ ║ ^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.125: val sum = n + m +//│ ╙── ^ +//│ let main: IO['B] | error +//│ main +//│ = Bind {} + + +// * With no type annotations: + +fun (|>=) bindOp(x, f) = x.bind(f) +//│ fun (|>=) bindOp: forall 'a 'b. ({bind: 'a -> 'b}, 'a) -> 'b + +// FIXME why `nothing`? +val main = + printLine("Hi! Input two numbers: ") |>= _ => + readInt |>= n => + readInt |>= m => + val sum = n + m + printLine(concat("The sum is: ")(String of sum)) |>= _ => + Pure(sum) +//│ let main: Bind[nothing, 'B] +//│ where +//│ 'B :> Int +//│ main +//│ = Bind {} + +main.run +//│ Int +//│ res +//│ = 84 +//│ // Output +//│ Hi! Input two numbers: +//│ The sum is: 84 + + +// * Abstracting over the monad: + +fun (|>=) bindOp(x, f) = x.bind(f) +//│ fun (|>=) bindOp: forall 'a 'b. ({bind: 'a -> 'b}, 'a) -> 'b + +fun main(ctx) = + ctx.printLine("Hi! Input two numbers: ") |>= _ => + ctx.readInt |>= n => + ctx.readInt |>= m => + val sum = n + m + ctx.printLine(concat("The sum is: ")(String of sum)) |>= _ => + ctx.pure(sum) +//│ fun main: forall 'a 'b. {printLine: Str -> {bind: (Int -> ('a | 'b)) -> 'a}, pure: Int -> 'b, readInt: {bind: (Int -> ('a | 'b)) -> 'a}} -> 'a + +val defaultCtx = {printLine, readInt, pure: Pure} +//│ let defaultCtx: {printLine: (str: Str) -> printLine, pure: forall 'A. (value: 'A) -> Pure['A], readInt: readInt} +//│ defaultCtx +//│ = { +//│ printLine: [Function (anonymous)] { class: [class printLine extends IO] }, +//│ readInt: readInt { class: [class readInt extends IO] }, +//│ pure: [Function (anonymous)] { class: [class Pure extends IO] } +//│ } + +main(defaultCtx).run +//│ Int +//│ res +//│ = 84 +//│ // Output +//│ Hi! Input two numbers: +//│ The sum is: 84 + +fun loop(ctx) = + ctx.printLine("Input a positive number: ") |>= _ => + ctx.readInt |>= n => + if n < 0 then loop(ctx) else ctx.pure(n) +//│ fun loop: forall 'a 'b 'c. {printLine: "Input a positive number: " -> {bind: ((Int & 'a) -> ('b | 'c)) -> 'b}, pure: 'a -> 'c, readInt: {bind: ((Int & 'a) -> ('b | 'c)) -> 'b}} -> 'b + +// FIXME why `nothing`? +let r = loop(defaultCtx).run +//│ let r: nothing +//│ r +//│ = 42 +//│ // Output +//│ Input a positive number: + +not(r) +//│ Bool +//│ res +//│ = false + + // * Note: using inferred type parent arguments module readInt extends IO { fun run = 42 } @@ -122,7 +276,7 @@ declare fun String: anything -> Str //│ fun run: 42 //│ } //│ class printLine(str: Str) extends IO { -//│ fun bind: forall 'B0 'A0. ('A0 -> IO['B0]) -> Bind['A0, 'B0] +//│ fun bind: forall 'A0 'B0. ('A0 -> IO['B0]) -> Bind['A0, 'B0] //│ fun run: undefined //│ } //│ fun String: anything -> Str diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index a6af12fd2a..04115b3d8c 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -85,15 +85,21 @@ fun bar: A => A //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.77: fun bar: A => A //│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Unsupported pattern shape: +//│ ╔══[ERROR] identifier not found: >: //│ ║ l.77: fun bar: A => A -//│ ╙── ^^^^^ +//│ ╙── ^^ +//│ ╔══[ERROR] identifier not found: A +//│ ║ l.77: fun bar: A => A +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: A +//│ ║ l.77: fun bar: A => A +//│ ╙── ^ //│ ╔══[ERROR] identifier not found: A //│ ║ l.77: fun bar: A => A //│ ╙── ^ -//│ error -> error +//│ error //│ Code generation encountered an error: -//│ term App(Var(>:), Tup(_: Var(A), _: Var(A))) is not a valid pattern +//│ unresolved symbol >: :e @@ -103,16 +109,16 @@ module Test { fun test(x: A) = x } //│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Test` -//│ ║ l.100: module Test { +//│ ║ l.106: module Test { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.101: fun foo: 'A => 'A +//│ ║ l.107: fun foo: 'A => 'A //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Test` -//│ ║ l.100: module Test { +//│ ║ l.106: module Test { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.102: fun bar: 'A +//│ ║ l.108: fun bar: 'A //│ ╙── ^^^^^^^ //│ module Test { //│ fun bar: nothing diff --git a/shared/src/test/diff/nu/LamPatterns.mls b/shared/src/test/diff/nu/LamPatterns.mls new file mode 100644 index 0000000000..58aa85eb8e --- /dev/null +++ b/shared/src/test/diff/nu/LamPatterns.mls @@ -0,0 +1,62 @@ +:NewDefs + + +class Some(value: Int) +//│ class Some(value: Int) + +:e // TODO +Some(x) => x +//│ ╔══[ERROR] Unsupported pattern shape: +//│ ║ l.8: Some(x) => x +//│ ╙── ^^^^^^^ +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.8: Some(x) => x +//│ ╙── ^ +//│ error -> error +//│ Code generation encountered an error: +//│ term App(Var(Some), Tup(_: Var(x))) is not a valid pattern + +:js +// FIXME type +let f = Some => 0 +//│ let f: ((value: Int) -> Some) -> 0 +//│ // Prelude +//│ class TypingUnit2 {} +//│ const typing_unit2 = new TypingUnit2; +//│ // Query 1 +//│ globalThis.f = function f(Some) { +//│ return 0; +//│ }; +//│ // End of generated code +//│ f +//│ = [Function: f] + +// :e // TODO +f(Some) +//│ 0 +//│ res +//│ = 0 + +// :e // TODO +f(_ => error) +//│ 0 +//│ res +//│ = 0 + +:e // TODO +f(Some(0)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.47: f(Some(0)) +//│ ║ ^^^^^^^^^^ +//│ ╟── application of type `Some` is not a function +//│ ║ l.47: f(Some(0)) +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.21: let f = Some => 0 +//│ ╙── ^^^^ +//│ 0 | error +//│ res +//│ = 0 + + + diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index 539c23787c..fbbd9ffb3f 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,3 +1,37 @@ :NewDefs + + +declare fun String: nothing +//│ fun String: nothing + +let makeString: anything => { length: Int, charCodeAt: Int => Int } = String +let StringInstance: { fromCharCode: Int => Str } = String +//│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} +//│ let StringInstance: {fromCharCode: Int -> Str} +//│ makeString +//│ = [Function: String] +//│ StringInstance +//│ = [Function: String] + +// * Why do we get below and not above?? + +declare fun String: nothing +let makeString: anything => { length: Int, charCodeAt: Int => Int } = String +let StringInstance: { fromCharCode: Int => Str } = String +//│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} +//│ let StringInstance: {fromCharCode: Int -> Str} +//│ fun String: nothing +//│ makeString +//│ = +//│ StringInstance +//│ = [Function: String] + + + + + + + + diff --git a/shared/src/test/diff/nu/OpLam.mls b/shared/src/test/diff/nu/OpLam.mls new file mode 100644 index 0000000000..c481673bca --- /dev/null +++ b/shared/src/test/diff/nu/OpLam.mls @@ -0,0 +1,89 @@ +:NewDefs + + +x => x is 42 +//│ Object -> Bool +//│ res +//│ = [Function: res] + + +fun (|>;) foo(a, b) = [a, b] +//│ fun (|>;) foo: forall 'a 'b. ('a, 'b) -> ['a, 'b] + +42 |>; x => x +//│ [42, forall 'a. 'a -> 'a] +//│ res +//│ = [ 42, [Function (anonymous)] ] + + +fun (>>) compose(f, g) = x => g(f(x)) +//│ fun (>>) compose: forall 'a 'b 'c. ('a -> 'b, 'b -> 'c) -> 'a -> 'c + +succ >> x => x + 2 +//│ Int -> Int +//│ res +//│ = [Function (anonymous)] + +:e +x => x + 2 >> succ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.28: x => x + 2 >> succ +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── operator application of type `Int` is not a function +//│ ║ l.28: x => x + 2 >> succ +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from application: +//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ ^^^^ +//│ ╟── from reference: +//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ╙── ^ +//│ Int -> (error | Int -> Int) +//│ res +//│ = [Function: res] + +(x => x + 2) >> succ +//│ Int -> Int +//│ res +//│ = [Function (anonymous)] + +:e // FIXME parsing +x => x + 2 + >> succ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.51: x => x + 2 +//│ ║ ^ +//│ ║ l.52: >> succ +//│ ║ ^^^^ +//│ ╟── integer literal of type `2` is not a 2-element tuple +//│ ║ l.51: x => x + 2 +//│ ║ ^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.51: x => x + 2 +//│ ║ ^ +//│ ║ l.52: >> succ +//│ ║ ^^^^^^^^^^ +//│ ╟── reference of type `Int -> Int` is not a 1-element tuple +//│ ║ l.52: >> succ +//│ ╙── ^^^^ +//│ Int -> Int +//│ Code generation encountered an error: +//│ ill-formed application App(App(Var(>>), IntLit(2)), Var(succ)) + + +:e +x => x.y => y +//│ ╔══[ERROR] Unsupported pattern shape: +//│ ║ l.78: x => x.y => y +//│ ╙── ^^^ +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.78: x => x.y => y +//│ ╙── ^ +//│ anything -> error -> error +//│ Code generation encountered an error: +//│ term Sel(Var(x), y) is not a valid pattern + + diff --git a/shared/src/test/diff/parser/Lambdas.mls b/shared/src/test/diff/parser/Lambdas.mls index 90d8a80a64..89240fd873 100644 --- a/shared/src/test/diff/parser/Lambdas.mls +++ b/shared/src/test/diff/parser/Lambdas.mls @@ -113,5 +113,5 @@ id + of x => x + 1 //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position //│ ║ l.111: id + of x => x + 1 //│ ╙── ^^ -//│ Parsed: {(+ (id,) (x,),) => + (x,) (1,)} +//│ Parsed: {+ (id,) ((x,) => + (x,) (1,),)} diff --git a/shared/src/test/diff/parser/Where.mls b/shared/src/test/diff/parser/Where.mls index b41503cf9b..90e4d15342 100644 --- a/shared/src/test/diff/parser/Where.mls +++ b/shared/src/test/diff/parser/Where.mls @@ -13,9 +13,9 @@ a + 1 where let a = 1 fun foo: 'a => 'a => 'a where 'a : int //│ |#fun| |foo|#:| |'a| |=>| |'a| |=>| |'a| |#where| |'a| |#:| |int| -//│ Parsed: {fun foo: 'a -> 'a -> 'a +//│ Parsed: {fun foo: 'a -> 'a -> ('a //│ where -//│ 'a <: int} +//│ 'a <: int)} :e fun foo: 'a + 'a + 'a where 'a : int From a86bc3620111aaaf5f75cc27cd76bab71f9e0669 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 13 Sep 2023 18:23:46 +0800 Subject: [PATCH 438/498] Fix omission and remove needless default argument value --- .../src/main/scala/mlscript/JSBackend.scala | 49 ++++++++++--------- .../main/scala/mlscript/codegen/Scope.scala | 4 +- shared/src/test/diff/codegen/SymbolicOps.mls | 29 ++++++++--- 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index f2ed6cfe24..9bec911ccb 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -396,7 +396,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case Lam(params, body) => val methodScope = scope.derive(s"Method $name") val methodParams = translateParams(params)(methodScope) - methodScope.declareValue("this", Some(false), false) + methodScope.declareValue("this", Some(false), false, N) instance(name) := JSFuncExpr( N, methodParams, @@ -405,7 +405,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Define getters for pure expressions. case term => val getterScope = scope.derive(s"Getter $name") - getterScope.declareValue("this", Some(false), false) + getterScope.declareValue("this", Some(false), false, N) id("Object")("defineProperty")( instance, JSExpr(name), @@ -547,7 +547,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case S(sym: NewClassSymbol) => val localScope = scope.derive(s"local ${sym.lexicalName}") val nd = translateNewTypeDefinition(sym, N, false)(localScope) - val ctorMth = localScope.declareValue("ctor", Some(false), false).runtimeName + val ctorMth = localScope.declareValue("ctor", Some(false), false, N).runtimeName val (constructor, params) = translateNewClassParameters(nd) val initList = if (sym.isPlainJSClass) @@ -564,7 +564,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { )) case S(sym: MixinSymbol) => val localScope = scope.derive(s"local ${sym.lexicalName}") - val base = localScope.declareValue("base", Some(false), false) + val base = localScope.declareValue("base", Some(false), false, N) val nd = translateNewTypeDefinition(sym, S(base), false)(localScope) JSConstDecl(sym.lexicalName, JSArrowFn( Ls(JSNamePattern(base.runtimeName)), R(Ls( @@ -574,7 +574,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case S(sym: ModuleSymbol) => val localScope = scope.derive(s"local ${sym.lexicalName}") val nd = translateNewTypeDefinition(sym, N, false)(localScope) - val ins = localScope.declareValue("ins", Some(false), false).runtimeName + val ins = localScope.declareValue("ins", Some(false), false, N).runtimeName JSConstDecl(sym.lexicalName, JSImmEvalFn( N, Nil, R(Ls( nd, JSLetDecl.from(Ls(ins)), @@ -592,7 +592,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { siblingsMembers: Ls[RuntimeSymbol] )(implicit scope: Scope): JSClassMethod = { val getterScope = scope.derive(s"getter ${mixinSymbol.lexicalName}") - val base = getterScope.declareValue("base", Some(false), false) + val base = getterScope.declareValue("base", Some(false), false, N) val outerSymbol = getterScope.declareOuterSymbol() siblingsMembers.foreach(getterScope.captureSymbol(outerSymbol, _)) @@ -737,10 +737,10 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ctorParams = sym.ctorParams.fold( fields.map { f => memberList += NewClassMemberSymbol(f, Some(false), false).tap(nuTypeScope.register) - constructorScope.declareValue(f, Some(false), false).runtimeName + constructorScope.declareValue(f, Some(false), false, N).runtimeName } )(lst => lst.map { p => - constructorScope.declareValue(p, Some(false), false).runtimeName + constructorScope.declareValue(p, Some(false), false, N).runtimeName }) sym.methods.foreach { @@ -784,7 +784,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } val (superParameters, rest) = if (baseSym.isDefined) { - val rest = constructorScope.declareValue("rest", Some(false), false) + val rest = constructorScope.declareValue("rest", Some(false), false, N) (Ls(JSIdent(s"...${rest.runtimeName}")), S(rest.runtimeName)) } else @@ -799,12 +799,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val stmts = sym.ctor.flatMap { case Eqn(Var(name), rhs) => Ls( JSAssignExpr(JSIdent(s"this.#$name"), translateTerm(rhs)(constructorScope)).stmt, - JSConstDecl(constructorScope.declareValue(name, S(false), false).runtimeName, JSIdent(s"this.#$name")) + JSConstDecl(constructorScope.declareValue(name, S(false), false, N).runtimeName, JSIdent(s"this.#$name")) ) case s: Term => JSExprStmt(translateTerm(s)(constructorScope)) :: Nil case NuFunDef(_, Var(nme), _, _, Left(rhs)) => getters += nme; Ls[JSStmt]( JSExprStmt(JSAssignExpr(JSIdent(s"this.#$nme"), translateTerm(rhs)(constructorScope))), - JSConstDecl(constructorScope.declareValue(nme, S(false), false).runtimeName, JSIdent(s"this.#$nme")) + JSConstDecl(constructorScope.declareValue(nme, S(false), false, N).runtimeName, JSIdent(s"this.#$nme")) ) case _ => Nil } @@ -882,7 +882,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Declare the alias for `this` before declaring parameters. val selfSymbol = memberScope.declareThisAlias() val preDecs = props.map(p => { - val runtime = memberScope.declareValue(p, Some(false), false) + val runtime = memberScope.declareValue(p, Some(false), false, N) JSConstDecl(runtime.runtimeName, JSIdent(s"this.#$p")) }) // Declare parameters. @@ -1104,17 +1104,18 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { // ``` .concat(otherStmts.flatMap { case Def(recursive, Var(name), L(body), isByname) => + val isLam = body.isInstanceOf[Lam] val (originalExpr, sym) = if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) - val sym = topLevelScope.declareValue(name, isByvalueRecIn, body.isInstanceOf[Lam]) + val sym = topLevelScope.declareValue(name, isByvalueRecIn, isLam, N) val translated = translateTerm(body)(topLevelScope) topLevelScope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - (translated, topLevelScope.declareValue(name, isByvalueRecOut, body.isInstanceOf[Lam])) + (translated, topLevelScope.declareValue(name, isByvalueRecOut, isLam, N)) } else { val translatedBody = translateTerm(body)(topLevelScope) val isByvalueRec = if (isByname) None else Some(false) - (translatedBody, topLevelScope.declareValue(name, isByvalueRec, body.isInstanceOf[Lam])) + (translatedBody, topLevelScope.declareValue(name, isByvalueRec, isLam, N)) } val translatedBody = if (sym.isByvalueRec.isEmpty && !sym.isLam) JSArrowFn(Nil, L(originalExpr)) else originalExpr topLevelScope.tempVars `with` JSConstDecl(sym.runtimeName, translatedBody) :: @@ -1143,7 +1144,7 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { // don't pass `otherStmts` to the top-level module, because we need to execute them one by one later val topModule = topLevelScope.declareTopModule("TypingUnit", Nil, typeDefs, true) - val moduleIns = topLevelScope.declareValue("typing_unit", Some(false), false) + val moduleIns = topLevelScope.declareValue("typing_unit", Some(false), false, N) val moduleDecl = translateTopModuleDeclaration(topModule, true)(topLevelScope) val insDecl = JSConstDecl(moduleIns.runtimeName, JSNew(JSIdent(topModule.runtimeName))) @@ -1170,7 +1171,7 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { val isByvalueRecIn = if (isByname) None else Some(true) // TODO Improve: (Lionel) what?! - val sym = topLevelScope.declareValue(name, isByvalueRecIn, bodyIsLam) + val sym = topLevelScope.declareValue(name, isByvalueRecIn, bodyIsLam, N) val translated = translateTerm(body)(topLevelScope) topLevelScope.unregisterSymbol(sym) @@ -1206,7 +1207,7 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { } class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { - private val lastResultSymbol = topLevelScope.declareValue("res", Some(false), false) + private val lastResultSymbol = topLevelScope.declareValue("res", Some(false), false, N) private val resultIdent = JSIdent(lastResultSymbol.runtimeName) private var numRun = 0 @@ -1259,12 +1260,12 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { val bodyIsLam = body match { case _: Lam => true case _ => false } (if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) - val sym = scope.declareValue(name, isByvalueRecIn, bodyIsLam) + val sym = scope.declareValue(name, isByvalueRecIn, bodyIsLam, N) try { val translated = translateTerm(body) scope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - R((translated, scope.declareValue(name, isByvalueRecOut, bodyIsLam))) + R((translated, scope.declareValue(name, isByvalueRecOut, bodyIsLam, N))) } catch { case e: UnimplementedError => scope.stubize(sym, e.symbol) @@ -1272,7 +1273,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case NonFatal(e) => scope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - scope.declareValue(name, isByvalueRecOut, bodyIsLam) + scope.declareValue(name, isByvalueRecOut, bodyIsLam, N) throw e } } else { @@ -1282,7 +1283,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { L(e.getMessage()) }) map { val isByvalueRec = if (isByname) None else Some(false) - expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam)) + expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam, N)) } }) match { case R((originalExpr, sym)) => @@ -1338,7 +1339,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { // don't pass `otherStmts` to the top-level module, because we need to execute them one by one later val topModule = topLevelScope.declareTopModule("TypingUnit", Nil, typeDefs, true) - val moduleIns = topLevelScope.declareValue("typing_unit", Some(false), false) + val moduleIns = topLevelScope.declareValue("typing_unit", Some(false), false, N) val moduleDecl = translateTopModuleDeclaration(topModule, true) val insDecl = JSConstDecl(moduleIns.runtimeName, JSNew(JSIdent(topModule.runtimeName))) @@ -1399,7 +1400,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { L(e.getMessage()) }) map { val isByvalueRec = if (isByname) None else Some(false) - expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam)) + expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam, symb)) } }) match { case R((originalExpr, sym)) => diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 498aa7cbfc..a49b5d963a 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -315,7 +315,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { symbol } - def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean, symbolicName: Opt[Str] = N): ValueSymbol = { + def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean, symbolicName: Opt[Str]): ValueSymbol = { val runtimeName = lexicalValueSymbols.get(lexicalName) match { // If we are implementing a stub symbol and the stub symbol did not shadow any other // symbols, it is safe to reuse its `runtimeName`. @@ -333,7 +333,7 @@ class Scope(name: Str, enclosing: Opt[Scope]) { def declareOuterSymbol(): ValueSymbol = { val lexicalName = "outer" - val symbol = declareValue(lexicalName, Some(false), false) + val symbol = declareValue(lexicalName, Some(false), false, N) outerSymbols += symbol.runtimeName symbol } diff --git a/shared/src/test/diff/codegen/SymbolicOps.mls b/shared/src/test/diff/codegen/SymbolicOps.mls index 0f946dfbde..c2e09605e4 100644 --- a/shared/src/test/diff/codegen/SymbolicOps.mls +++ b/shared/src/test/diff/codegen/SymbolicOps.mls @@ -312,15 +312,32 @@ fun (:-D) dd(a, b) = a + b // should be `:-D`, but we got `:-` -val (-->) f(x, y) = [x, y] -//│ let (-->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] +val (->) f(x, y) = [x, y] +//│ let (->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] //│ f //│ = [Function: f1] -:ge // FIXME -12 --> 34 +12 -> 34 //│ [12, 34] -//│ Code generation encountered an error: -//│ unresolved symbol --> +//│ res +//│ = [ 12, 34 ] + + +let (->) _ = f +//│ let (->) _: forall 'a 'b. ('a, 'b) -> ['a, 'b] +//│ _ +//│ = [Function: f1] + +:js +12 -> 34 +//│ [12, 34] +//│ // Prelude +//│ class TypingUnit42 {} +//│ const typing_unit42 = new TypingUnit42; +//│ // Query 1 +//│ res = _(12, 34); +//│ // End of generated code +//│ res +//│ = [ 12, 34 ] From 1443e6c7668bfad7bbcb38180dfc82e8ab739c4a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 16 Sep 2023 19:15:08 +0800 Subject: [PATCH 439/498] Clean up inadvertently-polluted NuScratch.mls file --- shared/src/test/diff/nu/MissingImplBug.mls | 29 ++++++++++++++++++ shared/src/test/diff/nu/NuScratch.mls | 34 ---------------------- 2 files changed, 29 insertions(+), 34 deletions(-) create mode 100644 shared/src/test/diff/nu/MissingImplBug.mls diff --git a/shared/src/test/diff/nu/MissingImplBug.mls b/shared/src/test/diff/nu/MissingImplBug.mls new file mode 100644 index 0000000000..cc81ccebdf --- /dev/null +++ b/shared/src/test/diff/nu/MissingImplBug.mls @@ -0,0 +1,29 @@ +:NewDefs + + +declare fun String: nothing +//│ fun String: nothing + +let makeString: anything => { length: Int, charCodeAt: Int => Int } = String +let StringInstance: { fromCharCode: Int => Str } = String +//│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} +//│ let StringInstance: {fromCharCode: Int -> Str} +//│ makeString +//│ = [Function: String] +//│ StringInstance +//│ = [Function: String] + +// * Why do we get below and not above?? + +declare fun String: nothing +let makeString: anything => { length: Int, charCodeAt: Int => Int } = String +let StringInstance: { fromCharCode: Int => Str } = String +//│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} +//│ let StringInstance: {fromCharCode: Int -> Str} +//│ fun String: nothing +//│ makeString +//│ = +//│ StringInstance +//│ = [Function: String] + + diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index fbbd9ffb3f..539c23787c 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,37 +1,3 @@ :NewDefs - - -declare fun String: nothing -//│ fun String: nothing - -let makeString: anything => { length: Int, charCodeAt: Int => Int } = String -let StringInstance: { fromCharCode: Int => Str } = String -//│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} -//│ let StringInstance: {fromCharCode: Int -> Str} -//│ makeString -//│ = [Function: String] -//│ StringInstance -//│ = [Function: String] - -// * Why do we get below and not above?? - -declare fun String: nothing -let makeString: anything => { length: Int, charCodeAt: Int => Int } = String -let StringInstance: { fromCharCode: Int => Str } = String -//│ let makeString: anything -> {charCodeAt: Int -> Int, length: Int} -//│ let StringInstance: {fromCharCode: Int -> Str} -//│ fun String: nothing -//│ makeString -//│ = -//│ StringInstance -//│ = [Function: String] - - - - - - - - From 904988a50ddc309ae3d530bf3067f8804f850492 Mon Sep 17 00:00:00 2001 From: "Cunyuan(Holden) Gao" Date: Sat, 16 Sep 2023 19:44:20 +0800 Subject: [PATCH 440/498] Update shared/src/main/scala/mlscript/NuTypeDefs.scala Co-authored-by: Lionel Parreaux --- shared/src/main/scala/mlscript/NuTypeDefs.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 48d00d2883..455105aad5 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -389,9 +389,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => this } - // The field `thisRef` is defined when the member accesses to `this` object without field selection + // Field `thisRef` is defined when the member refers to `this` selecting a field on it // e.g., val x = this - // The field `refs` contains all `Var`s accessed by the member with their qualifiers (None if it is an unqualifier access) + // Field `refs` contains all `Var`s accessed by the member with their possible `this` qualifiers (`None` if it is an unqualified access) case class RefMap(thisRef: Opt[Var], refs: Set[(Var, Opt[Var])]) object RefMap { lazy val nothing: RefMap = RefMap(N, Set.empty) From 2d5c659b191e031a264ba3e1c83b917bb4901c11 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Sun, 17 Sep 2023 10:14:21 +0800 Subject: [PATCH 441/498] Add test case --- shared/src/test/diff/nu/NoThisCtor.mls | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/shared/src/test/diff/nu/NoThisCtor.mls b/shared/src/test/diff/nu/NoThisCtor.mls index daa999f4e3..73d948f978 100644 --- a/shared/src/test/diff/nu/NoThisCtor.mls +++ b/shared/src/test/diff/nu/NoThisCtor.mls @@ -132,3 +132,20 @@ class Bar2() extends Bar() { //│ let d: Int //│ let two: error //│ } + +// it accesses this in an unusual way! +:e +abstract class Foo: Int -> Int { + val x = f + fun f = this(0) +} +//│ ╔══[ERROR] Cannot access `this` while initializing field x +//│ ║ l.139: val x = f +//│ ║ ^^^^^ +//│ ╟── The access to `this` is here +//│ ║ l.140: fun f = this(0) +//│ ╙── ^^^^ +//│ abstract class Foo: Int -> Int { +//│ fun f: nothing +//│ let x: nothing +//│ } From e82b124b097e1e3d284b9e6242d4965ebb6a8c61 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 18 Sep 2023 00:30:17 +0800 Subject: [PATCH 442/498] Minor improvements --- .../src/main/scala/mlscript/JSBackend.scala | 1 + shared/src/main/scala/mlscript/Typer.scala | 9 +- shared/src/main/scala/mlscript/helpers.scala | 21 ++--- .../src/test/diff/codegen/ConstructorStmt.mls | 10 +- .../src/test/diff/codegen/FieldOverride.mls | 10 +- .../test/diff/codegen/MemberInitShadowing.mls | 8 +- shared/src/test/diff/codegen/Mixin.mls | 28 +++--- shared/src/test/diff/codegen/MixinCapture.mls | 4 +- shared/src/test/diff/codegen/Nested.mls | 94 +++++++++---------- shared/src/test/diff/codegen/NuClasses.mls | 4 +- .../src/test/diff/codegen/OptionalParam.mls | 16 ++-- shared/src/test/diff/codegen/ValLet.mls | 12 +-- shared/src/test/diff/fcp-lit/MLF.mls | 2 +- 13 files changed, 109 insertions(+), 110 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 3b4c03c8ae..2fb57f2fc2 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -816,6 +816,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } val staticMethods = sym.unapplyMtd match { + // * Note: this code is a temporary hack until we have proper `unapply` desugaring case S(unapplyMtd) => unapplyMtd.rhs match { case Left(Lam(Tup(_ -> Fld(_, Asc(Var(nme), _)) :: Nil), Tup(fields))) => val unapplyScope = nuTypeScope.derive(s"unapply ${sym.name}") diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index f9ae0a92d1..3ff3110ab3 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -515,12 +515,12 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne } } }) - case tv: TypeVar => vars.getOrElse(tv.identifier.toOption.getOrElse(""), { + case tv: TypeVar => tv.identifier.toOption.flatMap(vars.get).getOrElse { recVars.getOrElse(tv, - localVars.getOrElseUpdate(tv, freshVar(noProv, N, tv.name) + localVars.getOrElseUpdate(tv, freshVar(noProv, N, tv.name.filter(_.exists(_ =/= '\''))) (outerCtxLvl)) // * Type variables not explicily bound are assigned the widest (the outer context's) level ).withProv(tyTp(ty.toLoc, "type variable")) - }) + } case AppliedType(base, targs) => val prov = tyTp(ty.toLoc, "applied type reference") typeNamed(ty.toLoc, base.name) match { @@ -1088,8 +1088,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, var ne case S(ti: DelayedTypeInfo) => ti.decl.genUnapply case _ => N }) match { - case S(NuFunDef(_, _, _, L(unapplyMtd))) => - typePolymorphicTerm(unapplyMtd) + case S(NuFunDef(_, _, _, L(unapplyMtd))) => typePolymorphicTerm(unapplyMtd) case _ => mthCallOrSel(obj, fieldName) } else mthCallOrSel(obj, fieldName) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index d9bea090c9..51e78c17fe 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -438,17 +438,16 @@ trait NuDeclImpl extends Located { self: NuDecl => if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" } lazy val genUnapply: Opt[NuFunDef] = this match { - case td: NuTypeDef if td.kind is Cls => td.params.fold[Opt[NuFunDef]](N)(tup => { - val ret = Tup( - tup.fields.map { - case S(p) -> f => N -> Fld(f.flags, Sel(Var("ins"), p)) - case N -> Fld(flags, p: Var) => N -> Fld(flags, Sel(Var("ins"), p)) - case _ => die - } - ) - S(NuFunDef(N, Var("unapply"), Nil, - L(Lam(Tup(N -> Fld(FldFlags(false, false, false), Asc(Var("ins"), Inter(TypeVar(R("Ins"), N), TypeName(name)))) :: Nil), ret)))(N, N, N, N, true)) - }) + case td: NuTypeDef if td.kind is Cls => td.params.map { tup => + val ret = Tup(tup.fields.map { + case S(p) -> f => N -> Fld(f.flags, Sel(Var("x"), p)) + case N -> Fld(flags, p: Var) => N -> Fld(flags, Sel(Var("x"), p)) + case _ => die + }) + NuFunDef(N, Var("unapply"), Nil, L(Lam( + Tup(N -> Fld(FldFlags(false, false, false), Asc(Var("x"), Inter(TypeVar(R("X"), N), TypeName(name)))) :: Nil), + ret)))(N, N, N, N, true) + } case _ => N } } diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 2116d41dd1..ee3aaf4679 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -79,8 +79,8 @@ class A(a: Int) { //│ log(a); //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#a]; +//│ unapply(x) { +//│ return [x.#a]; //│ } //│ }; //│ this.#A = ((a) => Object.freeze(new A(a))); @@ -238,7 +238,7 @@ class Baz() { //│ ]); //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -300,7 +300,7 @@ class Q() { //│ })()); //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -352,7 +352,7 @@ class W() { //│ return qualifier1.#x + self; //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; diff --git a/shared/src/test/diff/codegen/FieldOverride.mls b/shared/src/test/diff/codegen/FieldOverride.mls index 275861a5e3..84d1dbb883 100644 --- a/shared/src/test/diff/codegen/FieldOverride.mls +++ b/shared/src/test/diff/codegen/FieldOverride.mls @@ -24,8 +24,8 @@ class C(a: Int) { val a = 1 } //│ const a1 = this.#a; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#a]; +//│ unapply(x) { +//│ return [x.#a]; //│ } //│ }; //│ this.#C = ((a) => Object.freeze(new C(a))); @@ -80,10 +80,10 @@ class C2(a: Int, b: Int) { //│ const b1 = this.#b; //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return ([ -//│ ins.#a, -//│ ins.#b +//│ x.#a, +//│ x.#b //│ ]); //│ } //│ }; diff --git a/shared/src/test/diff/codegen/MemberInitShadowing.mls b/shared/src/test/diff/codegen/MemberInitShadowing.mls index df22e95204..ccd40adc76 100644 --- a/shared/src/test/diff/codegen/MemberInitShadowing.mls +++ b/shared/src/test/diff/codegen/MemberInitShadowing.mls @@ -32,8 +32,8 @@ class A(x0: Int) { //│ log(x11); //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x0]; +//│ unapply(x) { +//│ return [x.#x0]; //│ } //│ }; //│ this.#A = ((x0) => Object.freeze(new A(x0))); @@ -86,8 +86,8 @@ class A(x0: Int) { //│ log(x11); //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x0]; +//│ unapply(x) { +//│ return [x.#x0]; //│ } //│ }; //│ this.#A = ((x0) => Object.freeze(new A(x0))); diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index beb4047052..6ea6050b69 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -25,10 +25,10 @@ class Lit(n: Int) //│ this.#rhs = rhs; //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return ([ -//│ ins.#lhs, -//│ ins.#rhs +//│ x.#lhs, +//│ x.#rhs //│ ]); //│ } //│ }; @@ -47,8 +47,8 @@ class Lit(n: Int) //│ this.#n = n; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#n]; +//│ unapply(x) { +//│ return [x.#n]; //│ } //│ }; //│ this.#Lit = ((n) => Object.freeze(new Lit(n))); @@ -82,10 +82,10 @@ class Lit(n: Int) //│ │ │ this.#rhs = rhs; //│ │ │ } //│ │ │ static -//│ │ │ unapply(ins) { +//│ │ │ unapply(x) { //│ │ │ return ([ -//│ │ │ ins.#lhs, -//│ │ │ ins.#rhs +//│ │ │ x.#lhs, +//│ │ │ x.#rhs //│ │ │ ]); //│ │ │ } //│ │ │ }; @@ -104,8 +104,8 @@ class Lit(n: Int) //│ │ │ this.#n = n; //│ │ │ } //│ │ │ static -//│ │ │ unapply(ins) { -//│ │ │ return [ins.#n]; +//│ │ │ unapply(x) { +//│ │ │ return [x.#n]; //│ │ │ } //│ │ │ }; //│ │ │ this.#Lit = ((n) => Object.freeze(new Lit(n))); @@ -216,8 +216,8 @@ class Neg(expr: A) //│ this.#expr = expr; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#expr]; +//│ unapply(x) { +//│ return [x.#expr]; //│ } //│ }; //│ this.#Neg = ((expr) => Object.freeze(new Neg(expr))); @@ -246,8 +246,8 @@ class Neg(expr: A) //│ │ │ this.#expr = expr; //│ │ │ } //│ │ │ static -//│ │ │ unapply(ins) { -//│ │ │ return [ins.#expr]; +//│ │ │ unapply(x) { +//│ │ │ return [x.#expr]; //│ │ │ } //│ │ │ }; //│ │ │ this.#Neg = ((expr) => Object.freeze(new Neg(expr))); diff --git a/shared/src/test/diff/codegen/MixinCapture.mls b/shared/src/test/diff/codegen/MixinCapture.mls index 93ff0603b7..cf721dcf60 100644 --- a/shared/src/test/diff/codegen/MixinCapture.mls +++ b/shared/src/test/diff/codegen/MixinCapture.mls @@ -42,8 +42,8 @@ mixin EvalAddLit { //│ this.#n = n; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#n]; +//│ unapply(x) { +//│ return [x.#n]; //│ } //│ }; //│ this.#Lit = ((n) => Object.freeze(new Lit(n))); diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 8fa9d71cc2..5291381195 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -44,8 +44,8 @@ module A { //│ return x + 1; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#B = ((x) => Object.freeze(new B(x))); @@ -211,8 +211,8 @@ module D { //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#E = ((x) => Object.freeze(new E(x))); @@ -307,8 +307,8 @@ class E(x: Int) { //│ return qualifier1.#x + qualifier2.#y + z; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#z]; +//│ unapply(x) { +//│ return [x.#z]; //│ } //│ }; //│ this.#G = ((z) => Object.freeze(new G(z))); @@ -318,8 +318,8 @@ class E(x: Int) { //│ return this.#G; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#y]; +//│ unapply(x) { +//│ return [x.#y]; //│ } //│ }; //│ this.#F = ((y) => Object.freeze(new F(y))); @@ -329,8 +329,8 @@ class E(x: Int) { //│ return this.#F; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#E = ((x) => Object.freeze(new E(x))); @@ -414,7 +414,7 @@ class F() { //│ const x1 = qualifier1.#x + 1; //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -425,7 +425,7 @@ class F() { //│ return this.#G; //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -496,8 +496,8 @@ module G { //│ return qualifier1.I(x + a); //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#J = ((x) => Object.freeze(new J(x))); @@ -522,8 +522,8 @@ module G { //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#I = ((x) => Object.freeze(new I(x))); @@ -608,8 +608,8 @@ module H { //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#I = ((x) => Object.freeze(new I(x))); @@ -631,8 +631,8 @@ module H { //│ const i = this.#i; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#J = ((x) => Object.freeze(new J(x))); @@ -732,8 +732,8 @@ ij.incY //│ return qualifier2.#y + 1; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#J = ((x) => Object.freeze(new J(x))); @@ -743,8 +743,8 @@ ij.incY //│ return this.#J; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#I = ((x) => Object.freeze(new I(x))); @@ -815,8 +815,8 @@ module J { //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#K = ((x) => Object.freeze(new K(x))); @@ -833,7 +833,7 @@ module J { //│ super(1); //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -853,8 +853,8 @@ module J { //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#N = ((x) => Object.freeze(new N(x))); @@ -1036,7 +1036,7 @@ M.N.op(M.P()) //│ constructor() { //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -1053,7 +1053,7 @@ M.N.op(M.P()) //│ constructor() { //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -1119,7 +1119,7 @@ module N { //│ super(); //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -1142,7 +1142,7 @@ module N { //│ constructor() { //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -1225,8 +1225,8 @@ I(1).J(3).a //│ const a = this.#a; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#z]; +//│ unapply(x) { +//│ return [x.#z]; //│ } //│ }; //│ this.#J = ((z) => Object.freeze(new J(z))); @@ -1236,8 +1236,8 @@ I(1).J(3).a //│ return this.#J; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#I = ((x) => Object.freeze(new I(x))); @@ -1297,8 +1297,8 @@ fun mian = //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ } //│ let ctor; @@ -1353,8 +1353,8 @@ fun mian = //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ } //│ let ctor; @@ -1411,8 +1411,8 @@ fun main(arg) = //│ ]); //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#u]; +//│ unapply(x) { +//│ return [x.#u]; //│ } //│ } //│ let ctor; @@ -1475,8 +1475,8 @@ class Outer1(outer: Int) { //│ const outer = x + 1; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#Outer2 = ((x) => Object.freeze(new Outer2(x))); @@ -1486,8 +1486,8 @@ class Outer1(outer: Int) { //│ return this.#Outer2; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#outer]; +//│ unapply(x) { +//│ return [x.#outer]; //│ } //│ }; //│ this.#Outer1 = ((outer) => Object.freeze(new Outer1(outer))); diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index 5a7a907de0..8993e3a756 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -27,8 +27,8 @@ class Test(val n: Int) { //│ return qualifier.Test(n + 1); //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#n]; +//│ unapply(x) { +//│ return [x.#n]; //│ } //│ }; //│ this.#Test = ((n) => Object.freeze(new Test(n))); diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/OptionalParam.mls index f187e05c55..25a2ce400e 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/OptionalParam.mls @@ -19,8 +19,8 @@ class A(x: Int) {} //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#A = ((x) => Object.freeze(new A(x))); @@ -118,8 +118,8 @@ class D(val x: Int) { //│ log(x); //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#D = ((x) => Object.freeze(new D(x))); @@ -194,8 +194,8 @@ class H extends B {} //│ this.#x = x; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x]; +//│ unapply(x) { +//│ return [x.#x]; //│ } //│ }; //│ this.#F = ((x) => Object.freeze(new F(x))); @@ -366,8 +366,8 @@ fun g(x: Int) = //│ return x + y; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#y]; +//│ unapply(x) { +//│ return [x.#y]; //│ } //│ } //│ let ctor; diff --git a/shared/src/test/diff/codegen/ValLet.mls b/shared/src/test/diff/codegen/ValLet.mls index a2ddb52ead..891f084edb 100644 --- a/shared/src/test/diff/codegen/ValLet.mls +++ b/shared/src/test/diff/codegen/ValLet.mls @@ -42,8 +42,8 @@ class A(x0: Int) { //│ const x3 = this.#x3; //│ } //│ static -//│ unapply(ins) { -//│ return [ins.#x0]; +//│ unapply(x) { +//│ return [x.#x0]; //│ } //│ }; //│ this.#A = ((x0) => Object.freeze(new A(x0))); @@ -107,7 +107,7 @@ AA().f(0) //│ return qualifier1.#x + y; //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return []; //│ } //│ }; @@ -146,10 +146,10 @@ class B(x: Int, val y: Int) //│ this.#y = y; //│ } //│ static -//│ unapply(ins) { +//│ unapply(x) { //│ return ([ -//│ ins.#x, -//│ ins.#y +//│ x.#x, +//│ x.#y //│ ]); //│ } //│ }; diff --git a/shared/src/test/diff/fcp-lit/MLF.mls b/shared/src/test/diff/fcp-lit/MLF.mls index ac0f84223b..6cefd4e767 100644 --- a/shared/src/test/diff/fcp-lit/MLF.mls +++ b/shared/src/test/diff/fcp-lit/MLF.mls @@ -331,7 +331,7 @@ v = packed_int (fun p -> (snd p) ( fst p )) def a: ' -> ' -//│ a: ' -> ' +//│ a: 'a -> 'a From 57b42210e3f462e4daba46b890c1bfddb21340e9 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 18 Sep 2023 00:53:48 +0800 Subject: [PATCH 443/498] Slightly improve the logic of the `unapply` hack --- shared/src/main/scala/mlscript/JSBackend.scala | 4 ++-- shared/src/main/scala/mlscript/helpers.scala | 6 +++--- shared/src/test/diff/codegen/NewMatching.mls | 3 +-- shared/src/test/diff/nu/TODO_Classes.mls | 6 +++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 2fb57f2fc2..9f40993b55 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -816,9 +816,9 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } val staticMethods = sym.unapplyMtd match { - // * Note: this code is a temporary hack until we have proper `unapply` desugaring + // * Note: this code is a bad temporary hack until we have proper `unapply` desugaring case S(unapplyMtd) => unapplyMtd.rhs match { - case Left(Lam(Tup(_ -> Fld(_, Asc(Var(nme), _)) :: Nil), Tup(fields))) => + case Left(Lam(Tup(_ -> Fld(_, Var(nme)) :: Nil), Let(_, _, _, Tup(fields)))) => val unapplyScope = nuTypeScope.derive(s"unapply ${sym.name}") val ins = unapplyScope.declareParameter(nme) JSClassMethod("unapply", JSNamePattern(ins) :: Nil, L(JSArray(fields.map { diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 51e78c17fe..bb7e342265 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -439,13 +439,13 @@ trait NuDeclImpl extends Located { self: NuDecl => } lazy val genUnapply: Opt[NuFunDef] = this match { case td: NuTypeDef if td.kind is Cls => td.params.map { tup => - val ret = Tup(tup.fields.map { + val ret = Let(false, Var("_"), Asc(Var("x"), TypeName(name)), Tup(tup.fields.map { case S(p) -> f => N -> Fld(f.flags, Sel(Var("x"), p)) case N -> Fld(flags, p: Var) => N -> Fld(flags, Sel(Var("x"), p)) case _ => die - }) + })) NuFunDef(N, Var("unapply"), Nil, L(Lam( - Tup(N -> Fld(FldFlags(false, false, false), Asc(Var("x"), Inter(TypeVar(R("X"), N), TypeName(name)))) :: Nil), + Tup(N -> Fld(FldFlags(false, false, false), Var("x")) :: Nil), ret)))(N, N, N, N, true) } case _ => N diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index 35a0254028..30243e2a23 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -278,9 +278,8 @@ fun c(x) = class C[A](f: A -> A) //│ class C[A](f: A -> A) -// TODO simplify type more let r = C.unapply -//│ let r: forall 'f. (C[?] & {f: 'f} | C[?] & ~#C) -> ['f] +//│ let r: forall 'f. (C[?] & {f: 'f}) -> ['f] //│ r //│ = [Function: unapply] diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index dcf7f53ecc..e899bf1558 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -72,7 +72,7 @@ class D(x: Int) //│ class D(x: Int) D.unapply -//│ forall 'x. (D & {x: 'x} | D & ~#D) -> ['x] +//│ forall 'x. (D & {x: 'x}) -> ['x] //│ res //│ = [Function: unapply] @@ -97,7 +97,7 @@ D.unapply({ x: 42 }) class DT[T](x: T) DT.unapply //│ class DT[T](x: T) -//│ forall 'x. (DT[anything] & {x: 'x} | DT[anything] & ~#DT) -> ['x] +//│ forall 'x. (DT[anything] & {x: 'x}) -> ['x] //│ res //│ = [Function: unapply] @@ -114,7 +114,7 @@ DT.unapply({ x: 42 }) //│ ╟── record literal of type `{x: 42}` is not an instance of type `DT` //│ ║ l.110: DT.unapply({ x: 42 }) //│ ╙── ^^ -//│ error | [42 & ??T] +//│ error | [42] //│ res //│ Runtime error: //│ TypeError: Cannot read private member #x from an object whose class did not declare it From ebdf44ceceadb2426fb38f52c8c342b276199b48 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 19 Sep 2023 11:46:22 +0800 Subject: [PATCH 444/498] Improve internal pretty-printing of tuples and type defs --- compiler/shared/test/diff/LiftType.mls | 42 ++-- compiler/shared/test/diff/Lifter.mls | 230 +++++++++--------- compiler/shared/test/diff/LifterBlks.mls | 116 +++++---- shared/src/main/scala/mlscript/helpers.scala | 35 ++- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/basics/Blocks.fun | 20 +- shared/src/test/diff/basics/Data.fun | 4 +- shared/src/test/diff/basics/Datatypes.fun | 8 +- shared/src/test/diff/basics/Either.fun | 6 +- shared/src/test/diff/basics/Flow.fun | 2 +- shared/src/test/diff/basics/Operators.fun | 28 +-- shared/src/test/diff/basics/Slashes.fun | 4 +- shared/src/test/diff/basics/Tuples.fun | 4 +- .../src/test/diff/mlscript/ByNameByValue.mls | 8 +- shared/src/test/diff/mlscript/MultiArgs.mls | 12 +- shared/src/test/diff/mlscript/Ops.mls | 20 +- shared/src/test/diff/nu/OverrideShorthand.mls | 2 +- shared/src/test/diff/parser/Arrays.mls | 34 +-- shared/src/test/diff/parser/BasicSyntax.mls | 104 ++++---- shared/src/test/diff/parser/Binds.mls | 4 +- shared/src/test/diff/parser/Blocks.mls | 28 +-- shared/src/test/diff/parser/Brackets.mls | 12 +- shared/src/test/diff/parser/Classes.mls | 36 +-- shared/src/test/diff/parser/Comments.mls | 2 +- .../diff/parser/ControversialIfSplits.mls | 8 +- shared/src/test/diff/parser/Forall.mls | 2 +- shared/src/test/diff/parser/Fun.mls | 20 +- shared/src/test/diff/parser/IfThenElse.mls | 64 ++--- shared/src/test/diff/parser/Lambdas.mls | 12 +- shared/src/test/diff/parser/Lets.mls | 2 +- shared/src/test/diff/parser/Misc.mls | 14 +- .../src/test/diff/parser/MultiLineCalls.mls | 32 +-- shared/src/test/diff/parser/MultilineFun.mls | 6 +- shared/src/test/diff/parser/NamedArrays.mls | 50 ++-- shared/src/test/diff/parser/NegativeLits.mls | 4 +- shared/src/test/diff/parser/New.mls | 16 +- shared/src/test/diff/parser/Ops.mls | 58 ++--- shared/src/test/diff/parser/Select.mls | 54 ++-- shared/src/test/diff/parser/SpecParams.mls | 6 +- shared/src/test/diff/parser/Subscripts.mls | 24 +- shared/src/test/diff/parser/TypeParams.mls | 36 +-- .../test/diff/parser/UserDefinedOpsMaybe.mls | 8 +- shared/src/test/diff/parser/WeirdIfs.mls | 6 +- shared/src/test/diff/parser/Where.mls | 6 +- shared/src/test/diff/parser/Whitespace.mls | 6 +- shared/src/test/diff/parser/boolops.mls | 14 +- shared/src/test/diff/ucs/Exhaustiveness.mls | 2 +- shared/src/test/diff/ucs/LeadingAnd.mls | 4 +- shared/src/test/diff/ucs/SimpleUCS.mls | 2 +- shared/src/test/diff/ucs/SplitAfterOp.mls | 18 +- shared/src/test/diff/ucs/SplitAnd.mls | 4 +- shared/src/test/diff/ucs/SplitBeforeOp.mls | 2 +- shared/src/test/diff/ucs/SplitOps.mls | 8 +- shared/src/test/diff/ucs/TrivialIf.mls | 4 +- shared/src/test/diff/ucs/WeirdIf.mls | 2 +- ts2mls/js/src/test/diff/Dec.d.mls | 2 +- ts2mls/js/src/test/diff/Heritage.d.mls | 2 +- ts2mls/js/src/test/diff/MultiFiles.d.mls | 2 +- ts2mls/js/src/test/diff/Namespace.d.mls | 2 +- ts2mls/js/src/test/diff/Overload.d.mls | 2 +- ts2mls/js/src/test/diff/Type.d.mls | 2 +- ts2mls/js/src/test/diff/Variables.d.mls | 2 +- 62 files changed, 640 insertions(+), 631 deletions(-) diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index f6dcc38185..f56e9fdd14 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -6,14 +6,14 @@ class CTX{ fun foo(f: A => A): (A => A) => A = f(new A) } //│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |=>| |A|)|#:| |(|A| |=>| |A|)| |=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| -//│ Parsed: {class CTX() {class A() {}; fun foo = (f: (A,) => A,) => f (new A() {},) : (A -> A) -> A}} +//│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A([]) {},) : (A -> A) -> A}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),)), TypingUnit(List())))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit(List())))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2(par$CTX$1,) {} -//│ class CTX$1() { -//│ fun foo = (f: (CTX$1_A$2,) => CTX$1_A$2,) => f (new CTX$1_A$2(this,) {},) : (CTX$1_A$2 -> CTX$1_A$2) -> CTX$1_A$2 +//│ class CTX$1_A$2([par$CTX$1,]) {} +//│ class CTX$1([]) { +//│ fun foo = (f: (CTX$1_A$2,) => CTX$1_A$2,) => f(new CTX$1_A$2([this,]) {},) : (CTX$1_A$2 -> CTX$1_A$2) -> CTX$1_A$2 //│ } //│ } //│ @@ -24,15 +24,15 @@ class CTX(x, y){ fun foo(any: (A, B)): (B, A) = (any._2, any._1) } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |(|A|,| |B|)|)|#:| |(|B|,| |A|)| |#=| |(|any|._2|,| |any|._1|)|←|↵|}| -//│ Parsed: {class CTX(x, y,) {class A() {fun foo = x}; class B(): A {fun foo = y}; fun foo = (any: '(' A, B, ')',) => '(' (any)._2, (any)._1, ')' : [B, A]}} +//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '(' [A, B,] ')',) => '(' [(any)._2, (any)._1,] ')' : [B, A]}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2(par$CTX$1,) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3(par$CTX$1,) {fun foo = ((this).par$CTX$1).y} -//│ class CTX$1(x, y,) { -//│ fun foo = (any: '(' CTX$1_A$2, CTX$1_B$3, ')',) => '(' (any)._2, (any)._1, ')' : [CTX$1_B$3, CTX$1_A$2] +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} +//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1([x, y,]) { +//│ fun foo = (any: '(' [CTX$1_A$2, CTX$1_B$3,] ')',) => '(' [(any)._2, (any)._1,] ')' : [CTX$1_B$3, CTX$1_A$2] //│ } //│ } //│ @@ -43,15 +43,15 @@ class CTX(x, y){ fun foo(any: {p1: A, p2: B}): (B, A) = (any.p2, any.p1) } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |{|p1|#:| |A|,| |p2|#:| |B|}|)|#:| |(|B|,| |A|)| |#=| |(|any|.p2|,| |any|.p1|)|←|↵|}| -//│ Parsed: {class CTX(x, y,) {class A() {fun foo = x}; class B(): A {fun foo = y}; fun foo = (any: '{' {p1: A, p2: B} '}',) => '(' (any).p2, (any).p1, ')' : [B, A]}} +//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '{' {p1: A, p2: B} '}',) => '(' [(any).p2, (any).p1,] ')' : [B, A]}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2(par$CTX$1,) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3(par$CTX$1,) {fun foo = ((this).par$CTX$1).y} -//│ class CTX$1(x, y,) { -//│ fun foo = (any: '{' {p1: CTX$1_A$2, p2: CTX$1_B$3} '}',) => '(' (any).p2, (any).p1, ')' : [CTX$1_B$3, CTX$1_A$2] +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} +//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1([x, y,]) { +//│ fun foo = (any: '{' {p1: CTX$1_A$2, p2: CTX$1_B$3} '}',) => '(' [(any).p2, (any).p1,] ')' : [CTX$1_B$3, CTX$1_A$2] //│ } //│ } //│ @@ -62,15 +62,15 @@ class CTX(x, y){ fun foo(any: (A, B)): ((B, A), A) = (any, any._1) } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|‹|T|›| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |(|A|,| |B|‹|A|›|)|)|#:| |(|(|B|‹|A|›|,| |A|)|,| |A|)| |#=| |(|any|,| |any|._1|)|←|↵|}| -//│ Parsed: {class CTX(x, y,) {class A() {fun foo = x}; class B‹T›() {fun foo = y}; fun foo = (any: '(' A, B‹A›, ')',) => '(' any, (any)._1, ')' : [[B[A], A], A]}} +//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B‹T› {fun foo = y}; fun foo = (any: '(' [A, B‹A›,] ')',) => '(' [any, (any)._1,] ')' : [[B[A], A], A]}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A)))))), Asc(Bra(rcd = false, Tup(_: Var(any), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2(par$CTX$1,) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3[T](par$CTX$1,) {fun foo = ((this).par$CTX$1).y} -//│ class CTX$1(x, y,) { -//│ fun foo = (any: '(' CTX$1_A$2, CTX$1_B$3‹CTX$1_A$2›, ')',) => '(' any, (any)._1, ')' : [[CTX$1_B$3[CTX$1_A$2], CTX$1_A$2], CTX$1_A$2] +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} +//│ class CTX$1_B$3[T]([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1([x, y,]) { +//│ fun foo = (any: '(' [CTX$1_A$2, CTX$1_B$3‹CTX$1_A$2›,] ')',) => '(' [any, (any)._1,] ')' : [[CTX$1_B$3[CTX$1_A$2], CTX$1_A$2], CTX$1_A$2] //│ } //│ } //│ @@ -84,7 +84,7 @@ class CTX{ (new CTX).bar } //│ |#class| |CTX|{|→|#fun| |ctx|(|x|,|y|)| |#=| |→|#class| |A|{| |#fun| |foo| |#=| |x| |}|↵|#fun| |bar|‹|T|›|(|any|#:| |T|)|#:| |A| |#=| |→|#let| |x| |#=| |#new| |T|↵|#new| |A|←|↵|(|#new| |CTX|)|.bar|‹|CTX|›|←|←|↵|}| -//│ Parsed: {class CTX() {fun ctx = (x, y,) => {class A() {fun foo = x}; fun bar = (any: T,) => {let x = new T() {}; new A() {}} : A; ('(' new CTX() {} ')').bar‹CTX›}}} +//│ Parsed: {class CTX {fun ctx = (x, y,) => {class A {fun foo = x}; fun bar = (any: T,) => {let x = new T([]) {}; new A([]) {}} : A; ('(' new CTX([]) {} ')').bar‹CTX›}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, ctx, None, [], Lam(Tup(_: Var(x), _: Var(y)), Blk(...)))))) //│ Lifted: diff --git a/compiler/shared/test/diff/Lifter.mls b/compiler/shared/test/diff/Lifter.mls index 0d4b717ab9..be5fc34a14 100644 --- a/compiler/shared/test/diff/Lifter.mls +++ b/compiler/shared/test/diff/Lifter.mls @@ -26,34 +26,34 @@ class A(x) { fun getA = A(x) } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getB1| |#=| |B1|(|y|)|↵|#class| |C|(|z|)| |{|→|#fun| |inc|(||)| |#=| |x| |+| |1|↵|#fun| |getY| |#=| |y|↵|#fun| |getA| |#=| |A|(|z|)|↵|#fun| |getB|(|w|)| |#=| |B|(|w|)|↵|#fun| |getC| |#=| |#new| |C|(|inc|(||)|)|↵|#fun| |getSelf| |#=| |this|←|↵|}|←|↵|}|↵|#class| |B1|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getY| |#=| |y|↵|#fun| |getB| |#=| |#new| |B|(|y|)|↵|#fun| |getB1| |#=| |#new| |B1|(|y|)|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|(|x|)|↵|#fun| |getB2|(|y|)| |#=| |B1|(|y|)|↵|#fun| |getB3|(|z|)| |#=| |getB2|(|z|)|↵|#fun| |getA| |#=| |A|(|x|)|←|↵|}| -//│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1 (y,); class C(z,) {fun inc = () => + (x, 1,); fun getY = y; fun getA = A (z,); fun getB = (w,) => B (w,); fun getC = new C(inc (),) {}; fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = new B(y,) {}; fun getB1 = new B1(y,) {}}; fun getB = new B(x,) {}; fun getB2 = (y,) => B1 (y,); fun getB3 = (z,) => getB2 (z,); fun getA = A (x,)}} +//│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1(y,); class C(z,) {fun inc = () => +(x, 1,); fun getY = y; fun getA = A(z,); fun getB = (w,) => B(w,); fun getC = new C([inc(),]) {}; fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = new B([y,]) {}; fun getB1 = new B1([y,]) {}}; fun getB = new B([x,]) {}; fun getB2 = (y,) => B1(y,); fun getB3 = (z,) => getB2(z,); fun getA = A(x,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),inc (),)), TypingUnit(List()))), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),y,)), TypingUnit(List()))), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),y,)), TypingUnit(List()))))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),x,)), TypingUnit(List()))), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), TypingUnit(List()))), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), TypingUnit(List()))), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), TypingUnit(List()))))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), TypingUnit(List()))), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2_C$4(par$A$1_B$2, z,) { -//│ fun inc = () => + ((((this).par$A$1_B$2).par$A$1).x, 1,) +//│ class A$1_B$2_C$4([par$A$1_B$2, z,]) { +//│ fun inc = () => +((((this).par$A$1_B$2).par$A$1).x, 1,) //│ fun getY = ((this).par$A$1_B$2).y -//│ fun getA = A$1 ((this).z,) -//│ fun getB = (w,) => A$1_B$2 (((this).par$A$1_B$2).par$A$1, w,) -//│ fun getC = new A$1_B$2_C$4((this).par$A$1_B$2, (this).inc (),) {} +//│ fun getA = A$1((this).z,) +//│ fun getB = (w,) => A$1_B$2(((this).par$A$1_B$2).par$A$1, w,) +//│ fun getC = new A$1_B$2_C$4([(this).par$A$1_B$2, (this).inc(),]) {} //│ fun getSelf = this //│ } -//│ class A$1_B$2(par$A$1, y,) { +//│ class A$1_B$2([par$A$1, y,]) { //│ fun getX = ((this).par$A$1).x -//│ fun getB1 = A$1_B1$3 ((this).par$A$1, (this).y,) +//│ fun getB1 = A$1_B1$3((this).par$A$1, (this).y,) //│ } -//│ class A$1_B1$3(par$A$1, y,) { +//│ class A$1_B1$3([par$A$1, y,]) { //│ fun getX = ((this).par$A$1).x //│ fun getY = (this).y -//│ fun getB = new A$1_B$2((this).par$A$1, (this).y,) {} -//│ fun getB1 = new A$1_B1$3((this).par$A$1, (this).y,) {} +//│ fun getB = new A$1_B$2([(this).par$A$1, (this).y,]) {} +//│ fun getB1 = new A$1_B1$3([(this).par$A$1, (this).y,]) {} //│ } -//│ class A$1(x,) { -//│ fun getB = new A$1_B$2(this, (this).x,) {} -//│ fun getB2 = (y,) => A$1_B1$3 (this, y,) -//│ fun getB3 = (z,) => (this).getB2 (z,) -//│ fun getA = A$1 ((this).x,) +//│ class A$1([x,]) { +//│ fun getB = new A$1_B$2([this, (this).x,]) {} +//│ fun getB2 = (y,) => A$1_B1$3(this, y,) +//│ fun getB3 = (z,) => (this).getB2(z,) +//│ fun getA = A$1((this).x,) //│ } //│ } //│ @@ -66,16 +66,16 @@ class A(x) { } } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#class| |C|(|z|)| |{|→|#fun| |sum| |#=| |x| |+| |y| |+| |z|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A(x,) {class B(y,) {class C(z,) {fun sum = + (+ (x, y,), z,)}}}} +//│ Parsed: {class A(x,) {class B(y,) {class C(z,) {fun sum = +(+(x, y,), z,)}}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, sum, None, [], App(Var(+), Tup(_: App(Var(+), Tup(_: Var(x), _: Var(y))), _: Var(z))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2_C$3(par$A$1_B$2, z,) { -//│ fun sum = + (+ ((((this).par$A$1_B$2).par$A$1).x, ((this).par$A$1_B$2).y,), (this).z,) +//│ class A$1_B$2_C$3([par$A$1_B$2, z,]) { +//│ fun sum = +(+((((this).par$A$1_B$2).par$A$1).x, ((this).par$A$1_B$2).y,), (this).z,) //│ } -//│ class A$1_B$2(par$A$1, y,) {} -//│ class A$1(x,) {} +//│ class A$1_B$2([par$A$1, y,]) {} +//│ class A$1([x,]) {} //│ } //│ @@ -106,9 +106,9 @@ new C{ fun bar = 17 } //│ |#class| |A|(|x|)| |{|→|#class| |B|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |11|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |2|↵|#fun| |bar| |#=| |12|←|↵|}|↵|#fun| |bar| |#=| |13|←|↵|}|↵|#class| |C|#:| |A|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |3|↵|#fun| |bar| |#=| |14|←|↵|}|↵|#fun| |bar| |#=| |15|←|↵|}|↵|#new| |C|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |4|↵|#fun| |bar| |#=| |16|←|↵|}|↵|#fun| |bar| |#=| |17|←|↵|}| -//│ Parsed: {class A(x,) {class B() {fun foo = 1; fun bar = 11}; fun getB = new B() {fun foo = 2; fun bar = 12}; fun bar = 13}; class C(): A {fun getB = new B() {fun foo = 3; fun bar = 14}; fun bar = 15}; new C() {fun getB = new B() {fun foo = 4; fun bar = 16}; fun bar = 17}} +//│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B([]) {fun foo = 2; fun bar = 12}; fun bar = 13}; class C: A {fun getB = new B([]) {fun foo = 3; fun bar = 14}; fun bar = 15}; new C([]) {fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),)), TypingUnit(List(fun foo = 2, fun bar = 12)))), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),)), TypingUnit(List(fun foo = 3, fun bar = 14)))), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),)), TypingUnit(List(fun getB = new B() {fun foo = 4; fun bar = 16}, fun bar = 17)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(List(fun foo = 2, fun bar = 12)))), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(List(fun foo = 3, fun bar = 14)))), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), TypingUnit(List(fun getB = new B([]) {fun foo = 4; fun bar = 16}, fun bar = 17)))) //│ Lifted: //│ Lifting failed: java.util.NoSuchElementException: None.get //│ @@ -123,16 +123,16 @@ class Parent(x) { } } //│ |#class| |Parent|‹|T|,| |U|,| |V|›|(|x|)| |{| |→|#fun| |foo|(|x|#:| |Int|)|#:| |T| |#=| |x|+|1|↵|#class| |Inner|‹|W|›|(|y|#:| |Int|)|{|→|#fun| |bar|(|z|#:| |U|)| |#=| |foo|(|y|)|↵|#fun| |boo|(|z|#:| |W|)| |#=| |z|←|↵|}|←|↵|}| -//│ Parsed: {class Parent‹T, U, V›(x,) {fun foo = (x: Int,) => + (x, 1,) : T; class Inner‹W›(y: Int,) {fun bar = (z: U,) => foo (y,); fun boo = (z: W,) => z}}} +//│ Parsed: {class Parent‹T, U, V›(x,) {fun foo = (x: Int,) => +(x, 1,) : T; class Inner‹W›(y: Int,) {fun bar = (z: U,) => foo(y,); fun boo = (z: W,) => z}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, Parent, ((None,TypeName(T)), (None,TypeName(U)), (None,TypeName(V))), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(x: Var(Int)), Asc(App(Var(+), Tup(_: Var(x), _: IntLit(1))), TypeName(T)))), NuTypeDef(class, Inner, ((None,TypeName(W))), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(z: Var(U)), App(Var(foo), Tup(_: Var(y))))), NuFunDef(None, boo, None, [], Lam(Tup(z: Var(W)), Var(z)))))))) //│ Lifted: //│ TypingUnit { -//│ class Parent$1_Inner$2[W,U](par$Parent$1, y: Int,) { -//│ fun bar = (z: U,) => ((this).par$Parent$1).foo ((this).y,) +//│ class Parent$1_Inner$2[W,U]([par$Parent$1, y: Int,]) { +//│ fun bar = (z: U,) => ((this).par$Parent$1).foo((this).y,) //│ fun boo = (z: W,) => z //│ } -//│ class Parent$1[T,U,V](x,) {fun foo = (x: Int,) => + (x, 1,) : T} +//│ class Parent$1[T,U,V]([x,]) {fun foo = (x: Int,) => +(x, 1,) : T} //│ } //│ @@ -146,16 +146,16 @@ class A(x: Int): {a1: Int} & B & D(x){ } } //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| -//│ Parsed: {class B‹T›() {}; class C() {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C() {fun foo = (x: T,) => x}}} +//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C([]) {fun foo = (x: T,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = (x: T,) => x)))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(List(fun foo = (x: T,) => x)))))))) //│ Lifted: //│ TypingUnit { -//│ class B$1[T]() {} -//│ class C$2() {} -//│ class D$3(y: Int,) {} -//│ class A$4_C$1$5[T](par$A$4,): C$2 () {fun foo = (x: T,) => x} -//│ class A$4[T,U](x: Int,) {fun getA = () => {new A$4_C$1$5(this,) {}}} +//│ class B$1[T]([]) {} +//│ class C$2([]) {} +//│ class D$3([y: Int,]) {} +//│ class A$4_C$1$5[T]([par$A$4,]): C$2() {fun foo = (x: T,) => x} +//│ class A$4[T,U]([x: Int,]) {fun getA = () => {new A$4_C$1$5([this,]) {}}} //│ } //│ // │ TypingUnit(NuTypeDef(class, B, (TypeName(T)), Tup(), (), TypingUnit()), NuTypeDef(class, C, (), Tup(), (), TypingUnit()), NuTypeDef(class, A, (TypeName(T), TypeName(U)), Tup(x: Var(Int)), (App(App(Var(&), Tup(_: Bra(rcd = true, Rcd(Var(a1) = Var(Int)})))), Tup(_: TyApp(Var(B), List(TypeName(T)))))), TypingUnit(NuFunDef(None, getA, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = x: T, => x)))))))) @@ -169,16 +169,16 @@ class A(x: Int) extends {a1: Int}, B, D(x){ } } //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)| |#extends| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| -//│ Parsed: {class B‹T›() {}; class C() {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D (x,) {fun getA = () => new C() {fun foo = (x,) => x}}} +//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C([]) {fun foo = (x,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = (x,) => x)))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(List(fun foo = (x,) => x)))))))) //│ Lifted: //│ TypingUnit { -//│ class B$1[T]() {} -//│ class C$2() {} -//│ class D$3(y: Int,) {} -//│ class A$4_C$1$5(par$A$4,): C$2 () {fun foo = (x,) => x} -//│ class A$4[T,U](x: Int,): '{' {a1: Int} '}', B$1 ()‹T›, D$3 ((this).x,) {fun getA = () => {new A$4_C$1$5(this,) {}}} +//│ class B$1[T]([]) {} +//│ class C$2([]) {} +//│ class D$3([y: Int,]) {} +//│ class A$4_C$1$5([par$A$4,]): C$2() {fun foo = (x,) => x} +//│ class A$4[T,U]([x: Int,]): '{' {a1: Int} '}', B$1()‹T›, D$3((this).x,) {fun getA = () => {new A$4_C$1$5([this,]) {}}} //│ } //│ @@ -190,15 +190,15 @@ class Child(x): { age: T } & { name: String} { fun boo = new Inner } //│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| -//│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner() {fun foo = age}; fun bar = age; fun boo = new Inner() {}}} +//│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner {fun foo = age}; fun bar = age; fun boo = new Inner([]) {}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),)), TypingUnit(List())))))) +//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), TypingUnit(List())))))) //│ Lifted: //│ TypingUnit { -//│ class Child$1_Inner$2(par$Child$1, age,) {fun foo = (this).age} -//│ class Child$1[T,U](x,) { +//│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = (this).age} +//│ class Child$1[T,U]([x,]) { //│ fun bar = age -//│ fun boo = new Child$1_Inner$2(this, age,) {} +//│ fun boo = new Child$1_Inner$2([this, age,]) {} //│ } //│ } //│ @@ -213,14 +213,14 @@ new A(0) { fun getA2 = 2 } //│ |#class| |A|(|x|#:| |Int|)| |{|→|#fun| |getA|#:| |Int| |#=| |0|↵|#fun| |getA1| |#=| |1|←|↵|}|↵|#new| |A|(|0|)| |{|→|#fun| |getA| |#=| |3|↵|#fun| |getA2| |#=| |2|←|↵|}| -//│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; new A(0,) {fun getA = 3; fun getA2 = 2}} +//│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; new A([0,]) {fun getA = 3; fun getA2 = 2}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),0,)), TypingUnit(List(fun getA = 3, fun getA2 = 2)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), TypingUnit(List(fun getA = 3, fun getA2 = 2)))) //│ Lifted: //│ TypingUnit { -//│ class A$1(x: Int,) {fun getA = 0 : Int; fun getA1 = 1} -//│ class A$1$2(x: Int,): A$1 ((this).x,) {fun getA = 3; fun getA2 = 2} -//│ Code(List({new A$1$2(0,) {}})) +//│ class A$1([x: Int,]) {fun getA = 0 : Int; fun getA1 = 1} +//│ class A$1$2([x: Int,]): A$1((this).x,) {fun getA = 3; fun getA2 = 2} +//│ Code(List({new A$1$2([0,]) {}})) //│ } //│ @@ -234,16 +234,16 @@ new A(1) { } } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{| |}|←|↵|}|↵|#new| |A|(|1|)| |{|→|#fun| |getB| |#=| |#new| |B|(|2|)|{|→|#fun| |getB| |#=| |#new| |B|(|3|)|←|↵|}|←|↵|}| -//│ Parsed: {class A(x,) {class B(y,) {}}; new A(1,) {fun getB = new B(2,) {fun getB = new B(3,) {}}}} +//│ Parsed: {class A(x,) {class B(y,) {}}; new A([1,]) {fun getB = new B([2,]) {fun getB = new B([3,]) {}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),1,)), TypingUnit(List(fun getB = new B(2,) {fun getB = new B(3,) {}})))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), TypingUnit(List(fun getB = new B([2,]) {fun getB = new B([3,]) {}})))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2(par$A$1, y,) {} -//│ class A$1(x,) {} -//│ class A$1$3_B$2$4(par$A$1$3, y,): A$1_B$2 ((this).par$A$1$3, (this).y,) {fun getB = new A$1_B$2((this).par$A$1$3, 3,) {}} -//│ class A$1$3(x,): A$1 ((this).x,) {fun getB = {new A$1$3_B$2$4(this, 2,) {}}} -//│ Code(List({new A$1$3(1,) {}})) +//│ class A$1_B$2([par$A$1, y,]) {} +//│ class A$1([x,]) {} +//│ class A$1$3_B$2$4([par$A$1$3, y,]): A$1_B$2((this).par$A$1$3, (this).y,) {fun getB = new A$1_B$2([(this).par$A$1$3, 3,]) {}} +//│ class A$1$3([x,]): A$1((this).x,) {fun getB = {new A$1$3_B$2$4([this, 2,]) {}}} +//│ Code(List({new A$1$3([1,]) {}})) //│ } //│ @@ -267,20 +267,20 @@ new B{ fun getA = funcB } //│ |#class| |A| |{|→|#fun| |getA| |#=| |0|↵|#fun| |funcA| |#=| |10|←|↵|}|↵|#class| |B|#:| |A|{|→|#fun| |getA| |#=| |1|↵|#fun| |funcB| |#=| |11|←|↵|}|↵|#new| |A|↵|#new| |B|↵|#fun| |f|(|x|)| |#=| |#if| |x| |is| |A| |#then| |0| |#else| |1|↵|f|(|#new| |A|{|→|#fun| |getA| |#=| |2|←|↵|}|)|↵|#new| |B|{|→|#fun| |getA| |#=| |funcB|←|↵|}| -//│ Parsed: {class A() {fun getA = 0; fun funcA = 10}; class B(): A {fun getA = 1; fun funcB = 11}; new A() {}; new B() {}; fun f = (x,) => if (is (x, A,)) then 0 else 1; f (new A() {fun getA = 2},); new B() {fun getA = funcB}} +//│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A([]) {}; new B([]) {}; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A([]) {fun getA = 2},); new B([]) {fun getA = funcB}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),)), TypingUnit(List())), New(Some((TypeName(B),)), TypingUnit(List())), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),)), TypingUnit(List(fun getA = 2))))), New(Some((TypeName(B),)), TypingUnit(List(fun getA = funcB)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), TypingUnit(List())), New(Some((TypeName(B),[])), TypingUnit(List())), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit(List(fun getA = 2))))), New(Some((TypeName(B),[])), TypingUnit(List(fun getA = funcB)))) //│ Lifted: //│ TypingUnit { -//│ class A$1() {fun getA = 0; fun funcA = 10} -//│ class B$2() {fun getA = 1; fun funcB = 11} -//│ class A$1$3(): A$1 () {fun getA = 2} -//│ class B$2$4(): B$2 () {fun getA = (this).funcB} -//│ fun f = (x,) => if (is (x, A$1 (),)) then 0 else 1 -//│ Code(List(new A$1() {})) -//│ Code(List(new B$2() {})) -//│ Code(List(f ({new A$1$3() {}},))) -//│ Code(List({new B$2$4() {}})) +//│ class A$1([]) {fun getA = 0; fun funcA = 10} +//│ class B$2([]) {fun getA = 1; fun funcB = 11} +//│ class A$1$3([]): A$1() {fun getA = 2} +//│ class B$2$4([]): B$2() {fun getA = (this).funcB} +//│ fun f = (x,) => if (is(x, A$1(),)) then 0 else 1 +//│ Code(List(new A$1([]) {})) +//│ Code(List(new B$2([]) {})) +//│ Code(List(f({new A$1$3([]) {}},))) +//│ Code(List({new B$2$4([]) {}})) //│ } //│ @@ -308,17 +308,17 @@ class A{ } } //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A() {class B() {fun funB = 1; fun foo = 100}; class C(): B {fun funC = 2; fun foo = 1000}; class D() {fun funD = 3; fun foo = 10000; class E(): C {fun funE = 4; fun foo = 100000}; class F(): E {fun funF = 5; fun foo = 1000000}}}} +//│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000}; class F: E {fun funF = 5; fun foo = 1000000}}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2(par$A$1,) {fun funB = 1; fun foo = 100} -//│ class A$1_C$3(par$A$1,) {fun funC = 2; fun foo = 1000} -//│ class A$1_D$4_E$5(par$A$1_D$4,) {fun funE = 4; fun foo = 100000} -//│ class A$1_D$4_F$6(par$A$1_D$4,) {fun funF = 5; fun foo = 1000000} -//│ class A$1_D$4(par$A$1,) {fun funD = 3; fun foo = 10000} -//│ class A$1() {} +//│ class A$1_B$2([par$A$1,]) {fun funB = 1; fun foo = 100} +//│ class A$1_C$3([par$A$1,]) {fun funC = 2; fun foo = 1000} +//│ class A$1_D$4_E$5([par$A$1_D$4,]) {fun funE = 4; fun foo = 100000} +//│ class A$1_D$4_F$6([par$A$1_D$4,]) {fun funF = 5; fun foo = 1000000} +//│ class A$1_D$4([par$A$1,]) {fun funD = 3; fun foo = 10000} +//│ class A$1([]) {} //│ } //│ @@ -351,30 +351,30 @@ class A{ } } //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|↵|#fun| |getB| |#=| |#new| |B|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|↵|#fun| |getD| |#=| |#new| |D|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|↵|#fun| |getE| |#=| |#new| |E|{|→|#fun| |foo| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A() {class B() {fun funB = 1; fun foo = 100}; class C(): B {fun funC = 2; fun foo = 1000; fun getB = new B() {}}; class D() {fun funD = 3; fun foo = 10000; class E(): C {fun funE = 4; fun foo = 100000; fun getD = new D() {}}; class F(): E {fun funF = 5; fun foo = 1000000; fun getE = new E() {fun foo = 0}}}}} +//│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B([]) {}}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D([]) {}}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E([]) {fun foo = 0}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),)), TypingUnit(List()))))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),)), TypingUnit(List()))))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),)), TypingUnit(List(fun foo = 0))))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(List()))))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), TypingUnit(List()))))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), TypingUnit(List(fun foo = 0))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2(par$A$1,) {fun funB = 1; fun foo = 100} -//│ class A$1_C$3(par$A$1,) { +//│ class A$1_B$2([par$A$1,]) {fun funB = 1; fun foo = 100} +//│ class A$1_C$3([par$A$1,]) { //│ fun funC = 2 //│ fun foo = 1000 -//│ fun getB = new A$1_B$2((this).par$A$1,) {} +//│ fun getB = new A$1_B$2([(this).par$A$1,]) {} //│ } -//│ class A$1_D$4_E$5(par$A$1_D$4,) { +//│ class A$1_D$4_E$5([par$A$1_D$4,]) { //│ fun funE = 4 //│ fun foo = 100000 -//│ fun getD = new A$1_D$4(((this).par$A$1_D$4).par$A$1,) {} +//│ fun getD = new A$1_D$4([((this).par$A$1_D$4).par$A$1,]) {} //│ } -//│ class A$1_D$4_F$6_E$1$7(par$A$1_D$4_F$6,): A$1_D$4_E$5 (((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = 0} -//│ class A$1_D$4_F$6(par$A$1_D$4,) { +//│ class A$1_D$4_F$6_E$1$7([par$A$1_D$4_F$6,]): A$1_D$4_E$5(((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = 0} +//│ class A$1_D$4_F$6([par$A$1_D$4,]) { //│ fun funF = 5 //│ fun foo = 1000000 -//│ fun getE = {new A$1_D$4_F$6_E$1$7(this,) {}} +//│ fun getE = {new A$1_D$4_F$6_E$1$7([this,]) {}} //│ } -//│ class A$1_D$4(par$A$1,) {fun funD = 3; fun foo = 10000} -//│ class A$1() {} +//│ class A$1_D$4([par$A$1,]) {fun funD = 3; fun foo = 10000} +//│ class A$1([]) {} //│ } //│ @@ -387,14 +387,14 @@ class A{ } new A //│ |#class| |A|{|→|#class| |B|{|→|#fun| |foo| |#=| |1|←|↵|}|↵|#fun| |bar| |#=| |#new| |B|←|↵|}|↵|#new| |A| -//│ Parsed: {class A() {class B() {fun foo = 1}; fun bar = new B() {}}; new A() {}} +//│ Parsed: {class A {class B {fun foo = 1}; fun bar = new B([]) {}}; new A([]) {}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),)), TypingUnit(List()))))), New(Some((TypeName(A),)), TypingUnit(List()))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), TypingUnit(List()))))), New(Some((TypeName(A),[])), TypingUnit(List()))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2(par$A$1,) {fun foo = 1} -//│ class A$1() {fun bar = new A$1_B$2(this,) {}} -//│ Code(List(new A$1() {})) +//│ class A$1_B$2([par$A$1,]) {fun foo = 1} +//│ class A$1([]) {fun bar = new A$1_B$2([this,]) {}} +//│ Code(List(new A$1([]) {})) //│ } //│ @@ -412,22 +412,22 @@ let x = new A{ } } //│ |#class| |A|(|x|)| |{|→|#fun| |foo| |#=| |0|↵|#fun| |bar| |#=| |x|←|↵|}|↵|#let| |x| |#=| |#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |newFun| |#=| |2|↵|#fun| |bar| |#=| |#new| |A|(|foo|)|{|→|#fun| |foo| |#=| |bar| |+| |1|↵|#fun| |bar2| |#=| |newFun| |+| |1|←|↵|}|←|↵|}| -//│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A() {fun foo = 1; fun newFun = 2; fun bar = new A(foo,) {fun foo = + (bar, 1,); fun bar2 = + (newFun, 1,)}}} +//│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A([]) {fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),)), TypingUnit(List(fun foo = 1, fun newFun = 2, fun bar = new A(foo,) {fun foo = + (bar, 1,); fun bar2 = + (newFun, 1,)}))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), TypingUnit(List(fun foo = 1, fun newFun = 2, fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}))))) //│ Lifted: //│ TypingUnit { -//│ class A$1(x,) {fun foo = 0; fun bar = (this).x} -//│ class A$1$2_A$2$3(par$A$1$2, x,): A$1 ((this).x,) { -//│ fun foo = + ((this).bar, 1,) -//│ fun bar2 = + (((this).par$A$1$2).newFun, 1,) +//│ class A$1([x,]) {fun foo = 0; fun bar = (this).x} +//│ class A$1$2_A$2$3([par$A$1$2, x,]): A$1((this).x,) { +//│ fun foo = +((this).bar, 1,) +//│ fun bar2 = +(((this).par$A$1$2).newFun, 1,) //│ } -//│ class A$1$2(x,): A$1 ((this).x,) { +//│ class A$1$2([x,]): A$1((this).x,) { //│ fun foo = 1 //│ fun newFun = 2 -//│ fun bar = {new A$1$2_A$2$3(this, (this).foo,) {}} +//│ fun bar = {new A$1$2_A$2$3([this, (this).foo,]) {}} //│ } -//│ let x = {new A$1$2() {}} +//│ let x = {new A$1$2([]) {}} //│ } //│ @@ -449,30 +449,30 @@ new A{ } } //│ |#class| |A| |{||}|↵|#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |#new| |A|{|→|#fun| |foo1| |#=| |foo|↵|#fun| |bar1| |#=| |#new| |A|{|→|#fun| |foo2| |#=| |foo|↵|#fun| |bar2| |#=| |#new| |A|{|→|#fun| |foo3| |#=| |foo|↵|#fun| |bar3| |#=| |#new| |A|{|→|#fun| |foo4| |#=| |foo|↵|#fun| |bar4| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A() {}; new A() {fun foo = 1; fun bar = new A() {fun foo1 = foo; fun bar1 = new A() {fun foo2 = foo; fun bar2 = new A() {fun foo3 = foo; fun bar3 = new A() {fun foo4 = foo; fun bar4 = 0}}}}}} +//│ Parsed: {class A {}; new A([]) {fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),)), TypingUnit(List(fun foo = 1, fun bar = new A() {fun foo1 = foo; fun bar1 = new A() {fun foo2 = foo; fun bar2 = new A() {fun foo3 = foo; fun bar3 = new A() {fun foo4 = foo; fun bar4 = 0}}}})))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), TypingUnit(List(fun foo = 1, fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}})))) //│ Lifted: //│ TypingUnit { -//│ class A$1() {} -//│ class A$1$2_A$2$3_A$3$4_A$4$5_A$5$6(par$A$1$2_A$2$3_A$3$4_A$4$5,): A$1 () { +//│ class A$1([]) {} +//│ class A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([par$A$1$2_A$2$3_A$3$4_A$4$5,]): A$1() { //│ fun foo4 = (((((this).par$A$1$2_A$2$3_A$3$4_A$4$5).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo //│ fun bar4 = 0 //│ } -//│ class A$1$2_A$2$3_A$3$4_A$4$5(par$A$1$2_A$2$3_A$3$4,): A$1 () { +//│ class A$1$2_A$2$3_A$3$4_A$4$5([par$A$1$2_A$2$3_A$3$4,]): A$1() { //│ fun foo3 = ((((this).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar3 = {new A$1$2_A$2$3_A$3$4_A$4$5_A$5$6(this,) {}} +//│ fun bar3 = {new A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([this,]) {}} //│ } -//│ class A$1$2_A$2$3_A$3$4(par$A$1$2_A$2$3,): A$1 () { +//│ class A$1$2_A$2$3_A$3$4([par$A$1$2_A$2$3,]): A$1() { //│ fun foo2 = (((this).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar2 = {new A$1$2_A$2$3_A$3$4_A$4$5(this,) {}} +//│ fun bar2 = {new A$1$2_A$2$3_A$3$4_A$4$5([this,]) {}} //│ } -//│ class A$1$2_A$2$3(par$A$1$2,): A$1 () { +//│ class A$1$2_A$2$3([par$A$1$2,]): A$1() { //│ fun foo1 = ((this).par$A$1$2).foo -//│ fun bar1 = {new A$1$2_A$2$3_A$3$4(this,) {}} +//│ fun bar1 = {new A$1$2_A$2$3_A$3$4([this,]) {}} //│ } -//│ class A$1$2(): A$1 () {fun foo = 1; fun bar = {new A$1$2_A$2$3(this,) {}}} -//│ Code(List({new A$1$2() {}})) +//│ class A$1$2([]): A$1() {fun foo = 1; fun bar = {new A$1$2_A$2$3([this,]) {}}} +//│ Code(List({new A$1$2([]) {}})) //│ } //│ diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index bc45be8120..b2d692d3bd 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -5,11 +5,11 @@ fun foo = print("ok") print("ko") //│ |#fun| |foo| |#=|→|print|(|"ok"|)|↵|print|(|"ko"|)|←| -//│ Parsed: {fun foo = {print ("ok",); print ("ko",)}} +//│ Parsed: {fun foo = {print("ok",); print("ko",)}} //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) //│ Lifted: -//│ TypingUnit {fun foo = {print ("ok",); print ("ko",)}} +//│ TypingUnit {fun foo = {print("ok",); print("ko",)}} //│ class A{ @@ -17,13 +17,13 @@ class A{ fun foo(x: B) = (x:B) } //│ |#class| |A|{|→|#class| |B| |{||}|↵|#fun| |foo|(|x|#:| |B|)| |#=| |(|x|#:|B|)|←|↵|}| -//│ Parsed: {class A() {class B() {}; fun foo = (x: B,) => '(' x: B, ')'}} +//│ Parsed: {class A {class B {}; fun foo = (x: B,) => '(' [x: B,] ')'}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(x: Var(B)), Bra(rcd = false, Tup(x: Var(B)))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2(par$A$1,) {} -//│ class A$1() {fun foo = (x: A$1_B$2,) => '(' x: A$1_B$2, ')'} +//│ class A$1_B$2([par$A$1,]) {} +//│ class A$1([]) {fun foo = (x: A$1_B$2,) => '(' [x: A$1_B$2,] ')'} //│ } //│ @@ -39,13 +39,13 @@ fun foo = print of local of 0 + local of 1 fun tmp = 2 //│ |#fun| |foo| |#=|→|#fun| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| -//│ Parsed: {fun foo = {fun local = (x,) => {class Foo() {fun bar = + (x, 1,)}; (Foo ()).bar}; print (+ (local (0,), local (1,),),); print (+ ('(' local (0,) ')', local (1,),),); fun tmp = 1; print (local (+ (0, local (1,),),),); fun tmp = 2}} +//│ Parsed: {fun foo = {fun local = (x,) => {class Foo {fun bar = +(x, 1,)}; (Foo()).bar}; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); fun tmp = 1; print(local(+(0, local(1,),),),); fun tmp = 2}} //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1(x,) {fun bar = + ((this).x, 1,)} -//│ fun foo = {fun local = (x,) => {(Foo$1 (x,)).bar}; fun tmp = 1; fun tmp = 2; print (+ (local (0,), local (1,),),); print (+ ('(' local (0,) ')', local (1,),),); print (local (+ (0, local (1,),),),)} +//│ class Foo$1([x,]) {fun bar = +((this).x, 1,)} +//│ fun foo = {fun local = (x,) => {(Foo$1(x,)).bar}; fun tmp = 1; fun tmp = 2; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); print(local(+(0, local(1,),),),)} //│ } //│ @@ -53,15 +53,15 @@ class A(y){} let f = x => new A(0){fun bar = x+y} f(0) //│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| -//│ Parsed: {class A(y,) {}; let f = (x,) => new A(0,) {fun bar = + (x, y,)}; f (0,)} +//│ Parsed: {class A(y,) {}; let f = (x,) => new A([0,]) {fun bar = +(x, y,)}; f(0,)} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),0,)), TypingUnit(List(fun bar = + (x, y,)))))), App(Var(f), Tup(_: IntLit(0)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), TypingUnit(List(fun bar = +(x, y,)))))), App(Var(f), Tup(_: IntLit(0)))) //│ Lifted: //│ TypingUnit { -//│ class A$1(y,) {} -//│ class A$1$2(y, x,): A$1 ((this).y,) {fun bar = + ((this).x, (this).y,)} -//│ let f = (x,) => {new A$1$2(0, x,) {}} -//│ Code(List(f (0,))) +//│ class A$1([y,]) {} +//│ class A$1$2([y, x,]): A$1((this).y,) {fun bar = +((this).x, (this).y,)} +//│ let f = (x,) => {new A$1$2([0, x,]) {}} +//│ Code(List(f(0,))) //│ } //│ @@ -76,20 +76,16 @@ class A(x){ } } //│ |#class| |A|(|x|)|{|→|#fun| |w| |#=| |x|↵|#fun| |foo|(|y|)| |#=| |→|#class| |B|(|z|)|{|→|#fun| |bar| |#=| |x|+|y|+|z|←|↵|}|↵|#new| |B|(|0|)|{|→|#fun| |bar| |#=| |w|+|y|+|z|←|↵|}|←|←|↵|}| -//│ Parsed: {class A(x,) {fun w = x; fun foo = (y,) => {class B(z,) {fun bar = + (+ (x, y,), z,)}; new B(0,) {fun bar = + (+ (w, y,), z,)}}}} +//│ Parsed: {class A(x,) {fun w = x; fun foo = (y,) => {class B(z,) {fun bar = +(+(x, y,), z,)}; new B([0,]) {fun bar = +(+(w, y,), z,)}}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, w, None, [], Var(x)), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(y)), Blk(...)))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2(par$A$1, z, y,) { -//│ fun bar = + (+ (((this).par$A$1).x, (this).y,), (this).z,) -//│ } -//│ class A$1_B$1$3(par$A$1, z, y,): A$1_B$2 ((this).par$A$1, (this).z, (this).y,) { -//│ fun bar = + (+ (((this).par$A$1).w, (this).y,), (this).z,) -//│ } -//│ class A$1(x,) { +//│ class A$1_B$2([par$A$1, z, y,]) {fun bar = +(+(((this).par$A$1).x, (this).y,), (this).z,)} +//│ class A$1_B$1$3([par$A$1, z, y,]): A$1_B$2((this).par$A$1, (this).z, (this).y,) {fun bar = +(+(((this).par$A$1).w, (this).y,), (this).z,)} +//│ class A$1([x,]) { //│ fun w = (this).x -//│ fun foo = (y,) => {{new A$1_B$1$3(this, 0, y,) {}}} +//│ fun foo = (y,) => {{new A$1_B$1$3([this, 0, y,]) {}}} //│ } //│ } //│ @@ -107,20 +103,20 @@ fun f(x,y,z) = fun bar = bar1 + bar2 } //│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#class| |C| |#extends| |A|,| |B| |{|→|#fun| |bar| |#=| |bar1| |+| |bar2|←|↵|}|←| -//│ Parsed: {fun f = (x, y, z,) => {class A() {fun foo = new B() {}; fun bar1 = x}; class B() {fun foo = new A() {}; fun bar2 = y}; class C(): A, B {fun bar = + (bar1, bar2,)}}} +//│ Parsed: {fun f = (x, y, z,) => {class A {fun foo = new B([]) {}; fun bar1 = x}; class B {fun foo = new A([]) {}; fun bar2 = y}; class C: A, B {fun bar = +(bar1, bar2,)}}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class A$1(x, y,) { -//│ fun foo = new B$2((this).y, (this).x,) {} +//│ class A$1([x, y,]) { +//│ fun foo = new B$2([(this).y, (this).x,]) {} //│ fun bar1 = (this).x //│ } -//│ class B$2(y, x,) { -//│ fun foo = new A$1((this).x, (this).y,) {} +//│ class B$2([y, x,]) { +//│ fun foo = new A$1([(this).x, (this).y,]) {} //│ fun bar2 = (this).y //│ } -//│ class C$3(x, y,): A$1 ((this).x, (this).y,), B$2 ((this).y, (this).x,) {fun bar = + ((this).bar1, (this).bar2,)} +//│ class C$3([x, y,]): A$1((this).x, (this).y,), B$2((this).y, (this).x,) {fun bar = +((this).bar1, (this).bar2,)} //│ fun f = (x, y, z,) => {} //│ } //│ @@ -138,21 +134,21 @@ fun f(x,y,z) = fun boo = (new A).bar1 + B().bar2 + z } //│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |C|{|→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#fun| |boo| |#=| |(|#new| |A|)|.bar1| |+| |B|(||)|.bar2| |+| |z|←|↵|}|←| -//│ Parsed: {fun f = (x, y, z,) => {class C() {class A() {fun foo = new B() {}; fun bar1 = x}; class B() {fun foo = new A() {}; fun bar2 = y}; fun boo = + (+ (('(' new A() {} ')').bar1, (B ()).bar2,), z,)}}} +//│ Parsed: {fun f = (x, y, z,) => {class C {class A {fun foo = new B([]) {}; fun bar1 = x}; class B {fun foo = new A([]) {}; fun bar2 = y}; fun boo = +(+(('(' new A([]) {} ')').bar1, (B()).bar2,), z,)}}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class C$1_A$2(par$C$1,) { -//│ fun foo = new C$1_B$3((this).par$C$1,) {} +//│ class C$1_A$2([par$C$1,]) { +//│ fun foo = new C$1_B$3([(this).par$C$1,]) {} //│ fun bar1 = ((this).par$C$1).x //│ } -//│ class C$1_B$3(par$C$1,) { -//│ fun foo = new C$1_A$2((this).par$C$1,) {} +//│ class C$1_B$3([par$C$1,]) { +//│ fun foo = new C$1_A$2([(this).par$C$1,]) {} //│ fun bar2 = ((this).par$C$1).y //│ } -//│ class C$1(x, y, z,) { -//│ fun boo = + (+ (('(' new C$1_A$2(this,) {} ')').bar1, (C$1_B$3 (this,)).bar2,), (this).z,) +//│ class C$1([x, y, z,]) { +//│ fun boo = +(+(('(' new C$1_A$2([this,]) {} ')').bar1, (C$1_B$3(this,)).bar2,), (this).z,) //│ } //│ fun f = (x, y, z,) => {} //│ } @@ -165,13 +161,13 @@ fun f(x) = } Foo(x).h //│ |#fun| |f|(|x|)| |#=|→|#let| |g|(|x|)| |#=| |x| |+| |1|↵|#class| |Foo|(|x|)| |{|→|#fun| |h| |#=| |g|(|x|)|←|↵|}|↵|Foo|(|x|)|.h|←| -//│ Parsed: {fun f = (x,) => {let g = (x,) => + (x, 1,); class Foo(x,) {fun h = g (x,)}; (Foo (x,)).h}} +//│ Parsed: {fun f = (x,) => {let g = (x,) => +(x, 1,); class Foo(x,) {fun h = g(x,)}; (Foo(x,)).h}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1(x, g,) {fun h = (this).g ((this).x,)} -//│ fun f = (x,) => {let g = (x,) => + (x, 1,); (Foo$1 (x, g,)).h} +//│ class Foo$1([x, g,]) {fun h = (this).g((this).x,)} +//│ fun f = (x,) => {let g = (x,) => +(x, 1,); (Foo$1(x, g,)).h} //│ } //│ @@ -184,24 +180,24 @@ fun f(x) = } Foo(x, x).bar //│ |#fun| |f|(|x|)| |#=|→|#let| |g|(|x|)| |#=| |→|#let| |h|(|x|)| |#=| |x| |+| |2|↵|Foo|(|h|(|x|)|,| |x|)|.bar|←|↵|#class| |Foo|(|x|,| |y|)| |{|→|#fun| |bar| |#=| |g|(|x|)|+|y|←|↵|}|↵|Foo|(|x|,| |x|)|.bar|←| -//│ Parsed: {fun f = (x,) => {let g = (x,) => {let h = (x,) => + (x, 2,); (Foo (h (x,), x,)).bar}; class Foo(x, y,) {fun bar = + (g (x,), y,)}; (Foo (x, x,)).bar}} +//│ Parsed: {fun f = (x,) => {let g = (x,) => {let h = (x,) => +(x, 2,); (Foo(h(x,), x,)).bar}; class Foo(x, y,) {fun bar = +(g(x,), y,)}; (Foo(x, x,)).bar}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1(x, y, g,) {fun bar = + ((this).g ((this).x,), (this).y,)} -//│ fun f = (x,) => {let g = (x,) => {let h = (x,) => + (x, 2,); (Foo$1 (h (x,), x, g,)).bar}; (Foo$1 (x, x, g,)).bar} +//│ class Foo$1([x, y, g,]) {fun bar = +((this).g((this).x,), (this).y,)} +//│ fun f = (x,) => {let g = (x,) => {let h = (x,) => +(x, 2,); (Foo$1(h(x,), x, g,)).bar}; (Foo$1(x, x, g,)).bar} //│ } //│ class Foo(x, y) extends Bar(y, x), Baz(x + y) //│ |#class| |Foo|(|x|,| |y|)| |#extends| |Bar|(|y|,| |x|)|,| |Baz|(|x| |+| |y|)| -//│ Parsed: {class Foo(x, y,): Bar (y, x,), Baz (+ (x, y,),) {}} +//│ Parsed: {class Foo(x, y,): Bar(y, x,), Baz(+(x, y,),) {}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, Foo, (), Tup(_: Var(x), _: Var(y)), (App(Var(Bar), Tup(_: Var(y), _: Var(x))), App(Var(Baz), Tup(_: App(Var(+), Tup(_: Var(x), _: Var(y)))))), None, None, TypingUnit())) //│ Lifted: //│ TypingUnit { -//│ class Foo$1(x, y,): Bar ((this).y, (this).x,), Baz (+ ((this).x, (this).y,),) {} +//│ class Foo$1([x, y,]): Bar((this).y, (this).x,), Baz(+((this).x, (this).y,),) {} //│ } //│ @@ -211,12 +207,12 @@ fun foo(x: T): string = } "rua" //│ |#fun| |foo|‹|T|,| |U|›|(|x|#:| |T|)|#:| |string| |#=| |→|#class| |A|(|y|)| |#extends| |B|‹|T|›|,| |C|(|y|#:| |U|)| |{|→|#fun| |bar| |#=| |this|←|↵|}|↵|"rua"|←| -//│ Parsed: {fun foo = (x: T,) => {class A(y,): B‹T›, C (y: U,) {fun bar = this}; "rua"} : string} +//│ Parsed: {fun foo = (x: T,) => {class A(y,): B‹T›, C(y: U,) {fun bar = this}; "rua"} : string} //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, None, [TypeName(T), TypeName(U)], Lam(Tup(x: Var(T)), Asc(Blk(...), TypeName(string))))) //│ Lifted: //│ TypingUnit { -//│ class A$1[T,U](y,): B‹T›, C (y: U,) {fun bar = this} +//│ class A$1[T,U]([y,]): B‹T›, C(y: U,) {fun bar = this} //│ fun foo[T, U] = (x: T,) => {"rua"} : string //│ } //│ @@ -228,16 +224,16 @@ class A{ } } //│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f|#:| |T| |=>| |B| |=>| |T| |#=| |x| |=>| |y| |=>| |x|↵|#fun| |g|#:| |T| |=>| |B| |=>| |T|←|↵|}|←|↵|}| -//│ Parsed: {class A‹T›() {class B() {fun f = (x,) => (y,) => x : T -> B -> T; fun g: T -> B -> T}}} +//│ Parsed: {class A‹T› {class B {fun f = (x,) => (y,) => x : T -> B -> T; fun g: T -> B -> T}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, None, [], Asc(Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x))), Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T))))), NuFunDef(None, g, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2[T](par$A$1,) { +//│ class A$1_B$2[T]([par$A$1,]) { //│ fun f = (x,) => (y,) => x : T -> A$1_B$2 -> T //│ fun g = T -> A$1_B$2 -> T //│ } -//│ class A$1[T]() {} +//│ class A$1[T]([]) {} //│ } //│ @@ -247,15 +243,15 @@ class Foo{ class Bar: {any: RectangleBox => StackedRectangleBoxes} } //│ |#class| |Foo|‹|T|›|{|→|#class| |RectangleBox|#:| |Box|‹|T|›| |&| |{| |breadth|#:| |T| |}|↵|#class| |StackedRectangleBoxes|‹|N|›| |#:| |RectangleBox|‹|T|›| |&| |{| |size|#:| |N| |}|↵|#class| |Bar|#:| |{|any|#:| |RectangleBox| |=>| |StackedRectangleBoxes|}|←|↵|}| -//│ Parsed: {class Foo‹T›() {class RectangleBox(): Box[T] & {breadth: T} {}; class StackedRectangleBoxes‹N›(): RectangleBox[T] & {size: N} {}; class Bar(): {any: RectangleBox -> StackedRectangleBoxes} {}}} +//│ Parsed: {class Foo‹T› {class RectangleBox: Box[T] & {breadth: T} {}; class StackedRectangleBoxes‹N›: RectangleBox[T] & {size: N} {}; class Bar: {any: RectangleBox -> StackedRectangleBoxes} {}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, Foo, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, RectangleBox, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, StackedRectangleBoxes, ((None,TypeName(N))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, Bar, (), Tup(), (), None, None, TypingUnit())))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1_RectangleBox$2(par$Foo$1,) {} -//│ class Foo$1_StackedRectangleBoxes$3[N](par$Foo$1,) {} -//│ class Foo$1_Bar$4(par$Foo$1,) {} -//│ class Foo$1[T]() {} +//│ class Foo$1_RectangleBox$2([par$Foo$1,]) {} +//│ class Foo$1_StackedRectangleBoxes$3[N]([par$Foo$1,]) {} +//│ class Foo$1_Bar$4([par$Foo$1,]) {} +//│ class Foo$1[T]([]) {} //│ } //│ @@ -270,15 +266,15 @@ fun ctx(a,b) = fun apply(x) = a+x }, b) //│ |#class| |Func|‹|T|,| |U|›| |{|→|#fun| |apply|#:| |T| |=>| |U|←|↵|}|↵|#class| |Lambda|‹|T|,| |U|›| |#:| |Func|‹|T|,| |U|›| |{||}|↵|#fun| |ctx|(|a|,|b|)| |#=|→|#fun| |foo|(|f|#:| |Func|,| |x|)| |#=| |→|f|.apply|(|x|)|←|↵|foo|(|#new| |Lambda|{|→|#fun| |apply|(|x|)| |#=| |a|+|x|←|↵|}|,| |b|)|←| -//│ Parsed: {class Func‹T, U›() {fun apply: T -> U}; class Lambda‹T, U›(): Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply (x,)}; foo (new Lambda() {fun apply = (x,) => + (a, x,)}, b,)}} +//│ Parsed: {class Func‹T, U› {fun apply: T -> U}; class Lambda‹T, U›: Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply(x,)}; foo(new Lambda([]) {fun apply = (x,) => +(a, x,)}, b,)}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, Func, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),TypeName(U)))))), NuTypeDef(class, Lambda, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit()), NuFunDef(None, ctx, None, [], Lam(Tup(_: Var(a), _: Var(b)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class Func$1[T,U]() {fun apply = T -> U} -//│ class Lambda$2[T,U]() {} -//│ class Lambda$1$3(a,): Lambda$2 () {fun apply = (x,) => + ((this).a, x,)} -//│ fun ctx = (a, b,) => {fun foo = (f: Func$1, x,) => {(f).apply (x,)}; foo ({new Lambda$1$3(a,) {}}, b,)} +//│ class Func$1[T,U]([]) {fun apply = T -> U} +//│ class Lambda$2[T,U]([]) {} +//│ class Lambda$1$3([a,]): Lambda$2() {fun apply = (x,) => +((this).a, x,)} +//│ fun ctx = (a, b,) => {fun foo = (f: Func$1, x,) => {(f).apply(x,)}; foo({new Lambda$1$3([a,]) {}}, b,)} //│ } //│ @@ -286,7 +282,7 @@ fun f(T) = new T() f(MyClass) //│ |#fun| |f|(|T|)| |#=| |→|#new| |T|(||)|←|↵|f|(|MyClass|)| -//│ Parsed: {fun f = (T,) => {new T() {}}; f (MyClass,)} +//│ Parsed: {fun f = (T,) => {new T([]) {}}; f(MyClass,)} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(T)), Blk(...))), App(Var(f), Tup(_: Var(MyClass)))) //│ Lifted: diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 66e6ee1016..ffc732f83d 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -433,9 +433,9 @@ trait NuDeclImpl extends Located { self: NuDecl => case NuFunDef(S(false), n, snme, _, b) => s"let${snme.fold("")(" "+_+")")} $n" case NuFunDef(S(true), n, snme, _, b) => s"let rec${snme.fold("")(" "+_+")")} $n" case NuTypeDef(k, n, tps, sps, ctor, sig, parents, sup, ths, bod) => - s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}(${ - // sps.mkString("(",",",")") - sps.getOrElse(Tup(Nil))})${sig.fold("")(": " + _.showDbg2)}${ + s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}${ + sps.fold("")("(" + _.showElems + ")") + }${sig.fold("")(": " + _.showDbg2)}${ if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" } lazy val genUnapply: Opt[NuFunDef] = this match { @@ -546,22 +546,25 @@ trait TermImpl extends StatementImpl { self: Term => case UnitLit(value) => if (value) "undefined" else "null" case v @ Var(name) => name + v.uid.fold("")("::"+_.toString) case Asc(trm, ty) => s"$trm : ${ty.showDbg2}" |> bra - case Lam(pat, rhs) => s"($pat) => $rhs" |> bra - case App(lhs, rhs) => s"${lhs.print(!lhs.isInstanceOf[App])} ${rhs.print(true)}" |> bra + case Lam(pat: Tup, rhs) => s"(${pat.showElems}) => $rhs" |> bra + case Lam(pat, rhs) => s"(...$pat) => $rhs" |> bra + case App(lhs, rhs: Tup) => s"${lhs.print(!lhs.isInstanceOf[App])}(${rhs.showElems})" |> bra + case App(lhs, rhs) => s"${lhs.print(!lhs.isInstanceOf[App])}(...${rhs.print(true)})" |> bra case Rcd(fields) => fields.iterator.map(nv => (if (nv._2.flags.mut) "mut " else "") + nv._1.name + ": " + nv._2.value).mkString("{", ", ", "}") case Sel(receiver, fieldName) => "(" + receiver.toString + ")." + fieldName case Let(isRec, name, rhs, body) => s"let${if (isRec) " rec" else ""} $name = $rhs in $body" |> bra - case Tup(xs) => - xs.iterator.map { case (n, t) => - (if (t.flags.mut) "mut " else "") + (if (t.flags.spec) "#" else "") + n.fold("")(_.name + ": ") + t.value + "," - // }.mkString("(", " ", ")") - }.mkString(" ") |> bra + case tup: Tup => "[" + tup.showElems + "]" case Splc(fields) => fields.map{ case L(l) => s"...$l" - case R(Fld(FldFlags(m, s, g), r)) => (if (m) "mut " else "") + (if (g) "val " else "") + (if (s) "#" else "") + r + case R(Fld(FldFlags(m, s, g), r)) => ( + (if (m) "mut " else "") + + (if (g) "val " else "") + + (if (s) "#" else "") + + r + ) }.mkString("(", ", ", ")") case Bind(l, r) => s"$l as $r" |> bra case Test(l, r) => s"$l is $r" |> bra @@ -690,6 +693,16 @@ trait VarImpl { self: Var => var uid: Opt[Int] = N } +trait TupImpl { self: Tup => + def showElems: Str = + fields.iterator.map { case (n, t) => ( + (if (t.flags.mut) "mut " else "") + + (if (t.flags.genGetter) "val " else "") + + (if (t.flags.spec) "#" else "") + + n.fold("")(_.name + ": ") + t.value + "," + )}.mkString(" ") +} + trait SimpleTermImpl extends Ordered[SimpleTerm] { self: SimpleTerm => def compare(that: SimpleTerm): Int = this.idStr compare that.idStr val idStr: Str = this match { diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 64a191c3b9..c4f199abc5 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -67,7 +67,7 @@ sealed abstract class Lit extends Sim final case class Var(name: Str) extends SimpleTerm with VarImpl with NameRef final case class Lam(lhs: Term, rhs: Term) extends Term final case class App(lhs: Term, rhs: Term) extends Term -final case class Tup(fields: Ls[Opt[Var] -> Fld]) extends Term +final case class Tup(fields: Ls[Opt[Var] -> Fld]) extends Term with TupImpl final case class Rcd(fields: Ls[Var -> Fld]) extends Term final case class Sel(receiver: Term, fieldName: Var) extends Term final case class Let(isRec: Bool, name: Var, rhs: Term, body: Term) extends Term diff --git a/shared/src/test/diff/basics/Blocks.fun b/shared/src/test/diff/basics/Blocks.fun index 081e70fabc..65d88924eb 100644 --- a/shared/src/test/diff/basics/Blocks.fun +++ b/shared/src/test/diff/basics/Blocks.fun @@ -42,8 +42,8 @@ foo / foo / :p discard / foo 1 -//│ Parsed: discard (foo {1}); -//│ Desugared: discard (foo {1}) +//│ Parsed: discard(...(foo(...{1}))); +//│ Desugared: discard(...(foo(...{1}))) //│ AST: App(Var(discard), App(Var(foo), Blk(...))) :e @@ -79,8 +79,8 @@ foo :p id id id -//│ Parsed: id id {id}; -//│ Desugared: id id {id} +//│ Parsed: id(...id)(...{id}); +//│ Desugared: id(...id)(...{id}) //│ AST: App(App(Var(id), Var(id)), Blk(...)) //│ res: 'a -> 'a @@ -89,8 +89,8 @@ id id id id id id id id id id id id -//│ Parsed: id id id {id id id {id id id {id id id}}}; -//│ Desugared: id id id {id id id {id id id {id id id}}} +//│ Parsed: id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)})})}); +//│ Desugared: id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)})})}) //│ AST: App(App(App(Var(id), Var(id)), Var(id)), Blk(...)) //│ res: 'a -> 'a @@ -98,8 +98,8 @@ id id id id id / id id / id id -//│ Parsed: id id {id id {id id}}; -//│ Desugared: id id {id id {id id}} +//│ Parsed: id(...id)(...{id(...id)(...{id(...id)})}); +//│ Desugared: id(...id)(...{id(...id)(...{id(...id)})}) //│ AST: App(App(Var(id), Var(id)), Blk(...)) //│ res: 'a -> 'a @@ -107,8 +107,8 @@ id id / id id id id id id -//│ Parsed: id id {id id} {id id}; -//│ Desugared: id id {id id} {id id} +//│ Parsed: id(...id)(...{id(...id)})(...{id(...id)}); +//│ Desugared: id(...id)(...{id(...id)})(...{id(...id)}) //│ AST: App(App(App(Var(id), Var(id)), Blk(...)), Blk(...)) //│ res: 'a -> 'a diff --git a/shared/src/test/diff/basics/Data.fun b/shared/src/test/diff/basics/Data.fun index 2b58b9b00b..f155732eec 100644 --- a/shared/src/test/diff/basics/Data.fun +++ b/shared/src/test/diff/basics/Data.fun @@ -1,7 +1,7 @@ :p data Test a b -//│ Parsed: data Test a b; +//│ Parsed: data Test(...a)(...b); //│ Desugared: class Test[a, b]: {a: a, b: b} //│ Desugared: def Test: forall a b. (...a) -> (...b) -> Test[a, b] //│ AST: Def(false, Test, PolyType(List(Left(TypeName(a)), Left(TypeName(b))),Function(TypeName(a),Function(TypeName(b),AppliedType(TypeName(Test),List(TypeName(a), TypeName(b)))))), true) @@ -10,7 +10,7 @@ data Test a b :p data Person(name: string, age: int) -//│ Parsed: data Person '(' {name: string, age: int,} ')'; +//│ Parsed: data Person(...'(' {[name: string, age: int,]} ')'); //│ Desugared: class Person: {age: int, name: string} //│ Desugared: def Person: (name: string, age: int) -> Person[] //│ AST: Def(false, Person, PolyType(List(),Function(Tuple(List((Some(name),Field(None,TypeName(string))), (Some(age),Field(None,TypeName(int))))),AppliedType(TypeName(Person),List()))), true) diff --git a/shared/src/test/diff/basics/Datatypes.fun b/shared/src/test/diff/basics/Datatypes.fun index 1bb3531674..6dd65dc09d 100644 --- a/shared/src/test/diff/basics/Datatypes.fun +++ b/shared/src/test/diff/basics/Datatypes.fun @@ -25,7 +25,7 @@ Boolean :p :e data type Bool2 of True2 & False2 -//│ Parsed: data type Bool2 of {& True2 False2}; +//│ Parsed: data type Bool2 of {&(...True2)(...False2)}; //│ Desugared: type alias Bool2 = &[True2, False2] //│ Desugared: class &[True2, False2]: {False2 <: False2, True2 <: True2} //│ Desugared: def &: forall True2 False2. (...True2) -> (...False2) -> &[True2, False2] @@ -114,7 +114,7 @@ Tru : Boolean data type List a of Nil Cons (head: a) (tail: List a) -//│ Parsed: data type List a of {Nil; Cons '(' {head: a,} ')' '(' {tail: List a,} ')'}; +//│ Parsed: data type List(...a) of {Nil; Cons(...'(' {[head: a,]} ')')(...'(' {[tail: List(...a),]} ')')}; //│ ╔══[ERROR] not a recognized type //│ ║ l.116: Cons (head: a) (tail: List a) //│ ╙── ^^^^^^ @@ -140,7 +140,7 @@ data type List a of // TODO interpret as free type variable? :p data type Ls of LsA a -//│ Parsed: data type Ls of {LsA a}; +//│ Parsed: data type Ls of {LsA(...a)}; //│ Desugared: type alias Ls = LsA[a] //│ Desugared: class LsA[a]: {a: a} //│ Desugared: def LsA: forall a. (...a) -> LsA[a] @@ -155,7 +155,7 @@ data type Ls of LsA a :p :e data type Ls2 of LsA2 `a -//│ Parsed: data type Ls2 of {LsA2 `a}; +//│ Parsed: data type Ls2 of {LsA2(...`a)}; //│ Desugared: type alias Ls2 = LsA2[] //│ Desugared: class LsA2: {`a: 'a} //│ Desugared: def LsA2: (...'a) -> LsA2[] diff --git a/shared/src/test/diff/basics/Either.fun b/shared/src/test/diff/basics/Either.fun index bb6891f75c..7ea04bae6f 100644 --- a/shared/src/test/diff/basics/Either.fun +++ b/shared/src/test/diff/basics/Either.fun @@ -4,7 +4,7 @@ data type Either l r of Left l Right r -//│ Parsed: data type Either l r of {Left l; Right r}; +//│ Parsed: data type Either(...l)(...r) of {Left(...l); Right(...r)}; //│ Desugared: type alias Either[l, r] = Left[l, r] | Right[l, r] //│ Desugared: class Left[l, r]: {l: l} //│ Desugared: class Right[l, r]: {r: r} @@ -34,10 +34,10 @@ data type Either l r of data type Either2 (l: _) (r: _) of Left2 l Right2 r -//│ ╔══[ERROR] illegal datatype type parameter shape: '(' {l: _,} ')' +//│ ╔══[ERROR] illegal datatype type parameter shape: '(' {[l: _,]} ')' //│ ║ l.34: data type Either2 (l: _) (r: _) of //│ ╙── ^^^^^^ -//│ ╔══[ERROR] illegal datatype type parameter shape: '(' {r: _,} ')' +//│ ╔══[ERROR] illegal datatype type parameter shape: '(' {[r: _,]} ')' //│ ║ l.34: data type Either2 (l: _) (r: _) of //│ ╙── ^^^^^^ //│ ╔══[ERROR] type identifier not found: l diff --git a/shared/src/test/diff/basics/Flow.fun b/shared/src/test/diff/basics/Flow.fun index 878627f045..5005f8a42c 100644 --- a/shared/src/test/diff/basics/Flow.fun +++ b/shared/src/test/diff/basics/Flow.fun @@ -2,7 +2,7 @@ :p data L x data R x -//│ Parsed: data L x; data R x; +//│ Parsed: data L(...x); data R(...x); //│ Desugared: class L[x]: {x: x} //│ Desugared: class R[x]: {x: x} //│ Desugared: def L: forall x. (...x) -> L[x] diff --git a/shared/src/test/diff/basics/Operators.fun b/shared/src/test/diff/basics/Operators.fun index d6d82a6036..bbf5eff5cc 100644 --- a/shared/src/test/diff/basics/Operators.fun +++ b/shared/src/test/diff/basics/Operators.fun @@ -14,8 +14,8 @@ a + b :p a + b -//│ Parsed: + a {b}; -//│ Desugared: + a {b} +//│ Parsed: +(...a)(...{b}); +//│ Desugared: +(...a)(...{b}) //│ AST: App(App(Var(+), Var(a)), Blk(...)) //│ res: int @@ -29,8 +29,8 @@ a + succ a + b + c -//│ Parsed: + (succ a) {+ b {c}}; -//│ Desugared: + (succ a) {+ b {c}} +//│ Parsed: +(...(succ(...a)))(...{+(...b)(...{c})}); +//│ Desugared: +(...(succ(...a)))(...{+(...b)(...{c})}) //│ AST: App(App(Var(+), App(Var(succ), Var(a))), Blk(...)) //│ res: int @@ -38,8 +38,8 @@ succ a + succ / a + b + c -//│ Parsed: succ (+ a {+ b {c}}); -//│ Desugared: succ (+ a {+ b {c}}) +//│ Parsed: succ(...(+(...a)(...{+(...b)(...{c})}))); +//│ Desugared: succ(...(+(...a)(...{+(...b)(...{c})}))) //│ AST: App(Var(succ), App(App(Var(+), Var(a)), Blk(...))) //│ res: int @@ -53,12 +53,12 @@ a + b + c + d -//│ Parsed: + a b; + (+ a b) c; + (+ (+ a b) c) d; -//│ Desugared: + a b +//│ Parsed: +(...a)(...b); +(...(+(...a)(...b)))(...c); +(...(+(...(+(...a)(...b)))(...c)))(...d); +//│ Desugared: +(...a)(...b) //│ AST: App(App(Var(+), Var(a)), Var(b)) -//│ Desugared: + (+ a b) c +//│ Desugared: +(...(+(...a)(...b)))(...c) //│ AST: App(App(Var(+), App(App(Var(+), Var(a)), Var(b))), Var(c)) -//│ Desugared: + (+ (+ a b) c) d +//│ Desugared: +(...(+(...(+(...a)(...b)))(...c)))(...d) //│ AST: App(App(Var(+), App(App(Var(+), App(App(Var(+), Var(a)), Var(b))), Var(c))), Var(d)) //│ res: int //│ res: int @@ -72,8 +72,8 @@ a + 2 + 3 + d -//│ Parsed: + (+ (+ a b) (+ (+ c 1) (+ 2 3))) d; -//│ Desugared: + (+ (+ a b) (+ (+ c 1) (+ 2 3))) d +//│ Parsed: +(...(+(...(+(...a)(...b)))(...(+(...(+(...c)(...1)))(...(+(...2)(...3)))))))(...d); +//│ Desugared: +(...(+(...(+(...a)(...b)))(...(+(...(+(...c)(...1)))(...(+(...2)(...3)))))))(...d) //│ AST: App(App(Var(+), App(App(Var(+), App(App(Var(+), Var(a)), Var(b))), App(App(Var(+), App(App(Var(+), Var(c)), IntLit(1))), App(App(Var(+), IntLit(2)), IntLit(3))))), Var(d)) //│ res: int @@ -110,8 +110,8 @@ succ / succ 1 succ a + b + c -//│ Parsed: + (succ {+ a b}) c; -//│ Desugared: + (succ {+ a b}) c +//│ Parsed: +(...(succ(...{+(...a)(...b)})))(...c); +//│ Desugared: +(...(succ(...{+(...a)(...b)})))(...c) //│ AST: App(App(Var(+), App(Var(succ), Blk(...))), Var(c)) //│ res: int diff --git a/shared/src/test/diff/basics/Slashes.fun b/shared/src/test/diff/basics/Slashes.fun index 3f3fde492c..ef7aef7047 100644 --- a/shared/src/test/diff/basics/Slashes.fun +++ b/shared/src/test/diff/basics/Slashes.fun @@ -21,8 +21,8 @@ x => succ / succ / x + 1 :p foo / x => succ / succ / x -//│ Parsed: foo ((x) => succ (succ x)); -//│ Desugared: foo ((x) => succ (succ x)) +//│ Parsed: foo(...((...x) => succ(...(succ(...x))))); +//│ Desugared: foo(...((...x) => succ(...(succ(...x))))) //│ AST: App(Var(foo), Lam(Var(x), App(Var(succ), App(Var(succ), Var(x))))) //│ res: int diff --git a/shared/src/test/diff/basics/Tuples.fun b/shared/src/test/diff/basics/Tuples.fun index 8e6623ff7d..0ae793a335 100644 --- a/shared/src/test/diff/basics/Tuples.fun +++ b/shared/src/test/diff/basics/Tuples.fun @@ -36,8 +36,8 @@ let t = x: 1, y: 2, z: 3 :p :e (1, true, "hey").2 -//│ Parsed: '(' {1, true, "hey",} ')' 0.2; -//│ Desugared: '(' {1, true, "hey",} ')' 0.2 +//│ Parsed: '(' {[1, true, "hey",]} ')'(...0.2); +//│ Desugared: '(' {[1, true, "hey",]} ')'(...0.2) //│ AST: App(Bra(rcd = false, Blk(...)), DecLit(0.2)) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.38: (1, true, "hey").2 diff --git a/shared/src/test/diff/mlscript/ByNameByValue.mls b/shared/src/test/diff/mlscript/ByNameByValue.mls index e632a12518..e47b2b32ee 100644 --- a/shared/src/test/diff/mlscript/ByNameByValue.mls +++ b/shared/src/test/diff/mlscript/ByNameByValue.mls @@ -14,8 +14,8 @@ def incr x = x.a <- x.a + 1 :p :js def gensym = let n = { mut a = 0 } in fun () -> (incr n, n) -//│ Parsed: def gensym: let n = {mut a: 0} in () => incr (n,), n,; -//│ Desugared: def gensym: let n = {mut a: 0} in () => incr (n,), n, +//│ Parsed: def gensym: let n = {mut a: 0} in () => [incr(n,), n,]; +//│ Desugared: def gensym: let n = {mut a: 0} in () => [incr(n,), n,] //│ AST: Def(false, gensym, Let(false, n, Rcd(Var(a) = IntLit(0)), Lam(Tup(), Tup(_: App(Var(incr), Tup(_: Var(n))), _: Var(n)))), true) //│ // Query 1 //│ globalThis.gensym = function gensym() { @@ -33,8 +33,8 @@ def gensym = let n = { mut a = 0 } in fun () -> (incr n, n) :js :p gensym1 = let n = { mut a = 0 } in fun () -> (incr n, n) -//│ Parsed: let gensym1 = let n = {mut a: 0} in () => incr (n,), n,; -//│ Desugared: def gensym1: let n = {mut a: 0} in () => incr (n,), n, +//│ Parsed: let gensym1 = let n = {mut a: 0} in () => [incr(n,), n,]; +//│ Desugared: def gensym1: let n = {mut a: 0} in () => [incr(n,), n,] //│ AST: Def(false, gensym1, Let(false, n, Rcd(Var(a) = IntLit(0)), Lam(Tup(), Tup(_: App(Var(incr), Tup(_: Var(n))), _: Var(n)))), false) //│ // Query 1 //│ globalThis.gensym1 = ((n) => () => [ diff --git a/shared/src/test/diff/mlscript/MultiArgs.mls b/shared/src/test/diff/mlscript/MultiArgs.mls index 329ba9fcd5..62e7a8090d 100644 --- a/shared/src/test/diff/mlscript/MultiArgs.mls +++ b/shared/src/test/diff/mlscript/MultiArgs.mls @@ -73,10 +73,10 @@ bar((1, 2)) :p f = fun (x, y) -> add x y f(1, 2) -//│ Parsed: let f = (x, y,) => add (x,) (y,); f (1, 2,); -//│ Desugared: def f: (x, y,) => add (x,) (y,) +//│ Parsed: let f = (x, y,) => add(x,)(y,); f(1, 2,); +//│ Desugared: def f: (x, y,) => add(x,)(y,) //│ AST: Def(false, f, Lam(Tup(_: Var(x), _: Var(y)), App(App(Var(add), Tup(_: Var(x))), Tup(_: Var(y)))), false) -//│ Desugared: f (1, 2,) +//│ Desugared: f(1, 2,) //│ AST: App(Var(f), Tup(_: IntLit(1), _: IntLit(2))) //│ f: (int, int,) -> int //│ = [Function: f] @@ -117,10 +117,10 @@ f r :p f = fun ((x, y)) -> add x y f((1, 2)) -//│ Parsed: let f = ('(' x, y, ')',) => add (x,) (y,); f ('(' 1, 2, ')',); -//│ Desugared: def f: ('(' x, y, ')',) => add (x,) (y,) +//│ Parsed: let f = ('(' [x, y,] ')',) => add(x,)(y,); f('(' [1, 2,] ')',); +//│ Desugared: def f: ('(' [x, y,] ')',) => add(x,)(y,) //│ AST: Def(false, f, Lam(Tup(_: Bra(rcd = false, Tup(_: Var(x), _: Var(y)))), App(App(Var(add), Tup(_: Var(x))), Tup(_: Var(y)))), false) -//│ Desugared: f ('(' 1, 2, ')',) +//│ Desugared: f('(' [1, 2,] ')',) //│ AST: App(Var(f), Tup(_: Bra(rcd = false, Tup(_: IntLit(1), _: IntLit(2))))) //│ f: ((int, int,),) -> int //│ = [Function: f1] diff --git a/shared/src/test/diff/mlscript/Ops.mls b/shared/src/test/diff/mlscript/Ops.mls index 4bb2d45835..837b2c09e6 100644 --- a/shared/src/test/diff/mlscript/Ops.mls +++ b/shared/src/test/diff/mlscript/Ops.mls @@ -1,16 +1,16 @@ :p 2 + 2 -//│ Parsed: + (2,) (2,); -//│ Desugared: + (2,) (2,) +//│ Parsed: +(2,)(2,); +//│ Desugared: +(2,)(2,) //│ AST: App(App(Var(+), Tup(_: IntLit(2))), Tup(_: IntLit(2))) //│ res: int //│ = 4 :p 1 + 2 * 2 + 3 -//│ Parsed: + (+ (1,) (* (2,) (2,),),) (3,); -//│ Desugared: + (+ (1,) (* (2,) (2,),),) (3,) +//│ Parsed: +(+(1,)(*(2,)(2,),),)(3,); +//│ Desugared: +(+(1,)(*(2,)(2,),),)(3,) //│ AST: App(App(Var(+), Tup(_: App(App(Var(+), Tup(_: IntLit(1))), Tup(_: App(App(Var(*), Tup(_: IntLit(2))), Tup(_: IntLit(2))))))), Tup(_: IntLit(3))) //│ res: int //│ = 8 @@ -18,8 +18,8 @@ :e :p 1 + 2 / 2 + 3 -//│ Parsed: + (+ (1,) (/ (2,) (2,),),) (3,); -//│ Desugared: + (+ (1,) (/ (2,) (2,),),) (3,) +//│ Parsed: +(+(1,)(/(2,)(2,),),)(3,); +//│ Desugared: +(+(1,)(/(2,)(2,),),)(3,) //│ AST: App(App(Var(+), Tup(_: App(App(Var(+), Tup(_: IntLit(1))), Tup(_: App(App(Var(/), Tup(_: IntLit(2))), Tup(_: IntLit(2))))))), Tup(_: IntLit(3))) //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.20: 1 + 2 / 2 + 3 @@ -34,8 +34,8 @@ :ge :p 1 |> 2 || 3 -//│ Parsed: || (|> (1,) (2,),) (3,); -//│ Desugared: || (|> (1,) (2,),) (3,) +//│ Parsed: ||(|>(1,)(2,),)(3,); +//│ Desugared: ||(|>(1,)(2,),)(3,) //│ AST: App(App(Var(||), Tup(_: App(App(Var(|>), Tup(_: IntLit(1))), Tup(_: IntLit(2))))), Tup(_: IntLit(3))) //│ ╔══[ERROR] identifier not found: |> //│ ║ l.36: 1 |> 2 || 3 @@ -52,8 +52,8 @@ :p true || false && true || false -//│ Parsed: || (|| (true,) (&& (false,) (true,),),) (false,); -//│ Desugared: || (|| (true,) (&& (false,) (true,),),) (false,) +//│ Parsed: ||(||(true,)(&&(false,)(true,),),)(false,); +//│ Desugared: ||(||(true,)(&&(false,)(true,),),)(false,) //│ AST: App(App(Var(||), Tup(_: App(App(Var(||), Tup(_: Var(true))), Tup(_: App(App(Var(&&), Tup(_: Var(false))), Tup(_: Var(true))))))), Tup(_: Var(false))) //│ res: bool //│ = true diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls index c7d2b71693..25db2319d8 100644 --- a/shared/src/test/diff/nu/OverrideShorthand.mls +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -11,7 +11,7 @@ class Pair(lhs: Int, rhs: Int) fun f(override Pair(x, y)) = x + y //│ |#fun| |f|(|#override| |Pair|(|x|,| |y|)|)| |#=| |x| |+| |y| //│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(_$0)), If(IfOpApp(Var(_$0), Var(is), IfThen(App(Var(Pair), Tup(_: Var(x), _: Var(y))), App(Var(+), Tup(_: Var(x), _: Var(y))), Some(App(Sel(Super(), f), Tup(_: Var(_$0)))))))) -//│ Parsed: fun f = (_$0,) => if _$0 is (Pair (x, y,)) then + (x, y,) else (super).f (_$0,); +//│ Parsed: fun f = (_$0,) => if _$0 is (Pair(x, y,)) then +(x, y,) else (super).f(_$0,); //│ ╔══[ERROR] identifier not found: super //│ ║ l.11: fun f(override Pair(x, y)) = x + y //│ ╙── ^^^^^^^^ diff --git a/shared/src/test/diff/parser/Arrays.mls b/shared/src/test/diff/parser/Arrays.mls index f117263646..e7c41dbdd0 100644 --- a/shared/src/test/diff/parser/Arrays.mls +++ b/shared/src/test/diff/parser/Arrays.mls @@ -3,23 +3,23 @@ [] //│ |[||]| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} [1] //│ |[|1|]| -//│ Parsed: {'(' 1, ')'} +//│ Parsed: {'(' [1,] ')'} [1,] //│ |[|1|,|]| -//│ Parsed: {'(' 1, ')'} +//│ Parsed: {'(' [1,] ')'} [1, 2, 3] //│ |[|1|,| |2|,| |3|]| -//│ Parsed: {'(' 1, 2, 3, ')'} +//│ Parsed: {'(' [1, 2, 3,] ')'} () //│ |(||)| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} (1) //│ |(|1|)| @@ -31,7 +31,7 @@ (1, 2, 3) //│ |(|1|,| |2|,| |3|)| -//│ Parsed: {'(' 1, 2, 3, ')'} +//│ Parsed: {'(' [1, 2, 3,] ')'} 1 @@ -54,29 +54,29 @@ f of 1, 2, 3 //│ |f| |#of| |1|,| |2|,| |3| -//│ Parsed: {f (1, 2, 3,)} +//│ Parsed: {f(1, 2, 3,)} f of 1, 2, 3 //│ |f| |#of|→|1|,| |2|,| |3|←| -//│ Parsed: {f (1, 2, 3,)} +//│ Parsed: {f(1, 2, 3,)} f of 1, 2, 3 //│ |f| |#of|→|1|,|↵|2|,|↵|3|←| -//│ Parsed: {f (1, 2, 3,)} +//│ Parsed: {f(1, 2, 3,)} let arr = [] //│ |#let| |arr| |#=| |[||]| -//│ Parsed: {let arr = '(' ')'} +//│ Parsed: {let arr = '(' [] ')'} let arr = [ ] //│ |#let| |arr| |#=| |[|↵|]| -//│ Parsed: {let arr = '(' ')'} +//│ Parsed: {let arr = '(' [] ')'} let arr = [ @@ -87,26 +87,26 @@ let arr = //│ ║ ^ //│ ║ l.82: [ //│ ╙── -//│ Parsed: {let arr = '(' ')'} +//│ Parsed: {let arr = '(' [] ')'} let arr = [ 1 ] //│ |#let| |arr| |#=| |[|→|1|←|↵|]| -//│ Parsed: {let arr = '(' 1, ')'} +//│ Parsed: {let arr = '(' [1,] ')'} let arr = [ 1, 2 ] //│ |#let| |arr| |#=| |[|→|1|,| |2|←|↵|]| -//│ Parsed: {let arr = '(' 1, 2, ')'} +//│ Parsed: {let arr = '(' [1, 2,] ')'} let arr = [ 1, 2 ] //│ |#let| |arr| |#=| |[|→|1|,|↵|2|←|↵|]| -//│ Parsed: {let arr = '(' 1, 2, ')'} +//│ Parsed: {let arr = '(' [1, 2,] ')'} // :pe f [1, 2, 3] @@ -115,10 +115,10 @@ f [1, 2, 3] f([1, 2, 3]) //│ |f|(|[|1|,| |2|,| |3|]|)| -//│ Parsed: {f ('(' 1, 2, 3, ')',)} +//│ Parsed: {f('(' [1, 2, 3,] ')',)} f of [1, 2, 3] //│ |f| |#of| |[|1|,| |2|,| |3|]| -//│ Parsed: {f ('(' 1, 2, 3, ')',)} +//│ Parsed: {f('(' [1, 2, 3,] ')',)} diff --git a/shared/src/test/diff/parser/BasicSyntax.mls b/shared/src/test/diff/parser/BasicSyntax.mls index 0eda5558c7..7e3b3b0f98 100644 --- a/shared/src/test/diff/parser/BasicSyntax.mls +++ b/shared/src/test/diff/parser/BasicSyntax.mls @@ -9,50 +9,50 @@ f 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.7: f 1 //│ ╙── ^^^ -//│ Parsed: {f (1,)} +//│ Parsed: {f(1,)} () //│ |(||)| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} f() //│ |f|(||)| -//│ Parsed: {f ()} +//│ Parsed: {f()} f(1) //│ |f|(|1|)| -//│ Parsed: {f (1,)} +//│ Parsed: {f(1,)} f (1) //│ |f| |(|1|)| -//│ Parsed: {f (1,)} +//│ Parsed: {f(1,)} f of 1 //│ |f| |#of| |1| -//│ Parsed: {f (1,)} +//│ Parsed: {f(1,)} 1 + 1 //│ |1| |+| |1| -//│ Parsed: {+ (1,) (1,)} +//│ Parsed: {+(1,)(1,)} f 1 + 1 //│ |f| |1| |+| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.38: f 1 + 1 //│ ╙── ^^^^^^^ -//│ Parsed: {f (+ (1,) (1,),)} +//│ Parsed: {f(+(1,)(1,),)} f(1 + 1) //│ |f|(|1| |+| |1|)| -//│ Parsed: {f (+ (1,) (1,),)} +//│ Parsed: {f(+(1,)(1,),)} f of 1 + 1 //│ |f| |#of| |1| |+| |1| -//│ Parsed: {f (+ (1,) (1,),)} +//│ Parsed: {f(+(1,)(1,),)} f(1) + 1 //│ |f|(|1|)| |+| |1| -//│ Parsed: {+ (f (1,),) (1,)} +//│ Parsed: {+(f(1,),)(1,)} 1 2 3 //│ |1| |2| |3| @@ -62,21 +62,21 @@ f(1) + 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.57: 1 2 3 //│ ╙── ^^^^^ -//│ Parsed: {1 (2 (3,),)} +//│ Parsed: {1(2(3,),)} 12 3 //│ |12| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.67: 12 3 //│ ╙── ^^^^^ -//│ Parsed: {12 (3,)} +//│ Parsed: {12(3,)} 3 + 2 4 - 1 //│ |3| |+| |2| |4| |-| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.74: 3 + 2 4 - 1 //│ ╙── ^^^^^^^ -//│ Parsed: {+ (3,) (2 (- (4,) (1,),),)} +//│ Parsed: {+(3,)(2(-(4,)(1,),),)} foo bar baz 1 @@ -102,7 +102,7 @@ foo bar //│ ║ ^^^^^^^ //│ ║ l.83: 2 3 //│ ╙── ^^^^^ -//│ Parsed: {foo (bar ({baz (1,); 2 (3,)},),)} +//│ Parsed: {foo(bar({baz(1,); 2(3,)},),)} foo bar baz 1 @@ -143,14 +143,14 @@ foo bar //│ ║ ^^^^^^^ //│ ║ l.110: 4 v5 //│ ╙── ^^^^^^ -//│ Parsed: {foo (bar ({baz (1 (2 (3,),),); 4 (v5,)},),)} +//│ Parsed: {foo(bar({baz(1(2(3,),),); 4(v5,)},),)} foo of bar of baz of 1 of 2 of 3 4 of v5 //│ |foo| |#of| |bar| |#of|→|baz| |#of| |1| |#of|→|2| |#of| |3|←|↵|4| |#of| |v5|←| -//│ Parsed: {foo (bar ({baz (1 (2 (3,),),); 4 (v5,)},),)} +//│ Parsed: {foo(bar({baz(1(2(3,),),); 4(v5,)},),)} foo 1 @@ -160,52 +160,52 @@ foo //│ ║ ^^^ //│ ║ l.156: 1 //│ ╙── ^^^ -//│ Parsed: {foo (1,)} +//│ Parsed: {foo(1,)} foo of 1 //│ |foo| |#of|→|1|←| -//│ Parsed: {foo (1,)} +//│ Parsed: {foo(1,)} foo of 1 //│ |foo|→|#of| |1|←| -//│ Parsed: {foo (1,)} +//│ Parsed: {foo(1,)} foo of 1, 2, 3 //│ |foo|→|#of| |1|,| |2|,| |3|←| -//│ Parsed: {foo (1, 2, 3,)} +//│ Parsed: {foo(1, 2, 3,)} foo of (1, 2, 3) //│ |foo|→|#of| |(|1|,| |2|,| |3|)|←| -//│ Parsed: {foo ('(' 1, 2, 3, ')',)} +//│ Parsed: {foo('(' [1, 2, 3,] ')',)} foo of 1 //│ |foo|→|#of|→|1|←|←| -//│ Parsed: {foo (1,)} +//│ Parsed: {foo(1,)} // TODO foo of 1 of 2 //│ |foo|→|#of| |1|↵|#of| |2|←| -//│ Parsed: {foo (1,) (2,)} +//│ Parsed: {foo(1,)(2,)} foo of f of 2 //│ |foo|→|#of| |f|→|#of| |2|←|←| -//│ Parsed: {foo (f (2,),)} +//│ Parsed: {foo(f(2,),)} foo of 1 of 2 //│ |foo|→|#of| |1|←|→|#of| |2|←| -//│ Parsed: {foo (1,) (2,)} +//│ Parsed: {foo(1,)(2,)} //│ | | @@ -257,7 +257,7 @@ foo //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here //│ ║ l.255: 1+ //│ ╙── ^ -//│ Parsed: {+ (1,) (undefined,)} +//│ Parsed: {+(1,)(undefined,)} * //│ |*| @@ -275,15 +275,15 @@ f 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.273: f 1 //│ ╙── ^^^ -//│ Parsed: {f (1,)} +//│ Parsed: {f(1,)} f(1) //│ |f|(|1|)| -//│ Parsed: {f (1,)} +//│ Parsed: {f(1,)} f (1) //│ |f| |(|1|)| -//│ Parsed: {f (1,)} +//│ Parsed: {f(1,)} f 1, 2, 3 @@ -291,15 +291,15 @@ f 1, 2, 3 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.289: f 1, 2, 3 //│ ╙── ^^^^^^^^^ -//│ Parsed: {f (1, 2, 3,)} +//│ Parsed: {f(1, 2, 3,)} f (1, 2, 3) //│ |f| |(|1|,| |2|,| |3|)| -//│ Parsed: {f (1, 2, 3,)} +//│ Parsed: {f(1, 2, 3,)} f(1, 2, 3) //│ |f|(|1|,| |2|,| |3|)| -//│ Parsed: {f (1, 2, 3,)} +//│ Parsed: {f(1, 2, 3,)} // :pe f[] @@ -344,12 +344,12 @@ f 1,, 2 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.339: f 1,, 2 //│ ╙── ^^^^^^^ -//│ Parsed: {f (1, 2,)} +//│ Parsed: {f(1, 2,)} f of x //│ |f| |#of| |x| -//│ Parsed: {f (x,)} +//│ Parsed: {f(x,)} f g x //│ |f| |g| |x| @@ -359,18 +359,18 @@ f g x //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.354: f g x //│ ╙── ^^^^^ -//│ Parsed: {f (g (x,),)} +//│ Parsed: {f(g(x,),)} f of g of x //│ |f| |#of| |g| |#of| |x| -//│ Parsed: {f (g (x,),)} +//│ Parsed: {f(g(x,),)} f of of g //│ |f| |#of| |#of| |g| //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position //│ ║ l.368: f of of g //│ ╙── ^^ -//│ Parsed: {f (g,)} +//│ Parsed: {f(g,)} f x: 1 @@ -378,42 +378,42 @@ f x: 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.376: f x: 1 //│ ╙── ^^^^^^ -//│ Parsed: {f (x: 1,)} +//│ Parsed: {f(x: 1,)} f x: 1, //│ |f| |x|#:| |1|,| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.383: f x: 1, //│ ╙── ^^^^^^ -//│ Parsed: {f (x: 1,)} +//│ Parsed: {f(x: 1,)} f x : 1 //│ |f| |x| |#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.390: f x : 1 //│ ╙── ^^^ -//│ Parsed: {f (x : 1,)} +//│ Parsed: {f(x : 1,)} f x: 1, y: 2 //│ |f| |x|#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.397: f x: 1, y: 2 //│ ╙── ^^^^^^^^^^^^ -//│ Parsed: {f (x: 1, y: 2,)} +//│ Parsed: {f(x: 1, y: 2,)} f x : 1, y: 2 //│ |f| |x| |#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.404: f x : 1, y: 2 //│ ╙── ^^^^^^^^^^^^^ -//│ Parsed: {f (x : 1, y: 2,)} +//│ Parsed: {f(x : 1, y: 2,)} f x: 1, y: 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.411: f x: 1, y: 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^ -//│ Parsed: {f (x: 1, y: 2, z: 3,)} +//│ Parsed: {f(x: 1, y: 2, z: 3,)} f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| @@ -423,15 +423,15 @@ f x: 1, y: g 2, z: 3 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.418: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^ -//│ Parsed: {f (x: 1, y: g (2, z: 3,),)} +//│ Parsed: {f(x: 1, y: g(2, z: 3,),)} f(x: 1, y: g(2, z: 3)) //│ |f|(|x|#:| |1|,| |y|#:| |g|(|2|,| |z|#:| |3|)|)| -//│ Parsed: {f (x: 1, y: g (2, z: 3,),)} +//│ Parsed: {f(x: 1, y: g(2, z: 3,),)} f(x: 1, y: g(2), z: 3) //│ |f|(|x|#:| |1|,| |y|#:| |g|(|2|)|,| |z|#:| |3|)| -//│ Parsed: {f (x: 1, y: g (2,), z: 3,)} +//│ Parsed: {f(x: 1, y: g(2,), z: 3,)} f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| @@ -441,11 +441,11 @@ f x: 1, y: g 2, z: 3 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.436: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Parsed: {f (x: 1, y: g (2, z: 3,),)} +//│ Parsed: {f(x: 1, y: g(2, z: 3,),)} f of x: 1, y: g of 2, z: 3 //│ |f| |#of| |x|#:| |1|,| |y|#:| |g| |#of| |2|,| |z|#:| |3| -//│ Parsed: {f (x: 1, y: g (2, z: 3,),)} +//│ Parsed: {f(x: 1, y: g(2, z: 3,),)} f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ |f| |x|#:| |1| |+| |1|,| |y|#:| |2| |2|,| |z|#:| |3| |+| |2| |4| |-| |1| @@ -458,7 +458,7 @@ f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.450: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ Parsed: {f (x: + (1,) (1,), y: 2 (2, z: + (3,) (2 (- (4,) (1,),),),),)} +//│ Parsed: {f(x: +(1,)(1,), y: 2(2, z: +(3,)(2(-(4,)(1,),),),),)} x.y @@ -478,12 +478,12 @@ x.y 2 + f of 3 + 3 //│ |2| |+| |f| |#of| |3| |+| |3| -//│ Parsed: {+ (2,) (f (+ (3,) (3,),),)} +//│ Parsed: {+(2,)(f(+(3,)(3,),),)} 2 + 2 of 3 + 3 //│ |2| |+| |2|→|#of| |3| |+| |3|←| -//│ Parsed: {+ (2,) (2,) (+ (3,) (3,),)} +//│ Parsed: {+(2,)(2,)(+(3,)(3,),)} diff --git a/shared/src/test/diff/parser/Binds.mls b/shared/src/test/diff/parser/Binds.mls index 3beb9ad087..711f842512 100644 --- a/shared/src/test/diff/parser/Binds.mls +++ b/shared/src/test/diff/parser/Binds.mls @@ -3,11 +3,11 @@ f(x) is True //│ |f|(|x|)| |is| |True| -//│ Parsed: {is (f (x,),) (True,)} +//│ Parsed: {is(f(x,),)(True,)} // Precedence of 'of'/'is' may be surprising! f of x is True //│ |f| |#of| |x| |is| |True| -//│ Parsed: {f (is (x,) (True,),)} +//│ Parsed: {f(is(x,)(True,),)} diff --git a/shared/src/test/diff/parser/Blocks.mls b/shared/src/test/diff/parser/Blocks.mls index f0eaf64987..ee3801c4f8 100644 --- a/shared/src/test/diff/parser/Blocks.mls +++ b/shared/src/test/diff/parser/Blocks.mls @@ -42,28 +42,28 @@ foo //│ ║ ^^^ //│ ║ l.36: b //│ ╙── ^^^ -//│ Parsed: {foo ({a; b},)} +//│ Parsed: {foo({a; b},)} foo( a, b ) //│ |foo|(|→|a|,|↵|b|←|↵|)| -//│ Parsed: {foo (a, b,)} +//│ Parsed: {foo(a, b,)} foo( a, b, ) //│ |foo|(|→|a|,|↵|b|,|←|↵|)| -//│ Parsed: {foo (a, b,)} +//│ Parsed: {foo(a, b,)} foo( a b ) //│ |foo|(|→|a|↵|b|←|↵|)| -//│ Parsed: {foo ({a; b},)} +//│ Parsed: {foo({a; b},)} foo( a @@ -75,7 +75,7 @@ foo( //│ ║ ^^^ //│ ║ l.71: ) //│ ╙── ^ -//│ Parsed: {foo (a,)} +//│ Parsed: {foo(a,)} // TODO foo of @@ -89,26 +89,26 @@ foo of //│ ╔══[PARSE ERROR] Unexpected '=' here //│ ║ l.83: fun f = 1 //│ ╙── ^ -//│ Parsed: {foo ({a; f},)} +//│ Parsed: {foo({a; f},)} foo + a b //│ |foo| |+|→|a|↵|b|←| -//│ Parsed: {+ (foo,) ({a; b},)} +//│ Parsed: {+(foo,)({a; b},)} foo(a, b, c) foo of a, b, c //│ |foo|(|a|,| |b|,| |c|)|↵|foo| |#of| |a|,| |b|,| |c| -//│ Parsed: {foo (a, b, c,); foo (a, b, c,)} +//│ Parsed: {foo(a, b, c,); foo(a, b, c,)} foo of aaaaa, bbbbb, ccccc //│ |foo| |#of|→|aaaaa|,|↵|bbbbb|,|↵|ccccc|←| -//│ Parsed: {foo (aaaaa, bbbbb, ccccc,)} +//│ Parsed: {foo(aaaaa, bbbbb, ccccc,)} foo of a @@ -124,14 +124,14 @@ foo of //│ ║ ^^^^^ //│ ║ l.117: y //│ ╙── ^^^^^ -//│ Parsed: {foo ({a; boo ({x; y},); c},)} +//│ Parsed: {foo({a; boo({x; y},); c},)} fun foo = print("ok") print("ko") //│ |#fun| |foo| |#=|→|print|(|"ok"|)|↵|print|(|"ko"|)|←| -//│ Parsed: {fun foo = {print ("ok",); print ("ko",)}} +//│ Parsed: {fun foo = {print("ok",); print("ko",)}} fun foo = @@ -140,14 +140,14 @@ fun foo = print("ko") //│ |#fun| |foo| |#=|→|print|(|"ok"|)|↵|print|(|"ko"|)|↵|←| -//│ Parsed: {fun foo = {print ("ok",); print ("ko",)}} +//│ Parsed: {fun foo = {print("ok",); print("ko",)}} fun foo = fun local(x) = x + 1 print(local(1)) class Foo //│ |#fun| |foo| |#=|→|#fun| |local|(|x|)| |#=| |x| |+| |1|↵|print|(|local|(|1|)|)|↵|#class| |Foo|←| -//│ Parsed: {fun foo = {fun local = (x,) => + (x,) (1,); print (local (1,),); class Foo() {}}} +//│ Parsed: {fun foo = {fun local = (x,) => +(x,)(1,); print(local(1,),); class Foo {}}} fun foo = fun local(x) = @@ -161,6 +161,6 @@ fun foo = print of local of 0 + local of 1 fun tmp = 2 //│ |#fun| |foo| |#=|→|#fun| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| -//│ Parsed: {fun foo = {fun local = (x,) => {class Foo() {fun bar = + (x,) (1,)}; (Foo ()).bar}; print (+ (local (0,),) (local (1,),),); print (+ ('(' local (0,) ')',) (local (1,),),); fun tmp = 1; print (local (+ (0,) (local (1,),),),); fun tmp = 2}} +//│ Parsed: {fun foo = {fun local = (x,) => {class Foo {fun bar = +(x,)(1,)}; (Foo()).bar}; print(+(local(0,),)(local(1,),),); print(+('(' local(0,) ')',)(local(1,),),); fun tmp = 1; print(local(+(0,)(local(1,),),),); fun tmp = 2}} diff --git a/shared/src/test/diff/parser/Brackets.mls b/shared/src/test/diff/parser/Brackets.mls index 18f339b85c..a6df1948f4 100644 --- a/shared/src/test/diff/parser/Brackets.mls +++ b/shared/src/test/diff/parser/Brackets.mls @@ -1,11 +1,11 @@ () //│ |(||)| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} [] //│ |[||]| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} {} //│ |{||}| @@ -20,11 +20,11 @@ //│ ║ l.15: (} //│ ╙── ^ //│ |(||)| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} (([{}])) //│ |(|(|[|{||}|]|)|)| -//│ Parsed: {'(' '(' '(' '{' {} '}', ')' ')' ')'} +//│ Parsed: {'(' '(' '(' ['{' {} '}',] ')' ')' ')'} :pe (([{})]) @@ -41,10 +41,10 @@ //│ ║ l.30: (([{})]) //│ ╙── ^ //│ |(|(|[|{||}|]|)|)| -//│ Parsed: {'(' '(' '(' '{' {} '}', ')' ')' ')'} +//│ Parsed: {'(' '(' '(' ['{' {} '}',] ')' ')' ')'} fun f = () //│ |#fun| |f| |#=| |(||)| -//│ Parsed: {fun f = '(' ')'} +//│ Parsed: {fun f = '(' [] ')'} diff --git a/shared/src/test/diff/parser/Classes.mls b/shared/src/test/diff/parser/Classes.mls index cd53006828..dddfdd359c 100644 --- a/shared/src/test/diff/parser/Classes.mls +++ b/shared/src/test/diff/parser/Classes.mls @@ -2,17 +2,17 @@ class Foo //│ |#class| |Foo| -//│ Parsed: {class Foo() {}} +//│ Parsed: {class Foo {}} class Foo {} //│ |#class| |Foo| |{||}| -//│ Parsed: {class Foo() {}} +//│ Parsed: {class Foo {}} class Foo { fun foo: int } //│ |#class| |Foo| |{|→|#fun| |foo|#:| |int|←|↵|}| -//│ Parsed: {class Foo() {fun foo: int}} +//│ Parsed: {class Foo {fun foo: int}} class Foo { class Bar { @@ -20,15 +20,15 @@ class Foo { } } //│ |#class| |Foo| |{|→|#class| |Bar| |{|→|#class| |Baz|←|↵|}|←|↵|}| -//│ Parsed: {class Foo() {class Bar() {class Baz() {}}}} +//│ Parsed: {class Foo {class Bar {class Baz {}}}} class Foo: Bar //│ |#class| |Foo|#:| |Bar| -//│ Parsed: {class Foo(): Bar {}} +//│ Parsed: {class Foo: Bar {}} class Foo extends Bar, Baz //│ |#class| |Foo| |#extends| |Bar|,| |Baz| -//│ Parsed: {class Foo(): Bar, Baz {}} +//│ Parsed: {class Foo: Bar, Baz {}} :pe class Foo: Bar, Baz @@ -36,15 +36,15 @@ class Foo: Bar, Baz //│ ╔══[PARSE ERROR] Expected end of input; found comma instead //│ ║ l.34: class Foo: Bar, Baz //│ ╙── ^ -//│ Parsed: {class Foo(): Bar {}} +//│ Parsed: {class Foo: Bar {}} class Foo: Bar { fun f = 0 } //│ |#class| |Foo|#:| |Bar| |{| |#fun| |f| |#=| |0| |}| -//│ Parsed: {class Foo(): Bar {fun f = 0}} +//│ Parsed: {class Foo: Bar {fun f = 0}} class Foo extends Bar, Baz { fun f = 0 } //│ |#class| |Foo| |#extends| |Bar|,| |Baz| |{| |#fun| |f| |#=| |0| |}| -//│ Parsed: {class Foo(): Bar, Baz {fun f = 0}} +//│ Parsed: {class Foo: Bar, Baz {fun f = 0}} :pe class Foo: Bar, Baz { fun f = 0 } @@ -52,7 +52,7 @@ class Foo: Bar, Baz { fun f = 0 } //│ ╔══[PARSE ERROR] Expected end of input; found comma instead //│ ║ l.50: class Foo: Bar, Baz { fun f = 0 } //│ ╙── ^ -//│ Parsed: {class Foo(): Bar {}} +//│ Parsed: {class Foo: Bar {}} // * Pretty confusing... better reject this: :pe @@ -72,7 +72,7 @@ class Foo: Bar { fun f = 0 //│ ║ ^ //│ ║ l.61: fun bar = 1 //│ ╙── ^^^^^^^^^ -//│ Parsed: {class Foo(): Bar {fun f = 0 (bar,)}} +//│ Parsed: {class Foo: Bar {fun f = 0(bar,)}} // TODO disallow? (i.e., require unindent before closing brace) // :e @@ -81,14 +81,14 @@ class Foo: Bar { fun bar = 1 } //│ |#class| |Foo|#:| |Bar| |{|→|#fun| |f| |#=| |0|↵|#fun| |bar| |#=| |1|↵|←|}| -//│ Parsed: {class Foo(): Bar {fun f = 0; fun bar = 1}} +//│ Parsed: {class Foo: Bar {fun f = 0; fun bar = 1}} class Foo: Bar { fun f = 0 fun bar = 1 } //│ |#class| |Foo|#:| |Bar| |{|→|#fun| |f| |#=| |0|↵|#fun| |bar| |#=| |1|←|↵|}| -//│ Parsed: {class Foo(): Bar {fun f = 0; fun bar = 1}} +//│ Parsed: {class Foo: Bar {fun f = 0; fun bar = 1}} class Foo: Bar { @@ -98,20 +98,20 @@ class Foo: Bar { } //│ |#class| |Foo|#:| |Bar| |{|→|#fun| |f| |#=| |0|↵|#fun| |bar| |#=| |1|←|↵|}| -//│ Parsed: {class Foo(): Bar {fun f = 0; fun bar = 1}} +//│ Parsed: {class Foo: Bar {fun f = 0; fun bar = 1}} class Foo: Bar { } //│ |#class| |Foo|#:| |Bar| |{|↵|}| -//│ Parsed: {class Foo(): Bar {}} +//│ Parsed: {class Foo: Bar {}} fun foo = class Foo: Bar { } //│ |#fun| |foo| |#=|→|#class| |Foo|#:| |Bar| |{|↵|}|←| -//│ Parsed: {fun foo = {class Foo(): Bar {}}} +//│ Parsed: {fun foo = {class Foo: Bar {}}} class Foo() //│ |#class| |Foo|(||)| @@ -130,10 +130,10 @@ class Foo(x, y, z): Bar(z, x) { fun blah(x) = x + y } //│ |#class| |Foo|(|x|,| |y|,| |z|)|#:| |Bar|(|z|,| |x|)| |{|→|#fun| |blah|(|x|)| |#=| |x| |+| |y|←|↵|}| -//│ Parsed: {class Foo(x, y, z,): Bar[z, x] {fun blah = (x,) => + (x,) (y,)}} +//│ Parsed: {class Foo(x, y, z,): Bar[z, x] {fun blah = (x,) => +(x,)(y,)}} class Foo(x, y) extends Bar(y, x), Baz(x + y) //│ |#class| |Foo|(|x|,| |y|)| |#extends| |Bar|(|y|,| |x|)|,| |Baz|(|x| |+| |y|)| -//│ Parsed: {class Foo(x, y,): Bar (y, x,), Baz (+ (x,) (y,),) {}} +//│ Parsed: {class Foo(x, y,): Bar(y, x,), Baz(+(x,)(y,),) {}} diff --git a/shared/src/test/diff/parser/Comments.mls b/shared/src/test/diff/parser/Comments.mls index 9d52a520bc..1d3949e079 100644 --- a/shared/src/test/diff/parser/Comments.mls +++ b/shared/src/test/diff/parser/Comments.mls @@ -21,5 +21,5 @@ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.17: 1 //│ ╙── ^ -//│ Parsed: {1 (); 2} +//│ Parsed: {1(); 2} diff --git a/shared/src/test/diff/parser/ControversialIfSplits.mls b/shared/src/test/diff/parser/ControversialIfSplits.mls index 79fc46c831..e3c82524ce 100644 --- a/shared/src/test/diff/parser/ControversialIfSplits.mls +++ b/shared/src/test/diff/parser/ControversialIfSplits.mls @@ -16,7 +16,7 @@ if f of //│ ╟── Note: 'if' expression started here: //│ ║ l.4: if f of //│ ╙── ^^ -//│ Parsed: {if (f (0,)) then undefined} +//│ Parsed: {if (f(0,)) then undefined} if f ( 0 then "ok" @@ -38,7 +38,7 @@ if f ( //│ ╟── Note: 'if' expression started here: //│ ║ l.21: if f ( //│ ╙── ^^ -//│ Parsed: {if (f (0,)) then undefined} +//│ Parsed: {if (f(0,)) then undefined} if f of 0 then "ok" @@ -56,7 +56,7 @@ if f of //│ ╟── Note: 'if' expression started here: //│ ║ l.43: if f of //│ ╙── ^^ -//│ Parsed: {if (f (0,)) then undefined} +//│ Parsed: {if (f(0,)) then undefined} if f of 0 is 0 then "ok" @@ -73,7 +73,7 @@ if f of //│ ╟── Note: 'if' expression started here: //│ ║ l.61: if f of //│ ╙── ^^ -//│ Parsed: {if (f (is (0,) (0,),)) then undefined} +//│ Parsed: {if (f(is(0,)(0,),)) then undefined} diff --git a/shared/src/test/diff/parser/Forall.mls b/shared/src/test/diff/parser/Forall.mls index a46c24f1b3..9cf0e04451 100644 --- a/shared/src/test/diff/parser/Forall.mls +++ b/shared/src/test/diff/parser/Forall.mls @@ -5,7 +5,7 @@ forall 'a; 'a => 'a forall 'a, 'b; ('a, 'b) => ('b, 'a) //│ |#forall| |'a|,| |'b|#;| |(|'a|,| |'b|)| |=>| |(|'b|,| |'a|)| -//│ Parsed: {forall 'a, 'b. ('a, 'b,) => '(' 'b, 'a, ')'} +//│ Parsed: {forall 'a, 'b. ('a, 'b,) => '(' ['b, 'a,] ')'} fun f: forall 'a; 'a => 'a //│ |#fun| |f|#:| |#forall| |'a|#;| |'a| |=>| |'a| diff --git a/shared/src/test/diff/parser/Fun.mls b/shared/src/test/diff/parser/Fun.mls index 781fc59a32..c1a3f21808 100644 --- a/shared/src/test/diff/parser/Fun.mls +++ b/shared/src/test/diff/parser/Fun.mls @@ -46,7 +46,7 @@ let f = fun x => x f(x) + x //│ |f|(|x|)| |+| |x| -//│ Parsed: {+ (f (x,),) (x,)} +//│ Parsed: {+(f(x,),)(x,)} fun f(x, y) = x @@ -90,40 +90,40 @@ fun f x y = x fun f(x, y)(a, b) = x + y * a / b //│ |#fun| |f|(|x|,| |y|)|(|a|,| |b|)| |#=| |x| |+| |y| |*| |a| |/| |b| -//│ Parsed: {fun f = (x, y,) => (a, b,) => / (+ (x,) (* (y,) (a,),),) (b,)} +//│ Parsed: {fun f = (x, y,) => (a, b,) => /(+(x,)(*(y,)(a,),),)(b,)} fun f(x, y) of a, b = x + y * a / b //│ |#fun| |f|(|x|,| |y|)| |#of| |a|,| |b| |#=| |x| |+| |y| |*| |a| |/| |b| -//│ Parsed: {fun f = (x, y,) => (a, b,) => / (+ (x,) (* (y,) (a,),),) (b,)} +//│ Parsed: {fun f = (x, y,) => (a, b,) => /(+(x,)(*(y,)(a,),),)(b,)} fun f of x, y of a, b = x + y * a / b //│ |#fun| |f| |#of| |x|,| |y| |#of| |a|,| |b| |#=| |x| |+| |y| |*| |a| |/| |b| -//│ Parsed: {fun f = (x, y (a, b,),) => / (+ (x,) (* (y,) (a,),),) (b,)} +//│ Parsed: {fun f = (x, y(a, b,),) => /(+(x,)(*(y,)(a,),),)(b,)} fun f(Some(x)) = x //│ |#fun| |f|(|Some|(|x|)|)| |#=| |x| -//│ Parsed: {fun f = (Some (x,),) => x} +//│ Parsed: {fun f = (Some(x,),) => x} fun f(Some of x) = x //│ |#fun| |f|(|Some| |#of| |x|)| |#=| |x| -//│ Parsed: {fun f = (Some (x,),) => x} +//│ Parsed: {fun f = (Some(x,),) => x} fun f of Some of x = x //│ |#fun| |f| |#of| |Some| |#of| |x| |#=| |x| -//│ Parsed: {fun f = (Some (x,),) => x} +//│ Parsed: {fun f = (Some(x,),) => x} fun f(Some(x), Some(y)) = x //│ |#fun| |f|(|Some|(|x|)|,| |Some|(|y|)|)| |#=| |x| -//│ Parsed: {fun f = (Some (x,), Some (y,),) => x} +//│ Parsed: {fun f = (Some(x,), Some(y,),) => x} fun f(Some of x, Some of y) = x + y //│ |#fun| |f|(|Some| |#of| |x|,| |Some| |#of| |y|)| |#=| |x| |+| |y| -//│ Parsed: {fun f = (Some (x, Some (y,),),) => + (x,) (y,)} +//│ Parsed: {fun f = (Some(x, Some(y,),),) => +(x,)(y,)} fun f of Some of x, Some of y = x + y //│ |#fun| |f| |#of| |Some| |#of| |x|,| |Some| |#of| |y| |#=| |x| |+| |y| -//│ Parsed: {fun f = (Some (x, Some (y,),),) => + (x,) (y,)} +//│ Parsed: {fun f = (Some(x, Some(y,),),) => +(x,)(y,)} fun f(x: Int, y: Int) = x diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 152a9895ee..79d96cec6a 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -7,25 +7,25 @@ if true then 1 else 2 if a == 0 then "false" else 2 //│ |#if| |a| |==| |0|↵|#then| |"false"| |#else| |2| -//│ Parsed: {if (== (a,) (0,)) then "false" else 2} +//│ Parsed: {if (==(a,)(0,)) then "false" else 2} if a == 0 then "false" else 2 //│ |#if| |a| |==| |0|↵|#then| |"false"|↵|#else| |2| -//│ Parsed: {if (== (a,) (0,)) then "false" else 2} +//│ Parsed: {if (==(a,)(0,)) then "false" else 2} if a == 0 then "false" else 2 //│ |#if| |a| |==| |0|→|#then| |"false"|↵|#else| |2|←| -//│ Parsed: {if (== (a,) (0,)) then "false" else 2} +//│ Parsed: {if (==(a,)(0,)) then "false" else 2} if a == 0 then "false" else 2 //│ |#if| |a| |==| |0|↵|#then| |"false"|→|#else| |2|←| -//│ Parsed: {if (== (a,) (0,)) then "false" else 2} +//│ Parsed: {if (==(a,)(0,)) then "false" else 2} :pe if a == 0 @@ -35,19 +35,19 @@ else 2 //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause //│ ║ l.33: else 2 //│ ╙── ^^^^^^ -//│ Parsed: {if (== (a,) (0,)) then "false"; undefined} +//│ Parsed: {if (==(a,)(0,)) then "false"; undefined} if a == 0 then "false" print of "ok!" //│ |#if| |a| |==| |0|→|#then| |"false"|←|↵|print| |#of| |"ok!"| -//│ Parsed: {if (== (a,) (0,)) then "false"; print ("ok!",)} +//│ Parsed: {if (==(a,)(0,)) then "false"; print("ok!",)} if a == 0 then "false" else 2 print of "ok!" //│ |#if| |a| |==| |0| |#then| |"false"|→|#else| |2|←|↵|print| |#of| |"ok!"| -//│ Parsed: {if (== (a,) (0,)) then "false" else 2; print ("ok!",)} +//│ Parsed: {if (==(a,)(0,)) then "false" else 2; print("ok!",)} if true then "true" @@ -59,13 +59,13 @@ if a == 1 then "true" b == 2 then "false" //│ |#if|→|a| |==| |1| |#then| |"true"|↵|b| |==| |2| |#then| |"false"|←| -//│ Parsed: {if ‹(== (a,) (1,)) then "true"; (== (b,) (2,)) then "false"›} +//│ Parsed: {if ‹(==(a,)(1,)) then "true"; (==(b,)(2,)) then "false"›} if a == 0 then "false" a == 1 then "true" //│ |#if|→|a| |==| |0| |#then| |"false"|↵|a| |==| |1| |#then| |"true"|←| -//│ Parsed: {if ‹(== (a,) (0,)) then "false"; (== (a,) (1,)) then "true"›} +//│ Parsed: {if ‹(==(a,)(0,)) then "false"; (==(a,)(1,)) then "true"›} if a == 0 then "false" @@ -149,7 +149,7 @@ if a is Some(x) then "defined" None then "undefined" //│ |#if| |a| |is|→|Some|(|x|)| |#then| |"defined"|↵|None| |#then| |"undefined"|←| -//│ Parsed: {if a is ‹(Some (x,)) then "defined"; (None) then "undefined"›} +//│ Parsed: {if a is ‹(Some(x,)) then "defined"; (None) then "undefined"›} if a is Some(x) and x is @@ -157,36 +157,36 @@ if a is Right(b) then "right-defined" None then "undefined" //│ |#if| |a| |is|→|Some|(|x|)| |and| |x| |is|→|Left|(|a|)| |#then| |"left-defined"|↵|Right|(|b|)| |#then| |"right-defined"|←|↵|None| |#then| |"undefined"|←| -//│ Parsed: {if a is ‹Some (x,) and x is ‹(Left (a,)) then "left-defined"; (Right (b,)) then "right-defined"›; (None) then "undefined"›} +//│ Parsed: {if a is ‹Some(x,) and x is ‹(Left(a,)) then "left-defined"; (Right(b,)) then "right-defined"›; (None) then "undefined"›} if a is Some of x then "defined" None then "undefined" //│ |#if| |a| |is|→|Some| |#of| |x| |#then| |"defined"|↵|None| |#then| |"undefined"|←| -//│ Parsed: {if a is ‹(Some (x,)) then "defined"; (None) then "undefined"›} +//│ Parsed: {if a is ‹(Some(x,)) then "defined"; (None) then "undefined"›} if a is Some(x) then "defined" _ then "unknown" //│ |#if| |a| |is|→|Some|(|x|)| |#then| |"defined"|↵|_| |#then| |"unknown"|←| -//│ Parsed: {if a is ‹(Some (x,)) then "defined"; (_) then "unknown"›} +//│ Parsed: {if a is ‹(Some(x,)) then "defined"; (_) then "unknown"›} if a is Some(x) then "defined" else "unknown" //│ |#if| |a| |is|→|Some|(|x|)| |#then| |"defined"|↵|#else| |"unknown"|←| -//│ Parsed: {if a is ‹(Some (x,)) then "defined"; else "unknown"›} +//│ Parsed: {if a is ‹(Some(x,)) then "defined"; else "unknown"›} if a is Some(x) then "defined" else "unknown" else "unreachable?!" //│ |#if| |a| |is|→|Some|(|x|)| |#then| |"defined"|↵|#else| |"unknown"|↵|#else| |"unreachable?!"|←| -//│ Parsed: {if a is ‹(Some (x,)) then "defined"; else "unknown"; else "unreachable?!"›} +//│ Parsed: {if a is ‹(Some(x,)) then "defined"; else "unknown"; else "unreachable?!"›} a == 1 and b == 2 //│ |a| |==| |1| |and| |b| |==| |2| -//│ Parsed: {and (== (a,) (1,),) (== (b,) (2,),)} +//│ Parsed: {and(==(a,)(1,),)(==(b,)(2,),)} :pe @@ -293,17 +293,17 @@ if a == 2 and b == 0 //│ |2| |and| |b| |==| |0| -//│ Parsed: {and (2,) (== (b,) (0,),)} +//│ Parsed: {and(2,)(==(b,)(0,),)} if x == 2 and b then "" //│ |#if| |x| |==|→|2| |and| |b| |#then| |""|←| -//│ Parsed: {if x == ‹(and (2,) (b,)) then ""›} +//│ Parsed: {if x == ‹(and(2,)(b,)) then ""›} if x == 2 and b == 1 then "" //│ |#if| |x| |==|→|2| |and| |b| |==| |1| |#then| |""|←| -//│ Parsed: {if x == ‹(and (2,) (== (b,) (1,),)) then ""›} +//│ Parsed: {if x == ‹(and(2,)(==(b,)(1,),)) then ""›} if x == 0 then "x" @@ -312,7 +312,7 @@ if 2 and z == 0 then "z = 0" 3 then "y = 3" //│ |#if|→|x| |==| |0| |#then| |"x"|↵|y| |==|→|1| |#then| |"y = 1"|↵|2| |and| |z| |==| |0| |#then| |"z = 0"|↵|3| |#then| |"y = 3"|←|←| -//│ Parsed: {if ‹(== (x,) (0,)) then "x"; y == ‹(1) then "y = 1"; (and (2,) (== (z,) (0,),)) then "z = 0"; (3) then "y = 3"››} +//│ Parsed: {if ‹(==(x,)(0,)) then "x"; y == ‹(1) then "y = 1"; (and(2,)(==(z,)(0,),)) then "z = 0"; (3) then "y = 3"››} :pe else 1 @@ -345,7 +345,7 @@ if a is let y = a + 1 Right(0) then y //│ |#if| |a| |is|→|Left|(|x|)| |#then| |x|↵|#let| |y| |#=| |a| |+| |1|↵|Right|(|0|)| |#then| |y|←| -//│ Parsed: {if a is ‹(Left (x,)) then x; let y = + (a,) (1,); (Right (0,)) then y›} +//│ Parsed: {if a is ‹(Left(x,)) then x; let y = +(a,)(1,); (Right(0,)) then y›} if a is Some(v) and v is @@ -355,7 +355,7 @@ if a is Right(x) then x + y else 0 //│ |#if| |a| |is|→|Some|(|v|)| |and| |v| |is|→|Left|(|x|)| |#then| |x|↵|#let| |y| |#=| |v| |+| |1|↵|Right|(|0|)| |#then| |y|↵|Right|(|x|)| |#then| |x| |+| |y|←|↵|#else| |0|←| -//│ Parsed: {if a is ‹Some (v,) and v is ‹(Left (x,)) then x; let y = + (v,) (1,); (Right (0,)) then y; (Right (x,)) then + (x,) (y,)›; else 0›} +//│ Parsed: {if a is ‹Some(v,) and v is ‹(Left(x,)) then x; let y = +(v,)(1,); (Right(0,)) then y; (Right(x,)) then +(x,)(y,)›; else 0›} if a is Some(x) and x is @@ -364,7 +364,7 @@ if a is Right(b) then "right-defined" None then "undefined" //│ |#if| |a| |is|→|Some|(|x|)| |and| |x| |is|→|Left|(|a|)| |#then| |"left-defined"|↵|#let| |y| |#=| |x| |+| |1|↵|Right|(|b|)| |#then| |"right-defined"|←|↵|None| |#then| |"undefined"|←| -//│ Parsed: {if a is ‹Some (x,) and x is ‹(Left (a,)) then "left-defined"; let y = + (x,) (1,); (Right (b,)) then "right-defined"›; (None) then "undefined"›} +//│ Parsed: {if a is ‹Some(x,) and x is ‹(Left(a,)) then "left-defined"; let y = +(x,)(1,); (Right(b,)) then "right-defined"›; (None) then "undefined"›} :w if a is @@ -373,7 +373,7 @@ if a is //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.371: Left x then x //│ ╙── ^^^^^^ -//│ Parsed: {if a is ‹(Left (x,)) then x›} +//│ Parsed: {if a is ‹(Left(x,)) then x›} // TODO if a is @@ -386,7 +386,7 @@ if a is //│ ║ ^^^^^ //│ ║ l.382: then y //│ ╙── ^^^^^^^^ -//│ Parsed: {if a is ‹(Left (x,)) then x; let y = undefined›} +//│ Parsed: {if a is ‹(Left(x,)) then x; let y = undefined›} @@ -437,7 +437,7 @@ if let Some(x) = v and cond then 123 // MLscript: if v is Some(x) and x is Left(y) then 123 //│ |#if| |v| |is| |Some|(|x|)| |and| |x| |is| |Left|(|y|)| |#then| |123| -//│ Parsed: {if (and (is (v,) (Some (x,),),) (is (x,) (Left (y,),),)) then 123} +//│ Parsed: {if (and(is(v,)(Some(x,),),)(is(x,)(Left(y,),),)) then 123} // ML: let Some(x) = v @@ -446,7 +446,7 @@ let Some(x) = v v as Some(x) //│ |v| |as| |Some|(|x|)| -//│ Parsed: {as (v,) (Some (x,),)} +//│ Parsed: {as(v,)(Some(x,),)} @@ -465,7 +465,7 @@ if true then 0 + 1 //│ |#if| |true|→|#then| |0|→|+| |1|←|←| -//│ Parsed: {if (true) then + 0 1} +//│ Parsed: {if (true) then +(...0)(...1)} if true then 0 @@ -478,7 +478,7 @@ if true else 0 + 1 //│ |#if| |true|→|#then| |0|↵|#else| |0|→|+| |1|←|←| -//│ Parsed: {if (true) then 0 else + 0 1} +//│ Parsed: {if (true) then 0 else +(...0)(...1)} :pe if true @@ -504,12 +504,12 @@ if true if true then 0 + 1 //│ |#if| |true| |#then| |0|→|+| |1|←| -//│ Parsed: {if (true) then + 0 1} +//│ Parsed: {if (true) then +(...0)(...1)} if true then 0 else 0 + 1 //│ |#if| |true| |#then| |0| |#else| |0|→|+| |1|←| -//│ Parsed: {if (true) then 0 else + 0 1} +//│ Parsed: {if (true) then 0 else +(...0)(...1)} // TODO deal with meaningless whitespace: @@ -561,7 +561,7 @@ if true then; else; if true then () else; //│ |#if| |true| |#then| |(||)| |#else|#;| -//│ Parsed: {if (true) then '(' ')' else undefined} +//│ Parsed: {if (true) then '(' [] ')' else undefined} diff --git a/shared/src/test/diff/parser/Lambdas.mls b/shared/src/test/diff/parser/Lambdas.mls index 89240fd873..b0de021f2d 100644 --- a/shared/src/test/diff/parser/Lambdas.mls +++ b/shared/src/test/diff/parser/Lambdas.mls @@ -65,7 +65,7 @@ x => a --> b --> c //│ |a| |-->| |b| |-->| |c| -//│ Parsed: {--> (a,) (--> (b,) (c,),)} +//│ Parsed: {-->(a,)(-->(b,)(c,),)} a => b => c //│ |a| |=>| |b| |=>| |c| @@ -81,11 +81,11 @@ a => (b => c) xs.forall(x => x > 0) //│ |xs|.forall|(|x| |=>| |x| |>| |0|)| -//│ Parsed: {(xs).forall ((x,) => > (x,) (0,),)} +//│ Parsed: {(xs).forall((x,) => >(x,)(0,),)} xs.forall of x => x > 0 //│ |xs|.forall| |#of| |x| |=>| |x| |>| |0| -//│ Parsed: {(xs).forall ((x,) => > (x,) (0,),)} +//│ Parsed: {(xs).forall((x,) => >(x,)(0,),)} :pe a => b then c @@ -101,11 +101,11 @@ if a => b then c if xs.forall(a => b) then c //│ |#if| |xs|.forall|(|a| |=>| |b|)| |#then| |c| -//│ Parsed: {if ((xs).forall ((a,) => b,)) then c} +//│ Parsed: {if ((xs).forall((a,) => b,)) then c} if xs.forall of a => b then c //│ |#if| |xs|.forall| |#of| |a| |=>| |b| |#then| |c| -//│ Parsed: {if ((xs).forall ((a,) => b,)) then c} +//│ Parsed: {if ((xs).forall((a,) => b,)) then c} id + of x => x + 1 @@ -113,5 +113,5 @@ id + of x => x + 1 //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position //│ ║ l.111: id + of x => x + 1 //│ ╙── ^^ -//│ Parsed: {+ (id,) ((x,) => + (x,) (1,),)} +//│ Parsed: {+(id,)((x,) => +(x,)(1,),)} diff --git a/shared/src/test/diff/parser/Lets.mls b/shared/src/test/diff/parser/Lets.mls index 4c1f7e2ad0..a23ddda654 100644 --- a/shared/src/test/diff/parser/Lets.mls +++ b/shared/src/test/diff/parser/Lets.mls @@ -49,7 +49,7 @@ let in 123 let x = 1; x + 1 //│ |#let| |x| |#=| |1|#;| |x| |+| |1| -//│ Parsed: {let x = 1; + (x,) (1,)} +//│ Parsed: {let x = 1; +(x,)(1,)} let x = 1, y = 2; x + y //│ |#let| |x| |#=| |1|,| |y| |#=| |2|#;| |x| |+| |y| diff --git a/shared/src/test/diff/parser/Misc.mls b/shared/src/test/diff/parser/Misc.mls index eccf0ec21a..e0dec04ced 100644 --- a/shared/src/test/diff/parser/Misc.mls +++ b/shared/src/test/diff/parser/Misc.mls @@ -3,7 +3,7 @@ fun discard(x) = () //│ |#fun| |discard|(|x|)| |#=| |(||)| -//│ Parsed: {fun discard = (x,) => '(' ')'} +//│ Parsed: {fun discard = (x,) => '(' [] ')'} // FIXME parses wrong: foo of @@ -53,7 +53,7 @@ foo of //│ ╟── Note: 'if' expression started here: //│ ║ l.13: if g of y is //│ ╙── ^^ -//│ Parsed: {foo ({discard (if (f (undefined,)) then undefined,); if (g (undefined,)) then undefined},)} +//│ Parsed: {foo({discard(if (f(undefined,)) then undefined,); if (g(undefined,)) then undefined},)} foo of if f of x is @@ -120,21 +120,21 @@ foo of //│ ╟── Note: 'if' expression started here: //│ ║ l.62: if g of y is //│ ╙── ^^ -//│ Parsed: {foo ({if (f (undefined,)) then undefined; if (g (undefined,)) then undefined},)} +//│ Parsed: {foo({if (f(undefined,)) then undefined; if (g(undefined,)) then undefined},)} print of Foo(x) is Some //│ |print| |#of| |Foo|(|x|)| |is| |Some| -//│ Parsed: {print (is (Foo (x,),) (Some,),)} +//│ Parsed: {print(is(Foo(x,),)(Some,),)} // FIXME parses wrong: if f of x is Some then 1 else 0 //│ |#if| |f| |#of| |x| |is| |Some| |#then| |1| |#else| |0| -//│ Parsed: {if (f (is (x,) (Some,),)) then 1 else 0} +//│ Parsed: {if (f(is(x,)(Some,),)) then 1 else 0} if f of 0 and g of 1 then "ok" //│ |#if| |f| |#of| |0| |and| |g| |#of| |1| |#then| |"ok"| -//│ Parsed: {if (f (and (0,) (g (1,),),)) then "ok"} +//│ Parsed: {if (f(and(0,)(g(1,),),)) then "ok"} A and B or C and D //│ |A| |and| |B| |or| |C| |and| |D| -//│ Parsed: {or (and (A,) (B,),) (and (C,) (D,),)} +//│ Parsed: {or(and(A,)(B,),)(and(C,)(D,),)} diff --git a/shared/src/test/diff/parser/MultiLineCalls.mls b/shared/src/test/diff/parser/MultiLineCalls.mls index feb1bf2b9f..3a0b774424 100644 --- a/shared/src/test/diff/parser/MultiLineCalls.mls +++ b/shared/src/test/diff/parser/MultiLineCalls.mls @@ -5,34 +5,34 @@ f ( 0 ) //│ |f| |(|→|0|←|↵|)| -//│ Parsed: {f (0,)} +//│ Parsed: {f(0,)} f ( 0, 1 ) //│ |f| |(|→|0|,|↵|1|←|↵|)| -//│ Parsed: {f (0, 1,)} +//│ Parsed: {f(0, 1,)} f ( 0, 1, ) //│ |f| |(|→|0|,|↵|1|,|←|↵|)| -//│ Parsed: {f (0, 1,)} +//│ Parsed: {f(0, 1,)} f (0, 1) //│ |f| |(|0|,| |1|)| -//│ Parsed: {f (0, 1,)} +//│ Parsed: {f(0, 1,)} f (0, 1,) //│ |f| |(|0|,| |1|,|)| -//│ Parsed: {f (0, 1,)} +//│ Parsed: {f(0, 1,)} f (0, 1, ) //│ |f| |(|0|,| |1|,|↵|)| -//│ Parsed: {f (0, 1,)} +//│ Parsed: {f(0, 1,)} f(,) //│ |f|(|,|)| @@ -42,26 +42,26 @@ f(,) //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.37: f(,) //│ ╙── ^ -//│ Parsed: {f (undefined,)} +//│ Parsed: {f(undefined,)} f ( 0 1 ) //│ |f| |(|→|0|↵|1|←|↵|)| -//│ Parsed: {f ({0; 1},)} +//│ Parsed: {f({0; 1},)} f of 0, 1 //│ |f| |#of|→|0|,|↵|1|←| -//│ Parsed: {f (0, 1,)} +//│ Parsed: {f(0, 1,)} f of 0 1 //│ |f| |#of|→|0|↵|1|←| -//│ Parsed: {f ({0; 1},)} +//│ Parsed: {f({0; 1},)} // :pe f @@ -75,36 +75,36 @@ of 0 f (0) //│ |f|→|(|0|)|←| -//│ Parsed: {f (0,)} +//│ Parsed: {f(0,)} // TODO f of 0 of 1 //│ |f|→|#of| |0|↵|#of| |1|←| -//│ Parsed: {f (0,) (1,)} +//│ Parsed: {f(0,)(1,)} f (0) (1) //│ |f|→|(|0|)|↵|(|1|)|←| -//│ Parsed: {f (0,) (1,)} +//│ Parsed: {f(0,)(1,)} f of 0, 1 //│ |f|→|#of|→|0|,|↵|1|←|←| -//│ Parsed: {f (0, 1,)} +//│ Parsed: {f(0, 1,)} 2 + 2 (0) //│ |2| |+| |2|→|(|0|)|←| -//│ Parsed: {+ (2,) (2,) (0,)} +//│ Parsed: {+(2,)(2,)(0,)} 2 + 2 of 0 //│ |2| |+| |2|→|#of| |0|←| -//│ Parsed: {+ (2,) (2,) (0,)} +//│ Parsed: {+(2,)(2,)(0,)} diff --git a/shared/src/test/diff/parser/MultilineFun.mls b/shared/src/test/diff/parser/MultilineFun.mls index c08618d758..bf9cf21abf 100644 --- a/shared/src/test/diff/parser/MultilineFun.mls +++ b/shared/src/test/diff/parser/MultilineFun.mls @@ -28,18 +28,18 @@ x) = x fun f(x, y) = x + y //│ |#fun| |f|(|x|,|→|y|←|)| |#=| |x| |+| |y| -//│ Parsed: {fun f = (x, {y},) => + (x,) (y,)} +//│ Parsed: {fun f = (x, {y},) => +(x,)(y,)} fun f( x, y) = x + y //│ |#fun| |f|(|→|x|,|↵|y|←|)| |#=| |x| |+| |y| -//│ Parsed: {fun f = (x, y,) => + (x,) (y,)} +//│ Parsed: {fun f = (x, y,) => +(x,)(y,)} fun f( x, y ) = x + y //│ |#fun| |f|(|→|x|,|↵|y|←|↵|)| |#=| |x| |+| |y| -//│ Parsed: {fun f = (x, y,) => + (x,) (y,)} +//│ Parsed: {fun f = (x, y,) => +(x,)(y,)} diff --git a/shared/src/test/diff/parser/NamedArrays.mls b/shared/src/test/diff/parser/NamedArrays.mls index c9c224e3f0..5feeda316b 100644 --- a/shared/src/test/diff/parser/NamedArrays.mls +++ b/shared/src/test/diff/parser/NamedArrays.mls @@ -3,33 +3,33 @@ [] //│ |[||]| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} [x: 1] //│ |[|x|#:| |1|]| -//│ Parsed: {'(' x: 1, ')'} +//│ Parsed: {'(' [x: 1,] ')'} [x : 1] //│ |[|x| |#:| |1|]| -//│ Parsed: {'(' x : 1, ')'} +//│ Parsed: {'(' [x : 1,] ')'} [x: 1,] //│ |[|x|#:| |1|,|]| -//│ Parsed: {'(' x: 1, ')'} +//│ Parsed: {'(' [x: 1,] ')'} [x: 1, y:] //│ |[|x|#:| |1|,| |y|#:|]| //│ ╔══[PARSE ERROR] Unexpected end of square bracket section; an expression was expected here //│ ║ l.20: [x: 1, y:] //│ ╙── ^ -//│ Parsed: {'(' x: 1, y: undefined, ')'} +//│ Parsed: {'(' [x: 1, y: undefined,] ')'} [x:, y: 1] //│ |[|x|#:|,| |y|#:| |1|]| //│ ╔══[PARSE ERROR] Unexpected comma in expression position //│ ║ l.27: [x:, y: 1] //│ ╙── ^ -//│ Parsed: {'(' x: y : 1, ')'} +//│ Parsed: {'(' [x: y : 1,] ')'} [x:, y:] //│ |[|x|#:|,| |y|#:|]| @@ -39,50 +39,50 @@ //│ ╔══[PARSE ERROR] Unexpected end of square bracket section; an expression was expected here //│ ║ l.34: [x:, y:] //│ ╙── ^ -//│ Parsed: {'(' x: y : undefined, ')'} +//│ Parsed: {'(' [x: y : undefined,] ')'} [x: 1, 2, 3] //│ |[|x|#:| |1|,| |2|,| |3|]| -//│ Parsed: {'(' x: 1, 2, 3, ')'} +//│ Parsed: {'(' [x: 1, 2, 3,] ')'} [1, y: 2, 3] //│ |[|1|,| |y|#:| |2|,| |3|]| -//│ Parsed: {'(' 1, y: 2, 3, ')'} +//│ Parsed: {'(' [1, y: 2, 3,] ')'} [x: 1, y: 2, z: 3] //│ |[|x|#:| |1|,| |y|#:| |2|,| |z|#:| |3|]| -//│ Parsed: {'(' x: 1, y: 2, z: 3, ')'} +//│ Parsed: {'(' [x: 1, y: 2, z: 3,] ')'} () //│ |(||)| -//│ Parsed: {'(' ')'} +//│ Parsed: {'(' [] ')'} (x: 1) //│ |(|x|#:| |1|)| -//│ Parsed: {'(' x: 1, ')'} +//│ Parsed: {'(' [x: 1,] ')'} (x:) //│ |(|x|#:|)| //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.64: (x:) //│ ╙── ^ -//│ Parsed: {'(' x: undefined, ')'} +//│ Parsed: {'(' [x: undefined,] ')'} (x: 1,) //│ |(|x|#:| |1|,|)| -//│ Parsed: {'(' x: 1, ')'} +//│ Parsed: {'(' [x: 1,] ')'} (x: 1, 2, 3) //│ |(|x|#:| |1|,| |2|,| |3|)| -//│ Parsed: {'(' x: 1, 2, 3, ')'} +//│ Parsed: {'(' [x: 1, 2, 3,] ')'} (1, y: 2, 3) //│ |(|1|,| |y|#:| |2|,| |3|)| -//│ Parsed: {'(' 1, y: 2, 3, ')'} +//│ Parsed: {'(' [1, y: 2, 3,] ')'} (x: 1, y: 2, z: 3) //│ |(|x|#:| |1|,| |y|#:| |2|,| |z|#:| |3|)| -//│ Parsed: {'(' x: 1, y: 2, z: 3, ')'} +//│ Parsed: {'(' [x: 1, y: 2, z: 3,] ')'} 1 @@ -116,27 +116,27 @@ x: 1, f of 1, 2, 3 //│ |f| |#of| |1|,| |2|,| |3| -//│ Parsed: {f (1, 2, 3,)} +//│ Parsed: {f(1, 2, 3,)} f of x: 1, y: 2, z: 3 //│ |f| |#of| |x|#:| |1|,| |y|#:| |2|,| |z|#:| |3| -//│ Parsed: {f (x: 1, y: 2, z: 3,)} +//│ Parsed: {f(x: 1, y: 2, z: 3,)} f of x: 1, 2, z: 3 //│ |f| |#of| |x|#:| |1|,| |2|,| |z|#:| |3| -//│ Parsed: {f (x: 1, 2, z: 3,)} +//│ Parsed: {f(x: 1, 2, z: 3,)} f of x: 1, 2, 3 //│ |f| |#of|→|x|#:| |1|,| |2|,| |3|←| -//│ Parsed: {f (x: 1, 2, 3,)} +//│ Parsed: {f(x: 1, 2, 3,)} f of x: 1, y: 2, z: 3 //│ |f| |#of|→|x|#:| |1|,|↵|y|#:| |2|,|↵|z|#:| |3|←| -//│ Parsed: {f (x: 1, y: 2, z: 3,)} +//│ Parsed: {f(x: 1, y: 2, z: 3,)} f of x: 1 @@ -149,7 +149,7 @@ f of //│ ╔══[PARSE ERROR] Unexpected named argument name here //│ ║ l.143: y: 2 //│ ╙── ^ -//│ Parsed: {f (z: {1; 2; 3},)} +//│ Parsed: {f(z: {1; 2; 3},)} f of x: 1 @@ -159,7 +159,7 @@ f of //│ ╔══[PARSE ERROR] Unexpected named argument name here //│ ║ l.155: x: 1 //│ ╙── ^ -//│ Parsed: {f (z: {1; 2; 3},)} +//│ Parsed: {f(z: {1; 2; 3},)} f of x: 1 @@ -172,7 +172,7 @@ f of //│ ╔══[PARSE ERROR] Unexpected named argument name here //│ ║ l.166: y: 2 //│ ╙── ^ -//│ Parsed: {f ({1; 2; 3},)} +//│ Parsed: {f({1; 2; 3},)} diff --git a/shared/src/test/diff/parser/NegativeLits.mls b/shared/src/test/diff/parser/NegativeLits.mls index 79c8446d84..6dbcfff444 100644 --- a/shared/src/test/diff/parser/NegativeLits.mls +++ b/shared/src/test/diff/parser/NegativeLits.mls @@ -3,7 +3,7 @@ type MinusOne = -1 //│ |#type| |MinusOne| |#=| |-1| -//│ Parsed: {type alias MinusOne(): -1 {}} +//│ Parsed: {type alias MinusOne: -1 {}} fun f(x: MinusOne) = x //│ |#fun| |f|(|x|#:| |MinusOne|)| |#=| |x| @@ -11,4 +11,4 @@ fun f(x: MinusOne) = x f(-1) //│ |f|(|-1|)| -//│ Parsed: {f (-1,)} +//│ Parsed: {f(-1,)} diff --git a/shared/src/test/diff/parser/New.mls b/shared/src/test/diff/parser/New.mls index 249164a5f3..3bdc464a75 100644 --- a/shared/src/test/diff/parser/New.mls +++ b/shared/src/test/diff/parser/New.mls @@ -26,35 +26,35 @@ new {} new A //│ |#new| |A| -//│ Parsed: {new A() {}} +//│ Parsed: {new A([]) {}} new A() //│ |#new| |A|(||)| -//│ Parsed: {new A() {}} +//│ Parsed: {new A([]) {}} new A(1, 2, 3) //│ |#new| |A|(|1|,| |2|,| |3|)| -//│ Parsed: {new A(1, 2, 3,) {}} +//│ Parsed: {new A([1, 2, 3,]) {}} new A of 1, 2, 3 //│ |#new| |A| |#of| |1|,| |2|,| |3| -//│ Parsed: {new A(1, 2, 3,) {}} +//│ Parsed: {new A([1, 2, 3,]) {}} new A { fun x = 1 } //│ |#new| |A| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A() {fun x = 1}} +//│ Parsed: {new A([]) {fun x = 1}} new A() { fun x = 1 } //│ |#new| |A|(||)| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A() {fun x = 1}} +//│ Parsed: {new A([]) {fun x = 1}} new A(1, 2, 3) { fun x = 1 } //│ |#new| |A|(|1|,| |2|,| |3|)| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A(1, 2, 3,) {fun x = 1}} +//│ Parsed: {new A([1, 2, 3,]) {fun x = 1}} new A of 1, 2, 3 { fun x = 1 } //│ |#new| |A| |#of| |1|,| |2|,| |3| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A(1, 2, 3,) {fun x = 1}} +//│ Parsed: {new A([1, 2, 3,]) {fun x = 1}} :pe diff --git a/shared/src/test/diff/parser/Ops.mls b/shared/src/test/diff/parser/Ops.mls index a86338ee14..796d53e6fe 100644 --- a/shared/src/test/diff/parser/Ops.mls +++ b/shared/src/test/diff/parser/Ops.mls @@ -3,7 +3,7 @@ acc + 1 //│ |acc| |+| |1| -//│ Parsed: {+ (acc,) (1,)} +//│ Parsed: {+(acc,)(1,)} acc + 1 @@ -16,12 +16,12 @@ acc acc + 1 //│ |acc|→|+| |1|←| -//│ Parsed: {+ acc 1} +//│ Parsed: {+(...acc)(...1)} acc + 1 //│ |acc| |+|→|1|←| -//│ Parsed: {+ (acc,) ({1},)} +//│ Parsed: {+(acc,)({1},)} acc + @@ -32,34 +32,34 @@ acc //│ ║ ^ //│ ║ l.28: 1 //│ ╙── ^^ -//│ Parsed: {+ acc 1} +//│ Parsed: {+(...acc)(...1)} acc + 1 //│ |acc|→|+|→|1|←|←| -//│ Parsed: {+ acc {1}} +//│ Parsed: {+(...acc)(...{1})} acc + 1 * 3 //│ |acc|→|+| |1|↵|*| |3|←| -//│ Parsed: {* (+ acc 1) 3} +//│ Parsed: {*(...(+(...acc)(...1)))(...3)} acc + 1 + 2 * 3 //│ |acc|→|+| |1|↵|+| |2|↵|*| |3|←| -//│ Parsed: {* (+ (+ acc 1) 2) 3} +//│ Parsed: {*(...(+(...(+(...acc)(...1)))(...2)))(...3)} acc + 1 + 2 * 3 //│ |acc| |+| |1| |+| |2| |*| |3| -//│ Parsed: {+ (+ (acc,) (1,),) (* (2,) (3,),)} +//│ Parsed: {+(+(acc,)(1,),)(*(2,)(3,),)} acc+1+2*3 //│ |acc|+|1|+|2|*|3| -//│ Parsed: {+ (+ (acc,) (1,),) (* (2,) (3,),)} +//│ Parsed: {+(+(acc,)(1,),)(*(2,)(3,),)} acc + foo bar @@ -68,41 +68,41 @@ acc + //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.65: foo bar //│ ╙── ^^^^^^^ -//│ Parsed: {+ (acc,) ({foo (bar,); baz},)} +//│ Parsed: {+(acc,)({foo(bar,); baz},)} a+ b c //│ |a|+|→|b|↵|c|←| -//│ Parsed: {+ (a,) ({b; c},)} +//│ Parsed: {+(a,)({b; c},)} a+ b c //│ |a|+|→|b|←|↵|c| -//│ Parsed: {+ (a,) ({b},); c} +//│ Parsed: {+(a,)({b},); c} a +b c //│ |a|→|+|b|←|↵|c| -//│ Parsed: {+ a b; c} +//│ Parsed: {+(...a)(...b); c} a + b * 2 //│ |a| |+| |b|→|*| |2|←| -//│ Parsed: {+ (a,) (* b 2,)} +//│ Parsed: {+(a,)(*(...b)(...2),)} a(b) * 2 //│ |a|(|b|)|→|*| |2|←| -//│ Parsed: {* (a (b,)) 2} +//│ Parsed: {*(...(a(b,)))(...2)} a of b * 2 //│ |a| |#of| |b|→|*| |2|←| -//│ Parsed: {a (* b 2,)} +//│ Parsed: {a(*(...b)(...2),)} a then b * 2 @@ -119,26 +119,26 @@ a + b + 1 * 3 //│ |a| |+| |b|→|*| |2|↵|+| |1|↵|*| |3|←| -//│ Parsed: {+ (a,) (* (+ (* b 2) 1) 3,)} +//│ Parsed: {+(a,)(*(...(+(...(*(...b)(...2)))(...1)))(...3),)} a + b * 2 + 1 //│ |a| |+| |b|→|*| |2|→|+| |1|←|←| -//│ Parsed: {+ (a,) (* b (+ 2 1),)} +//│ Parsed: {+(a,)(*(...b)(...(+(...2)(...1))),)} a + b * 2 - 1 //│ |a| |+| |b|→|*| |2|←|→|-| |1|←| -//│ Parsed: {- (+ (a,) (* b 2,)) 1} +//│ Parsed: {-(...(+(a,)(*(...b)(...2),)))(...1)} a + b * 2 + 1 * 3 //│ |a| |+| |b|→|*| |2|→|+| |1|←|↵|*| |3|←| -//│ Parsed: {+ (a,) (* (* b (+ 2 1)) 3,)} +//│ Parsed: {+(a,)(*(...(*(...b)(...(+(...2)(...1)))))(...3),)} a + b @@ -152,7 +152,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.147: * 3 //│ ╙── ^ -//│ Parsed: {+ (a,) ({* b 2; 1; 3},)} +//│ Parsed: {+(a,)({*(...b)(...2); 1; 3},)} a + b @@ -163,7 +163,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.160: + 1 //│ ╙── ^ -//│ Parsed: {* (+ (a,) ({* b 2; 1},)) 3} +//│ Parsed: {*(...(+(a,)({*(...b)(...2); 1},)))(...3)} a + b @@ -175,7 +175,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.171: + //│ ╙── ^ -//│ Parsed: {+ (a,) ({* b 2; {* 1 3}},)} +//│ Parsed: {+(a,)({*(...b)(...2); {*(...1)(...3)}},)} a + b @@ -184,7 +184,7 @@ a + 1 * 3 //│ |a| |+|→|b|→|*| |2|↵|+|→|1|→|*| |3|←|←|←|←| -//│ Parsed: {+ (a,) ({+ (* b 2) {* 1 3}},)} +//│ Parsed: {+(a,)({+(...(*(...b)(...2)))(...{*(...1)(...3)})},)} a + b @@ -195,7 +195,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.192: + 1 //│ ╙── ^ -//│ Parsed: {+ (a,) ({* b 2; * 1 3},)} +//│ Parsed: {+(a,)({*(...b)(...2); *(...1)(...3)},)} a + b @@ -203,25 +203,25 @@ a + + 1 * 3 //│ |a| |+|→|b|→|*| |2|↵|+| |1|→|*| |3|←|←|←| -//│ Parsed: {+ (a,) ({+ (* b 2) (* 1 3)},)} +//│ Parsed: {+(a,)({+(...(*(...b)(...2)))(...(*(...1)(...3)))},)} a + b * c //│ |a| |+|→|b| |*|→|c|←|←| -//│ Parsed: {+ (a,) ({* (b,) ({c},)},)} +//│ Parsed: {+(a,)({*(b,)({c},)},)} a * b + c //│ |a| |*|→|b| |+|→|c|←|←| -//│ Parsed: {* (a,) ({+ (b,) ({c},)},)} +//│ Parsed: {*(a,)({+(b,)({c},)},)} a * let x = 1 b + c //│ |a| |*|→|#let| |x| |#=| |1|↵|b| |+|→|c|←|←| -//│ Parsed: {* (a,) ({let x = 1; + (b,) ({c},)},)} +//│ Parsed: {*(a,)({let x = 1; +(b,)({c},)},)} diff --git a/shared/src/test/diff/parser/Select.mls b/shared/src/test/diff/parser/Select.mls index b1a7ae70bd..76f786894c 100644 --- a/shared/src/test/diff/parser/Select.mls +++ b/shared/src/test/diff/parser/Select.mls @@ -5,11 +5,11 @@ x.a x . a //│ |x| |.| |a| -//│ Parsed: {. (x,) (a,)} +//│ Parsed: {.(x,)(a,)} x. a //│ |x|.| |a| -//│ Parsed: {. (x,) (a,)} +//│ Parsed: {.(x,)(a,)} x .a //│ |x| |.a| @@ -103,32 +103,32 @@ a .b .c a + 1 .c //│ |a| |+| |1| |.c| -//│ Parsed: {+ (a,) ((1).c,)} +//│ Parsed: {+(a,)((1).c,)} a + f(1) .c //│ |a| |+| |f|(|1|)| |.c| -//│ Parsed: {+ (a,) ((f (1,)).c,)} +//│ Parsed: {+(a,)((f(1,)).c,)} a + f (1) .c //│ |a| |+| |f| |(|1|)| |.c| -//│ Parsed: {+ (a,) ((f (1,)).c,)} +//│ Parsed: {+(a,)((f(1,)).c,)} a + f (1).c //│ |a| |+| |f| |(|1|)|.c| -//│ Parsed: {+ (a,) ((f (1,)).c,)} +//│ Parsed: {+(a,)((f(1,)).c,)} f of x . y //│ |f| |#of| |x| |.| |y| -//│ Parsed: {f (. (x,) (y,),)} +//│ Parsed: {f(.(x,)(y,),)} f of x .y //│ |f| |#of| |x| |.y| -//│ Parsed: {f ((x).y,)} +//│ Parsed: {f((x).y,)} a + b .c //│ |a| |+| |b|→|.c|←| -//│ Parsed: {(+ (a,) (b,)).c} +//│ Parsed: {(+(a,)(b,)).c} :pe a + @@ -141,44 +141,44 @@ a + //│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here //│ ║ l.136: .c //│ ╙── ^ -//│ Parsed: {+ (a,) ({b; undefined},)} +//│ Parsed: {+(a,)({b; undefined},)} a + b .c //│ |a| |+|→|b|→|.c|←|←| -//│ Parsed: {+ (a,) ({(b).c},)} +//│ Parsed: {+(a,)({(b).c},)} a + b .c * 2 .d - 1 //│ |a| |+| |b|→|.c| |*| |2|→|.d| |-| |1|←|←| -//│ Parsed: {- ((* ((+ (a,) (b,)).c,) (2,)).d,) (1,)} +//│ Parsed: {-((*((+(a,)(b,)).c,)(2,)).d,)(1,)} a + b .c * 2 .d - 1 //│ |a| |+| |b|→|.c| |*| |2|↵|.d| |-| |1|←| -//│ Parsed: {- ((* ((+ (a,) (b,)).c,) (2,)).d,) (1,)} +//│ Parsed: {-((*((+(a,)(b,)).c,)(2,)).d,)(1,)} a .b of c //│ |a|→|.b|↵|#of| |c|←| -//│ Parsed: {(a).b (c,)} +//│ Parsed: {(a).b(c,)} a .b + 1 of c //│ |a|→|.b| |+| |1|↵|#of| |c|←| -//│ Parsed: {+ ((a).b,) (1,) (c,)} +//│ Parsed: {+((a).b,)(1,)(c,)} a .b + 1 of c //│ |a|→|.b| |+| |1|→|#of| |c|←|←| -//│ Parsed: {+ ((a).b,) (1,) (c,)} +//│ Parsed: {+((a).b,)(1,)(c,)} :pe a @@ -189,35 +189,35 @@ a //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position //│ ║ l.187: of c //│ ╙── ^^ -//│ Parsed: {+ ((a).b,) ({1; c},)} +//│ Parsed: {+((a).b,)({1; c},)} a .b + 1 of c //│ |a|→|.b| |+|→|1|→|#of| |c|←|←|←| -//│ Parsed: {+ ((a).b,) ({1 (c,)},)} +//│ Parsed: {+((a).b,)({1(c,)},)} a .b of c .d //│ |a|→|.b|↵|#of| |c|↵|.d|←| -//│ Parsed: {((a).b (c,)).d} +//│ Parsed: {((a).b(c,)).d} a .b of c .d //│ |a|→|.b|→|#of| |c|←|↵|.d|←| -//│ Parsed: {((a).b (c,)).d} +//│ Parsed: {((a).b(c,)).d} a .b +1 *2 //│ |a|→|.b|↵|+|1|↵|*|2|←| -//│ Parsed: {* (+ ((a).b,) (1,),) (2,)} +//│ Parsed: {*(+((a).b,)(1,),)(2,)} // TODO we should find a more uniform way of typing indented operator/selector/of blocks a @@ -228,24 +228,24 @@ a //│ ╔══[PARSE ERROR] Unexpected selector in operator block //│ ║ l.226: .b //│ ╙── ^^ -//│ Parsed: {* (+ a 1) 2} +//│ Parsed: {*(...(+(...a)(...1)))(...2)} 1 .+ 2 //│ |1| |.+| |2| -//│ Parsed: {.+ (1,) (2,)} +//│ Parsed: {.+(1,)(2,)} 1 +. 2 //│ |1| |+.| |2| -//│ Parsed: {+. (1,) (2,)} +//│ Parsed: {+.(1,)(2,)} 1 .+! 2 //│ |1| |.+!| |2| -//│ Parsed: {.+! (1,) (2,)} +//│ Parsed: {.+!(1,)(2,)} 0 * 1 .+. 2 * 3 //│ |0| |*| |1| |.+.| |2| |*| |3| -//│ Parsed: {* (* (0,) (.+. (1,) (2,),),) (3,)} +//│ Parsed: {*(*(0,)(.+.(1,)(2,),),)(3,)} :w 1 .+a 2 @@ -253,6 +253,6 @@ a //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.251: 1 .+a 2 //│ ╙── ^^^ -//│ Parsed: {.+ (1,) (a (2,),)} +//│ Parsed: {.+(1,)(a(2,),)} diff --git a/shared/src/test/diff/parser/SpecParams.mls b/shared/src/test/diff/parser/SpecParams.mls index 44cb4d192b..d31db8c1a4 100644 --- a/shared/src/test/diff/parser/SpecParams.mls +++ b/shared/src/test/diff/parser/SpecParams.mls @@ -3,15 +3,15 @@ fun Foo(#x, y) = x + y //│ |#fun| |Foo|(|##|x|,| |y|)| |#=| |x| |+| |y| -//│ Parsed: {fun Foo = (#x, y,) => + (x,) (y,)} +//│ Parsed: {fun Foo = (#x, y,) => +(x,)(y,)} fun Foo(x, #y) = x + y //│ |#fun| |Foo|(|x|,| |##|y|)| |#=| |x| |+| |y| -//│ Parsed: {fun Foo = (x, #y,) => + (x,) (y,)} +//│ Parsed: {fun Foo = (x, #y,) => +(x,)(y,)} fun Foo(#x, #y, #z) = if z then x + y else z //│ |#fun| |Foo|(|##|x|,| |##|y|,| |##|z|)| |#=| |#if| |z| |#then| |x| |+| |y| |#else| |z| -//│ Parsed: {fun Foo = (#x, #y, #z,) => if (z) then + (x,) (y,) else z} +//│ Parsed: {fun Foo = (#x, #y, #z,) => if (z) then +(x,)(y,) else z} class Foo(x, #y, z) diff --git a/shared/src/test/diff/parser/Subscripts.mls b/shared/src/test/diff/parser/Subscripts.mls index 2ab3b1bee5..21846e563a 100644 --- a/shared/src/test/diff/parser/Subscripts.mls +++ b/shared/src/test/diff/parser/Subscripts.mls @@ -13,7 +13,7 @@ a.x[0].y[1].z a + b [0] * 2 //│ |a| |+| |b| |[|0|]| |*| |2| -//│ Parsed: {+ (a,) (* (b‹0›,) (2,),)} +//│ Parsed: {+(a,)(*(b‹0›,)(2,),)} foo [1] @@ -23,60 +23,60 @@ foo Foo(bar) + 1 ["hello"] //│ |Foo|(|bar|)| |+| |1|→|[|"hello"|]|←| -//│ Parsed: {+ (Foo (bar,),) (1,)‹"hello"›} +//│ Parsed: {+(Foo(bar,),)(1,)‹"hello"›} Foo(bar) + 1["hello"] //│ |Foo|(|bar|)| |+|→|1|[|"hello"|]|←| -//│ Parsed: {+ (Foo (bar,),) ({1‹"hello"›},)} +//│ Parsed: {+(Foo(bar,),)({1‹"hello"›},)} Foo(bar) + 1 ["hello"] //│ |Foo|(|bar|)| |+|→|1|→|[|"hello"|]|←|←| -//│ Parsed: {+ (Foo (bar,),) ({1‹"hello"›},)} +//│ Parsed: {+(Foo(bar,),)({1‹"hello"›},)} Foo(bar) + 1 [1] [2] //│ |Foo|(|bar|)| |+| |1|→|[|1|]|↵|[|2|]|←| -//│ Parsed: {+ (Foo (bar,),) (1,)‹1›‹2›} +//│ Parsed: {+(Foo(bar,),)(1,)‹1›‹2›} Foo(bar) + 1 [1] [2] //│ |Foo|(|bar|)| |+| |1|→|[|1|]|→|[|2|]|←|←| -//│ Parsed: {+ (Foo (bar,),) (1,)‹1›‹2›} +//│ Parsed: {+(Foo(bar,),)(1,)‹1›‹2›} a + 111 [22] [333] //│ |a| |+|→|111|→|[|22|]|←|↵|[|333|]|←| -//│ Parsed: {+ (a,) ({111‹22›; '(' 333, ')'},)} +//│ Parsed: {+(a,)({111‹22›; '(' [333,] ')'},)} Foo(bar) + 1 [1] [2] //│ |Foo|(|bar|)| |+|→|1|→|[|1|]|←|↵|[|2|]|←| -//│ Parsed: {+ (Foo (bar,),) ({1‹1›; '(' 2, ')'},)} +//│ Parsed: {+(Foo(bar,),)({1‹1›; '(' [2,] ')'},)} a of [333] //│ |a| |#of| |[|333|]| -//│ Parsed: {a ('(' 333, ')',)} +//│ Parsed: {a('(' [333,] ')',)} a of [333] //│ |a| |#of|→|[|333|]|←| -//│ Parsed: {a ('(' 333, ')',)} +//│ Parsed: {a('(' [333,] ')',)} a of 111 [22] [333] //│ |a| |#of|→|111|→|[|22|]|←|↵|[|333|]|←| -//│ Parsed: {a ({111‹22›; '(' 333, ')'},)} +//│ Parsed: {a({111‹22›; '(' [333,] ')'},)} a( 111 @@ -84,5 +84,5 @@ a( [333] ) //│ |a|(|→|111|→|[|22|]|←|↵|[|333|]|←|↵|)| -//│ Parsed: {a ({111‹22›; '(' 333, ')'},)} +//│ Parsed: {a({111‹22›; '(' [333,] ')'},)} diff --git a/shared/src/test/diff/parser/TypeParams.mls b/shared/src/test/diff/parser/TypeParams.mls index 6a624b55b2..a6e1ae383c 100644 --- a/shared/src/test/diff/parser/TypeParams.mls +++ b/shared/src/test/diff/parser/TypeParams.mls @@ -2,13 +2,13 @@ class Foo //│ |#class| |Foo|‹|A|›| -//│ Parsed: {class Foo‹A›() {}} +//│ Parsed: {class Foo‹A› {}} class Foo‹A› //│ |#class| |Foo|‹|A|›| -//│ Parsed: {class Foo‹A›() {}} +//│ Parsed: {class Foo‹A› {}} (1) @@ -26,15 +26,15 @@ foo<1, 2, 3> foo<1, 2, 3>() //│ |foo|‹|1|,| |2|,| |3|›|(||)| -//│ Parsed: {foo‹1, 2, 3› ()} +//│ Parsed: {foo‹1, 2, 3›()} foo<1, 2, 3>(1, 2, 3) //│ |foo|‹|1|,| |2|,| |3|›|(|1|,| |2|,| |3|)| -//│ Parsed: {foo‹1, 2, 3› (1, 2, 3,)} +//│ Parsed: {foo‹1, 2, 3›(1, 2, 3,)} 1 < 2 > 4 //│ |1| |<| |2| |>| |4| -//│ Parsed: {> (< (1,) (2,),) (4,)} +//│ Parsed: {>(<(1,)(2,),)(4,)} :w 1 < 2> 4 @@ -43,7 +43,7 @@ foo<1, 2, 3>(1, 2, 3) //│ ║ ^ //│ ╙── Add spaces around it if you intended to use `<` as an operator //│ |1| |<| |2|>| |4| -//│ Parsed: {> (< (1,) (2,),) (4,)} +//│ Parsed: {>(<(1,)(2,),)(4,)} :pe :w @@ -56,7 +56,7 @@ foo<1, 2, 3>(1, 2, 3) //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.50: 1< 2 > 4 //│ ╙── ^^^^^^^^ -//│ Parsed: {> (2,) (4 (1,),)} +//│ Parsed: {>(2,)(4(1,),)} :w 1< 2> 4 @@ -64,19 +64,19 @@ foo<1, 2, 3>(1, 2, 3) //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.62: 1< 2> 4 //│ ╙── ^^^^^^^ -//│ Parsed: {1‹2› (4,)} +//│ Parsed: {1‹2›(4,)} 1< 2> (4) //│ |1|‹| |2|›| |(|4|)| -//│ Parsed: {1‹2› (4,)} +//│ Parsed: {1‹2›(4,)} 1<2>(4) //│ |1|‹|2|›|(|4|)| -//│ Parsed: {1‹2› (4,)} +//│ Parsed: {1‹2›(4,)} 1<>2 //│ |1|<>|2| -//│ Parsed: {<> (1,) (2,)} +//│ Parsed: {<>(1,)(2,)} :pe 1< >2 @@ -88,7 +88,7 @@ foo<1, 2, 3>(1, 2, 3) //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.82: 1< >2 //│ ╙── ^ -//│ Parsed: {2 (1,)} +//│ Parsed: {2(1,)} :pe 1 < >2 @@ -96,25 +96,25 @@ foo<1, 2, 3>(1, 2, 3) //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.94: 1 < >2 //│ ╙── ^ -//│ Parsed: {< (1,) (2,)} +//│ Parsed: {<(1,)(2,)} foo(1, 2, 3) & Bar("ok") //│ |foo|‹|S|,| |T|›|(|1|,| |2|,| |3|)| |&| |Bar|‹|U|›|(|"ok"|)| -//│ Parsed: {& (foo‹S, T› (1, 2, 3,),) (Bar‹U› ("ok",),)} +//│ Parsed: {&(foo‹S, T›(1, 2, 3,),)(Bar‹U›("ok",),)} foo(2 + 3) & Bar("ok") //│ |foo|‹|Str|,| |Int|›|(|2| |+| |3|)| |&| |Bar|‹|MyClass|›|(|"ok"|)| -//│ Parsed: {& (foo‹Str, Int› (+ (2,) (3,),),) (Bar‹MyClass› ("ok",),)} +//│ Parsed: {&(foo‹Str, Int›(+(2,)(3,),),)(Bar‹MyClass›("ok",),)} // :pe foo[S, T](1, 2, 3) & Bar[U]("ok") //│ |foo|[|S|,| |T|]|(|1|,| |2|,| |3|)| |&| |Bar|[|U|]|(|"ok"|)| -//│ Parsed: {& (foo‹S, T› (1, 2, 3,),) (Bar‹U› ("ok",),)} +//│ Parsed: {&(foo‹S, T›(1, 2, 3,),)(Bar‹U›("ok",),)} class Foo {} //│ |#class| |Foo|‹|T|›| |{||}| -//│ Parsed: {class Foo‹T›() {}} +//│ Parsed: {class Foo‹T› {}} fun foo(x: T): string = "rua" //│ |#fun| |foo|‹|T|›|(|x|#:| |T|)|#:| |string| |#=| |"rua"| @@ -122,4 +122,4 @@ fun foo(x: T): string = "rua" foo(42) //│ |foo|‹|int|›|(|42|)| -//│ Parsed: {foo‹int› (42,)} +//│ Parsed: {foo‹int›(42,)} diff --git a/shared/src/test/diff/parser/UserDefinedOpsMaybe.mls b/shared/src/test/diff/parser/UserDefinedOpsMaybe.mls index bceeddd202..b36f6b4818 100644 --- a/shared/src/test/diff/parser/UserDefinedOpsMaybe.mls +++ b/shared/src/test/diff/parser/UserDefinedOpsMaybe.mls @@ -9,7 +9,7 @@ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.4: 1 div 2 //│ ╙── ^^^^^^^ -//│ Parsed: {1 (div (2,),)} +//│ Parsed: {1(div(2,),)} 1 mod 2 //│ |1| |mod| |2| @@ -19,7 +19,7 @@ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.14: 1 mod 2 //│ ╙── ^^^^^^^ -//│ Parsed: {1 (mod (2,),)} +//│ Parsed: {1(mod(2,),)} 3 eq 4 //│ |3| |eq| |4| @@ -29,7 +29,7 @@ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.24: 3 eq 4 //│ ╙── ^^^^^^ -//│ Parsed: {3 (eq (4,),)} +//│ Parsed: {3(eq(4,),)} xs map f map g map h //│ |xs| |map| |f| |map| |g| |map| |h| @@ -51,6 +51,6 @@ xs map f map g map h //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.34: xs map f map g map h //│ ╙── ^^^^^^^^^^^^^^^^^^^^ -//│ Parsed: {xs (map (f (map (g (map (h,),),),),),)} +//│ Parsed: {xs(map(f(map(g(map(h,),),),),),)} diff --git a/shared/src/test/diff/parser/WeirdIfs.mls b/shared/src/test/diff/parser/WeirdIfs.mls index b61b6cc3a3..e2c99b339a 100644 --- a/shared/src/test/diff/parser/WeirdIfs.mls +++ b/shared/src/test/diff/parser/WeirdIfs.mls @@ -25,7 +25,7 @@ if x is //│ ╟── Note: 'if' expression started here: //│ ║ l.11: if x is //│ ╙── ^^ -//│ Parsed: {if (is (x,) (undefined,)) then undefined} +//│ Parsed: {if (is(x,)(undefined,)) then undefined} :pe if x is @@ -42,7 +42,7 @@ if x is //│ ╟── Note: 'if' expression started here: //│ ║ l.31: if x is //│ ╙── ^^ -//│ Parsed: {if (is (x,) ({P},)) then undefined} +//│ Parsed: {if (is(x,)({P},)) then undefined} // TODO(Luyu): move to another test file @@ -51,7 +51,7 @@ if x is Some(xv) and y is Right(yv2) then xv + yv2 else els //│ |#if| |x| |is|→|Some|(|xv|)| |and| |y| |is| |Left|(|yv|)| |#then| |xv| |+| |yv|↵|Some|(|xv|)| |and| |y| |is| |Right|(|yv2|)| |#then| |xv| |+| |yv2|↵|#else| |els|←| -//│ Parsed: {if x is ‹(and (Some (xv,),) (is (y,) (Left (yv,),),)) then + (xv,) (yv,); (and (Some (xv,),) (is (y,) (Right (yv2,),),)) then + (xv,) (yv2,); else els›} +//│ Parsed: {if x is ‹(and(Some(xv,),)(is(y,)(Left(yv,),),)) then +(xv,)(yv,); (and(Some(xv,),)(is(y,)(Right(yv2,),),)) then +(xv,)(yv2,); else els›} diff --git a/shared/src/test/diff/parser/Where.mls b/shared/src/test/diff/parser/Where.mls index 90e4d15342..c4c9fabdc7 100644 --- a/shared/src/test/diff/parser/Where.mls +++ b/shared/src/test/diff/parser/Where.mls @@ -1,15 +1,15 @@ 1 + 1 where 1 //│ |1| |+| |1| |#where| |1| -//│ Parsed: {+ (1,) (1,) where {1}} +//│ Parsed: {+(1,)(1,) where {1}} a => a + 1 where foo //│ |a| |=>| |a| |+| |1| |#where| |foo| -//│ Parsed: {(a,) => + (a,) (1,) where {foo}} +//│ Parsed: {(a,) => +(a,)(1,) where {foo}} a + 1 where let a = 1 //│ |a| |+| |1| |#where| |#let| |a| |#=| |1| -//│ Parsed: {+ (a,) (1,) where {let a = 1}} +//│ Parsed: {+(a,)(1,) where {let a = 1}} fun foo: 'a => 'a => 'a where 'a : int //│ |#fun| |foo|#:| |'a| |=>| |'a| |=>| |'a| |#where| |'a| |#:| |int| diff --git a/shared/src/test/diff/parser/Whitespace.mls b/shared/src/test/diff/parser/Whitespace.mls index 986b2d1476..036725732c 100644 --- a/shared/src/test/diff/parser/Whitespace.mls +++ b/shared/src/test/diff/parser/Whitespace.mls @@ -16,13 +16,13 @@ false(1 , 2 , 3) //│ |false|(|1| |,| |2| |,| |3|)| -//│ Parsed: {false (1, 2, 3,)} +//│ Parsed: {false(1, 2, 3,)} false (1 ,2 ,3) //│ |false| |(|1| |,|2| |,|3|)| -//│ Parsed: {false (1, 2, 3,)} +//│ Parsed: {false(1, 2, 3,)} false( 1 , 2 , 3 ) //│ |false|(| |1| |,| |2| |,| |3| |)| -//│ Parsed: {false (1, 2, 3,)} +//│ Parsed: {false(1, 2, 3,)} diff --git a/shared/src/test/diff/parser/boolops.mls b/shared/src/test/diff/parser/boolops.mls index 6f4fb54d92..dbc1e7d5d6 100644 --- a/shared/src/test/diff/parser/boolops.mls +++ b/shared/src/test/diff/parser/boolops.mls @@ -1,31 +1,31 @@ true and false //│ |true| |and| |false| -//│ Parsed: {and (true,) (false,)} +//│ Parsed: {and(true,)(false,)} a and b or c //│ |a| |and| |b| |or| |c| -//│ Parsed: {or (and (a,) (b,),) (c,)} +//│ Parsed: {or(and(a,)(b,),)(c,)} a or b and c //│ |a| |or| |b| |and| |c| -//│ Parsed: {or (a,) (and (b,) (c,),)} +//│ Parsed: {or(a,)(and(b,)(c,),)} a + 1 or b + 2 and c + 3 //│ |a| |+| |1| |or| |b| |+| |2| |and| |c| |+| |3| -//│ Parsed: {or (+ (a,) (1,),) (and (+ (b,) (2,),) (+ (c,) (3,),),)} +//│ Parsed: {or(+(a,)(1,),)(and(+(b,)(2,),)(+(c,)(3,),),)} any of a, b, c //│ |any| |#of| |a|,| |b|,| |c| -//│ Parsed: {any (a, b, c,)} +//│ Parsed: {any(a, b, c,)} any of a b c //│ |any| |#of|→|a|↵|b|↵|c|←| -//│ Parsed: {any ({a; b; c},)} +//│ Parsed: {any({a; b; c},)} all of x @@ -35,7 +35,7 @@ all of c y //│ |all| |#of|→|x|↵|any| |#of|→|a|↵|b|↵|c|←|↵|y|←| -//│ Parsed: {all ({x; any ({a; b; c},); y},)} +//│ Parsed: {all({x; any({a; b; c},); y},)} diff --git a/shared/src/test/diff/ucs/Exhaustiveness.mls b/shared/src/test/diff/ucs/Exhaustiveness.mls index b335ba7e08..eb2377c61d 100644 --- a/shared/src/test/diff/ucs/Exhaustiveness.mls +++ b/shared/src/test/diff/ucs/Exhaustiveness.mls @@ -48,7 +48,7 @@ class Node[A](value: int, left: Tree[A], right: Tree[A]) { >= value then right.find(wanted) == value then true } -//│ ╔══[ERROR] The case when this is false is not handled: == (wanted, value,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(wanted, value,) //│ ║ l.46: fun contains(wanted) = if wanted //│ ║ ^^^^^^ //│ ║ l.47: <= value then left.find(wanted) diff --git a/shared/src/test/diff/ucs/LeadingAnd.mls b/shared/src/test/diff/ucs/LeadingAnd.mls index f052cd41a1..faa751e461 100644 --- a/shared/src/test/diff/ucs/LeadingAnd.mls +++ b/shared/src/test/diff/ucs/LeadingAnd.mls @@ -24,7 +24,7 @@ fun f(a, b) = if a is Some(av) then av + bv //│ |#fun| |f|(|a|,| |b|)| |#=| |#if| |a| |is| |Some|(|av|)|→|and| |b| |is| |Some|(|bv|)|↵|#then| |av| |+| |bv|←| //│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(a), _: Var(b)), If(IfOpApp(Var(a), Var(is), I; f; O; p; s; A; p; p; (; A; p; p; (; V; a; r; (; S; o; m; e; ); ,; ; T; u; p; (; _; :; ; V; a; r; (; a; v; ); ); ); ,; ; <; i; t; e; r; a; t; o; r; >, None)))) -//│ Parsed: fun f = (a, b,) => if a is Some (av,) ‹· and (is (b, Some (bv,),)) then + (av, bv,)›; +//│ Parsed: fun f = (a, b,) => if a is Some(av,) ‹· and (is(b, Some(bv,),)) then +(av, bv,)›; //│ fun f: (Some[Int], Some[Int]) -> Int // TODO @@ -35,7 +35,7 @@ fun f(a, b) = if a is then av + bv //│ |#fun| |f|(|a|,| |b|)| |#=| |#if| |a| |is|→|Some|(|av|)|→|and| |b| |is| |Some|(|bv|)|↵|#then| |av| |+| |bv|←|←| //│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(a), _: Var(b)), If(IfOpApp(Var(a), Var(is), IfBlock(I; f; O; p; s; A; p; p; (; A; p; p; (; V; a; r; (; S; o; m; e; ); ,; ; T; u; p; (; _; :; ; V; a; r; (; a; v; ); ); ); ,; ; <; i; t; e; r; a; t; o; r; >), None)))) -//│ Parsed: fun f = (a, b,) => if a is ‹Some (av,) ‹· and (is (b, Some (bv,),)) then + (av, bv,)››; +//│ Parsed: fun f = (a, b,) => if a is ‹Some(av,) ‹· and (is(b, Some(bv,),)) then +(av, bv,)››; //│ ╔══[ERROR] Illegal pattern `and` //│ ║ l.34: and b is Some(bv) //│ ╙── ^^^ diff --git a/shared/src/test/diff/ucs/SimpleUCS.mls b/shared/src/test/diff/ucs/SimpleUCS.mls index c901f0e6e9..80906e9abc 100644 --- a/shared/src/test/diff/ucs/SimpleUCS.mls +++ b/shared/src/test/diff/ucs/SimpleUCS.mls @@ -179,7 +179,7 @@ fun f(x, y) = > 0 then "gt" < 0 then "le" == 0 then "eq" -//│ ╔══[ERROR] The case when this is false is not handled: == (y,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(y,)(0,) //│ ║ l.178: Some(x) and y //│ ║ ^ //│ ║ l.179: > 0 then "gt" diff --git a/shared/src/test/diff/ucs/SplitAfterOp.mls b/shared/src/test/diff/ucs/SplitAfterOp.mls index 3f0a234740..d79edec279 100644 --- a/shared/src/test/diff/ucs/SplitAfterOp.mls +++ b/shared/src/test/diff/ucs/SplitAfterOp.mls @@ -5,7 +5,7 @@ fun f(x, b) = if x == 0 and b then 0 -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(0,) //│ ║ l.6: if x == //│ ║ ^^^^^ //│ ║ l.7: 0 and b then 0 @@ -19,7 +19,7 @@ fun f(x, b) = if x == y + 5 then 0 7 then 0 -//│ ╔══[ERROR] The case when this is false is not handled: + (== (x,) (y,),) (7,) +//│ ╔══[ERROR] The case when this is false is not handled: +(==(x,)(y,),)(7,) //│ ║ l.19: if x == y + //│ ║ ^^^^^^^^ //│ ║ l.20: 5 then 0 @@ -35,7 +35,7 @@ if x == y + if x == y * 5 then 0 6 + 7 then 0 -//│ ╔══[ERROR] The case when this is false is not handled: * (== (x,) (y,),) (+ (6,) (7,),) +//│ ╔══[ERROR] The case when this is false is not handled: *(==(x,)(y,),)(+(6,)(7,),) //│ ║ l.35: if x == y * //│ ║ ^^^^^^^^ //│ ║ l.36: 5 then 0 @@ -52,7 +52,7 @@ if x == y + 5 then 0 7 then 0 -//│ ╔══[ERROR] The case when this is false is not handled: + (== (x,) (y,),) (7,) +//│ ╔══[ERROR] The case when this is false is not handled: +(==(x,)(y,),)(7,) //│ ║ l.51: if x == //│ ║ ^^^^ //│ ║ l.52: y + @@ -69,7 +69,7 @@ if x == :ge if x == 1 and b then 0 -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (1,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(1,) //│ ║ l.70: if x == //│ ║ ^^^^ //│ ║ l.71: 1 and b then 0 @@ -85,7 +85,7 @@ fun toEnglish(x) = if x == true then "t" 0 then "z" -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(0,) //│ ║ l.85: if x == //│ ║ ^^^^ //│ ║ l.86: true then "t" @@ -102,7 +102,7 @@ fun toEnglish(x) = if x == 0 then "z" true then "t" -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (true,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(true,) //│ ║ l.102: if x == //│ ║ ^^^^ //│ ║ l.103: 0 then "z" @@ -119,7 +119,7 @@ fun toEnglish(x) = if x == 1 then "o" 0 then "z" -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(0,) //│ ║ l.119: if x == //│ ║ ^^^^ //│ ║ l.120: 1 then "o" @@ -157,7 +157,7 @@ fun toEnglish(x) = //│ ╟── Note: 'if' expression started here: //│ ║ l.144: if x == //│ ╙── ^^ -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (undefined,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(undefined,) //│ ║ l.144: if x == //│ ║ ^^^^ //│ ║ l.145: else 1 diff --git a/shared/src/test/diff/ucs/SplitAnd.mls b/shared/src/test/diff/ucs/SplitAnd.mls index 484a7e120f..3a3c4705d0 100644 --- a/shared/src/test/diff/ucs/SplitAnd.mls +++ b/shared/src/test/diff/ucs/SplitAnd.mls @@ -26,7 +26,7 @@ fun f(x) = B() then "B" x == 0 then "lol" else "bruh" -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(0,) //│ ║ l.23: if x == 0 and //│ ╙── ^^^^^^ //│ f: anything -> error @@ -40,7 +40,7 @@ fun f(x, y) = x == 0 and y == 0 then "bruh" else "lol" -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(0,) //│ ║ l.40: x == 0 and //│ ╙── ^^^^^^ //│ f: (anything, anything,) -> error diff --git a/shared/src/test/diff/ucs/SplitBeforeOp.mls b/shared/src/test/diff/ucs/SplitBeforeOp.mls index 15b69a053c..6f07068743 100644 --- a/shared/src/test/diff/ucs/SplitBeforeOp.mls +++ b/shared/src/test/diff/ucs/SplitBeforeOp.mls @@ -4,7 +4,7 @@ :ge if x == 0 then 0 -//│ ╔══[ERROR] The case when this is false is not handled: == (x, 0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x, 0,) //│ ║ l.5: if x //│ ║ ^ //│ ║ l.6: == 0 then 0 diff --git a/shared/src/test/diff/ucs/SplitOps.mls b/shared/src/test/diff/ucs/SplitOps.mls index 5e44153648..03ee227f54 100644 --- a/shared/src/test/diff/ucs/SplitOps.mls +++ b/shared/src/test/diff/ucs/SplitOps.mls @@ -33,7 +33,7 @@ fun f(x) = is Left(v) then 0 is Right(v) then 1 <> undefined then 2 -//│ ╔══[ERROR] The case when this is false is not handled: <> (x,) (undefined,) +//│ ╔══[ERROR] The case when this is false is not handled: <>(x,)(undefined,) //│ ║ l.32: if x //│ ║ ^ //│ ║ l.33: is Left(v) then 0 @@ -94,10 +94,10 @@ fun f(a, b, c) = == 0 and b is B() and c is C() then 0 //│ |#fun| |f|(|a|,| |b|,| |c|)| |#=|→|#if| |a|→|==| |0| |and| |b| |is| |B|(||)| |and| |c| |is| |C|(||)| |#then| |0|←|←| //│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(a), _: Var(b), _: Var(c)), Blk(...)))) -//│ Parsed: fun f = (a, b, c,) => {if a ‹· == (and (and (0,) (is (b,) (B (),),),) (is (c,) (C (),),)) then 0›}; -//│ Desugared: rec def f: (a, b, c,) => {if a ‹· == (and (and (0,) (is (b,) (B (),),),) (is (c,) (C (),),)) then 0›} +//│ Parsed: fun f = (a, b, c,) => {if a ‹· == (and(and(0,)(is(b,)(B(),),),)(is(c,)(C(),),)) then 0›}; +//│ Desugared: rec def f: (a, b, c,) => {if a ‹· == (and(and(0,)(is(b,)(B(),),),)(is(c,)(C(),),)) then 0›} //│ AST: Def(true, f, Lam(Tup(_: Var(a), _: Var(b), _: Var(c)), Blk(...)), true) -//│ ╔══[ERROR] The case when this is false is not handled: == (a,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: ==(a,)(0,) //│ ║ l.93: if a //│ ║ ^ //│ ║ l.94: == 0 and b is B() and c is C() then 0 diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index 70d8699df0..2d160cb73a 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -52,7 +52,7 @@ fun f(a, b) = if a and b then 0 fun f(x, y) = if x == y + 5 then 0 else if x == y + 7 then 0 -//│ ╔══[ERROR] The case when this is false is not handled: == (x,) (+ (y,) (7,),) +//│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(+(y,)(7,),) //│ ║ l.54: else if x == y + 7 then 0 //│ ╙── ^^^^^^^^^^ //│ f: (anything, anything,) -> error @@ -64,7 +64,7 @@ fun foo(x) = if x is Some //│ ╔══[PARSE ERROR] Unexpected parenthesis section here //│ ║ l.63: (1) then 1 //│ ╙── ^^^ -//│ ╔══[ERROR] The case when this is false is not handled: is (x,) (Some,) (0,) +//│ ╔══[ERROR] The case when this is false is not handled: is(x,)(Some,)(0,) //│ ║ l.61: fun foo(x) = if x is Some //│ ║ ^^^^^^^^^ //│ ║ l.62: (0) then 0 diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index 864e50a136..8e76a6124b 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -83,7 +83,7 @@ fun f(x) = //│ ╟── Note: 'if' expression started here: //│ ║ l.70: if x === //│ ╙── ^^ -//│ ╔══[ERROR] The case when this is false is not handled: === (x, undefined,) +//│ ╔══[ERROR] The case when this is false is not handled: ===(x, undefined,) //│ ║ l.70: if x === //│ ║ ^^^^^ //│ ║ l.71: else "bruh" diff --git a/ts2mls/js/src/test/diff/Dec.d.mls b/ts2mls/js/src/test/diff/Dec.d.mls index 2976186b91..47dc24950d 100644 --- a/ts2mls/js/src/test/diff/Dec.d.mls +++ b/ts2mls/js/src/test/diff/Dec.d.mls @@ -11,5 +11,5 @@ class Person(name: string, age: number) { module OOO { } //│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |=>| |unit|)| ||| |(|#undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#module| |OOO| |{|↵|}| -//│ Parsed: {fun getName: (id: string | number) -> string; fun render: (callback: unit -> unit | undefined) -> string; trait Get() {fun __call: (id: string) -> string}; class Person(name: string, age: number,) {fun getName: (id: number) -> string}; module OOO() {}} +//│ Parsed: {fun getName: (id: string | number) -> string; fun render: (callback: unit -> unit | undefined) -> string; trait Get() {fun __call: (id: string) -> string}; class Person(name: string, age: number,) {fun getName: (id: number) -> string}; module OOO {}} //│ diff --git a/ts2mls/js/src/test/diff/Heritage.d.mls b/ts2mls/js/src/test/diff/Heritage.d.mls index a90d7822eb..bc5d879a13 100644 --- a/ts2mls/js/src/test/diff/Heritage.d.mls +++ b/ts2mls/js/src/test/diff/Heritage.d.mls @@ -41,5 +41,5 @@ module Five { } class Y(): Five.ROTK {} //│ |#class| |A|(||)| |{|→|#fun| |foo|(||)|#:| |unit|←|↵|}|↵|#class| |B|(||)|#:| |A| |{||}|↵|#class| |C|‹|T|›|(||)| |{|→|#fun| |set|(|x|#:| |T|)|#:| |unit|↵|#fun| |get|(||)|#:| |T|←|↵|}|↵|#class| |D|(||)|#:| |C|‹|number|›| |{||}|↵|#trait| |Wu|(||)| |{|→|#let| |x|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#class| |WuWu|(||)|#:| |Wu| |{|→|#let| |y|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |WuWuWu|(||)|#:| |WuWu| |{|→|#let| |z|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |Never|(||)|#:| |WuWuWu| |{|→|#fun| |w|(||)|#:| |nothing|←|↵|}|↵|#class| |VG|‹|T|›|(||)| |{|→|#let| |x|#:| |T|←|↵|}|↵|#class| |Home|‹|T|›|(||)|#:| |VG|‹|string|›| |{|→|#let| |y|#:| |T|←|↵|}|↵|#trait| |O|‹|I|›|(||)| |{|→|#fun| |xx|(|x|#:| |I|)|#:| |I|←|↵|}|↵|#class| |OR|‹|R|›|(||)|#:| |O|‹|R|›| |{|→|#fun| |xx|(|x|#:| |R|)|#:| |R|←|↵|}|↵|#module| |Five| |{|→|#class| |ROTK|(||)| |{|→|#let| |wu|#:| |string|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}|←|↵|}|↵|#class| |Y|(||)|#:| |Five|.ROTK| |{||}| -//│ Parsed: {class A() {fun foo: () -> unit}; class B(): A {}; class C‹T›() {fun set: (x: T) -> unit; fun get: () -> T}; class D(): C[number] {}; trait Wu() {let x: bool}; class WuWu(): Wu {let y: bool}; trait WuWuWu(): WuWu {let z: bool}; trait Never(): WuWuWu {fun w: () -> nothing}; class VG‹T›() {let x: T}; class Home‹T›(): VG[string] {let y: T}; trait O‹I›() {fun xx: (x: I) -> I}; class OR‹R›(): O[R] {fun xx: (x: R) -> R}; module Five() {class ROTK() {let wu: string}; class Y(): Five.ROTK {}}; class Y(): Five.ROTK {}} +//│ Parsed: {class A() {fun foo: () -> unit}; class B(): A {}; class C‹T›() {fun set: (x: T) -> unit; fun get: () -> T}; class D(): C[number] {}; trait Wu() {let x: bool}; class WuWu(): Wu {let y: bool}; trait WuWuWu(): WuWu {let z: bool}; trait Never(): WuWuWu {fun w: () -> nothing}; class VG‹T›() {let x: T}; class Home‹T›(): VG[string] {let y: T}; trait O‹I›() {fun xx: (x: I) -> I}; class OR‹R›(): O[R] {fun xx: (x: R) -> R}; module Five {class ROTK() {let wu: string}; class Y(): Five.ROTK {}}; class Y(): Five.ROTK {}} //│ diff --git a/ts2mls/js/src/test/diff/MultiFiles.d.mls b/ts2mls/js/src/test/diff/MultiFiles.d.mls index f6719e1656..d44b2d9131 100644 --- a/ts2mls/js/src/test/diff/MultiFiles.d.mls +++ b/ts2mls/js/src/test/diff/MultiFiles.d.mls @@ -19,5 +19,5 @@ trait Base() { class AnotherFoo(): AnotherBase {} fun multi5(): unit //│ |#fun| |multi1|(|x|#:| |number|)|#:| |number|↵|#fun| |multi3|(||)|#:| |unit|↵|#class| |Foo|(||)|#:| |Base| |{||}|↵|#trait| |AnotherBase|(||)| |{|→|#let| |y|#:| |string|←|↵|}|↵|#module| |N| |{|→|#fun| |f|(||)|#:| |unit|↵|#fun| |g|(||)|#:| |unit|↵|#fun| |h|(||)|#:| |unit|←|↵|}|↵|#fun| |multi2|(|x|#:| |string|)|#:| |string|↵|#fun| |multi4|(||)|#:| |unit|↵|#trait| |Base|(||)| |{|→|#let| |a|#:| |number|←|↵|}|↵|#class| |AnotherFoo|(||)|#:| |AnotherBase| |{||}|↵|#fun| |multi5|(||)|#:| |unit| -//│ Parsed: {fun multi1: (x: number) -> number; fun multi3: () -> unit; class Foo(): Base {}; trait AnotherBase() {let y: string}; module N() {fun f: () -> unit; fun g: () -> unit; fun h: () -> unit}; fun multi2: (x: string) -> string; fun multi4: () -> unit; trait Base() {let a: number}; class AnotherFoo(): AnotherBase {}; fun multi5: () -> unit} +//│ Parsed: {fun multi1: (x: number) -> number; fun multi3: () -> unit; class Foo(): Base {}; trait AnotherBase() {let y: string}; module N {fun f: () -> unit; fun g: () -> unit; fun h: () -> unit}; fun multi2: (x: string) -> string; fun multi4: () -> unit; trait Base() {let a: number}; class AnotherFoo(): AnotherBase {}; fun multi5: () -> unit} //│ diff --git a/ts2mls/js/src/test/diff/Namespace.d.mls b/ts2mls/js/src/test/diff/Namespace.d.mls index 4baef6fd28..a11aa1f25b 100644 --- a/ts2mls/js/src/test/diff/Namespace.d.mls +++ b/ts2mls/js/src/test/diff/Namespace.d.mls @@ -29,5 +29,5 @@ module AA { fun f1(x: N1.C): N1.C fun f2(x: AA.C): AA.C //│ |#module| |N1| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |number|↵|#fun| |ff|(|y|#:| |anything|)|#:| |number|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#module| |N2| |{|→|#fun| |fff|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |number|↵|#fun| |gg|(|c|#:| |N1|.C|)|#:| |N1|.C|↵|#class| |BBB|(||)|#:| |N1|.C| |{||}|←|↵|}|←|↵|}|↵|#module| |AA| |{|→|#fun| |f|(|x|#:| |anything|)|#:| |string|↵|#class| |C|(||)| |{|→|#fun| |f|(||)|#:| |unit|←|↵|}|↵|#trait| |I|(||)| |{|→|#fun| |f|(||)|#:| |number|←|↵|}|↵|#module| |N2| |{|↵|}|←|↵|}|↵|#fun| |f1|(|x|#:| |N1|.C|)|#:| |N1|.C|↵|#fun| |f2|(|x|#:| |AA|.C|)|#:| |AA|.C| -//│ Parsed: {module N1() {fun f: (x: anything) -> number; fun ff: (y: anything) -> number; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2() {fun fff: (x: bool) -> number; fun gg: (c: N1.C) -> N1.C; class BBB(): N1.C {}}}; module AA() {fun f: (x: anything) -> string; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2() {}}; fun f1: (x: N1.C) -> N1.C; fun f2: (x: AA.C) -> AA.C} +//│ Parsed: {module N1 {fun f: (x: anything) -> number; fun ff: (y: anything) -> number; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2 {fun fff: (x: bool) -> number; fun gg: (c: N1.C) -> N1.C; class BBB(): N1.C {}}}; module AA {fun f: (x: anything) -> string; class C() {fun f: () -> unit}; trait I() {fun f: () -> number}; module N2 {}}; fun f1: (x: N1.C) -> N1.C; fun f2: (x: AA.C) -> AA.C} //│ diff --git a/ts2mls/js/src/test/diff/Overload.d.mls b/ts2mls/js/src/test/diff/Overload.d.mls index 3d9b91bfbe..ce7960b267 100644 --- a/ts2mls/js/src/test/diff/Overload.d.mls +++ b/ts2mls/js/src/test/diff/Overload.d.mls @@ -23,5 +23,5 @@ class WWW() { } fun baz(): anything /* warning: the overload of function baz is not supported yet. */ //│ |#fun| |f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |=>| |unit|)| |=>| |(|number|)| |=>| |unit|)| |&| |(|(|(|string|)| |=>| |unit|)| |=>| |(|string|)| |=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |=>| |unit|)| |&| |(|(|N|)| |=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |=>| |(|(|number|)| ||| |(|#undefined|)|)| |=>| |unit|)| |&| |(|(|number|)| |=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|#undefined|)|)| |=>| |unit|)|↵|#fun| |swap|#:| |(|(|(|number|,| |string|,| |)|)| |=>| |(|number|,| |string|,| |)|)| |&| |(|(|(|string|,| |number|,| |)|)| |=>| |(|number|,| |string|,| |)|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#module| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| -//│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | undefined) -> unit & number -> (false | true | undefined) -> unit; fun swap: ([number, string]) -> [number, string] & ([string, number]) -> [number, string]; fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything) -> unit; module XX() {fun f: (x: T, n: anything) -> string}; class WWW() {fun F: (x: T) -> anything}; fun baz: () -> anything} +//│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | undefined) -> unit & number -> (false | true | undefined) -> unit; fun swap: ([number, string]) -> [number, string] & ([string, number]) -> [number, string]; fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything) -> unit; module XX {fun f: (x: T, n: anything) -> string}; class WWW() {fun F: (x: T) -> anything}; fun baz: () -> anything} //│ diff --git a/ts2mls/js/src/test/diff/Type.d.mls b/ts2mls/js/src/test/diff/Type.d.mls index cbfe6d7a62..6b81712d9c 100644 --- a/ts2mls/js/src/test/diff/Type.d.mls +++ b/ts2mls/js/src/test/diff/Type.d.mls @@ -29,5 +29,5 @@ type G = ABC let none: {_tag: "None",} fun some(a: A): (None) | (Some) //│ |#trait| |None|(||)| |{|→|#let| |_tag|#:| |"None"|←|↵|}|↵|#trait| |Some|‹|A|›|(||)| |{|→|#let| |_tag|#:| |"Some"|↵|#let| |value|#:| |A|←|↵|}|↵|#type| |Option|‹|A|›| |#=| |(|None|)| ||| |(|Some|‹|A|›|)|↵|#type| |Func| |#=| |(|number|)| |=>| |number|↵|#type| |S2| |#=| |(|string|,| |string|,| |)|↵|#trait| |I1|(||)| |{||}|↵|#trait| |I2|(||)| |{||}|↵|#type| |I3| |#=| |(|I1|)| |&| |(|I2|)|↵|#type| |StringArray| |#=| |Array|‹|string|›|↵|#type| |SomeInterface| |#=| |{|x|#:| |number|,|y|#:| |number|,|}|↵|#class| |ABC|(||)| |{||}|↵|#type| |DEF| |#=| |ABC|↵|#type| |TP|‹|A|,| |B|,| |C|›| |#=| |(|A|,| |B|,| |C|,| |)|↵|#module| |NA| |{|→|#fun| |fb|(|b|#:| |string|)|#:| |unit|↵|#type| |B| |#=| |string|←|↵|}|↵|#class| |NC|(||)| |{|→|#let| |b|#:| |string|←|↵|}|↵|#type| |G| |#=| |ABC|↵|#let| |none|#:| |{|_tag|#:| |"None"|,|}|↵|#fun| |some|‹|A|›|(|a|#:| |A|)|#:| |(|None|)| ||| |(|Some|‹|A|›|)| -//│ Parsed: {trait None() {let _tag: "None"}; trait Some‹A›() {let _tag: "Some"; let value: A}; type alias Option‹A›(): None | Some[A] {}; type alias Func(): number -> number {}; type alias S2(): [string, string] {}; trait I1() {}; trait I2() {}; type alias I3(): I1 & I2 {}; type alias StringArray(): Array[string] {}; type alias SomeInterface(): {x: number, y: number} {}; class ABC() {}; type alias DEF(): ABC {}; type alias TP‹A, B, C›(): [A, B, C] {}; module NA() {fun fb: (b: string) -> unit; type alias B(): string {}}; class NC() {let b: string}; type alias G(): ABC {}; let none: {_tag: "None"}; fun some: (a: A) -> (None | Some[A])} +//│ Parsed: {trait None() {let _tag: "None"}; trait Some‹A›() {let _tag: "Some"; let value: A}; type alias Option‹A›: None | Some[A] {}; type alias Func: number -> number {}; type alias S2: [string, string] {}; trait I1() {}; trait I2() {}; type alias I3: I1 & I2 {}; type alias StringArray: Array[string] {}; type alias SomeInterface: {x: number, y: number} {}; class ABC() {}; type alias DEF: ABC {}; type alias TP‹A, B, C›: [A, B, C] {}; module NA {fun fb: (b: string) -> unit; type alias B: string {}}; class NC() {let b: string}; type alias G: ABC {}; let none: {_tag: "None"}; fun some: (a: A) -> (None | Some[A])} //│ diff --git a/ts2mls/js/src/test/diff/Variables.d.mls b/ts2mls/js/src/test/diff/Variables.d.mls index 68c9994b23..89f39fa49c 100644 --- a/ts2mls/js/src/test/diff/Variables.d.mls +++ b/ts2mls/js/src/test/diff/Variables.d.mls @@ -15,5 +15,5 @@ module DD { let bar: number } //│ |#let| |URI|#:| |string|↵|#let| |URI2|#:| |string|↵|#let| |foo|#:| |number|↵|#let| |bar|#:| |false|↵|#class| |FooBar|(||)| |{||}|↵|#let| |fb|#:| |FooBar|↵|#module| |ABC| |{|→|#class| |DEF|(||)| |{||}|←|↵|}|↵|#let| |d|#:| |ABC|.DEF|↵|#module| |DD| |{|→|#let| |foo|#:| |number|↵|#let| |bar|#:| |number|←|↵|}| -//│ Parsed: {let URI: string; let URI2: string; let foo: number; let bar: false; class FooBar() {}; let fb: FooBar; module ABC() {class DEF() {}}; let d: ABC.DEF; module DD() {let foo: number; let bar: number}} +//│ Parsed: {let URI: string; let URI2: string; let foo: number; let bar: false; class FooBar() {}; let fb: FooBar; module ABC {class DEF() {}}; let d: ABC.DEF; module DD {let foo: number; let bar: number}} //│ From 639d20202c809d3c27b6ce80d5d32d227dcac09f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 19 Sep 2023 11:25:52 +0800 Subject: [PATCH 445/498] Properly type check constructors, new expressions, val parameters & co --- .../scala/mlscript/ConstraintSolver.scala | 20 +- .../src/main/scala/mlscript/JSBackend.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 15 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 196 ++++++++++++---- shared/src/main/scala/mlscript/Typer.scala | 78 +++++-- .../main/scala/mlscript/TyperDatatypes.scala | 2 + .../main/scala/mlscript/TyperHelpers.scala | 11 +- shared/src/main/scala/mlscript/helpers.scala | 29 ++- shared/src/main/scala/mlscript/syntax.scala | 2 +- .../main/scala/mlscript/ucs/Desugarer.scala | 4 +- ...nalParam.mls => AuxiliaryConstructors.mls} | 220 ++++++++++++------ .../src/test/diff/codegen/ConstructorStmt.mls | 94 ++++---- shared/src/test/diff/codegen/New.mls | 15 +- shared/src/test/diff/codegen/NewMatching.mls | 5 +- shared/src/test/diff/codegen/NuClasses.mls | 4 +- shared/src/test/diff/codegen/Super.mls | 1 + shared/src/test/diff/codegen/ValLet.mls | 24 +- shared/src/test/diff/gadt/Exp1.mls | 10 +- shared/src/test/diff/gadt/Exp2.mls | 18 +- shared/src/test/diff/gadt/ThisMatching.mls | 29 ++- shared/src/test/diff/nu/AbstractClasses.mls | 17 +- shared/src/test/diff/nu/AuxCtors.mls | 149 ++++++++++++ shared/src/test/diff/nu/BadAliases.mls | 28 +-- shared/src/test/diff/nu/BadClassInherit.mls | 67 +++--- shared/src/test/diff/nu/BadClasses.mls | 43 ++-- shared/src/test/diff/nu/BadFieldInit.mls | 132 +++++++++++ shared/src/test/diff/nu/BadScopes.mls | 4 +- shared/src/test/diff/nu/BadSignatures.mls | 17 +- shared/src/test/diff/nu/BadSuper.mls | 1 + shared/src/test/diff/nu/BadUCS.mls | 22 +- .../test/diff/nu/BasicClassInheritance.mls | 131 ++++++++++- shared/src/test/diff/nu/BasicClasses.mls | 7 +- shared/src/test/diff/nu/BasicMixins.mls | 20 +- shared/src/test/diff/nu/CtorStatements.mls | 24 -- shared/src/test/diff/nu/Dates.mls | 13 +- shared/src/test/diff/nu/Declarations.mls | 8 +- shared/src/test/diff/nu/DiamondInherit.mls | 2 + shared/src/test/diff/nu/EncodedLists.mls | 3 +- shared/src/test/diff/nu/EqlClasses.mls | 18 +- shared/src/test/diff/nu/GADTMono.mls | 30 +-- .../test/diff/nu/GenericClassInheritance.mls | 34 +-- shared/src/test/diff/nu/GenericClasses.mls | 20 +- shared/src/test/diff/nu/GenericMethods.mls | 6 +- shared/src/test/diff/nu/GenericMixins.mls | 15 +- shared/src/test/diff/nu/GenericModules.mls | 4 +- shared/src/test/diff/nu/Huawei1.mls | 10 +- .../src/test/diff/nu/ImplicitMethodPolym.mls | 26 ++- .../diff/nu/InferredInheritanceTypeArgs.mls | 10 +- .../diff/nu/InheritanceLevelMismatches.mls | 1 + shared/src/test/diff/nu/InterfaceMono.mls | 118 +++++----- shared/src/test/diff/nu/Interfaces.mls | 193 ++++++++------- shared/src/test/diff/nu/Jonathan.mls | 16 +- shared/src/test/diff/nu/LocalLets.mls | 14 ++ shared/src/test/diff/nu/MemberConfusion.mls | 4 +- .../src/test/diff/nu/MemberIntersections.mls | 44 ++-- shared/src/test/diff/nu/MethodSignatures.mls | 6 +- shared/src/test/diff/nu/MixinParameters.mls | 35 ++- shared/src/test/diff/nu/ModuleParameters.mls | 46 +++- shared/src/test/diff/nu/MutualRec.mls | 50 +++- shared/src/test/diff/nu/NestedClasses.mls | 8 +- shared/src/test/diff/nu/New.mls | 2 + shared/src/test/diff/nu/NewNew.mls | 43 +++- shared/src/test/diff/nu/NoThisCtor.mls | 31 +-- shared/src/test/diff/nu/Object.mls | 33 ++- shared/src/test/diff/nu/ParamImplementing.mls | 8 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 7 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 6 +- shared/src/test/diff/nu/SelfAppMethods.mls | 3 +- shared/src/test/diff/nu/SelfRec.mls | 18 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 108 +++++---- shared/src/test/diff/nu/TODO_Classes.mls | 81 ++++--- .../src/test/diff/nu/ThisRefinedClasses.mls | 16 +- .../test/diff/nu/TrickyGenericInheritance.mls | 106 ++++----- shared/src/test/diff/nu/TypeAliases.mls | 6 +- shared/src/test/diff/nu/TypreMembers.mls | 3 +- shared/src/test/diff/nu/UndefMatching.mls | 8 +- shared/src/test/diff/nu/Uninstantiable.mls | 21 +- shared/src/test/diff/ucs/LitUCS.mls | 17 +- 78 files changed, 1876 insertions(+), 815 deletions(-) rename shared/src/test/diff/codegen/{OptionalParam.mls => AuxiliaryConstructors.mls} (71%) create mode 100644 shared/src/test/diff/nu/AuxCtors.mls create mode 100644 shared/src/test/diff/nu/BadFieldInit.mls delete mode 100644 shared/src/test/diff/nu/CtorStatements.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 140d878b9b..215d482046 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -541,13 +541,19 @@ class ConstraintSolver extends NormalForms { self: Typer => RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if ctx.tyDefs2.contains(nme) => if (newDefs && nme =/= "Eql" && fldNme.name === "Eql#A") { val info = ctx.tyDefs2(nme) - info.typedParams.foreach { p => - val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, p._1) - rec(fldTy.lb.getOrElse(die), RecordType(p._1 -> TypeRef(TypeName("Eql"), - fty.ub // FIXME check mutable? - :: Nil - )(provTODO).toUpper(provTODO) :: Nil)(provTODO), false) - } + if (info.typedParams.isEmpty && !primitiveTypes.contains(nme)) + // TODO shoudl actually reject all non-data classes... + err(msg"${info.decl.kind.str.capitalize} '${info.decl.name + }' does not support equality comparison because it does not have a parameter list", prov.loco) + info.typedParams + .getOrElse(Nil) // FIXME?... prim type + .foreach { p => + val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, p._1) + rec(fldTy.lb.getOrElse(die), RecordType(p._1 -> TypeRef(TypeName("Eql"), + fty.ub // FIXME check mutable? + :: Nil + )(provTODO).toUpper(provTODO) :: Nil)(provTODO), false) + } } else { val fty = lookupField(() => done_ls.toType(sort = true), S(nme), r.fields.toMap.get, ts, fldNme) rec(fty.ub, fldTy.ub, false) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index e49bd0f9a8..1c74bf0774 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -1034,6 +1034,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val (params, preStmts) = ctor match { case S(Constructor(Tup(ls), Blk(stmts))) => (S(ls.map { case (S(Var(nme)), Fld(flags, _)) => (nme, flags.genGetter) + case (N, Fld(flags, Var(nme))) => (nme, flags.genGetter) case _ => throw CodeGenError(s"Unexpected constructor parameters in $nme.") }), stmts) case _ => (N, Nil) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 7f665790a0..9b13a7a18d 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -667,7 +667,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo } case (KEYWORD("new"), l0) :: c => consume - val body = expr(0) + val body = expr(outer.prec('.')) val head = body match { case Var(clsNme) => S(TypeName(clsNme).withLocOf(body) -> Tup(Nil)) @@ -682,7 +682,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo msg"Unexpected ${body.describe} after `new` keyword" -> body.toLoc :: Nil)) N } - R(New(head, curlyTypingUnit).withLoc(S(head.foldLeft(l0)((l, h) => l ++ h._1.toLoc ++ h._2.toLoc)))) + val res = New(head, curlyTypingUnit).withLoc(S(head.foldLeft(l0)((l, h) => l ++ h._1.toLoc ++ h._2.toLoc))) + exprCont(res, prec, allowNewlines = false) case (KEYWORD("else"), l0) :: _ => consume val e = expr(0) @@ -797,16 +798,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo else App(App(v, toParams(acc)), toParams(rhs)) }, prec, allowNewlines) } - case (KEYWORD(":"), l0) :: _ => + case (KEYWORD(":"), l0) :: _ if prec <= outer.prec(':') => consume R(Asc(acc, typ(0))) - // case (KEYWORD(":"), _) :: _ if prec <= 1 => - // consume - // R(Asc(acc, typ(1))) case (KEYWORD("where"), l0) :: _ if prec <= 1 => consume val tu = typingUnitMaybeIndented - R(Where(acc, tu.entities)) + val res = Where(acc, tu.entities).withLoc(S(l0)) + exprCont(res, prec, allowNewlines = false) case (SPACE, l0) :: _ => consume exprCont(acc, prec, allowNewlines) @@ -917,7 +916,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo exprCont(res, prec, allowNewlines) case c @ (h :: _) if (h._1 match { - case KEYWORD(";" | "of" | "where" | "extends") | BRACKETS(Round | Square, _) + case KEYWORD(";" | ":" | "of" | "where" | "extends") | BRACKETS(Round | Square, _) | BRACKETS(Indent, ( KEYWORD(";" | "of") | BRACKETS(Round | Square, _) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 82e408d7b7..8c9e3d6569 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -209,7 +209,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuCls( level: Level, td: NuTypeDef, tparams: TyParams, - params: Ls[Var -> FieldType], + params: Opt[Ls[Var -> FieldType]], + auxCtorParams: Opt[Ls[Var -> ST]], members: Map[Str, NuMember], thisTy: ST, sign: ST, @@ -224,7 +225,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def name: Str = nme.name def isImplemented: Bool = true - def typeSignature: ST = typeSignatureOf(td, level, tparams, params, sign, inheritedTags) + /** Those parameters that are used in `new` and `extends` clauses. */ + lazy val effectiveParams: Params = + auxCtorParams.map(_.mapValues(_.toUpper(noProv))).orElse(params).getOrElse(Nil) + + /** The type of a palin term reference to this type definition. */ + def typeSignature(usesNew: Bool, loco: Opt[Loc])(implicit raise: Raise): ST = + typeSignatureOf(usesNew, loco, td, level, tparams, params, auxCtorParams, sign, inheritedTags) /** Includes class-name-coded type parameter fields. */ lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { @@ -286,7 +293,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => : TypedNuCls = { val outer = ctx; withLevel { implicit ctx => TypedNuCls(outer.lvl, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), - params.mapValues(_.freshenAbove(lim, rigidify)), + params.map(_.mapValues(_.freshenAbove(lim, rigidify))), + auxCtorParams.map(_.mapValues(_.freshenAbove(lim, rigidify))), members.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, thisTy.freshenAbove(lim, rigidify), sign.freshenAbove(lim, rigidify), @@ -299,7 +307,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx): TypedNuCls = TypedNuCls(level, td, tparams.map(tp => (tp._1, f(N, tp._2).assertTV, tp._3)), - params.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t))), + params.map(_.mapValues(_.update(t => f(pol.map(!_), t), t => f(pol, t)))), + auxCtorParams.map(_.mapValues(t => f(pol.map(!_), t))), members.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, f(pol.map(!_), thisTy), f(pol, sign), @@ -310,7 +319,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx): TypedNuCls = TypedNuCls(level, td, tparams.map(tp => (tp._1, f(pol.invar, tp._2).assertTV, tp._3)), - params.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t))), + params.map(_.mapValues(_.update(t => f(pol.contravar, t), t => f(pol, t)))), + auxCtorParams.map(_.mapValues(t => f(pol.contravar, t))), members.mapValuesIter(_.mapPolMap(pol)(f)).toMap, f(pol.contravar, thisTy), f(pol, sign), @@ -444,16 +454,32 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - def typeSignatureOf(td: NuTypeDef, level: Level, tparams: TyParams, params: Params, selfTy: ST, ihtags: Set[TypeName]) - : ST = td.kind match { - case Mod => + def typeSignatureOf(usesNew: Bool, loco: Opt[Loc], td: NuTypeDef, level: Level, + tparams: TyParams, params: Opt[Params], acParams: Opt[Ls[Var -> ST]], selfTy: ST, ihtags: Set[TypeName]) + (implicit raise: Raise) + : ST = + if ((td.kind is Mod) && params.isEmpty) ClassTag(Var(td.nme.name), ihtags + TN("Object") )(provTODO) - case Cls => + else if ((td.kind is Cls) || (td.kind is Mod)) { + if (td.kind is Mod) + err(msg"Parameterized modules are not supported", loco) + val psOpt: Opt[Params] = ( + if (usesNew) acParams.map(_.mapValues(_.toUpper(noProv))).orElse(params) + else params.orElse { + acParams.map { ps => + err(msg"Construction of unparameterized class ${td.nme.name} should use the `new` keyword", loco) + ps.mapValues(_.toUpper(noProv)) + } + } + ) + val ps = psOpt.getOrElse { + return err(msg"Class ${td.nme.name} cannot be instantiated as it exposes no such constructor", loco) + } PolymorphicType.mk(level, FunctionType( - TupleType(params.mapKeys(some))(provTODO), + TupleType(ps.mapKeys(some))(provTODO), ClassTag(Var(td.nme.name), ihtags + TN("Object") )(provTODO) & RecordType.mk( @@ -467,9 +493,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )(provTODO) )(provTODO) ) - // case k => err - case k => errType // FIXME - } + } else errType // FIXME def getRefs(body: Statement): RefMap = { @@ -523,7 +547,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => S(s) case N => S(fd) } - false // There will already be typed in DelayedTypeInfo + false // * Explicit signatures will already be typed in DelayedTypeInfo's typedSignatures case _ => true } @@ -643,6 +667,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val level: Level = ctx.lvl val kind: DeclKind = decl.kind + val name: Str = decl.name private implicit val prov: TP = TypeProvenance(decl.toLoc, decl.describe) @@ -759,16 +784,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // println(s"Fresh[${ctx.lvl}] $cls") - if (parArgs.sizeCompare(cls.params) =/= 0) + if (parArgs.sizeCompare(cls.effectiveParams) =/= 0) err(msg"class $parNme expects ${ - cls.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) + cls.effectiveParams.size.toString} parameter(s); got ${parArgs.size.toString + }", Loc(v :: parArgs.unzip._2)) - val paramMems = cls.params.lazyZip(parArgs).map { case (nme -> p, _ -> Fld(_, a)) => // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + // * TODO don't pick up non-vals as public members + val paramMems = cls.effectiveParams.lazyZip(parArgs).map { + case (nme -> p, _ -> Fld(FldFlags(mut, spec, get), a)) => + assert(!mut && !spec, "TODO") // TODO check name, mut, spec + implicit val genLambdas: GenLambdas = true + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) } S((cls, paramMems, ptp ++ cls.parentTP, p.toLoc)) @@ -843,11 +872,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (tp, tv, vi) => (tp.name, SkolemTag(tv)(tv.prov)) } - lazy val typedParams: Ls[Var -> FieldType] = ctx.nest.nextLevel { implicit ctx => + lazy val typedParams: Opt[Ls[Var -> FieldType]] = ctx.nest.nextLevel { implicit ctx => decl match { case td: NuTypeDef => - td.params.getOrElse(Tup(Nil)).fields.map { - case (S(nme), Fld(FldFlags(mut, spec, _), value)) => + td.params.map(_.fields.map { + case (S(nme), Fld(FldFlags(mut, spec, getter), value)) => assert(!mut && !spec, "TODO") // TODO value.toType match { case R(tpe) => @@ -856,18 +885,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => nme -> FieldType(N, ty)(provTODO) case _ => ??? } - case (N, Fld(FldFlags(mut, spec, _), nme: Var)) => - // assert(!mut && !spec, "TODO") // TODO + case (N, Fld(FldFlags(mut, spec, getter), nme: Var)) => + assert(!mut && !spec, "TODO") // TODO // nme -> FieldType(N, freshVar(ttp(nme), N, S(nme.name)))(provTODO) nme -> FieldType(N, err(msg"${td.kind.str.capitalize} parameters currently need type annotations", nme.toLoc))(provTODO) case _ => ??? - } - case fd: NuFunDef => Nil + }) + case fd: NuFunDef => N } } - lazy val paramSymbols = typedParams.map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) + lazy val paramSymbols = typedParams.getOrElse(Nil).map(p => p._1.name -> VarSymbol(p._2.ub, p._1)) // TODO also import signatures from base classes and mixins! lazy val (typedSignatures, funImplems) : (Ls[(NuFunDef, ST)], Ls[NuFunDef]) = decl match { @@ -924,9 +953,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _: NuFunDef => Set.empty } + // * TODO don't pick up non-vals as public members lazy val typedFields: Map[Var, FieldType] = - (typedParams.toMap -- inheritedFields /* parameters can be overridden by inherited fields/methods */) ++ - typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) + (typedParams.getOrElse(Nil).toMap + -- inheritedFields /* parameters can be overridden by inherited fields/methods */ + ) ++ typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) lazy val mutRecTV: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), @@ -1317,8 +1348,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => if ((td.kind is Mod) && typedParams.nonEmpty) // * Can we do better? (Memoization semantics?) - err(msg"${td.kind.str} parameters are not supported", - Loc(typedParams.iterator.map(_._1))) + err(msg"${td.kind.str.capitalize} parameters are not supported", + typedParams.fold(td.nme.toLoc)(tp => Loc(tp.iterator.map(_._1)))) ctx ++= paramSymbols ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) @@ -1335,8 +1366,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => NuParam(TypeName(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov))(lvl) } val tparamFields = tparamMems.map(p => p.nme.toVar -> p.ty) - assert(!typedParams.keys.exists(tparamFields.keys.toSet), ???) - + assert(!typedParams.exists(_.keys.exists(tparamFields.keys.toSet)), ???) + case class Pack( superType: ST, mxnMembers: Ls[NuMember], @@ -1412,10 +1443,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case Nil => - val thisType = WithType(pack.superType, RecordType(typedParams)(ttp(td.params.getOrElse(Tup(Nil)), isType = true)))(provTODO) & - clsNameToNomTag(td)(provTODO, ctx) & - RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) & - sig_ty + val thisType = WithType(pack.superType, + RecordType(typedParams.getOrElse(Nil))(ttp(td.params.getOrElse(Tup(Nil)), isType = true)) + )(provTODO) & + clsNameToNomTag(td)(provTODO, ctx) & + RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) & + sig_ty trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { assert(finalType.level === lvl) @@ -1430,7 +1463,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val baseType = RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) - val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) + val paramMems = typedParams.getOrElse(Nil).map(f => NuParam(f._1, f._2)(lvl)) val Pack(thisType, mxnMembers, _, baseClsMembers, traitMembers, tparamMembers) = inherit(typedParents, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) @@ -1496,8 +1529,68 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val allMembers = (ifaceMembers ++ impltdMems).map(d => d.name -> d).toMap ++ typedSignatureMembers + val auxCtorParams = td.ctor match { + case S(ctor @ Constructor(ps, bod)) => outerCtx.nest.nextLevel { implicit ctx => + def getterError(loco: Opt[Loc]) = + err(msg"Cannot use `val` in constructor parameters", loco) + val res = ps.fields.map { + case (S(nme), Fld(FldFlags(mut, spec, getter), value)) => + assert(!mut && !spec, "TODO") // TODO + if (getter) + // TODO we could support this to some extent + getterError(nme.toLoc) + value.toType match { + case R(tpe) => + implicit val newDefsInfo: Map[Str, (TypeDefKind, Int)] = Map.empty // TODO? (similar as one above in file) + val ty = typeType(tpe) + nme -> ty + case _ => ??? + } + case (N, Fld(FldFlags(mut, spec, getter), nme: Var)) => + assert(!mut && !spec, "TODO") // TODO + if (getter) + getterError(nme.toLoc) + nme -> freshVar(ttp(nme), N, S(nme.name)) + case (N, Fld(_, rhs)) => + Var("") -> err(msg"Unsupported constructor parameter shape", rhs.toLoc) + } + res.foreach { case (nme, ty) => ctx += nme.name -> VarSymbol(ty, nme) } + implicit val gl: GenLambdas = false + implicit val prov: TP = + TypeProvenance(ctor.toLoc, "auxiliary class constructor") + val bodStmts = bod match { + case Blk(sts) => sts + case _ => bod :: Nil + } + // * TODO later: for each `typedParams`, first add sthg like `ctx += lhs.name -> UndefinedParam(...)` + val classParamsMap = MutMap.from(typedParams.getOrElse(Nil)) + bodStmts.foreach { + case Eqn(lhs, rhs) => + classParamsMap.updateWith(lhs) { + case S(p) => + val rhs_ty = typeTerm(rhs) + constrain(rhs_ty, p.ub) + ctx += lhs.name -> VarSymbol(rhs_ty, lhs) + N + case N => + err(msg"Unknown class parameter ${lhs.name}", lhs.toLoc) + N + } + case stmt: DesugaredStatement => + typeStatement(stmt, allowPure = false) + case _ => die + } + S(res) + } + case N => N + } + TypedNuCls(outerCtx.lvl, td, - tparams, typedParams, allMembers, + tparams, + typedParams, + auxCtorParams.orElse(Option.when( + typedParams.isEmpty && (td.kind is Cls) && !td.isAbstract)(Nil)), + allMembers, TopType, sig_ty, inheritedTags, @@ -1513,7 +1606,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) - val paramMems = typedParams.map(f => NuParam(f._1, f._2)(lvl)) + + // * It seems this was unused for now: + // val paramMems = typedParams.map(_.map(f => NuParam(f._1, f._2)(lvl))) + val thisTV = freshVar(provTODO, N, S("this")) val superTV = freshVar(provTODO, N, S("super")) ctx += "this" -> VarSymbol(thisTV, Var("this")) @@ -1524,7 +1620,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => overrideCheck(impltdMems, signs, signs) implemCheck(impltdMems, signs) val mems = impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers - TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams, mems) + TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams.getOrElse(Nil), mems) } } @@ -1537,7 +1633,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => }(r => s"Completed ${r} where ${r.showBounds}") } - def typeSignature(implicit raise: Raise): ST = + def typeSignature(usesNew: Bool, loco: Opt[Loc])(implicit raise: Raise): ST = decl match { case _: NuFunDef => if (isComputing) { @@ -1549,7 +1645,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => die } case td: NuTypeDef => - typeSignatureOf(td, level, tparams, typedParams, TopType, inheritedTags) + // * We want to avoid forcing completion of types needlessly + // * OTOH we need the type to be completed to use its aux ctor (whose param types are optional) + // * TODO: avoid forcing when the aux ctor has type-annotated params + if (usesNew && (td.ctor.isDefined || !td.params.isDefined)) complete() match { + case cls: TypedNuCls => + cls.typeSignature(usesNew, loco) + case _: TypedNuDummy => errType + case _ => die + } else typeSignatureOf(usesNew, loco, td, level, tparams, typedParams, N, TopType, inheritedTags) } override def toString: String = diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3942eacd55..4d69e66577 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -229,7 +229,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne private val preludeLoc = Loc(0, 0, Origin("", 0, new FastParseHelpers(""))) val nuBuiltinTypes: Ls[NuTypeDef] = Ls( - NuTypeDef(Cls, TN("Object"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, N), + NuTypeDef(Cls, TN("Object"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Trt, TN("Eql"), (S(VarianceInfo.contra), TN("A")) :: Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Cls, TN("Num"), Nil, N, N, N, Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), NuTypeDef(Cls, TN("Int"), Nil, N, N, N, Var("Num") :: Nil, N, N, TypingUnit(Nil))(N, S(preludeLoc)), @@ -862,13 +862,13 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne p.typeSignature case ti: TypedNuCls => checkNotAbstract(ti.decl) - ti.typeSignature + ti.typeSignature(false, prov.loco) case ti: TypedNuDecl => err(msg"${ti.kind.str} ${ti.name} cannot be used in term position", prov.loco) } case ti: DelayedTypeInfo => checkNotAbstract(ti.decl) - ti.typeSignature + ti.typeSignature(false, prov.loco) } } mkProxy(ty, prov) @@ -912,7 +912,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne Asc(v, t.toTypeRaise).withLoc(v.toLoc.fold(t.toLoc)(_ ++ t.toLoc |> some)))) case _ => e } - }.map { case (n, Fld(FldFlags(mut, _, _), t)) => + }.map { case (n, Fld(FldFlags(mut, spec, getter), t)) => + if (getter) + err(msg"Cannot use `val` in this position", Loc(t :: n.toList)) val tym = typePolymorphicTerm(t) // val tym = if (n.isDefined) typeType(t.toTypeRaise) // else typePolymorphicTerm(t) @@ -1311,12 +1313,46 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne } } ret_ty - case New(S((nmedTy, trm)), TypingUnit(Nil)) => + case New(S((nmedTy, trm)), TypingUnit(Nil)) if !newDefs => typeMonomorphicTerm(App(Var(nmedTy.base.name).withLocOf(nmedTy), trm)) + case nw @ New(S((nmedTy, trm: Tup)), TypingUnit(Nil)) if newDefs => + typeMonomorphicTerm(App(New(S((nmedTy, UnitLit(true))), TypingUnit(Nil)).withLocOf(nw), trm)) + case New(S((nmedTy, UnitLit(true))), TypingUnit(Nil)) if newDefs => + if (nmedTy.targs.nonEmpty) + err(msg"Type arguments in `new` expressions are not yet supported", prov.loco) + ctx.get(nmedTy.base.name).fold(err("identifier not found: " + nmedTy.base, term.toLoc): ST) { + case AbstractConstructor(absMths, traitWithMths) => die + case VarSymbol(ty, _) => + err(msg"Cannot use `new` on non-class variable of type ${ty.expPos}", term.toLoc) + case lti: LazyTypeInfo => + def checkNotAbstract(decl: NuDecl) = + if (decl.isAbstract) + err(msg"Class ${decl.name} is abstract and cannot be instantiated", term.toLoc) + lti match { + case ti: CompletedTypeInfo => + ti.member match { + case _: TypedNuFun | _: NuParam => + err(msg"${ti.member.kind.str.capitalize} ${ti.member.name + } cannot be used in `new` expression", prov.loco) + case ti: TypedNuCls => + checkNotAbstract(ti.decl) + ti.typeSignature(true, prov.loco) + case ti: TypedNuDecl => + err(msg"${ti.kind.str.capitalize} ${ti.name + } cannot be used in term position", prov.loco) + } + case dti: DelayedTypeInfo if !(dti.kind is Cls) => + err(msg"${dti.kind.str.capitalize} ${dti.name + } cannot be used in `new` expression", prov.loco) + case dti: DelayedTypeInfo => + checkNotAbstract(dti.decl) + dti.typeSignature(true, prov.loco) + } + } case New(base, args) => err(msg"Currently unsupported `new` syntax", term.toCoveringLoc) - case TyApp(_, _) => - // ??? // TODO handle - err(msg"Type application syntax is not yet supported", term.toLoc) + case TyApp(base, _) => + err(msg"Type application syntax is not yet supported", term.toLoc) // TODO handle + typeTerm(base) case Where(bod, sts) => typeTerms(sts :+ bod, false, Nil, allowPure = true) case Forall(vs, bod) => @@ -1563,19 +1599,30 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne Nil, // TODO mixin parents? Option.when(!(TopType <:< superTy))(go(superTy)), Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) + mkTypingUnit(thisTy, members) + )(td.declareLoc, td.abstractLoc) } - case TypedNuCls(level, td, tparams, params, members, thisTy, sign, ihtags, ptps) => + case TypedNuCls(level, td, tparams, params, acParams, members, thisTy, sign, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, - Opt.when(td.params.isDefined)(Tup(params.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2.ub)))))), + // Opt.when(td.params.isDefined)(Tup(params.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2.ub)))))), + params.map(ps => Tup(ps.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2.ub)))))), td.ctor, Option.when(!(TopType <:< sign))(go(sign)), ihtags.toList.sorted.map(_.toVar), // TODO provide targs/args N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) - } + { + val tun = mkTypingUnit(thisTy, members) + acParams match { + case S(ps) => TypingUnit(Constructor( + Tup(ps.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2))))), + Blk(Nil)) :: tun.entities) + case N => tun + } + } + )(td.declareLoc, td.abstractLoc) + } case TypedNuTrt(level, td, tparams, members, thisTy, sign, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, @@ -1585,8 +1632,9 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne ihtags.toList.sorted.map(_.toVar), // TODO provide targs/args N,//TODO Option.when(!(TopType <:< thisTy))(go(thisTy)), - mkTypingUnit(thisTy, members))(td.declareLoc, td.abstractLoc) - } + mkTypingUnit(thisTy, members) + )(td.declareLoc, td.abstractLoc) + } case tf @ TypedNuFun(level, fd, bodyTy) => NuFunDef(fd.isLetRec, fd.nme, fd.symbolicNme, Nil, R(go(tf.typeSignature)))(fd.declareLoc, fd.virtualLoc, fd.signature, fd.outer, fd.genField) case p: NuParam => diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 8136aa12fc..306c82c566 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -41,12 +41,14 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => sealed abstract class LazyTypeInfo extends TypeInfo { def complete()(implicit raise: Raise): NuMember def kind: DeclKind + def name: Str } /** A LazyTypeInfo whose typing has been completed. */ case class CompletedTypeInfo(member: NuMember) extends LazyTypeInfo { def complete()(implicit raise: Raise): NuMember = member def kind: DeclKind = member.kind + val name: Str = member.name } /** Initialized lazy type information, to be computed soon. */ diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 21edc1b254..f20085d620 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -829,7 +829,8 @@ abstract class TyperHelpers { Typer: Typer => case cls: TypedNuCls => cls.tparams.iterator.map(pol.invar -> _._2) ++ // cls.params.flatMap(p => childrenPolField(pol.invar)(p._2)) - cls.params.flatMap(p => childrenPolField(PolMap.pos)(p._2)) ++ + cls.params.toList.flatMap(_.flatMap(p => childrenPolField(PolMap.pos)(p._2))) ++ + cls.auxCtorParams.toList.flatMap(_.map(PolMap.neg -> _._2)) ++ cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.sign) ++ @@ -961,7 +962,8 @@ abstract class TyperHelpers { Typer: Typer => S(mxn.thisTy) case cls: TypedNuCls => cls.tparams.iterator.map(_._2) ++ - cls.params.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil) ++ + cls.params.toList.flatMap(_.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil)) ++ + cls.auxCtorParams.toList.flatMap(_.values) ++ cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ S(cls.sign) ++ @@ -1300,9 +1302,10 @@ abstract class TyperHelpers { Typer: Typer => case TypedNuAls(level, td, tparams, body) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) apply(pol)(body) - case TypedNuCls(level, td, tparams, params, members, thisTy, sign, _, ptps) => + case TypedNuCls(level, td, tparams, params, acParams, members, thisTy, sign, _, ptps) => tparams.iterator.foreach(tp => apply(pol.invar)(tp._2)) - params.foreach(p => applyField(pol)(p._2)) + params.foreach(_.foreach(p => applyField(pol)(p._2))) + acParams.foreach(_.foreach(p => apply(pol.contravar)(p._2))) members.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTy) apply(pol.contravar)(sign) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index ffc732f83d..361fce59db 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -28,6 +28,8 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Field(S(lb), Top) => s"in ${lb.showIn(ctx, 0)}" case Field(S(lb), ub) => s"in ${lb.showIn(ctx, 0)} out ${ub.showIn(ctx, 0)}" } + private def showFields(fs: Ls[Opt[Var] -> Field], ctx: ShowCtx): Ls[Str] = + fs.map(nt => s"${nt._2.mutStr}${nt._1.fold("")(_.name + ": ")}${showField(nt._2, ctx)}") def showIn(ctx: ShowCtx, outerPrec: Int): Str = this match { // TODO remove obsolete pretty-printing hacks case Top => "anything" @@ -43,7 +45,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Nil => "()" case N -> Field(N, f) :: Nil if !f.isInstanceOf[Tuple] => f.showIn(ctx, 31) case _ => - val inner = fs.map(nt => s"${nt._2.mutStr}${nt._1.fold("")(_.name + ": ")}${showField(nt._2, ctx)}") + val inner = showFields(fs, ctx) if (ctx.newDefs) inner.mkString("(", ", ", ")") else inner.mkString("(", ", ", ",)") } parensIf(innerStr + " -> " + r.showIn(ctx, 30), outerPrec > 30) @@ -66,7 +68,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => val inner = fs.map{case L(l) => s"...${l.showIn(ctx, 0)}" case R(r) => s"${showField(r, ctx)}"} if (ctx.newDefs) inner.mkString("[", ", ", "]") else inner.mkString("(", ", ", ")") case Tuple(fs) => - val inner = fs.map(nt => s"${nt._2.mutStr}${nt._1.fold("")(_.name + ": ")}${showField(nt._2, ctx)}") + val inner = showFields(fs, ctx) if (ctx.newDefs) inner.mkString("[", ", ", "]") else inner.mkString("(", ", ", if (fs.nonEmpty) ",)" else ")") case Union(TypeName("true"), TypeName("false")) | Union(TypeName("false"), TypeName("true")) => @@ -150,6 +152,12 @@ trait TypeLikeImpl extends Located { self: TypeLike => // })).mkString("", "\n", "\n") })).mkString case NuTypeDef(kind @ Als, nme, tparams, params, ctor, sig, parents, sup, ths, body) => + assert(params.isEmpty, params) + assert(ctor.isEmpty, ctor) + assert(parents.isEmpty, parents) + assert(sup.isEmpty, sup) + assert(ths.isEmpty, ths) + assert(body.entities.isEmpty, body) s"type ${nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")} = ${ sig.getOrElse(die).showIn(ctx, 0)}" case td @ NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => @@ -158,8 +166,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => nme.name}${tparams.map(_._2.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}${params match { case S(Tup(fields)) => s"(${fields.map { case (N, Fld(_, Asc(v: Var, ty))) => v.name + ": " + ty.showIn(ctx, 0) - case (N, _) => "???" - case (S(nme), rhs) => nme.name + case (N | S(_), _) => lastWords("ill-formed type definition parameter") }.mkString(", ")})" case _ => "" }}${sig.fold("")(": " + _.showIn(bodyCtx, 0))}${parents match { @@ -168,6 +175,13 @@ trait TypeLikeImpl extends Located { self: TypeLike => }}${if (body.entities.isEmpty && sup.isEmpty && ths.isEmpty) "" else " {\n" + sup.fold("")(s"${bodyCtx.indStr}super: " + _.showIn(bodyCtx, 0) + "\n") + ths.fold("")(s"${bodyCtx.indStr}this: " + _.showIn(bodyCtx, 0) + "\n") + + body.entities.collect { + case Constructor(params, body) => s"${bodyCtx.indStr}constructor(${params.fields.map { + case N -> Fld(FldFlags(false, false, false), Asc(Var(nme), ty)) => + s"${nme}: ${ty.showIn(bodyCtx, 0)}" + case _ => lastWords("ill-formed constructor parameter") + }.mkString(", ")})\n" + }.mkString + Signature(body.entities.collect { case d: NuDecl => d }, N).showIn(bodyCtx, 0) + ctx.indStr + "}" }" @@ -441,8 +455,8 @@ trait NuDeclImpl extends Located { self: NuDecl => lazy val genUnapply: Opt[NuFunDef] = this match { case td: NuTypeDef if td.kind is Cls => td.params.map { tup => val ret = Let(false, Var("_"), Asc(Var("x"), TypeName(name)), Tup(tup.fields.map { - case S(p) -> f => N -> Fld(f.flags, Sel(Var("x"), p)) - case N -> Fld(flags, p: Var) => N -> Fld(flags, Sel(Var("x"), p)) + case S(p) -> f => N -> Fld(FldFlags.empty, Sel(Var("x"), p)) + case N -> Fld(flags, p: Var) => N -> Fld(FldFlags.empty, Sel(Var("x"), p)) case _ => die })) NuFunDef(N, Var("unapply"), N, Nil, L(Lam( @@ -462,7 +476,8 @@ trait TypingUnitImpl extends Located { self: TypingUnit => } trait TypeNameImpl extends Ordered[TypeName] { self: TypeName => - val base: TypeName = this + def base: TypeName = this + def targs: Ls[Type] = Nil def compare(that: TypeName): Int = this.name compare that.name lazy val toVar: Var = Var(name).withLocOf(this) } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index c4f199abc5..3c5cf7bc3d 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -138,7 +138,7 @@ sealed abstract class TypeLike extends TypeLikeImpl sealed abstract class Type extends TypeLike with TypeImpl -sealed trait NamedType extends Type { val base: TypeName } +sealed trait NamedType extends Type { def base: TypeName; def targs: Ls[Type] } sealed abstract class Composed(val pol: Bool) extends Type with ComposedImpl diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index d8007b9f6f..6895f2dccf 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -243,9 +243,9 @@ class Desugarer extends TypeDefs { self: Typer => ctx.tyDefs.get(className).map(td => (td.kind, td.positionals)) .orElse(ctx.get(className) match { case S(ti: DelayedTypeInfo) if ti.decl.kind is Cls => - S((ti.decl.kind, ti.typedParams.map(_._1.name))) + S((ti.decl.kind, ti.typedParams.getOrElse(Nil).map(_._1.name))) // * Error should be caught before if this doesn't take params case S(CompletedTypeInfo(td: TypedNuCls)) => - S((td.decl.kind, td.params.map(_._1.name))) + S((td.decl.kind, td.params.getOrElse(Nil).map(_._1.name))) // * Error should be caught before if this doesn't take params case _ => throw new DesugaringException(msg"Illegal pattern `$className`", classNameVar.toLoc) }) match { case N => diff --git a/shared/src/test/diff/codegen/OptionalParam.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls similarity index 71% rename from shared/src/test/diff/codegen/OptionalParam.mls rename to shared/src/test/diff/codegen/AuxiliaryConstructors.mls index 25a2ce400e..7003cc9827 100644 --- a/shared/src/test/diff/codegen/OptionalParam.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -36,7 +36,9 @@ class A(x: Int) {} :js class B {} -//│ class B +//│ class B { +//│ constructor() +//│ } //│ // Prelude //│ class TypingUnit1 { //│ #B; @@ -55,40 +57,101 @@ class B {} //│ globalThis.B = typing_unit1.B; //│ // End of generated code +new B +//│ B +//│ res +//│ = B {} + +:e +B() +//│ ╔══[ERROR] Construction of unparameterized class B should use the `new` keyword +//│ ║ l.66: B() +//│ ╙── ^ +//│ B +//│ res +//│ Runtime error: +//│ TypeError: Class constructor B cannot be invoked without 'new' + +abstract class C +//│ abstract class C + +:e +new C +//│ ╔══[ERROR] Class C is abstract and cannot be instantiated +//│ ║ l.79: new C +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Class C cannot be instantiated as it exposes no such constructor +//│ ║ l.79: new C +//│ ╙── ^^^^^ +//│ error +//│ res +//│ = C {} + +:e +C() +//│ ╔══[ERROR] Class C is abstract and cannot be instantiated +//│ ║ l.91: C() +//│ ╙── ^ +//│ ╔══[ERROR] Class C cannot be instantiated as it exposes no such constructor +//│ ║ l.91: C() +//│ ╙── ^ +//│ error +//│ res +//│ Runtime error: +//│ TypeError: Class constructor C cannot be invoked without 'new' + :js class C { - constructor(x: Int) + constructor(x: Int) { log(x) } } -//│ class C +//│ class C { +//│ constructor(x: Int) +//│ } //│ // Prelude -//│ class TypingUnit2 { +//│ function log(x) { +//│ return console.info(x); +//│ } +//│ class TypingUnit7 { //│ #C; //│ constructor() { //│ } //│ get C() { //│ const qualifier = this; //│ if (this.#C === undefined) { -//│ class C {}; +//│ class C { +//│ constructor(x) { +//│ log(x); +//│ } +//│ }; //│ this.#C = C; //│ } //│ return this.#C; //│ } //│ } -//│ const typing_unit2 = new TypingUnit2; -//│ globalThis.C = typing_unit2.C; +//│ const typing_unit7 = new TypingUnit7; +//│ globalThis.C = typing_unit7.C; //│ // End of generated code -:e // TODO: typing -let c = new C(1) +:e +let c = new C() //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.82: let c = new C(1) -//│ ║ ^^^^ -//│ ╟── argument of type `[1]` does not match type `[]` -//│ ║ l.82: let c = new C(1) -//│ ╙── ^^^ +//│ ║ l.136: let c = new C() +//│ ║ ^^^^^^^ +//│ ╟── argument of type `[]` does not match type `[x: Int]` +//│ ║ l.136: let c = new C() +//│ ╙── ^^ //│ let c: C | error //│ c //│ = C {} +//│ // Output +//│ undefined + +let c = new C(1) +//│ let c: C +//│ c +//│ = C {} +//│ // Output +//│ 1 :js class D(val x: Int) { @@ -97,12 +160,11 @@ class D(val x: Int) { } log(x) } -//│ class D(x: Int) -//│ // Prelude -//│ function log(x) { -//│ return console.info(x); +//│ class D(x: Int) { +//│ constructor(y: Int) //│ } -//│ class TypingUnit4 { +//│ // Prelude +//│ class TypingUnit10 { //│ #D; //│ constructor() { //│ } @@ -129,8 +191,8 @@ class D(val x: Int) { //│ return this.#D; //│ } //│ } -//│ const typing_unit4 = new TypingUnit4; -//│ globalThis.D = typing_unit4.D; +//│ const typing_unit10 = new TypingUnit10; +//│ globalThis.D = typing_unit10.D; //│ // End of generated code let dd = new D(41) @@ -144,41 +206,51 @@ dd.x //│ res //│ = 42 +let dd = D(41) +dd.x +//│ let dd: D +//│ Int +//│ dd +//│ = D {} +//│ // Output +//│ 42 +//│ res +//│ = 42 + :pe class E { constructor(x: Int) constructor(y: Int) } //│ ╔══[PARSE ERROR] A class may only have at most one explicit constructor -//│ ║ l.148: class E { +//│ ║ l.221: class E { //│ ╙── ^^^^^ -//│ class E +//│ class E { +//│ constructor() +//│ } :e constructor(x: Int) //│ ╔══[ERROR] constructor must be in a class. -//│ ║ l.158: constructor(x: Int) +//│ ║ l.233: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ [] //│ Code generation encountered an error: //│ unexpected constructor. -:e :js class F(x: Int) extends C(x + 1) {} class G extends C(2) {} class H extends B {} -//│ ╔══[ERROR] class C expects 0 parameter(s); got 1 -//│ ║ l.168: class F(x: Int) extends C(x + 1) {} -//│ ╙── ^^^^^^^ -//│ ╔══[ERROR] class C expects 0 parameter(s); got 1 -//│ ║ l.169: class G extends C(2) {} -//│ ╙── ^^^ //│ class F(x: Int) extends C -//│ class G extends C -//│ class H extends B +//│ class G extends C { +//│ constructor() +//│ } +//│ class H extends B { +//│ constructor() +//│ } //│ // Prelude -//│ class TypingUnit7 { +//│ class TypingUnit14 { //│ #F; //│ #G; //│ #H; @@ -229,10 +301,10 @@ class H extends B {} //│ return this.#H; //│ } //│ } -//│ const typing_unit7 = new TypingUnit7; -//│ globalThis.F = typing_unit7.F; -//│ globalThis.G = typing_unit7.G; -//│ globalThis.H = typing_unit7.H; +//│ const typing_unit14 = new TypingUnit14; +//│ globalThis.F = typing_unit14.F; +//│ globalThis.G = typing_unit14.G; +//│ globalThis.H = typing_unit14.H; //│ // End of generated code :js @@ -243,8 +315,8 @@ fun f(c) = _ then 0 //│ fun f: Object -> Int //│ // Prelude -//│ class TypingUnit8 {} -//│ const typing_unit8 = new TypingUnit8; +//│ class TypingUnit15 {} +//│ const typing_unit15 = new TypingUnit15; //│ // Query 1 //│ globalThis.f = function f(c) { //│ return ((() => { @@ -259,11 +331,14 @@ f(new G()) //│ Int //│ res //│ = 12 +//│ // Output +//│ 13 //│ res //│ = 2 +//│ // Output +//│ 2 :js -:e module I { class J { constructor(x: Int) @@ -272,17 +347,18 @@ module I { class L extends J(0) } } -//│ ╔══[ERROR] class J expects 0 parameter(s); got 1 -//│ ║ l.272: class L extends J(0) -//│ ╙── ^^^ //│ module I { -//│ class J +//│ class J { +//│ constructor(x: Int) +//│ } //│ module K { -//│ class L extends J +//│ class L extends J { +//│ constructor() +//│ } //│ } //│ } //│ // Prelude -//│ class TypingUnit10 { +//│ class TypingUnit17 { //│ #I; //│ constructor() { //│ } @@ -334,8 +410,8 @@ module I { //│ return this.#I; //│ } //│ } -//│ const typing_unit10 = new TypingUnit10; -//│ globalThis.I = typing_unit10.I; +//│ const typing_unit17 = new TypingUnit17; +//│ globalThis.I = typing_unit17.I; //│ // End of generated code :js @@ -349,8 +425,8 @@ fun g(x: Int) = L //│ fun g: (x: Int) -> (y: Int) -> L //│ // Prelude -//│ class TypingUnit11 {} -//│ const typing_unit11 = new TypingUnit11; +//│ class TypingUnit18 {} +//│ const typing_unit18 = new TypingUnit18; //│ // Query 1 //│ globalThis.g = function g(x) { //│ return ((() => { @@ -388,8 +464,8 @@ n.ll //│ let n: L //│ Int //│ // Prelude -//│ class TypingUnit12 {} -//│ const typing_unit12 = new TypingUnit12; +//│ class TypingUnit19 {} +//│ const typing_unit19 = new TypingUnit19; //│ // Query 1 //│ globalThis.m = g(1); //│ // Query 2 @@ -411,14 +487,15 @@ class M() let mm = new M() //│ let mm: M //│ // Prelude -//│ class TypingUnit14 {} -//│ const typing_unit14 = new TypingUnit14; +//│ class TypingUnit21 {} +//│ const typing_unit21 = new TypingUnit21; //│ // Query 1 //│ globalThis.mm = new M.class(); //│ // End of generated code //│ mm //│ = M {} +:e // TODO support first-class classes fun h(z: Int) = class N { constructor(x: Int) { @@ -426,21 +503,22 @@ fun h(z: Int) = } } N -//│ fun h: (z: Int) -> () -> N +//│ ╔══[ERROR] Construction of unparameterized class N should use the `new` keyword +//│ ║ l.505: N +//│ ╙── ^ +//│ fun h: (z: Int) -> (x: Int) -> N -:e // TODO: typing let hh = h(1) -new hh(1) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.433: new hh(1) -//│ ║ ^^^^^ -//│ ╟── argument of type `[1]` does not match type `[]` -//│ ║ l.433: new hh(1) -//│ ╙── ^^^ -//│ let hh: () -> N -//│ N | error +//│ let hh: (x: Int) -> N //│ hh //│ = [class N] + +:e +new hh(1) +//│ ╔══[ERROR] Value hh cannot be used in `new` expression +//│ ║ l.517: new hh(1) +//│ ╙── ^^^^^^^^^ +//│ error //│ res //│ = N {} //│ // Output @@ -454,10 +532,14 @@ mixin P { constructor(x: Int) } //│ ╔══[ERROR] Explicit module constructors are not supported -//│ ║ l.451: constructor(x: Int) +//│ ║ l.529: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Explicit mixin constructors are not supported -//│ ║ l.454: constructor(x: Int) +//│ ║ l.532: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ module O +//│ module O { +//│ constructor(x: Int) +//│ } //│ mixin P() + + diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index ee3aaf4679..83efd3c333 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -1,17 +1,21 @@ -:NewParser :NewDefs + +log("Hello!") +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ Hello! + + :js module Test0 { log("Hello!") } //│ module Test0 //│ // Prelude -//│ function log(x) { -//│ return console.info(x); -//│ } -//│ let res; -//│ class TypingUnit { +//│ class TypingUnit1 { //│ #Test0; //│ constructor() { //│ } @@ -29,16 +33,16 @@ module Test0 { //│ return this.#Test0; //│ } //│ } -//│ const typing_unit = new TypingUnit; -//│ globalThis.Test0 = typing_unit.Test0; +//│ const typing_unit1 = new TypingUnit1; +//│ globalThis.Test0 = typing_unit1.Test0; //│ // End of generated code :js Test0 //│ Test0 //│ // Prelude -//│ class TypingUnit1 {} -//│ const typing_unit1 = new TypingUnit1; +//│ class TypingUnit2 {} +//│ const typing_unit2 = new TypingUnit2; //│ // Query 1 //│ res = Test0; //│ // End of generated code @@ -51,8 +55,8 @@ Test0 Test0 //│ Test0 //│ // Prelude -//│ class TypingUnit2 {} -//│ const typing_unit2 = new TypingUnit2; +//│ class TypingUnit3 {} +//│ const typing_unit3 = new TypingUnit3; //│ // Query 1 //│ res = Test0; //│ // End of generated code @@ -65,7 +69,7 @@ class A(a: Int) { } //│ class A(a: Int) //│ // Prelude -//│ class TypingUnit3 { +//│ class TypingUnit4 { //│ #A; //│ constructor() { //│ } @@ -90,16 +94,16 @@ class A(a: Int) { //│ return this.#A; //│ } //│ } -//│ const typing_unit3 = new TypingUnit3; -//│ globalThis.A = typing_unit3.A; +//│ const typing_unit4 = new TypingUnit4; +//│ globalThis.A = typing_unit4.A; //│ // End of generated code :js let aa = A(42) //│ let aa: A //│ // Prelude -//│ class TypingUnit4 {} -//│ const typing_unit4 = new TypingUnit4; +//│ class TypingUnit5 {} +//│ const typing_unit5 = new TypingUnit5; //│ // Query 1 //│ globalThis.aa = A(42); //│ // End of generated code @@ -112,8 +116,8 @@ let aa = A(42) aa //│ A //│ // Prelude -//│ class TypingUnit5 {} -//│ const typing_unit5 = new TypingUnit5; +//│ class TypingUnit6 {} +//│ const typing_unit6 = new TypingUnit6; //│ // Query 1 //│ res = aa; //│ // End of generated code @@ -124,8 +128,8 @@ aa let ab = A(0) //│ let ab: A //│ // Prelude -//│ class TypingUnit6 {} -//│ const typing_unit6 = new TypingUnit6; +//│ class TypingUnit7 {} +//│ const typing_unit7 = new TypingUnit7; //│ // Query 1 //│ globalThis.ab = A(0); //│ // End of generated code @@ -140,11 +144,13 @@ class Foo { this: { x: Int } } //│ ╔══[ERROR] Type `#Foo` does not contain member `x` -//│ ║ l.140: this: { x: Int } +//│ ║ l.144: this: { x: Int } //│ ╙── ^ -//│ class Foo +//│ class Foo { +//│ constructor() +//│ } //│ // Prelude -//│ class TypingUnit7 { +//│ class TypingUnit8 { //│ #Foo; //│ constructor() { //│ } @@ -157,8 +163,8 @@ class Foo { //│ return this.#Foo; //│ } //│ } -//│ const typing_unit7 = new TypingUnit7; -//│ globalThis.Foo = typing_unit7.Foo; +//│ const typing_unit8 = new TypingUnit8; +//│ globalThis.Foo = typing_unit8.Foo; //│ // End of generated code :e @@ -167,14 +173,16 @@ class Bar { super: { x: Int } } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.167: super: { x: Int } +//│ ║ l.173: super: { x: Int } //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#Bar` does not contain member `x` -//│ ║ l.167: super: { x: Int } +//│ ║ l.173: super: { x: Int } //│ ╙── ^ -//│ class Bar +//│ class Bar { +//│ constructor() +//│ } //│ // Prelude -//│ class TypingUnit8 { +//│ class TypingUnit9 { //│ #Bar; //│ constructor() { //│ } @@ -187,8 +195,8 @@ class Bar { //│ return this.#Bar; //│ } //│ } -//│ const typing_unit8 = new TypingUnit8; -//│ globalThis.Bar = typing_unit8.Bar; +//│ const typing_unit9 = new TypingUnit9; +//│ globalThis.Bar = typing_unit9.Bar; //│ // End of generated code :js @@ -205,7 +213,7 @@ class Baz() { //│ let y: Int //│ } //│ // Prelude -//│ class TypingUnit9 { +//│ class TypingUnit10 { //│ #Baz; //│ constructor() { //│ } @@ -249,8 +257,8 @@ class Baz() { //│ return this.#Baz; //│ } //│ } -//│ const typing_unit9 = new TypingUnit9; -//│ globalThis.Baz = typing_unit9.Baz; +//│ const typing_unit10 = new TypingUnit10; +//│ globalThis.Baz = typing_unit10.Baz; //│ // End of generated code let baz = Baz() @@ -279,7 +287,7 @@ class Q() { //│ fun qq: {q: Int} //│ } //│ // Prelude -//│ class TypingUnit11 { +//│ class TypingUnit12 { //│ #Q; //│ constructor() { //│ } @@ -311,8 +319,8 @@ class Q() { //│ return this.#Q; //│ } //│ } -//│ const typing_unit11 = new TypingUnit11; -//│ globalThis.Q = typing_unit11.Q; +//│ const typing_unit12 = new TypingUnit12; +//│ globalThis.Q = typing_unit12.Q; //│ // End of generated code let q = Q() @@ -334,7 +342,7 @@ class W() { //│ let x: 42 //│ } //│ // Prelude -//│ class TypingUnit13 { +//│ class TypingUnit14 { //│ #W; //│ constructor() { //│ } @@ -363,8 +371,8 @@ class W() { //│ return this.#W; //│ } //│ } -//│ const typing_unit13 = new TypingUnit13; -//│ globalThis.W = typing_unit13.W; +//│ const typing_unit14 = new TypingUnit14; +//│ globalThis.W = typing_unit14.W; //│ // End of generated code :js @@ -373,8 +381,8 @@ www.add(42) //│ let www: W //│ Int //│ // Prelude -//│ class TypingUnit14 {} -//│ const typing_unit14 = new TypingUnit14; +//│ class TypingUnit15 {} +//│ const typing_unit15 = new TypingUnit15; //│ // Query 1 //│ globalThis.www = W(); //│ // Query 2 diff --git a/shared/src/test/diff/codegen/New.mls b/shared/src/test/diff/codegen/New.mls index 8a3a75346b..1e8b0b88de 100644 --- a/shared/src/test/diff/codegen/New.mls +++ b/shared/src/test/diff/codegen/New.mls @@ -2,7 +2,9 @@ class C -//│ class C +//│ class C { +//│ constructor() +//│ } :js new C @@ -16,9 +18,12 @@ new C //│ res //│ = C {} -:re // TODO reject in type checking +:e :js C() +//│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword +//│ ║ l.23: C() +//│ ╙── ^ //│ C //│ // Prelude //│ class TypingUnit2 {} @@ -31,7 +36,11 @@ C() //│ TypeError: Class constructor C cannot be invoked without 'new' :js +:e // TODO support first-class classes let c = C +//│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword +//│ ║ l.40: let c = C +//│ ╙── ^ //│ let c: () -> C //│ // Prelude //│ class TypingUnit3 {} @@ -42,7 +51,7 @@ let c = C //│ c //│ = [class C] -:re // TODO reject in type checking +:re // TODO should eventually be reject in type checking c() //│ C //│ res diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index 30243e2a23..34c1a6638c 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -162,6 +162,7 @@ class FooBar { val x = 42 } //│ class FooBar { +//│ constructor() //│ let x: 42 //│ } //│ // Prelude @@ -218,7 +219,7 @@ fun ft(x) = FooBar(x) then x _ then 0 //│ ╔══[ERROR] class FooBar expects 0 parameter but found 1 parameter -//│ ║ l.218: FooBar(x) then x +//│ ║ l.219: FooBar(x) then x //│ ╙── ^^^^^^^^^ //│ fun ft: anything -> error //│ Code generation encountered an error: @@ -264,7 +265,7 @@ fun c(x) = VVC(x, y, z) then x + y + z _ then 0 //│ ╔══[ERROR] class VVC expects 2 parameters but found 3 parameters -//│ ║ l.264: VVC(x, y, z) then x + y + z +//│ ║ l.265: VVC(x, y, z) then x + y + z //│ ╙── ^^^^^^^^^^^^ //│ class VVC(v: Int, vc: Int) //│ fun c: anything -> error diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index 8993e3a756..afc1f5e582 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -80,8 +80,8 @@ a.f //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.78: let a = C[Int](42) //│ ╙── ^^^^^^ -//│ let a: error -//│ error +//│ let a: C[42] +//│ 42 //│ a //│ = C {} //│ res diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 3dfb473f62..467d4259fa 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -159,6 +159,7 @@ class Foo extends Foo0 { fun foo0(n) = [super.foo0, super.foo0 + n] } //│ class Foo { +//│ constructor() //│ fun foo0: Int -> [0, Int] //│ } diff --git a/shared/src/test/diff/codegen/ValLet.mls b/shared/src/test/diff/codegen/ValLet.mls index 891f084edb..0431446238 100644 --- a/shared/src/test/diff/codegen/ValLet.mls +++ b/shared/src/test/diff/codegen/ValLet.mls @@ -175,12 +175,17 @@ B(0, 0).y //│ res //│ = 0 -// TODO: is this expected? +:e :js class C { constructor(val x: Int, y: Int) } -//│ class C +//│ ╔══[ERROR] Cannot use `val` in constructor parameters +//│ ║ l.181: constructor(val x: Int, y: Int) +//│ ╙── ^ +//│ class C { +//│ constructor(x: Int, y: Int) +//│ } //│ // Prelude //│ class TypingUnit7 { //│ #C; @@ -205,10 +210,23 @@ class C { //│ globalThis.C = typing_unit7.C; //│ // End of generated code -// TODO: shoud be rejected? +// * TODO improve error location +:e fun f(val x: Int) = x + 1 +//│ ╔══[ERROR] Cannot use `val` in this position +//│ ║ l.215: fun f(val x: Int) = x + 1 +//│ ╙── ^^^^^^ //│ fun f: (x: Int) -> Int +:e +(val x: 1) +//│ ╔══[ERROR] Cannot use `val` in this position +//│ ║ l.222: (val x: 1) +//│ ╙── ^^^^ +//│ [x: 1] +//│ res +//│ = [ 1 ] + class D(x: Int) { let x = 1 } diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 707f2221f2..4e7d1a4d4d 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -4,7 +4,9 @@ class Exp[A]: Pair | Lit class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] -//│ class Exp[A]: Lit | Pair[anything, anything] +//│ class Exp[A]: Lit | Pair[anything, anything] { +//│ constructor() +//│ } //│ class Lit(n: Int) extends Exp //│ class Pair[L, R](lhs: L, rhs: R) extends Exp @@ -34,7 +36,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.35: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.37: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -47,10 +49,10 @@ fun f(e) = if e is fun f(x: a) = x f(l) //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.47: fun f(x: a) = x +//│ ║ l.49: fun f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.48: f(l) +//│ ║ l.50: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index 52e62ecda6..f174a8ec11 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -4,7 +4,9 @@ class Exp[A]: Pair | Lit class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] -//│ class Exp[A]: Lit | Pair[?, ?] +//│ class Exp[A]: Lit | Pair[?, ?] { +//│ constructor() +//│ } //│ class Lit(n: Int) extends Exp //│ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp @@ -27,7 +29,7 @@ fun f(e) = if e is :e (e: Exp['X]) => f(e) //│ ╔══[ERROR] Type error in application -//│ ║ l.28: (e: Exp['X]) => f(e) +//│ ║ l.30: (e: Exp['X]) => f(e) //│ ║ ^^^^ //│ ╟── type variable `L` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] @@ -47,21 +49,21 @@ fun f(e) = if e is Pair(l, r) then f(l) + f(r) Lit(n) then n //│ ╔══[ERROR] Type error in definition -//│ ║ l.46: fun f(e) = if e is +//│ ║ l.48: fun f(e) = if e is //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.47: Pair(l, r) then f(l) + f(r) +//│ ║ l.49: Pair(l, r) then f(l) + f(r) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.48: Lit(n) then n +//│ ║ l.50: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ //│ ╔══[ERROR] Type error in definition -//│ ║ l.46: fun f(e) = if e is +//│ ║ l.48: fun f(e) = if e is //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.47: Pair(l, r) then f(l) + f(r) +//│ ║ l.49: Pair(l, r) then f(l) + f(r) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.48: Lit(n) then n +//│ ║ l.50: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `R` leaks out of its scope //│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index bd4491f5de..2146952fae 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -30,18 +30,20 @@ Dummy.introspect // * TODO: simplify `forall 'a. Int | 'a` – seems it's not because it shares a var... class Funny: Int { fun test = this + 1 } //│ class Funny: Int | 'a { +//│ constructor() //│ fun test: forall 'a. Int | 'a //│ } :e class Unfunny { fun test = this + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.37: class Unfunny { fun test = this + 1 } +//│ ║ l.38: class Unfunny { fun test = this + 1 } //│ ║ ^^^^^^^^ //│ ╟── reference of type `#Unfunny` is not an instance of type `Int` -//│ ║ l.37: class Unfunny { fun test = this + 1 } +//│ ║ l.38: class Unfunny { fun test = this + 1 } //│ ╙── ^^^^ //│ class Unfunny { +//│ constructor() //│ fun test: Int | error //│ } @@ -54,6 +56,7 @@ class Exp: Pair | Lit { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { +//│ constructor() //│ fun test: 0 | 1 //│ } //│ class Lit(n: Int) extends Exp { @@ -72,6 +75,7 @@ class Exp: Pair | Lit { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { +//│ constructor() //│ fun test: 0 | 1 //│ } //│ class Lit(n: Int) extends Exp { @@ -96,9 +100,10 @@ class Exp: Pair | Lit { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.94: Pair(l, r) then l.test + r.test +//│ ║ l.98: Pair(l, r) then l.test + r.test //│ ╙── ^^^^^ //│ class Exp: Lit | Pair { +//│ constructor() //│ fun test: Int | error //│ } //│ class Lit(n: Int) extends Exp { @@ -118,6 +123,7 @@ class Exp: Pair | Lit { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Exp: Lit | Pair { +//│ constructor() //│ fun test: Int //│ } //│ class Lit(n: Int) extends Exp { @@ -137,25 +143,26 @@ class Exp[A]: Pair | Lit { class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.132: class Exp[A]: Pair | Lit { +//│ ║ l.138: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.133: fun test = if this is +//│ ║ l.139: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.134: Lit then 0 +//│ ║ l.140: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.135: Pair then 1 +//│ ║ l.141: Pair then 1 //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.133: fun test = if this is +//│ ║ l.139: fun test = if this is //│ ║ ^^^^^^^ -//│ ║ l.134: Lit then 0 +//│ ║ l.140: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.135: Pair then 1 +//│ ║ l.141: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.138: class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +//│ ║ l.144: class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ ╙── ^ //│ class Exp[A]: Lit | Pair[anything, anything] { +//│ constructor() //│ fun test: 0 | 1 //│ } //│ class Lit(n: Int) extends Exp { diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index 51fc3eb1c4..9b060093b9 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -22,7 +22,7 @@ Foo(1) new Foo(1) //│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated //│ ║ l.22: new Foo(1) -//│ ╙── ^^^^^^ +//│ ╙── ^^^^^^^^^^ //│ Foo //│ res //│ = Foo {} @@ -108,11 +108,13 @@ class C2 extends C1, T1 //│ ║ l.92: abstract class C1 { fun x: Int | Str } //│ ╙── ^^^^^^^^^^^^ //│ class C2 extends C1, T1 { +//│ constructor() //│ fun x: Int //│ } class C2 extends C1, T1 { fun x = 1 } //│ class C2 extends C1, T1 { +//│ constructor() //│ fun x: 1 //│ } @@ -124,17 +126,19 @@ abstract class C2 extends C1, T1 :e class C3 extends C2 //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C3` -//│ ║ l.125: class C3 extends C2 +//│ ║ l.127: class C3 extends C2 //│ ║ ^^ //│ ╟── Declared here: //│ ║ l.92: abstract class C1 { fun x: Int | Str } //│ ╙── ^^^^^^^^^^^^ //│ class C3 extends C1, C2, T1 { +//│ constructor() //│ fun x: Int //│ } class C3 extends C2 { fun x = 1 } //│ class C3 extends C1, C2, T1 { +//│ constructor() //│ fun x: 1 //│ } @@ -147,10 +151,10 @@ abstract class C { fun foo1 = this.x } //│ ╔══[ERROR] Unqualified access to virtual member x -//│ ║ l.146: fun foo0 = x +//│ ║ l.150: fun foo0 = x //│ ║ ^^^^^^^^ //│ ╟── Declared here: -//│ ║ l.145: fun x : Int +//│ ║ l.149: fun x : Int //│ ╙── ^^^^^^^ //│ abstract class C { //│ fun foo0: Int @@ -165,12 +169,13 @@ class C { fun foo1 = this.x } //│ ╔══[ERROR] Unqualified access to virtual member x -//│ ║ l.164: fun foo0 = x +//│ ║ l.168: fun foo0 = x //│ ║ ^^^^^^^^ //│ ╟── Declared here: -//│ ║ l.163: val x : Int +//│ ║ l.167: val x : Int //│ ╙── ^^^^^^^ //│ class C { +//│ constructor() //│ fun foo0: Int //│ fun foo1: Int //│ let x: Int diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls new file mode 100644 index 0000000000..bf60294a68 --- /dev/null +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -0,0 +1,149 @@ +:NewDefs + + +class C(val x: Int) { constructor(y: Int) { x = y } } +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } + +class C(val x: Int) { constructor(y) { x = y } } +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } + +// * FIXME location +// * TODO `undefined` should be treated as the unit type... +:w // FIXME +class C(val x: Int) { constructor(y: Int) { log(y); x = y; log(x) } } +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ╙── +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } + +// FIXME should be a type error +class C(val x: Int) { constructor(y: Int) { log(x); x = y } } +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.25: class C(val x: Int) { constructor(y: Int) { log(x); x = y } } +//│ ╙── ^ +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol x + +:e +class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ╔══[ERROR] Type mismatch in auxiliary class constructor: +//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `Str` is not an instance of `Int` +//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `Int` +//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ╙── ^^^ +//│ class C(x: Int) { +//│ constructor(y: Str) +//│ } + +:e +class C(val x: Int) { constructor(y: Int) { z = y } } +//│ ╔══[ERROR] Unknown class parameter z +//│ ║ l.54: class C(val x: Int) { constructor(y: Int) { z = y } } +//│ ╙── ^ +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } +//│ Syntax error: +//│ Private field '#z' must be declared in an enclosing class + +:e +class C(val x: Int) { constructor(val y: Int) { x = y } } +//│ ╔══[ERROR] Cannot use `val` in constructor parameters +//│ ║ l.65: class C(val x: Int) { constructor(val y: Int) { x = y } } +//│ ╙── ^ +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } + +:e +class C(val x: Int) { constructor(val y) { x = y } } +//│ ╔══[ERROR] Cannot use `val` in constructor parameters +//│ ║ l.74: class C(val x: Int) { constructor(val y) { x = y } } +//│ ╙── ^ +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } + +:e +class C(val x: Int) { constructor(2 + 2) { x = 0 } } +//│ ╔══[ERROR] Unsupported constructor parameter shape +//│ ║ l.83: class C(val x: Int) { constructor(2 + 2) { x = 0 } } +//│ ╙── ^^^^^ +//│ class C(x: Int) { +//│ constructor(: error) +//│ } +//│ Code generation encountered an error: +//│ Unexpected constructor parameters in C. + + +:w // FIXME +class C(val x: Int, y: Int) { + constructor(z: Int) { x = z; y = z } + log([x, y]) +} +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ╙── +//│ class C(x: Int, y: Int) { +//│ constructor(z: Int) +//│ } + +:e +C(11) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.106: C(11) +//│ ║ ^^^^^ +//│ ╟── argument of type `[11]` does not match type `[x: Int, y: Int]` +//│ ║ l.106: C(11) +//│ ╙── ^^^^ +//│ C | error +//│ res +//│ = C {} +//│ // Output +//│ [ 11, 11 ] + +C(1, 2) +//│ C +//│ res +//│ = C {} +//│ // Output +//│ [ 1, 1 ] + +new C(11) +//│ C +//│ res +//│ = C {} +//│ // Output +//│ [ 11, 11 ] + +:e +new C(1, 2) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.134: new C(1, 2) +//│ ║ ^^^^^^^^^^^ +//│ ╟── argument list of type `[1, 2]` does not match type `[z: Int]` +//│ ║ l.134: new C(1, 2) +//│ ╙── ^^^^^^ +//│ C | error +//│ res +//│ = C {} +//│ // Output +//│ [ 1, 1 ] + + + + diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index 70615699f6..c9ec5fd25f 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -36,16 +36,18 @@ type Test(n: Int) = n //│ type Test = error class Base -//│ class Base +//│ class Base { +//│ constructor() +//│ } :pe :e type Test: Base //│ ╔══[PARSE ERROR] Expected end of input; found ':' instead -//│ ║ l.43: type Test: Base +//│ ║ l.45: type Test: Base //│ ╙── ^ //│ ╔══[ERROR] Type alias definition requires a right-hand side -//│ ║ l.43: type Test: Base +//│ ║ l.45: type Test: Base //│ ╙── ^^^^^^^^^ //│ type Test = error @@ -53,20 +55,20 @@ type Test: Base :e type Test: Base = Int //│ ╔══[PARSE ERROR] Expected end of input; found ':' instead -//│ ║ l.54: type Test: Base = Int +//│ ║ l.56: type Test: Base = Int //│ ╙── ^ //│ ╔══[ERROR] Type alias definition requires a right-hand side -//│ ║ l.54: type Test: Base = Int +//│ ║ l.56: type Test: Base = Int //│ ╙── ^^^^^^^^^ //│ type Test = error :e type Test extends Base //│ ╔══[ERROR] Type alias definitions cannot extend parents -//│ ║ l.64: type Test extends Base +//│ ║ l.66: type Test extends Base //│ ╙── ^^^^ //│ ╔══[ERROR] Type alias definition requires a right-hand side -//│ ║ l.64: type Test extends Base +//│ ║ l.66: type Test extends Base //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ type Test = error @@ -74,20 +76,20 @@ type Test extends Base :e type Test extends Base = Int //│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.75: type Test extends Base = Int +//│ ║ l.77: type Test extends Base = Int //│ ╙── ^ //│ ╔══[ERROR] Type alias definitions cannot extend parents -//│ ║ l.75: type Test extends Base = Int +//│ ║ l.77: type Test extends Base = Int //│ ╙── ^^^^ //│ ╔══[ERROR] Type alias definition requires a right-hand side -//│ ║ l.75: type Test extends Base = Int +//│ ║ l.77: type Test extends Base = Int //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ type Test = error :e type Test = Int extends Base //│ ╔══[ERROR] Type alias definitions cannot extend parents -//│ ║ l.88: type Test = Int extends Base +//│ ║ l.90: type Test = Int extends Base //│ ╙── ^^^^ //│ type Test = Int @@ -95,14 +97,14 @@ type Test = Int extends Base :pe type Poly[mut A] = A //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword here -//│ ║ l.96: type Poly[mut A] = A +//│ ║ l.98: type Poly[mut A] = A //│ ╙── ^^^ //│ type Poly = A :pe type Poly[#A] = A //│ ╔══[PARSE ERROR] Unexpected '#' here -//│ ║ l.103: type Poly[#A] = A +//│ ║ l.105: type Poly[#A] = A //│ ╙── ^ //│ type Poly = A diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index 78243b9d50..996450f0b4 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -25,6 +25,7 @@ class C2 extends C1(y) { //│ ║ l.21: class C2 extends C1(y) { //│ ╙── ^ //│ class C2 extends C1 { +//│ constructor() //│ let y: Int //│ } //│ Code generation encountered an error: @@ -35,9 +36,10 @@ class C2 extends C1(this.y) { val y: Int } //│ ╔══[ERROR] identifier not found: this -//│ ║ l.34: class C2 extends C1(this.y) { +//│ ║ l.35: class C2 extends C1(this.y) { //│ ╙── ^^^^ //│ class C2 extends C1 { +//│ constructor() //│ let y: Int //│ } @@ -48,34 +50,38 @@ class C1(x: C1) :e class C2 extends C1(this) //│ ╔══[ERROR] identifier not found: this -//│ ║ l.49: class C2 extends C1(this) +//│ ║ l.51: class C2 extends C1(this) //│ ╙── ^^^^ -//│ class C2 extends C1 +//│ class C2 extends C1 { +//│ constructor() +//│ } class Foo { virtual fun x: Int = 1 } //│ class Foo { +//│ constructor() //│ fun x: Int //│ } :e class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.62: class Bar extends Foo { fun x = false } +//│ ║ l.67: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.62: class Bar extends Foo { fun x = false } +//│ ║ l.67: class Bar extends Foo { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.62: class Bar extends Foo { fun x = false } +//│ ║ l.67: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.56: class Foo { virtual fun x: Int = 1 } +//│ ║ l.60: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.56: class Foo { virtual fun x: Int = 1 } +//│ ║ l.60: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { +//│ constructor() //│ fun x: false //│ } @@ -85,21 +91,22 @@ class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.84: fun x: Bool +//│ ║ l.90: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.84: fun x: Bool +//│ ║ l.90: fun x: Bool //│ ║ ^^^^ //│ ╟── but it flows into signature of member `x` with expected type `Int` -//│ ║ l.84: fun x: Bool +//│ ║ l.90: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.56: class Foo { virtual fun x: Int = 1 } +//│ ║ l.60: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.56: class Foo { virtual fun x: Int = 1 } +//│ ║ l.60: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { +//│ constructor() //│ fun x: Bool //│ } @@ -111,21 +118,22 @@ mixin M { fun x = false } :e class Bar extends Foo, M //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.106: mixin M { fun x = false } +//│ ║ l.113: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.106: mixin M { fun x = false } +//│ ║ l.113: mixin M { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.106: mixin M { fun x = false } +//│ ║ l.113: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.56: class Foo { virtual fun x: Int = 1 } +//│ ║ l.60: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.56: class Foo { virtual fun x: Int = 1 } +//│ ║ l.60: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { +//│ constructor() //│ fun x: false //│ } @@ -134,12 +142,15 @@ class Bar extends Foo, M class A { class X { fun f = 1 } } trait B { class X { fun g = 1 } } //│ class A { +//│ constructor() //│ class X { +//│ constructor() //│ fun f: 1 //│ } //│ } //│ trait B { //│ class X { +//│ constructor() //│ fun g: 1 //│ } //│ } @@ -147,22 +158,24 @@ trait B { class X { fun g = 1 } } :e class C extends A, B //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.148: class C extends A, B +//│ ║ l.159: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── Declared here: -//│ ║ l.135: trait B { class X { fun g = 1 } } +//│ ║ l.143: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Intersection of class member and class members currently unsupported -//│ ║ l.148: class C extends A, B +//│ ║ l.159: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.134: class A { class X { fun f = 1 } } +//│ ║ l.142: class A { class X { fun f = 1 } } //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.135: trait B { class X { fun g = 1 } } +//│ ║ l.143: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C extends A, B { +//│ constructor() //│ class X { +//│ constructor() //│ fun f: 1 //│ } //│ } @@ -172,15 +185,17 @@ class C extends A { class X { fun g = 1 } } //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.171: class C extends A { +//│ ║ l.184: class C extends A { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.172: class X { fun g = 1 } +//│ ║ l.185: class X { fun g = 1 } //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Declared here: -//│ ║ l.134: class A { class X { fun f = 1 } } +//│ ║ l.142: class A { class X { fun f = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C extends A { +//│ constructor() //│ class X { +//│ constructor() //│ fun g: 1 //│ } //│ } diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 30237c7f44..399cf00db0 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -10,27 +10,33 @@ class C0 extends M0 //│ ╔══[ERROR] mixin M0 expects 1 parameter(s); got 0 //│ ║ l.9: class C0 extends M0 //│ ╙── ^^ -//│ class C0 +//│ class C0 { +//│ constructor() +//│ } :e class C0 extends M0(1, 2) //│ ╔══[ERROR] mixin M0 expects 1 parameter(s); got 2 -//│ ║ l.16: class C0 extends M0(1, 2) +//│ ║ l.18: class C0 extends M0(1, 2) //│ ╙── ^^^^^^^ -//│ class C0 +//│ class C0 { +//│ constructor() +//│ } :e class C0 extends M0(true) //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.23: class C0 extends M0(true) +//│ ║ l.27: class C0 extends M0(true) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `Int` -//│ ║ l.23: class C0 extends M0(true) +//│ ║ l.27: class C0 extends M0(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: mixin M0(x: Int) //│ ╙── ^^^ -//│ class C0 +//│ class C0 { +//│ constructor() +//│ } // TODO catch this at typing (lack of `this`) @@ -39,6 +45,7 @@ class Foo { fun bar = foo } //│ class Foo { +//│ constructor() //│ fun bar: 0 //│ fun foo: 0 //│ } @@ -49,6 +56,7 @@ class Foo { fun bar = foo } //│ class Foo { +//│ constructor() //│ fun bar: 0 //│ let foo: 0 //│ } @@ -66,7 +74,7 @@ module Bar { :e hello //│ ╔══[ERROR] identifier not found: hello -//│ ║ l.67: hello +//│ ║ l.75: hello //│ ╙── ^^^^^ //│ error //│ Code generation encountered an error: @@ -75,7 +83,7 @@ hello :e 1 : I //│ ╔══[ERROR] type identifier not found: I -//│ ║ l.76: 1 : I +//│ ║ l.84: 1 : I //│ ╙── ^ //│ error //│ res @@ -85,21 +93,24 @@ hello :e class Foo[A] { 42: A } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.86: class Foo[A] { 42: A } +//│ ║ l.94: class Foo[A] { 42: A } //│ ║ ^^ //│ ╟── integer literal of type `42` does not match type `A` //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.86: class Foo[A] { 42: A } +//│ ║ l.94: class Foo[A] { 42: A } //│ ╙── ^ -//│ class Foo[A] +//│ class Foo[A] { +//│ constructor() +//│ } :e class C1 { fun oops = this.x } //│ ╔══[ERROR] Type `#C1` does not contain member `x` -//│ ║ l.98: class C1 { fun oops = this.x } -//│ ╙── ^^ +//│ ║ l.108: class C1 { fun oops = this.x } +//│ ╙── ^^ //│ class C1 { +//│ constructor() //│ fun oops: error //│ } @@ -107,12 +118,13 @@ class C1 { fun oops = this.x } :e class C { fun x: Int } //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C` -//│ ║ l.108: class C { fun x: Int } +//│ ║ l.119: class C { fun x: Int } //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.108: class C { fun x: Int } +//│ ║ l.119: class C { fun x: Int } //│ ╙── ^^^^^^ //│ class C { +//│ constructor() //│ fun x: Int //│ } @@ -120,6 +132,7 @@ class C { fun x: Int } // :e class C { val x: Int } //│ class C { +//│ constructor() //│ let x: Int //│ } diff --git a/shared/src/test/diff/nu/BadFieldInit.mls b/shared/src/test/diff/nu/BadFieldInit.mls new file mode 100644 index 0000000000..e145553678 --- /dev/null +++ b/shared/src/test/diff/nu/BadFieldInit.mls @@ -0,0 +1,132 @@ +:NewDefs + + + +:js +module A { + val x = y + val y = x +} +//│ module A { +//│ let x: nothing +//│ let y: nothing +//│ } +//│ // Prelude +//│ let res; +//│ class TypingUnit { +//│ #A; +//│ constructor() { +//│ } +//│ get A() { +//│ const qualifier = this; +//│ if (this.#A === undefined) { +//│ class A { +//│ #x; +//│ get x() { return this.#x; } +//│ #y; +//│ get y() { return this.#y; } +//│ constructor() { +//│ const qualifier1 = this; +//│ this.#x = qualifier1.y; +//│ const x = this.#x; +//│ this.#y = x; +//│ const y = this.#y; +//│ } +//│ } +//│ this.#A = new A(); +//│ this.#A.class = A; +//│ } +//│ return this.#A; +//│ } +//│ } +//│ const typing_unit = new TypingUnit; +//│ globalThis.A = typing_unit.A; +//│ // End of generated code + +[A.x, A.y] +//│ [nothing, nothing] +//│ res +//│ = [ undefined, undefined ] + + +:js +module A { + val x = y + val y = 1 +} +//│ module A { +//│ let x: 1 +//│ let y: 1 +//│ } +//│ // Prelude +//│ class TypingUnit2 { +//│ #A; +//│ constructor() { +//│ } +//│ get A() { +//│ const qualifier = this; +//│ if (this.#A === undefined) { +//│ class A { +//│ #x; +//│ get x() { return this.#x; } +//│ #y; +//│ get y() { return this.#y; } +//│ constructor() { +//│ const qualifier1 = this; +//│ this.#x = qualifier1.y; +//│ const x = this.#x; +//│ this.#y = 1; +//│ const y = this.#y; +//│ } +//│ } +//│ this.#A = new A(); +//│ this.#A.class = A; +//│ } +//│ return this.#A; +//│ } +//│ } +//│ const typing_unit2 = new TypingUnit2; +//│ globalThis.A = typing_unit2.A; +//│ // End of generated code + +[A.x, A.y] +//│ [1, 1] +//│ res +//│ = [ undefined, 1 ] + + + +:e +class B(x: Int, y: Int) { + constructor() { + x = y + y = x + } +} +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.102: x = y +//│ ╙── ^ +//│ class B(x: Int, y: Int) { +//│ constructor() +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol y + +:e +class B(x: Int, y: Int) { + constructor() { + x = y + y = 1 + } +} +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.118: x = y +//│ ╙── ^ +//│ class B(x: Int, y: Int) { +//│ constructor() +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol y + + + diff --git a/shared/src/test/diff/nu/BadScopes.mls b/shared/src/test/diff/nu/BadScopes.mls index 515e23bf16..c8b797dced 100644 --- a/shared/src/test/diff/nu/BadScopes.mls +++ b/shared/src/test/diff/nu/BadScopes.mls @@ -32,7 +32,9 @@ class Bar { x } //│ ║ l.30: class Bar { x } //│ ╙── ^ //│ class Foo(x: Int) -//│ class Bar +//│ class Bar { +//│ constructor() +//│ } //│ Code generation encountered an error: //│ unresolved symbol x diff --git a/shared/src/test/diff/nu/BadSignatures.mls b/shared/src/test/diff/nu/BadSignatures.mls index 03440ff9b4..5a4b8791cc 100644 --- a/shared/src/test/diff/nu/BadSignatures.mls +++ b/shared/src/test/diff/nu/BadSignatures.mls @@ -16,6 +16,7 @@ trait T { class A { virtual fun x = 1 } //│ class A { +//│ constructor() //│ fun x: 1 //│ } @@ -24,13 +25,13 @@ class B() extends A { fun x: Int } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.24: fun x: Int +//│ ║ l.25: fun x: Int //│ ║ ^^^^^^ //│ ╟── type `Int` does not match type `1` -//│ ║ l.24: fun x: Int +//│ ║ l.25: fun x: Int //│ ║ ^^^ //│ ╟── but it flows into signature of member `x` with expected type `1` -//│ ║ l.24: fun x: Int +//│ ║ l.25: fun x: Int //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from integer literal: //│ ║ l.17: class A { virtual fun x = 1 } @@ -68,13 +69,13 @@ class B() extends A { fun x = 1 } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.67: fun x: Int +//│ ║ l.68: fun x: Int //│ ║ ^^^^^^ //│ ╟── type `Int` does not match type `1` -//│ ║ l.67: fun x: Int +//│ ║ l.68: fun x: Int //│ ║ ^^^ //│ ╟── but it flows into signature of member `x` with expected type `1` -//│ ║ l.67: fun x: Int +//│ ║ l.68: fun x: Int //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from integer literal: //│ ║ l.17: class A { virtual fun x = 1 } @@ -90,10 +91,10 @@ class B() extends A { :e mixin M { fun x : Int } //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `M` -//│ ║ l.91: mixin M { fun x : Int } +//│ ║ l.92: mixin M { fun x : Int } //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.91: mixin M { fun x : Int } +//│ ║ l.92: mixin M { fun x : Int } //│ ╙── ^^^^^^^ //│ mixin M() { //│ fun x: Int diff --git a/shared/src/test/diff/nu/BadSuper.mls b/shared/src/test/diff/nu/BadSuper.mls index 8b5c47dbfc..cbd0eab923 100644 --- a/shared/src/test/diff/nu/BadSuper.mls +++ b/shared/src/test/diff/nu/BadSuper.mls @@ -43,6 +43,7 @@ class Foo { //│ ║ l.40: fun f = super //│ ╙── ^^^^^ //│ class Foo { +//│ constructor() //│ fun f: Foo //│ } //│ Syntax error: diff --git a/shared/src/test/diff/nu/BadUCS.mls b/shared/src/test/diff/nu/BadUCS.mls index 05d5210934..b0eda308c0 100644 --- a/shared/src/test/diff/nu/BadUCS.mls +++ b/shared/src/test/diff/nu/BadUCS.mls @@ -2,7 +2,9 @@ class Foo -//│ class Foo +//│ class Foo { +//│ constructor() +//│ } fun foo(x) = if x is Foo then 0 //│ fun foo: Foo -> 0 @@ -12,7 +14,9 @@ module Bar { class Foo0 } //│ module Bar { -//│ class Foo0 +//│ class Foo0 { +//│ constructor() +//│ } //│ } fun foo(x) = if x is Bar then 0 @@ -21,7 +25,7 @@ fun foo(x) = if x is Bar then 0 :e fun foo(x) = if x is Foo0 then 0 //│ ╔══[ERROR] Cannot find constructor `Foo0` in scope -//│ ║ l.22: fun foo(x) = if x is Foo0 then 0 +//│ ║ l.26: fun foo(x) = if x is Foo0 then 0 //│ ╙── ^^^^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -34,7 +38,7 @@ type F = Foo :e fun foo(x) = if x is F then 0 //│ ╔══[ERROR] Cannot find constructor `F` in scope -//│ ║ l.35: fun foo(x) = if x is F then 0 +//│ ║ l.39: fun foo(x) = if x is F then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -43,7 +47,7 @@ fun foo(x) = if x is F then 0 :e fun foo(x) = if x is F() then 0 //│ ╔══[ERROR] Illegal pattern `F` -//│ ║ l.44: fun foo(x) = if x is F() then 0 +//│ ║ l.48: fun foo(x) = if x is F() then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -56,7 +60,7 @@ mixin M :e fun foo(x) = if x is M then 0 //│ ╔══[ERROR] Cannot find constructor `M` in scope -//│ ║ l.57: fun foo(x) = if x is M then 0 +//│ ║ l.61: fun foo(x) = if x is M then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -65,7 +69,7 @@ fun foo(x) = if x is M then 0 :e fun foo(x) = if x is M() then 0 //│ ╔══[ERROR] Illegal pattern `M` -//│ ║ l.66: fun foo(x) = if x is M() then 0 +//│ ║ l.70: fun foo(x) = if x is M() then 0 //│ ╙── ^ //│ fun foo: anything -> error //│ Code generation encountered an error: @@ -82,7 +86,7 @@ fun foo = 0 :e fun foo0(x) = if x is foo() then 0 //│ ╔══[ERROR] Illegal pattern `foo` -//│ ║ l.83: fun foo0(x) = if x is foo() then 0 +//│ ║ l.87: fun foo0(x) = if x is foo() then 0 //│ ╙── ^^^ //│ fun foo0: anything -> error //│ Code generation encountered an error: @@ -91,7 +95,7 @@ fun foo0(x) = if x is foo() then 0 :e fun foo(x) = if x is foo() then 0 //│ ╔══[ERROR] Illegal pattern `foo` -//│ ║ l.92: fun foo(x) = if x is foo() then 0 +//│ ║ l.96: fun foo(x) = if x is foo() then 0 //│ ╙── ^^^ //│ fun foo: anything -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 3d083b3d25..18b0fbe41b 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -2,7 +2,9 @@ class A -//│ class A +//│ class A { +//│ constructor() +//│ } class B(m: Int) extends A //│ class B(m: Int) extends A @@ -21,12 +23,14 @@ class A { fun a2 = 2 } //│ class A { +//│ constructor() //│ fun a1: Int //│ fun a2: 2 //│ } class B extends A //│ class B extends A { +//│ constructor() //│ fun a1: Int //│ fun a2: 2 //│ } @@ -50,3 +54,128 @@ D().test //│ = 0 +class E(val m: Int) extends A { + constructor(a: Int, b: Int) { + m = a + b + log of concat("Here's m: ")(toString of m) + } +} +//│ class E(m: Int) extends A { +//│ constructor(a: Int, b: Int) +//│ fun a1: Int +//│ fun a2: 2 +//│ } + +// * FIXME codegen +E(1).m +//│ Int +//│ res +//│ = NaN +//│ // Output +//│ Here's m: NaN + +(new E(1, 2)).m +//│ Int +//│ res +//│ = 3 +//│ // Output +//│ Here's m: 3 + +if new E(1, 2) is E(x) then x +//│ Int +//│ res +//│ = 3 +//│ // Output +//│ Here's m: 3 + +:e +module F extends E +//│ ╔══[ERROR] class E expects 2 parameter(s); got 0 +//│ ║ l.92: module F extends E +//│ ╙── ^ +//│ module F extends A, E { +//│ fun a1: Int +//│ fun a2: 2 +//│ } + +:e +module F extends E(123) +//│ ╔══[ERROR] class E expects 2 parameter(s); got 1 +//│ ║ l.102: module F extends E(123) +//│ ╙── ^^^^^ +//│ module F extends A, E { +//│ fun a1: Int +//│ fun a2: 2 +//│ } + +module F extends E(123, 456) +//│ module F extends A, E { +//│ fun a1: Int +//│ fun a2: 2 +//│ } + +:e // FIXME +// * Note: strangely, we see here the ctor output from the previous definitions of the F module 🤔 +F.m +//│ ╔══[ERROR] Type `F` does not contain member `m` +//│ ║ l.119: F.m +//│ ╙── ^^ +//│ error +//│ res +//│ = 579 +//│ // Output +//│ Here's m: NaN +//│ Here's m: NaN +//│ Here's m: 579 + + +class G(x: Int) extends E(x, x + 1) +//│ class G(x: Int) extends A, E { +//│ fun a1: Int +//│ fun a2: 2 +//│ } + +:e // FIXME +G(123).m +//│ ╔══[ERROR] Type `G` does not contain member `m` +//│ ║ l.139: G(123).m +//│ ╙── ^^ +//│ error +//│ res +//│ = 247 +//│ // Output +//│ Here's m: 247 + + +:e // TODO support +class H extends E { + constructor(a: Int, b: Int) { + super(a, b) + } +} +//│ ╔══[ERROR] class E expects 2 parameter(s); got 0 +//│ ║ l.151: class H extends E { +//│ ╙── ^ +//│ ╔══[ERROR] Illegal use of `super` +//│ ║ l.153: super(a, b) +//│ ╙── ^^^^^ +//│ ╔══[ERROR] identifier not found: super +//│ ║ l.153: super(a, b) +//│ ╙── ^^^^^ +//│ class H extends A, E { +//│ constructor(a: Int, b: Int) +//│ fun a1: Int +//│ fun a2: 2 +//│ } + +:re +new H(111, 222) +//│ H +//│ res +//│ Runtime error: +//│ ReferenceError: Super constructor may only be called once +//│ // Output +//│ Here's m: NaN +//│ Here's m: 333 + + diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index f629d09726..9291f8d046 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -64,6 +64,7 @@ class C { fun const(x) = id } //│ class C { +//│ constructor() //│ fun const: anything -> (forall 'a. 'a -> 'a) //│ fun id: forall 'a. 'a -> 'a //│ } @@ -77,10 +78,10 @@ class Base0(val n) { fun oops = this.my } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.73: class Base0(val n) { +//│ ║ l.74: class Base0(val n) { //│ ╙── ^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.77: fun oops = this.my +//│ ║ l.78: fun oops = this.my //│ ╙── ^^^ //│ class Base0(n: error) { //│ fun me: Base0 & {n: error} @@ -174,7 +175,7 @@ b.me :e b.getBaseTypo //│ ╔══[ERROR] Type `Base1` does not contain member `getBaseTypo` -//│ ║ l.175: b.getBaseTypo +//│ ║ l.176: b.getBaseTypo //│ ╙── ^^^^^^^^^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index d76d5f17f5..61d03e0cf8 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -166,7 +166,7 @@ mixin Foo { :e module Base1(base: Int, misc: string) extends Foo -//│ ╔══[ERROR] module parameters are not supported +//│ ╔══[ERROR] Module parameters are not supported //│ ║ l.168: module Base1(base: Int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: @@ -197,8 +197,18 @@ module Base1(base: Int, misc: string) extends Foo //│ fun test: forall 'a. (Int & 'a) -> [Int, 'a, nothing] //│ } +:e Base1.test -//│ forall 'a. (Int & 'a) -> [Int, 'a, nothing] +//│ ╔══[ERROR] Parameterized modules are not supported +//│ ║ l.201: Base1.test +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.201: Base1.test +//│ ║ ^^^^^^^^^^ +//│ ╟── reference of type `(base: Int, misc: string) -> Base1` does not have field 'test' +//│ ║ l.201: Base1.test +//│ ╙── ^^^^^ +//│ error //│ res //│ = [Function: test] @@ -274,13 +284,13 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.275: WrapBase1.wrapA("ok") +//│ ║ l.285: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `Int` -//│ ║ l.275: WrapBase1.wrapA("ok") +//│ ║ l.285: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.219: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.229: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ error | [Int] //│ res diff --git a/shared/src/test/diff/nu/CtorStatements.mls b/shared/src/test/diff/nu/CtorStatements.mls deleted file mode 100644 index e131cca827..0000000000 --- a/shared/src/test/diff/nu/CtorStatements.mls +++ /dev/null @@ -1,24 +0,0 @@ -:NewDefs - - -log("Hello!") -//│ undefined -//│ res -//│ = undefined -//│ // Output -//│ Hello! - - -module Test0 { - log("Hello!") -} -//│ module Test0 - -Test0 -//│ Test0 -//│ res -//│ = Test0 { class: [class Test0] } -//│ // Output -//│ Hello! - - diff --git a/shared/src/test/diff/nu/Dates.mls b/shared/src/test/diff/nu/Dates.mls index 6509a203ef..dd5a5fc15c 100644 --- a/shared/src/test/diff/nu/Dates.mls +++ b/shared/src/test/diff/nu/Dates.mls @@ -7,24 +7,19 @@ declare class Date { fun toLocaleString(locales: Str | Array[Str], options: anything): Str } //│ declare class Date { +//│ constructor(date: Num) //│ fun toLocaleString: (locales: Str | Array[Str], options: anything) -> Str //│ fun toString: () -> Str //│ } -:e // TODO ctor typing let date1 = new Date(12345678) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.15: let date1 = new Date(12345678) -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── argument of type `[12345678]` does not match type `[]` -//│ ║ l.15: let date1 = new Date(12345678) -//│ ╙── ^^^^^^^^^^ -//│ let date1: Date | error +//│ let date1: Date //│ date1 //│ = 1970-01-01T03:25:45.678Z date1.toLocaleString("en-US", { timeZone: "America/New_York" }) -//│ Str | error +//│ Str //│ res //│ = '12/31/1969, 10:25:45 PM' + diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index 8f42b5d871..59090ce6da 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -71,11 +71,12 @@ declare class Sanitizer { fun sanitizeFor(element: Str, input: Str): Str } //│ declare class Sanitizer { +//│ constructor() //│ fun sanitizeFor: (element: Str, input: Str) -> Str //│ } :re -let s = Sanitizer() +let s = new Sanitizer //│ let s: Sanitizer //│ s //│ Runtime error: @@ -96,6 +97,7 @@ declare module Buffer { } //│ declare module Buffer { //│ class Buffer2 { +//│ constructor() //│ let length: Int //│ } //│ fun bar: Int @@ -118,10 +120,10 @@ b.length :pe declare 42 //│ ╔══[PARSE ERROR] Unexpected literal token after modifier -//│ ║ l.119: declare 42 +//│ ║ l.121: declare 42 //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected literal token after modifier -//│ ║ l.119: declare 42 +//│ ║ l.121: declare 42 //│ ╙── ^^ //│ 42 //│ res diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index bfbb4def02..340d8431f0 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -155,6 +155,7 @@ class Final extends Derived1[(Int, Int)], Derived2 { fun bar([x, y]) = [error, error] } //│ class Final extends Base, Derived1, Derived2 { +//│ constructor() //│ fun bar: ([anything, anything]) -> [nothing, nothing] //│ fun foo: [123, 456] //│ } @@ -164,6 +165,7 @@ class Final extends Derived1[(Int, Int)], Derived2 { fun bar([x, y]) = [y, x] } //│ class Final extends Base, Derived1, Derived2 { +//│ constructor() //│ fun bar: forall 'a 'b. (['a, 'b]) -> ['b, 'a] //│ fun foo: [123, 456] //│ } diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index a7d17efa41..29e5d9d1c1 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -9,6 +9,7 @@ class List { let Nil: List let Cons: (head: 'a, tail: List<'a>) => List<'a> //│ class List[A] { +//│ constructor() //│ fun match: forall 'res. (ifNil: () -> 'res, ifCons: ('res, List[A]) -> 'res) -> 'res //│ } //│ let Nil: List[nothing] @@ -20,7 +21,7 @@ let x: List // FIXME x: List //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.21: x: List +//│ ║ l.22: x: List //│ ║ ^ //│ ╙── expression of type `anything` is not an instance of type `Int` //│ List[anything] diff --git a/shared/src/test/diff/nu/EqlClasses.mls b/shared/src/test/diff/nu/EqlClasses.mls index 82be4b683d..740074aa2d 100644 --- a/shared/src/test/diff/nu/EqlClasses.mls +++ b/shared/src/test/diff/nu/EqlClasses.mls @@ -5,8 +5,12 @@ module Mod //│ module Mod +:e Mod === Mod -//│ Bool +//│ ╔══[ERROR] Module 'Mod' does not support equality comparison because it does not have a parameter list +//│ ║ l.9: Mod === Mod +//│ ╙── ^^^^^^^^^^^ +//│ error | false | true //│ res //│ = true @@ -63,10 +67,10 @@ p === { fst: 1, snd: 2 } :e { fst: 1, snd: 2 } === p //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.64: { fst: 1, snd: 2 } === p +//│ ║ l.68: { fst: 1, snd: 2 } === p //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── record literal of type `{fst: 1, snd: 2}` is not an instance of type `Eql` -//│ ║ l.64: { fst: 1, snd: 2 } === p +//│ ║ l.68: { fst: 1, snd: 2 } === p //│ ╙── ^^^^^^^^^ //│ error | false | true //│ res @@ -86,10 +90,10 @@ r : {x: Int} :e x => { a: 0 } === x //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.87: x => { a: 0 } === x +//│ ║ l.91: x => { a: 0 } === x //│ ║ ^^^^^^^^^^^^^^ //│ ╟── record literal of type `{a: 0}` is not an instance of type `Eql` -//│ ║ l.87: x => { a: 0 } === x +//│ ║ l.91: x => { a: 0 } === x //│ ╙── ^ //│ anything -> (error | false | true) //│ res @@ -111,10 +115,10 @@ let q = Pair(1, "oops") :e q === q //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.112: q === q +//│ ║ l.116: q === q //│ ║ ^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `Str` -//│ ║ l.106: let q = Pair(1, "oops") +//│ ║ l.110: let q = Pair(1, "oops") //│ ╙── ^ //│ error | false | true //│ res diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 15a5d89938..3fff3bb2ce 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -27,7 +27,9 @@ class Exp[type A] //│ ╔══[PARSE ERROR] Unexpected 'type' keyword here //│ ║ l.26: class Exp[type A] //│ ╙── ^^^^ -//│ class Exp +//│ class Exp { +//│ constructor() +//│ } l1: Expr[Int] //│ Expr[Int] @@ -37,13 +39,13 @@ l1: Expr[Int] :e l1: Expr[Bool] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.38: l1: Expr[Bool] +//│ ║ l.40: l1: Expr[Bool] //│ ║ ^^ //│ ╟── type `Int` is not an instance of `Bool` //│ ║ l.4: class LitInt(n: Int) extends Expr[Int] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.38: l1: Expr[Bool] +//│ ║ l.40: l1: Expr[Bool] //│ ╙── ^^^^ //│ Expr[Bool] //│ res @@ -56,34 +58,34 @@ fun eval[A](e: Expr[A]): A = e is LitBool(b) then b e is Add(x, y) then eval(x) + eval(y) //│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.55: e is LitInt(n) then n +//│ ║ l.57: e is LitInt(n) then n //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.56: e is LitBool(b) then b +//│ ║ l.58: e is LitBool(b) then b //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) +//│ ║ l.59: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `#Expr & (Add & {Expr#A = ?A} | Cond[?] & {Expr#A = ?A} | Fst[?, ?] & {Expr#A = ?A} | LitBool & {Expr#A = ?A} | LitInt & {Expr#A = ?A} | Pair[?, ?] & {Expr#A = ?A} | Snd[?, ?] & {Expr#A = ?A})` does not match type `Add | LitBool | LitInt` -//│ ║ l.53: fun eval[A](e: Expr[A]): A = +//│ ║ l.55: fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^ //│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt` -//│ ║ l.55: e is LitInt(n) then n +//│ ║ l.57: e is LitInt(n) then n //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.53: fun eval[A](e: Expr[A]): A = +//│ ║ l.55: fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.54: if +//│ ║ l.56: if //│ ║ ^^^^^^^ -//│ ║ l.55: e is LitInt(n) then n +//│ ║ l.57: e is LitInt(n) then n //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.56: e is LitBool(b) then b +//│ ║ l.58: e is LitBool(b) then b //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.57: e is Add(x, y) then eval(x) + eval(y) +//│ ║ l.59: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ║ l.5: class LitBool(b: Bool) extends Expr[Bool] //│ ║ ^^^^ //│ ╟── but it flows into reference with expected type `Int` -//│ ║ l.56: e is LitBool(b) then b +//│ ║ l.58: e is LitBool(b) then b //│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.6: class Add(x: Expr[Int], y: Expr[Int]) extends Expr[Int] diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 8b3242518a..2daf692231 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -9,6 +9,7 @@ class Room[A](name: Str) { class BigRoom extends Room[Bool]("big") //│ class BigRoom extends Room { +//│ constructor() //│ fun foo: (x: 'A) -> 'A //│ } //│ where @@ -19,6 +20,7 @@ class InferredRoom extends Room("infer") { fun foo(x) = x && true } //│ class InferredRoom extends Room { +//│ constructor() //│ fun foo: Bool -> Bool //│ } @@ -32,9 +34,10 @@ class InferredRoom extends Room("infer") { :e class TooManyRoom extends Room[Int, Str]("too many") //│ ╔══[ERROR] class Room expects 1 type parameter(s); got 2 -//│ ║ l.33: class TooManyRoom extends Room[Int, Str]("too many") +//│ ║ l.35: class TooManyRoom extends Room[Int, Str]("too many") //│ ╙── ^^^^^^^^^^^^^ //│ class TooManyRoom extends Room { +//│ constructor() //│ fun foo: (x: 'A) -> 'A //│ } //│ where @@ -45,53 +48,48 @@ class WrongRoom extends Room[Bool]("wrong") { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.45: fun foo(x) = x + 1 +//│ ║ l.48: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.44: class WrongRoom extends Room[Bool]("wrong") { +//│ ║ l.47: class WrongRoom extends Room[Bool]("wrong") { //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.45: fun foo(x) = x + 1 +//│ ║ l.48: fun foo(x) = x + 1 //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.45: fun foo(x) = x + 1 +//│ ║ l.48: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── operator application of type `Int` is not an instance of type `Bool` -//│ ║ l.45: fun foo(x) = x + 1 +//│ ║ l.48: fun foo(x) = x + 1 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.44: class WrongRoom extends Room[Bool]("wrong") { +//│ ║ l.47: class WrongRoom extends Room[Bool]("wrong") { //│ ║ ^^^^ //│ ╟── from reference: //│ ║ l.4: virtual fun foo(x: A) = x //│ ╙── ^ //│ class WrongRoom extends Room { +//│ constructor() //│ fun foo: Int -> Int //│ } class C0[A] { val a: A } //│ class C0[A] { +//│ constructor() //│ let a: A //│ } class C1[A] extends C0[A] { val a = a } //│ class C1[A] extends C0 { +//│ constructor() //│ let a: nothing //│ } -:pe -:e new C1 : C1[Int] -//│ ╔══[PARSE ERROR] Unexpected type ascription after `new` keyword -//│ ║ l.85: new C1 : C1[Int] -//│ ╙── ^^ -//│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.85: new C1 : C1[Int] -//│ ╙── ^^^ -//│ error +//│ C1[Int] //│ res -//│ = {} +//│ = C1 {} ((new C1) : C1[Int]) : C0['X] //│ C0[Int] @@ -117,12 +115,14 @@ class A1 extends M1 { fun f1(x: Int) = x } //│ class A1 { +//│ constructor() //│ fun f1: (x: Int) -> Int //│ fun f2: (x: 'A) -> ['A, 'A] //│ } class A2[S, T] extends M1[(S, T)] //│ class A2[S, T] { +//│ constructor() //│ fun f1: (x: [S, T]) -> [S, T] //│ fun f2: (x: [S, T]) -> [[S, T], [S, T]] //│ } diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index a6a57f35a1..8b29e054e4 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -2,7 +2,9 @@ class C -//│ class C[A] +//│ class C[A] { +//│ constructor() +//│ } fun f(x) = if x is C then x //│ fun f: forall 'A. C['A] -> C['A] @@ -189,7 +191,7 @@ class Test(n) { fun bar = n } //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.187: class Test(n) { +//│ ║ l.189: class Test(n) { //│ ╙── ^ //│ class Test(n: error) { //│ fun bar: error @@ -213,13 +215,13 @@ class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.213: fun foo = n + 1 +//│ ║ l.215: fun foo = n + 1 //│ ║ ^^^^^ //│ ╟── reference of type `A` is not an instance of type `Int` -//│ ║ l.213: fun foo = n + 1 +//│ ║ l.215: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.212: class Test(n: A) { +//│ ║ l.214: class Test(n: A) { //│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: Int | error @@ -296,13 +298,13 @@ class TestBad() { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.296: fun foo2(x: A) = x + 1 +//│ ║ l.298: fun foo2(x: A) = x + 1 //│ ║ ^^^^^ //│ ╟── reference of type `A` is not an instance of type `Int` -//│ ║ l.296: fun foo2(x: A) = x + 1 +//│ ║ l.298: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.294: class TestBad() { +//│ ║ l.296: class TestBad() { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A) -> A @@ -393,7 +395,7 @@ not(w.x.n) :e not(w.x.a) //│ ╔══[ERROR] Type `C['a]` does not contain member `a` -//│ ║ l.394: not(w.x.a) +//│ ║ l.396: not(w.x.a) //│ ╙── ^^ //│ Bool //│ res diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index 04115b3d8c..ea88aae72d 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -14,7 +14,7 @@ foo1[Int](42) //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.13: foo1[Int](42) //│ ╙── ^^^^^^^^^ -//│ error +//│ 42 //│ res //│ = 42 @@ -32,7 +32,7 @@ foo2(42) //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.31: foo2(42) //│ ╙── ^^^^^^^^^ -//│ error +//│ 42 //│ res //│ = 42 @@ -50,7 +50,7 @@ foo3[Int](42) //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.49: foo3[Int](42) //│ ╙── ^^^^^^^^^ -//│ error +//│ 42 //│ res //│ = 42 diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index cc5348ea0f..f4b64a0748 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -100,6 +100,7 @@ class C[A] extends Test[Array[A]] { fun baz2 = this.bar(this.foo) } //│ class C[A] { +//│ constructor() //│ fun bar: (Array[A] -> Array[A]) -> Array[A] -> Array[A] //│ fun baz1: Array[A] //│ fun baz2: Array[A] -> Array[A] @@ -143,10 +144,10 @@ module D extends C(0) { this.foo(false) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.143: this.foo(false) +//│ ║ l.144: this.foo(false) //│ ╙── ^^^^ //│ ╔══[ERROR] Cannot access `this` during object initialization -//│ ║ l.143: this.foo(false) +//│ ║ l.144: this.foo(false) //│ ╙── ^^^^ //│ module D extends C { //│ fun bar: forall 'A. [Int | 'A, Int | 'A] @@ -159,18 +160,19 @@ class C extends Test { // it also fails with Test[Int]... fun arg = 123 } //│ ╔══[ERROR] Type `#C & {bar: [?A, ?A], baz: ?a, foo: ?A -> ?A}` does not contain member `arg` -//│ ║ l.116: fun baz = foo(this.arg) +//│ ║ l.117: fun baz = foo(this.arg) //│ ╙── ^^^^ //│ ╔══[ERROR] Type `#C & {bar: [?A, ?A], baz: ?a, foo: ?A -> ?A}` does not contain member `arg` -//│ ║ l.115: fun bar = (this.arg, this.arg) +//│ ║ l.116: fun bar = (this.arg, this.arg) //│ ╙── ^^^^ //│ ╔══[ERROR] Type `#C & {bar: [?A, ?A], baz: ?a, foo: ?A -> ?A}` does not contain member `arg` -//│ ║ l.115: fun bar = (this.arg, this.arg) +//│ ║ l.116: fun bar = (this.arg, this.arg) //│ ╙── ^^^^ //│ ╔══[ERROR] Illegal position for this definition statement. -//│ ║ l.159: fun arg = 123 +//│ ║ l.160: fun arg = 123 //│ ╙── ^^^^^^^^^ //│ class C { +//│ constructor() //│ fun bar: [error | 'A, error | 'A] //│ fun baz: error //│ fun foo: 'A -> (error | 'A) @@ -181,6 +183,7 @@ class C extends Test { fun arg = 123 } //│ class C { +//│ constructor() //│ fun arg: Int //│ fun bar: [Int | 'A, Int | 'A] //│ fun baz: Int diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 6ec4a734f2..3e6b1cf30a 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -99,7 +99,7 @@ Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.98: Test .foo //│ ╙── ^^^^^^^^^ -//│ error +//│ ??A -> ??A0 //│ res //│ = undefined @@ -108,7 +108,7 @@ Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.107: (Test).foo //│ ╙── ^^^^^^^^^ -//│ error +//│ ??A -> ??A0 //│ res //│ = undefined diff --git a/shared/src/test/diff/nu/Huawei1.mls b/shared/src/test/diff/nu/Huawei1.mls index a74d30fdb8..bf50ba68db 100644 --- a/shared/src/test/diff/nu/Huawei1.mls +++ b/shared/src/test/diff/nu/Huawei1.mls @@ -14,7 +14,9 @@ let c = C(123) //│ = C {} class B -//│ class B +//│ class B { +//│ constructor() +//│ } fun bar(c) = if c is C(y) then y @@ -40,13 +42,13 @@ bar(c) :e bar(C(true)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.41: bar(C(true)) +//│ ║ l.43: bar(C(true)) //│ ║ ^^^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `Int` -//│ ║ l.41: bar(C(true)) +//│ ║ l.43: bar(C(true)) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.30: C(y) then y + 1 +//│ ║ l.32: C(y) then y + 1 //│ ║ ^ //│ ╟── from field selection: //│ ║ l.4: class C[A](x: A) { diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 5ee370436c..65102eaedd 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -116,6 +116,7 @@ class C { //│ ║ l.109: fun f = (this.id1(true), this.id1(0)) //│ ╙── ^^^^ //│ class C { +//│ constructor() //│ fun f: [error, error] //│ fun id1: forall 'a. 'a -> 'a //│ fun id2: forall 'b. 'b -> 'b @@ -127,10 +128,10 @@ module M extends C { this.id2(true) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.127: this.id2(true) +//│ ║ l.128: this.id2(true) //│ ╙── ^^^^ //│ ╔══[ERROR] Cannot access `this` during object initialization -//│ ║ l.127: this.id2(true) +//│ ║ l.128: this.id2(true) //│ ╙── ^^^^ //│ module M extends C { //│ fun f: [error, error] @@ -143,10 +144,10 @@ module M extends C { fun g = (this.id2(true), this.id2(0)) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.143: fun g = (this.id2(true), this.id2(0)) +//│ ║ l.144: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.143: fun g = (this.id2(true), this.id2(0)) +//│ ║ l.144: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ //│ module M extends C { //│ fun f: [error, error] @@ -181,11 +182,11 @@ module M extends C { fun id1 = succ } //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.181: fun id1 = succ +//│ ║ l.182: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╙── variable of type `?a` is not an instance of type `Int` //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.181: fun id1 = succ +//│ ║ l.182: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from reference: @@ -211,6 +212,9 @@ M.id1 // FIXME? parsing/semantics of this, currently treated as a named tuple... (M: C) +//│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword +//│ ║ l.214: (M: C) +//│ ╙── ^ //│ [M: () -> C] //│ res //│ = [ [class C] ] @@ -229,19 +233,19 @@ module M { fun oops(x) = m := x } //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword in expression position -//│ ║ l.228: mut val m = None +//│ ║ l.232: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.228: mut val m = None +//│ ║ l.232: mut val m = None //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: := -//│ ║ l.229: fun oops(x) = m := x +//│ ║ l.233: fun oops(x) = m := x //│ ╙── ^^ //│ ╔══[ERROR] identifier not found: m -//│ ║ l.229: fun oops(x) = m := x +//│ ║ l.233: fun oops(x) = m := x //│ ╙── ^ //│ ╔══[ERROR] Unexpected equation in this position -//│ ║ l.228: mut val m = None +//│ ║ l.232: mut val m = None //│ ╙── ^^^^^^^^ //│ module M { //│ fun oops: anything -> error diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index cb9302a892..05041870fa 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -209,30 +209,32 @@ trait Foo[A] { fun foo[A](x: A): A } class B extends Foo { fun foo(x) = x } //│ class B extends Foo { +//│ constructor() //│ fun foo: forall 'a. 'a -> 'a //│ } :e class B extends Foo { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.216: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `A` is not an instance of type `Int` //│ ║ l.205: trait Foo[A] { fun foo[A](x: A): A } //│ ║ ^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.216: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.216: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── operator application of type `Int` does not match type `A` -//│ ║ l.216: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from method type parameter: //│ ║ l.205: trait Foo[A] { fun foo[A](x: A): A } //│ ╙── ^ //│ class B extends Foo { +//│ constructor() //│ fun foo: Int -> Int //│ } diff --git a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls index 1dcc932356..739ac0f1b3 100644 --- a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls +++ b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls @@ -14,6 +14,7 @@ module Foo { } //│ module Foo { //│ class C extends T1, T2 { +//│ constructor() //│ fun x: 1 //│ } //│ trait T2 { diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index 70b5f51b40..e464e83f5b 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -72,9 +72,11 @@ class ErrC3(toString: Str -> Str) extends Showable //│ ║ l.5: fun toString: Str //│ ╙── ^^^^^^^^^^^^^ //│ class ErrC1 extends Showable { +//│ constructor() //│ fun toString: Str //│ } //│ class ErrC2 extends Showable { +//│ constructor() //│ fun toString: 114 //│ } //│ class ErrC3(toString: Str -> Str) extends Showable @@ -123,41 +125,41 @@ class Errcity(size: Int) extends SizedStadt { fun bar = "hahaha" } //│ ╔══[ERROR] Type mismatch in definition of method bar: -//│ ║ l.123: fun bar = "hahaha" +//│ ║ l.125: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── string literal of type `"hahaha"` is not a function -//│ ║ l.123: fun bar = "hahaha" +//│ ║ l.125: fun bar = "hahaha" //│ ║ ^^^^^^^^ //│ ╟── but it flows into definition of method bar with expected type `Int -> Int` -//│ ║ l.123: fun bar = "hahaha" +//│ ║ l.125: fun bar = "hahaha" //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.101: fun bar: Int -> Int +//│ ║ l.103: fun bar: Int -> Int //│ ║ ^^^^^^^^^^ //│ ╟── from signature of member `bar`: -//│ ║ l.101: fun bar: Int -> Int +//│ ║ l.103: fun bar: Int -> Int //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.122: class Errcity(size: Int) extends SizedStadt { +//│ ║ l.124: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^ //│ ╟── type `Int` does not match type `1 | 2 | 3` //│ ╟── Note: constraint arises from union type: -//│ ║ l.100: let size: 1 | 2 | 3 +//│ ║ l.102: let size: 1 | 2 | 3 //│ ║ ^^^^^^^^^ //│ ╟── from signature of member `size`: -//│ ║ l.100: let size: 1 | 2 | 3 +//│ ║ l.102: let size: 1 | 2 | 3 //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `name` is declared in parent but not implemented in `Errcity` -//│ ║ l.122: class Errcity(size: Int) extends SizedStadt { +//│ ║ l.124: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.83: let name: Str +//│ ║ l.85: let name: Str //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Errcity` -//│ ║ l.122: class Errcity(size: Int) extends SizedStadt { +//│ ║ l.124: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.91: fun foo: Bool -> Int +//│ ║ l.93: fun foo: Bool -> Int //│ ╙── ^^^^^^^^^^^^^^^^ //│ class Errcity(size: Int) extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: "hahaha" @@ -206,21 +208,22 @@ class Dirtberg extends More, SizedStadt, Fooo { fun size = 4 // this should not check } //│ ╔══[ERROR] Type mismatch in definition of method size: -//│ ║ l.206: fun size = 4 // this should not check +//│ ║ l.208: fun size = 4 // this should not check //│ ║ ^^^^^^^^ //│ ╟── integer literal of type `4` does not match type `1 | 2 | 3` -//│ ║ l.206: fun size = 4 // this should not check +//│ ║ l.208: fun size = 4 // this should not check //│ ║ ^ //│ ╟── but it flows into definition of method size with expected type `1 | 2 | 3` -//│ ║ l.206: fun size = 4 // this should not check +//│ ║ l.208: fun size = 4 // this should not check //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.100: let size: 1 | 2 | 3 +//│ ║ l.102: let size: 1 | 2 | 3 //│ ║ ^^^^^^^^^ //│ ╟── from signature of member `size`: -//│ ║ l.100: let size: 1 | 2 | 3 +//│ ║ l.102: let size: 1 | 2 | 3 //│ ╙── ^^^^^^^^^^^^^^^ //│ class Dirtberg extends RefinedStadt, SizedStadt, Stadt { +//│ constructor() //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: anything -> 0 //│ fun more: Num -> Bool @@ -238,41 +241,45 @@ class Iceburg(name: Str) extends RefinedStadt, More, Fooo class A { virtual fun x: Int = 1 } //│ class A { +//│ constructor() //│ fun x: Int //│ } :e class B extends A { fun x = "A" } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.245: class B extends A { fun x = "A" } +//│ ║ l.249: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── string literal of type `"A"` is not an instance of type `Int` -//│ ║ l.245: class B extends A { fun x = "A" } +//│ ║ l.249: class B extends A { fun x = "A" } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.245: class B extends A { fun x = "A" } +//│ ║ l.249: class B extends A { fun x = "A" } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.239: class A { virtual fun x: Int = 1 } +//│ ║ l.242: class A { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.239: class A { virtual fun x: Int = 1 } +//│ ║ l.242: class A { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class B extends A { +//│ constructor() //│ fun x: "A" //│ } :e class C1[A] { virtual fun a: A = this.a } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.266: class C1[A] { virtual fun a: A = this.a } +//│ ║ l.271: class C1[A] { virtual fun a: A = this.a } //│ ╙── ^^ //│ class C1[A] { +//│ constructor() //│ fun a: A //│ } class C2 extends C1[Int] { fun a = 1 } //│ class C2 extends C1 { +//│ constructor() //│ fun a: 1 //│ } @@ -290,27 +297,29 @@ trait MyTrait[A] { fun a: A } // :ds class C extends MyTrait[Int] { fun a = 1 } //│ class C extends MyTrait { +//│ constructor() //│ fun a: 1 //│ } :e class C extends MyTrait[Int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: -//│ ║ l.297: class C extends MyTrait[Int] { fun a = false } +//│ ║ l.305: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.297: class C extends MyTrait[Int] { fun a = false } +//│ ║ l.305: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `Int` -//│ ║ l.297: class C extends MyTrait[Int] { fun a = false } +//│ ║ l.305: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.297: class C extends MyTrait[Int] { fun a = false } +//│ ║ l.305: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^ //│ ╟── from signature of member `a`: -//│ ║ l.283: trait MyTrait[A] { fun a: A } +//│ ║ l.290: trait MyTrait[A] { fun a: A } //│ ╙── ^^^^ //│ class C extends MyTrait { +//│ constructor() //│ fun a: false //│ } @@ -349,21 +358,22 @@ class C3 extends T4{ fun bar = false } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.348: fun foo = 3 +//│ ║ l.357: fun foo = 3 //│ ║ ^^^^^^^ //│ ╟── integer literal of type `3` does not match type `2` -//│ ║ l.348: fun foo = 3 +//│ ║ l.357: fun foo = 3 //│ ║ ^ //│ ╟── but it flows into definition of method foo with expected type `2` -//│ ║ l.348: fun foo = 3 +//│ ║ l.357: fun foo = 3 //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from literal type: -//│ ║ l.336: fun foo: 2 +//│ ║ l.345: fun foo: 2 //│ ║ ^ //│ ╟── from signature of member `foo`: -//│ ║ l.336: fun foo: 2 +//│ ║ l.345: fun foo: 2 //│ ╙── ^^^^^^ //│ class C3 extends T1, T2, T4 { +//│ constructor() //│ fun bar: false //│ fun foo: 3 //│ } @@ -371,24 +381,24 @@ class C3 extends T4{ :e class C2(foo: Int, bar: Str) extends T4 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.372: class C2(foo: Int, bar: Str) extends T4 +//│ ║ l.382: class C2(foo: Int, bar: Str) extends T4 //│ ║ ^^^ //│ ╟── type `Int` does not match type `2` //│ ╟── Note: constraint arises from literal type: -//│ ║ l.336: fun foo: 2 +//│ ║ l.345: fun foo: 2 //│ ║ ^ //│ ╟── from signature of member `foo`: -//│ ║ l.336: fun foo: 2 +//│ ║ l.345: fun foo: 2 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.372: class C2(foo: Int, bar: Str) extends T4 +//│ ║ l.382: class C2(foo: Int, bar: Str) extends T4 //│ ║ ^^^ //│ ╟── type `Str` does not match type `Bool | Int` //│ ╟── Note: constraint arises from union type: -//│ ║ l.324: let bar : Int | Bool +//│ ║ l.333: let bar : Int | Bool //│ ║ ^^^^^^^^^^ //│ ╟── from signature of member `bar`: -//│ ║ l.324: let bar : Int | Bool +//│ ║ l.333: let bar : Int | Bool //│ ╙── ^^^^^^^^^^^^^^^^ //│ class C2(foo: Int, bar: Str) extends T1, T2, T4 @@ -397,19 +407,19 @@ trait T5 extends T4 { let foo: 4 } //│ ╔══[ERROR] Type mismatch in signature of member `foo`: -//│ ║ l.397: let foo: 4 +//│ ║ l.407: let foo: 4 //│ ║ ^^^^^^ //│ ╟── type `4` does not match type `2` -//│ ║ l.397: let foo: 4 +//│ ║ l.407: let foo: 4 //│ ║ ^ //│ ╟── but it flows into signature of member `foo` with expected type `2` -//│ ║ l.397: let foo: 4 +//│ ║ l.407: let foo: 4 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from literal type: -//│ ║ l.336: fun foo: 2 +//│ ║ l.345: fun foo: 2 //│ ║ ^ //│ ╟── from signature of member `foo`: -//│ ║ l.336: fun foo: 2 +//│ ║ l.345: fun foo: 2 //│ ╙── ^^^^^^ //│ trait T5 extends T1, T2, T4 { //│ fun bar: Bool @@ -421,34 +431,34 @@ trait T3 extends T1, T2 { let foo: true } //│ ╔══[ERROR] Type mismatch in signature of member `foo`: -//│ ║ l.421: let foo: true +//│ ║ l.431: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── type `true` does not match type `1 | 2 | 3` -//│ ║ l.421: let foo: true +//│ ║ l.431: let foo: true //│ ║ ^^^^ //│ ╟── but it flows into signature of member `foo` with expected type `1 | 2 | 3` -//│ ║ l.421: let foo: true +//│ ║ l.431: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.319: let foo : 1 | 2 | 3 +//│ ║ l.328: let foo : 1 | 2 | 3 //│ ║ ^^^^^^^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.319: let foo : 1 | 2 | 3 +//│ ║ l.328: let foo : 1 | 2 | 3 //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in signature of member `foo`: -//│ ║ l.421: let foo: true +//│ ║ l.431: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── type `true` does not match type `2 | 3 | 4` -//│ ║ l.421: let foo: true +//│ ║ l.431: let foo: true //│ ║ ^^^^ //│ ╟── but it flows into signature of member `foo` with expected type `2 | 3 | 4` -//│ ║ l.421: let foo: true +//│ ║ l.431: let foo: true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.323: let foo : 2 | 3 | 4 +//│ ║ l.332: let foo : 2 | 3 | 4 //│ ║ ^^^^^^^^^ //│ ╟── from signature of member `foo`: -//│ ║ l.323: let foo : 2 | 3 | 4 +//│ ║ l.332: let foo : 2 | 3 | 4 //│ ╙── ^^^^^^^^^^^^^^^ //│ trait T3 extends T1, T2 { //│ fun bar: Bool diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 085cb20a9b..c28a577e85 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -337,6 +337,7 @@ class Ea1 extends A1, A2 { //│ ║ l.311: trait A1 { fun a1: 1 | 2 | 3 } //│ ╙── ^^^^^^^^^^^^^ //│ class Ea1 extends A1, A2 { +//│ constructor() //│ fun a1: 4 //│ } @@ -351,6 +352,7 @@ class CE extends Ele { fun ce(x) = x } //│ class CE extends Ele { +//│ constructor() //│ fun ce: forall 'a. 'a -> 'a //│ } @@ -359,12 +361,13 @@ class E1 extends Test { fun foo = 2 } //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `E1` -//│ ║ l.358: class E1 extends Test { +//│ ║ l.360: class E1 extends Test { //│ ║ ^^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class E1 extends Test { +//│ constructor() //│ fun bar: Bool -> Bool //│ fun foo: 2 //│ } @@ -373,10 +376,10 @@ class E1 extends Test { trait TE1 extends C trait TE2 extends M, Test //│ ╔══[ERROR] A trait can only inherit from other traits -//│ ║ l.373: trait TE1 extends C +//│ ║ l.376: trait TE1 extends C //│ ╙── ^ //│ ╔══[ERROR] A trait can only inherit from other traits -//│ ║ l.374: trait TE2 extends M, Test +//│ ║ l.377: trait TE2 extends M, Test //│ ╙── ^ //│ trait TE1 extends C, Test //│ trait TE2 extends Test { @@ -390,13 +393,13 @@ class E2 extends Test { fun bar(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.389: fun foo = true +//│ ║ l.392: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `Int` -//│ ║ l.389: fun foo = true +//│ ║ l.392: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `Int` -//│ ║ l.389: fun foo = true +//│ ║ l.392: fun foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: Int @@ -405,6 +408,7 @@ class E2 extends Test { //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ class E2 extends Test { +//│ constructor() //│ fun bar: forall 'a. 'a -> 'a //│ fun foo: true //│ } @@ -412,24 +416,25 @@ class E2 extends Test { :e class D extends Test[Int], Test[Bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.413: class D extends Test[Int], Test[Bool] +//│ ║ l.417: class D extends Test[Int], Test[Bool] //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 -//│ ║ l.413: class D extends Test[Int], Test[Bool] +//│ ║ l.417: class D extends Test[Int], Test[Bool] //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `D` -//│ ║ l.413: class D extends Test[Int], Test[Bool] +//│ ║ l.417: class D extends Test[Int], Test[Bool] //│ ║ ^ //│ ╟── Declared here: //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `D` -//│ ║ l.413: class D extends Test[Int], Test[Bool] +//│ ║ l.417: class D extends Test[Int], Test[Bool] //│ ║ ^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class D extends Test { +//│ constructor() //│ fun bar: Bool -> Bool //│ fun foo: Int //│ } @@ -497,10 +502,10 @@ if b is Foo(a) then a else 0 :e // * Note: an error is raised in this case and not above because B is invariant so it can't be widened if b is Bar(f) then f else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.498: if b is Bar(f) then f else 0 +//│ ║ l.503: if b is Bar(f) then f else 0 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.472: class Bar[B](f: B => B) extends Base +//│ ║ l.477: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ 0 | (??B & 'B) -> ('B | ??B0) //│ res @@ -511,14 +516,14 @@ if b is Foo(a) then a Bar(f) then f //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.510: if b is +//│ ║ l.515: if b is //│ ║ ^^^^ -//│ ║ l.511: Foo(a) then a +//│ ║ l.516: Foo(a) then a //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.512: Bar(f) then f +//│ ║ l.517: Bar(f) then f //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `B` leaks out of its scope -//│ ║ l.472: class Bar[B](f: B => B) extends Base +//│ ║ l.477: class Bar[B](f: B => B) extends Base //│ ╙── ^ //│ anything //│ res @@ -527,7 +532,7 @@ if b is :e let tt1 = Test //│ ╔══[ERROR] trait Test cannot be used in term position -//│ ║ l.528: let tt1 = Test +//│ ║ l.533: let tt1 = Test //│ ╙── ^^^^ //│ let tt1: error //│ tt1 @@ -537,7 +542,7 @@ let tt1 = Test :e fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot match on trait `Test` -//│ ║ l.538: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.543: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error //│ Code generation encountered an error: @@ -601,40 +606,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.599: fun fto(w: WP): EM = w +//│ ║ l.604: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.599: fun fto(w: WP): EM = w +//│ ║ l.604: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.599: fun fto(w: WP): EM = w +//│ ║ l.604: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.599: fun fto(w: WP): EM = w +//│ ║ l.604: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.600: z: WP +//│ ║ l.605: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.558: let z: ZL +//│ ║ l.563: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.600: z: WP +//│ ║ l.605: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.600: z: WP +//│ ║ l.605: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.601: g: ZL +//│ ║ l.606: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.557: let g: Geo +//│ ║ l.562: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.601: g: ZL +//│ ║ l.606: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.601: g: ZL +//│ ║ l.606: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP) -> EM //│ WP & ZL @@ -689,31 +694,32 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.688: fun foo(x) = x && false +//│ ║ l.693: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.688: fun foo(x) = x && false +//│ ║ l.693: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.688: fun foo(x) = x && false +//│ ║ l.693: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.688: fun foo(x) = x && false +//│ ║ l.693: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.651: virtual fun foo(x) = x + 1 +//│ ║ l.656: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.688: fun foo(x) = x && false +//│ ║ l.693: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.688: fun foo(x) = x && false +//│ ║ l.693: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.651: virtual fun foo(x) = x + 1 +//│ ║ l.656: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2 extends Bs, Ele { +//│ constructor() //│ fun ce: forall 'a. 'a -> 'a //│ fun foo: Bool -> Bool //│ } @@ -723,25 +729,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.722: class Eh extends Bs(1) +//│ ║ l.728: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `Bool` -//│ ║ l.722: class Eh extends Bs(1) +//│ ║ l.728: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.650: class Bs(val a: Bool) { +//│ ║ l.655: class Bs(val a: Bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.723: class Eh1 extends Bs +//│ ║ l.729: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.651: virtual fun foo(x) = x + 1 +//│ ║ l.656: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `Int` -//│ ║ l.651: virtual fun foo(x) = x + 1 +//│ ║ l.656: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `Int` -//│ ║ l.651: virtual fun foo(x) = x + 1 +//│ ║ l.656: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: Int @@ -750,18 +756,21 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Eh3` -//│ ║ l.724: class Eh3 extends Bs(false), Test +//│ ║ l.730: class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool //│ ╙── ^^^^^^^^^^^^^^^^^ //│ class Eh extends Bs { +//│ constructor() //│ fun foo: Int -> Int //│ } //│ class Eh1 extends Bs { +//│ constructor() //│ fun foo: Int -> Int //│ } //│ class Eh3 extends Bs, Test { +//│ constructor() //│ fun bar: Bool -> Bool //│ fun foo: Int -> Int //│ } @@ -812,13 +821,14 @@ class Bc3 { //│ class Bc1(foo: Int) //│ class Bc2(bar: Bool) //│ class Bc3 { +//│ constructor() //│ let baz: Int //│ } :e class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.819: class Bc12() extends Bc1(1), Bc2(true) +//│ ║ l.829: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: @@ -839,14 +849,14 @@ Bc02().foo :e class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.840: class Bc31(baz: Bool) extends Bc3 +//│ ║ l.850: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.810: let baz : Int +//│ ║ l.819: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.810: let baz : Int +//│ ║ l.819: let baz : Int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: Bool) extends Bc3 @@ -855,13 +865,14 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.855: let foo = true +//│ ║ l.865: let foo = true //│ ║ ^^^^ //│ ╟── reference of type `true` does not match type `1` //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.854: class Bc11 extends Bc1(1) { +//│ ║ l.864: class Bc11 extends Bc1(1) { //│ ╙── ^ //│ class Bc11 extends Bc1 { +//│ constructor() //│ let foo: true //│ } @@ -873,11 +884,13 @@ trait Base[A] { fun f: A -> A } class Der1 extends Base[Int] { fun f(x) = x + 1 } //│ class Der1 extends Base { +//│ constructor() //│ fun f: Int -> Int //│ } class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } //│ class Der2[A, B] extends Base { +//│ constructor() //│ fun f: forall 'a 'b. (['a, 'b]) -> ['a, 'b] //│ } @@ -886,7 +899,7 @@ trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.886: fun f = error +//│ ║ l.899: fun f = error //│ ╙── ^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -917,7 +930,7 @@ bp: Base[(Int, Bool)] :e bp: Base[(Int, Int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.918: bp: Base[(Int, Int)] +//│ ║ l.931: bp: Base[(Int, Int)] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -978,15 +991,16 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.979: class DerBad1 extends Base[Int, Int] +//│ ║ l.992: class DerBad1 extends Base[Int, Int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `DerBad1` -//│ ║ l.979: class DerBad1 extends Base[Int, Int] +//│ ║ l.992: class DerBad1 extends Base[Int, Int] //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.869: trait Base[A] { fun f: A -> A } +//│ ║ l.880: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^ //│ class DerBad1 extends Base { +//│ constructor() //│ fun f: 'A -> 'A //│ } //│ where @@ -995,30 +1009,31 @@ class DerBad1 extends Base[Int, Int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ║ ^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ║ ^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ╙── ^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ║ ^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ║ ^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.996: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } -//│ ╙── ^ +//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ╙── ^ //│ class Der2[A, B] extends Base { +//│ constructor() //│ fun f: forall 'a 'b. (['a, 'b]) -> ['b, 'a] //│ } @@ -1067,7 +1082,7 @@ trait Tb extends Ta[Int] { virtual val p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1067: virtual val p = false +//│ ║ l.1082: virtual val p = false //│ ╙── ^^^^^^^^^ //│ trait Tb extends Ta { //│ let g: 'T @@ -1081,6 +1096,7 @@ class Ctb extends Tb { let g = 2 } //│ class Ctb extends Ta, Tb { +//│ constructor() //│ let g: 2 //│ let p: false //│ } @@ -1101,14 +1117,14 @@ trait Oz { :e class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1102: class Fischl(age: Bool) extends Oz +//│ ║ l.1118: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1095: let age: Int +//│ ║ l.1111: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1095: let age: Int +//│ ║ l.1111: let age: Int //│ ╙── ^^^^^^^^ //│ class Fischl(age: Bool) extends Oz @@ -1119,6 +1135,7 @@ class Fate { virtual fun foo(x) = x + 1 } //│ class Fate { +//│ constructor() //│ fun foo: Int -> Int //│ } @@ -1127,36 +1144,38 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1127: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1127: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1127: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1127: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1119: virtual fun foo(x) = x + 1 +//│ ║ l.1135: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1127: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1127: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1119: virtual fun foo(x) = x + 1 +//│ ║ l.1135: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { +//│ constructor() //│ fun foo: Bool -> Bool //│ } class Ha { virtual val x: Int = 1 } //│ class Ha { +//│ constructor() //│ let x: Int //│ } @@ -1166,11 +1185,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1167: class Ohhh(x: Bool) extends Ha +//│ ║ l.1186: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1158: class Ha { virtual val x: Int = 1 } +//│ ║ l.1176: class Ha { virtual val x: Int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: Bool) extends Ha diff --git a/shared/src/test/diff/nu/Jonathan.mls b/shared/src/test/diff/nu/Jonathan.mls index f5f8ccd1bd..13b9163b17 100644 --- a/shared/src/test/diff/nu/Jonathan.mls +++ b/shared/src/test/diff/nu/Jonathan.mls @@ -61,8 +61,12 @@ onMousePressed(event => readLine.flatMap(println)) class Event class MouseEvent: Event module Register -//│ class Event -//│ class MouseEvent: Event +//│ class Event { +//│ constructor() +//│ } +//│ class MouseEvent: Event { +//│ constructor() +//│ } //│ module Register fun onMousePressed(listener) = @@ -82,14 +86,14 @@ onMouseClick of ev => onMouseClick(ev => pure of ()).flatMap of _ => pure of () //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.81: onMouseClick of ev => +//│ ║ l.85: onMouseClick of ev => //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.82: onMouseClick(ev => pure of ()).flatMap of _ => +//│ ║ l.86: onMouseClick(ev => pure of ()).flatMap of _ => //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.83: pure of () +//│ ║ l.87: pure of () //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `Register` does not match type `~Register` -//│ ║ l.74: fun onMouseClick(f: Event -> Effectful[(), 'e \ Register]): Effectful[(), Register] +//│ ║ l.78: fun onMouseClick(f: Event -> Effectful[(), 'e \ Register]): Effectful[(), Register] //│ ╙── ^^^^^^^^ //│ Effectful[[], Register] | error diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index e844caebc0..461d1349d1 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -18,3 +18,17 @@ let x = 1 //│ x //│ = 1 + +class E(x: Int) +//│ class E(x: Int) + +:e // TODO support (currently parsed as a function definition named E) +let E(x) = new E(1) +//│ ╔══[ERROR] Value E cannot be used in `new` expression +//│ ║ l.26: let E(x) = new E(1) +//│ ╙── ^^^^^^^^ +//│ let E: anything -> error +//│ E +//│ = [Function: E1] + + diff --git a/shared/src/test/diff/nu/MemberConfusion.mls b/shared/src/test/diff/nu/MemberConfusion.mls index 6df183ad89..b50809f2ff 100644 --- a/shared/src/test/diff/nu/MemberConfusion.mls +++ b/shared/src/test/diff/nu/MemberConfusion.mls @@ -13,13 +13,14 @@ class C(a: Int) extends T class B { virtual val a = "hi" } //│ class B { +//│ constructor() //│ let a: "hi" //│ } :e class C(a: Int) extends B //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.20: class C(a: Int) extends B +//│ ║ l.21: class C(a: Int) extends B //│ ║ ^^^ //│ ╟── type `Int` does not match type `"hi"` //│ ╟── Note: constraint arises from string literal: @@ -35,6 +36,7 @@ mixin M { let b = "hi" } class B { virtual val a = 1 : Int } //│ class B { +//│ constructor() //│ let a: Int //│ } diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index 589688c1c0..fad7868856 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -19,13 +19,15 @@ trait T3 extends T1, T2 trait S1 { class f } //│ trait S1 { -//│ class f +//│ class f { +//│ constructor() +//│ } //│ } :e trait S2 extends T1, S1 //│ ╔══[ERROR] Intersection of value member and class members currently unsupported -//│ ║ l.26: trait S2 extends T1, S1 +//│ ║ l.28: trait S2 extends T1, S1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── The value member is defined here: //│ ║ l.6: trait T1 { fun f[A]: A -> A } @@ -37,19 +39,21 @@ trait S2 extends T1, S1 trait S2 { class f } //│ trait S2 { -//│ class f +//│ class f { +//│ constructor() +//│ } //│ } :e trait S3 extends S1, S2 //│ ╔══[ERROR] Intersection of class member and class members currently unsupported -//│ ║ l.44: trait S3 extends S1, S2 +//│ ║ l.48: trait S3 extends S1, S2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: //│ ║ l.20: trait S1 { class f } //│ ║ ^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.38: trait S2 { class f } +//│ ║ l.40: trait S2 { class f } //│ ╙── ^^^^^^^ //│ trait S3 extends S1, S2 @@ -77,8 +81,8 @@ trait T1 { val x: Int | string } //│ let x: Int | string //│ } -class C2 extends C1(0), T1 -//│ class C2 extends C1, T1 +class C2() extends C1(0), T1 +//│ class C2() extends C1, T1 C2().x : 0 //│ 0 @@ -86,39 +90,43 @@ C2().x : 0 :e class C2 extends C1(false), T1 //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.87: class C2 extends C1(false), T1 +//│ ║ l.91: class C2 extends C1(false), T1 //│ ║ ^^^^^ //│ ╟── reference of type `false` does not match type `Int | string` //│ ╟── Note: constraint arises from union type: -//│ ║ l.74: trait T1 { val x: Int | string } +//│ ║ l.78: trait T1 { val x: Int | string } //│ ║ ^^^^^^^^^^^^ //│ ╟── from signature of member `x`: -//│ ║ l.74: trait T1 { val x: Int | string } +//│ ║ l.78: trait T1 { val x: Int | string } //│ ╙── ^^^^^^^^^^^^^^^ -//│ class C2 extends C1, T1 +//│ class C2 extends C1, T1 { +//│ constructor() +//│ } :e class C2 extends C1("oops"), T1 //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.101: class C2 extends C1("oops"), T1 +//│ ║ l.107: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"oops"` does not match type `Bool | Int` -//│ ║ l.101: class C2 extends C1("oops"), T1 +//│ ║ l.107: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.73: class C1(x: Int | Bool) +//│ ║ l.77: class C1(x: Int | Bool) //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in string literal: -//│ ║ l.101: class C2 extends C1("oops"), T1 +//│ ║ l.107: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^ //│ ╟── string literal of type `"oops"` does not match type `Int | string` //│ ╟── Note: constraint arises from union type: -//│ ║ l.74: trait T1 { val x: Int | string } +//│ ║ l.78: trait T1 { val x: Int | string } //│ ║ ^^^^^^^^^^^^ //│ ╟── from signature of member `x`: -//│ ║ l.74: trait T1 { val x: Int | string } +//│ ║ l.78: trait T1 { val x: Int | string } //│ ╙── ^^^^^^^^^^^^^^^ -//│ class C2 extends C1, T1 +//│ class C2 extends C1, T1 { +//│ constructor() +//│ } diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 664551c54b..55fb957fd2 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -149,7 +149,9 @@ module M { //│ ║ l.133: fun a: A //│ ╙── ^^^^ //│ module M { -//│ class A +//│ class A { +//│ constructor() +//│ } //│ fun a: A //│ } @@ -160,7 +162,7 @@ module M { fun a = 1 } //│ ╔══[ERROR] undeclared `this` -//│ ║ l.159: fun a: this.A +//│ ║ l.161: fun a: this.A //│ ╙── ^^^^ //│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index 21dbc683b0..6e9d371678 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -8,12 +8,43 @@ mixin BaseTest(x: Int) { //│ fun test: Int //│ } -// TODO +module Test extends BaseTest(42) +//│ module Test { +//│ fun test: Int +//│ } + +Test.test +//│ Int +//│ res +//│ = 42 + +// :e // TODO reject +Test.x +//│ 42 +//│ res +//│ = undefined + + +mixin BaseTest(x: Int -> Int) +//│ mixin BaseTest(x: Int -> Int) + +module Test extends BaseTest(id) +//│ module Test + +:re // TODO implement mixin param getters +Test.x(1) +//│ 1 +//│ res +//│ Runtime error: +//│ TypeError: Test.x is not a function + + +:e // TODO support mixin BaseTest(x) { fun test = x } //│ ╔══[ERROR] Mixin parameters currently need type annotations -//│ ║ l.12: mixin BaseTest(x) { +//│ ║ l.43: mixin BaseTest(x) { //│ ╙── ^ //│ mixin BaseTest(x: error) { //│ fun test: error diff --git a/shared/src/test/diff/nu/ModuleParameters.mls b/shared/src/test/diff/nu/ModuleParameters.mls index a005806e52..b7301e33d5 100644 --- a/shared/src/test/diff/nu/ModuleParameters.mls +++ b/shared/src/test/diff/nu/ModuleParameters.mls @@ -3,21 +3,59 @@ :e module A(x: Int) { fun y = x } -//│ ╔══[ERROR] module parameters are not supported +//│ ╔══[ERROR] Module parameters are not supported //│ ║ l.5: module A(x: Int) { fun y = x } //│ ╙── ^ //│ module A(x: Int) { //│ fun y: Int //│ } +:e +A +//│ ╔══[ERROR] Parameterized modules are not supported +//│ ║ l.14: A +//│ ╙── ^ +//│ (x: Int) -> A +//│ res +//│ = A { class: [class A] } + +:e +A(123) +//│ ╔══[ERROR] Parameterized modules are not supported +//│ ║ l.23: A(123) +//│ ╙── ^ +//│ A +//│ res +//│ Runtime error: +//│ TypeError: A is not a function + +:e A.x -//│ Int +//│ ╔══[ERROR] Parameterized modules are not supported +//│ ║ l.33: A.x +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.33: A.x +//│ ║ ^^^ +//│ ╟── reference of type `(x: Int) -> A` does not have field 'x' +//│ ║ l.33: A.x +//│ ╙── ^ +//│ error //│ res //│ = undefined +:e A.y -//│ Int +//│ ╔══[ERROR] Parameterized modules are not supported +//│ ║ l.48: A.y +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.48: A.y +//│ ║ ^^^ +//│ ╟── reference of type `(x: Int) -> A` does not have field 'y' +//│ ║ l.48: A.y +//│ ╙── ^ +//│ error //│ res //│ = undefined - diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index c10b41ff6f..e18bbf0998 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -148,6 +148,7 @@ class Test0_2() { fun b = 123 } //│ class Test0_1 { +//│ constructor() //│ fun a: 123 //│ } //│ class Test0_2() { @@ -163,7 +164,7 @@ module Test1_2 { fun b = Test1_1.a } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.163: fun b = Test1_1.a +//│ ║ l.164: fun b = Test1_1.a //│ ╙── ^^ //│ module Test1_1 { //│ fun a: error @@ -187,13 +188,56 @@ class Test1_1 { class Test1_2 { fun b = Test1_1().a } +//│ ╔══[ERROR] Class Test1_2 cannot be instantiated as it exposes no such constructor +//│ ║ l.186: fun a = Test1_2().b +//│ ╙── ^^^^^^^ +//│ ╔══[ERROR] Class Test1_1 cannot be instantiated as it exposes no such constructor +//│ ║ l.189: fun b = Test1_1().a +//│ ╙── ^^^^^^^ +//│ class Test1_1 { +//│ constructor() +//│ fun a: error +//│ } +//│ class Test1_2 { +//│ constructor() +//│ fun b: error +//│ } + +:e +class Test1_1() { + fun a = Test1_2().b +} +class Test1_2() { + fun b = Test1_1().a +} //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.188: fun b = Test1_1().a +//│ ║ l.211: fun b = Test1_1().a //│ ╙── ^^ +//│ class Test1_1() { +//│ fun a: error +//│ } +//│ class Test1_2() { +//│ fun b: error +//│ } + +:e +class Test1_1 { + fun a = (new Test1_2).b +} +class Test1_2 { + fun b = (new Test1_1).a +} +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.224: class Test1_1 { +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.225: fun a = (new Test1_2).b +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ class Test1_1 { +//│ constructor() //│ fun a: error //│ } //│ class Test1_2 { +//│ constructor() //│ fun b: error //│ } @@ -211,7 +255,7 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.210: fun c = Test2_1.a +//│ ║ l.254: fun c = Test2_1.a //│ ╙── ^^ //│ module Test2_1 { //│ fun a: 123 | error diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index b0519077cd..3c4e1b2e9f 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -30,13 +30,15 @@ module M0 { class NC0 } //│ module M0 { -//│ class NC0 +//│ class NC0 { +//│ constructor() +//│ } //│ } :e M0.NC0 //│ ╔══[ERROR] access to class member not yet supported -//│ ║ l.37: M0.NC0 +//│ ║ l.39: M0.NC0 //│ ╙── ^^^^ //│ error //│ res @@ -53,7 +55,7 @@ module M1 { :e M1.NM1 //│ ╔══[ERROR] access to module member not yet supported -//│ ║ l.54: M1.NM1 +//│ ║ l.56: M1.NM1 //│ ╙── ^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/New.mls b/shared/src/test/diff/nu/New.mls index b29b06ab62..df4bd0f2f4 100644 --- a/shared/src/test/diff/nu/New.mls +++ b/shared/src/test/diff/nu/New.mls @@ -48,3 +48,5 @@ class PoInt(x, y) let origin = new PoInt(0, 0) //│ origin: PoInt & {x: 0, y: 0} //│ = PoInt { x: 0, y: 0 } + + diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index c30d4efe3c..1350b5e9bc 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -38,7 +38,7 @@ let origin = PoInt[Int](0, 0) //│ ╔══[ERROR] Type application syntax is not yet supported //│ ║ l.37: let origin = PoInt[Int](0, 0) //│ ╙── ^^^^^^^^^^ -//│ let origin: error +//│ let origin: PoInt[0] //│ origin //│ = PoInt {} @@ -94,3 +94,44 @@ new + +fun f(x) = {x} +//│ fun f: forall 'a. 'a -> {x: 'a} + +:e +new f(1) +//│ ╔══[ERROR] Value f cannot be used in `new` expression +//│ ║ l.102: new f(1) +//│ ╙── ^^^^^^^^ +//│ error +//│ res +//│ = { x: 1 } + + +module Oops +//│ module Oops + +:e +new Oops +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.115: new Oops +//│ ║ ^^^^^^^^ +//│ ╙── applied expression of type `Oops` is not a function +//│ error +//│ res +//│ = Oops {} + + +:e +new Oops2 +trait Oops2 +//│ ╔══[ERROR] Trait Oops2 cannot be used in term position +//│ ║ l.126: new Oops2 +//│ ╙── ^^^^^^^^^ +//│ trait Oops2 +//│ error +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'build') + + diff --git a/shared/src/test/diff/nu/NoThisCtor.mls b/shared/src/test/diff/nu/NoThisCtor.mls index 73d948f978..591d07019f 100644 --- a/shared/src/test/diff/nu/NoThisCtor.mls +++ b/shared/src/test/diff/nu/NoThisCtor.mls @@ -31,15 +31,20 @@ class Foo1() extends Foo() { //│ let foo: Int //│ } -// FIXME: type constrcutor +// FIXME: reject access to `this` from constructor class Foo2() extends Foo() { - virtual val foo = 2 + virtual val foo: Int + val foo = 2 constructor() { log(this.foo) } } +//│ ╔══[ERROR] identifier not found: this +//│ ║ l.39: log(this.foo) +//│ ╙── ^^^^ //│ class Foo2() extends Foo { -//│ let foo: 2 +//│ constructor() +//│ let foo: Int //│ } :e @@ -49,7 +54,7 @@ class Foo3() extends Foo() { val s = this.foo } //│ ╔══[ERROR] Cannot access `this` while initializing field s -//│ ║ l.49: val s = this.foo +//│ ║ l.54: val s = this.foo //│ ╙── ^^^^ //│ class Foo3() extends Foo { //│ let foo: Int @@ -64,10 +69,10 @@ class Foo4() extends Foo() { let bb = bar(0) // call `this` indirectly } //│ ╔══[ERROR] Cannot access `this` while initializing field bb -//│ ║ l.64: let bb = bar(0) // call `this` indirectly +//│ ║ l.69: let bb = bar(0) // call `this` indirectly //│ ║ ^^^^^^^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.63: fun bar(x) = this.foo + x // ok +//│ ║ l.68: fun bar(x) = this.foo + x // ok //│ ╙── ^^^^ //│ class Foo4() extends Foo { //│ fun bar: Int -> Int @@ -82,10 +87,10 @@ class Foo5() extends Foo() { fun bar(y: Int) = this.foo + y } //│ ╔══[ERROR] Cannot access `this` while initializing field x -//│ ║ l.81: val x = bar(0) +//│ ║ l.86: val x = bar(0) //│ ║ ^^^^^^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.82: fun bar(y: Int) = this.foo + y +//│ ║ l.87: fun bar(y: Int) = this.foo + y //│ ╙── ^^^^ //│ class Foo5() extends Foo { //│ fun bar: (y: Int) -> Int @@ -119,13 +124,13 @@ class Bar2() extends Bar() { val two = this.add(1) // add is final, but it refers to `this` } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.119: val two = this.add(1) // add is final, but it refers to `this` +//│ ║ l.124: val two = this.add(1) // add is final, but it refers to `this` //│ ╙── ^^^^ //│ ╔══[ERROR] Cannot access `this` while initializing field two -//│ ║ l.119: val two = this.add(1) // add is final, but it refers to `this` +//│ ║ l.124: val two = this.add(1) // add is final, but it refers to `this` //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.110: fun add(x) = x + this.d +//│ ║ l.115: fun add(x) = x + this.d //│ ╙── ^^^^ //│ class Bar2() extends Bar { //│ fun add: Int -> Int @@ -140,10 +145,10 @@ abstract class Foo: Int -> Int { fun f = this(0) } //│ ╔══[ERROR] Cannot access `this` while initializing field x -//│ ║ l.139: val x = f +//│ ║ l.144: val x = f //│ ║ ^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.140: fun f = this(0) +//│ ║ l.145: fun f = this(0) //│ ╙── ^^^^ //│ abstract class Foo: Int -> Int { //│ fun f: nothing diff --git a/shared/src/test/diff/nu/Object.mls b/shared/src/test/diff/nu/Object.mls index cd928b7102..a27e51bd99 100644 --- a/shared/src/test/diff/nu/Object.mls +++ b/shared/src/test/diff/nu/Object.mls @@ -89,15 +89,39 @@ fun foo = forall 'a; (x: 'a) => if x is A then true else false -:ge +:e Object -//│ () -> Object +//│ ╔══[ERROR] Class Object is abstract and cannot be instantiated +//│ ║ l.93: Object +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor +//│ ║ l.93: Object +//│ ╙── ^^^^^^ +//│ error //│ Code generation encountered an error: //│ unresolved symbol Object -:ge +:e Object() -//│ Object +//│ ╔══[ERROR] Class Object is abstract and cannot be instantiated +//│ ║ l.105: Object() +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor +//│ ║ l.105: Object() +//│ ╙── ^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol Object + +:e +new Object +//│ ╔══[ERROR] Class Object is abstract and cannot be instantiated +//│ ║ l.117: new Object +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor +//│ ║ l.117: new Object +//│ ╙── ^^^^^^^^^^ +//│ error //│ Code generation encountered an error: //│ unresolved symbol Object @@ -109,7 +133,6 @@ class B() extends Object //│ Code generation encountered an error: //│ unresolved parent Object. -// TODO class C() extends A //│ class C() extends A diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls index f06046af0a..a99fdcab6d 100644 --- a/shared/src/test/diff/nu/ParamImplementing.mls +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -21,7 +21,9 @@ class C extends T, M(false) //│ ╟── from signature of member `x`: //│ ║ l.4: trait T { fun x: Int } //│ ╙── ^^^^^^ -//│ class C extends T +//│ class C extends T { +//│ constructor() +//│ } trait T { fun x: Int } @@ -32,6 +34,8 @@ mixin M(x: Num) //│ mixin M(x: Num) class C extends T, M(0) -//│ class C extends T +//│ class C extends T { +//│ constructor() +//│ } diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 12a24d49fa..f6c7601f6d 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -18,14 +18,15 @@ class List { let Nil: () => List<'a> let Cons: (head: 'a, tail: List<'a>) => List<'a> //│ class List[A] { +//│ constructor() //│ fun match: forall 'res. (ifNil: () -> 'res, ifCons: (A, List[A]) -> 'res) -> 'res //│ } //│ let Nil: () -> List[nothing] //│ let Cons: forall 'a. (head: 'a, tail: List['a]) -> List['a] -class NotFound +module NotFound class Success(result: A) -//│ class NotFound +//│ module NotFound //│ class Success[A](result: A) fun eq(l: Str, r: Str): Bool @@ -35,7 +36,7 @@ fun eq(l: Str, r: Str): Bool // fun list_assoc(s, l) = fun list_assoc(s, l: List<'a>) = l.match( - ifNil: () => NotFound(), + ifNil: () => NotFound, ifCons: (h, t) => if eq(s, h._1) then Success(h._2) else list_assoc(s, t) diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index a5e6bb6fea..a05e28523c 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -100,7 +100,9 @@ trait Base2: Foo['FigureItOut] // TODO reject class Impl extends Base2 -//│ class Impl extends Base2 +//│ class Impl extends Base2 { +//│ constructor() +//│ } (x: Impl) => x : Base2 //│ (x: Impl) -> Base2 @@ -110,7 +112,7 @@ class Impl extends Base2 :e class Impl() extends Base2, Foo //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `Impl` -//│ ║ l.111: class Impl() extends Base2, Foo +//│ ║ l.113: class Impl() extends Base2, Foo //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.5: trait Foo[A] { fun x: A } diff --git a/shared/src/test/diff/nu/SelfAppMethods.mls b/shared/src/test/diff/nu/SelfAppMethods.mls index 2e742cd44f..3ff6e78883 100644 --- a/shared/src/test/diff/nu/SelfAppMethods.mls +++ b/shared/src/test/diff/nu/SelfAppMethods.mls @@ -10,6 +10,7 @@ class A { } //│ class A { +//│ constructor() //│ fun f: nothing //│ fun g: A //│ } @@ -22,7 +23,7 @@ module A { fun h = g(g) } //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.22: fun h = g(g) +//│ ║ l.23: fun h = g(g) //│ ║ ^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ module A { diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index f72baecc7d..71ae420fd7 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -56,13 +56,11 @@ Foo3(1).foo class Foo4 { fun test = [Foo4.test] } -//│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.57: fun test = [Foo4.test] -//│ ║ ^^^^^^^^^ -//│ ╟── reference of type `() -> #Foo4` does not have field 'test' +//│ ╔══[ERROR] Class Foo4 cannot be instantiated as it exposes no such constructor //│ ║ l.57: fun test = [Foo4.test] //│ ╙── ^^^^ //│ class Foo4 { +//│ constructor() //│ fun test: [error] //│ } @@ -71,7 +69,7 @@ class Foo5(x: Int) { fun test = [Foo5(5).test] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.71: fun test = [Foo5(5).test] +//│ ║ l.69: fun test = [Foo5(5).test] //│ ╙── ^^^^^ //│ class Foo5(x: Int) { //│ fun test: [error] @@ -84,13 +82,13 @@ class Foo6[A](x: A) { fun test3 = [Foo6([x]).test3] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.82: fun test1 = [Foo6(x).test1] +//│ ║ l.80: fun test1 = [Foo6(x).test1] //│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.83: fun test2 = [Foo6(123).test2] +//│ ║ l.81: fun test2 = [Foo6(123).test2] //│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.84: fun test3 = [Foo6([x]).test3] +//│ ║ l.82: fun test3 = [Foo6([x]).test3] //│ ╙── ^^^^^^ //│ class Foo6[A](x: A) { //│ fun test1: [error] @@ -108,7 +106,7 @@ class Foo7[A](head: A, tail: Foo7[A] | N) { _ then tail.test1 } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.108: _ then tail.test1 +//│ ║ l.106: _ then tail.test1 //│ ╙── ^^^^^^ //│ class Foo7[A](head: A, tail: Foo7[A] | N) { //│ fun test1: error | A @@ -149,7 +147,7 @@ class Foo8[A](x: A) { x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.148: let tmp = Foo8(y).test1(x) +//│ ║ l.146: let tmp = Foo8(y).test1(x) //│ ╙── ^^^^^^ //│ class Foo8[A](x: A) { //│ fun test1: (y: anything) -> A diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index 1f2972f9f2..81a2007a9e 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -71,6 +71,7 @@ module M extends C2 { class C1 { virtual fun x: 0 | 2 = 0 } //│ class C1 { +//│ constructor() //│ fun x: 0 | 2 //│ } @@ -123,7 +124,7 @@ module M extends T1, T2, C1 { fun x = this.x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.123: fun x = this.x +//│ ║ l.124: fun x = this.x //│ ╙── ^^ //│ module M extends C1, T1, T2 { //│ fun x: error @@ -135,13 +136,13 @@ module M extends T1, T2, C1 { fun x = this.x } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.134: fun x: 0 +//│ ║ l.135: fun x: 0 //│ ║ ^^^^ //│ ╟── type `0` does not match type `1 | 2` -//│ ║ l.134: fun x: 0 +//│ ║ l.135: fun x: 0 //│ ║ ^ //│ ╟── but it flows into signature of member `x` with expected type `1 | 2` -//│ ║ l.134: fun x: 0 +//│ ║ l.135: fun x: 0 //│ ║ ^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.8: trait T2 { fun x: 1 | 2 } @@ -158,6 +159,7 @@ class C extends C1, T2 { fun x = this.x } //│ class C extends C1, T2 { +//│ constructor() //│ fun x: 2 //│ } @@ -174,12 +176,13 @@ M.x :e class C2 extends T1 //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C2` -//│ ║ l.175: class C2 extends T1 +//│ ║ l.177: class C2 extends T1 //│ ║ ^^ //│ ╟── Declared here: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ //│ class C2 extends T1 { +//│ constructor() //│ fun x: 0 | 1 //│ } @@ -191,12 +194,13 @@ abstract class C2 extends T1 :e class C3 extends C2 //│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C3` -//│ ║ l.192: class C3 extends C2 +//│ ║ l.195: class C3 extends C2 //│ ║ ^^ //│ ╟── Declared here: //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ //│ class C3 extends C2, T1 { +//│ constructor() //│ fun x: 0 | 1 //│ } @@ -207,19 +211,20 @@ abstract class C3 extends C2 class C2 extends T1 { fun x = 1 } //│ class C2 extends T1 { +//│ constructor() //│ fun x: 1 //│ } :e class C2 extends T1, T2 { fun x = 2 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.214: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.219: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── integer literal of type `2` does not match type `0 | 1` -//│ ║ l.214: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.219: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 1` -//│ ║ l.214: class C2 extends T1, T2 { fun x = 2 } +//│ ║ l.219: class C2 extends T1, T2 { fun x = 2 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.7: trait T1 { fun x: 0 | 1 } @@ -228,60 +233,66 @@ class C2 extends T1, T2 { fun x = 2 } //│ ║ l.7: trait T1 { fun x: 0 | 1 } //│ ╙── ^^^^^^^^ //│ class C2 extends T1, T2 { +//│ constructor() //│ fun x: 2 //│ } class C2 extends T1, T2 { virtual fun x = 1 } //│ class C2 extends T1, T2 { +//│ constructor() //│ fun x: 1 //│ } :e class C3 extends C2 { virtual fun x = 111 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.240: class C3 extends C2 { virtual fun x = 111 } +//│ ║ l.247: class C3 extends C2 { virtual fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── integer literal of type `111` does not match type `1` -//│ ║ l.240: class C3 extends C2 { virtual fun x = 111 } +//│ ║ l.247: class C3 extends C2 { virtual fun x = 111 } //│ ║ ^^^ //│ ╟── but it flows into definition of method x with expected type `1` -//│ ║ l.240: class C3 extends C2 { virtual fun x = 111 } +//│ ║ l.247: class C3 extends C2 { virtual fun x = 111 } //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.234: class C2 extends T1, T2 { virtual fun x = 1 } +//│ ║ l.240: class C2 extends T1, T2 { virtual fun x = 1 } //│ ║ ^ //│ ╟── from definition of method x: -//│ ║ l.234: class C2 extends T1, T2 { virtual fun x = 1 } +//│ ║ l.240: class C2 extends T1, T2 { virtual fun x = 1 } //│ ╙── ^^^^^ //│ class C3 extends C2, T1, T2 { +//│ constructor() //│ fun x: 111 //│ } class C3 extends C2 { fun x = 1 } //│ class C3 extends C2, T1, T2 { +//│ constructor() //│ fun x: 1 //│ } class C2 extends C1, T1 { fun x = 0 } //│ class C2 extends C1, T1 { +//│ constructor() //│ fun x: 0 //│ } class C2 extends T1, C1 { fun x = 0 } //│ class C2 extends C1, T1 { +//│ constructor() //│ fun x: 0 //│ } :e class C2 extends C1, T1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.276: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.287: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.276: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.287: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.276: class C2 extends C1, T1 { fun x = 1 } +//│ ║ l.287: class C2 extends C1, T1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.72: class C1 { virtual fun x: 0 | 2 = 0 } @@ -290,19 +301,20 @@ class C2 extends C1, T1 { fun x = 1 } //│ ║ l.72: class C1 { virtual fun x: 0 | 2 = 0 } //│ ╙── ^^^^^^^^^^^^ //│ class C2 extends C1, T1 { +//│ constructor() //│ fun x: 1 //│ } :e class C2 extends T1, C1 { fun x = 1 } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.297: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.309: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── integer literal of type `1` does not match type `0 | 2` -//│ ║ l.297: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.309: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^ //│ ╟── but it flows into definition of method x with expected type `0 | 2` -//│ ║ l.297: class C2 extends T1, C1 { fun x = 1 } +//│ ║ l.309: class C2 extends T1, C1 { fun x = 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.72: class C1 { virtual fun x: 0 | 2 = 0 } @@ -311,6 +323,7 @@ class C2 extends T1, C1 { fun x = 1 } //│ ║ l.72: class C1 { virtual fun x: 0 | 2 = 0 } //│ ╙── ^^^^^^^^^^^^ //│ class C2 extends C1, T1 { +//│ constructor() //│ fun x: 1 //│ } @@ -319,13 +332,13 @@ class C2 extends T1, C1 { fun x = 1 } :e trait T2 { val r = 1(1) } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.320: trait T2 { val r = 1(1) } +//│ ║ l.333: trait T2 { val r = 1(1) } //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.320: trait T2 { val r = 1(1) } +//│ ║ l.333: trait T2 { val r = 1(1) } //│ ║ ^^^^ //│ ╟── integer literal of type `1` is not a function -//│ ║ l.320: trait T2 { val r = 1(1) } +//│ ║ l.333: trait T2 { val r = 1(1) } //│ ╙── ^ //│ trait T2 { //│ let r: error @@ -333,6 +346,7 @@ trait T2 { val r = 1(1) } class C2 extends T2 //│ class C2 extends T2 { +//│ constructor() //│ let r: error //│ } @@ -343,36 +357,33 @@ trait T3[A] { } class C2 extends T3[Int] //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.342: val r = C2().x +//│ ║ l.356: val r = C2().x //│ ╙── ^^^^^^^^^^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.341: trait T3[A] { -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.342: val r = C2().x -//│ ╙── ^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type `C2` does not contain member `x` -//│ ║ l.342: val r = C2().x -//│ ╙── ^^ +//│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no such constructor +//│ ║ l.356: val r = C2().x +//│ ╙── ^^ //│ trait T3[A] { //│ let r: error //│ } -//│ class C2 extends T3 +//│ class C2 extends T3 { +//│ constructor() +//│ let r: error +//│ } :e // * Note: lack of hygiene... happens only if class shadows previous C2 and is part of the error-throwing block C2() : T3['X] -//│ ╔══[ERROR] Type `C2` does not contain member `T3#A` -//│ ║ l.341: trait T3[A] { -//│ ╙── ^ -//│ T3['X] -//│ where -//│ 'X :> error +//│ ╔══[ERROR] Construction of unparameterized class C2 should use the `new` keyword +//│ ║ l.374: C2() : T3['X] +//│ ╙── ^^ +//│ T3[Int] class C3 extends T3[Int] //│ class C3 extends T3 { +//│ constructor() //│ let r: error //│ } -C3() : T3['X] +(new C3) : T3['X] //│ T3[Int] @@ -384,38 +395,41 @@ trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } class B extends Foo { fun foo = error } //│ class B extends Foo { +//│ constructor() //│ fun foo: nothing //│ } class B extends Foo { fun foo(x) = x } //│ class B extends Foo { +//│ constructor() //│ fun foo: forall 'a. 'a -> 'a //│ } :e class B extends Foo { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.396: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `'A` is not an instance of type `Int` -//│ ║ l.380: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ l.391: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } //│ ║ ^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.396: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^ //│ ╟── Note: quantified type variable 'A is defined at: -//│ ║ l.380: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ l.391: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.396: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── operator application of type `Int` does not match type `'A` -//│ ║ l.396: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.380: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ l.391: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } //│ ╙── ^^ //│ class B extends Foo { +//│ constructor() //│ fun foo: Int -> Int //│ } diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index e899bf1558..562536b2c3 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -8,7 +8,9 @@ class C -//│ class C +//│ class C { +//│ constructor() +//│ } new C //│ C @@ -21,9 +23,11 @@ new C() //│ res //│ = C {} -// :e // TODO reject -:re +:e C() +//│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword +//│ ║ l.27: C() +//│ ╙── ^ //│ C //│ res //│ Runtime error: @@ -84,10 +88,10 @@ D.unapply(D(42)) :e D.unapply({ x: 42 }) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.85: D.unapply({ x: 42 }) +//│ ║ l.89: D.unapply({ x: 42 }) //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── record literal of type `{x: 42}` is not an instance of type `D` -//│ ║ l.85: D.unapply({ x: 42 }) +//│ ║ l.89: D.unapply({ x: 42 }) //│ ╙── ^^ //│ error | [42] //│ res @@ -109,10 +113,10 @@ DT.unapply(DT(42)) :e DT.unapply({ x: 42 }) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.110: DT.unapply({ x: 42 }) +//│ ║ l.114: DT.unapply({ x: 42 }) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── record literal of type `{x: 42}` is not an instance of type `DT` -//│ ║ l.110: DT.unapply({ x: 42 }) +//│ ║ l.114: DT.unapply({ x: 42 }) //│ ╙── ^^ //│ error | [42] //│ res @@ -123,45 +127,55 @@ DT.unapply({ x: 42 }) class C -//│ class C +//│ class C { +//│ constructor() +//│ } -// :e // TODO fix type +:e fun foo(c) = new c -//│ fun foo: forall 'a. (() -> 'a) -> 'a +//│ ╔══[ERROR] Cannot use `new` on non-class variable of type ?a +//│ ║ l.135: fun foo(c) = new c +//│ ╙── ^^^^^ +//│ fun foo: anything -> error -// :e // TODO reject :re foo(() => 123) -//│ 123 +//│ error //│ res //│ Runtime error: //│ TypeError: c is not a constructor +:e foo(C) -//│ C +//│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword +//│ ║ l.149: foo(C) +//│ ╙── ^ +//│ error //│ res //│ = C {} -// :e // TODO fix type +:e fun bar(c) = new c(123) -//│ fun bar: forall 'a. (123 -> 'a) -> 'a +//│ ╔══[ERROR] Cannot use `new` on non-class variable of type ?a +//│ ║ l.159: fun bar(c) = new c(123) +//│ ╙── ^^^^^^^^^^ +//│ fun bar: anything -> error -// :e // TODO reject :re bar(D) -//│ D +//│ error //│ res //│ Runtime error: //│ TypeError: c is not a constructor -:e // TODO accept +:e // TODO accept when we have first-class classes bar(D.class) //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.159: bar(D.class) +//│ ║ l.173: bar(D.class) //│ ║ ^^^^^^^ //│ ╟── reference of type `(x: Int) -> D` does not have field 'class' -//│ ║ l.159: bar(D.class) +//│ ║ l.173: bar(D.class) //│ ╙── ^ //│ error //│ res @@ -173,12 +187,14 @@ bar(D.class) class C -//│ class C +//│ class C { +//│ constructor() +//│ } :e // TODO new C { val x = 1 } //│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.179: new C { val x = 1 } +//│ ║ l.195: new C { val x = 1 } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: @@ -191,6 +207,7 @@ new C { val x = 1 } class Cls[A] { fun x: A = x } //│ class Cls[A] { +//│ constructor() //│ fun x: A //│ } @@ -202,7 +219,7 @@ let c = new Cls // FIXME let y: c.A = c.x //│ ╔══[ERROR] type identifier not found: c -//│ ║ l.203: let y: c.A = c.x +//│ ║ l.220: let y: c.A = c.x //│ ╙── ^ //│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing @@ -213,6 +230,7 @@ let y: c.A = c.x class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ class Cls[A] { +//│ constructor() //│ fun g: A -> Int //│ fun x: A //│ } @@ -223,14 +241,14 @@ fun test(a: Object) = if a is Cls then a.x else error //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.222: fun test(a: Object) = if a is +//│ ║ l.240: fun test(a: Object) = if a is //│ ║ ^^^^ -//│ ║ l.223: Cls then a.x +//│ ║ l.241: Cls then a.x //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.224: else error +//│ ║ l.242: else error //│ ║ ^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.214: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } +//│ ║ l.231: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> (error | ??A) @@ -239,20 +257,21 @@ fun test(a: Object) = if a is Cls then a.g(a.x) // a.x : a.A ; a.g : a.A -> a.A else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.238: fun test(a: Object) = if a is +//│ ║ l.256: fun test(a: Object) = if a is //│ ║ ^^^^ -//│ ║ l.239: Cls then a.g(a.x) // a.x : a.A ; a.g : a.A -> a.A +//│ ║ l.257: Cls then a.g(a.x) // a.x : a.A ; a.g : a.A -> a.A //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.240: else 0 +//│ ║ l.258: else 0 //│ ║ ^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.214: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } +//│ ║ l.231: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> Int class Cls[out A] { fun x: A = x } //│ class Cls[A] { +//│ constructor() //│ fun x: A //│ } diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 871b742a14..050589659d 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -13,6 +13,7 @@ class Foo { fun test = this.x } //│ ║ l.11: class Foo { fun test = this.x } //│ ╙── ^^ //│ class Foo { +//│ constructor() //│ fun test: error //│ } @@ -20,7 +21,7 @@ class Foo { fun test = this.x } :e class Foo(n: Int) { fun test = this.x } //│ ╔══[ERROR] Type `#Foo & {n: Int}` does not contain member `x` -//│ ║ l.21: class Foo(n: Int) { fun test = this.x } +//│ ║ l.22: class Foo(n: Int) { fun test = this.x } //│ ╙── ^^ //│ class Foo(n: Int) { //│ fun test: error @@ -30,7 +31,7 @@ class Foo(n: Int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } //│ ╔══[ERROR] Type `#Foo & {Foo#A = ?A, n: A}` does not contain member `x` -//│ ║ l.31: class Foo(n: A) { fun test = this.x } +//│ ║ l.32: class Foo(n: A) { fun test = this.x } //│ ╙── ^^ //│ class Foo[A](n: A) { //│ fun test: error @@ -44,21 +45,24 @@ class Foo { // fun test = this.x } //│ ╔══[ERROR] Type `#Foo` does not contain member `x` -//│ ║ l.43: this: { x: 'a } +//│ ║ l.44: this: { x: 'a } //│ ╙── ^ -//│ class Foo +//│ class Foo { +//│ constructor() +//│ } // TODO // * All on one line: class Test { this: { x: Int}; fun test = this.x } //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.54: class Test { this: { x: Int}; fun test = this.x } +//│ ║ l.57: class Test { this: { x: Int}; fun test = this.x } //│ ╙── ^^ //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.54: class Test { this: { x: Int}; fun test = this.x } +//│ ║ l.57: class Test { this: { x: Int}; fun test = this.x } //│ ╙── ^ //│ class Test { +//│ constructor() //│ fun test: error //│ } diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index 15d616a772..6191d1589c 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -13,6 +13,7 @@ class C1 extends T1 { fun f(x: Int) = x } //│ class C1 extends T1 { +//│ constructor() //│ fun f: (x: Int) -> Int //│ } @@ -20,6 +21,7 @@ class C1 extends T1['FigureItOut] { fun f(x: Int) = x } //│ class C1 extends T1 { +//│ constructor() //│ fun f: (x: Int) -> Int //│ } @@ -66,16 +68,16 @@ c1.f :e (c1 : T1['X]).f(false) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.67: (c1 : T1['X]).f(false) +//│ ║ l.69: (c1 : T1['X]).f(false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.67: (c1 : T1['X]).f(false) +//│ ║ l.69: (c1 : T1['X]).f(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.20: fun f(x: Int) = x +//│ ║ l.21: fun f(x: Int) = x //│ ║ ^^^ //│ ╟── from type variable: -//│ ║ l.67: (c1 : T1['X]).f(false) +//│ ║ l.69: (c1 : T1['X]).f(false) //│ ╙── ^^ //│ Int | error | false //│ res @@ -94,30 +96,19 @@ class C2 extends T2['FigureItOut] { fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.91: val r = C2().f(false) +//│ ║ l.93: val r = C2().f(false) //│ ╙── ^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.89: trait T2[A] { -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.90: fun f: A -> A -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.91: val r = C2().f(false) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.91: val r = C2().f(false) -//│ ║ ^^^^^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.91: val r = C2().f(false) -//│ ║ ^^^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.94: fun f(x: Int) = x -//│ ╙── ^^^ +//│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no such constructor +//│ ║ l.93: val r = C2().f(false) +//│ ╙── ^^ //│ trait T2[A] { //│ fun f: A -> A -//│ let r: Int | error +//│ let r: error //│ } //│ class C2 extends T2 { +//│ constructor() //│ fun f: (x: Int) -> Int +//│ let r: error //│ } :e @@ -129,34 +120,27 @@ class C3 extends T3['FigureItOut] { fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.126: val r = (C3() : T3['X]).f(false) +//│ ║ l.117: val r = (C3() : T3['X]).f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.124: trait T3[A] { -//│ ║ ^^^^^^^^^^^^^ -//│ ║ l.125: fun f: A -> A -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.126: val r = (C3() : T3['X]).f(false) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Type `C3` does not contain member `T3#A` -//│ ║ l.124: trait T3[A] { -//│ ╙── ^ +//│ ╔══[ERROR] Class C3 cannot be instantiated as it exposes no such constructor +//│ ║ l.117: val r = (C3() : T3['X]).f(false) +//│ ╙── ^^ //│ trait T3[A] { //│ fun f: A -> A -//│ let r: error | false +//│ let r: false //│ } //│ class C3 extends T3 { +//│ constructor() //│ fun f: (x: Int) -> Int +//│ let r: false //│ } :e // FIXME C3() : T3['X] -//│ ╔══[ERROR] Type `C3` does not contain member `T3#A` -//│ ║ l.124: trait T3[A] { -//│ ╙── ^ -//│ T3['X] -//│ where -//│ 'X :> error +//│ ╔══[ERROR] Construction of unparameterized class C3 should use the `new` keyword +//│ ║ l.139: C3() : T3['X] +//│ ╙── ^^ +//│ T3[Int] //│ res //│ Runtime error: //│ TypeError: Class constructor C3 cannot be invoked without 'new' @@ -169,12 +153,12 @@ abstract class IO[A] { } class Bind[A](underlying: IO[A]) extends IO[Int] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.167: abstract class IO[A] { +//│ ║ l.151: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.168: fun test = Bind(this) : IO[Int] +//│ ║ l.152: fun test = Bind(this) : IO[Int] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type `Bind[?A]` does not contain member `IO#A` -//│ ║ l.167: abstract class IO[A] { +//│ ║ l.151: abstract class IO[A] { //│ ╙── ^ //│ abstract class IO[A] { //│ fun test: IO[Int] @@ -191,25 +175,25 @@ class Map[A, B](underlying: IO[A], f: A -> B) extends IO[B] { fun run: B = error } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.185: abstract class IO[A] { +//│ ║ l.169: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.186: fun map[B]: (A -> B) -> IO[B] // * Removing this works... +//│ ║ l.170: fun map[B]: (A -> B) -> IO[B] // * Removing this works... //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.187: fun map(f) = Map(this, f) +//│ ║ l.171: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.188: fun run: A +//│ ║ l.172: fun run: A //│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Type `Map[?A, ?B]` does not contain member `IO#A` -//│ ║ l.185: abstract class IO[A] { +//│ ║ l.169: abstract class IO[A] { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method map: -//│ ║ l.187: fun map(f) = Map(this, f) +//│ ║ l.171: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Map[?A, ?B]` does not have field 'IO#A' -//│ ║ l.187: fun map(f) = Map(this, f) +//│ ║ l.171: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.186: fun map[B]: (A -> B) -> IO[B] // * Removing this works... +//│ ║ l.170: fun map[B]: (A -> B) -> IO[B] // * Removing this works... //│ ╙── ^^^^^ //│ abstract class IO[A] { //│ fun map: forall 'B. (A -> 'B) -> IO['B] @@ -229,25 +213,25 @@ class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { fun run = f(underlying.run).run } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.223: abstract class IO[A] { +//│ ║ l.207: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.224: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error +//│ ║ l.208: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.225: fun bind(f) = Bind(this, f) +//│ ║ l.209: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.226: fun run: A +//│ ║ l.210: fun run: A //│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Type `Bind[?A, ?B]` does not contain member `IO#A` -//│ ║ l.223: abstract class IO[A] { +//│ ║ l.207: abstract class IO[A] { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method bind: -//│ ║ l.225: fun bind(f) = Bind(this, f) +//│ ║ l.209: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Bind[?A, ?B]` does not have field 'IO#A' -//│ ║ l.225: fun bind(f) = Bind(this, f) +//│ ║ l.209: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.224: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error +//│ ║ l.208: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error //│ ╙── ^^^^^ //│ abstract class IO[A] { //│ fun bind: forall 'B. (A -> IO['B]) -> IO['B] @@ -263,9 +247,9 @@ abstract class IO[A] { class Bind[B]() extends IO[B] } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.262: abstract class IO[A] { +//│ ║ l.246: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.263: class Bind[B]() extends IO[B] +//│ ║ l.247: class Bind[B]() extends IO[B] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ abstract class IO[A] { //│ class Bind[B]() extends IO diff --git a/shared/src/test/diff/nu/TypeAliases.mls b/shared/src/test/diff/nu/TypeAliases.mls index d7b46e1822..e1fc895a10 100644 --- a/shared/src/test/diff/nu/TypeAliases.mls +++ b/shared/src/test/diff/nu/TypeAliases.mls @@ -5,7 +5,9 @@ type I = Int //│ type I = Int class CI1 -//│ class CI1 +//│ class CI1 { +//│ constructor() +//│ } // :e type AI1 = Array[Int] @@ -17,7 +19,7 @@ type AI2 = Array :e type AI3(n) = Array[Int] //│ ╔══[ERROR] Type alias definitions cannot have value parameters -//│ ║ l.18: type AI3(n) = Array[Int] +//│ ║ l.20: type AI3(n) = Array[Int] //│ ╙── ^^^ //│ type AI3 = Array[Int] diff --git a/shared/src/test/diff/nu/TypreMembers.mls b/shared/src/test/diff/nu/TypreMembers.mls index 69ac693444..af6a856b41 100644 --- a/shared/src/test/diff/nu/TypreMembers.mls +++ b/shared/src/test/diff/nu/TypreMembers.mls @@ -3,6 +3,7 @@ class Test { type T = Int } //│ class Test { +//│ constructor() //│ type T = Int //│ } @@ -20,7 +21,7 @@ trait Test { type T = Int } :e 1 : Test.T //│ ╔══[ERROR] Illegal prefix of type selection: Test -//│ ║ l.21: 1 : Test.T +//│ ║ l.22: 1 : Test.T //│ ╙── ^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/UndefMatching.mls b/shared/src/test/diff/nu/UndefMatching.mls index e0e363c382..131a49bf97 100644 --- a/shared/src/test/diff/nu/UndefMatching.mls +++ b/shared/src/test/diff/nu/UndefMatching.mls @@ -21,6 +21,7 @@ class Abstract[A] { fun baz(a: A & Object) = [bar0(a), bar1(a), bar2(a)] } //│ class Abstract[A] { +//│ constructor() //│ fun bar0: (x: Object & A | undefined) -> (Object & A & ~undefined) //│ fun bar1: (x: Object & A | undefined) -> (Object & A & ~undefined) //│ fun bar2: (x: Object & A | undefined) -> (Object & A & ~undefined | undefined) @@ -34,15 +35,16 @@ class Abstract[A] { if x is undefined then error else x } //│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.34: if x is undefined then error else x +//│ ║ l.35: if x is undefined then error else x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `A & ~undefined` is not an instance of type `Object` -//│ ║ l.33: fun bar(x: A & ~undefined | undefined) = +//│ ║ l.34: fun bar(x: A & ~undefined | undefined) = //│ ║ ^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `Object` -//│ ║ l.34: if x is undefined then error else x +//│ ║ l.35: if x is undefined then error else x //│ ╙── ^ //│ class Abstract[A] { +//│ constructor() //│ fun bar: (x: undefined | A & ~undefined) -> (A & ~undefined) //│ } diff --git a/shared/src/test/diff/nu/Uninstantiable.mls b/shared/src/test/diff/nu/Uninstantiable.mls index a9a683fab7..0ea6cfac1d 100644 --- a/shared/src/test/diff/nu/Uninstantiable.mls +++ b/shared/src/test/diff/nu/Uninstantiable.mls @@ -6,25 +6,34 @@ Int //│ ╔══[ERROR] Class Int is abstract and cannot be instantiated //│ ║ l.5: Int //│ ╙── ^^^ -//│ () -> Int +//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no such constructor +//│ ║ l.5: Int +//│ ╙── ^^^ +//│ error //│ Code generation encountered an error: //│ unresolved symbol Int :e Int() //│ ╔══[ERROR] Class Int is abstract and cannot be instantiated -//│ ║ l.14: Int() +//│ ║ l.17: Int() +//│ ╙── ^^^ +//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no such constructor +//│ ║ l.17: Int() //│ ╙── ^^^ -//│ Int +//│ error //│ Code generation encountered an error: //│ unresolved symbol Int :e new Int //│ ╔══[ERROR] Class Int is abstract and cannot be instantiated -//│ ║ l.23: new Int -//│ ╙── ^^^ -//│ Int +//│ ║ l.29: new Int +//│ ╙── ^^^^^^^ +//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no such constructor +//│ ║ l.29: new Int +//│ ╙── ^^^^^^^ +//│ error //│ Code generation encountered an error: //│ unresolved symbol Int diff --git a/shared/src/test/diff/ucs/LitUCS.mls b/shared/src/test/diff/ucs/LitUCS.mls index 095d00af4c..6c77687f0f 100644 --- a/shared/src/test/diff/ucs/LitUCS.mls +++ b/shared/src/test/diff/ucs/LitUCS.mls @@ -16,6 +16,9 @@ fun test(x: 0 | A) = if x === 0 then 0 x is A then A +//│ ╔══[ERROR] Module 'A' does not support equality comparison because it does not have a parameter list +//│ ║ l.17: x === 0 then 0 +//│ ╙── ^^^^^^^ //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.18: x is A then A //│ ║ ^^^^^^^^^^^^^ @@ -39,22 +42,26 @@ fun test2(x) = :e test2(0) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.40: test2(0) +//│ ║ l.43: test2(0) //│ ║ ^^^^^^^^ //│ ╟── integer literal of type `0` is not an instance of type `A` -//│ ║ l.40: test2(0) +//│ ║ l.43: test2(0) //│ ║ ^ //│ ╟── Note: constraint arises from class pattern: -//│ ║ l.36: x is A then A +//│ ║ l.39: x is A then A //│ ║ ^ //│ ╟── from reference: -//│ ║ l.36: x is A then A +//│ ║ l.39: x is A then A //│ ╙── ^ //│ 0 | A | error //│ res //│ = 0 +:e test2(A) -//│ 0 | A +//│ ╔══[ERROR] Module 'A' does not support equality comparison because it does not have a parameter list +//│ ║ l.61: test2(A) +//│ ╙── ^^^^^^^^ +//│ 0 | A | error //│ res //│ = A { class: [class A] } From 3f4fab347b5ed8c0c74c551648cb471b2d5a5c0c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 20 Sep 2023 00:44:05 +0800 Subject: [PATCH 446/498] Fix typing of non-val parameters and handling of abstract vals --- .../scala/mlscript/ConstraintSolver.scala | 25 +- .../src/main/scala/mlscript/JSBackend.scala | 2 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 252 ++++++++++++------ .../main/scala/mlscript/TypeSimplifier.scala | 74 ++--- shared/src/main/scala/mlscript/Typer.scala | 4 +- .../main/scala/mlscript/TyperHelpers.scala | 6 +- shared/src/main/scala/mlscript/helpers.scala | 4 +- .../scala/mlscript/utils/shorthands.scala | 2 + .../src/test/diff/codegen/FieldOverride.mls | 2 +- shared/src/test/diff/codegen/Mixin.mls | 4 +- shared/src/test/diff/codegen/Nested.mls | 46 ++-- shared/src/test/diff/codegen/NewMatching.mls | 2 +- shared/src/test/diff/codegen/ValLet.mls | 16 +- shared/src/test/diff/gadt/Exp1.mls | 2 +- shared/src/test/diff/gadt/Exp2.mls | 10 +- shared/src/test/diff/mlscript/Repro.mls | 3 + shared/src/test/diff/nu/AbstractClasses.mls | 11 +- shared/src/test/diff/nu/BadClassInherit.mls | 89 ++++--- shared/src/test/diff/nu/BadClasses.mls | 46 ++-- shared/src/test/diff/nu/BadMixins.mls | 1 + shared/src/test/diff/nu/BadSignatures.mls | 2 +- .../test/diff/nu/BasicClassInheritance.mls | 18 +- shared/src/test/diff/nu/BasicClasses.mls | 2 +- shared/src/test/diff/nu/BasicMixins.mls | 10 +- .../src/test/diff/nu/ClassInstantiation.mls | 61 +++++ shared/src/test/diff/nu/ClassesInMixins.mls | 2 +- shared/src/test/diff/nu/Declarations.mls | 9 +- shared/src/test/diff/nu/EqlClasses.mls | 36 ++- .../test/diff/nu/ExpressionProblem_repro.mls | 2 +- shared/src/test/diff/nu/FieldRefinement.mls | 2 +- .../test/diff/nu/GenericClassInheritance.mls | 21 +- shared/src/test/diff/nu/GenericClasses.mls | 2 +- shared/src/test/diff/nu/GenericMethods.mls | 4 +- shared/src/test/diff/nu/GenericModules.mls | 6 +- .../diff/nu/InferredInheritanceTypeArgs.mls | 62 +++-- .../diff/nu/InheritanceLevelMismatches.mls | 2 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 2 +- shared/src/test/diff/nu/InterfaceMono.mls | 6 +- shared/src/test/diff/nu/Interfaces.mls | 127 +++++---- shared/src/test/diff/nu/LocalLets.mls | 2 +- .../src/test/diff/nu/MemberIntersections.mls | 30 +-- shared/src/test/diff/nu/MethodSignatures.mls | 2 +- shared/src/test/diff/nu/MixinParameters.mls | 15 +- shared/src/test/diff/nu/MutualRec.mls | 2 +- shared/src/test/diff/nu/NestedClasses.mls | 6 +- shared/src/test/diff/nu/NoThisCtor.mls | 2 +- shared/src/test/diff/nu/ParamImplementing.mls | 51 +++- shared/src/test/diff/nu/ParamPassing.mls | 222 +++++++++++++++ .../test/diff/nu/RawUnionTraitSignatures.mls | 2 +- shared/src/test/diff/nu/Refinements.mls | 2 +- shared/src/test/diff/nu/SelfRec.mls | 94 ++++++- shared/src/test/diff/nu/SimpleTraitImpl.mls | 4 +- shared/src/test/diff/nu/TODO_Classes.mls | 162 ++--------- shared/src/test/diff/nu/Unapply.mls | 108 ++++++++ shared/src/test/diff/nu/ValSigs.mls | 30 ++- shared/src/test/diff/nu/Virtual.mls | 6 +- shared/src/test/diff/nu/repro0.mls | 2 +- shared/src/test/diff/nu/repro1.mls | 2 +- shared/src/test/diff/ucs/JSON.mls | 4 +- 59 files changed, 1136 insertions(+), 589 deletions(-) create mode 100644 shared/src/test/diff/nu/ClassInstantiation.mls create mode 100644 shared/src/test/diff/nu/Unapply.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 215d482046..4a4913390e 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -55,10 +55,16 @@ class ConstraintSolver extends NormalForms { self: Typer => /** Note: `mkType` is just for reporting errors. */ - def lookupField(mkType: () => ST, clsNme: Opt[Str], rfnt: Var => Opt[FieldType], tags: SortedSet[AbstractTag], fld: Var) + def lookupField(mkType: () => ST, clsNme: Opt[Str], rfnt: Var => Opt[FieldType], + tags: SortedSet[AbstractTag], _fld: Var) (implicit ctx: Ctx, raise: Raise) : FieldType - = trace(s"Looking up field ${fld.name} in $clsNme & ${tags} & {...}") { + = trace(s"Looking up field ${_fld.name} in $clsNme & ${tags} & {...}") { + + // * Field selections with field names starting with `#` are a typer hack to access private members. + val (fld, allowPrivateAccess) = + if (_fld.name.startsWith("#")) (Var(_fld.name.tail).withLocOf(_fld), true) + else (_fld, false) val fromRft = rfnt(fld) @@ -69,7 +75,10 @@ class ConstraintSolver extends NormalForms { self: Typer => // * The raw type of this member, with original references to the class' type variables/type parameters val raw = (if (info.isComputed) N else info.typedFields.get(fld)) match { - case S(fty) => S(fty) + case S(fty) => + if (info.privateParams.contains(fld) && !allowPrivateAccess) + err(msg"Parameter '${fld.name}' cannot tbe accessed as a field" -> fld.toLoc :: Nil) + S(fty) case N if info.isComputing => @@ -86,9 +95,13 @@ class ConstraintSolver extends NormalForms { self: Typer => case S(d: TypedNuFun) => S(d.typeSignature.toUpper(provTODO)) case S(p: NuParam) => + if (!allowPrivateAccess && !p.isPublic) + err(msg"Parameter '${p.nme.name}' cannot tbe accessed as a field" -> fld.toLoc :: + msg"Either make the parameter a `val` or access it through destructuring" -> p.nme.toLoc :: + Nil) S(p.ty) case S(m) => - S(err(msg"access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) + S(err(msg"Access to ${m.kind.str} member not yet supported", fld.toLoc).toUpper(noProv)) case N => N } @@ -570,8 +583,8 @@ class ConstraintSolver extends NormalForms { self: Typer => annoying(Nil, lr, Nil, RhsBases(Nil, S(R(rf)), SortedMap.empty)) case (LhsRefined(N, ts, r, _), RhsBases(ots, S(R(RhsField(fldNme, fldTy))), trs)) if newDefs => val fty = lookupField(() => done_ls.toType(sort = true), N, r.fields.toMap.get, ts, fldNme) - rec(fty.ub, fldTy.ub, false) - recLb(fldTy, fty) + rec(fty.ub, fldTy.ub, false) + recLb(fldTy, fty) case (LhsRefined(bo, ts, r, _), RhsBases(ots, S(R(RhsField(n, t2))), trs)) => // TODO simplify - merge with above? r.fields.find(_._1 === n) match { diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 1c74bf0774..89a7ed34b1 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -833,7 +833,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { val ins = unapplyScope.declareParameter(nme) JSClassMethod("unapply", JSNamePattern(ins) :: Nil, L(JSArray(fields.map { case _ -> Fld(_, trm) => trm match { - case Sel(Var(ins), Var(f)) => JSIdent(s"$ins.#$f") + case Sel(Var(ins), Var(f)) => JSIdent(s"$ins.$f") case _ => translateTerm(trm) } }))) :: Nil diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8c9e3d6569..515d491c07 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -28,6 +28,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def toLoc: Opt[Loc] def level: Level def isImplemented: Bool + def isPublic: Bool def isValueParam: Bool = this match { case p: NuParam => !p.isType @@ -37,7 +38,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => protected def withLevel[R](k: Ctx => R)(implicit ctx: Ctx): R = k(ctx.copy(lvl = ctx.lvl + 1)) def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + (implicit ctx: Ctx, freshened: MutMap[TV, ST]) : NuMember def map(f: ST => ST)(implicit ctx: Ctx): NuMember = @@ -54,7 +55,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } - case class NuParam(nme: NameRef, ty: FieldType)(val level: Level) extends NuMember with TypedNuTermDef { + case class NuParam(nme: NameRef, ty: FieldType, isPublic: Bool)(val level: Level) + extends NuMember with TypedNuTermDef + { def name: Str = nme.name def isType: Bool = nme.isInstanceOf[TypeName] def kind: DeclKind = @@ -62,19 +65,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => else Val def toLoc: Opt[Loc] = nme.toLoc def isImplemented: Bool = true + def isVirtual: Bool = false // TODO allow annotating parameters with `virtual` def typeSignature: ST = ty.ub def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + (implicit ctx: Ctx, freshened: MutMap[TV, ST]) : NuParam = - NuParam(nme, ty.freshenAbove(lim, rigidify))(ctx.lvl) + NuParam(nme, ty.freshenAbove(lim, rigidify), isPublic)(ctx.lvl) def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): NuParam = - NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)))(level) + NuParam(nme, ty.update(t => f(pol.map(!_), t), t => f(pol, t)), isPublic)(level) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): NuParam = - NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)))(level) + NuParam(nme, ty.update(t => f(pol.contravar, t), t => f(pol, t)), isPublic)(level) } @@ -119,9 +123,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: mlscript.TypeName = td.nme def members: Map[Str, NuMember] = Map.empty def isImplemented: Bool = td.sig.isDefined + def isPublic = true // TODO def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + (implicit ctx: Ctx, freshened: MutMap[TV,ST]) : TypedNuAls = { val outer = ctx; withLevel { implicit ctx => TypedNuAls(outer.lvl, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), @@ -164,14 +169,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name def isImplemented: Bool = true + def isPublic = true // TODO lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO), isPublic = true)(level) } ++ parentTP def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + (implicit ctx: Ctx, freshened: MutMap[TV,ST]) : TypedNuTrt = { val outer = ctx; withLevel { implicit ctx => TypedNuTrt(outer.lvl, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), @@ -224,10 +230,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name def isImplemented: Bool = true - - /** Those parameters that are used in `new` and `extends` clauses. */ - lazy val effectiveParams: Params = - auxCtorParams.map(_.mapValues(_.toUpper(noProv))).orElse(params).getOrElse(Nil) + def isPublic = true // TODO /** The type of a palin term reference to this type definition. */ def typeSignature(usesNew: Bool, loco: Opt[Loc])(implicit raise: Raise): ST = @@ -236,7 +239,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => /** Includes class-name-coded type parameter fields. */ lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO), isPublic = true)(level) } ++ parentTP // TODO @@ -289,7 +292,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => variances.getOrElse(tv, VarianceInfo.in) def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + (implicit ctx: Ctx, freshened: MutMap[TV,ST]) : TypedNuCls = { val outer = ctx; withLevel { implicit ctx => TypedNuCls(outer.lvl, td, tparams.map(tp => (tp._1, tp._2.freshenAbove(lim, rigidify).assertTV, tp._3)), @@ -336,7 +339,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case class TypedNuMxn( level: Level, td: NuTypeDef, thisTy: ST, superTy: ST, - tparams: TyParams, params: Ls[Var -> FieldType], + tparams: TyParams, + params: Ls[Var -> FieldType], members: Map[Str, NuMember], ) extends TypedNuTypeDef(Mxn) with PolyNuDecl { @@ -345,14 +349,15 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def nme: TypeName = td.nme def name: Str = nme.name def isImplemented: Bool = true + def isPublic = true // TODO lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => - td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO))(level) + td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO), isPublic = false)(level) } def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV,ST]) + (implicit ctx: Ctx, freshened: MutMap[TV,ST]) : TypedNuMxn = { val outer = ctx; withLevel { implicit ctx => TypedNuMxn(outer.lvl, td, thisTy.freshenAbove(lim, rigidify), @@ -387,9 +392,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def toLoc: Opt[Loc] = N def name: Str = d.name def isImplemented: Bool = true + def isPublic = true // TODO def typeSignature: ST = errType def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) = + (implicit ctx: Ctx, freshened: MutMap[TV, ST]) = this def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuTermDef = @@ -413,10 +419,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def kind: DeclKind = Val def name: Str = fd.nme.name def toLoc: Opt[Loc] = fd.toLoc + def isPublic = true // TODO lazy val typeSignature: ST = PolymorphicType.mk(level, bodyType) def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + (implicit ctx: Ctx, freshened: MutMap[TV, ST]) : TypedNuFun = { val outer = ctx; withLevel { implicit ctx => this match { case TypedNuFun(level, fd, ty) => TypedNuFun(outer.lvl, fd, ty.freshenAbove(lim, rigidify))(isImplemented) @@ -447,7 +454,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit ctx: Ctx): TypedTypingUnit = TypedTypingUnit(implementedMembers.map(_.mapPolMap(pol)(f)), result.map(f(pol, _))) def freshenAbove(lim: Int, rigidify: Bool) - (implicit ctx: Ctx, shadows: Shadows, freshened: MutMap[TV, ST]) + (implicit ctx: Ctx, freshened: MutMap[TV, ST]) : TypedTypingUnit = TypedTypingUnit(implementedMembers.map(_.freshenAbove(lim, rigidify)), result.map(_.freshenAbove(lim, rigidify))) override def toString: Str = s"TypedTypingUnit(${(implementedMembers :+ result).lnIndent()})" @@ -540,7 +547,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } val funSigs = MutMap.empty[Str, NuFunDef] val implems = decls.filter { - case fd @ NuFunDef(N, nme, snme, tparams, R(rhs)) => + case fd @ NuFunDef(_, nme, snme, tparams, R(rhs)) => funSigs.updateWith(nme.name) { case S(s) => err(s"A type signature for '$nme' was already given", fd.toLoc) @@ -725,7 +732,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (fr, ptp) = refreshHelper(rawMxn, v, if (parTargs.isEmpty) N else S(parTargs)) // type args inferred val mxn = { implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty implicit val ctx: Ctx = outerCtx rawMxn.freshenAbove(info.level, rigidify = false) } @@ -736,19 +742,25 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"mixin $parNme expects ${ mxn.params.size.toString} parameter(s); got ${parArgs.size.toString}", Loc(v :: parArgs.unzip._2)) - val paramMems = mxn.params.lazyZip(parArgs).map { - case (nme -> p, _ -> Fld(_, a)) => // TODO check name, mut, spec + val paramMems = mxn.params.lazyZip(parArgs).flatMap { + case (nme -> p, _ -> Fld(FldFlags(mut, spec, get), a)) => // TODO factor this with code for classes: + assert(!mut && !spec && !get, "TODO") // TODO check mut, spec, get implicit val genLambdas: GenLambdas = true val a_ty = typeTerm(a) p.lb.foreach(constrain(_, a_ty)) constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + val isPublic = mxn.members(nme.name).isPublic + val fty = if (p.lb.isDefined) + // * We don't refine the field type when it's mutable as that could lead to muable updates being rejected + FieldType(p.lb, p.ub)(provTODO) + else FieldType(p.lb, a_ty)(provTODO) + Option.when(isPublic)(NuParam(nme, fty, isPublic = isPublic)(lvl)) } paramMems //++ mxn.members.valuesIterator } - println(s"Members $argMembs") + println(s"Mixin arg members $argMembs") S((mxn, argMembs, Map.empty[Str, NuMember], // TODO add ptp here once we support explicit type args @@ -761,7 +773,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (fr, ptp) = refreshHelper(rawTrt, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided val trt = { implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty implicit val ctx: Ctx = outerCtx rawTrt.freshenAbove(info.level, rigidify = false) } @@ -777,30 +788,55 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val (fr, ptp) = refreshHelper(rawCls, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided val cls = { implicit val frenshened: MutMap[TV,ST] = fr - implicit val shadows: Shadows = Shadows.empty implicit val ctx: Ctx = outerCtx rawCls.freshenAbove(info.level, rigidify = false) } // println(s"Fresh[${ctx.lvl}] $cls") - if (parArgs.sizeCompare(cls.effectiveParams) =/= 0) - err(msg"class $parNme expects ${ - cls.effectiveParams.size.toString} parameter(s); got ${parArgs.size.toString - }", Loc(v :: parArgs.unzip._2)) + def checkArgsNum(effectiveParamSize: Int) = + if (parArgs.sizeCompare(effectiveParamSize) =/= 0) + err(msg"class $parNme expects ${ + effectiveParamSize.toString} parameter(s); got ${parArgs.size.toString + }", Loc(v :: parArgs.unzip._2)) - // * TODO don't pick up non-vals as public members - val paramMems = cls.effectiveParams.lazyZip(parArgs).map { - case (nme -> p, _ -> Fld(FldFlags(mut, spec, get), a)) => - assert(!mut && !spec, "TODO") // TODO check name, mut, spec - implicit val genLambdas: GenLambdas = true - val a_ty = typeTerm(a) - p.lb.foreach(constrain(_, a_ty)) - constrain(a_ty, p.ub) - NuParam(nme, FieldType(p.lb, a_ty)(provTODO))(lvl) + val argMembs = { + implicit val genLambdas: GenLambdas = true + cls.auxCtorParams match { + case S(ps) => + checkArgsNum(ps.size) + ps.lazyZip(parArgs).map { + case (nme -> p_ty, _ -> Fld(FldFlags(mut, spec, get), a)) => + assert(!mut && !spec && !get, "TODO") // TODO check mut, spec, get + val a_ty = typeTerm(a) + constrain(a_ty, p_ty) + } + Nil + case N => cls.params match { + case S(ps) => + checkArgsNum(ps.size) + ps.lazyZip(parArgs).flatMap { + case (nme -> p, _ -> Fld(FldFlags(mut, spec, get), a)) => + assert(!mut && !spec && !get, "TODO") // TODO check mut, spec, get + val a_ty = typeTerm(a) + p.lb.foreach(constrain(_, a_ty)) + constrain(a_ty, p.ub) + val isPublic = cls.members(nme.name).isPublic + val fty = if (p.lb.isDefined) + // * We don't refine the field type when it's mutable as that could lead to muable updates being rejected + FieldType(p.lb, p.ub)(provTODO) + else FieldType(p.lb, a_ty)(provTODO) + Option.when(isPublic)(NuParam(nme, fty, isPublic = isPublic)(lvl)) + } + case N => + checkArgsNum(0) + Nil + } + } } + println(s"Class arg members $argMembs") - S((cls, paramMems, ptp ++ cls.parentTP, p.toLoc)) + S((cls, argMembs, ptp ++ cls.parentTP, p.toLoc)) case als: TypedNuAls => // TODO dealias first? @@ -832,7 +868,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case Nil => tags case (p, Var(nm), lti, _, _) :: ps => lti match { case lti: DelayedTypeInfo => lti.kind match { - case Trt | Cls | Mod => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) + case Trt | Cls | Mod => lookupTags(ps, Set.single(TypeName(nm)) union lti.inheritedTags union tags) case Val | Mxn | Als => lookupTags(ps, tags) } case CompletedTypeInfo(trt: TypedNuTrt) => @@ -845,7 +881,13 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } } - lazy val inheritedTags = lookupTags(parentSpecs, Set.empty) + private var inheritedTagsStartedComputing = false + lazy val inheritedTags: Set[TypeName] = + if (inheritedTagsStartedComputing) Set.empty // * Deals with malformed inheritances (cycles) + else { + inheritedTagsStartedComputing = true + lookupTags(parentSpecs, Set.empty) + } lazy val tparams: TyParams = ctx.nest.nextLevel { implicit ctx => decl match { @@ -944,6 +986,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => Set.empty}).toSet case _: NuFunDef => Set.empty } + lazy val privateParams: Set[Var] = decl match { + case td: NuTypeDef => + // td.params.dlof(_.fields)(Nil).iterator.collect { + // case (S(nme), Fld(flags, _)) if !flags.genGetter => nme + // case (N, Fld(flags, nme: Var)) if !flags.genGetter => nme + // // case (N, Fld(flags, _)) => die + // }.toSet + td.params.dlof(_.fields)(Nil).iterator.flatMap { + case (S(nme), Fld(flags, _)) => Option.when(!flags.genGetter)(nme) + case (N, Fld(flags, nme: Var)) => Option.when(!flags.genGetter)(nme) + case (N, Fld(flags, _)) => die + }.toSet + case _: NuFunDef => Set.empty + } lazy val allFields: Set[Var] = decl match { case td: NuTypeDef => @@ -953,12 +1009,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _: NuFunDef => Set.empty } - // * TODO don't pick up non-vals as public members - lazy val typedFields: Map[Var, FieldType] = + lazy val typedFields: Map[Var, FieldType] = {println(("privateFields"),privateParams) (typedParams.getOrElse(Nil).toMap + // -- privateFields -- inheritedFields /* parameters can be overridden by inherited fields/methods */ ) ++ typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) - + } lazy val mutRecTV: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), N, @@ -1146,7 +1202,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => implemsMap.get(m.name) match { case S(_) => case N => - err(msg"Member `${m.name}` is declared in parent but not implemented in `${ + err(msg"Member `${m.name}` is declared (or its declaration is inherited) but is not implemented in `${ td.nme.name}`" -> td.nme.toLoc :: msg"Declared here:" -> m.toLoc :: Nil) @@ -1169,16 +1225,24 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } newMembers.foreach { m => - println(s"Checking overriding for `${m.name}`...") + println(s"Checking overriding for ${m} against ${sigMap.get(m.name)}...") (m, sigMap.get(m.name)) match { case (_, N) => case (m: TypedNuTermDef, S(fun: TypedNuTermDef)) => fun match { - // If the implementation and the declaration are in the same class, it does not require to be virtual + // * If the implementation and the declaration are in the same class, + // * it does not require to be virtual. case td: TypedNuFun if (!td.fd.isVirtual && !clsSigns.contains(fun)) => - err(msg"${m.kind.str.capitalize} member `${m.name}` is not virtual and cannot be overridden" -> m.toLoc :: - msg"Declared here:" -> fun.toLoc :: + err(msg"${m.kind.str.capitalize} member `${m.name + }` is not virtual and cannot be overridden" -> m.toLoc :: + msg"Originally declared here:" -> fun.toLoc :: + Nil) + case p: NuParam if (!p.isVirtual && !clsSigns.contains(p)) => + err(msg"Inherited parameter named `${m.name + }` is not virtual and cannot be overridden" -> m.toLoc :: + msg"Originally declared here:" -> fun.toLoc :: Nil) case _ => + // println(s"?! $fun") val mSign = m.typeSignature implicit val prov: TP = mSign.prov constrain(mSign, fun.typeSignature) @@ -1186,7 +1250,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (_, S(that)) => err(msg"${m.kind.str.capitalize} member `${m.name}` cannot override ${ that.kind.str} member of the same name declared in parent" -> td.toLoc :: - msg"Declared here:" -> that.toLoc :: + msg"Originally declared here:" -> that.toLoc :: Nil) } } @@ -1207,7 +1271,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => }, a.fd.nme, N/*no sym name?*/, a.fd.tparams, a.fd.rhs)(a.fd.declareLoc, a.fd.virtualLoc, N, a.fd.outer orElse b.fd.outer, a.fd.genField) S(TypedNuFun(a.level, fd, a.bodyType & b.bodyType)(a.isImplemented || b.isImplemented)) case (a: NuParam, S(b: NuParam)) => - S(NuParam(a.nme, a.ty && b.ty)(a.level)) + if (!a.isPublic) S(b) else if (!b.isPublic) S(a) + else S(NuParam(a.nme, a.ty && b.ty, isPublic = true)(a.level)) case (a: NuParam, S(b: TypedNuFun)) => S(TypedNuFun(a.level, b.fd, a.ty.ub & b.bodyType)(a.isImplemented || b.isImplemented)) case (a: TypedNuFun, S(b: NuParam)) => @@ -1243,7 +1308,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val ty = typeType(td.sig.getOrElse(Top)) // * Make these type vars skolems implicit val freshened: MutMap[TV, ST] = MutMap.empty - implicit val shadows: Shadows = Shadows.empty ty.freshenAbove(outer.lvl, rigidify = true) } // * Create a lower-levl type variable to extrude the type through it, @@ -1363,7 +1427,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi val fldNme = td.nme.name + "#" + tp.name - NuParam(TypeName(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov))(lvl) + NuParam(TypeName(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isPublic = true)(lvl) } val tparamFields = tparamMems.map(p => p.nme.toVar -> p.ty) assert(!typedParams.exists(_.keys.exists(tparamFields.keys.toSet)), ???) @@ -1378,8 +1442,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ) def inherit(parents: Ls[TypedParentSpec], pack: Pack): Pack = parents match { - case (p, argMembs, tpms, loc) :: ps => p match { - + case (p, argMembs, tpms, loc) :: ps => println(s"=> Inheriting from $p"); p match { case mxn: TypedNuMxn => @@ -1423,18 +1486,28 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => traitMembers = membersInter(pack.traitMembers, trt.members.valuesIterator.filterNot(_.isValueParam).toList), tparamMembers = pack.tparamMembers ++ tpms )) - + case cls: TypedNuCls => val parNme = cls.nme.name pack.baseClsNme.foreach { cls => - err(msg"cannot inherit from more than one base class: ${ + err(msg"Cannot inherit from more than one base class: ${ cls} and ${parNme}", loc) } + val (baseParamMems, otherBaseMems) = + // cls.members.toList.partition(_._2.isValueParam) + cls.members.valuesIterator.toList.partition(_.isValueParam) + + println(s"argMembs $argMembs") + inherit(ps, pack.copy( baseClsNme = S(parNme), - baseClsMembers = argMembs ++ cls.members.valuesIterator.filterNot(_.isValueParam), + // baseClsMembers = argMembs ++ cls.members.valuesIterator.filterNot(_.isValueParam), + // baseClsMembers = argMembs.filterNot(_.isPrivate) ++ cls.members.valuesIterator.filterNot(_.isValueParam), + // baseClsMembers = cls.members.valuesIterator.filter(_.isValueParam) ++ argMembs ++ cls.members.valuesIterator.filterNot(_.isValueParam), + // baseClsMembers = baseParamMems ::: argMembs ::: otherBaseMems, + baseClsMembers = argMembs ++ cls.members.valuesIterator, tparamMembers = pack.tparamMembers ++ tpms )) @@ -1443,6 +1516,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } case Nil => + println(s"Done inheriting: $pack") + val thisType = WithType(pack.superType, RecordType(typedParams.getOrElse(Nil))(ttp(td.params.getOrElse(Tup(Nil)), isType = true)) )(provTODO) & @@ -1463,7 +1538,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val baseType = RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) - val paramMems = typedParams.getOrElse(Nil).map(f => NuParam(f._1, f._2)(lvl)) + println("PPP",privateParams) + + val paramMems = typedParams.getOrElse(Nil).map(f => + NuParam(f._1, f._2, isPublic = !privateParams.contains(f._1))(lvl)) val Pack(thisType, mxnMembers, _, baseClsMembers, traitMembers, tparamMembers) = inherit(typedParents, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) @@ -1472,21 +1550,33 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx += "super" -> VarSymbol(thisType, Var("super")) val ttu = typeTypingUnit(td.body, S(td)) + // * `baseClsImplemMembers` actually also includes parameter members and their arg-based refinements val (baseClsImplemMembers, baseClsIfaceMembers) = baseClsMembers.partition(_.isImplemented) + println(s"baseClsImplemMembers ${baseClsImplemMembers}") + val newImplems = ttu.implementedMembers + val clsSigns = typedSignatureMembers.map(_._2) + + trace(s"Checking `this` accesses...") { + val toCheckImplems = newImplems.filter(_.isImplemented) + qualificationCheck(toCheckImplems, td.body.entities.filter { + case _: NuDecl => false + case _ => true + }, baseClsMembers, clsSigns) + }() + // * Those member implementations we inherit from the base class that are not overridden val implemsInheritedFromBaseCls = { val possiblyOverridingNames = (newImplems.iterator ++ mxnMembers).map(_.name).toSet - baseClsImplemMembers.iterator + baseClsImplemMembers.iterator.distinctBy(_.name) .filterNot(possiblyOverridingNames contains _.name) .toList } // * ... must type check against the trait signatures - trace(s"Checking base class implementations...") { - println(implemsInheritedFromBaseCls, newImplems) + trace(s"Checking base class implementations against inherited signatures...") { overrideCheck(implemsInheritedFromBaseCls, traitMembers, Nil) }() @@ -1494,22 +1584,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * (but we already know the base class implems satisfy the baseClsMembers signatures) val ifaceMembers = membersInter(baseClsMembers, traitMembers) - val clsSigns = typedSignatureMembers.map(_._2) - // * We now check current and non-overridden mixin implementations against // * the signatures from the base class and traits val toCheck = (newImplems.iterator ++ mxnMembers).distinctBy(_.name).toList - - trace(s"Checking qualifications...") { - val toCheckImplems = newImplems.filter(_.isImplemented) - qualificationCheck(toCheckImplems, td.body.entities.filter { - case _: NuDecl => false - case _ => true - }, baseClsMembers, clsSigns) - }() - - trace(s"Checking new implementations...") { + + trace(s"Checking new implementations against inherited signatures...") { overrideCheck(toCheck, (clsSigns.iterator ++ ifaceMembers).distinctBy(_.name).toList, clsSigns) }() @@ -1520,7 +1600,9 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ++ baseClsImplemMembers ).distinctBy(_.name) - overrideCheck(clsSigns, ifaceMembers, clsSigns) + trace(s"Checking new signatures against inherited signatures...") { + overrideCheck(clsSigns, ifaceMembers, clsSigns) + }() implemCheck(impltdMems, (clsSigns.iterator ++ ifaceMembers.iterator) @@ -1529,6 +1611,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val allMembers = (ifaceMembers ++ impltdMems).map(d => d.name -> d).toMap ++ typedSignatureMembers + println(s"allMembers $allMembers") + val auxCtorParams = td.ctor match { case S(ctor @ Constructor(ps, bod)) => outerCtx.nest.nextLevel { implicit ctx => def getterError(loco: Opt[Loc]) = @@ -1606,10 +1690,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) - - // * It seems this was unused for now: - // val paramMems = typedParams.map(_.map(f => NuParam(f._1, f._2)(lvl))) - + val paramMems = typedParams.map(_.map(f => + f._1.name -> NuParam(f._1, f._2, !privateParams.contains(f._1))(lvl))).getOrElse(Nil).toMap val thisTV = freshVar(provTODO, N, S("this")) val superTV = freshVar(provTODO, N, S("super")) ctx += "this" -> VarSymbol(thisTV, Var("this")) @@ -1619,7 +1701,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val signs = typedSignatureMembers.map(_._2) overrideCheck(impltdMems, signs, signs) implemCheck(impltdMems, signs) - val mems = impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers + val mems = paramMems ++ impltdMems.map(m => m.name -> m).toMap ++ typedSignatureMembers TypedNuMxn(outer.lvl, td, thisTV, superTV, tparams, typedParams.getOrElse(Nil), mems) } } @@ -1684,7 +1766,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => tv }) freshened += _tv -> tv - rawName+"#"+tn.name -> NuParam(tn, FieldType(S(tv), tv)(provTODO))(ctx.lvl) + rawName+"#"+tn.name -> NuParam(tn, FieldType(S(tv), tv)(provTODO), isPublic = true)(ctx.lvl) } freshened -> parTP.toMap diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 1881271c61..c4968cdf5c 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -99,44 +99,44 @@ trait TypeSimplifier { self: Typer => val prefix = fnme.takeWhile(_ =/= '#') val postfix = fnme.drop(prefix.length + 1) lazy val default = fty.update(process(_ , N), process(_ , N)) - if (postfix.isEmpty) v -> default :: Nil + if (postfix.isEmpty || prefix.isEmpty) v -> default :: Nil else ctx.tyDefs.get(prefix) match { - case S(td) => - td.tvarVariances.fold(v -> default :: Nil)(tvv => - tvv(td.tparamsargs.find(_._1.name === postfix).getOrElse(die)._2) match { - case VarianceInfo(true, true) => Nil - case VarianceInfo(co, contra) => - if (co) v -> FieldType(S(BotType), process(fty.ub, N))(fty.prov) :: Nil - else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil - else v -> default :: Nil - }) - case N => - // v -> default :: Nil - ctx.tyDefs2.get(prefix) match { - case S(info) => - info.result match { - case S(cls: TypedNuCls) => - cls.varianceOf(cls.tparams.find(_._1.name === postfix).getOrElse(die)._2) match { - case VarianceInfo(true, true) => Nil - case VarianceInfo(co, contra) => - if (co) v -> FieldType(S(BotType), process(fty.ub, N))(fty.prov) :: Nil - else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil - else v -> default :: Nil - } - case S(trt: TypedNuTrt) => // TODO factor w/ above & generalize - trt.tparams.iterator.find(_._1.name === postfix).flatMap(_._3).getOrElse(VarianceInfo.in) match { - case VarianceInfo(true, true) => Nil - case VarianceInfo(co, contra) => - if (co) v -> FieldType(S(BotType), process(fty.ub, N))(fty.prov) :: Nil - else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil - else v -> default :: Nil - } - case S(_) => ??? // TODO: - case N => - ??? // TODO use info.explicitVariances - } - case N => die - } + case S(td) => + td.tvarVariances.fold(v -> default :: Nil)(tvv => + tvv(td.tparamsargs.find(_._1.name === postfix).getOrElse(die)._2) match { + case VarianceInfo(true, true) => Nil + case VarianceInfo(co, contra) => + if (co) v -> FieldType(S(BotType), process(fty.ub, N))(fty.prov) :: Nil + else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil + else v -> default :: Nil + }) + case N => + // v -> default :: Nil + ctx.tyDefs2.get(prefix) match { + case S(info) => + info.result match { + case S(cls: TypedNuCls) => + cls.varianceOf(cls.tparams.find(_._1.name === postfix).getOrElse(die)._2) match { + case VarianceInfo(true, true) => Nil + case VarianceInfo(co, contra) => + if (co) v -> FieldType(S(BotType), process(fty.ub, N))(fty.prov) :: Nil + else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil + else v -> default :: Nil + } + case S(trt: TypedNuTrt) => // TODO factor w/ above & generalize + trt.tparams.iterator.find(_._1.name === postfix).flatMap(_._3).getOrElse(VarianceInfo.in) match { + case VarianceInfo(true, true) => Nil + case VarianceInfo(co, contra) => + if (co) v -> FieldType(S(BotType), process(fty.ub, N))(fty.prov) :: Nil + else if (contra) v -> FieldType(fty.lb.map(process(_, N)), TopType)(fty.prov) :: Nil + else v -> default :: Nil + } + case S(_) => ??? // TODO: + case N => + ??? // TODO use info.explicitVariances + } + case N => lastWords(s"'$prefix' not found") + } } })(ty.prov) diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 4d69e66577..eb30ae4f50 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -86,7 +86,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val res = k(newCtx) val ec = newCtx.extrCtx assert(constrainedTypes || newCtx.extrCtx.isEmpty) - trace(s"UNSTASHING... (out)") { + if (ec.nonEmpty) trace(s"UNSTASHING... (out)") { implicit val ctx: Ctx = this ec.foreach { case (tv, bs) => bs.foreach { case (true, b) => constrain(b, tv) @@ -116,7 +116,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne println(s"Inferred poly constr: $cty —— where ${cty.showBounds}") val cty_fresh = - // * Samnity check: uncommenting this should change nothing (modulo type simplification randomness) + // * Sanity check: uncommenting this should change nothing (modulo type simplification randomness) // cty.freshenAbove(lvl, false) cty diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index f20085d620..03286e9624 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -782,7 +782,7 @@ abstract class TyperHelpers { Typer: Typer => def childrenPolField(pol: PolMap)(fld: FieldType): List[PolMap -> SimpleType] = fld.lb.map(pol.contravar -> _).toList ::: pol.covar -> fld.ub :: Nil def childrenPolMem(m: NuMember): List[PolMap -> SimpleType] = m match { - case NuParam(nme, ty) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable + case NuParam(nme, ty, pub) => childrenPolField(PolMap.pos)(ty) // TODO invariant when mutable case TypedNuFun(level, fd, ty) => pol -> ty :: Nil case td: TypedNuDecl => TypedTypingUnit(td :: Nil, N).childrenPol(pol: PolMap) // TODO refactor // case NuTypeParam(nme, ty) => childrenPolField(PolMap.pos)(ty) @@ -922,7 +922,7 @@ abstract class TyperHelpers { Typer: Typer => } private def childrenMem(m: NuMember): List[ST] = m match { - case NuParam(nme, ty) => ty.lb.toList ::: ty.ub :: Nil + case NuParam(nme, ty, pub) => ty.lb.toList ::: ty.ub :: Nil case TypedNuFun(level, fd, ty) => ty :: Nil case TypedNuDummy(d) => Nil case _ => ??? // TODO @@ -1322,7 +1322,7 @@ abstract class TyperHelpers { Typer: Typer => members.valuesIterator.foreach(applyMem(pol)) apply(pol.contravar)(thisTy) apply(pol.contravar)(superTy) - case NuParam(nme, ty) => applyField(pol)(ty) + case NuParam(nme, ty, pub) => applyField(pol)(ty) case TypedNuFun(level, fd, ty) => apply(pol)(ty) case TypedNuDummy(d) => () // case NuTypeParam(nme, ty) => applyField(pol)(ty) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 361fce59db..d49f520a5c 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -455,8 +455,8 @@ trait NuDeclImpl extends Located { self: NuDecl => lazy val genUnapply: Opt[NuFunDef] = this match { case td: NuTypeDef if td.kind is Cls => td.params.map { tup => val ret = Let(false, Var("_"), Asc(Var("x"), TypeName(name)), Tup(tup.fields.map { - case S(p) -> f => N -> Fld(FldFlags.empty, Sel(Var("x"), p)) - case N -> Fld(flags, p: Var) => N -> Fld(FldFlags.empty, Sel(Var("x"), p)) + case S(p) -> f => N -> Fld(FldFlags.empty, Sel(Var("x"), Var("#" + p.name).withLocOf(p))) + case N -> Fld(flags, p: Var) => N -> Fld(FldFlags.empty, Sel(Var("x"), Var("#" + p.name).withLocOf(p))) case _ => die })) NuFunDef(N, Var("unapply"), N, Nil, L(Lam( diff --git a/shared/src/main/scala/mlscript/utils/shorthands.scala b/shared/src/main/scala/mlscript/utils/shorthands.scala index e84ddb954c..613bfe1a47 100644 --- a/shared/src/main/scala/mlscript/utils/shorthands.scala +++ b/shared/src/main/scala/mlscript/utils/shorthands.scala @@ -28,6 +28,8 @@ object shorthands { def some[A]: A => Option[A] = Some(_) def none[A]: Option[A] = None + def nil[A]: List[A] = Nil + type Paf[-A,+B] = PartialFunction[A,B] type Exc = Exception diff --git a/shared/src/test/diff/codegen/FieldOverride.mls b/shared/src/test/diff/codegen/FieldOverride.mls index 84d1dbb883..3935fc6084 100644 --- a/shared/src/test/diff/codegen/FieldOverride.mls +++ b/shared/src/test/diff/codegen/FieldOverride.mls @@ -128,7 +128,7 @@ let c3 = C3(1) let c4 = c3.C4(2) c3.a c4.a -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.128: let c4 = c3.C4(2) //│ ╙── ^^^ //│ let c3: C3 diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 6ea6050b69..94fb338661 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -498,8 +498,8 @@ TestLang.eval(mk(0)) class Foo(x: Int) //│ class Foo(x: Int) -class Bar(x: Int, y: Int) extends Foo(x + y) -//│ class Bar(x: Int, y: Int) extends Foo +class Bar(x2: Int, y: Int) extends Foo(x2 + y) +//│ class Bar(x2: Int, y: Int) extends Foo mixin AA(a: Int) { diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 5291381195..46dfc45ce9 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -69,7 +69,7 @@ module A { :js let bb = A.B(A.a) bb.b -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.70: let bb = A.B(A.a) //│ ╙── ^^ //│ let bb: error @@ -102,10 +102,10 @@ let c = b.C(1) c.outer1 let d = b.D(1) d.outer -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.101: let c = b.C(1) //│ ╙── ^^ -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.103: let d = b.D(1) //│ ╙── ^^ //│ class B(x: Int) { @@ -350,7 +350,7 @@ let es = E(1) let fff = es.F(2) let gg = fff.G(3) gg.sum -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.350: let fff = es.F(2) //│ ╙── ^^ //│ let es: E @@ -549,7 +549,7 @@ module G { let jj = G.H.J(42) let i = jj.ii(2) i.x -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] Access to module member not yet supported //│ ║ l.549: let jj = G.H.J(42) //│ ╙── ^^ //│ let jj: error @@ -657,7 +657,7 @@ module H { :js let j = H.J(42) j.i.x -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.658: let j = H.J(42) //│ ╙── ^^ //│ let j: error @@ -687,7 +687,7 @@ class I(x: Int) { let i = I(1) let ij = i.J(0) ij.incY -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.688: let ij = i.J(0) //│ ╙── ^^ //│ class I(x: Int) { @@ -776,13 +776,13 @@ module J { class K(x: Int) {} mixin L() {} class M() extends K(1) {} - class N(x: Int) extends K(x + 2), L + class N(x2: Int) extends K(x2 + 2), L } //│ module J { //│ class K(x: Int) //│ mixin L() //│ class M() extends K -//│ class N(x: Int) extends K +//│ class N(x2: Int) extends K //│ } //│ // Prelude //│ class TypingUnit14 { @@ -847,17 +847,17 @@ module J { //│ const qualifier1 = this; //│ if (this.#N === undefined) { //│ class N extends qualifier1.L(qualifier1.K.class) { -//│ #x; -//│ constructor(x) { -//│ super(x + 2); -//│ this.#x = x; +//│ #x2; +//│ constructor(x2) { +//│ super(x2 + 2); +//│ this.#x2 = x2; //│ } //│ static //│ unapply(x) { -//│ return [x.#x]; +//│ return [x.#x2]; //│ } //│ }; -//│ this.#N = ((x) => Object.freeze(new N(x))); +//│ this.#N = ((x2) => Object.freeze(new N(x2))); //│ this.#N.class = N; //│ this.#N.unapply = N.unapply; //│ } @@ -878,10 +878,10 @@ module J { :js let m = J.M() let n = J.N(2) -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.879: let m = J.M() //│ ╙── ^^ -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.880: let n = J.N(2) //│ ╙── ^^ //│ let m: error @@ -922,7 +922,7 @@ module K { :e let m = K.L.M() m.f -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] Access to module member not yet supported //│ ║ l.923: let m = K.L.M() //│ ╙── ^^ //│ let m: error @@ -952,7 +952,7 @@ module L { :e let op = L.N.O.P(0) op.x -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] Access to module member not yet supported //│ ║ l.953: let op = L.N.O.P(0) //│ ╙── ^^ //│ let op: error @@ -979,10 +979,10 @@ module M { _ then 2 } M.N.op(M.P()) -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] Access to module member not yet supported //│ ║ l.981: M.N.op(M.P()) //│ ╙── ^^ -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.981: M.N.op(M.P()) //│ ╙── ^^ //│ module M { @@ -1165,7 +1165,7 @@ module N { :e N.O.P() -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] Access to module member not yet supported //│ ║ l.1167: N.O.P() //│ ╙── ^^ //│ error @@ -1181,7 +1181,7 @@ class I(x: Int) { } } I(1).J(3).a -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.1183: I(1).J(3).a //│ ╙── ^^ //│ class I(x: Int) { diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index 34c1a6638c..a9654c3102 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -280,7 +280,7 @@ class C[A](f: A -> A) //│ class C[A](f: A -> A) let r = C.unapply -//│ let r: forall 'f. (C[?] & {f: 'f}) -> ['f] +//│ let r: forall '#f. (C[?] & {#f: '#f}) -> ['#f] //│ r //│ = [Function: unapply] diff --git a/shared/src/test/diff/codegen/ValLet.mls b/shared/src/test/diff/codegen/ValLet.mls index 0431446238..763fc577fc 100644 --- a/shared/src/test/diff/codegen/ValLet.mls +++ b/shared/src/test/diff/codegen/ValLet.mls @@ -164,9 +164,15 @@ class B(x: Int, val y: Int) //│ globalThis.B = typing_unit4.B; //│ // End of generated code -// FIXME: should be rejected +:e B(0, 0).x -//│ Int +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.168: B(0, 0).x +//│ ║ ^^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.130: class B(x: Int, val y: Int) +//│ ╙── ^ +//│ Int | error //│ res //│ = undefined @@ -181,7 +187,7 @@ class C { constructor(val x: Int, y: Int) } //│ ╔══[ERROR] Cannot use `val` in constructor parameters -//│ ║ l.181: constructor(val x: Int, y: Int) +//│ ║ l.187: constructor(val x: Int, y: Int) //│ ╙── ^ //│ class C { //│ constructor(x: Int, y: Int) @@ -214,14 +220,14 @@ class C { :e fun f(val x: Int) = x + 1 //│ ╔══[ERROR] Cannot use `val` in this position -//│ ║ l.215: fun f(val x: Int) = x + 1 +//│ ║ l.221: fun f(val x: Int) = x + 1 //│ ╙── ^^^^^^ //│ fun f: (x: Int) -> Int :e (val x: 1) //│ ╔══[ERROR] Cannot use `val` in this position -//│ ║ l.222: (val x: 1) +//│ ║ l.228: (val x: 1) //│ ╙── ^^^^ //│ [x: 1] //│ res diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 4e7d1a4d4d..6cd0cf1d6f 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -3,7 +3,7 @@ class Exp[A]: Pair | Lit class Lit(n: Int) extends Exp[Int] -class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +class Pair[L, R](val lhs: L, val rhs: R) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[anything, anything] { //│ constructor() //│ } diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index f174a8ec11..8fc5a1176a 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -2,8 +2,8 @@ class Exp[A]: Pair | Lit -class Lit(n: Int) extends Exp[Int] -class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +class Lit(val n: Int) extends Exp[Int] +class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] //│ class Exp[A]: Lit | Pair[?, ?] { //│ constructor() //│ } @@ -32,7 +32,7 @@ fun f(e) = if e is //│ ║ l.30: (e: Exp['X]) => f(e) //│ ║ ^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ //│ (e: Exp['X]) -> (Int | error | [Exp['L], Exp['R]]) //│ where @@ -56,7 +56,7 @@ fun f(e) = if e is //│ ║ l.50: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ //│ ╔══[ERROR] Type error in definition //│ ║ l.48: fun f(e) = if e is @@ -66,7 +66,7 @@ fun f(e) = if e is //│ ║ l.50: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `R` leaks out of its scope -//│ ║ l.6: class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp[(L, R)] +//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ //│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> Int //│ where diff --git a/shared/src/test/diff/mlscript/Repro.mls b/shared/src/test/diff/mlscript/Repro.mls index e69de29bb2..539c23787c 100644 --- a/shared/src/test/diff/mlscript/Repro.mls +++ b/shared/src/test/diff/mlscript/Repro.mls @@ -0,0 +1,3 @@ +:NewDefs + + diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index 9b060093b9..b8eb1aa4cb 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -62,7 +62,7 @@ abstract class Bar extends Foo(1) :e module Baz extends Bar Baz.f(1) -//│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `Baz` +//│ ╔══[ERROR] Member `f` is declared (or its declaration is inherited) but is not implemented in `Baz` //│ ║ l.63: module Baz extends Bar //│ ║ ^^^ //│ ╟── Declared here: @@ -101,7 +101,7 @@ trait T1 { fun x: Int | Bool } :e class C2 extends C1, T1 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C2` +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C2` //│ ║ l.103: class C2 extends C1, T1 //│ ║ ^^ //│ ╟── Declared here: @@ -125,7 +125,7 @@ abstract class C2 extends C1, T1 :e class C3 extends C2 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C3` +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C3` //│ ║ l.127: class C3 extends C2 //│ ║ ^^ //│ ╟── Declared here: @@ -163,7 +163,7 @@ abstract class C { //│ } :e -class C { +abstract class C { val x : Int fun foo0 = x fun foo1 = this.x @@ -174,8 +174,7 @@ class C { //│ ╟── Declared here: //│ ║ l.167: val x : Int //│ ╙── ^^^^^^^ -//│ class C { -//│ constructor() +//│ abstract class C { //│ fun foo0: Int //│ fun foo1: Int //│ let x: Int diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index 996450f0b4..ab3724c9c1 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -11,6 +11,12 @@ class C2(x: Int) extends C1(y) { //│ ╔══[ERROR] identifier not found: y //│ ║ l.8: class C2(x: Int) extends C1(y) { //│ ╙── ^ +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.8: class C2(x: Int) extends C1(y) { +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.4: class C1(x: Int) +//│ ╙── ^ //│ class C2(x: Int) extends C1 { //│ let y: Int //│ } @@ -18,28 +24,26 @@ class C2(x: Int) extends C1(y) { //│ unresolved symbol y :e -class C2 extends C1(y) { +abstract class C2 extends C1(y) { val y: Int } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.21: class C2 extends C1(y) { -//│ ╙── ^ -//│ class C2 extends C1 { -//│ constructor() +//│ ║ l.27: abstract class C2 extends C1(y) { +//│ ╙── ^ +//│ abstract class C2 extends C1 { //│ let y: Int //│ } //│ Code generation encountered an error: //│ unresolved symbol y :e -class C2 extends C1(this.y) { +abstract class C2 extends C1(this.y) { val y: Int } //│ ╔══[ERROR] identifier not found: this -//│ ║ l.35: class C2 extends C1(this.y) { -//│ ╙── ^^^^ -//│ class C2 extends C1 { -//│ constructor() +//│ ║ l.40: abstract class C2 extends C1(this.y) { +//│ ╙── ^^^^ +//│ abstract class C2 extends C1 { //│ let y: Int //│ } @@ -50,7 +54,7 @@ class C1(x: C1) :e class C2 extends C1(this) //│ ╔══[ERROR] identifier not found: this -//│ ║ l.51: class C2 extends C1(this) +//│ ║ l.55: class C2 extends C1(this) //│ ╙── ^^^^ //│ class C2 extends C1 { //│ constructor() @@ -66,19 +70,19 @@ class Foo { virtual fun x: Int = 1 } :e class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.67: class Bar extends Foo { fun x = false } +//│ ║ l.71: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.67: class Bar extends Foo { fun x = false } +//│ ║ l.71: class Bar extends Foo { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.67: class Bar extends Foo { fun x = false } +//│ ║ l.71: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.60: class Foo { virtual fun x: Int = 1 } +//│ ║ l.64: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.60: class Foo { virtual fun x: Int = 1 } +//│ ║ l.64: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -91,19 +95,19 @@ class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.90: fun x: Bool +//│ ║ l.94: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.90: fun x: Bool +//│ ║ l.94: fun x: Bool //│ ║ ^^^^ //│ ╟── but it flows into signature of member `x` with expected type `Int` -//│ ║ l.90: fun x: Bool +//│ ║ l.94: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.60: class Foo { virtual fun x: Int = 1 } +//│ ║ l.64: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.60: class Foo { virtual fun x: Int = 1 } +//│ ║ l.64: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -118,19 +122,19 @@ mixin M { fun x = false } :e class Bar extends Foo, M //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.113: mixin M { fun x = false } +//│ ║ l.117: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.113: mixin M { fun x = false } +//│ ║ l.117: mixin M { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.113: mixin M { fun x = false } +//│ ║ l.117: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.60: class Foo { virtual fun x: Int = 1 } +//│ ║ l.64: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.60: class Foo { virtual fun x: Int = 1 } +//│ ║ l.64: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -158,19 +162,19 @@ trait B { class X { fun g = 1 } } :e class C extends A, B //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.159: class C extends A, B +//│ ║ l.163: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Declared here: -//│ ║ l.143: trait B { class X { fun g = 1 } } +//│ ╟── Originally declared here: +//│ ║ l.147: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Intersection of class member and class members currently unsupported -//│ ║ l.159: class C extends A, B +//│ ║ l.163: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.142: class A { class X { fun f = 1 } } +//│ ║ l.146: class A { class X { fun f = 1 } } //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.143: trait B { class X { fun g = 1 } } +//│ ║ l.147: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C extends A, B { //│ constructor() @@ -185,12 +189,12 @@ class C extends A { class X { fun g = 1 } } //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.184: class C extends A { +//│ ║ l.188: class C extends A { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.185: class X { fun g = 1 } +//│ ║ l.189: class X { fun g = 1 } //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── Declared here: -//│ ║ l.142: class A { class X { fun f = 1 } } +//│ ╟── Originally declared here: +//│ ║ l.146: class A { class X { fun f = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ class C extends A { //│ constructor() @@ -202,3 +206,16 @@ class C extends A { +:e +class Foo2 extends Foo2 +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.210: class Foo2 extends Foo2 +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ +//│ class Foo2 extends Foo2 { +//│ constructor() +//│ } +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + + + diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 399cf00db0..e1daa4f63c 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -39,27 +39,32 @@ class C0 extends M0(true) //│ } -// TODO catch this at typing (lack of `this`) -class Foo { +module Foo { fun foo = 0 fun bar = foo } -//│ class Foo { -//│ constructor() +[Foo.foo, Foo.bar] +//│ module Foo { //│ fun bar: 0 //│ fun foo: 0 //│ } +//│ [0, 0] +//│ res +//│ = [ 0, 0 ] -// FIXME -class Foo { +// * FIXME add initialization checking for non-lazy fields +module Foo { let foo = 0 fun bar = foo } -//│ class Foo { -//│ constructor() +[Foo.foo, Foo.bar] +//│ module Foo { //│ fun bar: 0 //│ let foo: 0 //│ } +//│ [0, 0] +//│ res +//│ = [ undefined, 0 ] module Bar { @@ -74,7 +79,7 @@ module Bar { :e hello //│ ╔══[ERROR] identifier not found: hello -//│ ║ l.75: hello +//│ ║ l.80: hello //│ ╙── ^^^^^ //│ error //│ Code generation encountered an error: @@ -83,7 +88,7 @@ hello :e 1 : I //│ ╔══[ERROR] type identifier not found: I -//│ ║ l.84: 1 : I +//│ ║ l.89: 1 : I //│ ╙── ^ //│ error //│ res @@ -93,11 +98,11 @@ hello :e class Foo[A] { 42: A } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.94: class Foo[A] { 42: A } +//│ ║ l.99: class Foo[A] { 42: A } //│ ║ ^^ //│ ╟── integer literal of type `42` does not match type `A` //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.94: class Foo[A] { 42: A } +//│ ║ l.99: class Foo[A] { 42: A } //│ ╙── ^ //│ class Foo[A] { //│ constructor() @@ -107,7 +112,7 @@ class Foo[A] { 42: A } :e class C1 { fun oops = this.x } //│ ╔══[ERROR] Type `#C1` does not contain member `x` -//│ ║ l.108: class C1 { fun oops = this.x } +//│ ║ l.113: class C1 { fun oops = this.x } //│ ╙── ^^ //│ class C1 { //│ constructor() @@ -117,20 +122,25 @@ class C1 { fun oops = this.x } :e class C { fun x: Int } -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C` -//│ ║ l.119: class C { fun x: Int } +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C` +//│ ║ l.124: class C { fun x: Int } //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.119: class C { fun x: Int } +//│ ║ l.124: class C { fun x: Int } //│ ╙── ^^^^^^ //│ class C { //│ constructor() //│ fun x: Int //│ } -// FIXME should error -// :e +:e class C { val x: Int } +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C` +//│ ║ l.137: class C { val x: Int } +//│ ║ ^ +//│ ╟── Declared here: +//│ ║ l.137: class C { val x: Int } +//│ ╙── ^^^^^^ //│ class C { //│ constructor() //│ let x: Int diff --git a/shared/src/test/diff/nu/BadMixins.mls b/shared/src/test/diff/nu/BadMixins.mls index 34cf7fba43..2cbe310433 100644 --- a/shared/src/test/diff/nu/BadMixins.mls +++ b/shared/src/test/diff/nu/BadMixins.mls @@ -21,3 +21,4 @@ M0 //│ res //│ = [Function (anonymous)] + diff --git a/shared/src/test/diff/nu/BadSignatures.mls b/shared/src/test/diff/nu/BadSignatures.mls index 5a4b8791cc..c82b49ebc0 100644 --- a/shared/src/test/diff/nu/BadSignatures.mls +++ b/shared/src/test/diff/nu/BadSignatures.mls @@ -90,7 +90,7 @@ class B() extends A { :e mixin M { fun x : Int } -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `M` +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `M` //│ ║ l.92: mixin M { fun x : Int } //│ ║ ^ //│ ╟── Declared here: diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index 18b0fbe41b..f9a0743f47 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -114,13 +114,9 @@ module F extends E(123, 456) //│ fun a2: 2 //│ } -:e // FIXME // * Note: strangely, we see here the ctor output from the previous definitions of the F module 🤔 F.m -//│ ╔══[ERROR] Type `F` does not contain member `m` -//│ ║ l.119: F.m -//│ ╙── ^^ -//│ error +//│ Int //│ res //│ = 579 //│ // Output @@ -135,12 +131,8 @@ class G(x: Int) extends E(x, x + 1) //│ fun a2: 2 //│ } -:e // FIXME G(123).m -//│ ╔══[ERROR] Type `G` does not contain member `m` -//│ ║ l.139: G(123).m -//│ ╙── ^^ -//│ error +//│ Int //│ res //│ = 247 //│ // Output @@ -154,13 +146,13 @@ class H extends E { } } //│ ╔══[ERROR] class E expects 2 parameter(s); got 0 -//│ ║ l.151: class H extends E { +//│ ║ l.143: class H extends E { //│ ╙── ^ //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.153: super(a, b) +//│ ║ l.145: super(a, b) //│ ╙── ^^^^^ //│ ╔══[ERROR] identifier not found: super -//│ ║ l.153: super(a, b) +//│ ║ l.145: super(a, b) //│ ╙── ^^^^^ //│ class H extends A, E { //│ constructor(a: Int, b: Int) diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 9291f8d046..b668405ca8 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -121,7 +121,7 @@ let n2 = b2.n -class Base1(base: Int) { +class Base1(val base: Int) { fun getBase1 = base fun getBase2 = this.base fun foo(x) = this.base + x diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 61d03e0cf8..60d500da85 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -35,17 +35,17 @@ Base0.test :e -class Base1(base: Int) extends BaseTest { +class Base1(val base: Int) extends BaseTest { fun test2 = [base, this.base] } //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.38: class Base1(base: Int) extends BaseTest { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.38: class Base1(val base: Int) extends BaseTest { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.39: fun test2 = [base, this.base] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.38: class Base1(base: Int) extends BaseTest { -//│ ║ ^ +//│ ║ l.38: class Base1(val base: Int) extends BaseTest { +//│ ║ ^ //│ ╟── Note: constraint arises from field selection: //│ ║ l.12: fun test = super.base //│ ║ ^^^^^^^^^^ diff --git a/shared/src/test/diff/nu/ClassInstantiation.mls b/shared/src/test/diff/nu/ClassInstantiation.mls new file mode 100644 index 0000000000..31b1a6066d --- /dev/null +++ b/shared/src/test/diff/nu/ClassInstantiation.mls @@ -0,0 +1,61 @@ +// *** Class instantiation tests *** // + +:NewDefs + + +class C +//│ class C { +//│ constructor() +//│ } + +new C +//│ C +//│ res +//│ = C {} + +// * TODO decide: forbid? +new C() +//│ C +//│ res +//│ = C {} + +:e +C() +//│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword +//│ ║ l.23: C() +//│ ╙── ^ +//│ C +//│ res +//│ Runtime error: +//│ TypeError: Class constructor C cannot be invoked without 'new' + + +class D(x: Int) +//│ class D(x: Int) + +:js +D(0) +//│ D +//│ // Prelude +//│ class TypingUnit5 {} +//│ const typing_unit5 = new TypingUnit5; +//│ // Query 1 +//│ res = D(0); +//│ // End of generated code +//│ res +//│ = D {} + +// * TODO decide: reject or accept? +:js +new D(0) +//│ D +//│ // Prelude +//│ class TypingUnit6 {} +//│ const typing_unit6 = new TypingUnit6; +//│ // Query 1 +//│ res = new D.class(0); +//│ // End of generated code +//│ res +//│ = D {} + + diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 1d4d2569c8..bf6d759ecb 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -29,7 +29,7 @@ M.f.n :e M.Foo -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.31: M.Foo //│ ╙── ^^^^ //│ error diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index 59090ce6da..a62a6529b9 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -87,7 +87,7 @@ let s = new Sanitizer // * TODO allow Buffer2 to be named Buffer... // :d declare module Buffer { - class Buffer2 { + abstract class Buffer2 { val length: Int } fun bar: Int @@ -96,8 +96,7 @@ declare module Buffer { // fun from2(a: Array[Int]): Buffer.Buffer2 = from2(a) // FIXME } //│ declare module Buffer { -//│ class Buffer2 { -//│ constructor() +//│ abstract class Buffer2 { //│ let length: Int //│ } //│ fun bar: Int @@ -120,10 +119,10 @@ b.length :pe declare 42 //│ ╔══[PARSE ERROR] Unexpected literal token after modifier -//│ ║ l.121: declare 42 +//│ ║ l.120: declare 42 //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected literal token after modifier -//│ ║ l.121: declare 42 +//│ ║ l.120: declare 42 //│ ╙── ^^ //│ 42 //│ res diff --git a/shared/src/test/diff/nu/EqlClasses.mls b/shared/src/test/diff/nu/EqlClasses.mls index 740074aa2d..76f346178c 100644 --- a/shared/src/test/diff/nu/EqlClasses.mls +++ b/shared/src/test/diff/nu/EqlClasses.mls @@ -27,6 +27,22 @@ Cls1() === Cls1() class Cls2(x: Int) //│ class Cls2(x: Int) +:e // TODO better error – or actually only support data classes +Cls2(0) === Cls2(1) +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.27: class Cls2(x: Int) +//│ ║ ^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.27: class Cls2(x: Int) +//│ ╙── ^ +//│ error | false | true +//│ res +//│ = false + + +class Cls2(val x: Int) +//│ class Cls2(x: Int) + Cls2(0) === Cls2(1) //│ Bool //│ res @@ -34,7 +50,7 @@ Cls2(0) === Cls2(1) -class Pair[A](fst: A, snd: A) +class Pair[A](val fst: A, val snd: A) // extends (A <: Eql[A]) => Eql[Pair[A]] //│ class Pair[A](fst: A, snd: A) @@ -67,10 +83,10 @@ p === { fst: 1, snd: 2 } :e { fst: 1, snd: 2 } === p //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.68: { fst: 1, snd: 2 } === p +//│ ║ l.84: { fst: 1, snd: 2 } === p //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── record literal of type `{fst: 1, snd: 2}` is not an instance of type `Eql` -//│ ║ l.68: { fst: 1, snd: 2 } === p +//│ ║ l.84: { fst: 1, snd: 2 } === p //│ ╙── ^^^^^^^^^ //│ error | false | true //│ res @@ -90,11 +106,11 @@ r : {x: Int} :e x => { a: 0 } === x //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.91: x => { a: 0 } === x -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.107: x => { a: 0 } === x +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── record literal of type `{a: 0}` is not an instance of type `Eql` -//│ ║ l.91: x => { a: 0 } === x -//│ ╙── ^ +//│ ║ l.107: x => { a: 0 } === x +//│ ╙── ^ //│ anything -> (error | false | true) //│ res //│ Syntax error: @@ -115,17 +131,17 @@ let q = Pair(1, "oops") :e q === q //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.116: q === q +//│ ║ l.132: q === q //│ ║ ^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `Str` -//│ ║ l.110: let q = Pair(1, "oops") +//│ ║ l.126: let q = Pair(1, "oops") //│ ╙── ^ //│ error | false | true //│ res //│ = true -class Pair2[A, B](fst: A, snd: B) +class Pair2[A, B](val fst: A, val snd: B) //│ class Pair2[A, B](fst: A, snd: B) let q = Pair2(1, "oops") diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index b6d6141e31..193b5f1033 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -12,7 +12,7 @@ fun eval(e) = if e is Add0(l) then eval(l) class Add(lhs: E, rhs: E) -class Lit(value: Int) +class Lit(val value: Int) //│ class Add[E](lhs: E, rhs: E) //│ class Lit(value: Int) diff --git a/shared/src/test/diff/nu/FieldRefinement.mls b/shared/src/test/diff/nu/FieldRefinement.mls index 03eaaa2970..b3c4789409 100644 --- a/shared/src/test/diff/nu/FieldRefinement.mls +++ b/shared/src/test/diff/nu/FieldRefinement.mls @@ -2,7 +2,7 @@ :NoJS -class Foo(x: Int) { +class Foo(val x: Int) { fun bar = x fun baz: 1 | 2 = 1 } diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 2daf692231..4c26146966 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -74,9 +74,8 @@ class WrongRoom extends Room[Bool]("wrong") { //│ } -class C0[A] { val a: A } -//│ class C0[A] { -//│ constructor() +abstract class C0[A] { val a: A } +//│ abstract class C0[A] { //│ let a: A //│ } @@ -141,27 +140,27 @@ mixin M2[A] { //│ fun m: A //│ } -class B1(a: Int) extends M2[Int] +class B1(val a: Int) extends M2[Int] //│ class B1(a: Int) { //│ fun m: Int //│ } -class B2[A](a: Int => A) extends M2 +class B2[A](val a: Int => A) extends M2 //│ class B2[A](a: Int -> A) { //│ fun m: Int -> A //│ } :e -class E1(a: Int) extends M2[Bool] +class E1(val a: Int) extends M2[Bool] //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.155: class E1(a: Int) extends M2[Bool] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.154: class E1(val a: Int) extends M2[Bool] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int` is not an instance of type `Bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.155: class E1(a: Int) extends M2[Bool] -//│ ║ ^^^^ +//│ ║ l.154: class E1(val a: Int) extends M2[Bool] +//│ ║ ^^^^ //│ ╟── from field selection: -//│ ║ l.137: fun m: A = this.a +//│ ║ l.136: fun m: A = this.a //│ ╙── ^^^^^^ //│ class E1(a: Int) { //│ fun m: Bool diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 8b29e054e4..5629b4406d 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -35,7 +35,7 @@ f(c) //│ = 1 -class C[A](n: A) { +class C[A](val n: A) { fun f = this.n fun g = C(12).n } diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index ea88aae72d..a460124798 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -108,13 +108,13 @@ module Test { fun bar: 'A fun test(x: A) = x } -//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Test` +//│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.106: module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.107: fun foo: 'A => 'A //│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Test` +//│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.106: module Test { //│ ║ ^^^^ //│ ╟── Declared here: diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 3e6b1cf30a..34c55b519e 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -10,19 +10,19 @@ module Test { fun poly1: forall 'a; 'a -> 'a fun poly2: 'a -> 'a = id } -//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Test` +//│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.5: module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.6: fun foo: A => A //│ ╙── ^^^^^^^^^^^ -//│ ╔══[ERROR] Member `poly0` is declared in parent but not implemented in `Test` +//│ ╔══[ERROR] Member `poly0` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.5: module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.9: fun poly0: 'a -> 'a //│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `poly1` is declared in parent but not implemented in `Test` +//│ ╔══[ERROR] Member `poly1` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.5: module Test { //│ ║ ^^^^ //│ ╟── Declared here: diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 05041870fa..302248d7c0 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -2,24 +2,36 @@ mixin Test[A] { - fun bar: (A, A) - fun bar = (this.a, this.a) + fun bar: (A, A) + fun bar = (this.a, this.a) } //│ mixin Test[A]() { //│ this: {a: A} //│ fun bar: [A, A] //│ } +class A(val a: Int) extends Test +//│ class A(a: Int) { +//│ fun bar: [Int, Int] +//│ } + +:e class A(a: Int) extends Test +//│ ╔══[ERROR] Parameter 'a' cannot tbe accessed as a field +//│ ║ l.6: fun bar = (this.a, this.a) +//│ ╙── ^^ +//│ ╔══[ERROR] Parameter 'a' cannot tbe accessed as a field +//│ ║ l.6: fun bar = (this.a, this.a) +//│ ╙── ^^ //│ class A(a: Int) { //│ fun bar: [Int, Int] //│ } mixin Test2[S, T] { - fun x: (S, T) - fun x = (this.s, this.t) - fun fb: S => (S, S) - fun fb(h: S) = (this.s, h) + fun x: (S, T) + fun x = (this.s, this.t) + fun fb: S => (S, S) + fun fb(h: S) = (this.s, h) } //│ mixin Test2[S, T]() { //│ this: {s: S, t: T} @@ -27,50 +39,50 @@ mixin Test2[S, T] { //│ fun x: [S, T] //│ } -class A1[B](s: Bool, t: B) extends Test2[Bool, B] +class A1[B](val s: Bool, val t: B) extends Test2[Bool, B] //│ class A1[B](s: Bool, t: B) { //│ fun fb: (Bool & 'S) -> [Bool | 'S, Bool | 'S] //│ fun x: [Bool | 'S, B] //│ } -// TODO: Investigate type of fb -class A2[A](s: A, t: Int) extends Test2 +// * TODO: Investigate type of fb +class A2[A](val s: A, val t: Int) extends Test2 //│ class A2[A](s: A, t: Int) { //│ fun fb: 'S -> [A | 'S, A | 'S] //│ fun x: [A | 'S, Int] //│ } -// TODO: Investigate type of fb -class A3(s: Int, t: Bool) extends Test2 +// * TODO: Investigate type of fb +class A3(val s: Int, val t: Bool) extends Test2 //│ class A3(s: Int, t: Bool) { //│ fun fb: 'S -> [Int | 'S, Int | 'S] //│ fun x: [Int | 'S, Bool] //│ } class P(val p: Int) { - virtual fun foo(x) = x + p + virtual fun foo(x) = x + p } //│ class P(p: Int) { //│ fun foo: Int -> Int //│ } -:e // FIXME +:e // TODO improve type checking class C1(a: Int) extends P(a) { fun bar = this.foo(0) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.58: class C1(a: Int) extends P(a) { fun bar = this.foo(0) } +//│ ║ l.70: class C1(a: Int) extends P(a) { fun bar = this.foo(0) } //│ ╙── ^^^^ //│ class C1(a: Int) extends P { //│ fun bar: error //│ fun foo: Int -> Int //│ } -:e // FIXME +:e // TODO improve type checking class C2(a: Int, b: Int) extends P(a + b) { - fun foo(x) = x * this.p + a * b + fun foo(x) = x * this.p + a * b } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.69: fun foo(x) = x * this.p + a * b -//│ ╙── ^^ +//│ ║ l.81: fun foo(x) = x * this.p + a * b +//│ ╙── ^^ //│ class C2(a: Int, b: Int) extends P { //│ fun foo: Int -> Int //│ } @@ -165,7 +177,7 @@ B.foo :pe trait Foo[type A] { fun foo(x: A): A } //│ ╔══[PARSE ERROR] Unexpected 'type' keyword here -//│ ║ l.166: trait Foo[type A] { fun foo(x: A): A } +//│ ║ l.178: trait Foo[type A] { fun foo(x: A): A } //│ ╙── ^^^^ //│ trait Foo { //│ fun foo: (x: A) -> A @@ -216,22 +228,22 @@ class B extends Foo { fun foo(x) = x } :e class B extends Foo { fun foo(x) = x + 1 } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.229: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `A` is not an instance of type `Int` -//│ ║ l.205: trait Foo[A] { fun foo[A](x: A): A } +//│ ║ l.217: trait Foo[A] { fun foo[A](x: A): A } //│ ║ ^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.229: class B extends Foo { fun foo(x) = x + 1 } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.229: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── operator application of type `Int` does not match type `A` -//│ ║ l.217: class B extends Foo { fun foo(x) = x + 1 } +//│ ║ l.229: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from method type parameter: -//│ ║ l.205: trait Foo[A] { fun foo[A](x: A): A } +//│ ║ l.217: trait Foo[A] { fun foo[A](x: A): A } //│ ╙── ^ //│ class B extends Foo { //│ constructor() diff --git a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls index 739ac0f1b3..f637d0991a 100644 --- a/shared/src/test/diff/nu/InheritanceLevelMismatches.mls +++ b/shared/src/test/diff/nu/InheritanceLevelMismatches.mls @@ -30,7 +30,7 @@ mixin Foo { fun f = this.x } //│ } module Bar { - class C(x: Int) extends Foo + class C(val x: Int) extends Foo } //│ module Bar { //│ class C(x: Int) { diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index d486aee96a..b5d084c994 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -25,7 +25,7 @@ trait Product[A, B] extends Into[A] { //│ where //│ 'T := A -class TwoInts(pair: (Int, Int)) extends Product[Int, Int] { +class TwoInts(val pair: (Int, Int)) extends Product[Int, Int] { fun Into = pair._1 + pair._2 } //│ class TwoInts(pair: [Int, Int]) extends Into, Product { diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index e464e83f5b..e42427a9c1 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -40,7 +40,7 @@ class ErrC2 extends Showable { fun toString = 114 } class ErrC3(toString: Str -> Str) extends Showable -//│ ╔══[ERROR] Member `toString` is declared in parent but not implemented in `ErrC1` +//│ ╔══[ERROR] Member `toString` is declared (or its declaration is inherited) but is not implemented in `ErrC1` //│ ║ l.38: class ErrC1 extends Showable //│ ║ ^^^^^ //│ ╟── Declared here: @@ -149,13 +149,13 @@ class Errcity(size: Int) extends SizedStadt { //│ ╟── from signature of member `size`: //│ ║ l.102: let size: 1 | 2 | 3 //│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `name` is declared in parent but not implemented in `Errcity` +//│ ╔══[ERROR] Member `name` is declared (or its declaration is inherited) but is not implemented in `Errcity` //│ ║ l.124: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: //│ ║ l.85: let name: Str //│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `Errcity` +//│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `Errcity` //│ ║ l.124: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index c28a577e85..4c2527d23b 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -360,7 +360,7 @@ class CE extends Ele { class E1 extends Test { fun foo = 2 } -//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `E1` +//│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `E1` //│ ║ l.360: class E1 extends Test { //│ ║ ^^ //│ ╟── Declared here: @@ -421,13 +421,13 @@ class D extends Test[Int], Test[Bool] //│ ╔══[ERROR] trait Test expects 0 type parameter(s); got 1 //│ ║ l.417: class D extends Test[Int], Test[Bool] //│ ╙── ^^^^^^^^^ -//│ ╔══[ERROR] Member `foo` is declared in parent but not implemented in `D` +//│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `D` //│ ║ l.417: class D extends Test[Int], Test[Bool] //│ ║ ^ //│ ╟── Declared here: //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `D` +//│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `D` //│ ║ l.417: class D extends Test[Int], Test[Bool] //│ ║ ^ //│ ╟── Declared here: @@ -563,10 +563,10 @@ let g: Geo let z: ZL let w: WP let e: EM +//│ let e: EM //│ let g: Geo -//│ let z: ZL //│ let w: WP -//│ let e: EM +//│ let z: ZL //│ g //│ = //│ z @@ -755,7 +755,7 @@ class Eh3 extends Bs(false), Test //│ ╟── from signature of member `foo`: //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ -//│ ╔══[ERROR] Member `bar` is declared in parent but not implemented in `Eh3` +//│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `Eh3` //│ ║ l.730: class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: @@ -786,7 +786,21 @@ class Ca(a: Int) extends Oth { //│ fun foo: 1 //│ } +class Cx(a2: 1 | 2, val b: Bool) extends Ca(a2) +//│ class Cx(a2: 1 | 2, b: Bool) extends Ca, Oth, Test { +//│ fun bar: forall 'a. 'a -> 'a +//│ fun cool: anything -> false +//│ fun foo: 1 +//│ } + +:e class Cx(a: 1 | 2, val b: Bool) extends Ca(a) +//│ ╔══[ERROR] Inherited parameter named `a` is not virtual and cannot be overridden +//│ ║ l.797: class Cx(a: 1 | 2, val b: Bool) extends Ca(a) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.778: class Ca(a: Int) extends Oth { +//│ ╙── ^ //│ class Cx(a: 1 | 2, b: Bool) extends Ca, Oth, Test { //│ fun bar: forall 'a. 'a -> 'a //│ fun cool: anything -> false @@ -815,28 +829,34 @@ cx1: Ca class Bc1(foo: Int) class Bc2(bar: Bool) -class Bc3 { +abstract class Bc3 { let baz : Int } //│ class Bc1(foo: Int) //│ class Bc2(bar: Bool) -//│ class Bc3 { -//│ constructor() +//│ abstract class Bc3 { //│ let baz: Int //│ } :e class Bc12() extends Bc1(1), Bc2(true) -//│ ╔══[ERROR] cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.829: class Bc12() extends Bc1(1), Bc2(true) +//│ ╔══[ERROR] Cannot inherit from more than one base class: Bc1 and Bc2 +//│ ║ l.842: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: //│ unexpected parent symbol new class Bc2. +:e class Bc02() extends Bc1(1:Int) { val foo = 2 } +//│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden +//│ ║ l.852: val foo = 2 +//│ ║ ^^^^^^^ +//│ ╟── Originally declared here: +//│ ║ l.830: class Bc1(foo: Int) +//│ ╙── ^^^ //│ class Bc02() extends Bc1 { //│ let foo: 2 //│ } @@ -849,14 +869,14 @@ Bc02().foo :e class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.850: class Bc31(baz: Bool) extends Bc3 +//│ ║ l.870: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.819: let baz : Int +//│ ║ l.833: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.819: let baz : Int +//│ ║ l.833: let baz : Int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: Bool) extends Bc3 @@ -864,13 +884,12 @@ class Bc31(baz: Bool) extends Bc3 class Bc11 extends Bc1(1) { let foo = true } -//│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.865: let foo = true -//│ ║ ^^^^ -//│ ╟── reference of type `true` does not match type `1` -//│ ╟── Note: constraint arises from integer literal: -//│ ║ l.864: class Bc11 extends Bc1(1) { -//│ ╙── ^ +//│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden +//│ ║ l.885: let foo = true +//│ ║ ^^^^^^^^^^ +//│ ╟── Originally declared here: +//│ ║ l.830: class Bc1(foo: Int) +//│ ╙── ^^^ //│ class Bc11 extends Bc1 { //│ constructor() //│ let foo: true @@ -899,7 +918,7 @@ trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.899: fun f = error +//│ ║ l.918: fun f = error //│ ╙── ^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -930,7 +949,7 @@ bp: Base[(Int, Bool)] :e bp: Base[(Int, Int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.931: bp: Base[(Int, Int)] +//│ ║ l.950: bp: Base[(Int, Int)] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -991,13 +1010,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.992: class DerBad1 extends Base[Int, Int] -//│ ╙── ^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `f` is declared in parent but not implemented in `DerBad1` -//│ ║ l.992: class DerBad1 extends Base[Int, Int] -//│ ║ ^^^^^^^ +//│ ║ l.1011: class DerBad1 extends Base[Int, Int] +//│ ╙── ^^^^^^^^^^^^^ +//│ ╔══[ERROR] Member `f` is declared (or its declaration is inherited) but is not implemented in `DerBad1` +//│ ║ l.1011: class DerBad1 extends Base[Int, Int] +//│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.880: trait Base[A] { fun f: A -> A } +//│ ║ l.899: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^ //│ class DerBad1 extends Base { //│ constructor() @@ -1009,28 +1028,28 @@ class DerBad1 extends Base[Int, Int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.1010: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ constructor() @@ -1041,7 +1060,7 @@ trait Ta[T] { val p: Bool val g: T } -class K[A](k: Ta[A]) +class K[A](val k: Ta[A]) //│ trait Ta[T] { //│ let g: T //│ let p: Bool @@ -1082,7 +1101,7 @@ trait Tb extends Ta[Int] { virtual val p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1082: virtual val p = false +//│ ║ l.1101: virtual val p = false //│ ╙── ^^^^^^^^^ //│ trait Tb extends Ta { //│ let g: 'T @@ -1104,8 +1123,8 @@ class Ctb extends Tb { class G1[A](x: A) //│ class G1[A](x: A) -class GI(x: Int) extends G1[Int](x) -//│ class GI(x: Int) extends G1 +class GI(x2: Int) extends G1[Int](x2) +//│ class GI(x2: Int) extends G1 trait Oz { let age: Int @@ -1117,14 +1136,14 @@ trait Oz { :e class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1118: class Fischl(age: Bool) extends Oz +//│ ║ l.1137: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1111: let age: Int +//│ ║ l.1130: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1111: let age: Int +//│ ║ l.1130: let age: Int //│ ╙── ^^^^^^^^ //│ class Fischl(age: Bool) extends Oz @@ -1144,29 +1163,29 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1163: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1163: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1163: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1163: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1135: virtual fun foo(x) = x + 1 +//│ ║ l.1154: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1163: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1163: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1135: virtual fun foo(x) = x + 1 +//│ ║ l.1154: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { //│ constructor() @@ -1185,11 +1204,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1186: class Ohhh(x: Bool) extends Ha +//│ ║ l.1205: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1176: class Ha { virtual val x: Int = 1 } +//│ ║ l.1195: class Ha { virtual val x: Int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: Bool) extends Ha diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index 461d1349d1..51f2653edb 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -11,8 +11,8 @@ let f = let x : Int | string let x = 1 -//│ let x: Int | string //│ let x: 1 +//│ let x: Int | string //│ x //│ = //│ x diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index fad7868856..6f23b2825e 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -74,11 +74,11 @@ trait S3 extends S1, T1 //│ } -class C1(x: Int | Bool) -trait T1 { val x: Int | string } +class C1(val x: Int | Bool) +trait T1 { val x: Int | Str } //│ class C1(x: Int | false | true) //│ trait T1 { -//│ let x: Int | string +//│ let x: Int | Str //│ } class C2() extends C1(0), T1 @@ -92,13 +92,13 @@ class C2 extends C1(false), T1 //│ ╔══[ERROR] Type mismatch in reference: //│ ║ l.91: class C2 extends C1(false), T1 //│ ║ ^^^^^ -//│ ╟── reference of type `false` does not match type `Int | string` +//│ ╟── reference of type `false` does not match type `Int | Str` //│ ╟── Note: constraint arises from union type: -//│ ║ l.78: trait T1 { val x: Int | string } -//│ ║ ^^^^^^^^^^^^ +//│ ║ l.78: trait T1 { val x: Int | Str } +//│ ║ ^^^^^^^^^ //│ ╟── from signature of member `x`: -//│ ║ l.78: trait T1 { val x: Int | string } -//│ ╙── ^^^^^^^^^^^^^^^ +//│ ║ l.78: trait T1 { val x: Int | Str } +//│ ╙── ^^^^^^^^^^^^ //│ class C2 extends C1, T1 { //│ constructor() //│ } @@ -112,18 +112,8 @@ class C2 extends C1("oops"), T1 //│ ║ l.107: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: -//│ ║ l.77: class C1(x: Int | Bool) -//│ ╙── ^^^^^^^^^^ -//│ ╔══[ERROR] Type mismatch in string literal: -//│ ║ l.107: class C2 extends C1("oops"), T1 -//│ ║ ^^^^^^ -//│ ╟── string literal of type `"oops"` does not match type `Int | string` -//│ ╟── Note: constraint arises from union type: -//│ ║ l.78: trait T1 { val x: Int | string } -//│ ║ ^^^^^^^^^^^^ -//│ ╟── from signature of member `x`: -//│ ║ l.78: trait T1 { val x: Int | string } -//│ ╙── ^^^^^^^^^^^^^^^ +//│ ║ l.77: class C1(val x: Int | Bool) +//│ ╙── ^^^^^^^^^^ //│ class C2 extends C1, T1 { //│ constructor() //│ } diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 55fb957fd2..bf74fb1108 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -14,7 +14,7 @@ module Oops { module Oops { fun a : Int } -//│ ╔══[ERROR] Member `a` is declared in parent but not implemented in `Oops` +//│ ╔══[ERROR] Member `a` is declared (or its declaration is inherited) but is not implemented in `Oops` //│ ║ l.14: module Oops { //│ ║ ^^^^ //│ ╟── Declared here: diff --git a/shared/src/test/diff/nu/MixinParameters.mls b/shared/src/test/diff/nu/MixinParameters.mls index 6e9d371678..b0e1a6320a 100644 --- a/shared/src/test/diff/nu/MixinParameters.mls +++ b/shared/src/test/diff/nu/MixinParameters.mls @@ -18,25 +18,26 @@ Test.test //│ res //│ = 42 -// :e // TODO reject +:e Test.x -//│ 42 +//│ ╔══[ERROR] Type `Test` does not contain member `x` +//│ ║ l.22: Test.x +//│ ╙── ^^ +//│ error //│ res //│ = undefined -mixin BaseTest(x: Int -> Int) +mixin BaseTest(val x: Int -> Int) //│ mixin BaseTest(x: Int -> Int) module Test extends BaseTest(id) //│ module Test -:re // TODO implement mixin param getters Test.x(1) //│ 1 //│ res -//│ Runtime error: -//│ TypeError: Test.x is not a function +//│ = 1 :e // TODO support @@ -44,7 +45,7 @@ mixin BaseTest(x) { fun test = x } //│ ╔══[ERROR] Mixin parameters currently need type annotations -//│ ║ l.43: mixin BaseTest(x) { +//│ ║ l.44: mixin BaseTest(x) { //│ ╙── ^ //│ mixin BaseTest(x: error) { //│ fun test: error diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index e18bbf0998..cd8274f755 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -335,7 +335,7 @@ Test2_1.n //│ = 456 -class Test2(n: Int) { +class Test2(val n: Int) { fun inc = Test3.inc(this) } module Test3 { diff --git a/shared/src/test/diff/nu/NestedClasses.mls b/shared/src/test/diff/nu/NestedClasses.mls index 3c4e1b2e9f..d712fc8db9 100644 --- a/shared/src/test/diff/nu/NestedClasses.mls +++ b/shared/src/test/diff/nu/NestedClasses.mls @@ -15,7 +15,7 @@ let c = C0() :e c.NC0 -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.17: c.NC0 //│ ╙── ^^^^ //│ error @@ -37,7 +37,7 @@ module M0 { :e M0.NC0 -//│ ╔══[ERROR] access to class member not yet supported +//│ ╔══[ERROR] Access to class member not yet supported //│ ║ l.39: M0.NC0 //│ ╙── ^^^^ //│ error @@ -54,7 +54,7 @@ module M1 { :e M1.NM1 -//│ ╔══[ERROR] access to module member not yet supported +//│ ╔══[ERROR] Access to module member not yet supported //│ ║ l.56: M1.NM1 //│ ╙── ^^^^ //│ error diff --git a/shared/src/test/diff/nu/NoThisCtor.mls b/shared/src/test/diff/nu/NoThisCtor.mls index 591d07019f..104c381d08 100644 --- a/shared/src/test/diff/nu/NoThisCtor.mls +++ b/shared/src/test/diff/nu/NoThisCtor.mls @@ -1,6 +1,6 @@ :NewDefs -class Base(base: Int) { +class Base(val base: Int) { fun getBase1 = base fun getBase2 = this.base fun foo(x) = this.base + x diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls index a99fdcab6d..661ba4635b 100644 --- a/shared/src/test/diff/nu/ParamImplementing.mls +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -2,18 +2,18 @@ trait T { fun x: Int } +mixin M(val x: Bool) //│ trait T { //│ fun x: Int //│ } - -mixin M(x: Bool) //│ mixin M(x: Bool) :e -class C extends T, M(false) +module C extends T, M(false) +C.x //│ ╔══[ERROR] Type mismatch in reference: -//│ ║ l.13: class C extends T, M(false) -//│ ║ ^^^^^ +//│ ║ l.12: module C extends T, M(false) +//│ ║ ^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` //│ ╟── Note: constraint arises from type reference: //│ ║ l.4: trait T { fun x: Int } @@ -21,21 +21,48 @@ class C extends T, M(false) //│ ╟── from signature of member `x`: //│ ║ l.4: trait T { fun x: Int } //│ ╙── ^^^^^^ -//│ class C extends T { -//│ constructor() -//│ } +//│ module C extends T +//│ false +//│ res +//│ = false trait T { fun x: Int } -mixin M(x: Num) +mixin M(val x: Num) //│ trait T { //│ fun x: Int //│ } //│ mixin M(x: Num) -class C extends T, M(0) -//│ class C extends T { -//│ constructor() +module C extends T, M(0) +C.x +//│ module C extends T +//│ 0 +//│ res +//│ = 0 + + +trait T { fun x: Int } +mixin M(x: Bool) +//│ trait T { +//│ fun x: Int +//│ } +//│ mixin M(x: Bool) + +:e +module C extends T, M(false) +C.x +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C` +//│ ║ l.53: module C extends T, M(false) +//│ ║ ^ +//│ ╟── Declared here: +//│ ║ l.45: trait T { fun x: Int } +//│ ╙── ^^^^^^ +//│ module C extends T { +//│ fun x: Int //│ } +//│ Int +//│ res +//│ = undefined diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 17735352f4..ab7fdb58fa 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -4,11 +4,39 @@ class Foo(x: Int) //│ class Foo(x: Int) +class Bar(z: Int, y: Int) extends Foo(z + y) +//│ class Bar(z: Int, y: Int) extends Foo +:e class Bar(x: Int, y: Int) extends Foo(x + y) +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.11: class Bar(x: Int, y: Int) extends Foo(x + y) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.4: class Foo(x: Int) +//│ ╙── ^ //│ class Bar(x: Int, y: Int) extends Foo +class Foo(val x: Int) +//│ class Foo(x: Int) + +module Bar extends Foo(11) +Bar.x +//│ module Bar extends Foo +//│ 11 +//│ res +//│ = 11 + +:e // FIXME +module Bar extends Foo(11) { fun get = this.x } +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.32: module Bar extends Foo(11) { fun get = this.x } +//│ ╙── ^^ +//│ module Bar extends Foo { +//│ fun get: error +//│ } + mixin AA(a: Int) { } @@ -28,3 +56,197 @@ class E(x: Int) extends BB, AA(x) //│ class E(x: Int) +class Foo(x: Int) +//│ class Foo(x: Int) + +:e +Foo(1).x +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.63: Foo(1).x +//│ ║ ^^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.59: class Foo(x: Int) +//│ ╙── ^ +//│ Int | error +//│ res +//│ = undefined + +:e +Foo(1).#x +//│ ╔══[ERROR] identifier not found: .# +//│ ║ l.75: Foo(1).#x +//│ ╙── ^^ +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.75: Foo(1).#x +//│ ╙── ^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol .# + +if Foo(1) is Foo(x) then x +//│ Int +//│ res +//│ = 1 + + +class Foo(val x: Int) +//│ class Foo(x: Int) + +Foo(1).x +//│ Int +//│ res +//│ = 1 + +if Foo(1) is Foo(x) then x +//│ Int +//│ res +//│ = 1 + + +:e +class Bar(x: Int) extends Foo(x) +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.107: class Bar(x: Int) extends Foo(x) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.92: class Foo(val x: Int) +//│ ╙── ^ +//│ class Bar(x: Int) extends Foo + +:e +Bar(11).x +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.117: Bar(11).x +//│ ║ ^^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.107: class Bar(x: Int) extends Foo(x) +//│ ╙── ^ +//│ Int | error +//│ res +//│ = 11 + + +:e +class Bar(val x: Int) extends Foo(x + 1) +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.130: class Bar(val x: Int) extends Foo(x + 1) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.92: class Foo(val x: Int) +//│ ╙── ^ +//│ class Bar(x: Int) extends Foo + +Bar(11).x +//│ Int +//│ res +//│ = 11 + +:e +class Bar extends Foo(1) { val x: 2 } +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.145: class Bar extends Foo(1) { val x: 2 } +//│ ║ ^^^^ +//│ ╟── Originally declared here: +//│ ║ l.92: class Foo(val x: Int) +//│ ╙── ^ +//│ class Bar extends Foo { +//│ constructor() +//│ let x: 2 +//│ } + +:e +module Bar extends Foo(1) { fun x = 2 } +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.158: module Bar extends Foo(1) { fun x = 2 } +//│ ║ ^^^^^ +//│ ╟── Originally declared here: +//│ ║ l.92: class Foo(val x: Int) +//│ ╙── ^ +//│ module Bar extends Foo { +//│ fun x: 2 +//│ } + + +class A(val x: Int) +//│ class A(x: Int) + +module B extends A(42) +//│ module B extends A + +B.x +//│ 42 +//│ res +//│ = 42 + + +class A(x: Int) +//│ class A(x: Int) + +module B extends A(42) +//│ module B extends A + +:e +B.x +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.189: B.x +//│ ║ ^^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.182: class A(x: Int) +//│ ╙── ^ +//│ Int | error +//│ res +//│ = undefined + + + +abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } +//│ abstract class Foo[A](x: A) { +//│ fun i: A -> A +//│ fun y: A +//│ } + +abstract class Bar extends Foo(0) +//│ abstract class Bar extends Foo { +//│ fun i: 'A -> 'A +//│ fun y: 'A +//│ } +//│ where +//│ 'A :> 0 + +module Baz extends Foo(0) { fun i = id } +[Baz.x, Baz.i] +//│ module Baz extends Foo { +//│ fun i: forall 'a. 'a -> 'a +//│ fun y: 'A +//│ } +//│ [0, forall 'a. 'a -> 'a] +//│ where +//│ 'A :> 0 +//│ res +//│ = [ 0, [Function: id] ] + +:e +module Bazz extends Foo(0) { + val x: 2 +} +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.230: val x: 2 +//│ ║ ^^^^ +//│ ╟── Originally declared here: +//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } +//│ ╙── ^ +//│ ╔══[ERROR] Member `i` is declared (or its declaration is inherited) but is not implemented in `Bazz` +//│ ║ l.229: module Bazz extends Foo(0) { +//│ ║ ^^^^ +//│ ╟── Declared here: +//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } +//│ ╙── ^^^^^^^^^ +//│ module Bazz extends Foo { +//│ fun i: 'A -> 'A +//│ let x: 2 +//│ fun y: 'A +//│ } +//│ where +//│ 'A :> 0 + + diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index a05e28523c..2ee3145928 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -111,7 +111,7 @@ class Impl extends Base2 :e class Impl() extends Base2, Foo -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `Impl` +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `Impl` //│ ║ l.113: class Impl() extends Base2, Foo //│ ║ ^^^^ //│ ╟── Declared here: diff --git a/shared/src/test/diff/nu/Refinements.mls b/shared/src/test/diff/nu/Refinements.mls index c3363ed0f4..5db034cb6b 100644 --- a/shared/src/test/diff/nu/Refinements.mls +++ b/shared/src/test/diff/nu/Refinements.mls @@ -27,7 +27,7 @@ c : D & { f: 1 } //│ = D { f: 1 } -class C[A](a: A) extends D() +class C[A](val a: A) extends D() //│ class C[A](a: A) extends D { //│ fun f: 0 //│ } diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 71ae420fd7..e749e4f78c 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -2,20 +2,86 @@ -class Foo1(x: Int) { +class Foo1(val x: Int) { fun test = Foo1(1).x } //│ class Foo1(x: Int) { //│ fun test: Int //│ } -class Foo2[A](x: A) { +:e +class Foo1X(x: 0 | 1) extends Foo1(x) { + fun test2 = Foo1X(1).x +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.14: fun test2 = Foo1X(1).x +//│ ╙── ^^ +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.13: class Foo1X(x: 0 | 1) extends Foo1(x) { +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.5: class Foo1(val x: Int) { +//│ ╙── ^ +//│ class Foo1X(x: 0 | 1) extends Foo1 { +//│ fun test: Int +//│ fun test2: error +//│ } + + +class Foo2[A](val x: A) { fun test = Foo2(1).x } //│ class Foo2[A](x: A) { //│ fun test: 1 //│ } +:e +class Foo2X(x: 0 | 1) extends Foo2(x) { + fun test2 = Foo2X(1).x +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.40: fun test2 = Foo2X(1).x +//│ ╙── ^^ +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.39: class Foo2X(x: 0 | 1) extends Foo2(x) { +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.31: class Foo2[A](val x: A) { +//│ ╙── ^ +//│ class Foo2X(x: 0 | 1) extends Foo2 { +//│ fun test: 1 +//│ fun test2: error +//│ } + +:e +Foo2X(1).x +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.57: Foo2X(1).x +//│ ║ ^^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.39: class Foo2X(x: 0 | 1) extends Foo2(x) { +//│ ╙── ^ +//│ 0 | 1 | error +//│ res +//│ = 1 + +:e // TODO improve type checking +class Foo2X(a: 0 | 1) extends Foo2(a) { + fun test2 = Foo2X(1).x +} +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.70: fun test2 = Foo2X(1).x +//│ ╙── ^^ +//│ class Foo2X(a: 0 | 1) extends Foo2 { +//│ fun test: 1 +//│ fun test2: error +//│ } + +Foo2X(1).x +//│ 0 | 1 +//│ res +//│ = 1 + class Foo3[A](val x: A) { fun test = Foo3(1) @@ -57,8 +123,8 @@ class Foo4 { fun test = [Foo4.test] } //│ ╔══[ERROR] Class Foo4 cannot be instantiated as it exposes no such constructor -//│ ║ l.57: fun test = [Foo4.test] -//│ ╙── ^^^^ +//│ ║ l.123: fun test = [Foo4.test] +//│ ╙── ^^^^ //│ class Foo4 { //│ constructor() //│ fun test: [error] @@ -69,8 +135,8 @@ class Foo5(x: Int) { fun test = [Foo5(5).test] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.69: fun test = [Foo5(5).test] -//│ ╙── ^^^^^ +//│ ║ l.135: fun test = [Foo5(5).test] +//│ ╙── ^^^^^ //│ class Foo5(x: Int) { //│ fun test: [error] //│ } @@ -82,14 +148,14 @@ class Foo6[A](x: A) { fun test3 = [Foo6([x]).test3] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.80: fun test1 = [Foo6(x).test1] -//│ ╙── ^^^^^^ +//│ ║ l.146: fun test1 = [Foo6(x).test1] +//│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.81: fun test2 = [Foo6(123).test2] -//│ ╙── ^^^^^^ +//│ ║ l.147: fun test2 = [Foo6(123).test2] +//│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.82: fun test3 = [Foo6([x]).test3] -//│ ╙── ^^^^^^ +//│ ║ l.148: fun test3 = [Foo6([x]).test3] +//│ ╙── ^^^^^^ //│ class Foo6[A](x: A) { //│ fun test1: [error] //│ fun test2: [error] @@ -106,7 +172,7 @@ class Foo7[A](head: A, tail: Foo7[A] | N) { _ then tail.test1 } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.106: _ then tail.test1 +//│ ║ l.172: _ then tail.test1 //│ ╙── ^^^^^^ //│ class Foo7[A](head: A, tail: Foo7[A] | N) { //│ fun test1: error | A @@ -147,7 +213,7 @@ class Foo8[A](x: A) { x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.146: let tmp = Foo8(y).test1(x) +//│ ║ l.212: let tmp = Foo8(y).test1(x) //│ ╙── ^^^^^^ //│ class Foo8[A](x: A) { //│ fun test1: (y: anything) -> A diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index 81a2007a9e..c7dbaf9c84 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -175,7 +175,7 @@ M.x :e class C2 extends T1 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C2` +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C2` //│ ║ l.177: class C2 extends T1 //│ ║ ^^ //│ ╟── Declared here: @@ -193,7 +193,7 @@ abstract class C2 extends T1 :e class C3 extends C2 -//│ ╔══[ERROR] Member `x` is declared in parent but not implemented in `C3` +//│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C3` //│ ║ l.195: class C3 extends C2 //│ ║ ^^ //│ ╟── Declared here: diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index 562536b2c3..b48d617237 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -2,9 +2,7 @@ - - -// *** Class instantiation *** // +// *** First-class classes *** // class C @@ -12,130 +10,14 @@ class C //│ constructor() //│ } -new C -//│ C -//│ res -//│ = C {} - -// TODO Forbid? -new C() -//│ C -//│ res -//│ = C {} - -:e -C() -//│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword -//│ ║ l.27: C() -//│ ╙── ^ -//│ C -//│ res -//│ Runtime error: -//│ TypeError: Class constructor C cannot be invoked without 'new' - - -class D(x: Int) -//│ class D(x: Int) - -:js -D(0) -//│ D -//│ // Prelude -//│ class TypingUnit5 {} -//│ const typing_unit5 = new TypingUnit5; -//│ // Query 1 -//│ res = D(0); -//│ // End of generated code -//│ res -//│ = D {} - -// TODO reject or accept? -:js -new D(0) -//│ D -//│ // Prelude -//│ class TypingUnit6 {} -//│ const typing_unit6 = new TypingUnit6; -//│ // Query 1 -//│ res = new D.class(0); -//│ // End of generated code -//│ res -//│ = D {} - - - -// *** Explicit unapply *** // - - -// function D ... -// D.class = class D { #x; static unapply(self) { return [self.#x] } } -// D.unapply = D.class.unapply - - class D(x: Int) //│ class D(x: Int) -D.unapply -//│ forall 'x. (D & {x: 'x}) -> ['x] -//│ res -//│ = [Function: unapply] - -D.unapply(D(42)) -//│ [Int] -//│ res -//│ = [ 42 ] - -:e -D.unapply({ x: 42 }) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.89: D.unapply({ x: 42 }) -//│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── record literal of type `{x: 42}` is not an instance of type `D` -//│ ║ l.89: D.unapply({ x: 42 }) -//│ ╙── ^^ -//│ error | [42] -//│ res -//│ Runtime error: -//│ TypeError: Cannot read private member #x from an object whose class did not declare it - -class DT[T](x: T) -DT.unapply -//│ class DT[T](x: T) -//│ forall 'x. (DT[anything] & {x: 'x}) -> ['x] -//│ res -//│ = [Function: unapply] - -DT.unapply(DT(42)) -//│ [42] -//│ res -//│ = [ 42 ] - -:e -DT.unapply({ x: 42 }) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.114: DT.unapply({ x: 42 }) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── record literal of type `{x: 42}` is not an instance of type `DT` -//│ ║ l.114: DT.unapply({ x: 42 }) -//│ ╙── ^^ -//│ error | [42] -//│ res -//│ Runtime error: -//│ TypeError: Cannot read private member #x from an object whose class did not declare it - -// *** First-class classes *** // - - -class C -//│ class C { -//│ constructor() -//│ } - :e fun foo(c) = new c //│ ╔══[ERROR] Cannot use `new` on non-class variable of type ?a -//│ ║ l.135: fun foo(c) = new c -//│ ╙── ^^^^^ +//│ ║ l.17: fun foo(c) = new c +//│ ╙── ^^^^^ //│ fun foo: anything -> error :re @@ -148,8 +30,8 @@ foo(() => 123) :e foo(C) //│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword -//│ ║ l.149: foo(C) -//│ ╙── ^ +//│ ║ l.31: foo(C) +//│ ╙── ^ //│ error //│ res //│ = C {} @@ -158,8 +40,8 @@ foo(C) :e fun bar(c) = new c(123) //│ ╔══[ERROR] Cannot use `new` on non-class variable of type ?a -//│ ║ l.159: fun bar(c) = new c(123) -//│ ╙── ^^^^^^^^^^ +//│ ║ l.41: fun bar(c) = new c(123) +//│ ╙── ^^^^^^^^^^ //│ fun bar: anything -> error :re @@ -172,11 +54,11 @@ bar(D) :e // TODO accept when we have first-class classes bar(D.class) //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.173: bar(D.class) -//│ ║ ^^^^^^^ +//│ ║ l.55: bar(D.class) +//│ ║ ^^^^^^^ //│ ╟── reference of type `(x: Int) -> D` does not have field 'class' -//│ ║ l.173: bar(D.class) -//│ ╙── ^ +//│ ║ l.55: bar(D.class) +//│ ╙── ^ //│ error //│ res //│ = D {} @@ -194,8 +76,8 @@ class C :e // TODO new C { val x = 1 } //│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.195: new C { val x = 1 } -//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.77: new C { val x = 1 } +//│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: //│ custom class body is not supported yet @@ -219,7 +101,7 @@ let c = new Cls // FIXME let y: c.A = c.x //│ ╔══[ERROR] type identifier not found: c -//│ ║ l.220: let y: c.A = c.x +//│ ║ l.102: let y: c.A = c.x //│ ╙── ^ //│ /!!!\ Uncaught error: scala.NotImplementedError: an implementation is missing @@ -241,14 +123,14 @@ fun test(a: Object) = if a is Cls then a.x else error //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.240: fun test(a: Object) = if a is +//│ ║ l.122: fun test(a: Object) = if a is //│ ║ ^^^^ -//│ ║ l.241: Cls then a.x +//│ ║ l.123: Cls then a.x //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.242: else error +//│ ║ l.124: else error //│ ║ ^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.231: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } +//│ ║ l.113: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> (error | ??A) @@ -257,14 +139,14 @@ fun test(a: Object) = if a is Cls then a.g(a.x) // a.x : a.A ; a.g : a.A -> a.A else 0 //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.256: fun test(a: Object) = if a is +//│ ║ l.138: fun test(a: Object) = if a is //│ ║ ^^^^ -//│ ║ l.257: Cls then a.g(a.x) // a.x : a.A ; a.g : a.A -> a.A +//│ ║ l.139: Cls then a.g(a.x) // a.x : a.A ; a.g : a.A -> a.A //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.258: else 0 +//│ ║ l.140: else 0 //│ ║ ^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.231: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } +//│ ║ l.113: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> Int diff --git a/shared/src/test/diff/nu/Unapply.mls b/shared/src/test/diff/nu/Unapply.mls new file mode 100644 index 0000000000..627b325f75 --- /dev/null +++ b/shared/src/test/diff/nu/Unapply.mls @@ -0,0 +1,108 @@ +// *** Explicit unapply tests *** // + +:NewDefs + + +// * Unapply's current compilation strategy: +// function D ... +// D.class = class D { #x; static unapply(self) { return [self.#x] } } +// D.unapply = D.class.unapply + +class D(x: Int) +//│ class D(x: Int) + +D.unapply +//│ forall '#x. (D & {#x: '#x}) -> ['#x] +//│ res +//│ = [Function: unapply] + +D.unapply(D(42)) +//│ [Int] +//│ res +//│ = [ 42 ] + +:e +D.unapply({ x: 42 }) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.25: D.unapply({ x: 42 }) +//│ ║ ^^^^^^^^^^^^^^^^^^^^ +//│ ╟── record literal of type `{x: 42}` does not have field '#x' +//│ ║ l.25: D.unapply({ x: 42 }) +//│ ║ ^^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.11: class D(x: Int) +//│ ╙── ^ +//│ error | [nothing] +//│ res +//│ Runtime error: +//│ TypeError: Cannot read private member #x from an object whose class did not declare it + +class DT[T](x: T) +DT.unapply +//│ class DT[T](x: T) +//│ forall '#x. (DT[anything] & {#x: '#x}) -> ['#x] +//│ res +//│ = [Function: unapply] + +DT.unapply(DT(42)) +//│ [42] +//│ res +//│ = [ 42 ] + +:e +DT.unapply({ x: 42 }) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.53: DT.unapply({ x: 42 }) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── record literal of type `{x: 42}` does not have field '#x' +//│ ║ l.53: DT.unapply({ x: 42 }) +//│ ║ ^^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.40: class DT[T](x: T) +//│ ╙── ^ +//│ error | [nothing] +//│ res +//│ Runtime error: +//│ TypeError: Cannot read private member #x from an object whose class did not declare it + + +// * TODO improve `unapply` logic: currently it picks up shadowing fields/methods + +class Foo(x: Int) { + val x = toString(x) +} +//│ class Foo(x: Int) { +//│ let x: Str +//│ } + +// * Current hack: use `scrut.#x` to access a private field while passing the typer... +Foo.unapply +//│ forall '#x. (Foo & {#x: '#x}) -> ['#x] +//│ res +//│ = [Function: unapply] + +Foo.unapply(Foo(123)) +//│ [Str] +//│ res +//│ = [ '123' ] + +if Foo(123) is Foo(a) then a +//│ Str +//│ res +//│ = '123' + + + +// * Eventually we'll want to support this sort of overloading: +:e +fun D(x: Int) = {x} +module D { fun unapply(a) = [a.x] } +//│ ╔══[ERROR] Refininition of 'D' +//│ ║ l.99: module D { fun unapply(a) = [a.x] } +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ fun D: (x: Int) -> {x: Int} +//│ module D { +//│ fun unapply: forall 'x. {x: 'x} -> ['x] +//│ } + + diff --git a/shared/src/test/diff/nu/ValSigs.mls b/shared/src/test/diff/nu/ValSigs.mls index 134efcb94c..45982cc7f3 100644 --- a/shared/src/test/diff/nu/ValSigs.mls +++ b/shared/src/test/diff/nu/ValSigs.mls @@ -2,26 +2,46 @@ val x: Int -val x = 1 //│ let x: Int +//│ x +//│ = + +// * Note that this counts as a completely new `val` since it's in a new block +val x = "hi" +//│ let x: "hi" +//│ x +//│ = 'hi' + + +val x: Int +val x = 1 //│ let x: 1 +//│ let x: Int //│ x //│ = //│ x //│ = 1 -// * FIXME type x -//│ 1 +//│ Int //│ res //│ = 1 -// :e // FIXME should be an error +:e val x: Int val x = "oops" -//│ let x: Int +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.33: val x = "oops" +//│ ║ ^^^^^^^^^^ +//│ ╟── string literal of type `"oops"` is not an instance of type `Int` +//│ ║ l.33: val x = "oops" +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.32: val x: Int +//│ ╙── ^^^ //│ let x: "oops" +//│ let x: Int //│ x //│ = //│ x diff --git a/shared/src/test/diff/nu/Virtual.mls b/shared/src/test/diff/nu/Virtual.mls index 847fb2a432..137a9ee225 100644 --- a/shared/src/test/diff/nu/Virtual.mls +++ b/shared/src/test/diff/nu/Virtual.mls @@ -29,7 +29,7 @@ class Baz() extends Foo { //│ ╔══[ERROR] Value member `g` is not virtual and cannot be overridden //│ ║ l.27: val g = 1 //│ ║ ^^^^^ -//│ ╟── Declared here: +//│ ╟── Originally declared here: //│ ║ l.5: val g: Int = 0 //│ ╙── ^^^^^^^^^^ //│ class Baz() extends Foo { @@ -60,14 +60,14 @@ T().f(0 - 42) //│ res //│ = 42 -class M1() { +abstract class M1() { val foo: Str } class M2(s: Str) extends M1 { val foo = s } M2("foo").foo -//│ class M1() { +//│ abstract class M1() { //│ let foo: Str //│ } //│ class M2(s: Str) extends M1 { diff --git a/shared/src/test/diff/nu/repro0.mls b/shared/src/test/diff/nu/repro0.mls index 15a4cb7394..604c409c2f 100644 --- a/shared/src/test/diff/nu/repro0.mls +++ b/shared/src/test/diff/nu/repro0.mls @@ -2,7 +2,7 @@ :NoJS -class Add[E](lhs: E) +class Add[E](val lhs: E) val add11 = Add(add11) module EvalAddLit { fun eval(e: Add['A]) = diff --git a/shared/src/test/diff/nu/repro1.mls b/shared/src/test/diff/nu/repro1.mls index b7f0f9a1dc..09c7cb8328 100644 --- a/shared/src/test/diff/nu/repro1.mls +++ b/shared/src/test/diff/nu/repro1.mls @@ -2,7 +2,7 @@ :NoJS -class Union[out Region](a: Region) +class Union[out Region](val a: Region) // class Union[Region](a: Region) //│ class Union[Region](a: Region) diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index 62c9a44f48..c19a628eb4 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -8,10 +8,10 @@ let asNativeString: anything => { length: Int, charCodeAt: Int => Int, charAt: I let StringInstance: { fromCharCode: Int => Str } = String // We will validate our implementation with the built-in `JSON.parse`. let JSON: { parse: Str => anything, stringify: anything => Str } -//│ let String: nothing //│ let asNativeString: anything -> {charAt: Int -> Str, charCodeAt: Int -> Int, length: Int, slice: Int -> Str} //│ let StringInstance: {fromCharCode: Int -> Str} //│ let JSON: {parse: Str -> anything, stringify: anything -> Str} +//│ let String: nothing //│ String //│ = //│ asNativeString @@ -205,7 +205,7 @@ toString of JsonObject of insert(Empty, "hello", JsonString("world")) //│ res //│ = '{ hello: "world" }' -class Scanner(source: Str, at: Int) { +class Scanner(source: Str, val at: Int) { fun peek: Option[Str] = if at < strlen(source) then Some(getCharAtIndex(source, at)) else None fun advance: Scanner = From a87510934b528f9ec5530a460c37b454d98092b5 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 20 Sep 2023 00:48:41 +0800 Subject: [PATCH 447/498] Fix pretty-printing of `val` members --- shared/src/main/scala/mlscript/helpers.scala | 10 ++----- .../src/test/diff/codegen/ConstructorStmt.mls | 4 +-- .../src/test/diff/codegen/FieldOverride.mls | 10 +++---- .../test/diff/codegen/MemberInitShadowing.mls | 2 +- shared/src/test/diff/codegen/Nested.mls | 10 +++---- shared/src/test/diff/codegen/NewMatching.mls | 2 +- shared/src/test/diff/codegen/NuClasses.mls | 4 +-- shared/src/test/diff/codegen/Super.mls | 10 +++---- shared/src/test/diff/codegen/SymbolicOps.mls | 2 +- shared/src/test/diff/codegen/ValLet.mls | 6 ++-- shared/src/test/diff/nu/AbstractClasses.mls | 2 +- shared/src/test/diff/nu/BadClassInherit.mls | 6 ++-- shared/src/test/diff/nu/BadClasses.mls | 2 +- shared/src/test/diff/nu/BadFieldInit.mls | 8 ++--- shared/src/test/diff/nu/BasicMixins.mls | 4 +-- shared/src/test/diff/nu/ClassesInMixins.mls | 4 +-- shared/src/test/diff/nu/Declarations.mls | 2 +- shared/src/test/diff/nu/FlatMonads.mls | 14 ++++----- .../test/diff/nu/GenericClassInheritance.mls | 4 +-- .../src/test/diff/nu/ImplicitMethodPolym.mls | 2 +- shared/src/test/diff/nu/Interfaces.mls | 12 ++++---- shared/src/test/diff/nu/MemberConfusion.mls | 4 +-- .../src/test/diff/nu/MemberIntersections.mls | 4 +-- shared/src/test/diff/nu/Mixin42.mls | 22 +++++++------- shared/src/test/diff/nu/NoThisCtor.mls | 30 +++++++++---------- shared/src/test/diff/nu/ParamPassing.mls | 4 +-- .../test/diff/nu/RawUnionTraitSignatures.mls | 4 +-- shared/src/test/diff/nu/SimpleTraitImpl.mls | 10 +++---- shared/src/test/diff/nu/TraitSignatures.mls | 2 +- .../test/diff/nu/TrickyGenericInheritance.mls | 8 ++--- shared/src/test/diff/nu/Unapply.mls | 2 +- shared/src/test/diff/nu/ValSigs.mls | 24 ++++++++------- shared/src/test/diff/nu/Vals.mls | 14 ++++----- shared/src/test/diff/nu/Virtual.mls | 14 ++++----- shared/src/test/diff/nu/repro0.mls | 2 +- 35 files changed, 132 insertions(+), 132 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index d49f520a5c..991a30b390 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -132,10 +132,10 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Bounds(lo, hi) => s"\n${ctx.indStr}${lo.showIn(ctx, 0)} <: ${hi.showIn(ctx, 0)}" // TODO print differently from bs? }.mkString}" }, outerPrec > 0) - case NuFunDef(isLetRec, nme, snme, targs, rhs) => + case fd @ NuFunDef(isLetRec, nme, snme, targs, rhs) => s"${isLetRec match { - case S(false) => "let" - case S(true) => "let rec" + case S(false) => if (fd.genField) "val" else "let" + case S(true) => if (fd.genField) die else "let rec" case N => "fun" }}${snme.fold("")(" (" + _.name + ")") } ${nme.name}${targs.map(_.showIn(ctx, 0)).mkStringOr(", ", "[", "]")}${rhs match { @@ -143,13 +143,9 @@ trait TypeLikeImpl extends Located { self: TypeLike => case R(ty) => ": " + ty.showIn(ctx, 0) }}" case Signature(decls, res) => - // decls.map(ctx.indStr + (if (ctx.indentLevel === 0) "" else "\n") + _.showIn(ctx, 0)).mkString + (decls.map(ctx.indStr + _.showIn(ctx, 0) + "\n") ::: (res match { case S(ty) => ctx.indStr + ty.showIn(ctx, 0) + "\n" :: Nil case N => Nil - // })).mkString(if (ctx.indentLevel === 0) "" else "\n", "\n", "") - // })).mkString("\n") - // })).mkString("", "\n", "\n") })).mkString case NuTypeDef(kind @ Als, nme, tparams, params, ctor, sig, parents, sup, ths, body) => assert(params.isEmpty, params) diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 83efd3c333..b4ecfe328a 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -209,8 +209,8 @@ class Baz() { log((3, y)) } //│ class Baz() { -//│ let x: 123 -//│ let y: Int +//│ val x: 123 +//│ val y: Int //│ } //│ // Prelude //│ class TypingUnit10 { diff --git a/shared/src/test/diff/codegen/FieldOverride.mls b/shared/src/test/diff/codegen/FieldOverride.mls index 3935fc6084..0fb2afb424 100644 --- a/shared/src/test/diff/codegen/FieldOverride.mls +++ b/shared/src/test/diff/codegen/FieldOverride.mls @@ -4,7 +4,7 @@ :js class C(a: Int) { val a = 1 } //│ class C(a: Int) { -//│ let a: 1 +//│ val a: 1 //│ } //│ // Prelude //│ let res; @@ -55,8 +55,8 @@ class C2(a: Int, b: Int) { val b = a + 1 } //│ class C2(a: Int, b: Int) { -//│ let a: Int -//│ let b: Int +//│ val a: Int +//│ val b: Int //│ } //│ // Prelude //│ class TypingUnit2 { @@ -118,9 +118,9 @@ class C3(a: Int) { } //│ class C3(a: Int) { //│ class C4(a: Int) { -//│ let a: 44 +//│ val a: 44 //│ } -//│ let a: 42 +//│ val a: 42 //│ } :e diff --git a/shared/src/test/diff/codegen/MemberInitShadowing.mls b/shared/src/test/diff/codegen/MemberInitShadowing.mls index ccd40adc76..96682546ec 100644 --- a/shared/src/test/diff/codegen/MemberInitShadowing.mls +++ b/shared/src/test/diff/codegen/MemberInitShadowing.mls @@ -63,7 +63,7 @@ class A(x0: Int) { log(x1) } //│ class A(x0: Int) { -//│ let x1: Int +//│ val x1: Int //│ } //│ // Prelude //│ class TypingUnit2 { diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 46dfc45ce9..b3a935e0e3 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -12,7 +12,7 @@ module A { //│ class B(x: Int) { //│ fun b: Int //│ } -//│ let a: 42 +//│ val a: 42 //│ } //│ // Prelude //│ let res; @@ -110,10 +110,10 @@ d.outer //│ ╙── ^^ //│ class B(x: Int) { //│ class C(y: Int) { -//│ let outer1: Int +//│ val outer1: Int //│ } //│ class D(outer: Int) -//│ let outer: 42 +//│ val outer: 42 //│ } //│ let b: B //│ let c: error @@ -582,7 +582,7 @@ module H { //│ module H { //│ class I(x: Int) //│ class J(x: Int) { -//│ let i: I +//│ val i: I //│ } //│ } //│ // Prelude @@ -1186,7 +1186,7 @@ I(1).J(3).a //│ ╙── ^^ //│ class I(x: Int) { //│ class J(z: Int) { -//│ let a: [Int, Int, Int] +//│ val a: [Int, Int, Int] //│ } //│ let y: Int //│ } diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index a9654c3102..53d1897942 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -163,7 +163,7 @@ class FooBar { } //│ class FooBar { //│ constructor() -//│ let x: 42 +//│ val x: 42 //│ } //│ // Prelude //│ class TypingUnit12 { diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index afc1f5e582..f7e70bc421 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -106,7 +106,7 @@ mixin M0(n: Int) { //│ mixin M0(n: Int) { //│ fun bar: Int //│ fun foo: [Int, Int, Int] -//│ let m: Int +//│ val m: Int //│ } module M1 extends M0(123) { @@ -145,7 +145,7 @@ module M2 { //│ ╙── ^^ //│ module M2 { //│ fun foo: Int -> Int -//│ let m: 100 +//│ val m: 100 //│ } //│ // Prelude //│ class TypingUnit11 { diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index 467d4259fa..c56042ec20 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -7,7 +7,7 @@ mixin Foo0 { val foo0 = 0 } //│ mixin Foo0() { -//│ let foo0: 0 +//│ val foo0: 0 //│ } //│ // Prelude //│ let res; @@ -38,8 +38,8 @@ mixin Foo1 { } //│ mixin Foo1() { //│ super: {foo0: 'foo0} -//│ let foo0: 1 -//│ let foo1: 'foo0 +//│ val foo0: 1 +//│ val foo1: 'foo0 //│ } //│ // Prelude //│ class TypingUnit1 { @@ -68,8 +68,8 @@ mixin Foo1 { module Test0 extends Foo0, Foo1 //│ module Test0 { -//│ let foo0: 1 -//│ let foo1: 0 +//│ val foo0: 1 +//│ val foo1: 0 //│ } [Test0.foo0, Test0.foo1] diff --git a/shared/src/test/diff/codegen/SymbolicOps.mls b/shared/src/test/diff/codegen/SymbolicOps.mls index c2e09605e4..b3f2fc73e9 100644 --- a/shared/src/test/diff/codegen/SymbolicOps.mls +++ b/shared/src/test/diff/codegen/SymbolicOps.mls @@ -313,7 +313,7 @@ fun (:-D) dd(a, b) = a + b val (->) f(x, y) = [x, y] -//│ let (->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] +//│ val (->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] //│ f //│ = [Function: f1] diff --git a/shared/src/test/diff/codegen/ValLet.mls b/shared/src/test/diff/codegen/ValLet.mls index 763fc577fc..0f8b1fc5e2 100644 --- a/shared/src/test/diff/codegen/ValLet.mls +++ b/shared/src/test/diff/codegen/ValLet.mls @@ -11,7 +11,7 @@ class A(x0: Int) { //│ class A(x0: Int) { //│ let x1: Int //│ let x2: Int -//│ let x3: Int +//│ val x3: Int //│ } //│ // Prelude //│ function log(x) { @@ -249,7 +249,7 @@ class E(x: Int) { } if E(42) is E(x) then x else 0 //│ class E(x: Int) { -//│ let x: 2 +//│ val x: 2 //│ } //│ 0 | 2 //│ res @@ -271,7 +271,7 @@ class G(val x: Int) { } G(1).x //│ class G(x: Int) { -//│ let x: 4 +//│ val x: 4 //│ } //│ 4 //│ res diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index b8eb1aa4cb..bb3876874d 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -177,7 +177,7 @@ abstract class C { //│ abstract class C { //│ fun foo0: Int //│ fun foo1: Int -//│ let x: Int +//│ val x: Int //│ } diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index ab3724c9c1..82cec66949 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -18,7 +18,7 @@ class C2(x: Int) extends C1(y) { //│ ║ l.4: class C1(x: Int) //│ ╙── ^ //│ class C2(x: Int) extends C1 { -//│ let y: Int +//│ val y: Int //│ } //│ Code generation encountered an error: //│ unresolved symbol y @@ -31,7 +31,7 @@ abstract class C2 extends C1(y) { //│ ║ l.27: abstract class C2 extends C1(y) { //│ ╙── ^ //│ abstract class C2 extends C1 { -//│ let y: Int +//│ val y: Int //│ } //│ Code generation encountered an error: //│ unresolved symbol y @@ -44,7 +44,7 @@ abstract class C2 extends C1(this.y) { //│ ║ l.40: abstract class C2 extends C1(this.y) { //│ ╙── ^^^^ //│ abstract class C2 extends C1 { -//│ let y: Int +//│ val y: Int //│ } diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index e1daa4f63c..79497a629b 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -143,7 +143,7 @@ class C { val x: Int } //│ ╙── ^^^^^^ //│ class C { //│ constructor() -//│ let x: Int +//│ val x: Int //│ } diff --git a/shared/src/test/diff/nu/BadFieldInit.mls b/shared/src/test/diff/nu/BadFieldInit.mls index e145553678..132ea48f4a 100644 --- a/shared/src/test/diff/nu/BadFieldInit.mls +++ b/shared/src/test/diff/nu/BadFieldInit.mls @@ -8,8 +8,8 @@ module A { val y = x } //│ module A { -//│ let x: nothing -//│ let y: nothing +//│ val x: nothing +//│ val y: nothing //│ } //│ // Prelude //│ let res; @@ -55,8 +55,8 @@ module A { val y = 1 } //│ module A { -//│ let x: 1 -//│ let y: 1 +//│ val x: 1 +//│ val y: 1 //│ } //│ // Prelude //│ class TypingUnit2 { diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 60d500da85..b9a39ae0e7 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -5,7 +5,7 @@ mixin Base { val base = 42 } //│ mixin Base() { -//│ let base: 42 +//│ val base: 42 //│ } mixin BaseTest { @@ -19,7 +19,7 @@ mixin BaseTest { module Base0 extends Base, BaseTest //│ module Base0 { -//│ let base: 42 +//│ val base: 42 //│ fun test: 42 //│ } diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index bf6d759ecb..56a7b4fed4 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -8,13 +8,13 @@ mixin Test { } //│ mixin Test() { //│ class Foo(n: Int) -//│ let f: Foo +//│ val f: Foo //│ } module M extends Test //│ module M { //│ class Foo(n: Int) -//│ let f: Foo +//│ val f: Foo //│ } M.f diff --git a/shared/src/test/diff/nu/Declarations.mls b/shared/src/test/diff/nu/Declarations.mls index a62a6529b9..8f0c1e015b 100644 --- a/shared/src/test/diff/nu/Declarations.mls +++ b/shared/src/test/diff/nu/Declarations.mls @@ -97,7 +97,7 @@ declare module Buffer { } //│ declare module Buffer { //│ abstract class Buffer2 { -//│ let length: Int +//│ val length: Int //│ } //│ fun bar: Int //│ fun from: (a: Array[Int]) -> Buffer2 diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index afd9bb3c3e..80df624236 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -56,7 +56,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ let main: Bind['A, 'B] +//│ val main: Bind['A, 'B] //│ where //│ 'B :> Int //│ 'A <: undefined @@ -80,7 +80,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ let main: Bind['A, 'B] +//│ val main: Bind['A, 'B] //│ where //│ 'B :> Int //│ 'A <: undefined @@ -182,7 +182,7 @@ val main = //│ ╟── Note: constraint arises from reference: //│ ║ l.125: val sum = n + m //│ ╙── ^ -//│ let main: IO['B] | error +//│ val main: IO['B] | error //│ main //│ = Bind {} @@ -200,7 +200,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)) |>= _ => Pure(sum) -//│ let main: Bind[nothing, 'B] +//│ val main: Bind[nothing, 'B] //│ where //│ 'B :> Int //│ main @@ -230,7 +230,7 @@ fun main(ctx) = //│ fun main: forall 'a 'b. {printLine: Str -> {bind: (Int -> ('a | 'b)) -> 'a}, pure: Int -> 'b, readInt: {bind: (Int -> ('a | 'b)) -> 'a}} -> 'a val defaultCtx = {printLine, readInt, pure: Pure} -//│ let defaultCtx: {printLine: (str: Str) -> printLine, pure: forall 'A. (value: 'A) -> Pure['A], readInt: readInt} +//│ val defaultCtx: {printLine: (str: Str) -> printLine, pure: forall 'A. (value: 'A) -> Pure['A], readInt: readInt} //│ defaultCtx //│ = { //│ printLine: [Function (anonymous)] { @@ -299,7 +299,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ let main: Bind['A, 'B] +//│ val main: Bind['A, 'B] //│ where //│ 'B :> Int //│ main @@ -367,7 +367,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)) of _ => pure(sum) -//│ let main: IO['b] +//│ val main: IO['b] //│ where //│ 'b :> Int diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 4c26146966..43eb81cc41 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -76,13 +76,13 @@ class WrongRoom extends Room[Bool]("wrong") { abstract class C0[A] { val a: A } //│ abstract class C0[A] { -//│ let a: A +//│ val a: A //│ } class C1[A] extends C0[A] { val a = a } //│ class C1[A] extends C0 { //│ constructor() -//│ let a: nothing +//│ val a: nothing //│ } new C1 : C1[Int] diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 65102eaedd..1c813490f2 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -53,7 +53,7 @@ module M extends Mx { } //│ module M { //│ fun id1: forall 'a. ('b & 'a) -> (0 | 'a) -//│ let r: 0 | 'b +//│ val r: 0 | 'b //│ } mixin Mx { diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 4c2527d23b..48145f48c9 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -858,7 +858,7 @@ class Bc02() extends Bc1(1:Int) { //│ ║ l.830: class Bc1(foo: Int) //│ ╙── ^^^ //│ class Bc02() extends Bc1 { -//│ let foo: 2 +//│ val foo: 2 //│ } Bc02().foo @@ -1062,8 +1062,8 @@ trait Ta[T] { } class K[A](val k: Ta[A]) //│ trait Ta[T] { -//│ let g: T -//│ let p: Bool +//│ val g: T +//│ val p: Bool //│ } //│ class K[A](k: Ta[A]) @@ -1104,8 +1104,8 @@ trait Tb extends Ta[Int] { //│ ║ l.1101: virtual val p = false //│ ╙── ^^^^^^^^^ //│ trait Tb extends Ta { -//│ let g: 'T -//│ let p: false +//│ val g: 'T +//│ val p: false //│ } //│ where //│ 'T := Int @@ -1195,7 +1195,7 @@ class Go extends Fate { class Ha { virtual val x: Int = 1 } //│ class Ha { //│ constructor() -//│ let x: Int +//│ val x: Int //│ } class Haha(x: 1 | 2) extends Ha diff --git a/shared/src/test/diff/nu/MemberConfusion.mls b/shared/src/test/diff/nu/MemberConfusion.mls index b50809f2ff..f63c6da4fc 100644 --- a/shared/src/test/diff/nu/MemberConfusion.mls +++ b/shared/src/test/diff/nu/MemberConfusion.mls @@ -14,7 +14,7 @@ class C(a: Int) extends T class B { virtual val a = "hi" } //│ class B { //│ constructor() -//│ let a: "hi" +//│ val a: "hi" //│ } :e @@ -37,7 +37,7 @@ mixin M { let b = "hi" } class B { virtual val a = 1 : Int } //│ class B { //│ constructor() -//│ let a: Int +//│ val a: Int //│ } class C(val a: Int, val b: Int) extends B, M diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index 6f23b2825e..1eaf1dcb92 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -60,7 +60,7 @@ trait S3 extends S1, S2 trait S1 { val f: Int -> Int } //│ trait S1 { -//│ let f: Int -> Int +//│ val f: Int -> Int //│ } trait S2 extends T1, S1 @@ -78,7 +78,7 @@ class C1(val x: Int | Bool) trait T1 { val x: Int | Str } //│ class C1(x: Int | false | true) //│ trait T1 { -//│ let x: Int | Str +//│ val x: Int | Str //│ } class C2() extends C1(0), T1 diff --git a/shared/src/test/diff/nu/Mixin42.mls b/shared/src/test/diff/nu/Mixin42.mls index 09e0b9bc9e..4bede9b036 100644 --- a/shared/src/test/diff/nu/Mixin42.mls +++ b/shared/src/test/diff/nu/Mixin42.mls @@ -16,10 +16,10 @@ C1().test //│ fun test: Int //│ } //│ mixin M3() { -//│ let factor: 2 +//│ val factor: 2 //│ } //│ class C1() { -//│ let factor: 2 +//│ val factor: 2 //│ fun test: Int //│ } //│ Int @@ -51,7 +51,7 @@ class C1() extends M1, M2 { val factor = 2 } //│ ║ l.6: mixin M2 { fun test = super.test * this.factor } //│ ╙── ^^^^^^^ //│ class C1() { -//│ let factor: 2 +//│ val factor: 2 //│ fun test: Int //│ } @@ -62,7 +62,7 @@ class C1() extends M1, M2 { val factor: Int = 2 } //│ ║ l.6: mixin M2 { fun test = super.test * this.factor } //│ ╙── ^^^^^^^ //│ class C1() { -//│ let factor: Int +//│ val factor: Int //│ fun test: Int //│ } @@ -71,11 +71,11 @@ abstract class C1 extends M1, M2 { val factor: Int } module C2 extends C1 { val factor = 2 } C2.test //│ abstract class C1 { -//│ let factor: Int +//│ val factor: Int //│ fun test: Int //│ } //│ module C2 extends C1 { -//│ let factor: 2 +//│ val factor: 2 //│ fun test: Int //│ } //│ Int @@ -86,7 +86,7 @@ C2.test class C1() extends M1, M2 { val factor: Int; val factor = 2 } C1().test //│ class C1() { -//│ let factor: Int +//│ val factor: Int //│ fun test: Int //│ } //│ Int @@ -96,7 +96,7 @@ C1().test abstract class C0 { val factor = 2 } //│ abstract class C0 { -//│ let factor: 2 +//│ val factor: 2 //│ } :e @@ -105,14 +105,14 @@ class C1() extends C0, M1, M2 //│ ║ l.6: mixin M2 { fun test = super.test * this.factor } //│ ╙── ^^^^^^^ //│ class C1() extends C0 { -//│ let factor: 2 +//│ val factor: 2 //│ fun test: Int //│ } abstract class C0 { val factor: Int } //│ abstract class C0 { -//│ let factor: Int +//│ val factor: Int //│ } :e // * TODO support @@ -121,7 +121,7 @@ class C1() extends C0, M1, M2 { val factor = 2 } //│ ║ l.6: mixin M2 { fun test = super.test * this.factor } //│ ╙── ^^^^^^^ //│ class C1() extends C0 { -//│ let factor: 2 +//│ val factor: 2 //│ fun test: Int //│ } diff --git a/shared/src/test/diff/nu/NoThisCtor.mls b/shared/src/test/diff/nu/NoThisCtor.mls index 104c381d08..59577268a1 100644 --- a/shared/src/test/diff/nu/NoThisCtor.mls +++ b/shared/src/test/diff/nu/NoThisCtor.mls @@ -15,7 +15,7 @@ class Foo() { virtual val foo: Int = 42 } //│ class Foo() { -//│ let foo: Int +//│ val foo: Int //│ } :e @@ -28,7 +28,7 @@ class Foo1() extends Foo() { //│ ║ l.25: log(this.foo) //│ ╙── ^^^^ //│ class Foo1() extends Foo { -//│ let foo: Int +//│ val foo: Int //│ } // FIXME: reject access to `this` from constructor @@ -44,7 +44,7 @@ class Foo2() extends Foo() { //│ ╙── ^^^^ //│ class Foo2() extends Foo { //│ constructor() -//│ let foo: Int +//│ val foo: Int //│ } :e @@ -57,8 +57,8 @@ class Foo3() extends Foo() { //│ ║ l.54: val s = this.foo //│ ╙── ^^^^ //│ class Foo3() extends Foo { -//│ let foo: Int -//│ let s: Int +//│ val foo: Int +//│ val s: Int //│ } :e @@ -77,7 +77,7 @@ class Foo4() extends Foo() { //│ class Foo4() extends Foo { //│ fun bar: Int -> Int //│ let bb: Int -//│ let foo: Int +//│ val foo: Int //│ } :e @@ -94,8 +94,8 @@ class Foo5() extends Foo() { //│ ╙── ^^^^ //│ class Foo5() extends Foo { //│ fun bar: (y: Int) -> Int -//│ let foo: Int -//│ let x: Int +//│ val foo: Int +//│ val x: Int //│ } class Foo6() extends Foo() { @@ -104,9 +104,9 @@ class Foo6() extends Foo() { val y = this.baz // baz is final } //│ class Foo6() extends Foo { -//│ let baz: Int -//│ let foo: Int -//│ let y: Int +//│ val baz: Int +//│ val foo: Int +//│ val y: Int //│ } class Bar() { @@ -116,7 +116,7 @@ class Bar() { } //│ class Bar() { //│ fun add: Int -> Int -//│ let d: Int +//│ val d: Int //│ } :e @@ -134,8 +134,8 @@ class Bar2() extends Bar() { //│ ╙── ^^^^ //│ class Bar2() extends Bar { //│ fun add: Int -> Int -//│ let d: Int -//│ let two: error +//│ val d: Int +//│ val two: error //│ } // it accesses this in an unusual way! @@ -152,5 +152,5 @@ abstract class Foo: Int -> Int { //│ ╙── ^^^^ //│ abstract class Foo: Int -> Int { //│ fun f: nothing -//│ let x: nothing +//│ val x: nothing //│ } diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index ab7fdb58fa..d4c0c0fb63 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -151,7 +151,7 @@ class Bar extends Foo(1) { val x: 2 } //│ ╙── ^ //│ class Bar extends Foo { //│ constructor() -//│ let x: 2 +//│ val x: 2 //│ } :e @@ -243,7 +243,7 @@ module Bazz extends Foo(0) { //│ ╙── ^^^^^^^^^ //│ module Bazz extends Foo { //│ fun i: 'A -> 'A -//│ let x: 2 +//│ val x: 2 //│ fun y: 'A //│ } //│ where diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index 2ee3145928..a74093f24b 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -55,7 +55,7 @@ trait Base1: Foo trait Base1: Foo { val x: Int } //│ trait Base1: #Foo { -//│ let x: Int +//│ val x: Int //│ } (b: Base1) => b.x @@ -66,7 +66,7 @@ trait Base1: Foo { val x: Int } trait Base1: Foo[1 | 2] { val x: 0 | 1 } //│ trait Base1: Foo[1 | 2] { -//│ let x: 0 | 1 +//│ val x: 0 | 1 //│ } (b: Base1) => b.x diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index c7dbaf9c84..1b89c895fb 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -341,13 +341,13 @@ trait T2 { val r = 1(1) } //│ ║ l.333: trait T2 { val r = 1(1) } //│ ╙── ^ //│ trait T2 { -//│ let r: error +//│ val r: error //│ } class C2 extends T2 //│ class C2 extends T2 { //│ constructor() -//│ let r: error +//│ val r: error //│ } @@ -363,11 +363,11 @@ class C2 extends T3[Int] //│ ║ l.356: val r = C2().x //│ ╙── ^^ //│ trait T3[A] { -//│ let r: error +//│ val r: error //│ } //│ class C2 extends T3 { //│ constructor() -//│ let r: error +//│ val r: error //│ } :e // * Note: lack of hygiene... happens only if class shadows previous C2 and is part of the error-throwing block @@ -380,7 +380,7 @@ C2() : T3['X] class C3 extends T3[Int] //│ class C3 extends T3 { //│ constructor() -//│ let r: error +//│ val r: error //│ } (new C3) : T3['X] diff --git a/shared/src/test/diff/nu/TraitSignatures.mls b/shared/src/test/diff/nu/TraitSignatures.mls index 7cf6b2eab1..698cae9273 100644 --- a/shared/src/test/diff/nu/TraitSignatures.mls +++ b/shared/src/test/diff/nu/TraitSignatures.mls @@ -8,7 +8,7 @@ declare trait Foo: (x: Num) => Num { val y: Str } //│ declare trait Foo: (x: Num) -> Num { -//│ let y: Str +//│ val y: Str //│ } (f: Foo) => [f.y, f(0)] diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index 6191d1589c..1abcd36edc 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -103,12 +103,12 @@ class C2 extends T2['FigureItOut] { //│ ╙── ^^ //│ trait T2[A] { //│ fun f: A -> A -//│ let r: error +//│ val r: error //│ } //│ class C2 extends T2 { //│ constructor() //│ fun f: (x: Int) -> Int -//│ let r: error +//│ val r: error //│ } :e @@ -127,12 +127,12 @@ class C3 extends T3['FigureItOut] { //│ ╙── ^^ //│ trait T3[A] { //│ fun f: A -> A -//│ let r: false +//│ val r: false //│ } //│ class C3 extends T3 { //│ constructor() //│ fun f: (x: Int) -> Int -//│ let r: false +//│ val r: false //│ } :e // FIXME diff --git a/shared/src/test/diff/nu/Unapply.mls b/shared/src/test/diff/nu/Unapply.mls index 627b325f75..06066e48c2 100644 --- a/shared/src/test/diff/nu/Unapply.mls +++ b/shared/src/test/diff/nu/Unapply.mls @@ -72,7 +72,7 @@ class Foo(x: Int) { val x = toString(x) } //│ class Foo(x: Int) { -//│ let x: Str +//│ val x: Str //│ } // * Current hack: use `scrut.#x` to access a private field while passing the typer... diff --git a/shared/src/test/diff/nu/ValSigs.mls b/shared/src/test/diff/nu/ValSigs.mls index 45982cc7f3..01cc07e753 100644 --- a/shared/src/test/diff/nu/ValSigs.mls +++ b/shared/src/test/diff/nu/ValSigs.mls @@ -2,28 +2,32 @@ val x: Int -//│ let x: Int +//│ val x: Int //│ x //│ = // * Note that this counts as a completely new `val` since it's in a new block val x = "hi" -//│ let x: "hi" +//│ val x: "hi" //│ x //│ = 'hi' val x: Int val x = 1 -//│ let x: 1 -//│ let x: Int +//│ val x: 1 +//│ val x: Int //│ x //│ = //│ x //│ = 1 +val x = 1 +//│ val x: 1 +//│ x +//│ = 1 x -//│ Int +//│ 1 //│ res //│ = 1 @@ -32,16 +36,16 @@ x val x: Int val x = "oops" //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.33: val x = "oops" +//│ ║ l.37: val x = "oops" //│ ║ ^^^^^^^^^^ //│ ╟── string literal of type `"oops"` is not an instance of type `Int` -//│ ║ l.33: val x = "oops" +//│ ║ l.37: val x = "oops" //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.32: val x: Int +//│ ║ l.36: val x: Int //│ ╙── ^^^ -//│ let x: "oops" -//│ let x: Int +//│ val x: "oops" +//│ val x: Int //│ x //│ = //│ x diff --git a/shared/src/test/diff/nu/Vals.mls b/shared/src/test/diff/nu/Vals.mls index 14602aa1a5..5a5a62a811 100644 --- a/shared/src/test/diff/nu/Vals.mls +++ b/shared/src/test/diff/nu/Vals.mls @@ -3,8 +3,8 @@ val a = 1 val b = a + 1 -//│ let a: 1 -//│ let b: Int +//│ val a: 1 +//│ val b: Int //│ a //│ = 1 //│ b @@ -15,21 +15,21 @@ val b = a + 1 :ge val c = d + 1 val d = 1 -//│ let c: Int -//│ let d: 1 +//│ val c: Int +//│ val d: 1 //│ Code generation encountered an error: //│ unresolved symbol d // :e // FIXME should not type check val a = a -//│ let a: nothing +//│ val a: nothing //│ a //│ = 1 val f(x) = x -//│ let f: forall 'a. 'a -> 'a +//│ val f: forall 'a. 'a -> 'a //│ f //│ = [Function: f] @@ -44,7 +44,7 @@ module M { val f(x) = x + tmp } //│ module M { -//│ let f: Int -> Int +//│ val f: Int -> Int //│ let tmp: 2 //│ } diff --git a/shared/src/test/diff/nu/Virtual.mls b/shared/src/test/diff/nu/Virtual.mls index 137a9ee225..8782ab7cd7 100644 --- a/shared/src/test/diff/nu/Virtual.mls +++ b/shared/src/test/diff/nu/Virtual.mls @@ -6,7 +6,7 @@ class Foo() { } //│ class Foo() { //│ fun f: (x: Int) -> Int -//│ let g: Int +//│ val g: Int //│ } class Bar() extends Foo { @@ -14,7 +14,7 @@ class Bar() extends Foo { } //│ class Bar() extends Foo { //│ fun f: (x: Int) -> Int -//│ let g: Int +//│ val g: Int //│ } Bar().f(40) @@ -34,7 +34,7 @@ class Baz() extends Foo { //│ ╙── ^^^^^^^^^^ //│ class Baz() extends Foo { //│ fun f: (x: Int) -> Int -//│ let g: 1 +//│ val g: 1 //│ } mixin X { @@ -68,10 +68,10 @@ class M2(s: Str) extends M1 { } M2("foo").foo //│ abstract class M1() { -//│ let foo: Str +//│ val foo: Str //│ } //│ class M2(s: Str) extends M1 { -//│ let foo: Str +//│ val foo: Str //│ } //│ Str //│ res @@ -98,7 +98,7 @@ class V1() { //│ ╙── ^^^^^^ //│ class V1() { //│ fun foo: 42 -//│ let x: 42 +//│ val x: 42 //│ } class V2() { @@ -108,7 +108,7 @@ class V2() { } //│ class V2() { //│ fun foo: Int -//│ let x: Int +//│ val x: Int //│ } diff --git a/shared/src/test/diff/nu/repro0.mls b/shared/src/test/diff/nu/repro0.mls index 604c409c2f..72b3f9fadf 100644 --- a/shared/src/test/diff/nu/repro0.mls +++ b/shared/src/test/diff/nu/repro0.mls @@ -10,7 +10,7 @@ module EvalAddLit { } let res = EvalAddLit.eval(add11) //│ class Add[E](lhs: E) -//│ let add11: 'E +//│ val add11: 'E //│ module EvalAddLit { //│ fun eval: forall 'lhs 'A. (e: 'lhs) -> nothing //│ } From 14829db8da00e7af8827293bf7b54f6174b8e7f2 Mon Sep 17 00:00:00 2001 From: NeilKleistGao Date: Mon, 18 Sep 2023 20:36:03 +0800 Subject: [PATCH 448/498] Type constructor and check this access --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- .../diff/codegen/AuxiliaryConstructors.mls | 35 +++++++++++++++++++ shared/src/test/diff/nu/NoThisCtor.mls | 25 +++++++------ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 515d491c07..38d6730570 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1565,7 +1565,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => qualificationCheck(toCheckImplems, td.body.entities.filter { case _: NuDecl => false case _ => true - }, baseClsMembers, clsSigns) + } ++ td.ctor.fold[Ls[Statement]](Nil)(s => s.body.stmts), baseClsMembers, clsSigns) }() // * Those member implementations we inherit from the base class that are not overridden diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls index 7003cc9827..438107085f 100644 --- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -542,4 +542,39 @@ mixin P { //│ } //│ mixin P() +:w +:e +class QQ(qq: Str) { + constructor(foo: Int) { + lol + qq = foo + } +} +//│ ╔══[ERROR] identifier not found: lol +//│ ║ l.549: lol +//│ ╙── ^^^ +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.549: lol +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in auxiliary class constructor: +//│ ║ l.548: constructor(foo: Int) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.549: lol +//│ ║ ^^^^^^^ +//│ ║ l.550: qq = foo +//│ ║ ^^^^^^^^^^^^ +//│ ╟── type `Int` is not an instance of `Str` +//│ ║ l.548: constructor(foo: Int) { +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `Str` +//│ ║ l.550: qq = foo +//│ ║ ^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.547: class QQ(qq: Str) { +//│ ╙── ^^^ +//│ class QQ(qq: Str) { +//│ constructor(foo: Int) +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol lol diff --git a/shared/src/test/diff/nu/NoThisCtor.mls b/shared/src/test/diff/nu/NoThisCtor.mls index 59577268a1..0493ba15e1 100644 --- a/shared/src/test/diff/nu/NoThisCtor.mls +++ b/shared/src/test/diff/nu/NoThisCtor.mls @@ -31,7 +31,7 @@ class Foo1() extends Foo() { //│ val foo: Int //│ } -// FIXME: reject access to `this` from constructor +:e class Foo2() extends Foo() { virtual val foo: Int val foo = 2 @@ -39,6 +39,9 @@ class Foo2() extends Foo() { log(this.foo) } } +//│ ╔══[ERROR] Cannot access `this` during object initialization +//│ ║ l.39: log(this.foo) +//│ ╙── ^^^^ //│ ╔══[ERROR] identifier not found: this //│ ║ l.39: log(this.foo) //│ ╙── ^^^^ @@ -54,7 +57,7 @@ class Foo3() extends Foo() { val s = this.foo } //│ ╔══[ERROR] Cannot access `this` while initializing field s -//│ ║ l.54: val s = this.foo +//│ ║ l.57: val s = this.foo //│ ╙── ^^^^ //│ class Foo3() extends Foo { //│ val foo: Int @@ -69,10 +72,10 @@ class Foo4() extends Foo() { let bb = bar(0) // call `this` indirectly } //│ ╔══[ERROR] Cannot access `this` while initializing field bb -//│ ║ l.69: let bb = bar(0) // call `this` indirectly +//│ ║ l.72: let bb = bar(0) // call `this` indirectly //│ ║ ^^^^^^^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.68: fun bar(x) = this.foo + x // ok +//│ ║ l.71: fun bar(x) = this.foo + x // ok //│ ╙── ^^^^ //│ class Foo4() extends Foo { //│ fun bar: Int -> Int @@ -87,10 +90,10 @@ class Foo5() extends Foo() { fun bar(y: Int) = this.foo + y } //│ ╔══[ERROR] Cannot access `this` while initializing field x -//│ ║ l.86: val x = bar(0) +//│ ║ l.89: val x = bar(0) //│ ║ ^^^^^^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.87: fun bar(y: Int) = this.foo + y +//│ ║ l.90: fun bar(y: Int) = this.foo + y //│ ╙── ^^^^ //│ class Foo5() extends Foo { //│ fun bar: (y: Int) -> Int @@ -124,13 +127,13 @@ class Bar2() extends Bar() { val two = this.add(1) // add is final, but it refers to `this` } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.124: val two = this.add(1) // add is final, but it refers to `this` +//│ ║ l.127: val two = this.add(1) // add is final, but it refers to `this` //│ ╙── ^^^^ //│ ╔══[ERROR] Cannot access `this` while initializing field two -//│ ║ l.124: val two = this.add(1) // add is final, but it refers to `this` +//│ ║ l.127: val two = this.add(1) // add is final, but it refers to `this` //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.115: fun add(x) = x + this.d +//│ ║ l.118: fun add(x) = x + this.d //│ ╙── ^^^^ //│ class Bar2() extends Bar { //│ fun add: Int -> Int @@ -145,10 +148,10 @@ abstract class Foo: Int -> Int { fun f = this(0) } //│ ╔══[ERROR] Cannot access `this` while initializing field x -//│ ║ l.144: val x = f +//│ ║ l.147: val x = f //│ ║ ^^^^^ //│ ╟── The access to `this` is here -//│ ║ l.145: fun f = this(0) +//│ ║ l.148: fun f = this(0) //│ ╙── ^^^^ //│ abstract class Foo: Int -> Int { //│ fun f: nothing From 031ee4d8fe312ed7508c1612f14f84fb97ae5e2a Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 20 Sep 2023 13:27:35 +0800 Subject: [PATCH 449/498] Minor improvements to ctor parsing and error reporting --- compiler/shared/test/diff/LiftType.mls | 2 +- compiler/shared/test/diff/Lifter.mls | 24 +++--- compiler/shared/test/diff/LifterBlks.mls | 2 +- .../src/main/scala/mlscript/NewParser.scala | 21 +++--- .../src/main/scala/mlscript/NuTypeDefs.scala | 11 +-- .../main/scala/mlscript/codegen/Helpers.scala | 2 +- shared/src/main/scala/mlscript/helpers.scala | 6 +- shared/src/test/diff/nu/AuxCtors.mls | 73 ++++++++++++------- shared/src/test/diff/parser/Blocks.mls | 25 +++++++ shared/src/test/diff/parser/IfThenElse.mls | 2 +- 10 files changed, 111 insertions(+), 57 deletions(-) diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index f56e9fdd14..3701bf2f2d 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -8,7 +8,7 @@ class CTX{ //│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |=>| |A|)|#:| |(|A| |=>| |A|)| |=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| //│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A([]) {},) : (A -> A) -> A}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit(List())))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), ‹›))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {} diff --git a/compiler/shared/test/diff/Lifter.mls b/compiler/shared/test/diff/Lifter.mls index be5fc34a14..29d225c0fc 100644 --- a/compiler/shared/test/diff/Lifter.mls +++ b/compiler/shared/test/diff/Lifter.mls @@ -28,7 +28,7 @@ class A(x) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getB1| |#=| |B1|(|y|)|↵|#class| |C|(|z|)| |{|→|#fun| |inc|(||)| |#=| |x| |+| |1|↵|#fun| |getY| |#=| |y|↵|#fun| |getA| |#=| |A|(|z|)|↵|#fun| |getB|(|w|)| |#=| |B|(|w|)|↵|#fun| |getC| |#=| |#new| |C|(|inc|(||)|)|↵|#fun| |getSelf| |#=| |this|←|↵|}|←|↵|}|↵|#class| |B1|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getY| |#=| |y|↵|#fun| |getB| |#=| |#new| |B|(|y|)|↵|#fun| |getB1| |#=| |#new| |B1|(|y|)|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|(|x|)|↵|#fun| |getB2|(|y|)| |#=| |B1|(|y|)|↵|#fun| |getB3|(|z|)| |#=| |getB2|(|z|)|↵|#fun| |getA| |#=| |A|(|x|)|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1(y,); class C(z,) {fun inc = () => +(x, 1,); fun getY = y; fun getA = A(z,); fun getB = (w,) => B(w,); fun getC = new C([inc(),]) {}; fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = new B([y,]) {}; fun getB1 = new B1([y,]) {}}; fun getB = new B([x,]) {}; fun getB2 = (y,) => B1(y,); fun getB3 = (z,) => getB2(z,); fun getA = A(x,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), TypingUnit(List()))), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), TypingUnit(List()))), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), TypingUnit(List()))))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), TypingUnit(List()))), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), ‹›)), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), ‹›)), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), ‹›)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), ‹›)), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2_C$4([par$A$1_B$2, z,]) { @@ -108,7 +108,7 @@ new C{ //│ |#class| |A|(|x|)| |{|→|#class| |B|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |11|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |2|↵|#fun| |bar| |#=| |12|←|↵|}|↵|#fun| |bar| |#=| |13|←|↵|}|↵|#class| |C|#:| |A|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |3|↵|#fun| |bar| |#=| |14|←|↵|}|↵|#fun| |bar| |#=| |15|←|↵|}|↵|#new| |C|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |4|↵|#fun| |bar| |#=| |16|←|↵|}|↵|#fun| |bar| |#=| |17|←|↵|}| //│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B([]) {fun foo = 2; fun bar = 12}; fun bar = 13}; class C: A {fun getB = new B([]) {fun foo = 3; fun bar = 14}; fun bar = 15}; new C([]) {fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(List(fun foo = 2, fun bar = 12)))), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(List(fun foo = 3, fun bar = 14)))), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), TypingUnit(List(fun getB = new B([]) {fun foo = 4; fun bar = 16}, fun bar = 17)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹fun foo = 2; fun bar = 12›)), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹fun foo = 3; fun bar = 14›)), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), ‹fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17›)) //│ Lifted: //│ Lifting failed: java.util.NoSuchElementException: None.get //│ @@ -148,7 +148,7 @@ class A(x: Int): {a1: Int} & B & D(x){ //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| //│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C([]) {fun foo = (x: T,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(List(fun foo = (x: T,) => x)))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), ‹fun foo = (x: T,) => x›)))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -171,7 +171,7 @@ class A(x: Int) extends {a1: Int}, B, D(x){ //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)| |#extends| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| //│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C([]) {fun foo = (x,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(List(fun foo = (x,) => x)))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), ‹fun foo = (x,) => x›)))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -192,7 +192,7 @@ class Child(x): { age: T } & { name: String} { //│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| //│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner {fun foo = age}; fun bar = age; fun boo = new Inner([]) {}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), TypingUnit(List())))))) +//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), ‹›))))) //│ Lifted: //│ TypingUnit { //│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = (this).age} @@ -215,7 +215,7 @@ new A(0) { //│ |#class| |A|(|x|#:| |Int|)| |{|→|#fun| |getA|#:| |Int| |#=| |0|↵|#fun| |getA1| |#=| |1|←|↵|}|↵|#new| |A|(|0|)| |{|→|#fun| |getA| |#=| |3|↵|#fun| |getA2| |#=| |2|←|↵|}| //│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; new A([0,]) {fun getA = 3; fun getA2 = 2}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), TypingUnit(List(fun getA = 3, fun getA2 = 2)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), ‹fun getA = 3; fun getA2 = 2›)) //│ Lifted: //│ TypingUnit { //│ class A$1([x: Int,]) {fun getA = 0 : Int; fun getA1 = 1} @@ -236,7 +236,7 @@ new A(1) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{| |}|←|↵|}|↵|#new| |A|(|1|)| |{|→|#fun| |getB| |#=| |#new| |B|(|2|)|{|→|#fun| |getB| |#=| |#new| |B|(|3|)|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {}}; new A([1,]) {fun getB = new B([2,]) {fun getB = new B([3,]) {}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), TypingUnit(List(fun getB = new B([2,]) {fun getB = new B([3,]) {}})))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), ‹fun getB = new B([2,]) {fun getB = new B([3,]) {}}›)) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1, y,]) {} @@ -269,7 +269,7 @@ new B{ //│ |#class| |A| |{|→|#fun| |getA| |#=| |0|↵|#fun| |funcA| |#=| |10|←|↵|}|↵|#class| |B|#:| |A|{|→|#fun| |getA| |#=| |1|↵|#fun| |funcB| |#=| |11|←|↵|}|↵|#new| |A|↵|#new| |B|↵|#fun| |f|(|x|)| |#=| |#if| |x| |is| |A| |#then| |0| |#else| |1|↵|f|(|#new| |A|{|→|#fun| |getA| |#=| |2|←|↵|}|)|↵|#new| |B|{|→|#fun| |getA| |#=| |funcB|←|↵|}| //│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A([]) {}; new B([]) {}; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A([]) {fun getA = 2},); new B([]) {fun getA = funcB}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), TypingUnit(List())), New(Some((TypeName(B),[])), TypingUnit(List())), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit(List(fun getA = 2))))), New(Some((TypeName(B),[])), TypingUnit(List(fun getA = funcB)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), ‹›), New(Some((TypeName(B),[])), ‹›), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), ‹fun getA = 2›))), New(Some((TypeName(B),[])), ‹fun getA = funcB›)) //│ Lifted: //│ TypingUnit { //│ class A$1([]) {fun getA = 0; fun funcA = 10} @@ -353,7 +353,7 @@ class A{ //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|↵|#fun| |getB| |#=| |#new| |B|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|↵|#fun| |getD| |#=| |#new| |D|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|↵|#fun| |getE| |#=| |#new| |E|{|→|#fun| |foo| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B([]) {}}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D([]) {}}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E([]) {fun foo = 0}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(List()))))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), TypingUnit(List()))))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), TypingUnit(List(fun foo = 0))))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹›)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), ‹›)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), ‹fun foo = 0›))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {fun funB = 1; fun foo = 100} @@ -389,7 +389,7 @@ new A //│ |#class| |A|{|→|#class| |B|{|→|#fun| |foo| |#=| |1|←|↵|}|↵|#fun| |bar| |#=| |#new| |B|←|↵|}|↵|#new| |A| //│ Parsed: {class A {class B {fun foo = 1}; fun bar = new B([]) {}}; new A([]) {}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), TypingUnit(List()))))), New(Some((TypeName(A),[])), TypingUnit(List()))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), ‹›)))), New(Some((TypeName(A),[])), ‹›)) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {fun foo = 1} @@ -414,7 +414,7 @@ let x = new A{ //│ |#class| |A|(|x|)| |{|→|#fun| |foo| |#=| |0|↵|#fun| |bar| |#=| |x|←|↵|}|↵|#let| |x| |#=| |#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |newFun| |#=| |2|↵|#fun| |bar| |#=| |#new| |A|(|foo|)|{|→|#fun| |foo| |#=| |bar| |+| |1|↵|#fun| |bar2| |#=| |newFun| |+| |1|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A([]) {fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), TypingUnit(List(fun foo = 1, fun newFun = 2, fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), ‹fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}›))) //│ Lifted: //│ TypingUnit { //│ class A$1([x,]) {fun foo = 0; fun bar = (this).x} @@ -451,7 +451,7 @@ new A{ //│ |#class| |A| |{||}|↵|#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |#new| |A|{|→|#fun| |foo1| |#=| |foo|↵|#fun| |bar1| |#=| |#new| |A|{|→|#fun| |foo2| |#=| |foo|↵|#fun| |bar2| |#=| |#new| |A|{|→|#fun| |foo3| |#=| |foo|↵|#fun| |bar3| |#=| |#new| |A|{|→|#fun| |foo4| |#=| |foo|↵|#fun| |bar4| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A {}; new A([]) {fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), TypingUnit(List(fun foo = 1, fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}})))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), ‹fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}›)) //│ Lifted: //│ TypingUnit { //│ class A$1([]) {} diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index b2d692d3bd..b6246e2a69 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -55,7 +55,7 @@ f(0) //│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| //│ Parsed: {class A(y,) {}; let f = (x,) => new A([0,]) {fun bar = +(x, y,)}; f(0,)} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), TypingUnit(List(fun bar = +(x, y,)))))), App(Var(f), Tup(_: IntLit(0)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), ‹fun bar = +(x, y,)›))), App(Var(f), Tup(_: IntLit(0)))) //│ Lifted: //│ TypingUnit { //│ class A$1([y,]) {} diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 9b13a7a18d..cbd661250d 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -528,16 +528,19 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case _ => exprOrIf(0, allowSpace = false) } - yeetSpaces match { + val finalTerm = yeetSpaces match { case (KEYWORD("="), l0) :: _ => t match { case R(v: Var) => consume - R(Eqn(v, expr(0))) :: block - case _ => t :: Nil + R(Eqn(v, expr(0))) + case _ => t } - case (KEYWORD(";"), _) :: _ => consume; t :: block - case (NEWLINE, _) :: _ => consume; t :: block - case _ => t :: Nil + case _ => t + } + yeetSpaces match { + case (KEYWORD(";"), _) :: _ => consume; finalTerm :: block + case (NEWLINE, _) :: _ => consume; finalTerm :: block + case _ => finalTerm :: Nil } } @@ -659,7 +662,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo consume exprOrIf(0) case _ => - R(UnitLit(true)) + R(UnitLit(true).withLoc(curLoc.map(_.left))) } bs.foldRight(body) { case ((v, r), R(acc)) => R(Let(false, v, r, acc)) @@ -746,8 +749,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case Nil => err(msg"Unexpected end of $description; an expression was expected here" -> lastLoc :: Nil) R(errExpr) - case ((KEYWORD(";") /* | NEWLINE */ /* | BRACKETS(Curly, _) */, _) :: _) => - R(UnitLit(true)) + case ((KEYWORD(";") /* | NEWLINE */ /* | BRACKETS(Curly, _) */, l0) :: _) => + R(UnitLit(true).withLoc(S(l0))) // R(errExpr) // TODO case (tk, l0) :: _ => err(msg"Unexpected ${tk.describe} in expression position" -> S(l0) :: Nil) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 38d6730570..7bc3eb37c2 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1538,8 +1538,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val baseType = RecordType(Nil)(TypeProvenance(Loc(td.parents).map(_.left), "Object")) - println("PPP",privateParams) - val paramMems = typedParams.getOrElse(Nil).map(f => NuParam(f._1, f._2, isPublic = !privateParams.contains(f._1))(lvl)) @@ -1647,17 +1645,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => bod :: Nil } // * TODO later: for each `typedParams`, first add sthg like `ctx += lhs.name -> UndefinedParam(...)` - val classParamsMap = MutMap.from(typedParams.getOrElse(Nil)) + val classParamsMap = MutMap.from(typedParams.getOrElse(Nil).mapValues(some)) bodStmts.foreach { case Eqn(lhs, rhs) => classParamsMap.updateWith(lhs) { - case S(p) => + case S(S(p)) => val rhs_ty = typeTerm(rhs) constrain(rhs_ty, p.ub) ctx += lhs.name -> VarSymbol(rhs_ty, lhs) + S(N) + case S(N) => + err(msg"Class parameter '${lhs.name}' was already set", lhs.toLoc) N case N => - err(msg"Unknown class parameter ${lhs.name}", lhs.toLoc) + err(msg"Unknown class parameter '${lhs.name}'", lhs.toLoc) N } case stmt: DesugaredStatement => diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index f5eca10462..96b4114479 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -56,7 +56,7 @@ object Helpers { case Where(bod, sts) => s"Where(${inspect(bod)}, ...)" case Forall(ps, bod) => s"Forall($ps, ${inspect(bod)})" case Inst(bod) => s"Inst(${inspect(bod)})" - case Eqn(lhs, rhs) => s"Ass(${inspect(lhs)}, ${inspect(rhs)})" + case Eqn(lhs, rhs) => s"Eqn(${inspect(lhs)}, ${inspect(rhs)})" case Super() => "Super()" case AdtMatchWith(cond, arms) => s"match ${inspect(cond)} with ${arms.map(patmat => s"${inspect(patmat.pat)} -> ${inspect(patmat.rhs)}").mkString(" | ")}" diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 991a30b390..bd3186f5c7 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -466,8 +466,10 @@ trait TypingUnitImpl extends Located { self: TypingUnit => def showDbg: Str = entities.map { case t: Term => t.toString case d: NuDecl => d.showDbg - case _ => die + case c: Constructor => c.toString + case e => lastWords(s"Unexpected typing unit entity: $e") }.mkString("{", "; ", "}") + override def toString: String = s"‹${entities.mkString("; ")}›" lazy val children: List[Located] = entities } @@ -974,7 +976,7 @@ trait StatementImpl extends Located { self: Statement => case LetS(isRec, name, rhs) => s"let${if (isRec) " rec" else ""} $name = $rhs" case DatatypeDefn(head, body) => s"data type $head of $body" case DataDefn(head) => s"data $head" - case Constructor(params, _) => s"constructor($params)" + case Constructor(params, bod) => s"constructor(${params.showElems}) $bod" case _: Term => super.toString case d: Decl => d.showDbg case d: NuDecl => d.showDbg diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index bf60294a68..7de3b76e5d 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -2,29 +2,55 @@ class C(val x: Int) { constructor(y: Int) { x = y } } +C(123).x //│ class C(x: Int) { //│ constructor(y: Int) //│ } +//│ Int +//│ res +//│ = 123 class C(val x: Int) { constructor(y) { x = y } } +C(123).x //│ class C(x: Int) { //│ constructor(y: Int) //│ } +//│ Int +//│ res +//│ = 123 -// * FIXME location -// * TODO `undefined` should be treated as the unit type... -:w // FIXME class C(val x: Int) { constructor(y: Int) { log(y); x = y; log(x) } } -//│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ╙── +C(123).x //│ class C(x: Int) { //│ constructor(y: Int) //│ } +//│ Int +//│ res +//│ = 123 +//│ // Output +//│ 123 +//│ 123 -// FIXME should be a type error +:e +class C(val x: Int) { constructor(y: Int) { x = y; log(x); x = y + 1; log(x) } } +C(123).x +//│ ╔══[ERROR] Class parameter 'x' was already set +//│ ║ l.35: class C(val x: Int) { constructor(y: Int) { x = y; log(x); x = y + 1; log(x) } } +//│ ╙── ^ +//│ class C(x: Int) { +//│ constructor(y: Int) +//│ } +//│ Int +//│ res +//│ = 124 +//│ // Output +//│ 123 +//│ 124 + +:e class C(val x: Int) { constructor(y: Int) { log(x); x = y } } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.25: class C(val x: Int) { constructor(y: Int) { log(x); x = y } } +//│ ║ l.51: class C(val x: Int) { constructor(y: Int) { log(x); x = y } } //│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) @@ -35,16 +61,16 @@ class C(val x: Int) { constructor(y: Int) { log(x); x = y } } :e class C(val x: Int) { constructor(y: Str) { x = y } } //│ ╔══[ERROR] Type mismatch in auxiliary class constructor: -//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Str` is not an instance of `Int` -//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `Int` -//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.36: class C(val x: Int) { constructor(y: Str) { x = y } } +//│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } //│ ╙── ^^^ //│ class C(x: Int) { //│ constructor(y: Str) @@ -52,8 +78,8 @@ class C(val x: Int) { constructor(y: Str) { x = y } } :e class C(val x: Int) { constructor(y: Int) { z = y } } -//│ ╔══[ERROR] Unknown class parameter z -//│ ║ l.54: class C(val x: Int) { constructor(y: Int) { z = y } } +//│ ╔══[ERROR] Unknown class parameter 'z' +//│ ║ l.80: class C(val x: Int) { constructor(y: Int) { z = y } } //│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) @@ -64,7 +90,7 @@ class C(val x: Int) { constructor(y: Int) { z = y } } :e class C(val x: Int) { constructor(val y: Int) { x = y } } //│ ╔══[ERROR] Cannot use `val` in constructor parameters -//│ ║ l.65: class C(val x: Int) { constructor(val y: Int) { x = y } } +//│ ║ l.91: class C(val x: Int) { constructor(val y: Int) { x = y } } //│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) @@ -73,8 +99,8 @@ class C(val x: Int) { constructor(val y: Int) { x = y } } :e class C(val x: Int) { constructor(val y) { x = y } } //│ ╔══[ERROR] Cannot use `val` in constructor parameters -//│ ║ l.74: class C(val x: Int) { constructor(val y) { x = y } } -//│ ╙── ^ +//│ ║ l.100: class C(val x: Int) { constructor(val y) { x = y } } +//│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) //│ } @@ -82,8 +108,8 @@ class C(val x: Int) { constructor(val y) { x = y } } :e class C(val x: Int) { constructor(2 + 2) { x = 0 } } //│ ╔══[ERROR] Unsupported constructor parameter shape -//│ ║ l.83: class C(val x: Int) { constructor(2 + 2) { x = 0 } } -//│ ╙── ^^^^^ +//│ ║ l.109: class C(val x: Int) { constructor(2 + 2) { x = 0 } } +//│ ╙── ^^^^^ //│ class C(x: Int) { //│ constructor(: error) //│ } @@ -91,13 +117,10 @@ class C(val x: Int) { constructor(2 + 2) { x = 0 } } //│ Unexpected constructor parameters in C. -:w // FIXME class C(val x: Int, y: Int) { constructor(z: Int) { x = z; y = z } log([x, y]) } -//│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ╙── //│ class C(x: Int, y: Int) { //│ constructor(z: Int) //│ } @@ -105,10 +128,10 @@ class C(val x: Int, y: Int) { :e C(11) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.106: C(11) +//│ ║ l.129: C(11) //│ ║ ^^^^^ //│ ╟── argument of type `[11]` does not match type `[x: Int, y: Int]` -//│ ║ l.106: C(11) +//│ ║ l.129: C(11) //│ ╙── ^^^^ //│ C | error //│ res @@ -133,10 +156,10 @@ new C(11) :e new C(1, 2) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.134: new C(1, 2) +//│ ║ l.157: new C(1, 2) //│ ║ ^^^^^^^^^^^ //│ ╟── argument list of type `[1, 2]` does not match type `[z: Int]` -//│ ║ l.134: new C(1, 2) +//│ ║ l.157: new C(1, 2) //│ ╙── ^^^^^^ //│ C | error //│ res diff --git a/shared/src/test/diff/parser/Blocks.mls b/shared/src/test/diff/parser/Blocks.mls index ee3801c4f8..4725ff0179 100644 --- a/shared/src/test/diff/parser/Blocks.mls +++ b/shared/src/test/diff/parser/Blocks.mls @@ -164,3 +164,28 @@ fun foo = //│ Parsed: {fun foo = {fun local = (x,) => {class Foo {fun bar = +(x,)(1,)}; (Foo()).bar}; print(+(local(0,),)(local(1,),),); print(+('(' local(0,) ')',)(local(1,),),); fun tmp = 1; print(local(+(0,)(local(1,),),),); fun tmp = 2}} + +log(1); log(a) +//│ |log|(|1|)|#;| |log|(|a|)| +//│ Parsed: {log(1,); log(a,)} + +constructor(){ + a = 1 + a = 2 +} +//│ |#constructor|(||)|{|→|a| |#=| |1|↵|a| |#=| |2|←|↵|}| +//│ Parsed: {constructor() {a = 1; a = 2}} + +a = 1; log(a) +//│ |a| |#=| |1|#;| |log|(|a|)| +//│ Parsed: {a = 1; log(a,)} + +:pe +f(a) = 1 +//│ |f|(|a|)| |#=| |1| +//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead +//│ ║ l.184: f(a) = 1 +//│ ╙── ^ +//│ Parsed: {f(a,)} + + diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 79d96cec6a..7286adb3f3 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -556,7 +556,7 @@ if true then; else; //│ |#if| |true| |#then|#;| |#else|#;| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause //│ ║ l.555: if true then; else; -//│ ╙── ^^^^ +//│ ╙── ^^^^^ //│ Parsed: {if (true) then undefined; undefined} if true then () else; From 86c705193670188d729262206bed62b8d321fcfb Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 20 Sep 2023 17:41:59 +0800 Subject: [PATCH 450/498] Address minor PR comments --- shared/src/main/scala/mlscript/MLParser.scala | 2 +- shared/src/main/scala/mlscript/NewParser.scala | 6 +++--- shared/src/main/scala/mlscript/NuTypeDefs.scala | 1 - shared/src/main/scala/mlscript/Parser.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 9 ++++----- shared/src/main/scala/mlscript/helpers.scala | 8 ++++---- shared/src/main/scala/mlscript/ucs/Desugarer.scala | 10 +++++----- shared/src/main/scala/mlscript/ucs/helpers.scala | 2 +- 8 files changed, 19 insertions(+), 21 deletions(-) diff --git a/shared/src/main/scala/mlscript/MLParser.scala b/shared/src/main/scala/mlscript/MLParser.scala index c22a12ff41..b9a0e8223a 100644 --- a/shared/src/main/scala/mlscript/MLParser.scala +++ b/shared/src/main/scala/mlscript/MLParser.scala @@ -23,7 +23,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { } def toParam(t: Term): Tup = - Tup((N, Fld(FldFlags(false, false, false), t)) :: Nil) + Tup((N, Fld(FldFlags.empty, t)) :: Nil) def toParams(t: Term): Tup = t match { case t: Tup => t diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index cbd661250d..7e96689e81 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -251,7 +251,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo final def toParams(t: Term): Tup = t match { case t: Tup => t case Bra(false, t: Tup) => t - case _ => Tup((N, Fld(FldFlags(false, false, false), t)) :: Nil) + case _ => Tup((N, Fld(FldFlags.empty, t)) :: Nil) } final def toParamsTy(t: Type): Tuple = t match { case t: Tuple => t @@ -1060,7 +1060,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo // argsOrIf(Nil).map{case (_, L(x))=> ???; case (n, R(x))=>n->x} // TODO argsOrIf(Nil, Nil, allowNewlines, prec).flatMap{case (n, L(x))=> err(msg"Unexpected 'then'/'else' clause" -> x.toLoc :: Nil) - n->Fld(FldFlags(false, false, false), errExpr)::Nil + n->Fld(FldFlags.empty, errExpr)::Nil case (n, R(x))=>n->x::Nil} // TODO /* final def argsOrIf2()(implicit fe: FoundErr, et: ExpectThen): IfBlock \/ Ls[Opt[Var] -> Fld] = { @@ -1081,7 +1081,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case Nil => seqAcc match { case res :: seqAcc => - (N -> R(Fld(FldFlags(false, false, false), Blk((res :: seqAcc).reverse))) :: acc).reverse + (N -> R(Fld(FldFlags.empty, Blk((res :: seqAcc).reverse))) :: acc).reverse case Nil => acc.reverse } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 7bc3eb37c2..c6bc7b72b6 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1242,7 +1242,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => msg"Originally declared here:" -> fun.toLoc :: Nil) case _ => - // println(s"?! $fun") val mSign = m.typeSignature implicit val prov: TP = mSign.prov constrain(mSign, fun.typeSignature) diff --git a/shared/src/main/scala/mlscript/Parser.scala b/shared/src/main/scala/mlscript/Parser.scala index 9595ccb715..ba61c790bf 100644 --- a/shared/src/main/scala/mlscript/Parser.scala +++ b/shared/src/main/scala/mlscript/Parser.scala @@ -101,7 +101,7 @@ class Parser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { Index ~~ (NAME ~ ":" ~ (noCommas | suite) | noCommas.map(Var("") -> _)).rep(1, ",").map(_.toList) ~ ",".!.? ~~ Index ).map { case (_, (Var(""), x) :: Nil, N, _) => x - case (i0, xs, _, i1) => Tup(xs.map { case (n, t) => (n optionIf (_.name.nonEmpty), Fld(FldFlags(false, false, false), t)) }).withLoc(i0, i1, origin) + case (i0, xs, _, i1) => Tup(xs.map { case (n, t) => (n optionIf (_.name.nonEmpty), Fld(FldFlags.empty, t)) }).withLoc(i0, i1, origin) } def booleans[p: P]: P[Term] = P(binops rep (1, kw("and")) rep (1, kw("or"))) // TODO locs diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index eb30ae4f50..3c4b9e60bd 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1485,7 +1485,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne (implicit ctx: Ctx, raise: Raise, prov: TypeProvenance, vars: Map[Str, SimpleType], genLambdas: GenLambdas): SimpleType = term match { case (trm @ Var(nme)) :: sts if rcd => // field punning - typeTerms(Tup(S(trm) -> Fld(FldFlags(false, false, false), trm) :: Nil) :: sts, rcd, fields) + typeTerms(Tup(S(trm) -> Fld(FldFlags.empty, trm) :: Nil) :: sts, rcd, fields) case Blk(sts0) :: sts1 => typeTerms(sts0 ::: sts1, rcd, fields) case Tup(Nil) :: sts => typeTerms(sts, rcd, fields) case Tup((no, Fld(FldFlags(tmut, _, _), trm)) :: ofs) :: sts => @@ -1593,7 +1593,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne case TypedNuMxn(level, td, thisTy, superTy, tparams, params, members) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, - S(Tup(params.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2.ub)))))), + S(Tup(params.map(p => N -> Fld(FldFlags.empty, Asc(p._1, go(p._2.ub)))))), N,//TODO N, Nil, // TODO mixin parents? @@ -1605,8 +1605,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne case TypedNuCls(level, td, tparams, params, acParams, members, thisTy, sign, ihtags, ptps) => ectx(tparams) |> { implicit ectx => NuTypeDef(td.kind, td.nme, td.tparams, - // Opt.when(td.params.isDefined)(Tup(params.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2.ub)))))), - params.map(ps => Tup(ps.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2.ub)))))), + params.map(ps => Tup(ps.map(p => N -> Fld(FldFlags.empty, Asc(p._1, go(p._2.ub)))))), td.ctor, Option.when(!(TopType <:< sign))(go(sign)), ihtags.toList.sorted.map(_.toVar), // TODO provide targs/args @@ -1616,7 +1615,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val tun = mkTypingUnit(thisTy, members) acParams match { case S(ps) => TypingUnit(Constructor( - Tup(ps.map(p => N -> Fld(FldFlags(false, false, false), Asc(p._1, go(p._2))))), + Tup(ps.map(p => N -> Fld(FldFlags.empty, Asc(p._1, go(p._2))))), Blk(Nil)) :: tun.entities) case N => tun } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index bd3186f5c7..6c0d674359 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -173,7 +173,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => ths.fold("")(s"${bodyCtx.indStr}this: " + _.showIn(bodyCtx, 0) + "\n") + body.entities.collect { case Constructor(params, body) => s"${bodyCtx.indStr}constructor(${params.fields.map { - case N -> Fld(FldFlags(false, false, false), Asc(Var(nme), ty)) => + case N -> Fld(FldFlags.empty, Asc(Var(nme), ty)) => s"${nme}: ${ty.showIn(bodyCtx, 0)}" case _ => lastWords("ill-formed constructor parameter") }.mkString(", ")})\n" @@ -456,7 +456,7 @@ trait NuDeclImpl extends Located { self: NuDecl => case _ => die })) NuFunDef(N, Var("unapply"), N, Nil, L(Lam( - Tup(N -> Fld(FldFlags(false, false, false), Var("x")) :: Nil), + Tup(N -> Fld(FldFlags.empty, Var("x")) :: Nil), ret)))(N, N, N, N, true) } case _ => N @@ -675,7 +675,7 @@ private class NotAType(val trm: Statement) extends Throwable object PlainTup { def apply(fields: Term*): Term = - Tup(fields.iterator.map(t => (N, Fld(FldFlags(false, false, false), t))).toList) + Tup(fields.iterator.map(t => (N, Fld(FldFlags.empty, t))).toList) def unapplySeq(trm: Term): Opt[List[Term]] = trm match { case Tup(fields) if fields.forall(f => f._1.isEmpty && f._2.flags.mut === false && f._2.flags.spec === false @@ -846,7 +846,7 @@ trait StatementImpl extends Located { self: Statement => val pos = params.unzip._1 val bod = pars.map(tt).foldRight(Record(params): Type)(Inter) val termName = Var(nme.name).withLocOf(nme) - val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(FldFlags(false, false, false), Rcd(fs.map { + val ctor = Def(false, termName, L(Lam(tup, App(termName, Tup(N -> Fld(FldFlags.empty, Rcd(fs.map { case (S(nme), fld) => nme -> Fld(FldFlags(false, false, fld.flags.genGetter), nme) case (N, fld @ Fld(_, nme: Var)) => nme -> fld case _ => die diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 6895f2dccf..d5156d86d8 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -809,16 +809,16 @@ class Desugarer extends TypeDefs { self: Typer => } App(Lam(Tup( - N -> Fld(FldFlags(false, false, false), Tup( + N -> Fld(FldFlags.empty, Tup( fields.distinctBy(_._1).map { case (_ -> Var(alias)) => - if (alias === "_") N -> Fld(FldFlags(false, false, false), Var(freshName)) - else N -> Fld(FldFlags(false, false, false), Var(alias)) + if (alias === "_") N -> Fld(FldFlags.empty, Var(freshName)) + else N -> Fld(FldFlags.empty, Var(alias)) }.toList )) :: Nil ), extraAlias.toList.foldRight(consequent)((lt, rs) => Let(false, Var(lt._2), Var(lt._1), rs))), - Tup(N -> Fld(FldFlags(false, false, false), App(Sel(className, Var(unapplyMtd.name)), - Tup(N -> Fld(FldFlags(false, false, false), scrutinee.reference) :: Nil)) + Tup(N -> Fld(FldFlags.empty, App(Sel(className, Var(unapplyMtd.name)), + Tup(N -> Fld(FldFlags.empty, scrutinee.reference) :: Nil)) ) :: Nil) ) case _ => mkLetFromFields(scrutinee, fields.filter(_._2.name =/= "_").toList, consequent) diff --git a/shared/src/main/scala/mlscript/ucs/helpers.scala b/shared/src/main/scala/mlscript/ucs/helpers.scala index 27140d2369..0babee09b4 100644 --- a/shared/src/main/scala/mlscript/ucs/helpers.scala +++ b/shared/src/main/scala/mlscript/ucs/helpers.scala @@ -16,7 +16,7 @@ object helpers { * @param t the sole element * @return a tuple term with the only element */ - def mkMonuple(t: Term): Tup = Tup(N -> Fld(FldFlags(false, false, false), t) :: Nil) + def mkMonuple(t: Term): Tup = Tup(N -> Fld(FldFlags.empty, t) :: Nil) /** * Make a binary operation. From bce48deb7980edeb331b294a5f08251f814f846b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 20 Sep 2023 21:03:05 +0800 Subject: [PATCH 451/498] Fix #180 --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 + shared/src/test/diff/codegen/SymbolicOps.mls | 6 +- shared/src/test/diff/nu/FlatMonads.mls | 72 ++--------------- shared/src/test/diff/nu/OpLam.mls | 2 +- shared/src/test/diff/nu/SimpleSymbolicOps.mls | 20 +++++ shared/src/test/diff/nu/i180.mls | 79 +++++++++++++++++++ 6 files changed, 113 insertions(+), 68 deletions(-) create mode 100644 shared/src/test/diff/nu/SimpleSymbolicOps.mls create mode 100644 shared/src/test/diff/nu/i180.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index c6bc7b72b6..7ad5738aaa 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -418,6 +418,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => extends TypedNuDecl with TypedNuTermDef { def kind: DeclKind = Val def name: Str = fd.nme.name + def symbolicName: Opt[Str] = fd.symbolicNme.map(_.name) def toLoc: Opt[Loc] = fd.toLoc def isPublic = true // TODO lazy val typeSignature: ST = PolymorphicType.mk(level, bodyType) @@ -628,6 +629,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * Generalize functions as they are typed. // * Note: eventually we'll want to first reorder their typing topologically so as to maximize polymorphism. ctx += res.name -> VarSymbol(res.typeSignature, res.fd.nme) + res.symbolicName.foreach(ctx += _ -> VarSymbol(res.typeSignature, res.fd.nme)) } CompletedTypeInfo(res) case res => CompletedTypeInfo(res) diff --git a/shared/src/test/diff/codegen/SymbolicOps.mls b/shared/src/test/diff/codegen/SymbolicOps.mls index b3f2fc73e9..9dd61cb78a 100644 --- a/shared/src/test/diff/codegen/SymbolicOps.mls +++ b/shared/src/test/diff/codegen/SymbolicOps.mls @@ -54,13 +54,13 @@ succ >> succ of 3 //│ ╟── from reference: //│ ║ l.4: fun (>>) compose(f, g) = x => g(f(x)) //│ ╙── ^ -//│ error | Int -> Int +//│ error | Int -> nothing //│ res //│ = [Function (anonymous)] :js let f = (>>) -//│ let f: forall 'a 'b. ((3 | 'a) -> Int, Int -> 'b) -> (Int & 'a) -> (Int | 'b) +//│ let f: forall 'a 'b 'c. ('a -> 'b, 'b -> 'c) -> 'a -> 'c //│ // Prelude //│ class TypingUnit7 {} //│ const typing_unit7 = new TypingUnit7; @@ -109,7 +109,7 @@ f(succ, succ)(3) //│ ╟── from reference: //│ ║ l.4: fun (>>) compose(f, g) = x => g(f(x)) //│ ╙── ^ -//│ error | Int -> Int +//│ error | Int -> nothing //│ res //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index 80df624236..e11d038816 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -117,7 +117,6 @@ printLine("").bind of [] => error fun (|>=) bindOp[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) //│ fun (|>=) bindOp: forall 'A 'B. (x: IO['A], f: 'A -> IO['B]) -> IO['B] -:e // FIXME why the errors? val main = printLine("Hi! Input two numbers: ") |>= _ => readInt |>= n => @@ -125,64 +124,9 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)) |>= _ => Pure(sum) -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.124: readInt |>= m => -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.125: val sum = n + m -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.126: printLine(concat("The sum is: ")(String of sum)) |>= _ => -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.127: Pure(sum) -//│ ║ ^^^^^^^^^^^ -//│ ╟── type `Int` does not match type `undefined` -//│ ║ l.32: module readInt extends IO[Int] { fun run = 42 } -//│ ║ ^^^ -//│ ╟── Note: constraint arises from literal type: -//│ ║ l.33: class printLine(str: Str) extends IO[undefined] { fun run = log(str) } -//│ ║ ^^^^^^^^^ -//│ ╟── Note: method type parameter A is defined at: -//│ ║ l.117: fun (|>=) bindOp[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.123: readInt |>= n => -//│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.124: readInt |>= m => -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.125: val sum = n + m -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.126: printLine(concat("The sum is: ")(String of sum)) |>= _ => -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.127: Pure(sum) -//│ ║ ^^^^^^^^^^^ -//│ ╟── type `Int` does not match type `undefined` -//│ ║ l.32: module readInt extends IO[Int] { fun run = 42 } -//│ ║ ^^^ -//│ ╟── Note: constraint arises from literal type: -//│ ║ l.33: class printLine(str: Str) extends IO[undefined] { fun run = log(str) } -//│ ║ ^^^^^^^^^ -//│ ╟── Note: method type parameter A is defined at: -//│ ║ l.117: fun (|>=) bindOp[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) -//│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.122: printLine("Hi! Input two numbers: ") |>= _ => -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.123: readInt |>= n => -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.124: readInt |>= m => -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.125: val sum = n + m -//│ ║ ^^^^^^^^^^^^^^^^^ -//│ ║ l.126: printLine(concat("The sum is: ")(String of sum)) |>= _ => -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.127: Pure(sum) -//│ ║ ^^^^^^^^^^^ -//│ ╟── type `undefined` is not an instance of type `Int` -//│ ║ l.33: class printLine(str: Str) extends IO[undefined] { fun run = log(str) } -//│ ║ ^^^^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.125: val sum = n + m -//│ ╙── ^ -//│ val main: IO['B] | error +//│ val main: IO['B] +//│ where +//│ 'B :> Int //│ main //│ = Bind {} @@ -192,7 +136,6 @@ val main = fun (|>=) bindOp(x, f) = x.bind(f) //│ fun (|>=) bindOp: forall 'a 'b. ({bind: 'a -> 'b}, 'a) -> 'b -// FIXME why `nothing`? val main = printLine("Hi! Input two numbers: ") |>= _ => readInt |>= n => @@ -200,9 +143,10 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)) |>= _ => Pure(sum) -//│ val main: Bind[nothing, 'B] +//│ val main: Bind['A, 'B] //│ where //│ 'B :> Int +//│ 'A <: undefined //│ main //│ = Bind {} @@ -227,7 +171,7 @@ fun main(ctx) = val sum = n + m ctx.printLine(concat("The sum is: ")(String of sum)) |>= _ => ctx.pure(sum) -//│ fun main: forall 'a 'b. {printLine: Str -> {bind: (Int -> ('a | 'b)) -> 'a}, pure: Int -> 'b, readInt: {bind: (Int -> ('a | 'b)) -> 'a}} -> 'a +//│ fun main: forall 'a 'b 'c 'd 'e. {printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'a) -> 'e} & Str -> {bind: (anything -> 'd) -> 'b}, pure: Int -> 'd, readInt: {bind: (Int -> 'c) -> 'a & (Int -> 'b) -> 'c}} -> 'e val defaultCtx = {printLine, readInt, pure: Pure} //│ val defaultCtx: {printLine: (str: Str) -> printLine, pure: forall 'A. (value: 'A) -> Pure['A], readInt: readInt} @@ -256,9 +200,9 @@ fun loop(ctx) = ctx.printLine("Input a positive number: ") |>= _ => ctx.readInt |>= n => if n < 0 then loop(ctx) else ctx.pure(n) -//│ fun loop: forall 'a 'b 'c. {printLine: "Input a positive number: " -> {bind: ((Int & 'a) -> ('b | 'c)) -> 'b}, pure: 'a -> 'c, readInt: {bind: ((Int & 'a) -> ('b | 'c)) -> 'b}} -> 'b +//│ fun loop: forall 'a 'b 'c 'd. {printLine: "Input a positive number: " -> {bind: (anything -> 'a) -> 'b}, pure: 'c -> 'd, readInt: {bind: ((Num & 'c) -> ('d | 'b)) -> 'a}} -> 'b -// FIXME why `nothing`? +// * FIXME why `nothing`? let r = loop(defaultCtx).run //│ let r: nothing //│ r diff --git a/shared/src/test/diff/nu/OpLam.mls b/shared/src/test/diff/nu/OpLam.mls index c481673bca..bcbddb6ae8 100644 --- a/shared/src/test/diff/nu/OpLam.mls +++ b/shared/src/test/diff/nu/OpLam.mls @@ -38,7 +38,7 @@ x => x + 2 >> succ //│ ╟── from reference: //│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) //│ ╙── ^ -//│ Int -> (error | Int -> Int) +//│ Int -> (error | anything -> Int) //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/nu/SimpleSymbolicOps.mls b/shared/src/test/diff/nu/SimpleSymbolicOps.mls new file mode 100644 index 0000000000..cdd52ef17f --- /dev/null +++ b/shared/src/test/diff/nu/SimpleSymbolicOps.mls @@ -0,0 +1,20 @@ +:NewDefs + + +fun (-) i(x, y) = x +//│ fun (-) i: forall 'a. ('a, anything) -> 'a + +1 - 1 +//│ 1 +//│ res +//│ = 1 + + +fun (-) i(x, y) = x +[i(1,1), i(2,1), 1 - 1, 2 - 1] +//│ fun (-) i: forall 'a. ('a, anything) -> 'a +//│ [1, 2, 1, 2] +//│ res +//│ = [Function: i1] + + diff --git a/shared/src/test/diff/nu/i180.mls b/shared/src/test/diff/nu/i180.mls new file mode 100644 index 0000000000..39013ced9f --- /dev/null +++ b/shared/src/test/diff/nu/i180.mls @@ -0,0 +1,79 @@ +:NewDefs + + +fun (++) stringConcat(a, b) = concat(a)(b) +//│ fun (++) stringConcat: (Str, Str) -> Str + +type List[out A] = Cons[A] | Nil +class Cons[out A](head: A, tail: List[A]) { + fun join(sep: Str): Str + fun join(sep) = + if tail is + Nil then toString(head) + Cons(x, Nil) then toString(head) ++ sep ++ toString(x) + Cons(x, xs) then toString(head) ++ sep ++ toString(x) ++ sep ++ xs.join(sep) +} +module Nil { + fun join(sep: Str): Str = "" + fun contains(x): Bool = false +} +//│ type List[A] = Cons[A] | Nil +//│ class Cons[A](head: A, tail: List[A]) { +//│ fun join: (sep: Str) -> Str +//│ } +//│ module Nil { +//│ fun contains: anything -> Bool +//│ fun join: (sep: Str) -> Str +//│ } + + +fun (::) cons[A](x: A, xs: List[A]): List[A] = Cons(x, xs) +//│ fun (::) cons: forall 'A. (x: 'A, xs: List['A]) -> List['A] + +(1 :: Nil).join(", ") +(1 :: (2 :: Nil)).join(", ") +(1 :: (2 :: (3 :: Nil))).join(", ") +(1 :: (2 :: (3 :: (4 :: Nil)))).join(", ") +(1 :: (2 :: (3 :: (4 :: (5 :: Nil))))).join(", ") +//│ Str +//│ res +//│ = '1' +//│ res +//│ = '1, 2' +//│ res +//│ = '1, 2, 3' +//│ res +//│ = '1, 2, 3, 4' +//│ res +//│ = '1, 2, 3, 4, 5' + + +fun (:-) listExclude(xs, x) = + if xs is + Nil then Nil + Cons(x', xs') and + x === x' then xs' :- x + else x' :: (xs' :- x) +//│ fun (:-) listExclude: forall 'A. (Cons['A] | Nil, Eql['A]) -> (Nil | List['A]) + +(Nil :- 0).join(", ") +((0 :: Nil) :- 0).join(", ") +((1 :: Nil) :- 0).join(", ") +((1 :: (2 :: Nil)) :- 0).join(", ") +//│ Str +//│ res +//│ = '' +//│ res +//│ = '' +//│ res +//│ = '1' +//│ res +//│ = '1, 2' + + +("x" :: Nil).join(", ") +//│ Str +//│ res +//│ = 'x' + + From fa586244525dad6d2e107fd9b5866785389fcd83 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 20 Sep 2023 23:26:48 +0800 Subject: [PATCH 452/498] Pretty-print long record types on several lines --- shared/src/main/scala/mlscript/helpers.scala | 12 +- shared/src/test/diff/ecoop23/Intro.mls | 7 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 20 ++- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 14 +- shared/src/test/diff/fcp/NestedDataTypes.mls | 6 +- .../src/test/diff/fcp/NestedDataTypesGADT.mls | 13 +- .../src/test/diff/fcp/QML_exist_Classes.mls | 169 +++++++++++------- .../test/diff/fcp/QML_exist_Classes_min.mls | 22 +-- .../src/test/diff/fcp/QML_exist_Records_D.mls | 78 ++++++-- .../test/diff/fcp/QML_exist_Records_ND.mls | 103 +++++++---- .../test/diff/fcp/QML_exist_Records_min_1.mls | 8 +- shared/src/test/diff/mlscript/David2.mls | 13 +- shared/src/test/diff/mlscript/ExprProb.mls | 33 +++- shared/src/test/diff/mlscript/ExprProb2.mls | 44 +++-- .../src/test/diff/mlscript/ExprProb_Inv.mls | 13 +- shared/src/test/diff/mlscript/HeadOption.mls | 20 ++- .../diff/mlscript/PolyVariantCodeReuse.mls | 15 +- shared/src/test/diff/mlscript/Yicong.mls | 158 ++++++++-------- shared/src/test/diff/mlscript/Yuheng.mls | 18 +- shared/src/test/diff/nu/FlatMonads.mls | 18 +- shared/src/test/diff/nu/MetaWrap.mls | 50 +++++- shared/src/test/diff/nu/NestedRecords.mls | 45 +++++ .../test/diff/nu/PolymorphicVariants_Alt.mls | 4 +- shared/src/test/diff/tapl/SimplyTyped.mls | 96 ++++++---- shared/src/test/diff/tapl/Untyped.mls | 60 ++++++- shared/src/test/diff/ucs/InterleavedLet.mls | 49 +++-- shared/src/test/diff/ucs/SimpleUCS.mls | 6 +- 27 files changed, 740 insertions(+), 354 deletions(-) create mode 100644 shared/src/test/diff/nu/NestedRecords.mls diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 6c0d674359..116a7a0408 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -53,7 +53,8 @@ trait TypeLikeImpl extends Located { self: TypeLike => parensIf("(..." + l.showIn(ctx, 0) + ") -> " + r.showIn(ctx, 30), outerPrec > 30) case Function(l, r) => parensIf(l.showIn(ctx, 31) + " -> " + r.showIn(ctx, 30), outerPrec > 30) case Neg(t) => s"~${t.showIn(ctx, 100)}" - case Record(fs) => fs.map { nt => + case Record(fs) => + val strs = fs.map { nt => val nme = nt._1.name if (nme.isCapitalized) nt._2 match { case Field(N | S(Bot), Top) => s"$nme" @@ -63,7 +64,11 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Field(S(lb), ub) => s"$nme :> ${lb.showIn(ctx, 0)} <: ${ub.showIn(ctx, 0)}" } else s"${nt._2.mutStr}${nme}: ${showField(nt._2, ctx)}" - }.mkString("{", ", ", "}") + } + if (strs.foldLeft(0)(_ + _.length) > 80) + strs.mkString("{\n" + ctx.indStr, ",\n" + ctx.indStr, "") + .indentNewLines(ShowCtx.indentation) + "\n" + ctx.indStr + "}" + else strs.mkString("{", ", ", "}") case Splice(fs) => val inner = fs.map{case L(l) => s"...${l.showIn(ctx, 0)}" case R(r) => s"${showField(r, ctx)}"} if (ctx.newDefs) inner.mkString("[", ", ", "]") else inner.mkString("(", ", ", ")") @@ -286,13 +291,14 @@ final case class ShowCtx( angletards: Bool = false, ) { - lazy val indStr: Str = " " * indentLevel + lazy val indStr: Str = ShowCtx.indentation * indentLevel def lnIndStr: Str = "\n" + indStr def indent: ShowCtx = copy(indentLevel = indentLevel + 1) def < : Str = if (angletards) "<" else "[" def > : Str = if (angletards) ">" else "]" } object ShowCtx { + def indentation: Str = " " /** * Create a context from a list of types. For named variables and * hinted variables use what is given. For unnamed variables generate diff --git a/shared/src/test/diff/ecoop23/Intro.mls b/shared/src/test/diff/ecoop23/Intro.mls index 9a583c0a54..dda082110c 100644 --- a/shared/src/test/diff/ecoop23/Intro.mls +++ b/shared/src/test/diff/ecoop23/Intro.mls @@ -96,7 +96,12 @@ module CompareMyPoint extends ComparePoint, CompareColored, CompareNested //│ } //│ where //│ 'b <: {color: 'color, parent: Object & ~#Some | Some['b], x: 'c, y: 'd} -//│ 'a <: {color: {equals: 'color -> Bool}, parent: Object & ~#Some | Some['a], x: Eql['c], y: Eql['d]} +//│ 'a <: { +//│ color: {equals: 'color -> Bool}, +//│ parent: Object & ~#Some | Some['a], +//│ x: Eql['c], +//│ y: Eql['d] +//│ } let p0 = MyPoint(0, 0, Red, None) diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index b56ed8e3fe..607c8d4d21 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -72,7 +72,9 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b) -> 'c} -//│ this: {eval: ('a, 'd) -> ('A & 'e) & (Cons[[Str, 'e]], 'f) -> 'c & (Cons[[Str, Var] | 'A0], 'g) -> 'A1} +//│ this: { +//│ eval: ('a, 'd) -> ('A & 'e) & (Cons[[Str, 'e]], 'f) -> 'c & (Cons[[Str, Var] | 'A0], 'g) -> 'A1 +//│ } //│ fun eval: ('a & (Cons['A0] | Nil), Abs['g] | App['d & (Abs['f] | Object & ~#Abs)] | Object & 'b & ~#Abs & ~#App) -> (Abs['A1] | App['A] | 'c) //│ } @@ -175,16 +177,16 @@ Test2.eval(Cons(("a", Numb(1)), Nil), Var("a")) :e Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.176: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.129: if v is +//│ ║ l.131: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.139: let vv = map_expr(eta, v) +//│ ║ l.141: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Numb | Var | error //│ res @@ -241,16 +243,16 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr :e Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.242: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.244: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.242: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.244: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.129: if v is +//│ ║ l.131: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.139: let vv = map_expr(eta, v) +//│ ║ l.141: let vv = map_expr(eta, v) //│ ╙── ^ //│ error | 'A //│ where diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index c268e1d78b..01a853089a 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -291,7 +291,9 @@ mixin Eliminate { else e } //│ mixin Eliminate() { -//│ this: {eliminate: 'a -> 'b & 'c -> 'Region & 'd -> 'Region0 & 'e -> 'Region1 & 'f -> 'Region2 & 'g -> 'Region3} +//│ this: { +//│ eliminate: 'a -> 'b & 'c -> 'Region & 'd -> 'Region0 & 'e -> 'Region1 & 'f -> 'Region2 & 'g -> 'Region3 +//│ } //│ fun eliminate: (Intersect['e] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['c & (Object & ~#Outside | Outside['a])] | Scale['g] | Translate['f] | Union['d]) -> (Intersect['Region1] | Outside['Region] | Scale['Region3] | Translate['Region2] | Union['Region0] | 'b) //│ } @@ -403,10 +405,10 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.404: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.406: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.328: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.330: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.113: if a is @@ -426,13 +428,13 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.427: Lang.text(mk(100)) +//│ ║ l.429: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.328: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.330: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.427: Lang.text(mk(100)) +//│ ║ l.429: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.156: if e is diff --git a/shared/src/test/diff/fcp/NestedDataTypes.mls b/shared/src/test/diff/fcp/NestedDataTypes.mls index 9c0eb4f5d3..402062b150 100644 --- a/shared/src/test/diff/fcp/NestedDataTypes.mls +++ b/shared/src/test/diff/fcp/NestedDataTypes.mls @@ -223,7 +223,9 @@ rec def map f tree = case tree of { //│ map: ('value -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'value0) & 'a -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'b & 'A) & 'c -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'd & 'A) & 'e -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'f & 'A) & 'g -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'h & 'A)) -> 'i -> 'subTree //│ where //│ 'subTree :> Leaf[((nothing, (nothing, nothing,) | 'd,) | 'b, ((nothing, nothing,) | 'h, nothing,) | 'f,) | 'value0] | (Node['A] with {subTree: 'subTree}) -//│ 'i <: Leaf[?] & {value: ((anything, (anything, anything,) & 'c,) & 'a, ((anything, anything,) & 'g, anything,) & 'e,) & 'value} | (Node[?] with {subTree: 'i}) +//│ 'i <: Leaf[?] & { +//│ value: ((anything, (anything, anything,) & 'c,) & 'a, ((anything, anything,) & 'g, anything,) & 'e,) & 'value +//│ } | (Node[?] with {subTree: 'i}) //│ 'A :> ((nothing, nothing,) | 'h, (nothing, nothing,) | 'd,) //│ <: Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] //│ = [Function: map] @@ -265,7 +267,7 @@ map succ n4 //│ 'a <: 'value -> 'value0) //│ ╙── //│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b. ?b) -> ?c` exceeded recursion depth limit (250) -//│ ║ l.257: map succ n4 +//│ ║ l.259: map succ n4 //│ ║ ^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error diff --git a/shared/src/test/diff/fcp/NestedDataTypesGADT.mls b/shared/src/test/diff/fcp/NestedDataTypesGADT.mls index db15e37181..3e49f0f67b 100644 --- a/shared/src/test/diff/fcp/NestedDataTypesGADT.mls +++ b/shared/src/test/diff/fcp/NestedDataTypesGADT.mls @@ -63,7 +63,10 @@ d1_ : HTree[Z, int] //│ = [Function: d1_] d2 = DNode { subTree = (d1_, d1_); n = S{} } -//│ d2: DNode['N, 1] with {n: forall 'P. S['P], subTree: (forall 'a. (DLeaf[1] -> 'a) -> 'a, forall 'a. (DLeaf[1] -> 'a) -> 'a,)} +//│ d2: DNode['N, 1] with { +//│ n: forall 'P. S['P], +//│ subTree: (forall 'a. (DLeaf[1] -> 'a) -> 'a, forall 'a. (DLeaf[1] -> 'a) -> 'a,) +//│ } //│ = DNode { n: S {}, subTree: [ [Function: d1_], [Function: d1_] ] } def d1_ty: HTree[Z, int] @@ -91,11 +94,11 @@ d2_ k = k d2 :e // FIXME d2_ : HTree[S[Z], int] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.92: d2_ : HTree[S[Z], int] +//│ ║ l.95: d2_ : HTree[S[Z], int] //│ ║ ^^^ //│ ╟── expression of type `S[in Z & 'p out Z | 'p]` is not an instance of `Z` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.69: def d1_ty: HTree[Z, int] +//│ ║ l.72: def d1_ty: HTree[Z, int] //│ ║ ^ //│ ╟── Note: class type parameter N is defined at: //│ ║ l.36: class DNode[N, A]: HTreeBase[S[N], A] & { subTree: Two[HTree[N, A]] } @@ -111,10 +114,10 @@ d2_ : HTree[S[Z], int] //│ = //│ d2 and d1_ty are not implemented //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.109: d2_ : HTree[S[Z], int] +//│ ║ l.112: d2_ : HTree[S[Z], int] //│ ║ ^^^ //│ ╟── type `HTreeBase[S[Z], ?]` does not match type `DLeaf[int] | DNode[S[in Z & 'p out Z | 'p], int]` -//│ ║ l.108: d2_ k = k (d2:HTreeBase[S[Z], int]) +//│ ║ l.111: d2_ k = k (d2:HTreeBase[S[Z], int]) //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.37: type HTree[N, A] = forall 'r. (forall 'p. (DLeaf[A] | DNode[S['p], A] & DNode[N, A]) -> 'r) -> 'r diff --git a/shared/src/test/diff/fcp/QML_exist_Classes.mls b/shared/src/test/diff/fcp/QML_exist_Classes.mls index 683f832a81..f550afb0f0 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes.mls @@ -45,7 +45,12 @@ baseImpl = ArraysImpl { update = fun r -> fun (i : int) -> fun a -> a; fold = fun f -> fun b -> fun r -> f r b } -//│ baseImpl: ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> int -> 'e, update: forall 'f. anything -> int -> 'f -> 'f} +//│ baseImpl: ArraysImpl['Rep, 'Rep] with { +//│ fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, +//│ init: forall 'd. 'd -> 'd, +//│ sub: forall 'e. 'e -> int -> 'e, +//│ update: forall 'f. anything -> int -> 'f -> 'f +//│ } //│ = ArraysImpl { //│ init: [Function: init], //│ sub: [Function: sub], @@ -57,7 +62,12 @@ def base: Arrays['a] def base f = f baseImpl //│ base: Arrays['a] //│ = -//│ ((forall 'Rep. ArraysImpl['Rep, 'Rep] with {fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> int -> 'e, update: forall 'f. anything -> int -> 'f -> 'f}) -> 'g) -> 'g +//│ ((forall 'Rep. ArraysImpl['Rep, 'Rep] with { +//│ fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, +//│ init: forall 'd. 'd -> 'd, +//│ sub: forall 'e. 'e -> int -> 'e, +//│ update: forall 'f. anything -> int -> 'f -> 'f +//│ }) -> 'g) -> 'g //│ <: base: //│ Arrays['a] //│ = [Function: base] @@ -72,15 +82,20 @@ def simpleStepImpl arrImpl = ArraysImpl { update = fun ((r0, r1)) -> fun i -> fun a -> (arrImpl.Update r0 i a, "updated"); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f b r0 } -//│ simpleStepImpl: ArraysRep[in 'A & 'A0 & 'A1 out 'A0 | 'A, in 'Rep & 'Rep0 & 'a out 'Rep | 'Rep0] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b. ('A0 -> 'b -> 'b) -> 'b -> (('Rep0, anything,),) -> 'b, init: 'A -> ('Rep, "initialized",), sub: (('Rep0, anything,),) -> int -> 'A0, update: forall 'c. (('Rep0 & 'c, anything,),) -> int -> 'A -> ('Rep | 'c, "updated",)}) -//│ where -//│ 'Rep1 :> ('Rep | 'd, "initialized" | "updated",) -//│ <: ('Rep0 & 'a, anything,) -//│ 'a <: 'Rep0 & 'd -//│ 'd :> 'Rep -//│ <: 'Rep0 & 'a -//│ 'A1 :> 'A0 -//│ <: 'A +//│ simpleStepImpl: ArraysRep[in 'A & 'A0 & 'A1 out 'A0 | 'A, in 'Rep & 'Rep0 & 'a out 'Rep | 'Rep0] -> (ArraysImpl['A1, 'Rep1] with { +//│ fold: forall 'b. ('A0 -> 'b -> 'b) -> 'b -> (('Rep0, anything,),) -> 'b, +//│ init: 'A -> ('Rep, "initialized",), +//│ sub: (('Rep0, anything,),) -> int -> 'A0, +//│ update: forall 'c. (('Rep0 & 'c, anything,),) -> int -> 'A -> ('Rep | 'c, "updated",) +//│ }) +//│ where +//│ 'Rep1 :> ('Rep | 'd, "initialized" | "updated",) +//│ <: ('Rep0 & 'a, anything,) +//│ 'a <: 'Rep0 & 'd +//│ 'd :> 'Rep +//│ <: 'Rep0 & 'a +//│ 'A1 :> 'A0 +//│ <: 'A //│ = [Function: simpleStepImpl] def simpleStepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] @@ -88,15 +103,20 @@ def simpleStepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ = simpleStepImpl_ty = simpleStepImpl -//│ ArraysRep[in 'A & 'A0 & 'A1 out 'A0 | 'A, in 'Rep & 'Rep0 & 'a out 'Rep | 'Rep0] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b. ('A0 -> 'b -> 'b) -> 'b -> (('Rep0, anything,),) -> 'b, init: 'A -> ('Rep, "initialized",), sub: (('Rep0, anything,),) -> int -> 'A0, update: forall 'c. (('Rep0 & 'c, anything,),) -> int -> 'A -> ('Rep | 'c, "updated",)}) -//│ where -//│ 'Rep1 :> ('Rep | 'd, "initialized" | "updated",) -//│ <: ('Rep0 & 'a, anything,) -//│ 'a <: 'Rep0 & 'd -//│ 'd :> 'Rep -//│ <: 'Rep0 & 'a -//│ 'A1 :> 'A0 -//│ <: 'A +//│ ArraysRep[in 'A & 'A0 & 'A1 out 'A0 | 'A, in 'Rep & 'Rep0 & 'a out 'Rep | 'Rep0] -> (ArraysImpl['A1, 'Rep1] with { +//│ fold: forall 'b. ('A0 -> 'b -> 'b) -> 'b -> (('Rep0, anything,),) -> 'b, +//│ init: 'A -> ('Rep, "initialized",), +//│ sub: (('Rep0, anything,),) -> int -> 'A0, +//│ update: forall 'c. (('Rep0 & 'c, anything,),) -> int -> 'A -> ('Rep | 'c, "updated",) +//│ }) +//│ where +//│ 'Rep1 :> ('Rep | 'd, "initialized" | "updated",) +//│ <: ('Rep0 & 'a, anything,) +//│ 'a <: 'Rep0 & 'd +//│ 'd :> 'Rep +//│ <: 'Rep0 & 'a +//│ 'A1 :> 'A0 +//│ <: 'A //│ <: simpleStepImpl_ty: //│ ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)] //│ = [Function: simpleStepImpl] @@ -108,7 +128,7 @@ simpleStepImpl_ty = simpleStepImpl :stats simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b. ?a -> ?b <: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)]` took too many steps and ran out of fuel (10000) -//│ ║ l.109: simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] +//│ ║ l.129: simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)] @@ -185,7 +205,7 @@ sb (fun arr -> arr.Sub (arr.Init true) 1) :e // * Type error is expected – argument order confusion sb (fun arr -> arr.Sub 0 (arr.Init true)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.186: sb (fun arr -> arr.Sub 0 (arr.Init true)) +//│ ║ l.206: sb (fun arr -> arr.Sub 0 (arr.Init true)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'Rep` is not an instance of type `int` //│ ║ l.37: type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r @@ -194,7 +214,7 @@ sb (fun arr -> arr.Sub 0 (arr.Init true)) //│ ║ l.9: method Sub: Rep -> int -> A //│ ║ ^^^ //│ ╟── from application: -//│ ║ l.186: sb (fun arr -> arr.Sub 0 (arr.Init true)) +//│ ║ l.206: sb (fun arr -> arr.Sub 0 (arr.Init true)) //│ ║ ^^^^^^^^^^^^^ //│ ╟── Note: quantified type variable 'Rep is defined at: //│ ║ l.37: type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r @@ -213,26 +233,26 @@ sb (fun arr -> arr.Update (arr.Init true) 1 false) :e // * Rightly prevent skolem confusion sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) //│ ╔══[ERROR] Type error in application -//│ ║ l.214: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) +//│ ║ l.234: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'Rep` leaks out of its scope //│ ║ l.37: type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this application: -//│ ║ l.214: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) +//│ ║ l.234: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) //│ ║ ^^^^^^^^^^^^^^ //│ ╟── • this application: -//│ ║ l.173: sb = simpleStep base +//│ ║ l.193: sb = simpleStep base //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.214: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) +//│ ║ l.234: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) //│ ║ ^^ //│ ╟── • this reference: -//│ ║ l.214: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) +//│ ║ l.234: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) //│ ║ ^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.214: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) +//│ ║ l.234: sb (fun arr1 -> sb (fun arr2 -> arr2.Update (arr1.Init true))) //│ ╙── ^^^^^^^^^^^^^^ //│ res: error | int -> anything -> (??Rep | ??Rep0) //│ = [Function (anonymous)] @@ -250,63 +270,73 @@ sb (fun arr -> :e def simpleStep arr = arr (fun impl -> fun k -> k (simpleStepImpl impl)) -//│ ((forall 'Rep 'a 'A 'c 'A0 'd 'Rep0 'A1. ArraysRep[in 'A1 & 'A & 'A0 out 'A | 'A1, in 'Rep0 & 'Rep & 'c out 'Rep0 | 'Rep] -> ((forall 'Rep1. ArraysImpl['A0, 'Rep1] with {fold: forall 'b. ('A -> 'b -> 'b) -> 'b -> (('Rep, anything,),) -> 'b, init: 'A1 -> ('Rep0, "initialized",), sub: (('Rep, anything,),) -> int -> 'A, update: forall 'e. (('Rep & 'e, anything,),) -> int -> 'A1 -> ('Rep0 | 'e, "updated",)}) -> 'a) -> 'a) -> 'f) -> 'f -//│ where -//│ 'Rep1 :> ('Rep0 | 'd, "initialized" | "updated",) -//│ <: ('Rep & 'c, anything,) -//│ 'c <: 'Rep & 'd -//│ 'd :> 'Rep0 -//│ <: 'Rep & 'c -//│ 'A0 :> 'A -//│ <: 'A1 +//│ ((forall 'Rep 'a 'A 'c 'A0 'd 'Rep0 'A1. ArraysRep[in 'A1 & 'A & 'A0 out 'A | 'A1, in 'Rep0 & 'Rep & 'c out 'Rep0 | 'Rep] -> ((forall 'Rep1. ArraysImpl['A0, 'Rep1] with { +//│ fold: forall 'b. ('A -> 'b -> 'b) -> 'b -> (('Rep, anything,),) -> 'b, +//│ init: 'A1 -> ('Rep0, "initialized",), +//│ sub: (('Rep, anything,),) -> int -> 'A, +//│ update: forall 'e. (('Rep & 'e, anything,),) -> int -> 'A1 -> ('Rep0 | 'e, "updated",) +//│ }) -> 'a) -> 'a) -> 'f) -> 'f +//│ where +//│ 'Rep1 :> ('Rep0 | 'd, "initialized" | "updated",) +//│ <: ('Rep & 'c, anything,) +//│ 'c <: 'Rep & 'd +//│ 'd :> 'Rep0 +//│ <: 'Rep & 'c +//│ 'A0 :> 'A +//│ <: 'A1 //│ <: simpleStep: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.252: def simpleStep arr = arr (fun impl -> fun k -> k (simpleStepImpl impl)) +//│ ║ l.272: def simpleStep arr = arr (fun impl -> fun k -> k (simpleStepImpl impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'Rep` leaks out of its scope //│ ║ l.37: type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this applied expression: -//│ ║ l.252: def simpleStep arr = arr (fun impl -> fun k -> k (simpleStepImpl impl)) +//│ ║ l.272: def simpleStep arr = arr (fun impl -> fun k -> k (simpleStepImpl impl)) //│ ║ ^^^ //│ ╟── • this function: -//│ ║ l.252: def simpleStep arr = arr (fun impl -> fun k -> k (simpleStepImpl impl)) +//│ ║ l.272: def simpleStep arr = arr (fun impl -> fun k -> k (simpleStepImpl impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.71: sub = fun ((r0, r1)) -> fun i -> arrImpl.Sub r0 i; +//│ ║ l.81: sub = fun ((r0, r1)) -> fun i -> arrImpl.Sub r0 i; //│ ╙── ^^ //│ = [Function: simpleStep1] :e def simpleStep2 arr k = arr (fun impl -> k (simpleStepImpl impl)) -//│ ((ArraysRep[out 'A, out 'Rep] -> 'a) -> 'c) -> ((forall 'Rep0. ArraysImpl[in 'A & 'A0 out 'A0, 'Rep0] with {fold: forall 'b. (nothing -> 'b -> 'b) -> 'b -> (('Rep, anything,),) -> 'b, init: 'A -> (nothing, "initialized",), sub: (('Rep, anything,),) -> int -> nothing, update: forall 'd. (('Rep & 'd, anything,),) -> int -> 'A -> ('d, "updated",)}) -> 'a) -> 'c -//│ where -//│ 'Rep0 :> ('e | 'f, "initialized" | "updated",) -//│ <: ('Rep & 'g & 'h, anything,) -//│ 'f :> 'e -//│ <: 'Rep & 'g & 'h -//│ 'h <: 'Rep & 'f -//│ 'e <: 'Rep & 'g -//│ 'g <: 'Rep & 'e +//│ ((ArraysRep[out 'A, out 'Rep] -> 'a) -> 'c) -> ((forall 'Rep0. ArraysImpl[in 'A & 'A0 out 'A0, 'Rep0] with { +//│ fold: forall 'b. (nothing -> 'b -> 'b) -> 'b -> (('Rep, anything,),) -> 'b, +//│ init: 'A -> (nothing, "initialized",), +//│ sub: (('Rep, anything,),) -> int -> nothing, +//│ update: forall 'd. (('Rep & 'd, anything,),) -> int -> 'A -> ('d, "updated",) +//│ }) -> 'a) -> 'c +//│ where +//│ 'Rep0 :> ('e | 'f, "initialized" | "updated",) +//│ <: ('Rep & 'g & 'h, anything,) +//│ 'f :> 'e +//│ <: 'Rep & 'g & 'h +//│ 'h <: 'Rep & 'f +//│ 'e <: 'Rep & 'g +//│ 'g <: 'Rep & 'e //│ <: simpleStep2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.283: def simpleStep2 arr k = arr (fun impl -> k (simpleStepImpl impl)) +//│ ║ l.308: def simpleStep2 arr k = arr (fun impl -> k (simpleStepImpl impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'Rep` leaks out of its scope //│ ║ l.37: type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.73: fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f b r0 +//│ ║ l.83: fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f b r0 //│ ║ ^^^^^^^ //│ ╟── • this reference: -//│ ║ l.283: def simpleStep2 arr k = arr (fun impl -> k (simpleStepImpl impl)) +//│ ║ l.308: def simpleStep2 arr k = arr (fun impl -> k (simpleStepImpl impl)) //│ ║ ^^^^ //│ ╟── • this applied expression: -//│ ║ l.283: def simpleStep2 arr k = arr (fun impl -> k (simpleStepImpl impl)) +//│ ║ l.308: def simpleStep2 arr k = arr (fun impl -> k (simpleStepImpl impl)) //│ ╙── ^^^ //│ = [Function: simpleStep21] @@ -350,18 +380,23 @@ def stepImpl arrImpl = ArraysImpl { else (r0, arrImpl.Update r1 (div i 2) a); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.Fold f (arrImpl.Fold f b r0) r1 } -//│ stepImpl: ArraysRep[in 'A & 'A0 & 'A1 out 'A0 | 'A, in 'Rep & 'Rep0 & 'a & 'c out 'Rep | 'Rep0] -> (ArraysImpl['A1, 'Rep1] with {fold: forall 'b 'b0. ('A0 -> 'b0 -> 'b0 & 'A0 -> 'b -> ('b0 & 'b)) -> ('b0 & 'b) -> (('Rep0, 'Rep0,),) -> 'b0, init: 'A -> ('Rep, 'Rep,), sub: (('Rep0, 'Rep0,),) -> int -> 'A0, update: forall 'd 'e. (('Rep0 & 'd, 'Rep0 & 'e,),) -> int -> 'A -> ('Rep | 'd, 'Rep | 'e,)}) -//│ where -//│ 'Rep1 :> ('Rep | 'a | 'f, 'Rep | 'c | 'g,) -//│ <: ('Rep0 & 'a, 'Rep0 & 'c,) -//│ 'c <: 'Rep0 & 'g -//│ 'g :> 'Rep -//│ <: 'Rep0 & 'c -//│ 'a <: 'Rep0 & 'f -//│ 'f :> 'Rep -//│ <: 'Rep0 & 'a -//│ 'A1 :> 'A0 -//│ <: 'A +//│ stepImpl: ArraysRep[in 'A & 'A0 & 'A1 out 'A0 | 'A, in 'Rep & 'Rep0 & 'a & 'c out 'Rep | 'Rep0] -> (ArraysImpl['A1, 'Rep1] with { +//│ fold: forall 'b 'b0. ('A0 -> 'b0 -> 'b0 & 'A0 -> 'b -> ('b0 & 'b)) -> ('b0 & 'b) -> (('Rep0, 'Rep0,),) -> 'b0, +//│ init: 'A -> ('Rep, 'Rep,), +//│ sub: (('Rep0, 'Rep0,),) -> int -> 'A0, +//│ update: forall 'd 'e. (('Rep0 & 'd, 'Rep0 & 'e,),) -> int -> 'A -> ('Rep | 'd, 'Rep | 'e,) +//│ }) +//│ where +//│ 'Rep1 :> ('Rep | 'a | 'f, 'Rep | 'c | 'g,) +//│ <: ('Rep0 & 'a, 'Rep0 & 'c,) +//│ 'c <: 'Rep0 & 'g +//│ 'g :> 'Rep +//│ <: 'Rep0 & 'c +//│ 'a <: 'Rep0 & 'f +//│ 'f :> 'Rep +//│ <: 'Rep0 & 'a +//│ 'A1 :> 'A0 +//│ <: 'A //│ = [Function: stepImpl] diff --git a/shared/src/test/diff/fcp/QML_exist_Classes_min.mls b/shared/src/test/diff/fcp/QML_exist_Classes_min.mls index 60ee083587..fff2ca6edd 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes_min.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes_min.mls @@ -22,13 +22,15 @@ type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r def simpleStepImpl arrImpl = ArraysImpl { update = fun ((r0, r1)) -> fun i -> fun a -> (arrImpl.Update r0 i a, "updated") } -//│ simpleStepImpl: ArraysRep['A, in 'Rep & 'a out 'Rep | 'Rep0] -> (ArraysImpl['A, 'Rep1] with {update: forall 'b. (('Rep0 & 'b, anything,),) -> int -> 'A -> ('Rep | 'b, "updated",)}) -//│ where -//│ 'Rep1 :> ('c, "updated",) -//│ <: ('a, anything,) -//│ 'a <: 'Rep0 & 'c -//│ 'c :> 'Rep -//│ <: 'a +//│ simpleStepImpl: ArraysRep['A, in 'Rep & 'a out 'Rep | 'Rep0] -> (ArraysImpl['A, 'Rep1] with { +//│ update: forall 'b. (('Rep0 & 'b, anything,),) -> int -> 'A -> ('Rep | 'b, "updated",) +//│ }) +//│ where +//│ 'Rep1 :> ('c, "updated",) +//│ <: ('a, anything,) +//│ 'a <: 'Rep0 & 'c +//│ 'c :> 'Rep +//│ <: 'a //│ = [Function: simpleStepImpl] @@ -51,17 +53,17 @@ mkArrays impl k = k impl :e def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) //│ ╔══[ERROR] Type error in application -//│ ║ l.52: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) +//│ ║ l.54: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'Rep` leaks out of its scope //│ ║ l.18: type Arrays[A] = (forall 'Rep. ArraysRep[A, 'Rep] -> 'r) -> 'r //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this function: -//│ ║ l.52: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) +//│ ║ l.54: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.52: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) +//│ ║ l.54: def stepped = arr (fun arrImpl -> fun k -> k (simpleStepImpl arrImpl)) //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.23: update = fun ((r0, r1)) -> fun i -> fun a -> (arrImpl.Update r0 i a, "updated") diff --git a/shared/src/test/diff/fcp/QML_exist_Records_D.mls b/shared/src/test/diff/fcp/QML_exist_Records_D.mls index b86167df96..0d709ad756 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records_D.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records_D.mls @@ -31,7 +31,12 @@ baseImpl = { update = fun r -> fun i -> fun a -> a; fold = fun f -> fun b -> fun r -> f r b } -//│ baseImpl: {fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> anything -> 'e, update: forall 'f. anything -> anything -> 'f -> 'f} +//│ baseImpl: { +//│ fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, +//│ init: forall 'd. 'd -> 'd, +//│ sub: forall 'e. 'e -> anything -> 'e, +//│ update: forall 'f. anything -> anything -> 'f -> 'f +//│ } //│ = { //│ init: [Function: init], //│ sub: [Function: sub], @@ -56,7 +61,12 @@ def base: Arrays['a] // * (not within a more polymorphic context), // * so we do not need first-class parametric polymorphism to type check the definition. def base f = f baseImpl -//│ ({fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> anything -> 'e, update: forall 'f. anything -> anything -> 'f -> 'f} -> 'g) -> 'g +//│ ({ +//│ fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, +//│ init: forall 'd. 'd -> 'd, +//│ sub: forall 'e. 'e -> anything -> 'e, +//│ update: forall 'f. anything -> anything -> 'f -> 'f +//│ } -> 'g) -> 'g //│ <: base: //│ Arrays['a] //│ = [Function: base] @@ -84,11 +94,21 @@ def stepImpl (arrImpl: ArraysImpl['a, 'r]) = { update = fun ((r0, r1)) -> fun i -> fun a -> (arrImpl.update r0 i a, "hey"); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.fold f b r0 } -//│ stepImpl: ArraysImpl['a, 'r] -> {fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> (('r, anything,),) -> 'b, init: 'a -> ('r, "hi",), sub: (('r, anything,),) -> int -> 'a, update: (('r, anything,),) -> int -> 'a -> ('r, "hey",)} +//│ stepImpl: ArraysImpl['a, 'r] -> { +//│ fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> (('r, anything,),) -> 'b, +//│ init: 'a -> ('r, "hi",), +//│ sub: (('r, anything,),) -> int -> 'a, +//│ update: (('r, anything,),) -> int -> 'a -> ('r, "hey",) +//│ } //│ = [Function: stepImpl] stepImpl_ty = stepImpl -//│ ArraysImpl['a, 'r] -> {fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> (('r, anything,),) -> 'b, init: 'a -> ('r, "hi",), sub: (('r, anything,),) -> int -> 'a, update: (('r, anything,),) -> int -> 'a -> ('r, "hey",)} +//│ ArraysImpl['a, 'r] -> { +//│ fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> (('r, anything,),) -> 'b, +//│ init: 'a -> ('r, "hi",), +//│ sub: (('r, anything,),) -> int -> 'a, +//│ update: (('r, anything,),) -> int -> 'a -> ('r, "hey",) +//│ } //│ <: stepImpl_ty: //│ ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)] //│ = [Function: stepImpl] @@ -261,20 +281,20 @@ def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (ste //│ <: step2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.259: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.279: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.17: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.259: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.279: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^ //│ ╟── • this reference: -//│ ║ l.259: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.279: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.76: def stepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] +//│ ║ l.86: def stepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ╙── ^^ //│ = [Function: step24] @@ -287,44 +307,49 @@ def step arr = arr (fun impl -> fun k -> k (stepImpl_ty impl)) //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.285: def step arr = arr (fun impl -> fun k -> k (stepImpl_ty impl)) +//│ ║ l.305: def step arr = arr (fun impl -> fun k -> k (stepImpl_ty impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.17: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this applied expression: -//│ ║ l.285: def step arr = arr (fun impl -> fun k -> k (stepImpl_ty impl)) +//│ ║ l.305: def step arr = arr (fun impl -> fun k -> k (stepImpl_ty impl)) //│ ║ ^^^ //│ ╟── • this function: -//│ ║ l.285: def step arr = arr (fun impl -> fun k -> k (stepImpl_ty impl)) +//│ ║ l.305: def step arr = arr (fun impl -> fun k -> k (stepImpl_ty impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.76: def stepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] +//│ ║ l.86: def stepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ╙── ^^ //│ = [Function: step5] // * Still doesn't work if we only annotate `arr`, as `k` still leaks the internal repr :e def step (arr: Arrays['a]) = arr (fun impl -> fun k -> k (stepImpl impl)) -//│ Arrays['a] -> ({fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> ((??rep & 'r, anything,),) -> 'b, init: 'a -> ('r | ??rep0, "hi",), sub: ((??rep & 'r, anything,),) -> int -> 'a, update: ((??rep & 'r, anything,),) -> int -> 'a -> ('r | ??rep0, "hey",)} -> 'c) -> 'c +//│ Arrays['a] -> ({ +//│ fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> ((??rep & 'r, anything,),) -> 'b, +//│ init: 'a -> ('r | ??rep0, "hi",), +//│ sub: ((??rep & 'r, anything,),) -> int -> 'a, +//│ update: ((??rep & 'r, anything,),) -> int -> 'a -> ('r | ??rep0, "hey",) +//│ } -> 'c) -> 'c //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.309: def step (arr: Arrays['a]) = arr (fun impl -> fun k -> k (stepImpl impl)) +//│ ║ l.329: def step (arr: Arrays['a]) = arr (fun impl -> fun k -> k (stepImpl impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.17: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this function: -//│ ║ l.309: def step (arr: Arrays['a]) = arr (fun impl -> fun k -> k (stepImpl impl)) +//│ ║ l.329: def step (arr: Arrays['a]) = arr (fun impl -> fun k -> k (stepImpl impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.309: def step (arr: Arrays['a]) = arr (fun impl -> fun k -> k (stepImpl impl)) +//│ ║ l.329: def step (arr: Arrays['a]) = arr (fun impl -> fun k -> k (stepImpl impl)) //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.83: sub = fun ((r0, r1)) -> fun i -> arrImpl.sub r0 i; +//│ ║ l.93: sub = fun ((r0, r1)) -> fun i -> arrImpl.sub r0 i; //│ ╙── ^^ //│ = [Function: step6] @@ -428,11 +453,26 @@ def stepImpl_Ann = forall 'a 'rep. fun arrImpl -> { update = fun ((r0, r1)) -> fun i -> fun a -> (arrImpl.update r0 i a, "hey"); fold = fun f -> fun b -> fun ((r0, r1)) -> (arrImpl.fold: Fold['a, 'rep]) f b r0 } -//│ stepImpl_Ann: {fold: Fold['a, 'rep], init: 'c -> 'd, sub: 'e -> 'f -> 'g, update: 'h -> 'i -> 'j -> 'k} -> {fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> (('rep, anything,),) -> 'b, init: 'c -> ('d, "hi",), sub: (('e, anything,),) -> 'f -> 'g, update: (('h, anything,),) -> 'i -> 'j -> ('k, "hey",)} +//│ stepImpl_Ann: { +//│ fold: Fold['a, 'rep], +//│ init: 'c -> 'd, +//│ sub: 'e -> 'f -> 'g, +//│ update: 'h -> 'i -> 'j -> 'k +//│ } -> { +//│ fold: forall 'b. ('a -> 'b -> 'b) -> 'b -> (('rep, anything,),) -> 'b, +//│ init: 'c -> ('d, "hi",), +//│ sub: (('e, anything,),) -> 'f -> 'g, +//│ update: (('h, anything,),) -> 'i -> 'j -> ('k, "hey",) +//│ } //│ = [Function: stepImpl_Ann] def step arr = arr (fun impl -> fun (k: ArraysImplConsumer['a, 'r]) -> k (stepImpl_Ann impl)) -//│ ((forall 'a 'rep 'b. {fold: Fold['a, 'rep], init: 'a -> 'rep, sub: 'rep -> int -> 'a, update: 'rep -> int -> 'a -> 'rep} -> ArraysImplConsumer['a, 'b] -> 'b) -> 'c) -> 'c +//│ ((forall 'a 'rep 'b. { +//│ fold: Fold['a, 'rep], +//│ init: 'a -> 'rep, +//│ sub: 'rep -> int -> 'a, +//│ update: 'rep -> int -> 'a -> 'rep +//│ } -> ArraysImplConsumer['a, 'b] -> 'b) -> 'c) -> 'c //│ <: step: //│ Arrays['a] -> Arrays['a] //│ = [Function: step17] diff --git a/shared/src/test/diff/fcp/QML_exist_Records_ND.mls b/shared/src/test/diff/fcp/QML_exist_Records_ND.mls index d3bb90fb62..34a93be3fa 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records_ND.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records_ND.mls @@ -33,7 +33,12 @@ baseImpl = { update = fun r -> fun i -> fun a -> a; fold = fun f -> fun b -> fun r -> f r b } -//│ baseImpl: {fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> anything -> 'e, update: anything -> anything -> (forall 'f. 'f -> 'f)} +//│ baseImpl: { +//│ fold: forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c, +//│ init: forall 'd. 'd -> 'd, +//│ sub: forall 'e. 'e -> anything -> 'e, +//│ update: anything -> anything -> (forall 'f. 'f -> 'f) +//│ } //│ = { //│ init: [Function: init], //│ sub: [Function: sub], @@ -58,7 +63,12 @@ def base: Arrays['a] // * (not within a more polymorphic context), // * so we do not need first-class parametric polymorphism to type check the definition. def base f = f baseImpl -//│ ({fold: forall 'a 'b 'c. ('c -> 'a -> 'b) -> 'a -> 'c -> 'b, init: forall 'd. 'd -> 'd, sub: forall 'e. 'e -> anything -> 'e, update: anything -> anything -> (forall 'f. 'f -> 'f)} -> 'g) -> 'g +//│ ({ +//│ fold: forall 'a 'b 'c. ('c -> 'a -> 'b) -> 'a -> 'c -> 'b, +//│ init: forall 'd. 'd -> 'd, +//│ sub: forall 'e. 'e -> anything -> 'e, +//│ update: anything -> anything -> (forall 'f. 'f -> 'f) +//│ } -> 'g) -> 'g //│ <: base: //│ Arrays['a] //│ = [Function: base] @@ -86,11 +96,21 @@ def stepImpl (arrImpl: ArraysImpl['a, 'r]) = { update = fun ((r0, r1)) -> fun i -> fun a -> (arrImpl.update r0 i a, "hey"); fold = fun f -> fun b -> fun ((r0, r1)) -> arrImpl.fold f b r0 } -//│ stepImpl: ArraysImpl['a, 'r] -> {fold: forall 'b 'b0. ('a -> 'b -> ('b & 'b0)) -> (forall 'c. ('b & 'c) -> (('r, anything,),) -> ('b0 | 'c)), init: 'a -> ('r, "hi",), sub: (('r, anything,),) -> int -> 'a, update: (('r, anything,),) -> int -> 'a -> ('r, "hey",)} +//│ stepImpl: ArraysImpl['a, 'r] -> { +//│ fold: forall 'b 'b0. ('a -> 'b -> ('b & 'b0)) -> (forall 'c. ('b & 'c) -> (('r, anything,),) -> ('b0 | 'c)), +//│ init: 'a -> ('r, "hi",), +//│ sub: (('r, anything,),) -> int -> 'a, +//│ update: (('r, anything,),) -> int -> 'a -> ('r, "hey",) +//│ } //│ = [Function: stepImpl] stepImpl_ty = stepImpl -//│ ArraysImpl['a, 'r] -> {fold: forall 'b 'b0. ('a -> 'b -> ('b & 'b0)) -> (forall 'c. ('b & 'c) -> (('r, anything,),) -> ('b0 | 'c)), init: 'a -> ('r, "hi",), sub: (('r, anything,),) -> int -> 'a, update: (('r, anything,),) -> int -> 'a -> ('r, "hey",)} +//│ ArraysImpl['a, 'r] -> { +//│ fold: forall 'b 'b0. ('a -> 'b -> ('b & 'b0)) -> (forall 'c. ('b & 'c) -> (('r, anything,),) -> ('b0 | 'c)), +//│ init: 'a -> ('r, "hi",), +//│ sub: (('r, anything,),) -> int -> 'a, +//│ update: (('r, anything,),) -> int -> 'a -> ('r, "hey",) +//│ } //│ <: stepImpl_ty: //│ ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string,)] //│ = [Function: stepImpl] @@ -163,11 +183,11 @@ def step (arr: Arrays['a]) = arr helper //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Subtyping constraint of the form `Arrays['a] <: (forall 'a0 'rep. ArraysImpl['a0, 'rep] -> (forall ?a 'res 'b. ArraysImplConsumer['b, 'res] -> ?a)) -> ?b` took too many steps and ran out of fuel (10000) -//│ ║ l.161: def step (arr: Arrays['a]) = arr helper +//│ ║ l.181: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Subtyping constraint of the form `forall 'a ?a. Arrays['a] -> ?a <: forall 'a0. Arrays['a0] -> Arrays['a0]` took too many steps and ran out of fuel (10000) -//│ ║ l.161: def step (arr: Arrays['a]) = arr helper +//│ ║ l.181: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ = [Function: step3] @@ -193,62 +213,77 @@ def step (arr: Arrays['a]) = arr helper // * Doesn't work (`'rep` leaks out of its scope in `step`) def helper impl k = k (stepImpl impl) -//│ helper: ArraysImpl[in 'a out 'a | 'a0, in 'r out 'r | 'r0] -> (forall 'a1 'r1 'c. ({fold: forall 'b 'b0. (('a | 'a1) -> 'b -> ('b & 'b0)) -> (forall 'd. ('b & 'd) -> (('r0 & 'r1, anything,),) -> ('b0 | 'd)), init: ('a0 & 'a1) -> ('r | 'r1, "hi",), sub: (('r0 & 'r1, anything,),) -> int -> ('a | 'a1), update: (('r0 & 'r1, anything,),) -> int -> ('a0 & 'a1) -> ('r | 'r1, "hey",)} -> 'c) -> 'c) +//│ helper: ArraysImpl[in 'a out 'a | 'a0, in 'r out 'r | 'r0] -> (forall 'a1 'r1 'c. ({ +//│ fold: forall 'b 'b0. (('a | 'a1) -> 'b -> ('b & 'b0)) -> (forall 'd. ('b & 'd) -> (('r0 & 'r1, anything,),) -> ('b0 | 'd)), +//│ init: ('a0 & 'a1) -> ('r | 'r1, "hi",), +//│ sub: (('r0 & 'r1, anything,),) -> int -> ('a | 'a1), +//│ update: (('r0 & 'r1, anything,),) -> int -> ('a0 & 'a1) -> ('r | 'r1, "hey",) +//│ } -> 'c) -> 'c) //│ = [Function: helper4] // * Idem def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) -//│ helper: ArraysImpl['a, 'rep] -> (forall 'c. ({fold: forall 'b 'b0. ('a -> 'b -> ('b & 'b0)) -> (forall 'd. ('b & 'd) -> (('rep, anything,),) -> ('b0 | 'd)), init: 'a -> ('rep, "hi",), sub: (('rep, anything,),) -> int -> 'a, update: (('rep, anything,),) -> int -> 'a -> ('rep, "hey",)} -> 'c) -> 'c) +//│ helper: ArraysImpl['a, 'rep] -> (forall 'c. ({ +//│ fold: forall 'b 'b0. ('a -> 'b -> ('b & 'b0)) -> (forall 'd. ('b & 'd) -> (('rep, anything,),) -> ('b0 | 'd)), +//│ init: 'a -> ('rep, "hi",), +//│ sub: (('rep, anything,),) -> int -> 'a, +//│ update: (('rep, anything,),) -> int -> 'a -> ('rep, "hey",) +//│ } -> 'c) -> 'c) //│ = [Function: helper5] :e def step (arr: Arrays['a]) = arr helper -//│ Arrays['a] -> (forall 'c. error | ({fold: forall 'b 'b0. (('a0 | 'a) -> 'b -> ('b & 'b0)) -> (forall 'd. ('b & 'd) -> (('rep & 'rep0, anything,),) -> ('b0 | 'd)), init: 'a -> ('rep, "hi",), sub: (('rep & 'rep0, anything,),) -> int -> ('a0 | 'a), update: (('rep & 'rep0, anything,),) -> int -> 'a -> ('rep, "hey",)} -> 'c) -> 'c) -//│ where -//│ 'rep :> ??rep -//│ <: 'rep0 -//│ 'rep0 <: ??rep0 & 'rep -//│ 'a <: 'a0 -//│ 'a0 := 'a +//│ Arrays['a] -> (forall 'c. error | ({ +//│ fold: forall 'b 'b0. (('a0 | 'a) -> 'b -> ('b & 'b0)) -> (forall 'd. ('b & 'd) -> (('rep & 'rep0, anything,),) -> ('b0 | 'd)), +//│ init: 'a -> ('rep, "hi",), +//│ sub: (('rep & 'rep0, anything,),) -> int -> ('a0 | 'a), +//│ update: (('rep & 'rep0, anything,),) -> int -> 'a -> ('rep, "hey",) +//│ } -> 'c) -> 'c) +//│ where +//│ 'rep :> ??rep +//│ <: 'rep0 +//│ 'rep0 <: ??rep0 & 'rep +//│ 'a <: 'a0 +//│ 'a0 := 'a //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in application -//│ ║ l.205: def step (arr: Arrays['a]) = arr helper +//│ ║ l.235: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.19: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this function: -//│ ║ l.200: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) +//│ ║ l.225: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.205: def step (arr: Arrays['a]) = arr helper +//│ ║ l.235: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^ //│ ╟── • this reference: -//│ ║ l.205: def step (arr: Arrays['a]) = arr helper +//│ ║ l.235: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.83: def stepImpl (arrImpl: ArraysImpl['a, 'r]) = { +//│ ║ l.93: def stepImpl (arrImpl: ArraysImpl['a, 'r]) = { //│ ╙── ^^ //│ ╔══[ERROR] Type error in def definition -//│ ║ l.205: def step (arr: Arrays['a]) = arr helper +//│ ║ l.235: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.19: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this function: -//│ ║ l.200: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) +//│ ║ l.225: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.205: def step (arr: Arrays['a]) = arr helper +//│ ║ l.235: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^ //│ ╟── • this reference: -//│ ║ l.205: def step (arr: Arrays['a]) = arr helper +//│ ║ l.235: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.85: sub = fun ((r0, r1)) -> fun i -> arrImpl.sub r0 i; +//│ ║ l.95: sub = fun ((r0, r1)) -> fun i -> arrImpl.sub r0 i; //│ ╙── ^^ //│ = [Function: step5] @@ -496,20 +531,20 @@ def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (ste //│ <: step2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.494: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.529: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.19: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.494: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.529: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^ //│ ╟── • this reference: -//│ ║ l.494: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.529: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.78: def stepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] +//│ ║ l.88: def stepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ ╙── ^^ //│ = [Function: step25] @@ -521,7 +556,7 @@ def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr ( //│ <: step2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.517: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.552: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'r` leaks out of its scope //│ ║ l.22: type Arrays[A] = forall 'r. ArraysImplConsumer[A, 'r] -> 'r @@ -531,7 +566,7 @@ def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr ( //│ ║ ^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this application: -//│ ║ l.517: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.552: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ = [Function: step26] @@ -565,7 +600,7 @@ step2 = s //│ <: step2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.563: step2 = s +//│ ║ l.598: step2 = s //│ ║ ^^^^^^^^^ //│ ╟── type variable `'r` leaks out of its scope //│ ║ l.22: type Arrays[A] = forall 'r. ArraysImplConsumer[A, 'r] -> 'r @@ -575,10 +610,10 @@ step2 = s //│ ║ ^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.563: step2 = s +//│ ║ l.598: step2 = s //│ ║ ^ //│ ╟── • this application: -//│ ║ l.540: def s arr (k: ArraysImplConsumer['a, 'rep]) = arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.575: def s arr (k: ArraysImplConsumer['a, 'rep]) = arr (fun impl -> k (stepImpl_ty impl)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ = [Function: s] diff --git a/shared/src/test/diff/fcp/QML_exist_Records_min_1.mls b/shared/src/test/diff/fcp/QML_exist_Records_min_1.mls index bba79c34ed..b39b761b03 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records_min_1.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records_min_1.mls @@ -142,9 +142,11 @@ def step: Arrays2 -> Arrays2 def step arr k = k (arr stepImpl) //│ 'a -> (('b -> 'c) -> 'c //│ where -//│ 'a <: (forall 'd. 'd -> {fold: forall 'e 'f 'g. 'e -> ('f -> 'g -//│ where -//│ 'd <: {fold: 'e -> 'f -> 'g})}) -> 'b) +//│ 'a <: (forall 'd. 'd -> { +//│ fold: forall 'e 'f 'g. 'e -> ('f -> 'g +//│ where +//│ 'd <: {fold: 'e -> 'f -> 'g}) +//│ }) -> 'b) //│ <: step: //│ Arrays2 -> Arrays2 //│ ╔══[ERROR] Type error in def definition diff --git a/shared/src/test/diff/mlscript/David2.mls b/shared/src/test/diff/mlscript/David2.mls index 2112cc5cd6..58944c9abe 100644 --- a/shared/src/test/diff/mlscript/David2.mls +++ b/shared/src/test/diff/mlscript/David2.mls @@ -148,7 +148,10 @@ rec def mkInteger_oops value = Integer { value; addOne = fun n -> mkInteger_oops // * We may still want to retain the precise typing of the `value` part: def mkIntegerPrecise value = Integer { value; addOne = addOne1 } -//│ mkIntegerPrecise: (int & 'value) -> (Integer with {addOne: forall 'a 'b. ((Integer\value with {addOne: 'a -> 'b}) & 'a) -> 'b, value: 'value}) +//│ mkIntegerPrecise: (int & 'value) -> (Integer with { +//│ addOne: forall 'a 'b. ((Integer\value with {addOne: 'a -> 'b}) & 'a) -> 'b, +//│ value: 'value +//│ }) //│ = [Function: mkIntegerPrecise] def mkIntegerPrecise value = Integer { value; addOne = fun n -> mkInteger (n.value + 1) } @@ -203,13 +206,13 @@ def mkIntegerPrecise3 = mkInteger //│ <: mkIntegerPrecise3: //│ (int & 'a) -> (Integer\addOne with {value: 'a}) //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.199: def mkIntegerPrecise3 = mkInteger +//│ ║ l.202: def mkIntegerPrecise3 = mkInteger //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `int` does not match type `'a` //│ ║ l.72: rec def mkInteger value = Integer { value; addOne = fun n -> mkInteger (n.value + 1) } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.193: def mkIntegerPrecise3: (int & 'a) -> (Integer & { value: 'a }) +//│ ║ l.196: def mkIntegerPrecise3: (int & 'a) -> (Integer & { value: 'a }) //│ ╙── ^^ //│ = [Function: mkIntegerPrecise3] @@ -217,10 +220,10 @@ def mkIntegerPrecise3 = mkInteger :e addOne1 (Stri { value = ""; addOne = error }) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.218: addOne1 (Stri { value = ""; addOne = error }) +//│ ║ l.221: addOne1 (Stri { value = ""; addOne = error }) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Stri & {addOne: ?addOne, value: ?value}` does not match type `Integer & ?a` -//│ ║ l.218: addOne1 (Stri { value = ""; addOne = error }) +//│ ║ l.221: addOne1 (Stri { value = ""; addOne = error }) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.11: addOne1 x = case x of { diff --git a/shared/src/test/diff/mlscript/ExprProb.mls b/shared/src/test/diff/mlscript/ExprProb.mls index 760192b619..29a7f4ab23 100644 --- a/shared/src/test/diff/mlscript/ExprProb.mls +++ b/shared/src/test/diff/mlscript/ExprProb.mls @@ -314,7 +314,10 @@ pretty1 done e1 prettier1 done (eval1 done) e1 prettier11 done (eval1 done) e1 prettier12 done (eval1 done) e1 -//│ e1: Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with {lhs: Lit & {val: 1}, rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}} +//│ e1: Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} +//│ } //│ = Add { //│ lhs: Lit { val: 1 }, //│ rhs: Add { lhs: Lit { val: 2 }, rhs: Lit { val: 3 } } @@ -340,7 +343,10 @@ pretty1 done e1 prettier1 done (eval1 done) e1 prettier11 done (eval1 done) e1 prettier12 done (eval1 done) e1 -//│ e1: Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with {lhs: Lit & {val: 1}, rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}} +//│ e1: Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} +//│ } //│ = Add { //│ lhs: Lit { val: 1 }, //│ rhs: Add { lhs: Lit { val: 2 }, rhs: Lit { val: 3 } } @@ -420,7 +426,16 @@ eval2 done e1 //│ subtyping calls : 1263 e2 = add (lit 1) (nega e1) -//│ e2: Add[Lit & {val: 1} | Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with {lhs: Lit & {val: 1}, rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}]] with {lhs: Lit & {val: 1}, rhs: Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with {lhs: Lit & {val: 1}, rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}]} +//│ e2: Add[Lit & {val: 1} | Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} +//│ }]] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} +//│ }] +//│ } //│ = Add { //│ lhs: Lit { val: 1 }, //│ rhs: Nega { arg: Add { lhs: [Lit], rhs: [Add] } } @@ -548,7 +563,7 @@ eval1 done e2 //│ ║ l.+1: eval1 done e2 //│ ║ ^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` does not match type `nothing` -//│ ║ l.362: def nega arg = Nega { arg } +//│ ║ l.368: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.4: def done x = case x of {} @@ -603,7 +618,7 @@ prettier2 done (eval1 done) e2 //│ ║ l.+1: prettier2 done (eval1 done) e2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` does not match type `nothing` -//│ ║ l.362: def nega arg = Nega { arg } +//│ ║ l.368: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.4: def done x = case x of {} @@ -675,7 +690,7 @@ prettier2 done eval2 e1 //│ ║ l.18: def lit val = Lit { val } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.371: | _ -> k x +//│ ║ l.377: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.262: else if ev e.rhs == 0 then prettier1 k ev e.lhs @@ -713,7 +728,7 @@ prettier2 done eval2 e2 //│ ║ l.18: def lit val = Lit { val } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.371: | _ -> k x +//│ ║ l.377: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.262: else if ev e.rhs == 0 then prettier1 k ev e.lhs @@ -748,10 +763,10 @@ prettier2 done eval2 d2 //│ ║ l.+1: prettier2 done eval2 d2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` is not a function -//│ ║ l.362: def nega arg = Nega { arg } +//│ ║ l.368: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.371: | _ -> k x +//│ ║ l.377: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.262: else if ev e.rhs == 0 then prettier1 k ev e.lhs diff --git a/shared/src/test/diff/mlscript/ExprProb2.mls b/shared/src/test/diff/mlscript/ExprProb2.mls index a797d6d2fa..4638c57f69 100644 --- a/shared/src/test/diff/mlscript/ExprProb2.mls +++ b/shared/src/test/diff/mlscript/ExprProb2.mls @@ -49,7 +49,10 @@ def eval1f eval1 e = case e of { e1 = add (lit 1) (add (lit 2) (lit 3)) -//│ e1: Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with {lhs: Lit & {val: 1}, rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}} +//│ e1: Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} +//│ } //│ = Add { //│ lhs: Lit { val: 1 }, //│ rhs: Add { lhs: Lit { val: 2 }, rhs: Lit { val: 3 } } @@ -74,7 +77,10 @@ eval1_fixed_1 e1 rec def eval1_fixed_2 = eval1f (fun x -> eval1f eval1_fixed_2 x) //│ eval1_fixed_2: (Add[?] & 'a | (Lit with {val: 'val})) -> (int | 'val) //│ where -//│ 'a <: {lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit} +//│ 'a <: { +//│ lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, +//│ rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit +//│ } //│ 'rhs <: Add[?] & 'a | Lit //│ = [Function: eval1_fixed_2] @@ -87,9 +93,15 @@ eval1_fixed_2 e1 def eval1_fixed_3 = let fixed fixed = eval1f (fun x -> eval1f (fixed fixed) x) in fixed fixed! -//│ eval1_fixed_3: (Add[?] & {lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit} | (Lit with {val: 'val})) -> (int | 'val) -//│ where -//│ 'rhs <: Add[?] & {lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit} | Lit +//│ eval1_fixed_3: (Add[?] & { +//│ lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, +//│ rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit +//│ } | (Lit with {val: 'val})) -> (int | 'val) +//│ where +//│ 'rhs <: Add[?] & { +//│ lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, +//│ rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit +//│ } | Lit //│ = [Function: eval1_fixed_3] eval1_fixed_3 e1 @@ -124,7 +136,16 @@ def eval2f eval2 e = case e of { e2 = add (lit 1) (nega e1) -//│ e2: Add[Lit & {val: 1} | Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with {lhs: Lit & {val: 1}, rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}]] with {lhs: Lit & {val: 1}, rhs: Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with {lhs: Lit & {val: 1}, rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}]} +//│ e2: Add[Lit & {val: 1} | Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} +//│ }]] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Nega[Add[Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} | Lit & {val: 1}] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Add[Lit & {val: 2 | 3}] & {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}} +//│ }] +//│ } //│ = Add { //│ lhs: Lit { val: 1 }, //│ rhs: Nega { arg: Add { lhs: [Lit], rhs: [Add] } } @@ -240,7 +261,10 @@ def eval1_fixed = eval1f (fun x -> eval1f eval1f x) //│ ╟── Note: constraint arises from application: //│ ║ l.32: | Add -> eval1 e.lhs + eval1 e.rhs //│ ╙── ^^^^^^^^^^^ -//│ eval1_fixed: (Add[?] & {lhs: Add[?] & {lhs: nothing -> int, rhs: nothing -> int} | Lit, rhs: Add[?] & {lhs: nothing -> int, rhs: nothing -> int} | Lit} | (Lit with {val: 'val})) -> (int | 'val) +//│ eval1_fixed: (Add[?] & { +//│ lhs: Add[?] & {lhs: nothing -> int, rhs: nothing -> int} | Lit, +//│ rhs: Add[?] & {lhs: nothing -> int, rhs: nothing -> int} | Lit +//│ } | (Lit with {val: 'val})) -> (int | 'val) rec def eval1_fixed = eval1f (fun x -> eval1_fixed eval1_fixed x) //│ ╔══[ERROR] Type mismatch in binding of application: @@ -328,7 +352,7 @@ eval2_broken eval2_broken! e2 //│ ║ l.20: | Add -> eval1 eval1 e.lhs + eval1 eval1 e.rhs //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── from field selection: -//│ ║ l.314: | Nega -> e.arg +//│ ║ l.338: | Nega -> e.arg //│ ╙── ^^^^^ //│ res: error | int @@ -345,13 +369,13 @@ fix eval2f_oops e2 //│ ║ l.+1: fix eval2f_oops e2 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` does not match type `Add[?] & ?c | Lit & ?d` -//│ ║ l.147: def fix f = let fixed = fun x -> f (fun v -> (x x) v) in fixed fixed! +//│ ║ l.168: def fix f = let fixed = fun x -> f (fun v -> (x x) v) in fixed fixed! //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.18: def eval1 eval1 e = case e of { //│ ║ ^ //│ ╟── from reference: -//│ ║ l.336: def eval2f_oops eval2 e = case e of { +//│ ║ l.360: def eval2f_oops eval2 e = case e of { //│ ╙── ^ //│ res: error diff --git a/shared/src/test/diff/mlscript/ExprProb_Inv.mls b/shared/src/test/diff/mlscript/ExprProb_Inv.mls index 213727c532..b2b77fce0c 100644 --- a/shared/src/test/diff/mlscript/ExprProb_Inv.mls +++ b/shared/src/test/diff/mlscript/ExprProb_Inv.mls @@ -428,11 +428,14 @@ eval2 done e1 //│ subtyping calls : 1263 e2 = add (lit 1) (nega e1) -//│ e2: Add['E] with {lhs: Lit & {val: 1}, rhs: Nega[forall 'E0 'E1. Add['E0] with {lhs: Lit & {val: 1}, rhs: Add['E1] with {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}]} -//│ where -//│ 'E :> Lit & {val: 1} | Nega[forall 'E0 'E1. Add['E0] with {lhs: Lit & {val: 1}, rhs: Add['E1] with {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}] -//│ 'E0 :> (Add['E1] with {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}) | Lit & {val: 1} -//│ 'E1 :> Lit & {val: 2 | 3} +//│ e2: Add['E] with { +//│ lhs: Lit & {val: 1}, +//│ rhs: Nega[forall 'E0 'E1. Add['E0] with {lhs: Lit & {val: 1}, rhs: Add['E1] with {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}] +//│ } +//│ where +//│ 'E :> Lit & {val: 1} | Nega[forall 'E0 'E1. Add['E0] with {lhs: Lit & {val: 1}, rhs: Add['E1] with {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}}] +//│ 'E0 :> (Add['E1] with {lhs: Lit & {val: 2}, rhs: Lit & {val: 3}}) | Lit & {val: 1} +//│ 'E1 :> Lit & {val: 2 | 3} //│ = Add { //│ lhs: Lit { val: 1 }, //│ rhs: Nega { arg: Add { lhs: [Lit], rhs: [Add] } } diff --git a/shared/src/test/diff/mlscript/HeadOption.mls b/shared/src/test/diff/mlscript/HeadOption.mls index 1fb3ead7cf..16fed63996 100644 --- a/shared/src/test/diff/mlscript/HeadOption.mls +++ b/shared/src/test/diff/mlscript/HeadOption.mls @@ -99,7 +99,9 @@ Cons.HeadOption l2 :stats l3 = Cons { head = 0-1; tail = l2 } -//│ l3: Cons[int] with {tail: Cons[0] with {tail: Cons[1] with {tail: Cons[2] with {tail: Cons[3] with {tail: Nil[?]}}}}} +//│ l3: Cons[int] with { +//│ tail: Cons[0] with {tail: Cons[1] with {tail: Cons[2] with {tail: Cons[3] with {tail: Nil[?]}}}} +//│ } //│ constrain calls : 34 //│ annoying calls : 1 //│ subtyping calls : 253 @@ -148,23 +150,25 @@ Cons.HeadOption lr2 :e l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.149: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } +//│ ║ l.151: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── record literal of type `{tail: ?a}` does not have field 'head' -//│ ║ l.149: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } +//│ ║ l.151: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } //│ ╙── ^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.149: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } +//│ ║ l.151: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── record literal of type `{tail: ?a}` does not have field 'head' -//│ ║ l.149: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } +//│ ║ l.151: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.149: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } +//│ ║ l.151: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── record literal of type `{tail: ?a}` does not have field 'head' -//│ ║ l.149: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } +//│ ║ l.151: l1 = Cons { tail = Cons { tail = Cons { tail = Nil {} } } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ l1: (Cons[nothing] with {tail: (Cons[nothing] with {tail: (Cons[nothing] with {tail: Nil[?]}) | error}) | error}) | error +//│ l1: (Cons[nothing] with { +//│ tail: (Cons[nothing] with {tail: (Cons[nothing] with {tail: Nil[?]}) | error}) | error +//│ }) | error diff --git a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls index 4ea032d6c7..d93cc227ee 100644 --- a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls +++ b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls @@ -416,9 +416,18 @@ rec def eval4 subst = eval_lexpr' eval4 subst //│ 'tail4 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result0}, tail: 'tail4} | Nil //│ 'tail3 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result0}, tail: 'tail3} | Nil //│ 'tail2 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: 'tail2} | Nil -//│ 'tail1 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, tail: 'tail1} | Nil -//│ 'tail0 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, tail: 'tail0} | Nil -//│ 'tail <: Cons[?]\head\tail & {head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, tail: 'tail} | Nil +//│ 'tail1 <: Cons[?]\head\tail & { +//│ head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, +//│ tail: 'tail1 +//│ } | Nil +//│ 'tail0 <: Cons[?]\head\tail & { +//│ head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, +//│ tail: 'tail0 +//│ } | Nil +//│ 'tail <: Cons[?]\head\tail & { +//│ head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, +//│ tail: 'tail +//│ } | Nil //│ 'result :> Mul['result] | Add['result] | Abs['result] | App['lhs] & {lhs: 'lhs, rhs: nothing} | 'result0 | 'c | 'd | 'e //│ 'result0 :> Var | Numb //│ <: 'a & (Numb | ~#Numb) diff --git a/shared/src/test/diff/mlscript/Yicong.mls b/shared/src/test/diff/mlscript/Yicong.mls index 29ffa70c49..a1b4e2a760 100644 --- a/shared/src/test/diff/mlscript/Yicong.mls +++ b/shared/src/test/diff/mlscript/Yicong.mls @@ -151,7 +151,9 @@ gwx.x with {y = gwx} //│ = [ 6, 6, 6 ] //│ gwx: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {_1: 1 | 6 | true, _2: 2 | 4 | 6, _3: 3 | 6 | false, x: 123} //│ = [ 6, 6, 6, x: 123 ] -//│ res: 123 & {y: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {_1: 1 | 6 | true, _2: 2 | 4 | 6, _3: 3 | 6 | false, x: 123}} +//│ res: 123 & { +//│ y: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {_1: 1 | 6 | true, _2: 2 | 4 | 6, _3: 3 | 6 | false, x: 123} +//│ } //│ = [Number: 123] { y: [ 6, 6, 6, x: 123 ] } def f: (int, bool) -> int @@ -183,10 +185,10 @@ def h f = (f (1,2,false), f (1,true)) :e h (fun x -> x[0]) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.184: h (fun x -> x[0]) +//│ ║ l.186: h (fun x -> x[0]) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── argument list of type `(1, true,)` does not match type `(?a,)` -//│ ║ l.179: def h f = (f (1,2,false), f (1,true)) +//│ ║ l.181: def h f = (f (1,2,false), f (1,true)) //│ ╙── ^^^^^^^^ //│ res: error | (undefined, undefined,) //│ = [ undefined, undefined ] @@ -194,13 +196,13 @@ h (fun x -> x[0]) :e h (fun (x, y) -> x) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.195: h (fun (x, y) -> x) +//│ ║ l.197: h (fun (x, y) -> x) //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── argument list of type `(1, 2, false,)` does not match type `(?a, ?b,)` -//│ ║ l.179: def h f = (f (1,2,false), f (1,true)) +//│ ║ l.181: def h f = (f (1,2,false), f (1,true)) //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.195: h (fun (x, y) -> x) +//│ ║ l.197: h (fun (x, y) -> x) //│ ╙── ^^^^^^ //│ res: error | (nothing, 1,) //│ = [ 1, 1 ] @@ -231,30 +233,30 @@ fx ((a,b,c)) = a + b + c fx q1 fx q2 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.231: fx q1 +//│ ║ l.233: fx q1 //│ ║ ^^^^^ //│ ╟── tuple literal of type `(1, 1, 1, 1,)` does not match type `(?a, ?b, ?c,)` -//│ ║ l.220: q1 = (1,1,1,1) +//│ ║ l.222: q1 = (1,1,1,1) //│ ║ ^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(?d, ?e, ?f,)` -//│ ║ l.231: fx q1 +//│ ║ l.233: fx q1 //│ ║ ^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.222: fx ((a,b,c)) = a + b + c +//│ ║ l.224: fx ((a,b,c)) = a + b + c //│ ╙── ^^^^^^^ //│ res: error | int //│ = 3 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.232: fx q2 +//│ ║ l.234: fx q2 //│ ║ ^^^^^ //│ ╟── tuple literal of type `(1, 1,)` does not match type `(?a, ?b, ?c,)` -//│ ║ l.221: q2 = (1,1) +//│ ║ l.223: q2 = (1,1) //│ ║ ^^^^^ //│ ╟── but it flows into reference with expected type `(?d, ?e, ?f,)` -//│ ║ l.232: fx q2 +//│ ║ l.234: fx q2 //│ ║ ^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.222: fx ((a,b,c)) = a + b + c +//│ ║ l.224: fx ((a,b,c)) = a + b + c //│ ╙── ^^^^^^^ //│ res: error | int //│ = NaN @@ -284,13 +286,13 @@ sum t2 //│ t2: (1, 1, 2, true,) //│ = [ 1, 1, 2, true ] //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.283: sum t2 +//│ ║ l.285: sum t2 //│ ║ ^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.282: t2 = (1,1,2,true) +//│ ║ l.284: t2 = (1,1,2,true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.270: def sum: Array[int] -> int +//│ ║ l.272: def sum: Array[int] -> int //│ ╙── ^^^ //│ res: error | int //│ = @@ -337,23 +339,23 @@ a1._2 //│ <: a1: //│ Array[int] //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.332: a1 = (1,2,true,'hello') +//│ ║ l.334: a1 = (1,2,true,'hello') //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.332: a1 = (1,2,true,'hello') +//│ ║ l.334: a1 = (1,2,true,'hello') //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.331: def a1: Array[int] +//│ ║ l.333: def a1: Array[int] //│ ╙── ^^^ //│ = [ 1, 2, true, 'hello' ] //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.333: a1._2 +//│ ║ l.335: a1._2 //│ ║ ^^^^^ //│ ╟── type `Array[int]` does not have field '_2' -//│ ║ l.331: def a1: Array[int] +//│ ║ l.333: def a1: Array[int] //│ ║ ^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{_2: ?a}` -//│ ║ l.333: a1._2 +//│ ║ l.335: a1._2 //│ ╙── ^^ //│ res: error //│ = undefined @@ -400,13 +402,13 @@ append2 ((mut 1, mut 2, mut false)) ((mut (), mut 'hi')) :e append2 ((mut 1, mut 2, mut false)) ((mut (), 'hi')) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.401: append2 ((mut 1, mut 2, mut false)) ((mut (), 'hi')) +//│ ║ l.403: append2 ((mut 1, mut 2, mut false)) ((mut (), 'hi')) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `(mut ?a, "hi",)` does not match type `MutArray['bb]` -//│ ║ l.401: append2 ((mut 1, mut 2, mut false)) ((mut (), 'hi')) +//│ ║ l.403: append2 ((mut 1, mut 2, mut false)) ((mut (), 'hi')) //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.384: def append2: MutArray['aa] -> MutArray['bb] -> MutArray['aa | 'bb] +//│ ║ l.386: def append2: MutArray['aa] -> MutArray['bb] -> MutArray['aa | 'bb] //│ ╙── ^^^^^^^^^^^^^ //│ res: error | MutArray['aa | 'bb] //│ where @@ -513,31 +515,31 @@ iarr = intersect ((1,2,3,false)) ((1,5,true,'hi',false)) fst iarr snd (T1 ((1,2,3))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.513: fst iarr +//│ ║ l.515: fst iarr //│ ║ ^^^^^^^^ //│ ╟── type `Array['a & 'b]` is not a 2-element tuple -//│ ║ l.504: def intersect: Array['a] -> Array['b] -> Array['a & 'b] +//│ ║ l.506: def intersect: Array['a] -> Array['b] -> Array['a & 'b] //│ ║ ^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(?a, ?b,)` -//│ ║ l.513: fst iarr +//│ ║ l.515: fst iarr //│ ║ ^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.483: def fst ((a, b)) = a +//│ ║ l.485: def fst ((a, b)) = a //│ ╙── ^^^^^^ //│ res: error //│ = //│ iarr and intersect are not implemented //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.514: snd (T1 ((1,2,3))) +//│ ║ l.516: snd (T1 ((1,2,3))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `(1, 2, 3,)` does not match type `(?a, ?b,) | ~#T1` -//│ ║ l.514: snd (T1 ((1,2,3))) +//│ ║ l.516: snd (T1 ((1,2,3))) //│ ║ ^^^^^^^ //│ ╟── but it flows into application with expected type `(?a, ?b,) | ~#T1` -//│ ║ l.514: snd (T1 ((1,2,3))) +//│ ║ l.516: snd (T1 ((1,2,3))) //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.484: def snd ((a, b)) = b +//│ ║ l.486: def snd ((a, b)) = b //│ ╙── ^^^^^^ //│ res: error //│ = 2 @@ -587,28 +589,28 @@ inn2 (T2 r1) inn (T1 v3) inn2 v1 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.587: inn (T1 v3) +//│ ║ l.589: inn (T1 v3) //│ ║ ^^^^^^^^^^^ //│ ╟── type `Array[Array[(int, true,)]]` does not match type `#T2 | ~#T1` -//│ ║ l.551: def v3: Array[Array[(int, true)]] +//│ ║ l.553: def v3: Array[Array[(int, true)]] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `#T2 | ~#T1` -//│ ║ l.587: inn (T1 v3) +//│ ║ l.589: inn (T1 v3) //│ ║ ^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.547: def inn: (T1 & T2 & Array['a]) -> 'a +//│ ║ l.549: def inn: (T1 & T2 & Array['a]) -> 'a //│ ║ ^^ //│ ╟── from intersection type: -//│ ║ l.547: def inn: (T1 & T2 & Array['a]) -> 'a +//│ ║ l.549: def inn: (T1 & T2 & Array['a]) -> 'a //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ res: error | Array[(int, true,)] //│ = //│ inn is not implemented //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.588: inn2 v1 +//│ ║ l.590: inn2 v1 //│ ║ ^^^^^^^ //│ ╟── integer literal of type `1` does not match type `Array['a]` -//│ ║ l.545: v1 = T1 (T2 ((1,2,true))) +//│ ║ l.547: v1 = T1 (T2 ((1,2,true))) //│ ╙── ^ //│ res: error | Array[nothing] //│ = @@ -642,16 +644,16 @@ ra: (Array['a], Array['a]) as 'a ra: ('a, 'a, 'a) as 'a ra: (Array['a], Array['a], Array['a]) as 'a //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.642: ra: ('a, 'a, 'a) as 'a +//│ ║ l.644: ra: ('a, 'a, 'a) as 'a //│ ║ ^^ //│ ╟── type `('a, 'a,)` does not match type `('a0, 'a0, 'a0,)` -//│ ║ l.617: def ra: ('a, 'a) as 'a +//│ ║ l.619: def ra: ('a, 'a) as 'a //│ ║ ^^^^^^^^ //│ ╟── but it flows into reference with expected type `('a1, 'a1, 'a1,)` -//│ ║ l.642: ra: ('a, 'a, 'a) as 'a +//│ ║ l.644: ra: ('a, 'a, 'a) as 'a //│ ║ ^^ //│ ╟── Note: constraint arises from tuple type: -//│ ║ l.642: ra: ('a, 'a, 'a) as 'a +//│ ║ l.644: ra: ('a, 'a, 'a) as 'a //│ ╙── ^^^^^^^^^^^^ //│ res: 'a //│ where @@ -659,16 +661,16 @@ ra: (Array['a], Array['a], Array['a]) as 'a //│ = //│ ra is not implemented //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.643: ra: (Array['a], Array['a], Array['a]) as 'a +//│ ║ l.645: ra: (Array['a], Array['a], Array['a]) as 'a //│ ║ ^^ //│ ╟── type `('a, 'a,)` does not match type `(Array['a0], Array['a0], Array['a0],)` -//│ ║ l.617: def ra: ('a, 'a) as 'a +//│ ║ l.619: def ra: ('a, 'a) as 'a //│ ║ ^^^^^^^^ //│ ╟── but it flows into reference with expected type `(Array['a1], Array['a1], Array['a1],)` -//│ ║ l.643: ra: (Array['a], Array['a], Array['a]) as 'a +//│ ║ l.645: ra: (Array['a], Array['a], Array['a]) as 'a //│ ║ ^^ //│ ╟── Note: constraint arises from tuple type: -//│ ║ l.643: ra: (Array['a], Array['a], Array['a]) as 'a +//│ ║ l.645: ra: (Array['a], Array['a], Array['a]) as 'a //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: 'a //│ where @@ -686,19 +688,19 @@ tktup ((1,2,3,true)) :e tktup a123 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.687: tktup a123 +//│ ║ l.689: tktup a123 //│ ║ ^^^^^^^^^^ //│ ╟── type `Array[int]` does not have field '_3' -//│ ║ l.362: def a123: Array[int] +//│ ║ l.364: def a123: Array[int] //│ ║ ^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{_3: ?a}` -//│ ║ l.687: tktup a123 +//│ ║ l.689: tktup a123 //│ ║ ^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.679: def tktup t = (t._2, t._3) +//│ ║ l.681: def tktup t = (t._2, t._3) //│ ║ ^^^^ //│ ╟── from reference: -//│ ║ l.679: def tktup t = (t._2, t._3) +//│ ║ l.681: def tktup t = (t._2, t._3) //│ ╙── ^ //│ res: error | (nothing, nothing,) //│ = [ undefined, undefined ] @@ -749,10 +751,10 @@ ta3[1-2] :e ((defined ta2[0])[1+4], ta[1])[0] //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.750: ((defined ta2[0])[1+4], ta[1])[0] +//│ ║ l.752: ((defined ta2[0])[1+4], ta[1])[0] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── possibly-undefined array access of type `undefined` does not match type `~undefined` -//│ ║ l.750: ((defined ta2[0])[1+4], ta[1])[0] +//│ ║ l.752: ((defined ta2[0])[1+4], ta[1])[0] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ res: error | false | int | true | undefined //│ = undefined @@ -766,53 +768,53 @@ ge[2] //│ ge: int -> int //│ = [Function: ge] //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.762: ta3[ge 3][ge (1+2)] +//│ ║ l.764: ta3[ge 3][ge (1+2)] //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"hello"` does not match type `Array[?a]` -//│ ║ l.731: ta3 = ((1,2,3), "hello", false) +//│ ║ l.733: ta3 = ((1,2,3), "hello", false) //│ ║ ^^^^^^^ //│ ╟── but it flows into array access with expected type `Array[?b]` -//│ ║ l.762: ta3[ge 3][ge (1+2)] +//│ ║ l.764: ta3[ge 3][ge (1+2)] //│ ╙── ^^^^^^^^^ //│ res: 1 | 2 | 3 | error | undefined //│ Runtime error: //│ TypeError: Cannot read properties of undefined (reading '4') //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.763: true[false] +//│ ║ l.765: true[false] //│ ║ ^^^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `int` -//│ ║ l.763: true[false] +//│ ║ l.765: true[false] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.763: true[false] +//│ ║ l.765: true[false] //│ ║ ^^^^^^^^^^^ //│ ╟── reference of type `true` does not match type `Array[?a]` -//│ ║ l.763: true[false] +//│ ║ l.765: true[false] //│ ╙── ^^^^ //│ res: error | undefined //│ = undefined //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.764: 4["hello"] +//│ ║ l.766: 4["hello"] //│ ║ ^^^^^^^^^^ //│ ╟── string literal of type `"hello"` is not an instance of type `int` -//│ ║ l.764: 4["hello"] +//│ ║ l.766: 4["hello"] //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.764: 4["hello"] +//│ ║ l.766: 4["hello"] //│ ║ ^^^^^^^^^^ //│ ╟── integer literal of type `4` does not match type `Array[?a]` -//│ ║ l.764: 4["hello"] +//│ ║ l.766: 4["hello"] //│ ╙── ^ //│ res: error | undefined //│ = undefined //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.765: ge[2] +//│ ║ l.767: ge[2] //│ ║ ^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` does not match type `Array[?c]` -//│ ║ l.761: def ge x = x + 1 +//│ ║ l.763: def ge x = x + 1 //│ ║ ^^^^^^^^^ //│ ╟── but it flows into reference with expected type `Array[?d]` -//│ ║ l.765: ge[2] +//│ ║ l.767: ge[2] //│ ╙── ^^ //│ res: error | undefined //│ = undefined @@ -839,21 +841,21 @@ mkarr (1,true,"hi")[0] mkarr 3 [ 1] mk1[2 ] //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.839: mkarr 3 [ 1] +//│ ║ l.841: mkarr 3 [ 1] //│ ║ ^^^^^^^ //│ ╟── integer literal of type `3` does not match type `Array[?a]` -//│ ║ l.839: mkarr 3 [ 1] +//│ ║ l.841: mkarr 3 [ 1] //│ ╙── ^ //│ res: Array[error | undefined] //│ = [ undefined, undefined, undefined, undefined, undefined ] //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.840: mk1[2 ] +//│ ║ l.842: mk1[2 ] //│ ║ ^^^^^^^^ //│ ╟── integer literal of type `6` does not match type `Array[?a]` -//│ ║ l.822: mk1 = defined (mkarr 6)[ 0] +//│ ║ l.824: mk1 = defined (mkarr 6)[ 0] //│ ║ ^ //│ ╟── but it flows into reference with expected type `Array[?b]` -//│ ║ l.840: mk1[2 ] +//│ ║ l.842: mk1[2 ] //│ ╙── ^^^ //│ res: error | undefined //│ = undefined @@ -903,13 +905,13 @@ dup (defined ara[1])._1 (defined (defined arb[10])[8])._2 + 1 :e (1,2,3)._1[1] //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.904: (1,2,3)._1[1] +//│ ║ l.906: (1,2,3)._1[1] //│ ║ ^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` does not match type `Array[?a]` -//│ ║ l.904: (1,2,3)._1[1] +//│ ║ l.906: (1,2,3)._1[1] //│ ║ ^ //│ ╟── but it flows into field selection with expected type `Array[?b]` -//│ ║ l.904: (1,2,3)._1[1] +//│ ║ l.906: (1,2,3)._1[1] //│ ╙── ^^^^^^^^^^ //│ res: error | undefined //│ Runtime error: diff --git a/shared/src/test/diff/mlscript/Yuheng.mls b/shared/src/test/diff/mlscript/Yuheng.mls index 37faccc865..d3d8d9f9b0 100644 --- a/shared/src/test/diff/mlscript/Yuheng.mls +++ b/shared/src/test/diff/mlscript/Yuheng.mls @@ -153,7 +153,10 @@ p = Pair { rhs = Pair { lhs = IntLit { value = 2 }; rhs = IntLit { value = 3 } } } -//│ p: Pair[?, ?] with {lhs: IntLit & {value: 1}, rhs: Pair[?, ?] with {lhs: IntLit & {value: 2}, rhs: IntLit & {value: 3}}} +//│ p: Pair[?, ?] with { +//│ lhs: IntLit & {value: 1}, +//│ rhs: Pair[?, ?] with {lhs: IntLit & {value: 2}, rhs: IntLit & {value: 3}} +//│ } //│ = Pair { //│ lhs: IntLit { value: 1 }, //│ rhs: Pair { lhs: IntLit { value: 2 }, rhs: IntLit { value: 3 } } @@ -191,13 +194,13 @@ ep = eval p class Pair2[A, B]: Expr[(A, B)] & { lhs: Expr[A]; rhs: Expr[A] } //│ Defined class Pair2[±A, ±B] //│ ╔══[WARNING] Type definition Pair2 has bivariant type parameters: -//│ ║ l.191: class Pair2[A, B]: Expr[(A, B)] & { lhs: Expr[A]; rhs: Expr[A] } +//│ ║ l.194: class Pair2[A, B]: Expr[(A, B)] & { lhs: Expr[A]; rhs: Expr[A] } //│ ║ ^^^^^ //│ ╟── A is irrelevant and may be removed -//│ ║ l.191: class Pair2[A, B]: Expr[(A, B)] & { lhs: Expr[A]; rhs: Expr[A] } +//│ ║ l.194: class Pair2[A, B]: Expr[(A, B)] & { lhs: Expr[A]; rhs: Expr[A] } //│ ║ ^ //│ ╟── B is irrelevant and may be removed -//│ ║ l.191: class Pair2[A, B]: Expr[(A, B)] & { lhs: Expr[A]; rhs: Expr[A] } +//│ ║ l.194: class Pair2[A, B]: Expr[(A, B)] & { lhs: Expr[A]; rhs: Expr[A] } //│ ╙── ^ @@ -266,7 +269,10 @@ p = Pair2 { rhs = Pair2 { lhs = IntLit { value = 2 }; rhs = IntLit { value = 3 } } } -//│ p: Pair2[?, ?] with {lhs: IntLit & {value: 1}, rhs: Pair2[?, ?] with {lhs: IntLit & {value: 2}, rhs: IntLit & {value: 3}}} +//│ p: Pair2[?, ?] with { +//│ lhs: IntLit & {value: 1}, +//│ rhs: Pair2[?, ?] with {lhs: IntLit & {value: 2}, rhs: IntLit & {value: 3}} +//│ } @@ -293,7 +299,7 @@ rec def eval(e) = case e of //│ ║ l.+4: } //│ ║ ^^^ //│ ╟── type `Expr[?]` does not match type `IntLit & ?a | Pair[?, ?] & ?b` -//│ ║ l.273: def eval: Expr['a] -> 'a +//│ ║ l.279: def eval: Expr['a] -> 'a //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.+1: rec def eval(e) = case e of diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index e11d038816..0948a07bb8 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -171,10 +171,18 @@ fun main(ctx) = val sum = n + m ctx.printLine(concat("The sum is: ")(String of sum)) |>= _ => ctx.pure(sum) -//│ fun main: forall 'a 'b 'c 'd 'e. {printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'a) -> 'e} & Str -> {bind: (anything -> 'd) -> 'b}, pure: Int -> 'd, readInt: {bind: (Int -> 'c) -> 'a & (Int -> 'b) -> 'c}} -> 'e +//│ fun main: forall 'a 'b 'c 'd 'e. { +//│ printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'a) -> 'e} & Str -> {bind: (anything -> 'd) -> 'b}, +//│ pure: Int -> 'd, +//│ readInt: {bind: (Int -> 'c) -> 'a & (Int -> 'b) -> 'c} +//│ } -> 'e val defaultCtx = {printLine, readInt, pure: Pure} -//│ val defaultCtx: {printLine: (str: Str) -> printLine, pure: forall 'A. (value: 'A) -> Pure['A], readInt: readInt} +//│ val defaultCtx: { +//│ printLine: (str: Str) -> printLine, +//│ pure: forall 'A. (value: 'A) -> Pure['A], +//│ readInt: readInt +//│ } //│ defaultCtx //│ = { //│ printLine: [Function (anonymous)] { @@ -200,7 +208,11 @@ fun loop(ctx) = ctx.printLine("Input a positive number: ") |>= _ => ctx.readInt |>= n => if n < 0 then loop(ctx) else ctx.pure(n) -//│ fun loop: forall 'a 'b 'c 'd. {printLine: "Input a positive number: " -> {bind: (anything -> 'a) -> 'b}, pure: 'c -> 'd, readInt: {bind: ((Num & 'c) -> ('d | 'b)) -> 'a}} -> 'b +//│ fun loop: forall 'a 'b 'c 'd. { +//│ printLine: "Input a positive number: " -> {bind: (anything -> 'a) -> 'b}, +//│ pure: 'c -> 'd, +//│ readInt: {bind: ((Num & 'c) -> ('d | 'b)) -> 'a} +//│ } -> 'b // * FIXME why `nothing`? let r = loop(defaultCtx).run diff --git a/shared/src/test/diff/nu/MetaWrap.mls b/shared/src/test/diff/nu/MetaWrap.mls index cb1ba9ee0e..ac0c228866 100644 --- a/shared/src/test/diff/nu/MetaWrap.mls +++ b/shared/src/test/diff/nu/MetaWrap.mls @@ -24,7 +24,10 @@ mixin WithUid { }) } //│ mixin WithUid() { -//│ super: {rewrap: ('a, forall 'uid. {uid: 'uid, underlying: 'underlying} -> {uid: 'uid, underlying: 'b}) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {uid: Int, underlying: 'underlying0}) -> 'e, unwrap: 'f -> {underlying: 'underlying1} & 'g -> {uid: 'uid0}} +//│ super: { +//│ rewrap: ('a, forall 'uid. {uid: 'uid, underlying: 'underlying} -> {uid: 'uid, underlying: 'b}) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {uid: Int, underlying: 'underlying0}) -> 'e, +//│ unwrap: 'f -> {underlying: 'underlying1} & 'g -> {uid: 'uid0} +//│ } //│ fun getUid: 'g -> 'uid0 //│ fun rewrap: ('a, 'underlying -> 'b) -> 'c //│ fun setUid: ('d, uid: Int) -> 'e @@ -45,7 +48,10 @@ mixin WithType { }) } //│ mixin WithType() { -//│ super: {rewrap: ('a, forall 'ty. {ty: 'ty, underlying: 'underlying} -> {ty: 'ty, underlying: 'b}) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {ty: Type, underlying: 'underlying0}) -> 'e, unwrap: 'f -> {underlying: 'underlying1} & 'g -> {ty: 'ty0}} +//│ super: { +//│ rewrap: ('a, forall 'ty. {ty: 'ty, underlying: 'underlying} -> {ty: 'ty, underlying: 'b}) -> 'c & ('d, forall 'underlying0. {underlying: 'underlying0} -> {ty: Type, underlying: 'underlying0}) -> 'e, +//│ unwrap: 'f -> {underlying: 'underlying1} & 'g -> {ty: 'ty0} +//│ } //│ fun getType: 'g -> 'ty0 //│ fun rewrap: ('a, 'underlying -> 'b) -> 'c //│ fun setType: ('d, ty: Type) -> 'e @@ -64,8 +70,20 @@ module Test0 extends Base, WithUid module Test0 extends Base, WithUid, WithUid //│ module Test0 { //│ fun getUid: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0) -> {uid: Int | 'uid0, underlying: 'underlying2 | {uid: Int | 'uid1, underlying: 'underlying0}} -//│ fun setUid: ({uid: 'uid0, underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: Int) -> {uid: Int | 'uid0, underlying: 'underlying2 | {uid: Int | 'uid1, underlying: 'underlying0}} +//│ fun rewrap: ({ +//│ uid: 'uid0, +//│ underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2 +//│ }, 'underlying1 -> 'underlying0) -> { +//│ uid: Int | 'uid0, +//│ underlying: 'underlying2 | {uid: Int | 'uid1, underlying: 'underlying0} +//│ } +//│ fun setUid: ({ +//│ uid: 'uid0, +//│ underlying: {uid: 'uid1, underlying: 'underlying0 & 'underlying1} & 'underlying2 +//│ }, uid: Int) -> { +//│ uid: Int | 'uid0, +//│ underlying: 'underlying2 | {uid: Int | 'uid1, underlying: 'underlying0} +//│ } //│ fun unwrap: {uid: anything, underlying: {uid: 'uid, underlying: 'underlying}} -> 'underlying //│ } @@ -74,9 +92,27 @@ module Test1 extends Base, WithUid, WithType //│ module Test1 { //│ fun getType: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'ty //│ fun getUid: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'uid -//│ fun rewrap: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, 'underlying1 -> 'underlying0) -> {uid: Int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun setType: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, ty: Type) -> {uid: Int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} -//│ fun setUid: ({uid: 'uid0, underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2}, uid: Int) -> {uid: Int | 'uid0, underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0}} +//│ fun rewrap: ({ +//│ uid: 'uid0, +//│ underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2 +//│ }, 'underlying1 -> 'underlying0) -> { +//│ uid: Int | 'uid0, +//│ underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0} +//│ } +//│ fun setType: ({ +//│ uid: 'uid0, +//│ underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2 +//│ }, ty: Type) -> { +//│ uid: Int | 'uid0, +//│ underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0} +//│ } +//│ fun setUid: ({ +//│ uid: 'uid0, +//│ underlying: {ty: 'ty0, underlying: 'underlying0 & 'underlying1} & 'underlying2 +//│ }, uid: Int) -> { +//│ uid: Int | 'uid0, +//│ underlying: 'underlying2 | {ty: Type | 'ty0, underlying: 'underlying0} +//│ } //│ fun unwrap: {uid: 'uid, underlying: {ty: 'ty, underlying: 'underlying}} -> 'underlying //│ } diff --git a/shared/src/test/diff/nu/NestedRecords.mls b/shared/src/test/diff/nu/NestedRecords.mls new file mode 100644 index 0000000000..ebe7bbcbd6 --- /dev/null +++ b/shared/src/test/diff/nu/NestedRecords.mls @@ -0,0 +1,45 @@ +:NewDefs + + +let f(x) = [x, x] +//│ let f: forall 'a. 'a -> ['a, 'a] +//│ f +//│ = [Function: f] + +let a = { u: f(f(f(1))), v: f(f(f(1))) } +//│ let a: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]} +//│ a +//│ = { +//│ u: [ [ [Array], [Array] ], [ [Array], [Array] ] ], +//│ v: [ [ [Array], [Array] ], [ [Array], [Array] ] ] +//│ } + +{ a } +//│ { +//│ a: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]} +//│ } +//│ res +//│ = { a: { u: [ [Array], [Array] ], v: [ [Array], [Array] ] } } + +{ a, b: a } +//│ { +//│ a: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]}, +//│ b: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]} +//│ } +//│ res +//│ = { +//│ a: { u: [ [Array], [Array] ], v: [ [Array], [Array] ] }, +//│ b: { u: [ [Array], [Array] ], v: [ [Array], [Array] ] } +//│ } + +{ x: { a, b: a } } +//│ { +//│ x: { +//│ a: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]}, +//│ b: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]} +//│ } +//│ } +//│ res +//│ = { x: { a: { u: [Array], v: [Array] }, b: { u: [Array], v: [Array] } } } + + diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index f6c7601f6d..2bbd0f1dac 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -95,7 +95,9 @@ mixin EvalLambda { } //│ mixin EvalLambda() { //│ super: {eval: ('b, 'c) -> 'd} -//│ this: {eval: ('b, 'e) -> 'A & (List[[Str, 'A]], 'f) -> 'd & (List['a | [Str, Var]], 'g) -> 'A0} +//│ this: { +//│ eval: ('b, 'e) -> 'A & (List[[Str, 'A]], 'f) -> 'd & (List['a | [Str, Var]], 'g) -> 'A0 +//│ } //│ fun eval: (List['a] & 'b, Abs['g] | App['e & (Abs['f] | Object & ~#Abs)] | Object & 'c & ~#Abs & ~#App) -> (Abs['A0] | App['A] | 'd) //│ } diff --git a/shared/src/test/diff/tapl/SimplyTyped.mls b/shared/src/test/diff/tapl/SimplyTyped.mls index 18429f0a04..771fee6190 100644 --- a/shared/src/test/diff/tapl/SimplyTyped.mls +++ b/shared/src/test/diff/tapl/SimplyTyped.mls @@ -131,7 +131,12 @@ fun find(t, k) = //│ = [Function: empty] //│ insert: ('a, string & 'key, 'value,) -> 'right //│ where -//│ 'right :> Node & {key: 'key, left: Empty | 'left | 'right, right: Empty | 'right | 'right0, value: 'value} +//│ 'right :> Node & { +//│ key: 'key, +//│ left: Empty | 'left | 'right, +//│ right: Empty | 'right | 'right0, +//│ value: 'value +//│ } //│ 'a <: Empty | Node & {key: string & 'key, left: 'left, right: 'right0} //│ 'right0 <: 'a //│ 'left <: 'a @@ -222,82 +227,93 @@ fun typeTerm(t, ctx) = Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) Err(message) then Err(message) //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.207: fun typeTerm(t, ctx) = +//│ ║ l.212: fun typeTerm(t, ctx) = //│ ║ ^^^^^^^^^^ -//│ ║ l.208: if t is +//│ ║ l.213: if t is //│ ║ ^^^^^^^^^ -//│ ║ l.209: Lit(_, ty) then Ok(ty) +//│ ║ l.214: Lit(_, ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.210: Var(name) and find(ctx, name) is +//│ ║ l.215: Var(name) and find(ctx, name) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.211: Some(ty) then Ok(ty) +//│ ║ l.216: Some(ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.212: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ l.217: None then Err(concat3("unbound variable `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.213: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ l.218: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.214: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ l.219: Ok(resTy) then Ok(FunctionType(ty, resTy)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.215: Err(message) then Err(message) +//│ ║ l.220: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.216: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ l.221: App(lhs, rhs) and typeTerm(lhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.217: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ l.222: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.218: Ok(aTy) and +//│ ║ l.223: Ok(aTy) and //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.219: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ l.224: typeEqual(pTy, aTy) then Ok(resTy) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.220: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ l.225: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.221: Err(message) then Err(message) +//│ ║ l.226: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.222: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ l.227: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.223: Err(message) then Err(message) +//│ ║ l.228: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.207: fun typeTerm(t, ctx) = +//│ ║ l.212: fun typeTerm(t, ctx) = //│ ║ ^^^^^^^^^^ -//│ ║ l.208: if t is +//│ ║ l.213: if t is //│ ║ ^^^^^^^^^ -//│ ║ l.209: Lit(_, ty) then Ok(ty) +//│ ║ l.214: Lit(_, ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.210: Var(name) and find(ctx, name) is +//│ ║ l.215: Var(name) and find(ctx, name) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.211: Some(ty) then Ok(ty) +//│ ║ l.216: Some(ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.212: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ l.217: None then Err(concat3("unbound variable `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.213: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ l.218: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.214: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ l.219: Ok(resTy) then Ok(FunctionType(ty, resTy)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.215: Err(message) then Err(message) +//│ ║ l.220: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.216: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ l.221: App(lhs, rhs) and typeTerm(lhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.217: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ l.222: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.218: Ok(aTy) and +//│ ║ l.223: Ok(aTy) and //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.219: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ l.224: typeEqual(pTy, aTy) then Ok(resTy) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.220: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ l.225: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.221: Err(message) then Err(message) +//│ ║ l.226: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.222: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ l.227: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.223: Err(message) then Err(message) +//│ ║ l.228: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ typeTerm: ('rhs, 'right,) -> (Err & {message: 'message} | Ok & {value: 'ty}) //│ where //│ 'right <: 'right0 & (Empty | Node & {key: string, left: 'right, right: 'right}) -//│ 'right0 <: Empty | Node & {key: string, left: 'right0, right: 'right0, value: 'lhs & 'ty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType))} -//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'lhs & 'rhs0 & 'lhs0 & 'lty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)), rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'lhs & 'ty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType))} | Var & {name: string} +//│ 'right0 <: Empty | Node & { +//│ key: string, +//│ left: 'right0, +//│ right: 'right0, +//│ value: 'lhs & 'ty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) +//│ } +//│ 'rhs <: Abs & { +//│ lhs: Var & {name: string}, +//│ lty: 'lhs & 'rhs0 & 'lhs0 & 'lty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)), +//│ rhs: 'rhs +//│ } | App & {lhs: 'rhs, rhs: 'rhs} | Lit & { +//│ ty: 'lhs & 'ty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) +//│ } | Var & {name: string} //│ 'a <: {lhs: 'rhs0 & 'lhs0, rhs: 'rhs1} //│ 'rhs1 :> 'ty //│ <: 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) @@ -333,7 +349,11 @@ fun showTypeTerm(t, ctx) = //│ 'lhs2 <: FunctionType & {lhs: 'lhs2 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs2} | PrimitiveType & {name: string} //│ 'rhs0 <: Abs & {lhs: 'rhs0, lty: 'lty, rhs: 'rhs0} | App & {lhs: 'rhs0 & (Abs & {lhs: 'rhs0, lty: 'lty} | ~#Abs), rhs: 'rhs0} | Lit | Var //│ 'lty <: FunctionType & {lhs: 'lty & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lty} | PrimitiveType & {name: string} -//│ 'rhs <: Abs & {lhs: Var & {name: string}, lty: 'lhs4 & 'rhs7 & 'lhs5 & 'lhs & (PrimitiveType & {name: string} | 'd & (FunctionType & 'e | FunctionType & ~#FunctionType)), rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'rhs8} | Var & {name: string} +//│ 'rhs <: Abs & { +//│ lhs: Var & {name: string}, +//│ lty: 'lhs4 & 'rhs7 & 'lhs5 & 'lhs & (PrimitiveType & {name: string} | 'd & (FunctionType & 'e | FunctionType & ~#FunctionType)), +//│ rhs: 'rhs +//│ } | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'rhs8} | Var & {name: string} //│ 'd <: {lhs: 'rhs7 & 'lhs5, rhs: 'rhs8} //│ 'rhs8 <: 'lhs4 & 'lhs & (PrimitiveType & {name: string} | 'd & (FunctionType & 'e | FunctionType & ~#FunctionType)) //│ 'e <: {lhs: 'rhs9, rhs: 'rhs9} diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls index ccbd405bfb..1eafbd9ade 100644 --- a/shared/src/test/diff/tapl/Untyped.mls +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -86,15 +86,60 @@ fun list8(x, y, z, w, v, u, t, s) = Cons(x, list7(y, z, w, v, u, t, s)) //│ = [Function: list2] //│ list3: ('head, 'head0, 'head1,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Nil}}}) //│ = [Function: list3] -//│ list4: ('head, 'head0, 'head1, 'head2,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Nil}}}}) +//│ list4: ('head, 'head0, 'head1, 'head2,) -> (Cons & { +//│ head: 'head, +//│ tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Nil}}} +//│ }) //│ = [Function: list4] -//│ list5: ('head, 'head0, 'head1, 'head2, 'head3,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Nil}}}}}) +//│ list5: ('head, 'head0, 'head1, 'head2, 'head3,) -> (Cons & { +//│ head: 'head, +//│ tail: Cons & { +//│ head: 'head0, +//│ tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Nil}}} +//│ } +//│ }) //│ = [Function: list5] -//│ list6: ('head, 'head0, 'head1, 'head2, 'head3, 'head4,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Nil}}}}}}) +//│ list6: ('head, 'head0, 'head1, 'head2, 'head3, 'head4,) -> (Cons & { +//│ head: 'head, +//│ tail: Cons & { +//│ head: 'head0, +//│ tail: Cons & { +//│ head: 'head1, +//│ tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Nil}}} +//│ } +//│ } +//│ }) //│ = [Function: list6] -//│ list7: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Cons & {head: 'head5, tail: Nil}}}}}}}) +//│ list7: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5,) -> (Cons & { +//│ head: 'head, +//│ tail: Cons & { +//│ head: 'head0, +//│ tail: Cons & { +//│ head: 'head1, +//│ tail: Cons & { +//│ head: 'head2, +//│ tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Cons & {head: 'head5, tail: Nil}}} +//│ } +//│ } +//│ } +//│ }) //│ = [Function: list7] -//│ list8: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5, 'head6,) -> (Cons & {head: 'head, tail: Cons & {head: 'head0, tail: Cons & {head: 'head1, tail: Cons & {head: 'head2, tail: Cons & {head: 'head3, tail: Cons & {head: 'head4, tail: Cons & {head: 'head5, tail: Cons & {head: 'head6, tail: Nil}}}}}}}}) +//│ list8: ('head, 'head0, 'head1, 'head2, 'head3, 'head4, 'head5, 'head6,) -> (Cons & { +//│ head: 'head, +//│ tail: Cons & { +//│ head: 'head0, +//│ tail: Cons & { +//│ head: 'head1, +//│ tail: Cons & { +//│ head: 'head2, +//│ tail: Cons & { +//│ head: 'head3, +//│ tail: Cons & {head: 'head4, tail: Cons & {head: 'head5, tail: Cons & {head: 'head6, tail: Nil}}} +//│ } +//│ } +//│ } +//│ } +//│ }) //│ = [Function: list8] fun listConcat(xs, ys) = @@ -465,7 +510,10 @@ fun showStepByValue(t) = ) //│ showStepByValue: ('rhs & (Abs | App & 'a | Var)) -> string //│ where -//│ 'a <: {lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), rhs: 'lhs & 'rhs0 & 'rhs2 & 'rhs3 & (Abs | App & 'a | Var)} +//│ 'a <: { +//│ lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), +//│ rhs: 'lhs & 'rhs0 & 'rhs2 & 'rhs3 & (Abs | App & 'a | Var) +//│ } //│ 'rhs2 <: Abs & {rhs: 'rhs2} | App & {lhs: 'rhs2, rhs: 'rhs2} | Var | ~Abs & ~App & ~Var //│ 'rhs1 <: Abs & 'b | App & 'c | Var & 'd | 'e & ~#Abs & ~#App & ~#Var //│ 'b <: 'lhs & 'rhs0 & 'rhs4 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'c | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'd | {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'e & ~#Abs & ~#App & ~#Var) diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index ab8f32b374..147e241a3e 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -233,7 +233,10 @@ fun showList(xs) = //│ = [Function: showList] let zeroToThree = Cons(0, Cons(1, Cons(2, Cons(3, Nil())))) -//│ zeroToThree: Cons & {head: 0, tail: Cons & {head: 1, tail: Cons & {head: 2, tail: Cons & {head: 3, tail: Nil}}}} +//│ zeroToThree: Cons & { +//│ head: 0, +//│ tail: Cons & {head: 1, tail: Cons & {head: 2, tail: Cons & {head: 3, tail: Nil}}} +//│ } //│ = Cons { //│ head: 0, //│ tail: Cons { head: 1, tail: Cons { head: 2, tail: [Cons] } } @@ -276,22 +279,40 @@ fun mapPartition2(f, xs) = Cons(x, xs) and mapPartition(f, xs) is res and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition2: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}) & 'head0 -> (Left & {leftValue: 'leftValue0} | Right & {rightValue: 'rightValue0}), Cons & {head: 'head0, tail: 'tail} | Nil,) -> (Pair & {fst: forall 'fst. Cons & {head: 'leftValue0, tail: forall 'fst0. Nil | 'fst0 | Cons & {head: 'leftValue, tail: Nil | 'fst0}} | Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}, snd: forall 'snd. Cons & {head: 'rightValue0, tail: forall 'snd0. Nil | 'snd0 | Cons & {head: 'rightValue, tail: Nil | 'snd0}} | Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd}}) -//│ where -//│ 'snd :> Nil | Cons & {head: 'rightValue, tail: 'snd} -//│ 'snd0 :> Nil | Cons & {head: 'rightValue, tail: 'snd0} -//│ 'fst :> Nil | Cons & {head: 'leftValue, tail: 'fst} -//│ 'fst0 :> Nil | Cons & {head: 'leftValue, tail: 'fst0} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ mapPartition2: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}) & 'head0 -> (Left & {leftValue: 'leftValue0} | Right & {rightValue: 'rightValue0}), Cons & {head: 'head0, tail: 'tail} | Nil,) -> (Pair & { +//│ fst: forall 'fst. Cons & { +//│ head: 'leftValue0, +//│ tail: forall 'fst0. Nil | 'fst0 | Cons & {head: 'leftValue, tail: Nil | 'fst0} +//│ } | Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}, +//│ snd: forall 'snd. Cons & { +//│ head: 'rightValue0, +//│ tail: forall 'snd0. Nil | 'snd0 | Cons & {head: 'rightValue, tail: Nil | 'snd0} +//│ } | Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd} +//│ }) +//│ where +//│ 'snd :> Nil | Cons & {head: 'rightValue, tail: 'snd} +//│ 'snd0 :> Nil | Cons & {head: 'rightValue, tail: 'snd0} +//│ 'fst :> Nil | Cons & {head: 'leftValue, tail: 'fst} +//│ 'fst0 :> Nil | Cons & {head: 'leftValue, tail: 'fst0} +//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil //│ = [Function: mapPartition2] mapPartition2(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) -//│ res: Pair & {fst: forall 'fst. Cons & {head: 0, tail: forall 'fst0. Nil | 'fst0 | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst0}} | Nil | 'fst | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst}, snd: forall 'snd. Cons & {head: 0, tail: forall 'snd0. Nil | 'snd0 | Cons & {head: 1 | 2 | 3, tail: Nil | 'snd0}} | Nil | 'snd | Cons & {head: 1 | 2 | 3, tail: Nil | 'snd}} -//│ where -//│ 'snd :> Nil | Cons & {head: 1 | 2 | 3, tail: 'snd} -//│ 'snd0 :> Nil | Cons & {head: 1 | 2 | 3, tail: 'snd0} -//│ 'fst :> Nil | Cons & {head: 1 | 2 | 3, tail: 'fst} -//│ 'fst0 :> Nil | Cons & {head: 1 | 2 | 3, tail: 'fst0} +//│ res: Pair & { +//│ fst: forall 'fst. Cons & { +//│ head: 0, +//│ tail: forall 'fst0. Nil | 'fst0 | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst0} +//│ } | Nil | 'fst | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst}, +//│ snd: forall 'snd. Cons & { +//│ head: 0, +//│ tail: forall 'snd0. Nil | 'snd0 | Cons & {head: 1 | 2 | 3, tail: Nil | 'snd0} +//│ } | Nil | 'snd | Cons & {head: 1 | 2 | 3, tail: Nil | 'snd} +//│ } +//│ where +//│ 'snd :> Nil | Cons & {head: 1 | 2 | 3, tail: 'snd} +//│ 'snd0 :> Nil | Cons & {head: 1 | 2 | 3, tail: 'snd0} +//│ 'fst :> Nil | Cons & {head: 1 | 2 | 3, tail: 'fst} +//│ 'fst0 :> Nil | Cons & {head: 1 | 2 | 3, tail: 'fst0} //│ = Pair { //│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, //│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } diff --git a/shared/src/test/diff/ucs/SimpleUCS.mls b/shared/src/test/diff/ucs/SimpleUCS.mls index 80906e9abc..d74a1b06eb 100644 --- a/shared/src/test/diff/ucs/SimpleUCS.mls +++ b/shared/src/test/diff/ucs/SimpleUCS.mls @@ -338,7 +338,9 @@ fun p(e, context) = Some(BoolVal(v)) then Right(v) Lit(IntVal(v)) then Left(v) Lit(BoolVal(v)) then Right(v) -//│ p: (Lit & {value: BoolVal & {value: 'value} | IntVal & {value: 'value0}} | Var & {name: 'name}, {get: 'name -> (Some & {value: BoolVal & {value: 'value} | IntVal & {value: 'value0}})},) -> (Left & {leftValue: 'value0} | Right & {rightValue: 'value}) +//│ p: (Lit & {value: BoolVal & {value: 'value} | IntVal & {value: 'value0}} | Var & {name: 'name}, { +//│ get: 'name -> (Some & {value: BoolVal & {value: 'value} | IntVal & {value: 'value0}}) +//│ },) -> (Left & {leftValue: 'value0} | Right & {rightValue: 'value}) //│ = [Function: p1] class Nil() @@ -354,7 +356,7 @@ fun f(x) = 0 :: Nil() then "oh" //│ ╔══[ERROR] Cannot find operator `::` in the context -//│ ║ l.354: 0 :: +//│ ║ l.356: 0 :: //│ ╙── ^^ //│ f: anything -> error //│ Code generation encountered an error: From 354f0d6490cabc655450ea722682313f4a1a8592 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 21 Sep 2023 18:17:03 +0800 Subject: [PATCH 453/498] Fix rigidity of explicit method parameters + add some tests --- .../src/main/scala/mlscript/NuTypeDefs.scala | 33 +++++---- .../src/test/diff/mlscript/RigidVariables.mls | 71 +++++++++++++++++++ shared/src/test/diff/nu/Extrusion.mls | 43 +++++++++++ shared/src/test/diff/nu/FlatMonads.mls | 8 +-- shared/src/test/diff/nu/GADTMono.mls | 44 ++++++++++-- shared/src/test/diff/nu/GenericMethods.mls | 30 ++++---- shared/src/test/diff/nu/Interfaces.mls | 4 +- shared/src/test/diff/nu/Jonathan.mls | 2 +- shared/src/test/diff/nu/Metaprog.mls | 65 +++++++++++++++++ shared/src/test/diff/nu/RigidVariables.mls | 44 ++++++++++++ 10 files changed, 298 insertions(+), 46 deletions(-) create mode 100644 shared/src/test/diff/mlscript/RigidVariables.mls create mode 100644 shared/src/test/diff/nu/Extrusion.mls create mode 100644 shared/src/test/diff/nu/Metaprog.mls create mode 100644 shared/src/test/diff/nu/RigidVariables.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 7ad5738aaa..87a1600a06 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -895,14 +895,24 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => decl match { case td: NuTypeDef => td.tparams.map(tp => - (tp._2, freshVar(TypeProvenance( - tp._2.toLoc, - "type parameter", - S(tp._2.name), - true), N, S(tp._2.name)), tp._1)) - case fd: NuFunDef => Nil // TODO + (tp._2, freshVar( + TypeProvenance(tp._2.toLoc, "type parameter", + S(tp._2.name), + isType = true), + N, S(tp._2.name)), tp._1)) + case fd: NuFunDef => + fd.tparams.map { tn => + (tn, freshVar( + TypeProvenance(tn.toLoc, "method type parameter", + originName = S(tn.name), + isType = true), + N, S(tn.name)), N) + } } } + lazy val tparamsSkolems: Ls[Str -> SkolemTag] = tparams.map { + case (tp, tv, vi) => (tp.name, SkolemTag(tv)(tv.prov)) + } lazy val explicitVariances: VarianceStore = MutMap.from(tparams.iterator.map(tp => tp._2 -> tp._3.getOrElse(VarianceInfo.in))) @@ -912,9 +922,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => explicitVariances.get(tv).getOrElse(VarianceInfo.in) lazy private implicit val vars: Map[Str, SimpleType] = - outerVars ++ tparams.iterator.map { - case (tp, tv, vi) => (tp.name, SkolemTag(tv)(tv.prov)) - } + outerVars ++ tparamsSkolems lazy val typedParams: Opt[Ls[Var -> FieldType]] = ctx.nest.nextLevel { implicit ctx => decl match { @@ -1089,11 +1097,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val body_ty = ctx.nextLevel { implicit ctx: Ctx => // * Note: can't use `ctx.poly` instead of `ctx.nextLevel` because all the methods // * in the current typing unit are quantified together. - vars ++ fd.tparams.map { tn => - tn.name -> freshVar(TypeProvenance(tn.toLoc, "method type parameter", - originName = S(tn.name), - isType = true), N, S(tn.name)) - } |> { implicit vars => + assert(fd.tparams.sizeCompare(tparamsSkolems) === 0, (fd.tparams, tparamsSkolems)) + vars ++ tparamsSkolems |> { implicit vars => // * Only type methods polymorphically if they're at the top level or if // * they're annotated with a type signature. // * Otherwise, we get too much extrusion and cycle check failures diff --git a/shared/src/test/diff/mlscript/RigidVariables.mls b/shared/src/test/diff/mlscript/RigidVariables.mls new file mode 100644 index 0000000000..ad93234d27 --- /dev/null +++ b/shared/src/test/diff/mlscript/RigidVariables.mls @@ -0,0 +1,71 @@ + + +:e +def foo[AAA]: AAA -> AAA +def foo(x) = x.a +//│ foo: 'a -> 'a +//│ = +//│ {a: 'a} -> 'a +//│ <: foo: +//│ 'a -> 'a +//│ ╔══[ERROR] Type mismatch in def definition: +//│ ║ l.5: def foo(x) = x.a +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `?a` does not have field 'a' +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.5: def foo(x) = x.a +//│ ║ ^^^ +//│ ╟── from reference: +//│ ║ l.5: def foo(x) = x.a +//│ ╙── ^ +//│ = [Function: foo] + +:e +class Test0 + method Foo0[AAA]: AAA -> AAA + method Foo0(x) = x.a +//│ ╔══[ERROR] Type mismatch in method definition: +//│ ║ l.26: method Foo0(x) = x.a +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── type `AAA` does not have field 'a' +//│ ║ l.25: method Foo0[AAA]: AAA -> AAA +//│ ║ ^^^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.26: method Foo0(x) = x.a +//│ ║ ^^^ +//│ ╟── from reference: +//│ ║ l.26: method Foo0(x) = x.a +//│ ╙── ^ +//│ Defined class Test0 +//│ Declared Test0.Foo0: Test0 -> 'AAA -> 'AAA +//│ Defined Test0.Foo0: Test0 -> {a: 'a} -> 'a + +class Test1 + method Foo1[AAA]: (AAA & {a: int}) -> int + method Foo1(x) = x.a +//│ Defined class Test1 +//│ Declared Test1.Foo1: Test1 -> {a: int} -> int +//│ Defined Test1.Foo1: Test1 -> {a: 'a} -> 'a + +:e +(Test1{}).Foo1({x=1}) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.51: (Test1{}).Foo1({x=1}) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── record literal of type `{x: 1}` does not have field 'a' +//│ ║ l.51: (Test1{}).Foo1({x=1}) +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from record type: +//│ ║ l.44: method Foo1[AAA]: (AAA & {a: int}) -> int +//│ ║ ^^^^^^^^ +//│ ╟── from intersection type: +//│ ║ l.44: method Foo1[AAA]: (AAA & {a: int}) -> int +//│ ╙── ^^^^^^^^^^^^^^^^ +//│ res: error | int +//│ = undefined + +(Test1{}).Foo1({a=1}) +//│ res: int +//│ = 1 + + diff --git a/shared/src/test/diff/nu/Extrusion.mls b/shared/src/test/diff/nu/Extrusion.mls new file mode 100644 index 0000000000..c566246f5d --- /dev/null +++ b/shared/src/test/diff/nu/Extrusion.mls @@ -0,0 +1,43 @@ +:NewDefs + + +fun f(y) = + let local = forall 'A; (x: 'A) => + y(x) + 1 + x + y +//│ fun f: forall 'a. (??A -> Int & 'a) -> 'a + +:e +f(id) +//│ ╔══[ERROR] Type error in application +//│ ║ l.12: f(id) +//│ ║ ^^^^^ +//│ ╟── type variable `'A` leaks out of its scope +//│ ║ l.5: let local = forall 'A; (x: 'A) => +//│ ║ ^^ +//│ ╟── into application of type `Int` +//│ ║ l.6: y(x) + 1 +//│ ║ ^^^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this reference: +//│ ║ l.6: y(x) + 1 +//│ ╙── ^ +//│ forall 'a. error | 'a -> 'a +//│ res +//│ = [Function: id] + + +fun f(y) = + let local = forall 'A; (x: 'A) => + (y : forall 'a; 'a -> 'a)(x) + x + y +//│ fun f: forall 'b. (forall 'a. 'a -> 'a & 'b) -> 'b + +f(id) +//│ forall 'a. 'a -> 'a +//│ res +//│ = [Function: id] + + diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index 0948a07bb8..9a6d4a6166 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -172,10 +172,10 @@ fun main(ctx) = ctx.printLine(concat("The sum is: ")(String of sum)) |>= _ => ctx.pure(sum) //│ fun main: forall 'a 'b 'c 'd 'e. { -//│ printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'a) -> 'e} & Str -> {bind: (anything -> 'd) -> 'b}, -//│ pure: Int -> 'd, -//│ readInt: {bind: (Int -> 'c) -> 'a & (Int -> 'b) -> 'c} -//│ } -> 'e +//│ printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'e) -> 'c} & Str -> {bind: (anything -> 'a) -> 'b}, +//│ pure: Int -> 'a, +//│ readInt: {bind: (Int -> 'd) -> 'e & (Int -> 'b) -> 'd} +//│ } -> 'c val defaultCtx = {printLine, readInt, pure: Pure} //│ val defaultCtx: { diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 3fff3bb2ce..2d33db314d 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -64,12 +64,28 @@ fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.59: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `#Expr & (Add & {Expr#A = ?A} | Cond[?] & {Expr#A = ?A} | Fst[?, ?] & {Expr#A = ?A} | LitBool & {Expr#A = ?A} | LitInt & {Expr#A = ?A} | Pair[?, ?] & {Expr#A = ?A} | Snd[?, ?] & {Expr#A = ?A})` does not match type `Add | LitBool | LitInt` +//│ ╟── type `#Expr & (Add & {Expr#A = A} | Cond[?] & {Expr#A = A} | Fst[?, ?] & {Expr#A = A} | LitBool & {Expr#A = A} | LitInt & {Expr#A = A} | Pair[?, ?] & {Expr#A = A} | Snd[?, ?] & {Expr#A = A})` does not match type `Add | LitBool | LitInt` //│ ║ l.55: fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^ //│ ╟── but it flows into reference with expected type `Add | LitBool | LitInt` //│ ║ l.57: e is LitInt(n) then n //│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.57: e is LitInt(n) then n +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.58: e is LitBool(b) then b +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.59: e is Add(x, y) then eval(x) + eval(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `Int` does not match type `A` +//│ ║ l.4: class LitInt(n: Int) extends Expr[Int] +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `A` +//│ ║ l.57: e is LitInt(n) then n +//│ ║ ^ +//│ ╟── Note: constraint arises from method type parameter: +//│ ║ l.55: fun eval[A](e: Expr[A]): A = +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition: //│ ║ l.55: fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,14 +97,28 @@ fun eval[A](e: Expr[A]): A = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.59: e is Add(x, y) then eval(x) + eval(y) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.5: class LitBool(b: Bool) extends Expr[Bool] -//│ ║ ^^^^ -//│ ╟── but it flows into reference with expected type `Int` +//│ ╟── type `Int` does not match type `A` +//│ ║ l.6: class Add(x: Expr[Int], y: Expr[Int]) extends Expr[Int] +//│ ║ ^^^ +//│ ╟── Note: constraint arises from method type parameter: +//│ ║ l.55: fun eval[A](e: Expr[A]): A = +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.55: fun eval[A](e: Expr[A]): A = +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.56: if +//│ ║ ^^^^^^^ +//│ ║ l.57: e is LitInt(n) then n +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.58: e is LitBool(b) then b -//│ ║ ^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.59: e is Add(x, y) then eval(x) + eval(y) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `A` is not an instance of type `Int` +//│ ║ l.55: fun eval[A](e: Expr[A]): A = +//│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.6: class Add(x: Expr[Int], y: Expr[Int]) extends Expr[Int] //│ ╙── ^^^ -//│ fun eval: (e: Expr[in Int out Int | false | true]) -> (Int | false | true) +//│ fun eval: forall 'A. (e: Expr['A]) -> 'A diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index a460124798..d06506d9c3 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -63,39 +63,33 @@ fun bar : A => A //│ ╔══[ERROR] Type parameters are not yet supported in this position //│ ║ l.62: fun bar : A => A //│ ╙── ^ -//│ ╔══[ERROR] type identifier not found: A -//│ ║ l.62: fun bar : A => A -//│ ╙── ^ -//│ ╔══[ERROR] type identifier not found: A -//│ ║ l.62: fun bar : A => A -//│ ╙── ^ -//│ fun bar: error -> error +//│ fun bar: forall 'A. 'A -> 'A :pe :e :w fun bar: A => A //│ ╔══[PARSE ERROR] Unmatched opening angle bracket -//│ ║ l.77: fun bar: A => A +//│ ║ l.71: fun bar: A => A //│ ║ ^ //│ ╙── Note that `<` without spaces around it is considered as an angle bracket and not as an operator //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position -//│ ║ l.77: fun bar: A => A +//│ ║ l.71: fun bar: A => A //│ ╙── ^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.77: fun bar: A => A +//│ ║ l.71: fun bar: A => A //│ ╙── ^^^^^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: >: -//│ ║ l.77: fun bar: A => A +//│ ║ l.71: fun bar: A => A //│ ╙── ^^ //│ ╔══[ERROR] identifier not found: A -//│ ║ l.77: fun bar: A => A +//│ ║ l.71: fun bar: A => A //│ ╙── ^ //│ ╔══[ERROR] identifier not found: A -//│ ║ l.77: fun bar: A => A +//│ ║ l.71: fun bar: A => A //│ ╙── ^ //│ ╔══[ERROR] identifier not found: A -//│ ║ l.77: fun bar: A => A +//│ ║ l.71: fun bar: A => A //│ ╙── ^ //│ error //│ Code generation encountered an error: @@ -109,16 +103,16 @@ module Test { fun test(x: A) = x } //│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `Test` -//│ ║ l.106: module Test { +//│ ║ l.100: module Test { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.107: fun foo: 'A => 'A +//│ ║ l.101: fun foo: 'A => 'A //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `Test` -//│ ║ l.106: module Test { +//│ ║ l.100: module Test { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.108: fun bar: 'A +//│ ║ l.102: fun bar: 'A //│ ╙── ^^^^^^^ //│ module Test { //│ fun bar: nothing diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 48145f48c9..8d2abef8cf 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -292,8 +292,8 @@ fc(c) fun fts['a](x: 'a & Test) = x.foo fts(c) -//│ fun fts: forall 'foo. (x: Test & {foo: 'foo} | Test & ~#Test) -> 'foo -//│ 1 +//│ fun fts: (x: Test) -> Int +//│ Int //│ res //│ = [Function: fts] diff --git a/shared/src/test/diff/nu/Jonathan.mls b/shared/src/test/diff/nu/Jonathan.mls index 13b9163b17..c5fc46d3c4 100644 --- a/shared/src/test/diff/nu/Jonathan.mls +++ b/shared/src/test/diff/nu/Jonathan.mls @@ -11,7 +11,7 @@ fun pure[A](a: A): Effectful['a, 'e] = Effectful(a) //│ class Effectful[A, E](value: A) { //│ fun flatMap: forall 'B. (f: A -> Effectful['B, E]) -> Effectful['B, E] //│ } -//│ fun pure: forall 'a. (a: 'a) -> Effectful['a, nothing] +//│ fun pure: forall 'A. (a: 'A) -> Effectful['A, nothing] // * Some effect tags module IO diff --git a/shared/src/test/diff/nu/Metaprog.mls b/shared/src/test/diff/nu/Metaprog.mls new file mode 100644 index 0000000000..7d6c5f36f4 --- /dev/null +++ b/shared/src/test/diff/nu/Metaprog.mls @@ -0,0 +1,65 @@ +:NewDefs + + +class Code[out A, out Ctx] +//│ class Code[A, Ctx] { +//│ constructor() +//│ } + +class IntLit(value: Int) extends Code[Int, nothing] +//│ class IntLit(value: Int) extends Code + +class Add[C](lhs: Code[Int, C], rhs: Code[Int, C]) extends Code[Int, C] +//│ class Add[C](lhs: Code[Int, C], rhs: Code[Int, C]) extends Code + +fun bind(x: Code['a, 'c], k: (forall 'cc; Code['a, 'cc] -> Code['b, 'cc])): Code['b, 'c] = k(x) +//│ fun bind: forall 'a 'c 'b. (x: Code['a, 'c], k: forall 'cc. Code['a, 'cc] -> Code['b, 'cc]) -> Code['b, 'c] + + +// * Note: extrusion +fun test(f) = + bind of IntLit(42), n => + f(n) + Add(n, IntLit(1)) +//│ fun test: (Code[Int, ??cc] -> anything) -> Code[Int, nothing] + + +abstract class Test[C] { + // * Represents what happens in "... ${input} ..." when a binding of C is in scope + fun unquote: (input: Code['a, C | 'c]) -> Code[Int, 'c] + fun getVar: Code[Int, C] + fun test0 = this.unquote of IntLit(1) + fun test1 = this.unquote of Add(this.getVar, IntLit(1)) +} +//│ abstract class Test[C] { +//│ fun getVar: Code[Int, C] +//│ fun test0: Code[Int, nothing] +//│ fun test1: Code[Int, nothing] +//│ fun unquote: forall 'c. (input: Code[anything, 'c | C]) -> Code[Int, 'c] +//│ } + + +:NoJS + +fun mkVar(f: forall 'C; Test['C] -> 'a): 'a +//│ fun mkVar: forall 'a. (f: forall 'C. Test['C] -> 'a) -> 'a + +mkVar of t0 => + t0.unquote of Add(t0.getVar, IntLit(1)) +//│ Code[Int, nothing] + +mkVar of t0 => + Add(t0.getVar, IntLit(1)) +//│ Add[??C] + +mkVar of t0 => + mkVar of t1 => + t1.unquote of t0.unquote of Add(t0.getVar, t1.getVar) +//│ Code[Int, nothing] + +mkVar of t0 => + mkVar of t1 => + t0.unquote of t1.unquote of Add(t0.getVar, t1.getVar) +//│ Code[Int, nothing] + + diff --git a/shared/src/test/diff/nu/RigidVariables.mls b/shared/src/test/diff/nu/RigidVariables.mls new file mode 100644 index 0000000000..12f4c4d28b --- /dev/null +++ b/shared/src/test/diff/nu/RigidVariables.mls @@ -0,0 +1,44 @@ +:NewDefs + + +// * Flexible + +fun f(x: 'test) = [x.b, x] +//│ fun f: forall 'b 'test. (x: {b: 'b} & 'test) -> ['b, 'test] + + +// * Rigid + +:e +fun f[A](x: A) = x.b +//│ ╔══[ERROR] Type `A` does not contain member `b` +//│ ║ l.13: fun f[A](x: A) = x.b +//│ ╙── ^^ +//│ fun f: (x: anything) -> error + +fun f[A](x: A & { b: ' }) = x.b +//│ fun f: forall 'b. (x: {b: 'b}) -> 'b + +:e +module Foo { + fun f[A](x: A) = x.b +} +//│ ╔══[ERROR] Type `A` does not contain member `b` +//│ ║ l.24: fun f[A](x: A) = x.b +//│ ╙── ^^ +//│ module Foo { +//│ fun f: (x: anything) -> error +//│ } + +:e +class Foo[A](x: A) { + fun f = x.b +} +//│ ╔══[ERROR] Type `A` does not contain member `b` +//│ ║ l.35: fun f = x.b +//│ ╙── ^^ +//│ class Foo[A](x: A) { +//│ fun f: error +//│ } + + From b428bfb096f120da404a40028d00d5a359e329d9 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 22 Sep 2023 14:50:52 +0800 Subject: [PATCH 454/498] Add some minor tests --- .../test/diff/ecoop23/ComparePointPoly.mls | 90 ++++++++++++++++++ shared/src/test/diff/nu/EqlClasses.mls | 39 ++++++++ shared/src/test/diff/nu/MissingTypeArg.mls | 94 +++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 shared/src/test/diff/ecoop23/ComparePointPoly.mls create mode 100644 shared/src/test/diff/nu/MissingTypeArg.mls diff --git a/shared/src/test/diff/ecoop23/ComparePointPoly.mls b/shared/src/test/diff/ecoop23/ComparePointPoly.mls new file mode 100644 index 0000000000..c90dfde588 --- /dev/null +++ b/shared/src/test/diff/ecoop23/ComparePointPoly.mls @@ -0,0 +1,90 @@ +:NewDefs + + +class Some[out A](val value: A) +module None +//│ class Some[A](value: A) +//│ module None + +mixin ComparePoint { + fun compare(lhs, rhs) = (lhs.x === rhs.x) && (lhs.y === rhs.y) +} +mixin CompareColored { + fun compare(lhs, rhs) = + super.compare(lhs, rhs) && (lhs.color === rhs.color) +} +mixin CompareNested { + fun compare(lhs, rhs) = + super.compare(lhs, rhs) && + if lhs.parent is Some(p) + then rhs.parent is Some(q) and this.compare(p, q) + else rhs.parent is None +} +//│ mixin ComparePoint() { +//│ fun compare: ({x: Eql['a], y: Eql['b]}, {x: 'a, y: 'b}) -> Bool +//│ } +//│ mixin CompareColored() { +//│ super: {compare: ('c, 'd) -> Bool} +//│ fun compare: ({color: Eql['e]} & 'c, {color: 'e} & 'd) -> Bool +//│ } +//│ mixin CompareNested() { +//│ super: {compare: ('f, 'g) -> Bool} +//│ this: {compare: ('h, 'i) -> Bool} +//│ fun compare: ({parent: Object & ~#Some | Some['h]} & 'f, {parent: Object & ~#Some | Some['i]} & 'g) -> Bool +//│ } + +class MyPoint[out Col](val x: Int, val y: Int, val color: Col, val parent: Some[MyPoint[Col]] | None) +//│ class MyPoint[Col](x: Int, y: Int, color: Col, parent: None | Some[MyPoint[Col]]) + +module CompareMyPoint extends ComparePoint, CompareColored, CompareNested +//│ module CompareMyPoint { +//│ fun compare: ('a, 'b) -> Bool +//│ } +//│ where +//│ 'b <: {color: 'c, parent: Object & ~#Some | Some['b], x: 'd, y: 'e} +//│ 'a <: {color: Eql['c], parent: Object & ~#Some | Some['a], x: Eql['d], y: Eql['e]} + +let Red = 0 +let p0 = MyPoint(0, 0, Red, None) +let p1 = MyPoint(0, 1, Red, None) +let p2 = MyPoint(0, 1, Red, None) +let p3 = MyPoint(0, 1, Red, Some(p1)) +let p4 = MyPoint(0, 1, Red, Some(p2)) +let p5 = MyPoint(0, 1, Red, Some(p3)) +//│ let Red: 0 +//│ let p0: MyPoint[0] +//│ let p1: MyPoint[0] +//│ let p2: MyPoint[0] +//│ let p3: MyPoint[0] +//│ let p4: MyPoint[0] +//│ let p5: MyPoint[0] +//│ Red +//│ = 0 +//│ p0 +//│ = MyPoint {} +//│ p1 +//│ = MyPoint {} +//│ p2 +//│ = MyPoint {} +//│ p3 +//│ = MyPoint {} +//│ p4 +//│ = MyPoint {} +//│ p5 +//│ = MyPoint {} + +CompareMyPoint.compare(p0, p1) +CompareMyPoint.compare(p1, p2) +CompareMyPoint.compare(p3, p4) +CompareMyPoint.compare(p3, p5) +//│ Bool +//│ res +//│ = false +//│ res +//│ = true +//│ res +//│ = true +//│ res +//│ = false + + diff --git a/shared/src/test/diff/nu/EqlClasses.mls b/shared/src/test/diff/nu/EqlClasses.mls index 76f346178c..0b3382c62b 100644 --- a/shared/src/test/diff/nu/EqlClasses.mls +++ b/shared/src/test/diff/nu/EqlClasses.mls @@ -156,6 +156,45 @@ q === q +class MP[Col](val color: Col) +//│ class MP[Col](color: Col) + +val mp = MP(1) +//│ val mp: MP[1] +//│ mp +//│ = MP {} + +mp === mp +//│ Bool +//│ res +//│ = true + +fun cmp(lhs, rhs) = lhs.color === rhs.color +//│ fun cmp: forall 'a. ({color: Eql['a]}, {color: 'a}) -> Bool + +cmp(mp, mp) +//│ Bool +//│ res +//│ = true + +module Mix { + fun compare(lhs, rhs) = (lhs.color === rhs.color) +} +module Comp extends Mix +//│ module Mix { +//│ fun compare: forall 'a. ({color: Eql['a]}, {color: 'a}) -> Bool +//│ } +//│ module Comp extends Mix { +//│ fun compare: forall 'b. ({color: Eql['b]}, {color: 'b}) -> Bool +//│ } + +Comp.compare(mp, mp) +//│ Bool +//│ res +//│ = true + + + // *** NOTES *** diff --git a/shared/src/test/diff/nu/MissingTypeArg.mls b/shared/src/test/diff/nu/MissingTypeArg.mls new file mode 100644 index 0000000000..07fa09fb8f --- /dev/null +++ b/shared/src/test/diff/nu/MissingTypeArg.mls @@ -0,0 +1,94 @@ +// * This is an example program where the error we get is really not ideal + +:NewDefs + + +// * An example recursive definition: + +fun test(pt1, pt2) = pt1.color === pt1.color and + let p1 = pt1.parent + let p2 = pt2.parent + if p1 is undefined then true + else if p2 is undefined then true + else test(p1, p2) +//│ fun test: forall 'a 'b 'c. ('a, 'c) -> Bool +//│ where +//│ 'c <: {parent: Object & 'c & ~undefined | undefined} +//│ 'a <: {color: Eql['b] & 'b, parent: Object & 'a & ~undefined | undefined} + + +// * This works out fine: + +class MyPoint1[Col](val color: Col, val parent: MyPoint1[Col] | undefined) +//│ class MyPoint1[Col](color: Col, parent: MyPoint1[Col] | undefined) + +val p = MyPoint1(0, undefined) +//│ val p: MyPoint1['Col] +//│ where +//│ 'Col :> 0 +//│ p +//│ = MyPoint1 {} + +test(p, p) +//│ Bool +//│ res +//│ = true + + +// * BUT... if we forgot to pass the type argument to MyPoint2 (getting a raw/nominal-tag type), +// * the error is not helpful at all: + +class MyPoint2[Col](val color: Col, val parent: MyPoint2 | undefined) +//│ class MyPoint2[Col](color: Col, parent: MyPoint2[anything] | undefined) + +val p = MyPoint2(0, undefined) +//│ val p: MyPoint2[0] +//│ p +//│ = MyPoint2 {} + +:e +test(p, p) +//│ ╔══[ERROR] Type error in application +//│ ║ l.50: test(p, p) +//│ ║ ^^^^^^^^^^ +//│ ╟── type variable `Col` leaks out of its scope +//│ ║ l.41: class MyPoint2[Col](val color: Col, val parent: MyPoint2 | undefined) +//│ ║ ^^^ +//│ ╟── into field selection of type `#Eql` +//│ ║ l.8: fun test(pt1, pt2) = pt1.color === pt1.color and +//│ ╙── ^^^^^^^^^ +//│ error +//│ res +//│ = true + + + +// TODO[ucs] ideally this should work + +fun test(pt1, pt2) = pt1.color === pt1.color and + let p1 = pt1.parent + let p2 = pt2.parent + if p1 is undefined then p2 is undefined + else test(p1, p2) +//│ fun test: forall 'a 'b 'c. ('b, 'a) -> Bool +//│ where +//│ 'a <: {parent: Object & 'a} +//│ 'b <: {color: Eql['c] & 'c, parent: Object & 'b & ~undefined | undefined} + +:e // TODO support +test(p, p) +//│ ╔══[ERROR] Type error in application +//│ ║ l.79: test(p, p) +//│ ║ ^^^^^^^^^^ +//│ ╟── type variable `Col` leaks out of its scope +//│ ║ l.41: class MyPoint2[Col](val color: Col, val parent: MyPoint2 | undefined) +//│ ║ ^^^ +//│ ╟── into field selection of type `#Eql` +//│ ║ l.68: fun test(pt1, pt2) = pt1.color === pt1.color and +//│ ╙── ^^^^^^^^^ +//│ error +//│ res +//│ = true + + + From 29762d0eacdeb24c0f445885241a00619dc2da32 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 23 Sep 2023 09:20:01 +0800 Subject: [PATCH 455/498] Fix missing skolems in type of `this`, leading to unsound constraints --- .../src/main/scala/mlscript/NuTypeDefs.scala | 18 +- shared/src/test/diff/nu/ClassesInMixins.mls | 14 +- shared/src/test/diff/nu/FlatMonads.mls | 247 ++++++++++++------ shared/src/test/diff/nu/FlatMonads_repro.mls | 219 ++++++++++++++++ .../src/test/diff/nu/ThisRefinedClasses.mls | 2 +- 5 files changed, 413 insertions(+), 87 deletions(-) create mode 100644 shared/src/test/diff/nu/FlatMonads_repro.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 87a1600a06..b8662000fb 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -785,7 +785,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case rawCls: TypedNuCls => - // println(s"Raw $rawCls") + // println(s"Raw $rawCls where ${rawCls.showBounds}") val (fr, ptp) = refreshHelper(rawCls, v, if (parTargs.isEmpty) N else S(parTargs)) // infer ty args if not provided val cls = { @@ -794,7 +794,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => rawCls.freshenAbove(info.level, rigidify = false) } - // println(s"Fresh[${ctx.lvl}] $cls") + // println(s"Fresh[${ctx.lvl}] $cls where ${cls.showBounds}") def checkArgsNum(effectiveParamSize: Int) = if (parArgs.sizeCompare(effectiveParamSize) =/= 0) @@ -1433,7 +1433,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val tparamMems = tparams.map { case (tp, tv, vi) => // TODO use vi val fldNme = td.nme.name + "#" + tp.name - NuParam(TypeName(fldNme).withLocOf(tp), FieldType(S(tv), tv)(tv.prov), isPublic = true)(lvl) + val skol = SkolemTag(tv)(tv.prov) + NuParam(TypeName(fldNme).withLocOf(tp), FieldType(S(skol), skol)(tv.prov), isPublic = true)(lvl) } val tparamFields = tparamMems.map(p => p.nme.toVar -> p.ty) assert(!typedParams.exists(_.keys.exists(tparamFields.keys.toSet)), ???) @@ -1765,10 +1766,19 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => println(s"Assigning ${tn.name} :: ${_tv} := $targ where ${targ.showBounds}") val tv = - freshVar(_tv.prov, S(_tv), _tv.nameHint)(targ.level) + freshVar(_tv.prov, S(_tv), _tv.nameHint, + lbs = _tv.lowerBounds, + ubs = _tv.upperBounds, + )(targ.level) println(s"Set ${tv} ~> ${_tv}") assert(tv.assignedTo.isEmpty) + + // * Note: no checks that the assigned variable satisfies the bounds... + // * When we support bounded types, bounds check will be needed at the type definition site + assert(tv.lowerBounds.isEmpty, tv.lowerBounds) + assert(tv.upperBounds.isEmpty, tv.upperBounds) tv.assignedTo = S(targ) + // println(s"Assigned ${tv.assignedTo}") tv }) diff --git a/shared/src/test/diff/nu/ClassesInMixins.mls b/shared/src/test/diff/nu/ClassesInMixins.mls index 56a7b4fed4..eb76284141 100644 --- a/shared/src/test/diff/nu/ClassesInMixins.mls +++ b/shared/src/test/diff/nu/ClassesInMixins.mls @@ -72,21 +72,29 @@ mixin Test3 { fun f(x) = if x is Foo then 1 } +:e mixin Test { class Lit(n: Int) class Add(lhs: A, rhs: A) { + // Should be a lazy val only forceable when A has the right shape (constrained types?): fun cached = size(this) } fun size(x) = if x is Add(l, r) then this.size(l) + this.size(r) } +//│ ╔══[ERROR] Type error in application +//│ ║ l.80: fun cached = size(this) +//│ ║ ^^^^^^^^^^ +//│ ╟── type variable `A` leaks out of its scope +//│ ║ l.78: class Add(lhs: A, rhs: A) { +//│ ╙── ^ //│ mixin Test() { -//│ this: {size: 'A -> Int} +//│ this: {size: (??A | 'a) -> Int} //│ class Add[A](lhs: A, rhs: A) { -//│ fun cached: Int +//│ fun cached: Int | error //│ } //│ class Lit(n: Int) -//│ fun size: Add['A] -> Int +//│ fun size: Add[??A0 & 'a] -> Int //│ } diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index 9a6d4a6166..950d067d5f 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -1,6 +1,10 @@ :NewDefs +declare fun String: anything -> Str +//│ fun String: anything -> Str + + abstract class IO[A] { fun bind(f) = Bind(this, f) fun run: A @@ -16,39 +20,34 @@ class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { //│ fun run: A //│ } //│ class Pure[A](value: A) extends IO { -//│ fun bind: forall 'A 'B0. ('A -> IO['B0]) -> Bind['A, 'B0] +//│ fun bind: forall 'B0. (A -> IO['B0]) -> Bind[in A & 'A out A, 'B0] //│ fun run: A //│ } //│ class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO { -//│ fun bind: forall 'B1 'A0. ('A0 -> IO['B1]) -> Bind['A0, 'B1] +//│ fun bind: forall 'B1. (B -> IO['B1]) -> Bind[in B & 'A0 out B, 'B1] //│ fun run: B //│ } //│ where -//│ 'A0 <: 'A1 -//│ 'A1 := B -//│ 'A <: 'A2 -//│ 'A2 := A +//│ 'A0 := B +//│ 'A := A -module readInt extends IO[Int] { fun run = 42 } +module readInt extends IO[Int] { fun run: Int = 42 } class printLine(str: Str) extends IO[undefined] { fun run = log(str) } -declare fun String: anything -> Str //│ module readInt extends IO { -//│ fun bind: forall 'A 'B. ('A -> IO['B]) -> Bind['A, 'B] -//│ fun run: 42 +//│ fun bind: forall 'B. ('A -> IO['B]) -> Bind[Int & 'A, 'B] +//│ fun run: Int //│ } //│ class printLine(str: Str) extends IO { -//│ fun bind: forall 'A0 'B0. ('A0 -> IO['B0]) -> Bind['A0, 'B0] +//│ fun bind: forall 'B0. ('A0 -> IO['B0]) -> Bind[undefined & 'A0, 'B0] //│ fun run: undefined //│ } -//│ fun String: anything -> Str //│ where -//│ 'A0 <: 'A1 -//│ 'A1 := undefined -//│ 'A <: 'A2 -//│ 'A2 := Int +//│ 'A0 := undefined +//│ 'A := Int // * Nested indent: + val main = printLine("Hi! Input two numbers: ").bind of _ => readInt.bind of n => @@ -56,10 +55,9 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ val main: Bind['A, 'B] +//│ val main: Bind[undefined, 'B] //│ where //│ 'B :> Int -//│ 'A <: undefined //│ main //│ = Bind {} @@ -73,6 +71,7 @@ main.run // * Flat indent: + val main = printLine("Hi! Input two numbers: ").bind of _ => readInt.bind of n => @@ -80,10 +79,9 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ val main: Bind['A, 'B] +//│ val main: Bind[undefined, 'B] //│ where //│ 'B :> Int -//│ 'A <: undefined //│ main //│ = Bind {} @@ -96,33 +94,31 @@ main.run //│ The sum is: 84 -// * TODO improve this error +// * TODO improve this error (parameter list repr.) :e printLine("").bind of [] => error //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.101: printLine("").bind of [] => error -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.99: printLine("").bind of [] => error +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `[?A]` does not match type `[]` -//│ ║ l.11: class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { +//│ ║ l.15: class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { //│ ╙── ^ -//│ Bind['A, 'B] | error -//│ where -//│ 'A <: undefined +//│ Bind[undefined, 'B] | error //│ res //│ = Bind {} -// * Using a shortand operator for `bind` +// * Using a shortand operator for `bind`... What's the use of a `do` notation?! :^) -fun (|>=) bindOp[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) -//│ fun (|>=) bindOp: forall 'A 'B. (x: IO['A], f: 'A -> IO['B]) -> IO['B] +fun (#>>) bind[A, B](x: IO[A], f: A -> IO[B]): IO[B] = x.bind(f) +//│ fun (#>>) bind: forall 'A 'B. (x: IO['A], f: 'A -> IO['B]) -> IO['B] val main = - printLine("Hi! Input two numbers: ") |>= _ => - readInt |>= n => - readInt |>= m => + printLine("Hi! Input two numbers: ") #>> _ => + readInt #>> n => + readInt #>> m => val sum = n + m - printLine(concat("The sum is: ")(String of sum)) |>= _ => + printLine(concat("The sum is: ")(String of sum)) #>> _ => Pure(sum) //│ val main: IO['B] //│ where @@ -130,23 +126,70 @@ val main = //│ main //│ = Bind {} +main.run +//│ Int +//│ res +//│ = 84 +//│ // Output +//│ Hi! Input two numbers: +//│ The sum is: 84 + +fun loop = + printLine("Input a positive number: ") #>> _ => + readInt #>> n => + if n < 0 then loop else Pure(n) +//│ fun loop: forall 'B. IO['B] +//│ where +//│ 'B :> Int + +let r = loop.run +//│ let r: Int +//│ r +//│ = 42 +//│ // Output +//│ Input a positive number: + + +// * Using another shortand operator for `map` + +fun (>>) compose[A, B, C](f: A -> B, g: B -> C): A -> C = x => g(f(x)) +fun (#>) map[A, B](x: IO[A], f: A -> B): IO[B] = x.bind(f >> Pure) +//│ fun (>>) compose: forall 'A 'B 'C. (f: 'A -> 'B, g: 'B -> 'C) -> 'A -> 'C +//│ fun (#>) map: forall 'A0 'B0. (x: IO['A0], f: 'A0 -> 'B0) -> IO['B0] + +val main = + printLine("Hi! Input two numbers: ") #>> _ => + readInt #>> n => + readInt #>> m => + val sum = n + m + printLine(concat("The sum is: ")(String of sum)) #> _ => + sum +//│ val main: IO['B] +//│ where +//│ 'B :> Int +//│ main +//│ = Bind {} + // * With no type annotations: -fun (|>=) bindOp(x, f) = x.bind(f) -//│ fun (|>=) bindOp: forall 'a 'b. ({bind: 'a -> 'b}, 'a) -> 'b +fun (>>) compose(f, g) = x => g(f(x)) +fun (#>>) bind(x, f) = x.bind(f) +fun (#>) map(x, f) = x.bind(f >> Pure) +//│ fun (>>) compose: forall 'a 'b 'c. ('c -> 'a, 'a -> 'b) -> 'c -> 'b +//│ fun (#>>) bind: forall 'd 'e. ({bind: 'd -> 'e}, 'd) -> 'e +//│ fun (#>) map: forall 'f 'A 'g. ({bind: ('f -> Pure['A]) -> 'g}, 'f -> 'A) -> 'g val main = - printLine("Hi! Input two numbers: ") |>= _ => - readInt |>= n => - readInt |>= m => + printLine("Hi! Input two numbers: ") #>> _ => + readInt #>> n => + readInt #>> m => val sum = n + m - printLine(concat("The sum is: ")(String of sum)) |>= _ => - Pure(sum) -//│ val main: Bind['A, 'B] + printLine(concat("The sum is: ")(String of sum)) #> _ => + sum +//│ val main: Bind[undefined, 'B] //│ where //│ 'B :> Int -//│ 'A <: undefined //│ main //│ = Bind {} @@ -158,24 +201,36 @@ main.run //│ Hi! Input two numbers: //│ The sum is: 84 +fun loop = + printLine("Input a positive number: ") #>> _ => + readInt #>> n => + if n < 0 then loop else Pure(n) +//│ fun loop: forall 'B. Bind[undefined, 'B] +//│ where +//│ 'B :> Int + +let r = loop.run +//│ let r: Int +//│ r +//│ = 42 +//│ // Output +//│ Input a positive number: -// * Abstracting over the monad: -fun (|>=) bindOp(x, f) = x.bind(f) -//│ fun (|>=) bindOp: forall 'a 'b. ({bind: 'a -> 'b}, 'a) -> 'b +// * Abstracting over the monad: fun main(ctx) = - ctx.printLine("Hi! Input two numbers: ") |>= _ => - ctx.readInt |>= n => - ctx.readInt |>= m => + ctx.printLine("Hi! Input two numbers: ") #>> _ => + ctx.readInt #>> n => + ctx.readInt #>> m => val sum = n + m - ctx.printLine(concat("The sum is: ")(String of sum)) |>= _ => + ctx.printLine(concat("The sum is: ")(String of sum)) #>> _ => ctx.pure(sum) //│ fun main: forall 'a 'b 'c 'd 'e. { -//│ printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'e) -> 'c} & Str -> {bind: (anything -> 'a) -> 'b}, -//│ pure: Int -> 'a, -//│ readInt: {bind: (Int -> 'd) -> 'e & (Int -> 'b) -> 'd} -//│ } -> 'c +//│ printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'a) -> 'e} & Str -> {bind: (anything -> 'd) -> 'c}, +//│ pure: Int -> 'd, +//│ readInt: {bind: (Int -> 'b) -> 'a & (Int -> 'c) -> 'b} +//│ } -> 'e val defaultCtx = {printLine, readInt, pure: Pure} //│ val defaultCtx: { @@ -205,8 +260,8 @@ main(defaultCtx).run //│ The sum is: 84 fun loop(ctx) = - ctx.printLine("Input a positive number: ") |>= _ => - ctx.readInt |>= n => + ctx.printLine("Input a positive number: ") #>> _ => + ctx.readInt #>> n => if n < 0 then loop(ctx) else ctx.pure(n) //│ fun loop: forall 'a 'b 'c 'd. { //│ printLine: "Input a positive number: " -> {bind: (anything -> 'a) -> 'b}, @@ -214,39 +269,51 @@ fun loop(ctx) = //│ readInt: {bind: ((Num & 'c) -> ('d | 'b)) -> 'a} //│ } -> 'b -// * FIXME why `nothing`? +let r = loop(defaultCtx) +//│ let r: Bind[undefined, 'B] +//│ where +//│ 'B :> Int +//│ r +//│ = Bind {} + let r = loop(defaultCtx).run -//│ let r: nothing +//│ let r: Int //│ r //│ = 42 //│ // Output //│ Input a positive number: +:e not(r) -//│ Bool +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.287: not(r) +//│ ║ ^^^^^^ +//│ ╟── type `Int` is not an instance of type `Bool` +//│ ║ l.34: module readInt extends IO[Int] { fun run: Int = 42 } +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `Bool` +//│ ║ l.287: not(r) +//│ ╙── ^ +//│ error | false | true //│ res //│ = false -// * Note: using inferred type parent arguments +// * Note: using inferred parent type arguments module readInt extends IO { fun run = 42 } class printLine(str: Str) extends IO { fun run = log(str) } -declare fun String: anything -> Str //│ module readInt extends IO { -//│ fun bind: forall 'A 'B. ('A -> IO['B]) -> Bind['A, 'B] +//│ fun bind: forall 'B. ('A -> IO['B]) -> Bind['A, 'B] //│ fun run: 42 //│ } //│ class printLine(str: Str) extends IO { -//│ fun bind: forall 'A0 'B0. ('A0 -> IO['B0]) -> Bind['A0, 'B0] +//│ fun bind: forall 'B0. ('A0 -> IO['B0]) -> Bind['A0, 'B0] //│ fun run: undefined //│ } -//│ fun String: anything -> Str //│ where -//│ 'A0 <: 'A1 -//│ 'A1 :> undefined -//│ 'A <: 'A2 -//│ 'A2 :> 42 +//│ 'A0 :> undefined +//│ 'A :> 42 val main = printLine("Hi! Input two numbers: ").bind of _ => @@ -255,50 +322,72 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ val main: Bind['A, 'B] +//│ val main: Bind[in 'A out undefined | 'A, 'B] //│ where //│ 'B :> Int //│ main //│ = Bind {} main -//│ Bind['A, 'B] +//│ Bind[in 'A out undefined | 'A, 'B] //│ where //│ 'B :> Int //│ res //│ = Bind {} -// :e // * FIXME this should be an error +:e let r = printLine("").bind of 0 => Pure(1) -//│ let r: Bind['A, 'B] +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.340: let r = printLine("").bind of 0 => Pure(1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `undefined` does not match type `0` +//│ ║ l.305: class printLine(str: Str) extends IO { fun run = log(str) } +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from integer literal: +//│ ║ l.340: let r = printLine("").bind of 0 => Pure(1) +//│ ╙── ^ +//│ let r: Bind[in 0 & 'A out undefined | 'A, 'B] | error //│ where //│ 'B :> 1 -//│ 'A <: 0 //│ r //│ = Bind {} -// :e // * FIXME this should be an error +:e let r = printLine("").bind of x => log(x.a) Pure(1) -//│ let r: Bind['A, 'B] +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.357: let r = printLine("").bind of x => +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.358: log(x.a) +//│ ║ ^^^^^^^^^ +//│ ║ l.359: Pure(1) +//│ ║ ^^^^^^^ +//│ ╟── application of type `undefined` does not have field 'a' +//│ ║ l.305: class printLine(str: Str) extends IO { fun run = log(str) } +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from field selection: +//│ ║ l.358: log(x.a) +//│ ║ ^^^ +//│ ╟── from reference: +//│ ║ l.358: log(x.a) +//│ ╙── ^ +//│ let r: Bind[in {a: anything} & 'A out undefined | 'A, 'B] | error //│ where //│ 'B :> 1 -//│ 'A <: {a: anything} //│ r //│ = Bind {} :re r.run -//│ 1 +//│ 1 | error //│ res //│ Runtime error: //│ TypeError: Cannot read properties of undefined (reading 'a') - -// * We can even have the following syntax... what's the use of a `do` notation?! +// * We can even technically support the following syntax... :NoJS // * TODO We'll need to support functions extended with fields diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls new file mode 100644 index 0000000000..250e3635db --- /dev/null +++ b/shared/src/test/diff/nu/FlatMonads_repro.mls @@ -0,0 +1,219 @@ +:NewDefs + + +abstract class IO[A] { + fun bind(f) = Bind(this, f) + fun hey = this + fun run: A +} +class Bind[CC, AA](underlying: IO[CC], f: CC -> IO[AA]) extends IO[AA] { + fun run = f(underlying.run).run +} +class Pure[A](value: A) extends IO[A] { + fun run = value +} +//│ abstract class IO[A] { +//│ fun bind: forall 'AA. (A -> IO['AA]) -> Bind[A, 'AA] +//│ fun hey: IO[A] +//│ fun run: A +//│ } +//│ class Bind[CC, AA](underlying: IO[CC], f: CC -> IO[AA]) extends IO { +//│ fun bind: forall 'AA0. ('A -> IO['AA0]) -> Bind['A, 'AA0] +//│ fun hey: IO['A] +//│ fun run: AA +//│ } +//│ class Pure[A](value: A) extends IO { +//│ fun bind: forall 'AA1. (A -> IO['AA1]) -> Bind[in A & 'A0 out A, 'AA1] +//│ fun hey: IO['A0] +//│ fun run: A +//│ } +//│ where +//│ 'A0 := A +//│ 'A := AA + +module readInt extends IO[Int] { fun run: Int = 42 } +//│ module readInt extends IO { +//│ fun bind: forall 'AA. ('A -> IO['AA]) -> Bind[Int & 'A, 'AA] +//│ fun hey: IO['A] +//│ fun run: Int +//│ } +//│ where +//│ 'A := Int + + +let ri(f) = Bind(Pure(42), f) +// let ri(f) = Bind(Pure(42) : IO[Int], f) +// let ri(f) = Bind(error : IO[Int], f) +//│ let ri: forall 'CC 'AA. ('CC -> IO['AA]) -> Bind['CC, 'AA] +//│ where +//│ 'CC :> 42 +//│ ri +//│ = [Function: ri] + +ri(Pure) +//│ Bind['CC, 'AA] +//│ where +//│ 'CC :> 42 +//│ <: 'AA +//│ 'AA :> 42 +//│ res +//│ = Bind {} + +readInt.bind +//│ forall 'AA. (Int -> IO['AA]) -> Bind[Int, 'AA] +//│ res +//│ = [Function: bind] + +Bind(readInt, Pure) +//│ Bind[Int & 'AA, 'AA] +//│ where +//│ 'AA :> Int +//│ res +//│ = Bind {} + + +// TODO prevent JS method extrusion; force explicit use of eta epxansion + +let b = readInt.bind : (Int -> IO['B]) -> Bind[Int, 'B] +//│ let b: (Int -> IO['B]) -> Bind[Int, 'B] +//│ b +//│ = [Function: bind] + +let b = readInt.bind : ('A -> IO['B]) -> Bind['A, 'B] where 'A : Int +//│ let b: (Int -> IO['B]) -> Bind[Int, 'B] +//│ b +//│ = [Function: bind] + +let b = readInt.bind : ('A -> IO['B]) -> Bind['A, 'B] where Int : 'A +//│ let b: (Int -> IO['B]) -> Bind[Int, 'B] +//│ b +//│ = [Function: bind] + + +let r = b of Pure +//│ let r: Bind[in Int & 'B out Int, 'B] +//│ where +//│ 'B :> Int +//│ r +//│ = Bind {} + +:re // FIXME `undefined` due to JS method extrusion +r.run +//│ Int +//│ res +//│ Runtime error: +//│ TypeError: Cannot read properties of undefined (reading 'run') + + +let r = readInt.bind of Pure +//│ let r: Bind[in Int & 'AA out Int, 'AA] +//│ where +//│ 'AA :> Int +//│ r +//│ = Bind {} + +r.run +//│ Int +//│ res +//│ = 42 + +x => readInt.bind of x +//│ (Int -> IO['AA]) -> Bind[Int, 'AA] +//│ res +//│ = [Function: res] + +readInt.bind of Pure +//│ Bind[in Int & 'AA out Int, 'AA] +//│ where +//│ 'AA :> Int +//│ res +//│ = Bind {} + +readInt: IO['a] +//│ IO[Int] +//│ res +//│ = readInt { class: [class readInt extends IO] } + +(readInt : IO[Int]).bind +//│ forall 'AA. (Int -> IO['AA]) -> Bind[Int, 'AA] +//│ res +//│ = [Function: bind] + +readInt.run +//│ Int +//│ res +//│ = 42 + +x => Pure(x).run +//│ 'run -> 'run +//│ res +//│ = [Function: res] + + +fun loop0 = readInt.bind of Pure +fun loop1 = readInt.bind of (Pure : Int => IO[Int]) +fun loop2 = readInt.bind of ((x: Int) => Pure(x)) +fun loop3 = readInt.bind of (x => Pure(x) : IO[Int]) +//│ fun loop0: forall 'AA. Bind[in Int & 'AA out Int, 'AA] +//│ fun loop1: Bind[Int, Int] +//│ fun loop2: forall 'AA0. Bind[Int, 'AA0] +//│ fun loop3: Bind[Int, Int] +//│ where +//│ 'AA0 :> Int +//│ 'AA :> Int + +fun (#>>) bindOp(x, f) = x.bind(f) +//│ fun (#>>) bindOp: forall 'a 'b. ({bind: 'a -> 'b}, 'a) -> 'b + +fun loop = + readInt #>> n => + Pure(n) +//│ fun loop: forall 'AA. Bind[in Int & 'AA out Int, 'AA] +//│ where +//│ 'AA :> Int + + + +val x: Bind['A, 'B] where undefined : 'A; 'A : 'B +//│ val x: forall 'A 'B. Bind['A, 'B] +//│ where +//│ 'A :> undefined +//│ <: 'B +//│ 'B :> undefined +//│ x +//│ = + +x.run +//│ undefined +//│ res +//│ = +//│ x is not implemented + +val x: Bind['A, 'B] where 'A : undefined; 'A : 'B +//│ val x: forall 'A 'B. Bind['A, 'B] +//│ where +//│ 'A <: undefined & 'B +//│ x +//│ = + +x.run +//│ nothing +//│ res +//│ = +//│ x is not implemented + +val x: Bind[Int, Bool] +//│ val x: Bind[Int, Bool] +//│ x +//│ = + +// :d +x.run +//│ Bool +//│ res +//│ = +//│ x is not implemented + + + + diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 050589659d..e43c778756 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -30,7 +30,7 @@ class Foo(n: Int) { fun test = this.x } :e class Foo(n: A) { fun test = this.x } -//│ ╔══[ERROR] Type `#Foo & {Foo#A = ?A, n: A}` does not contain member `x` +//│ ╔══[ERROR] Type `#Foo & {Foo#A = A, n: A}` does not contain member `x` //│ ║ l.32: class Foo(n: A) { fun test = this.x } //│ ╙── ^^ //│ class Foo[A](n: A) { From 98282a9abf68b29602f1648e700fc5794c50b146 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 23 Sep 2023 10:11:58 +0800 Subject: [PATCH 456/498] Change usage of semicolons; support semicolon sequence expressions --- shared/src/main/scala/mlscript/NewLexer.scala | 4 +- .../src/main/scala/mlscript/NewParser.scala | 42 +++++++++++-------- .../src/test/diff/codegen/ConstructorStmt.mls | 2 +- shared/src/test/diff/codegen/NewMatching.mls | 4 +- .../test/diff/contys/ExplicitConstraints.mls | 6 +-- shared/src/test/diff/mlscript/Sequence.mls | 26 ++++++++++++ shared/src/test/diff/nu/AuxCtors.mls | 14 +++---- shared/src/test/diff/nu/DiamondInherit.mls | 4 +- shared/src/test/diff/nu/DidierNu.mls | 4 +- shared/src/test/diff/nu/EncodedLists.mls | 2 +- shared/src/test/diff/nu/Extrusion.mls | 8 ++-- shared/src/test/diff/nu/FlatMonads.mls | 2 +- shared/src/test/diff/nu/FlatMonads_repro.mls | 4 +- shared/src/test/diff/nu/GenericMethods.mls | 4 +- shared/src/test/diff/nu/GenericModules.mls | 4 +- .../diff/nu/InferredInheritanceTypeArgs.mls | 2 +- shared/src/test/diff/nu/Metaprog.mls | 4 +- shared/src/test/diff/nu/MethodSignatures.mls | 2 +- shared/src/test/diff/nu/Mixin42.mls | 2 +- shared/src/test/diff/nu/NuForallTerms.mls | 4 +- shared/src/test/diff/nu/Object.mls | 25 +++++------ shared/src/test/diff/nu/ParamPassing.mls | 8 ++-- .../test/diff/nu/PolymorphicVariants_Alt.mls | 2 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 8 ++-- shared/src/test/diff/nu/TODO_Classes.mls | 6 +-- .../src/test/diff/nu/ThisRefinedClasses.mls | 8 ++-- shared/src/test/diff/nu/TraitSignatures.mls | 2 +- shared/src/test/diff/nu/TypeVariables.mls | 10 ++--- shared/src/test/diff/parser/Blocks.mls | 8 ++-- shared/src/test/diff/parser/Forall.mls | 16 +++---- shared/src/test/diff/parser/IfThenElse.mls | 25 +++++++---- shared/src/test/diff/parser/Lets.mls | 6 +-- 32 files changed, 156 insertions(+), 112 deletions(-) create mode 100644 shared/src/test/diff/mlscript/Sequence.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 28086adc17..6d08e2570a 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -26,17 +26,19 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { def isDigit(c: Char): Bool = c >= '0' && c <= '9' + /* // TODO remove (unused) private val isNonStickyKeywordChar = Set( ',', ':', ';', ) + */ private val isSymKeyword = Set( // "->", "=", ":", - ";", + ";;", "#", // ".", // "<", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 7e96689e81..36cbd579fa 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -538,7 +538,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case _ => t } yeetSpaces match { - case (KEYWORD(";"), _) :: _ => consume; finalTerm :: block + case (KEYWORD(";;"), _) :: _ => consume; finalTerm :: block case (NEWLINE, _) :: _ => consume; finalTerm :: block case _ => finalTerm :: Nil } @@ -635,27 +635,33 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo exprCont(bra.withLoc(S(loc)), prec, allowNewlines = false) case (KEYWORD("forall"), l0) :: _ => consume - val as = argsMaybeIndented() + def getIdents: Ls[TypeVar] = yeetSpaces match { + case (IDENT(nme, false), l0) :: _ => + consume + val res = TypeVar(R(nme), N).withLoc(S(l0)) + yeetSpaces match { + case (COMMA, _) :: _ => + consume + res :: getIdents + case _ => res :: Nil + } + case _ => Nil + } + val idents = getIdents val rest = cur match { - case (KEYWORD(";"), l0) :: _ => + case (KEYWORD(":"), l0) :: _ => consume expr(0) case _ => - err((msg"Expected `;` after `forall` section" -> curLoc.orElse(lastLoc) :: Nil)) + err((msg"Expected `:` after `forall` section" -> curLoc.orElse(lastLoc) :: Nil)) errExpr } - R(Forall(as.flatMap { - case N -> Fld(FldFlags(false, false, _), v: Var) => - TypeVar(R(v.name), N).withLocOf(v) :: Nil - case v -> f => - err(msg"illegal `forall` quantifier body" -> f.value.toLoc :: Nil) - Nil - }, rest)) + R(Forall(idents, rest)) case (KEYWORD("let"), l0) :: _ => consume val bs = bindings(Nil) val body = yeetSpaces match { - case (KEYWORD("in") | KEYWORD(";"), _) :: _ => + case (KEYWORD("in" | ";;"), _) :: _ => consume exprOrIf(0) case (NEWLINE, _) :: _ => @@ -749,7 +755,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case Nil => err(msg"Unexpected end of $description; an expression was expected here" -> lastLoc :: Nil) R(errExpr) - case ((KEYWORD(";") /* | NEWLINE */ /* | BRACKETS(Curly, _) */, l0) :: _) => + case ((KEYWORD(";;") /* | NEWLINE */ /* | BRACKETS(Curly, _) */, l0) :: _) => R(UnitLit(true).withLoc(S(l0))) // R(errExpr) // TODO case (tk, l0) :: _ => @@ -796,6 +802,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo } case "=>" => Lam(toParams(acc), rhs) + case ";" => + Blk(acc :: rhs :: Nil) case _ => if (newDefs) App(v, PlainTup(acc, rhs)) else App(App(v, toParams(acc)), toParams(rhs)) @@ -841,7 +849,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (NEWLINE, _) :: _ if allowNewlines => consume exprCont(acc, 0, allowNewlines) - case (COMMA | NEWLINE | KEYWORD("then" | "else" | "in" | ";" | "=") + case (COMMA | NEWLINE | KEYWORD("then" | "else" | "in" | ";;" | "=") | IDENT(_, true) | BRACKETS(Curly, _), _) :: _ => R(acc) case (KEYWORD("of"), _) :: _ if prec <= 1 => @@ -919,9 +927,9 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo exprCont(res, prec, allowNewlines) case c @ (h :: _) if (h._1 match { - case KEYWORD(";" | ":" | "of" | "where" | "extends") | BRACKETS(Round | Square, _) + case KEYWORD(";;" | ":" | "of" | "where" | "extends") | BRACKETS(Round | Square, _) | BRACKETS(Indent, ( - KEYWORD(";" | "of") + KEYWORD(";;" | "of") | BRACKETS(Round | Square, _) | SELECT(_) , _) :: _) @@ -1162,7 +1170,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (SPACE, _) :: _ => consume bindings(acc) - case (NEWLINE | IDENT(_, true) | KEYWORD(";"), _) :: _ => // TODO: | ... + case (NEWLINE | IDENT(_, true) | KEYWORD(";;"), _) :: _ => // TODO: | ... acc.reverse case (IDENT(id, false), l0) :: _ => consume diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index b4ecfe328a..7a8379d262 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -280,7 +280,7 @@ log((baz.x, baz.y)) class Q() { let q = 42 fun qq = - let f = (x: Int) => {q: x + q}; f(1) + let f = (x: Int) => {q: x + q};; f(1) } //│ class Q() { //│ let q: 42 diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index 53d1897942..50d2dbc1da 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -127,7 +127,7 @@ let s2 = Some(1) :js fun foo(s) = if s is - Some(t) then let b = s2.value; b + t.x + Some(t) then let b = s2.value in b + t.x _ then 0 //│ fun foo: (Object & ~#Some | Some[{x: Int}]) -> Int //│ // Prelude @@ -148,7 +148,7 @@ foo(Some(V1(12))) fun bar(s) = if s is - Some(_) then let b = s2.value; b + 1 + Some(_) then let b = s2.value in b + 1 _ then 0 //│ fun bar: (Object & ~#Some | Some[anything]) -> Int diff --git a/shared/src/test/diff/contys/ExplicitConstraints.mls b/shared/src/test/diff/contys/ExplicitConstraints.mls index f41cbd444a..728a2f9fd0 100644 --- a/shared/src/test/diff/contys/ExplicitConstraints.mls +++ b/shared/src/test/diff/contys/ExplicitConstraints.mls @@ -74,7 +74,7 @@ fun f: 'a => 'a where :e -fun f: 'a => forall 'b; 'a where +fun f: 'a => forall 'b: 'a where 'a : 'b 'b : string int : 'a @@ -94,7 +94,7 @@ fun f: 'a => forall 'b; 'a where // * Constraint is stashed! -fun f: 'a => forall 'b; 'a where +fun f: 'a => forall 'b: 'a where 'a : 'b => 'b int : 'a //│ f: 'a -> (int | 'a @@ -150,7 +150,7 @@ r + 1 //│ res: error | int -fun f: 'a => forall 'b; 'b where +fun f: 'a => forall 'b: 'b where 'a : 'b => 'b int : 'a //│ f: 'a -> ('b diff --git a/shared/src/test/diff/mlscript/Sequence.mls b/shared/src/test/diff/mlscript/Sequence.mls new file mode 100644 index 0000000000..919c7251b1 --- /dev/null +++ b/shared/src/test/diff/mlscript/Sequence.mls @@ -0,0 +1,26 @@ +:NewDefs + + +let test(x) = log(x); x + 1 +//│ let test: Int -> Int +//│ test +//│ = [Function: test] + +test(log("here we go"); 123) +//│ Int +//│ res +//│ = 124 +//│ // Output +//│ here we go +//│ 123 + + +let a = 1;; let b = a + 1 +//│ let a: 1 +//│ let b: Int +//│ a +//│ = 1 +//│ b +//│ = 2 + + diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index 7de3b76e5d..e4b371ede4 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -19,7 +19,7 @@ C(123).x //│ res //│ = 123 -class C(val x: Int) { constructor(y: Int) { log(y); x = y; log(x) } } +class C(val x: Int) { constructor(y: Int) { log(y);; x = y;; log(x) } } C(123).x //│ class C(x: Int) { //│ constructor(y: Int) @@ -32,11 +32,11 @@ C(123).x //│ 123 :e -class C(val x: Int) { constructor(y: Int) { x = y; log(x); x = y + 1; log(x) } } +class C(val x: Int) { constructor(y: Int) { x = y;; log(x);; x = y + 1;; log(x) } } C(123).x //│ ╔══[ERROR] Class parameter 'x' was already set -//│ ║ l.35: class C(val x: Int) { constructor(y: Int) { x = y; log(x); x = y + 1; log(x) } } -//│ ╙── ^ +//│ ║ l.35: class C(val x: Int) { constructor(y: Int) { x = y;; log(x);; x = y + 1;; log(x) } } +//│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) //│ } @@ -48,9 +48,9 @@ C(123).x //│ 124 :e -class C(val x: Int) { constructor(y: Int) { log(x); x = y } } +class C(val x: Int) { constructor(y: Int) { log(x);; x = y } } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.51: class C(val x: Int) { constructor(y: Int) { log(x); x = y } } +//│ ║ l.51: class C(val x: Int) { constructor(y: Int) { log(x);; x = y } } //│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) @@ -118,7 +118,7 @@ class C(val x: Int) { constructor(2 + 2) { x = 0 } } class C(val x: Int, y: Int) { - constructor(z: Int) { x = z; y = z } + constructor(z: Int) { x = z;; y = z } log([x, y]) } //│ class C(x: Int, y: Int) { diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index 340d8431f0..a93a3e02bf 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -33,7 +33,7 @@ Bar : Foo['X] //│ = 123 -trait Foo[A] { fun foo: A; fun bar: A -> A } +trait Foo[A] { fun foo: A;; fun bar: A -> A } //│ trait Foo[A] { //│ fun bar: A -> A //│ fun foo: A @@ -131,7 +131,7 @@ module Bar extends T1, Foo[Int | Str] { //│ } -trait Base[A] { fun foo: A; fun bar: A -> A } +trait Base[A] { fun foo: A;; fun bar: A -> A } trait Derived1[A] extends Base[A] trait Derived2 extends Base[(Int | Str, Int | Str)] //│ trait Base[A] { diff --git a/shared/src/test/diff/nu/DidierNu.mls b/shared/src/test/diff/nu/DidierNu.mls index d1ad039613..5f5cf12d78 100644 --- a/shared/src/test/diff/nu/DidierNu.mls +++ b/shared/src/test/diff/nu/DidierNu.mls @@ -21,7 +21,7 @@ fun unify = x => y => z => k of z => k(z(x), y => k of z(y), y), z //│ fun unify: forall 'a. anything -> anything -> 'a -> 'a -fun a0 = (z => z) (id : forall 'A; 'A -> 'A) of 1 +fun a0 = (z => z) (id : forall 'A: 'A -> 'A) of 1 //│ fun a0: 1 fun fst([a, _]) = a @@ -29,7 +29,7 @@ fun snd([_, b]) = b //│ fun fst: forall 'a. (['a, anything]) -> 'a //│ fun snd: forall 'b. ([anything, 'b]) -> 'b -fun a1(x) = (z => unify(x)(fst of z)(snd of z))([id, (id : forall 'A; 'A -> 'A)]) of 1 +fun a1(x) = (z => unify(x)(fst of z)(snd of z))([id, (id : forall 'A: 'A -> 'A)]) of 1 //│ fun a1: anything -> 1 diff --git a/shared/src/test/diff/nu/EncodedLists.mls b/shared/src/test/diff/nu/EncodedLists.mls index 29e5d9d1c1..8d12d0a75b 100644 --- a/shared/src/test/diff/nu/EncodedLists.mls +++ b/shared/src/test/diff/nu/EncodedLists.mls @@ -3,7 +3,7 @@ class List { - fun match: forall 'res; (ifNil: () => 'res, ifCons: ('res, List[A]) => 'res) => 'res + fun match: forall 'res: (ifNil: () => 'res, ifCons: ('res, List[A]) => 'res) => 'res fun match = error // TODO use self-type... } let Nil: List diff --git a/shared/src/test/diff/nu/Extrusion.mls b/shared/src/test/diff/nu/Extrusion.mls index c566246f5d..bc5fc9af3f 100644 --- a/shared/src/test/diff/nu/Extrusion.mls +++ b/shared/src/test/diff/nu/Extrusion.mls @@ -2,7 +2,7 @@ fun f(y) = - let local = forall 'A; (x: 'A) => + let local = forall 'A: (x: 'A) => y(x) + 1 x y @@ -14,7 +14,7 @@ f(id) //│ ║ l.12: f(id) //│ ║ ^^^^^ //│ ╟── type variable `'A` leaks out of its scope -//│ ║ l.5: let local = forall 'A; (x: 'A) => +//│ ║ l.5: let local = forall 'A: (x: 'A) => //│ ║ ^^ //│ ╟── into application of type `Int` //│ ║ l.6: y(x) + 1 @@ -29,8 +29,8 @@ f(id) fun f(y) = - let local = forall 'A; (x: 'A) => - (y : forall 'a; 'a -> 'a)(x) + let local = forall 'A: (x: 'A) => + (y : forall 'a: 'a -> 'a)(x) x y //│ fun f: forall 'b. (forall 'a. 'a -> 'a & 'b) -> 'b diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index 950d067d5f..b229fe39c9 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -392,7 +392,7 @@ r.run :NoJS // * TODO We'll need to support functions extended with fields // * An interface that describes monadic functions with a field `run` -declare trait IO[A]: forall 'b; (A -> IO['b]) -> IO['b] { +declare trait IO[A]: forall 'b: (A -> IO['b]) -> IO['b] { fun run: A } declare fun pure: 'a -> IO['a] diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls index 250e3635db..31068b55aa 100644 --- a/shared/src/test/diff/nu/FlatMonads_repro.mls +++ b/shared/src/test/diff/nu/FlatMonads_repro.mls @@ -174,7 +174,7 @@ fun loop = -val x: Bind['A, 'B] where undefined : 'A; 'A : 'B +val x: Bind['A, 'B] where undefined : 'A;; 'A : 'B //│ val x: forall 'A 'B. Bind['A, 'B] //│ where //│ 'A :> undefined @@ -189,7 +189,7 @@ x.run //│ = //│ x is not implemented -val x: Bind['A, 'B] where 'A : undefined; 'A : 'B +val x: Bind['A, 'B] where 'A : undefined;; 'A : 'B //│ val x: forall 'A 'B. Bind['A, 'B] //│ where //│ 'A <: undefined & 'B diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index d06506d9c3..e91a3617d7 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -1,7 +1,7 @@ :NewDefs -fun foo1 = forall 'A; (x: 'A) => x +fun foo1 = forall 'A: (x: 'A) => x //│ fun foo1: forall 'A. (x: 'A) -> 'A foo1(42) @@ -55,7 +55,7 @@ foo3[Int](42) //│ = 42 -fun bar: forall 'A; 'A => 'A +fun bar: forall 'A: 'A => 'A //│ fun bar: forall 'A. 'A -> 'A :e diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 34c55b519e..35b9e07b61 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -7,7 +7,7 @@ module Test { fun bar: A => A = id fun baz(x: A) = x fun poly0: 'a -> 'a - fun poly1: forall 'a; 'a -> 'a + fun poly1: forall 'a: 'a -> 'a fun poly2: 'a -> 'a = id } //│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `Test` @@ -26,7 +26,7 @@ module Test { //│ ║ l.5: module Test { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.10: fun poly1: forall 'a; 'a -> 'a +//│ ║ l.10: fun poly1: forall 'a: 'a -> 'a //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ module Test[A] { //│ fun bar: A -> A diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 302248d7c0..8f834c3601 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -184,7 +184,7 @@ trait Foo[type A] { fun foo(x: A): A } //│ } -trait Foo[A] { fun a: A; fun foo(x: A): A } +trait Foo[A] { fun a: A;; fun foo(x: A): A } //│ trait Foo[A] { //│ fun a: A //│ fun foo: (x: A) -> A diff --git a/shared/src/test/diff/nu/Metaprog.mls b/shared/src/test/diff/nu/Metaprog.mls index 7d6c5f36f4..49429e55ea 100644 --- a/shared/src/test/diff/nu/Metaprog.mls +++ b/shared/src/test/diff/nu/Metaprog.mls @@ -12,7 +12,7 @@ class IntLit(value: Int) extends Code[Int, nothing] class Add[C](lhs: Code[Int, C], rhs: Code[Int, C]) extends Code[Int, C] //│ class Add[C](lhs: Code[Int, C], rhs: Code[Int, C]) extends Code -fun bind(x: Code['a, 'c], k: (forall 'cc; Code['a, 'cc] -> Code['b, 'cc])): Code['b, 'c] = k(x) +fun bind(x: Code['a, 'c], k: (forall 'cc: Code['a, 'cc] -> Code['b, 'cc])): Code['b, 'c] = k(x) //│ fun bind: forall 'a 'c 'b. (x: Code['a, 'c], k: forall 'cc. Code['a, 'cc] -> Code['b, 'cc]) -> Code['b, 'c] @@ -41,7 +41,7 @@ abstract class Test[C] { :NoJS -fun mkVar(f: forall 'C; Test['C] -> 'a): 'a +fun mkVar(f: forall 'C: Test['C] -> 'a): 'a //│ fun mkVar: forall 'a. (f: forall 'C. Test['C] -> 'a) -> 'a mkVar of t0 => diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index bf74fb1108..085d273ac0 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -86,7 +86,7 @@ module A { // * With a type signature, it is generalized and checked against the signature module A { - fun i: forall 'a; 'a -> 'a + fun i: forall 'a: 'a -> 'a fun i(x) = x fun j: 'b -> 'b diff --git a/shared/src/test/diff/nu/Mixin42.mls b/shared/src/test/diff/nu/Mixin42.mls index 4bede9b036..e5d214bb92 100644 --- a/shared/src/test/diff/nu/Mixin42.mls +++ b/shared/src/test/diff/nu/Mixin42.mls @@ -83,7 +83,7 @@ C2.test //│ = 42 -class C1() extends M1, M2 { val factor: Int; val factor = 2 } +class C1() extends M1, M2 { val factor: Int;; val factor = 2 } C1().test //│ class C1() { //│ val factor: Int diff --git a/shared/src/test/diff/nu/NuForallTerms.mls b/shared/src/test/diff/nu/NuForallTerms.mls index 33f75d4a38..00e5321e47 100644 --- a/shared/src/test/diff/nu/NuForallTerms.mls +++ b/shared/src/test/diff/nu/NuForallTerms.mls @@ -1,13 +1,13 @@ :NewDefs -forall 'a; (x: 'a) => x +forall 'a: (x: 'a) => x //│ forall 'a. (x: 'a) -> 'a //│ res //│ = [Function: res] -forall 'a; +forall 'a: (x: 'a) => x //│ forall 'a. (x: 'a) -> 'a //│ res diff --git a/shared/src/test/diff/nu/Object.mls b/shared/src/test/diff/nu/Object.mls index a27e51bd99..24a69b95ac 100644 --- a/shared/src/test/diff/nu/Object.mls +++ b/shared/src/test/diff/nu/Object.mls @@ -76,26 +76,23 @@ fun foo(x: Object) = if x is A then true else false // TODO make this a rigid type variable! // :e fun foo = forall 'a; (x: 'a) => if x is A then true else false -//│ ╔══[ERROR] Type mismatch in `case` expression: -//│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── rigid type variable of type `'a` is not an instance of type `Object` +//│ ╔══[PARSE ERROR] Expected `:` after `forall` section //│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false -//│ ║ ^^ -//│ ╟── but it flows into reference with expected type `Object` +//│ ╙── ^ +//│ ╔══[PARSE ERROR] Expected end of input; found operator instead //│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false -//│ ╙── ^ -//│ fun foo: (x: anything) -> Bool +//│ ╙── ^ +//│ fun foo: undefined :e Object //│ ╔══[ERROR] Class Object is abstract and cannot be instantiated -//│ ║ l.93: Object +//│ ║ l.90: Object //│ ╙── ^^^^^^ //│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor -//│ ║ l.93: Object +//│ ║ l.90: Object //│ ╙── ^^^^^^ //│ error //│ Code generation encountered an error: @@ -104,10 +101,10 @@ Object :e Object() //│ ╔══[ERROR] Class Object is abstract and cannot be instantiated -//│ ║ l.105: Object() +//│ ║ l.102: Object() //│ ╙── ^^^^^^ //│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor -//│ ║ l.105: Object() +//│ ║ l.102: Object() //│ ╙── ^^^^^^ //│ error //│ Code generation encountered an error: @@ -116,10 +113,10 @@ Object() :e new Object //│ ╔══[ERROR] Class Object is abstract and cannot be instantiated -//│ ║ l.117: new Object +//│ ║ l.114: new Object //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor -//│ ║ l.117: new Object +//│ ║ l.114: new Object //│ ╙── ^^^^^^^^^^ //│ error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index d4c0c0fb63..31934e26e8 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -199,7 +199,7 @@ B.x -abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } +abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } //│ abstract class Foo[A](x: A) { //│ fun i: A -> A //│ fun y: A @@ -233,14 +233,14 @@ module Bazz extends Foo(0) { //│ ║ l.230: val x: 2 //│ ║ ^^^^ //│ ╟── Originally declared here: -//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } +//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } //│ ╙── ^ //│ ╔══[ERROR] Member `i` is declared (or its declaration is inherited) but is not implemented in `Bazz` //│ ║ l.229: module Bazz extends Foo(0) { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } -//│ ╙── ^^^^^^^^^ +//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } +//│ ╙── ^^^^^^^^^ //│ module Bazz extends Foo { //│ fun i: 'A -> 'A //│ val x: 2 diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 2bbd0f1dac..9dd65ad51c 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -12,7 +12,7 @@ class List { - fun match: forall 'res; (ifNil: () => 'res, ifCons: (A, List[A]) => 'res) => 'res + fun match: forall 'res: (ifNil: () => 'res, ifCons: (A, List[A]) => 'res) => 'res fun match = error } let Nil: () => List<'a> diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index 1b89c895fb..af9bb51faa 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -388,7 +388,7 @@ class C3 extends T3[Int] -trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +trait Foo { fun foo: forall 'A: (x: 'A) -> 'A } //│ trait Foo { //│ fun foo: forall 'A. (x: 'A) -> 'A //│ } @@ -411,13 +411,13 @@ class B extends Foo { fun foo(x) = x + 1 } //│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `'A` is not an instance of type `Int` -//│ ║ l.391: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ l.391: trait Foo { fun foo: forall 'A: (x: 'A) -> 'A } //│ ║ ^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^ //│ ╟── Note: quantified type variable 'A is defined at: -//│ ║ l.391: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ l.391: trait Foo { fun foo: forall 'A: (x: 'A) -> 'A } //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } @@ -426,7 +426,7 @@ class B extends Foo { fun foo(x) = x + 1 } //│ ║ l.409: class B extends Foo { fun foo(x) = x + 1 } //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.391: trait Foo { fun foo: forall 'A; (x: 'A) -> 'A } +//│ ║ l.391: trait Foo { fun foo: forall 'A: (x: 'A) -> 'A } //│ ╙── ^^ //│ class B extends Foo { //│ constructor() diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index b48d617237..4b70ba4385 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -110,7 +110,7 @@ let y: c.A = c.x // *** GADTs *** // -class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } +class Cls[A] { fun x: A = x;; fun g: A -> Int;; fun g = g } //│ class Cls[A] { //│ constructor() //│ fun g: A -> Int @@ -130,7 +130,7 @@ fun test(a: Object) = if a is //│ ║ l.124: else error //│ ║ ^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.113: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } +//│ ║ l.113: class Cls[A] { fun x: A = x;; fun g: A -> Int;; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> (error | ??A) @@ -146,7 +146,7 @@ fun test(a: Object) = if a is //│ ║ l.140: else 0 //│ ║ ^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.113: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } +//│ ║ l.113: class Cls[A] { fun x: A = x;; fun g: A -> Int;; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> Int diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index e43c778756..839defa279 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -54,12 +54,12 @@ class Foo { // TODO // * All on one line: -class Test { this: { x: Int}; fun test = this.x } +class Test { this: { x: Int};; fun test = this.x } //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.57: class Test { this: { x: Int}; fun test = this.x } -//│ ╙── ^^ +//│ ║ l.57: class Test { this: { x: Int};; fun test = this.x } +//│ ╙── ^^ //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.57: class Test { this: { x: Int}; fun test = this.x } +//│ ║ l.57: class Test { this: { x: Int};; fun test = this.x } //│ ╙── ^ //│ class Test { //│ constructor() diff --git a/shared/src/test/diff/nu/TraitSignatures.mls b/shared/src/test/diff/nu/TraitSignatures.mls index 698cae9273..394cb400e1 100644 --- a/shared/src/test/diff/nu/TraitSignatures.mls +++ b/shared/src/test/diff/nu/TraitSignatures.mls @@ -17,7 +17,7 @@ declare trait Foo: (x: Num) => Num { //│ = [Function: res] -declare trait FooPoly: forall 'a; (x: 'a) => 'a +declare trait FooPoly: forall 'a: (x: 'a) => 'a //│ declare trait FooPoly: forall 'a. (x: 'a) -> 'a (f: FooPoly) => [f(0), f(true)] diff --git a/shared/src/test/diff/nu/TypeVariables.mls b/shared/src/test/diff/nu/TypeVariables.mls index 8a16d6b5de..47ba5aa8b4 100644 --- a/shared/src/test/diff/nu/TypeVariables.mls +++ b/shared/src/test/diff/nu/TypeVariables.mls @@ -5,19 +5,19 @@ fun x: 'a -> 'a = succ //│ fun x: Int -> Int :e -fun x: forall 'a; 'a -> 'a = succ +fun x: forall 'a: 'a -> 'a = succ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ +//│ ║ l.8: fun x: forall 'a: 'a -> 'a = succ //│ ║ ^^^^ //│ ╟── type `'a` is not an instance of type `Int` -//│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ +//│ ║ l.8: fun x: forall 'a: 'a -> 'a = succ //│ ║ ^^ //│ ╟── Note: quantified type variable 'a is defined at: -//│ ║ l.8: fun x: forall 'a; 'a -> 'a = succ +//│ ║ l.8: fun x: forall 'a: 'a -> 'a = succ //│ ╙── ^^ //│ fun x: forall 'a. 'a -> 'a -fun x: [Int -> Int,] = [id : forall 'a; 'a -> 'a,] +fun x: [Int -> Int,] = [id : forall 'a: 'a -> 'a,] //│ fun x: [Int -> Int] diff --git a/shared/src/test/diff/parser/Blocks.mls b/shared/src/test/diff/parser/Blocks.mls index 4725ff0179..1f1dd0ef69 100644 --- a/shared/src/test/diff/parser/Blocks.mls +++ b/shared/src/test/diff/parser/Blocks.mls @@ -166,8 +166,8 @@ fun foo = log(1); log(a) -//│ |log|(|1|)|#;| |log|(|a|)| -//│ Parsed: {log(1,); log(a,)} +//│ |log|(|1|)|;| |log|(|a|)| +//│ Parsed: {{log(1,); log(a,)}} constructor(){ a = 1 @@ -177,8 +177,8 @@ constructor(){ //│ Parsed: {constructor() {a = 1; a = 2}} a = 1; log(a) -//│ |a| |#=| |1|#;| |log|(|a|)| -//│ Parsed: {a = 1; log(a,)} +//│ |a| |#=| |1|;| |log|(|a|)| +//│ Parsed: {a = {1; log(a,)}} :pe f(a) = 1 diff --git a/shared/src/test/diff/parser/Forall.mls b/shared/src/test/diff/parser/Forall.mls index 9cf0e04451..539bca4919 100644 --- a/shared/src/test/diff/parser/Forall.mls +++ b/shared/src/test/diff/parser/Forall.mls @@ -1,17 +1,17 @@ -forall 'a; 'a => 'a -//│ |#forall| |'a|#;| |'a| |=>| |'a| +forall 'a: 'a => 'a +//│ |#forall| |'a|#:| |'a| |=>| |'a| //│ Parsed: {forall 'a. ('a,) => 'a} -forall 'a, 'b; ('a, 'b) => ('b, 'a) -//│ |#forall| |'a|,| |'b|#;| |(|'a|,| |'b|)| |=>| |(|'b|,| |'a|)| +forall 'a, 'b: ('a, 'b) => ('b, 'a) +//│ |#forall| |'a|,| |'b|#:| |(|'a|,| |'b|)| |=>| |(|'b|,| |'a|)| //│ Parsed: {forall 'a, 'b. ('a, 'b,) => '(' ['b, 'a,] ')'} -fun f: forall 'a; 'a => 'a -//│ |#fun| |f|#:| |#forall| |'a|#;| |'a| |=>| |'a| +fun f: forall 'a: 'a => 'a +//│ |#fun| |f|#:| |#forall| |'a|#:| |'a| |=>| |'a| //│ Parsed: {fun f: forall 'a. 'a -> 'a} -fun f: forall 'a, 'b; ('a, 'b) => ('b, 'a) -//│ |#fun| |f|#:| |#forall| |'a|,| |'b|#;| |(|'a|,| |'b|)| |=>| |(|'b|,| |'a|)| +fun f: forall 'a, 'b: ('a, 'b) => ('b, 'a) +//│ |#fun| |f|#:| |#forall| |'a|,| |'b|#:| |(|'a|,| |'b|)| |=>| |(|'b|,| |'a|)| //│ Parsed: {fun f: forall 'a 'b. ('a, 'b) -> ['b, 'a]} diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 7286adb3f3..326b5ab561 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -547,20 +547,31 @@ if true //│ ╙── ^ //│ Parsed: {'(' if (true) then undefined ')'} +:pe if true then; -//│ |#if| |true| |#then|#;| +//│ |#if| |true| |#then|;| +//│ ╔══[PARSE ERROR] Unexpected operator in expression position +//│ ║ l.551: if true then; +//│ ╙── ^ +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.551: if true then; +//│ ╙── ^ +//│ Parsed: {if (true) then undefined} + +if true then;; +//│ |#if| |true| |#then|#;;| //│ Parsed: {if (true) then undefined} :pe -if true then; else; -//│ |#if| |true| |#then|#;| |#else|#;| +if true then;; else;; +//│ |#if| |true| |#then|#;;| |#else|#;;| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.555: if true then; else; -//│ ╙── ^^^^^ +//│ ║ l.566: if true then;; else;; +//│ ╙── ^^^^^^ //│ Parsed: {if (true) then undefined; undefined} -if true then () else; -//│ |#if| |true| |#then| |(||)| |#else|#;| +if true then () else;; +//│ |#if| |true| |#then| |(||)| |#else|#;;| //│ Parsed: {if (true) then '(' [] ')' else undefined} diff --git a/shared/src/test/diff/parser/Lets.mls b/shared/src/test/diff/parser/Lets.mls index a23ddda654..61d18990f1 100644 --- a/shared/src/test/diff/parser/Lets.mls +++ b/shared/src/test/diff/parser/Lets.mls @@ -48,11 +48,11 @@ let in 123 //│ Parsed: {let = undefined} let x = 1; x + 1 -//│ |#let| |x| |#=| |1|#;| |x| |+| |1| -//│ Parsed: {let x = 1; +(x,)(1,)} +//│ |#let| |x| |#=| |1|;| |x| |+| |1| +//│ Parsed: {let x = {1; +(x,)(1,)}} let x = 1, y = 2; x + y -//│ |#let| |x| |#=| |1|,| |y| |#=| |2|#;| |x| |+| |y| +//│ |#let| |x| |#=| |1|,| |y| |#=| |2|;| |x| |+| |y| //│ ╔══[PARSE ERROR] Expected end of input; found comma instead //│ ║ l.54: let x = 1, y = 2; x + y //│ ╙── ^ From 4248d23c07397612d2ea16f74c5655aaeb9b7d81 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 23 Sep 2023 10:33:04 +0800 Subject: [PATCH 457/498] Forbid `val` and `fun` in declarations block scopes --- .../src/main/scala/mlscript/NewParser.scala | 12 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 6 + .../main/scala/mlscript/utils/Identity.scala | 2 +- .../main/scala/mlscript/utils/package.scala | 2 +- shared/src/test/diff/codegen/Nested.mls | 8 +- shared/src/test/diff/codegen/NuClasses.mls | 3 + shared/src/test/diff/codegen/NuFuns.mls | 2 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 2 +- shared/src/test/diff/gadt/Exp1.mls | 3 + shared/src/test/diff/nu/AbstractClasses.mls | 6 +- shared/src/test/diff/nu/BadBlocks.mls | 126 ++++++++++++++++++ shared/src/test/diff/nu/BadClasses.mls | 4 +- shared/src/test/diff/nu/BadSignatures.mls | 4 +- shared/src/test/diff/nu/GenericMethods.mls | 4 +- shared/src/test/diff/nu/GenericMixins.mls | 2 +- shared/src/test/diff/nu/GenericModules.mls | 6 +- shared/src/test/diff/nu/InterfaceMono.mls | 6 +- shared/src/test/diff/nu/Interfaces.mls | 10 +- shared/src/test/diff/nu/Jonathan.mls | 4 +- shared/src/test/diff/nu/LetRec.mls | 43 +++++- .../src/test/diff/nu/MemberIntersections.mls | 2 +- shared/src/test/diff/nu/MethodSignatures.mls | 4 +- shared/src/test/diff/nu/ParamImplementing.mls | 2 +- shared/src/test/diff/nu/ParamPassing.mls | 6 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 2 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 2 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 8 +- .../test/diff/nu/TrickyGenericInheritance.mls | 4 +- 28 files changed, 235 insertions(+), 50 deletions(-) create mode 100644 shared/src/test/diff/nu/BadBlocks.mls diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 36cbd579fa..1253e1e89e 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -506,7 +506,9 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo val body = expr(0) val newBody = transformBody.fold(body)(_(body)) val annotatedBody = asc.fold(newBody)(ty => Asc(newBody, ty)) - R(NuFunDef(isLetRec, v, opStr, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))))(isDecl, isVirtual, N, N, genField)) + R(NuFunDef( + isLetRec, v, opStr, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))) + )(isDecl, isVirtual, N, N, genField).withLoc(S(l0 ++ annotatedBody.toLoc))) case c => asc match { case S(ty) => @@ -514,14 +516,18 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo R(NuFunDef(isLetRec, v, opStr, tparams, R(PolyType(Nil, ps.foldRight(ty)((p, r) => Function(p.toType match { case L(diag) => raise(diag); Top // TODO better case R(tp) => tp - }, r)))))(isDecl, isVirtual, N, N, genField)) // TODO rm PolyType after FCP is merged + }, r)))))(isDecl, isVirtual, N, N, genField).withLoc(S(l0 ++ ty.toLoc))) + // TODO rm PolyType after FCP is merged case N => // TODO dedup: val (tkstr, loc) = c.headOption.fold(("end of input", lastLoc))(_.mapFirst(_.describe).mapSecond(some)) err(( msg"Expected ':' or '=' followed by a function body or signature; found ${tkstr} instead" -> loc :: Nil)) consume - R(NuFunDef(isLetRec, v, opStr, Nil, L(ps.foldRight(errExpr: Term)((i, acc) => Lam(i, acc))))(isDecl, isVirtual, N, N, genField)) + val bod = errExpr + R(NuFunDef( + isLetRec, v, opStr, Nil, L(ps.foldRight(bod: Term)((i, acc) => Lam(i, acc))) + )(isDecl, isVirtual, N, N, genField).withLoc(S(l0 ++ bod.toLoc))) } } } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index b8662000fb..c42fddbdde 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -535,6 +535,12 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // println(s"vars ${vars}") + tu.entities.foreach { + case fd: NuFunDef if fd.isLetRec.isEmpty && outer.exists(_.kind is Block) => + err(msg"Cannot use `val` or `fun` in local block; use `let` instead.", fd.toLoc) + case _ => + } + val named = mutable.Map.empty[Str, LazyTypeInfo] // * Not sure we should support declaring signature with the `ident: type` syntax diff --git a/shared/src/main/scala/mlscript/utils/Identity.scala b/shared/src/main/scala/mlscript/utils/Identity.scala index 69e87a6aa3..85dbede27d 100644 --- a/shared/src/main/scala/mlscript/utils/Identity.scala +++ b/shared/src/main/scala/mlscript/utils/Identity.scala @@ -4,7 +4,7 @@ package mlscript.utils class Identity[T <: AnyRef](val value: T) { override def equals(other: Any): Boolean = other match { - case that: Identity[_] => that.value is this.value + case that: Identity[_] => (that.value: Any) is this.value case _ => false } diff --git a/shared/src/main/scala/mlscript/utils/package.scala b/shared/src/main/scala/mlscript/utils/package.scala index 10bd120245..212f8cac8c 100644 --- a/shared/src/main/scala/mlscript/utils/package.scala +++ b/shared/src/main/scala/mlscript/utils/package.scala @@ -14,7 +14,7 @@ package object utils { implicit final class AnyOps[A](self: A) { def ===(other: A): Bool = self == other def =/=(other: A): Bool = self != other - def is(other: AnyRef): Bool = self.asInstanceOf[AnyRef] eq other + def is(other: A): Bool = self.asInstanceOf[AnyRef] eq other.asInstanceOf[AnyRef] def isnt(other: AnyRef): Bool = !(self.asInstanceOf[AnyRef] eq other) /** An alternative to === when in ScalaTest, which shadows our === */ def =:=(other: A): Bool = self == other diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index b3a935e0e3..afd2ac3ed9 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -1258,10 +1258,10 @@ I(1).J(3).a :js fun main = - fun f(x: Int): Int = if x is + let f(x: Int): Int = if x is 0 then 1 else g(x - 1) - fun g(x: Int): Int = f(x) + let g(x: Int): Int = f(x) f //│ fun main: (x: Int) -> Int //│ // Prelude @@ -1384,9 +1384,9 @@ fun mian = :js fun main(arg) = let x = arg + 1 - fun foo(y) = x + y + let foo(y) = x + y class C(u: Int) { fun z = [foo(u), bar] } - fun bar = x + let bar = x C(123) //│ fun main: Int -> C //│ // Prelude diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index f7e70bc421..a3f97c69fd 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -140,6 +140,9 @@ module M2 { fun bar(x) = x + y + this.m bar(10) } +//│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. +//│ ║ l.140: fun bar(x) = x + y + this.m +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.140: fun bar(x) = x + y + this.m //│ ╙── ^^ diff --git a/shared/src/test/diff/codegen/NuFuns.mls b/shared/src/test/diff/codegen/NuFuns.mls index 120f061347..94ea8c7053 100644 --- a/shared/src/test/diff/codegen/NuFuns.mls +++ b/shared/src/test/diff/codegen/NuFuns.mls @@ -3,7 +3,7 @@ :js fun foo = - fun bar(x) = x + 1 + let bar(x) = x + 1 bar(10) //│ fun foo: Int //│ // Prelude diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 607c8d4d21..965fa50bce 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -137,7 +137,7 @@ fun map_expr(f, v) = mixin EvalExpr { fun eval(sub, v) = - fun eta(e) = this.eval(sub, e) + let eta(e) = this.eval(sub, e) let vv = map_expr(eta, v) if vv is Var then super.eval(sub, vv) diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 6cd0cf1d6f..832217818b 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -48,6 +48,9 @@ fun f(e) = if e is Pair(l: a, r) then fun f(x: a) = x f(l) +//│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. +//│ ║ l.49: fun f(x: a) = x +//│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] type identifier not found: a //│ ║ l.49: fun f(x: a) = x //│ ╙── ^ diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index bb3876874d..6c78fa993e 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -67,7 +67,7 @@ Baz.f(1) //│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.32: fun f: Int -> Int -//│ ╙── ^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^ //│ module Baz extends Bar, Foo { //│ fun f: Int -> Int //│ } @@ -155,7 +155,7 @@ abstract class C { //│ ║ ^^^^^^^^ //│ ╟── Declared here: //│ ║ l.149: fun x : Int -//│ ╙── ^^^^^^^ +//│ ╙── ^^^^^^^^^^^ //│ abstract class C { //│ fun foo0: Int //│ fun foo1: Int @@ -173,7 +173,7 @@ abstract class C { //│ ║ ^^^^^^^^ //│ ╟── Declared here: //│ ║ l.167: val x : Int -//│ ╙── ^^^^^^^ +//│ ╙── ^^^^^^^^^^^ //│ abstract class C { //│ fun foo0: Int //│ fun foo1: Int diff --git a/shared/src/test/diff/nu/BadBlocks.mls b/shared/src/test/diff/nu/BadBlocks.mls new file mode 100644 index 0000000000..33fa9affaa --- /dev/null +++ b/shared/src/test/diff/nu/BadBlocks.mls @@ -0,0 +1,126 @@ +:NewDefs + + +:e +fun test = + fun lol = log("ok") + [lol, lol] +//│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. +//│ ║ l.6: fun lol = log("ok") +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ fun test: [undefined, undefined] + +test +//│ [undefined, undefined] +//│ res +//│ = [ undefined, undefined ] +//│ // Output +//│ ok + +:e +fun test = + fun lol = log("ok") + [] +//│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. +//│ ║ l.22: fun lol = log("ok") +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ fun test: [] + +test +//│ [] +//│ res +//│ = [] +//│ // Output +//│ ok + +fun test = + let a = 0 + a +//│ fun test: 0 + +:e +fun test = + fun a = b + fun b = 1 + a +//│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. +//│ ║ l.43: fun a = b +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. +//│ ║ l.44: fun b = 1 +//│ ╙── ^^^^^^^^^ +//│ fun test: 1 + +// TODO[init-check] reject +fun test = + let a = b + let b = 1 + a +//│ fun test: 1 + +:re +test +//│ 1 +//│ res +//│ Runtime error: +//│ ReferenceError: Cannot access 'b' before initialization + +:js +fun test = + let a() = b + let b = 1 + a() +//│ fun test: 1 +//│ // Prelude +//│ class TypingUnit8 {} +//│ const typing_unit8 = new TypingUnit8; +//│ // Query 1 +//│ globalThis.test5 = function test5() { +//│ return ((() => { +//│ let a = () => b; +//│ let b = 1; +//│ return a(); +//│ })()); +//│ }; +//│ // End of generated code + +test +//│ 1 +//│ res +//│ = 1 + + +// * OK +fun test = + class Foo(x: Int) { fun y = x + 1 } + Foo(1).y +//│ fun test: Int + +// * MAYBE OK +:ge // TODO accept? +fun test = + let r() = Foo(1).y + class Foo(x: Int) { fun y = x + 1 } + r() +//│ fun test: Int +//│ Code generation encountered an error: +//│ unresolved symbol Foo + +// * NOT OK +:ge // :e // TODO[init-check] reject +fun test = + let r = Foo(1).y + class Foo(x: Int) { fun y = x + 1 } + r +//│ fun test: Int +//│ Code generation encountered an error: +//│ unresolved symbol Foo + +:re +test +//│ Int +//│ res +//│ Runtime error: +//│ ReferenceError: test8 is not defined + + diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 79497a629b..0498d01ebe 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -127,7 +127,7 @@ class C { fun x: Int } //│ ║ ^ //│ ╟── Declared here: //│ ║ l.124: class C { fun x: Int } -//│ ╙── ^^^^^^ +//│ ╙── ^^^^^^^^^^ //│ class C { //│ constructor() //│ fun x: Int @@ -140,7 +140,7 @@ class C { val x: Int } //│ ║ ^ //│ ╟── Declared here: //│ ║ l.137: class C { val x: Int } -//│ ╙── ^^^^^^ +//│ ╙── ^^^^^^^^^^ //│ class C { //│ constructor() //│ val x: Int diff --git a/shared/src/test/diff/nu/BadSignatures.mls b/shared/src/test/diff/nu/BadSignatures.mls index c82b49ebc0..22bc0b8215 100644 --- a/shared/src/test/diff/nu/BadSignatures.mls +++ b/shared/src/test/diff/nu/BadSignatures.mls @@ -8,7 +8,7 @@ trait T { } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.7: fun x = false -//│ ╙── ^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^ //│ trait T { //│ fun x: Int //│ } @@ -95,7 +95,7 @@ mixin M { fun x : Int } //│ ║ ^ //│ ╟── Declared here: //│ ║ l.92: mixin M { fun x : Int } -//│ ╙── ^^^^^^^ +//│ ╙── ^^^^^^^^^^^ //│ mixin M() { //│ fun x: Int //│ } diff --git a/shared/src/test/diff/nu/GenericMethods.mls b/shared/src/test/diff/nu/GenericMethods.mls index e91a3617d7..a0d7466a87 100644 --- a/shared/src/test/diff/nu/GenericMethods.mls +++ b/shared/src/test/diff/nu/GenericMethods.mls @@ -107,13 +107,13 @@ module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.101: fun foo: 'A => 'A -//│ ╙── ^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.100: module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.102: fun bar: 'A -//│ ╙── ^^^^^^^ +//│ ╙── ^^^^^^^^^^^ //│ module Test { //│ fun bar: nothing //│ fun foo: forall 'A. 'A -> 'A diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index f4b64a0748..527338893c 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -170,7 +170,7 @@ class C extends Test { // it also fails with Test[Int]... //│ ╙── ^^^^ //│ ╔══[ERROR] Illegal position for this definition statement. //│ ║ l.160: fun arg = 123 -//│ ╙── ^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^ //│ class C { //│ constructor() //│ fun bar: [error | 'A, error | 'A] diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index 35b9e07b61..ae49e4872a 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -15,19 +15,19 @@ module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.6: fun foo: A => A -//│ ╙── ^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `poly0` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.5: module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.9: fun poly0: 'a -> 'a -//│ ╙── ^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `poly1` is declared (or its declaration is inherited) but is not implemented in `Test` //│ ║ l.5: module Test { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.10: fun poly1: forall 'a: 'a -> 'a -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ module Test[A] { //│ fun bar: A -> A //│ fun baz: (x: A) -> A diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index e42427a9c1..be9f30ddbd 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -45,7 +45,7 @@ class ErrC3(toString: Str -> Str) extends Showable //│ ║ ^^^^^ //│ ╟── Declared here: //│ ║ l.5: fun toString: Str -//│ ╙── ^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method toString: //│ ║ l.40: fun toString = 114 //│ ║ ^^^^^^^^^^^^^^ @@ -154,13 +154,13 @@ class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: //│ ║ l.85: let name: Str -//│ ╙── ^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `Errcity` //│ ║ l.124: class Errcity(size: Int) extends SizedStadt { //│ ║ ^^^^^^^ //│ ╟── Declared here: //│ ║ l.93: fun foo: Bool -> Int -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ class Errcity(size: Int) extends RefinedStadt, SizedStadt, Stadt { //│ fun bar: "hahaha" //│ fun foo: Bool -> Int diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 8d2abef8cf..18c37d4c68 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -365,7 +365,7 @@ class E1 extends Test { //│ ║ ^^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool -//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class E1 extends Test { //│ constructor() //│ fun bar: Bool -> Bool @@ -760,7 +760,7 @@ class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool -//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class Eh extends Bs { //│ constructor() //│ fun foo: Int -> Int @@ -919,7 +919,7 @@ trait BInt extends Base[Int] { } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.918: fun f = error -//│ ╙── ^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing //│ } @@ -1017,7 +1017,7 @@ class DerBad1 extends Base[Int, Int] //│ ║ ^^^^^^^ //│ ╟── Declared here: //│ ║ l.899: trait Base[A] { fun f: A -> A } -//│ ╙── ^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^ //│ class DerBad1 extends Base { //│ constructor() //│ fun f: 'A -> 'A @@ -1102,7 +1102,7 @@ trait Tb extends Ta[Int] { } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.1101: virtual val p = false -//│ ╙── ^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^ //│ trait Tb extends Ta { //│ val g: 'T //│ val p: false diff --git a/shared/src/test/diff/nu/Jonathan.mls b/shared/src/test/diff/nu/Jonathan.mls index c5fc46d3c4..e1dfa8f34f 100644 --- a/shared/src/test/diff/nu/Jonathan.mls +++ b/shared/src/test/diff/nu/Jonathan.mls @@ -37,7 +37,7 @@ fun f(x) = x : NonBlocking // * the `listener` callback should be non-blocking fun onMousePressed(listener) = - fun l(e) = listener(e) : NonBlocking + let l(e) = listener(e) : NonBlocking l(0).flatMap of a => l(1).flatMap of b => pure of () //│ fun onMousePressed: forall 'a. ((0 | 1) -> NonBlocking[anything, 'a]) -> Effectful[[], 'a & ~Block] @@ -70,7 +70,7 @@ module Register //│ module Register fun onMousePressed(listener) = - fun l(e: MouseEvent) = listener(e) : Effectful[(), 'e \ Block \ Register] + let l(e: MouseEvent) = listener(e) : Effectful[(), 'e \ Block \ Register] () //│ fun onMousePressed: (MouseEvent -> Effectful[[], ~Block & ~Register]) -> [] diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index d7f7adad37..e2c7a238c8 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -62,7 +62,7 @@ f() //│ Runtime error: //│ RangeError: Maximum call stack size exceeded -// TODO (for later) this should be rejected by the type checker +// :e // TODO this should be rejected by the type checker :ge :js let rec f = @@ -85,6 +85,47 @@ f //│ Runtime error: //│ ReferenceError: f3 is not defined +// :e // TODO this should be rejected by the type checker +:ge +:js +fun test = + let rec f = + f +//│ fun test: undefined +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding f + +:ge // TODO this one should actually be accepted by codegen! +fun test = + let rec f() = f() +//│ fun test: undefined +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding f + +:ge // TODO this one should actually be accepted by codegen! +fun test = + let rec lol = () => lol +//│ fun test: undefined +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding lol + +:ge // TODO this one should actually be accepted by codegen! +fun test = + let rec lol() = lol + lol +//│ fun test: forall 'lol. 'lol +//│ where +//│ 'lol :> () -> 'lol +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding lol + +let rec lol = () => lol +//│ let rec lol: forall 'lol. 'lol +//│ where +//│ 'lol :> () -> 'lol +//│ lol +//│ = [Function: lol] + :p let rec f = 1 //│ |#let| |#rec| |f| |#=| |1| diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index 1eaf1dcb92..04f116577c 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -31,7 +31,7 @@ trait S2 extends T1, S1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── The value member is defined here: //│ ║ l.6: trait T1 { fun f[A]: A -> A } -//│ ║ ^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: //│ ║ l.20: trait S1 { class f } //│ ╙── ^^^^^^^ diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 085d273ac0..347391dae0 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -19,7 +19,7 @@ module Oops { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.15: fun a : Int -//│ ╙── ^^^^^^^ +//│ ╙── ^^^^^^^^^^^ //│ module Oops { //│ fun a: Int //│ } @@ -32,7 +32,7 @@ module Oops { } //│ ╔══[ERROR] A type signature for 'a' was already given //│ ║ l.30: fun a : string -//│ ╙── ^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^ //│ module Oops { //│ fun a: string //│ } diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls index 661ba4635b..ad5ba53197 100644 --- a/shared/src/test/diff/nu/ParamImplementing.mls +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -57,7 +57,7 @@ C.x //│ ║ ^ //│ ╟── Declared here: //│ ║ l.45: trait T { fun x: Int } -//│ ╙── ^^^^^^ +//│ ╙── ^^^^^^^^^^ //│ module C extends T { //│ fun x: Int //│ } diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 31934e26e8..57cbf7b8ef 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -145,7 +145,7 @@ Bar(11).x class Bar extends Foo(1) { val x: 2 } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden //│ ║ l.145: class Bar extends Foo(1) { val x: 2 } -//│ ║ ^^^^ +//│ ║ ^^^^^^^^ //│ ╟── Originally declared here: //│ ║ l.92: class Foo(val x: Int) //│ ╙── ^ @@ -231,7 +231,7 @@ module Bazz extends Foo(0) { } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden //│ ║ l.230: val x: 2 -//│ ║ ^^^^ +//│ ║ ^^^^^^^^ //│ ╟── Originally declared here: //│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } //│ ╙── ^ @@ -240,7 +240,7 @@ module Bazz extends Foo(0) { //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } -//│ ╙── ^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^ //│ module Bazz extends Foo { //│ fun i: 'A -> 'A //│ val x: 2 diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 9dd65ad51c..2555c2e0ed 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -151,7 +151,7 @@ fun map_expr(f, v) = mixin EvalExpr { fun eval(sub, v) = - fun eta(e) = this.eval(sub, e) + let eta(e) = this.eval(sub, e) let vv = map_expr(eta, v) if vv is Var then super.eval(sub, vv) diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index a74093f24b..359e5ee3cd 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -116,7 +116,7 @@ class Impl() extends Base2, Foo //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.5: trait Foo[A] { fun x: A } -//│ ╙── ^^^^ +//│ ╙── ^^^^^^^^ //│ class Impl() extends Base2, Foo { //│ fun x: 'A //│ } diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index af9bb51faa..2792480218 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -180,7 +180,7 @@ class C2 extends T1 //│ ║ ^^ //│ ╟── Declared here: //│ ║ l.7: trait T1 { fun x: 0 | 1 } -//│ ╙── ^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^ //│ class C2 extends T1 { //│ constructor() //│ fun x: 0 | 1 @@ -198,7 +198,7 @@ class C3 extends C2 //│ ║ ^^ //│ ╟── Declared here: //│ ║ l.7: trait T1 { fun x: 0 | 1 } -//│ ╙── ^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^ //│ class C3 extends C2, T1 { //│ constructor() //│ fun x: 0 | 1 @@ -333,7 +333,7 @@ class C2 extends T1, C1 { fun x = 1 } trait T2 { val r = 1(1) } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.333: trait T2 { val r = 1(1) } -//│ ╙── ^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.333: trait T2 { val r = 1(1) } //│ ║ ^^^^ @@ -358,7 +358,7 @@ trait T3[A] { class C2 extends T3[Int] //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.356: val r = C2().x -//│ ╙── ^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^ //│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no such constructor //│ ║ l.356: val r = C2().x //│ ╙── ^^ diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index 1abcd36edc..9bfcbc05b6 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -97,7 +97,7 @@ class C2 extends T2['FigureItOut] { } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.93: val r = C2().f(false) -//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no such constructor //│ ║ l.93: val r = C2().f(false) //│ ╙── ^^ @@ -121,7 +121,7 @@ class C3 extends T3['FigureItOut] { } //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.117: val r = (C3() : T3['X]).f(false) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Class C3 cannot be instantiated as it exposes no such constructor //│ ║ l.117: val r = (C3() : T3['X]).f(false) //│ ╙── ^^ From f1bd93e671dab9371a5e648c1e8206716f2ac9bd Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 23 Sep 2023 11:01:03 +0800 Subject: [PATCH 458/498] Improve parsing of type defs and ctors --- .../src/main/scala/mlscript/NewParser.scala | 31 +++++------ .../diff/codegen/AuxiliaryConstructors.mls | 6 ++- shared/src/test/diff/gadt/ThisMatching.mls | 4 +- shared/src/test/diff/nu/AuxCtors.mls | 10 +++- shared/src/test/diff/nu/BadClassInherit.mls | 14 ++--- shared/src/test/diff/nu/BasicMixins.mls | 40 +++++++------- shared/src/test/diff/nu/MutualRec.mls | 6 ++- .../test/diff/nu/TrickyGenericInheritance.mls | 52 +++++++++++-------- shared/src/test/diff/nu/Unapply.mls | 2 +- 9 files changed, 93 insertions(+), 72 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 1253e1e89e..e536d4b651 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -315,17 +315,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (br @ BRACKETS(Round, toks), loc) :: _ => consume val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO - val body = curlyTypingUnit.entities - Constructor(Tup(as).withLoc(S(loc)), Blk(body)) + val body = curlyTypingUnit + Constructor(Tup(as).withLoc(S(loc)), Blk(body.entities).withLocOf(body)) case _ => err(msg"Expect parameter list for the constructor" -> S(l0) :: Nil) Constructor(Tup(Nil), Blk(Nil)) } - val t = R(res.withLoc(S(l0 ++ res.getLoc))) - yeetSpaces match { - case (NEWLINE, _) :: _ => consume; t :: block - case _ => t :: Nil - } + R(res.withLoc(S(l0 ++ res.getLoc))) :: block case c => val t = c match { case ModifierSet(mods, (KEYWORD(k @ ("class" | "infce" | "trait" | "mixin" | "type" | "module")), l0) :: c) => @@ -401,21 +397,20 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo expr(0) :: otherParents case _ => Nil } - val tu = curlyTypingUnit - val (ctors, body) = tu.entities.partitionMap { + val fullTu = curlyTypingUnit + val (ctors, bodyStmts) = fullTu.entities.partitionMap { case c: Constructor => L(c) case t => R(t) } - - val ctor = - if (ctors.lengthIs > 1) { - err(msg"A class may only have at most one explicit constructor" -> S(l0) :: Nil) - N - } - else ctors.headOption - + val tu = TypingUnit(bodyStmts).withLocOf(fullTu) + if (ctors.lengthIs > 1) { + err(msg"A class may have at most one explicit constructor" -> S(l0) :: Nil) + N + } + val ctor = ctors.headOption val res = - NuTypeDef(kind, tn, tparams, params, ctor, sig, ps, N, N, TypingUnit(body))(isDecl, isAbs) + NuTypeDef(kind, tn, tparams, params, ctor, sig, ps, N, N, tu)(isDecl, isAbs) + R(res.withLoc(S(l0 ++ tn.getLoc ++ res.getLoc))) R(res.withLoc(S(l0 ++ res.getLoc))) case ModifierSet(mods, (KEYWORD(kwStr @ ("fun" | "val" | "let")), l0) :: c) => // TODO support rec? diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls index 438107085f..b12ba400a2 100644 --- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -222,11 +222,11 @@ class E { constructor(x: Int) constructor(y: Int) } -//│ ╔══[PARSE ERROR] A class may only have at most one explicit constructor +//│ ╔══[PARSE ERROR] A class may have at most one explicit constructor //│ ║ l.221: class E { //│ ╙── ^^^^^ //│ class E { -//│ constructor() +//│ constructor(x: Int) //│ } :e @@ -563,6 +563,8 @@ class QQ(qq: Str) { //│ ║ ^^^^^^^ //│ ║ l.550: qq = foo //│ ║ ^^^^^^^^^^^^ +//│ ║ l.551: } +//│ ║ ^^^ //│ ╟── type `Int` is not an instance of `Str` //│ ║ l.548: constructor(foo: Int) { //│ ║ ^^^ diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index 2146952fae..aa9a52555b 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -150,7 +150,9 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ ║ l.140: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ //│ ║ l.141: Pair then 1 -//│ ╙── ^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.142: } +//│ ╙── ^ //│ ╔══[ERROR] Type error in `case` expression //│ ║ l.139: fun test = if this is //│ ║ ^^^^^^^ diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index e4b371ede4..038deb6eee 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -62,7 +62,7 @@ class C(val x: Int) { constructor(y: Int) { log(x);; x = y } } class C(val x: Int) { constructor(y: Str) { x = y } } //│ ╔══[ERROR] Type mismatch in auxiliary class constructor: //│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `Str` is not an instance of `Int` //│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } //│ ║ ^^^ @@ -167,6 +167,14 @@ new C(1, 2) //│ // Output //│ [ 1, 1 ] +:pe +class C { constructor(x: Int);; constructor(y: Int) } +//│ ╔══[PARSE ERROR] A class may have at most one explicit constructor +//│ ║ l.171: class C { constructor(x: Int);; constructor(y: Int) } +//│ ╙── ^^^^^ +//│ class C { +//│ constructor(x: Int) +//│ } diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index 82cec66949..cb696fc26e 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -166,16 +166,16 @@ class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── Originally declared here: //│ ║ l.147: trait B { class X { fun g = 1 } } -//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Intersection of class member and class members currently unsupported //│ ║ l.163: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: //│ ║ l.146: class A { class X { fun f = 1 } } -//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: //│ ║ l.147: trait B { class X { fun g = 1 } } -//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A, B { //│ constructor() //│ class X { @@ -192,10 +192,12 @@ class C extends A { //│ ║ l.188: class C extends A { //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ║ l.189: class X { fun g = 1 } -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.190: } +//│ ║ ^ //│ ╟── Originally declared here: //│ ║ l.146: class A { class X { fun f = 1 } } -//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A { //│ constructor() //│ class X { @@ -209,7 +211,7 @@ class C extends A { :e class Foo2 extends Foo2 //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.210: class Foo2 extends Foo2 +//│ ║ l.212: class Foo2 extends Foo2 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ //│ class Foo2 extends Foo2 { //│ constructor() diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index b9a39ae0e7..31de48af83 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -43,6 +43,8 @@ class Base1(val base: Int) extends BaseTest { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.39: fun test2 = [base, this.base] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.40: } +//│ ║ ^ //│ ╟── Object of type `anything` does not have field 'base' //│ ║ l.38: class Base1(val base: Int) extends BaseTest { //│ ║ ^ @@ -113,7 +115,7 @@ Base2(11).test2 // TODO class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.114: class Base2(x) extends BaseOf(x + 1), BaseTest +//│ ║ l.116: class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╙── ^ //│ class Base2(x: error) { //│ fun original: Int @@ -123,7 +125,7 @@ class Base2(x) extends BaseOf(x + 1), BaseTest :e class Base1(x: Int): BaseTest //│ ╔══[ERROR] mixin BaseTest cannot be used as a type -//│ ║ l.124: class Base1(x: Int): BaseTest +//│ ║ l.126: class Base1(x: Int): BaseTest //│ ╙── ^^^^^^^^ //│ class Base1(x: Int): BaseTest @@ -138,7 +140,7 @@ Base1 :e 1 : BaseTest //│ ╔══[ERROR] mixin BaseTest cannot be used as a type -//│ ║ l.139: 1 : BaseTest +//│ ║ l.141: 1 : BaseTest //│ ╙── ^^^^^^^^ //│ BaseTest //│ res @@ -147,7 +149,7 @@ Base1 :e error : BaseTest //│ ╔══[ERROR] mixin BaseTest cannot be used as a type -//│ ║ l.148: error : BaseTest +//│ ║ l.150: error : BaseTest //│ ╙── ^^^^^^^^ //│ BaseTest //│ res @@ -167,31 +169,31 @@ mixin Foo { :e module Base1(base: Int, misc: string) extends Foo //│ ╔══[ERROR] Module parameters are not supported -//│ ║ l.168: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.168: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'misc' -//│ ║ l.168: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.160: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.160: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.168: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.168: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.160: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.160: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ module Base1(base: Int, misc: string) { //│ fun test: forall 'a. (Int & 'a) -> [Int, 'a, nothing] @@ -200,13 +202,13 @@ module Base1(base: Int, misc: string) extends Foo :e Base1.test //│ ╔══[ERROR] Parameterized modules are not supported -//│ ║ l.201: Base1.test +//│ ║ l.203: Base1.test //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.201: Base1.test +//│ ║ l.203: Base1.test //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `(base: Int, misc: string) -> Base1` does not have field 'test' -//│ ║ l.201: Base1.test +//│ ║ l.203: Base1.test //│ ╙── ^^^^^ //│ error //│ res @@ -284,13 +286,13 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.285: WrapBase1.wrapA("ok") +//│ ║ l.287: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `Int` -//│ ║ l.285: WrapBase1.wrapA("ok") +//│ ║ l.287: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.229: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.231: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ error | [Int] //│ res diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index cd8274f755..0220f31374 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -231,7 +231,9 @@ class Test1_2 { //│ ║ l.224: class Test1_1 { //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.225: fun a = (new Test1_2).b -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.226: } +//│ ╙── ^ //│ class Test1_1 { //│ constructor() //│ fun a: error @@ -255,7 +257,7 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.254: fun c = Test2_1.a +//│ ║ l.256: fun c = Test2_1.a //│ ╙── ^^ //│ module Test2_1 { //│ fun a: 123 | error diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index 9bfcbc05b6..b63734cda5 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -156,7 +156,9 @@ class Bind[A](underlying: IO[A]) extends IO[Int] //│ ║ l.151: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ //│ ║ l.152: fun test = Bind(this) : IO[Int] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.153: } +//│ ╙── ^ //│ ╔══[ERROR] Type `Bind[?A]` does not contain member `IO#A` //│ ║ l.151: abstract class IO[A] { //│ ╙── ^ @@ -175,25 +177,27 @@ class Map[A, B](underlying: IO[A], f: A -> B) extends IO[B] { fun run: B = error } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.169: abstract class IO[A] { +//│ ║ l.171: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.170: fun map[B]: (A -> B) -> IO[B] // * Removing this works... +//│ ║ l.172: fun map[B]: (A -> B) -> IO[B] // * Removing this works... //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.171: fun map(f) = Map(this, f) +//│ ║ l.173: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.172: fun run: A -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.174: fun run: A +//│ ║ ^^^^^^^^^^^^ +//│ ║ l.175: } +//│ ╙── ^ //│ ╔══[ERROR] Type `Map[?A, ?B]` does not contain member `IO#A` -//│ ║ l.169: abstract class IO[A] { +//│ ║ l.171: abstract class IO[A] { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method map: -//│ ║ l.171: fun map(f) = Map(this, f) +//│ ║ l.173: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Map[?A, ?B]` does not have field 'IO#A' -//│ ║ l.171: fun map(f) = Map(this, f) +//│ ║ l.173: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.170: fun map[B]: (A -> B) -> IO[B] // * Removing this works... +//│ ║ l.172: fun map[B]: (A -> B) -> IO[B] // * Removing this works... //│ ╙── ^^^^^ //│ abstract class IO[A] { //│ fun map: forall 'B. (A -> 'B) -> IO['B] @@ -213,25 +217,27 @@ class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { fun run = f(underlying.run).run } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.207: abstract class IO[A] { +//│ ║ l.211: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.208: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error +//│ ║ l.212: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.209: fun bind(f) = Bind(this, f) +//│ ║ l.213: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.210: fun run: A -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.214: fun run: A +//│ ║ ^^^^^^^^^^^^ +//│ ║ l.215: } +//│ ╙── ^ //│ ╔══[ERROR] Type `Bind[?A, ?B]` does not contain member `IO#A` -//│ ║ l.207: abstract class IO[A] { +//│ ║ l.211: abstract class IO[A] { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method bind: -//│ ║ l.209: fun bind(f) = Bind(this, f) +//│ ║ l.213: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Bind[?A, ?B]` does not have field 'IO#A' -//│ ║ l.209: fun bind(f) = Bind(this, f) +//│ ║ l.213: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.208: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error +//│ ║ l.212: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error //│ ╙── ^^^^^ //│ abstract class IO[A] { //│ fun bind: forall 'B. (A -> IO['B]) -> IO['B] @@ -247,10 +253,12 @@ abstract class IO[A] { class Bind[B]() extends IO[B] } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.246: abstract class IO[A] { +//│ ║ l.252: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.247: class Bind[B]() extends IO[B] -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.253: class Bind[B]() extends IO[B] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.254: } +//│ ╙── ^ //│ abstract class IO[A] { //│ class Bind[B]() extends IO //│ } diff --git a/shared/src/test/diff/nu/Unapply.mls b/shared/src/test/diff/nu/Unapply.mls index 06066e48c2..9dcc6a93a4 100644 --- a/shared/src/test/diff/nu/Unapply.mls +++ b/shared/src/test/diff/nu/Unapply.mls @@ -99,7 +99,7 @@ fun D(x: Int) = {x} module D { fun unapply(a) = [a.x] } //│ ╔══[ERROR] Refininition of 'D' //│ ║ l.99: module D { fun unapply(a) = [a.x] } -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun D: (x: Int) -> {x: Int} //│ module D { //│ fun unapply: forall 'x. {x: 'x} -> ['x] From 941343c28058e8c2266c7ca43f5d925ecbb4be54 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 23 Sep 2023 11:08:52 +0800 Subject: [PATCH 459/498] Add test exposing a DiffTest bug --- shared/src/test/diff/codegen/Mixin.mls | 238 +----------------- shared/src/test/diff/codegen/NuReplHost.mls | 48 ++++ shared/src/test/diff/codegen/ReplHost.mls | 8 +- shared/src/test/diff/codegen/Super.mls | 3 +- shared/src/test/diff/nu/BadBlocks.mls | 52 ++++ .../src/test/scala/mlscript/DiffTests.scala | 2 +- 6 files changed, 107 insertions(+), 244 deletions(-) create mode 100644 shared/src/test/diff/codegen/NuReplHost.mls diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 94fb338661..429c72da89 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -2,7 +2,6 @@ :NewDefs :js -:ShowRepl class Add(lhs: E, rhs: E) class Lit(n: Int) //│ class Add[E](lhs: E, rhs: E) @@ -62,71 +61,8 @@ class Lit(n: Int) //│ globalThis.Add = typing_unit.Add; //│ globalThis.Lit = typing_unit.Lit; //│ // End of generated code -//│ ┌ Block at Mixin.mls:6 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ let res; -//│ │ │ class TypingUnit { -//│ │ │ #Add; -//│ │ │ #Lit; -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ get Add() { -//│ │ │ const qualifier = this; -//│ │ │ if (this.#Add === undefined) { -//│ │ │ class Add { -//│ │ │ #lhs; -//│ │ │ #rhs; -//│ │ │ constructor(lhs, rhs) { -//│ │ │ this.#lhs = lhs; -//│ │ │ this.#rhs = rhs; -//│ │ │ } -//│ │ │ static -//│ │ │ unapply(x) { -//│ │ │ return ([ -//│ │ │ x.#lhs, -//│ │ │ x.#rhs -//│ │ │ ]); -//│ │ │ } -//│ │ │ }; -//│ │ │ this.#Add = ((lhs, rhs) => Object.freeze(new Add(lhs, rhs))); -//│ │ │ this.#Add.class = Add; -//│ │ │ this.#Add.unapply = Add.unapply; -//│ │ │ } -//│ │ │ return this.#Add; -//│ │ │ } -//│ │ │ get Lit() { -//│ │ │ const qualifier = this; -//│ │ │ if (this.#Lit === undefined) { -//│ │ │ class Lit { -//│ │ │ #n; -//│ │ │ constructor(n) { -//│ │ │ this.#n = n; -//│ │ │ } -//│ │ │ static -//│ │ │ unapply(x) { -//│ │ │ return [x.#n]; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.#Lit = ((n) => Object.freeze(new Lit(n))); -//│ │ │ this.#Lit.class = Lit; -//│ │ │ this.#Lit.unapply = Lit.unapply; -//│ │ │ } -//│ │ │ return this.#Lit; -//│ │ │ } -//│ │ │ } -//│ │ │ const typing_unit = new TypingUnit; -//│ │ │ globalThis.Add = typing_unit.Add; -//│ │ │ globalThis.Lit = typing_unit.Lit; -//│ │ └── Reply -//│ │ [Function (anonymous)] { -//│ │ class: [class Lit], -//│ │ unapply: [Function: unapply] -//│ │ } -//│ └── No queries :js -:ShowRepl mixin EvalBase { fun eval(e) = if e is @@ -165,41 +101,8 @@ mixin EvalBase { //│ const typing_unit1 = new TypingUnit1; //│ globalThis.EvalBase = ((base) => typing_unit1.EvalBase(base)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:130 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ class TypingUnit1 { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ EvalBase(base) { -//│ │ │ const qualifier = this; -//│ │ │ return (class EvalBase extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const qualifier1 = this; -//│ │ │ return ((() => { -//│ │ │ let a; -//│ │ │ return (a = e, a instanceof Lit.class ? (([n]) => n)(Lit.unapply(e)) : a instanceof Add.class ? (([ -//│ │ │ l, -//│ │ │ r -//│ │ │ ]) => qualifier1.eval(l) + qualifier1.eval(r))(Add.unapply(e)) : (() => { -//│ │ │ throw new Error("non-exhaustive case expression"); -//│ │ │ })()); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ const typing_unit1 = new TypingUnit1; -//│ │ │ globalThis.EvalBase = ((base) => typing_unit1.EvalBase(base)); -//│ │ └── Reply -//│ │ [Function (anonymous)] -//│ └── No queries :js -:ShowRepl class Neg(expr: A) //│ class Neg[A](expr: A) //│ // Prelude @@ -230,44 +133,8 @@ class Neg(expr: A) //│ const typing_unit2 = new TypingUnit2; //│ globalThis.Neg = typing_unit2.Neg; //│ // End of generated code -//│ ┌ Block at Mixin.mls:203 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ class TypingUnit2 { -//│ │ │ #Neg; -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ get Neg() { -//│ │ │ const qualifier = this; -//│ │ │ if (this.#Neg === undefined) { -//│ │ │ class Neg { -//│ │ │ #expr; -//│ │ │ constructor(expr) { -//│ │ │ this.#expr = expr; -//│ │ │ } -//│ │ │ static -//│ │ │ unapply(x) { -//│ │ │ return [x.#expr]; -//│ │ │ } -//│ │ │ }; -//│ │ │ this.#Neg = ((expr) => Object.freeze(new Neg(expr))); -//│ │ │ this.#Neg.class = Neg; -//│ │ │ this.#Neg.unapply = Neg.unapply; -//│ │ │ } -//│ │ │ return this.#Neg; -//│ │ │ } -//│ │ │ } -//│ │ │ const typing_unit2 = new TypingUnit2; -//│ │ │ globalThis.Neg = typing_unit2.Neg; -//│ │ └── Reply -//│ │ [Function (anonymous)] { -//│ │ class: [class Neg], -//│ │ unapply: [Function: unapply] -//│ │ } -//│ └── No queries :js -:ShowRepl mixin EvalNeg { fun eval(e) = if e is Neg(d) then 0 - this.eval(d) @@ -300,35 +167,8 @@ mixin EvalNeg { //│ const typing_unit3 = new TypingUnit3; //│ globalThis.EvalNeg = ((base) => typing_unit3.EvalNeg(base)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:271 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ class TypingUnit3 { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ EvalNeg(base) { -//│ │ │ const qualifier = this; -//│ │ │ return (class EvalNeg extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const qualifier1 = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg.class ? (([d]) => 0 - qualifier1.eval(d))(Neg.unapply(e)) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ const typing_unit3 = new TypingUnit3; -//│ │ │ globalThis.EvalNeg = ((base) => typing_unit3.EvalNeg(base)); -//│ │ └── Reply -//│ │ [Function (anonymous)] -//│ └── No queries :js -:ShowRepl mixin EvalNegNeg { fun eval(e) = if e is Neg(Neg(d)) then this.eval(d) @@ -361,35 +201,8 @@ mixin EvalNegNeg { //│ const typing_unit4 = new TypingUnit4; //│ globalThis.EvalNegNeg = ((base) => typing_unit4.EvalNegNeg(base)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:332 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ class TypingUnit4 { -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ EvalNegNeg(base) { -//│ │ │ const qualifier = this; -//│ │ │ return (class EvalNegNeg extends base { -//│ │ │ constructor(...rest) { -//│ │ │ super(...rest); -//│ │ │ } -//│ │ │ eval(e) { -//│ │ │ const qualifier1 = this; -//│ │ │ return ((() => { -//│ │ │ return e instanceof Neg.class ? (([tmp0]) => tmp0 instanceof Neg.class ? (([d]) => qualifier1.eval(d))(Neg.unapply(tmp0)) : super.eval(e))(Neg.unapply(e)) : super.eval(e); -//│ │ │ })()); -//│ │ │ } -//│ │ │ }); -//│ │ │ } -//│ │ │ } -//│ │ │ const typing_unit4 = new TypingUnit4; -//│ │ │ globalThis.EvalNegNeg = ((base) => typing_unit4.EvalNegNeg(base)); -//│ │ └── Reply -//│ │ [Function (anonymous)] -//│ └── No queries :js -:ShowRepl module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang { //│ fun eval: 'a -> Int @@ -420,35 +233,8 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ const typing_unit5 = new TypingUnit5; //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code -//│ ┌ Block at Mixin.mls:393 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ class TypingUnit5 { -//│ │ │ #TestLang; -//│ │ │ constructor() { -//│ │ │ } -//│ │ │ get TestLang() { -//│ │ │ const qualifier = this; -//│ │ │ if (this.#TestLang === undefined) { -//│ │ │ class TestLang extends EvalNegNeg(EvalNeg(EvalBase(Object))) { -//│ │ │ constructor() { -//│ │ │ super(); -//│ │ │ } -//│ │ │ } -//│ │ │ this.#TestLang = new TestLang(); -//│ │ │ this.#TestLang.class = TestLang; -//│ │ │ } -//│ │ │ return this.#TestLang; -//│ │ │ } -//│ │ │ } -//│ │ │ const typing_unit5 = new TypingUnit5; -//│ │ │ globalThis.TestLang = typing_unit5.TestLang; -//│ │ └── Reply -//│ │ TestLang { class: [Function: TestLang] } -//│ └── No queries :js -:ShowRepl fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) @@ -469,28 +255,6 @@ TestLang.eval(mk(0)) //│ // Query 2 //│ res = TestLang.eval(mk(0)); //│ // End of generated code -//│ ┌ Block at Mixin.mls:452 -//│ ├─┬ Prelude -//│ │ ├── Code -//│ │ │ class TypingUnit6 {} -//│ │ │ const typing_unit6 = new TypingUnit6; -//│ │ └── Reply -//│ │ undefined -//│ ├─┬ Query 1/2 -//│ │ ├── Prelude: -//│ │ ├── Code: -//│ │ ├── globalThis.mk = function mk(n) { -//│ │ ├── let a; -//│ │ ├── return a = n, a === 0 ? Lit(0) : a === 1 ? Neg(mk(n)) : Add(mk(n), mk(n)); -//│ │ ├── }; -//│ │ ├── Intermediate: [Function: mk] -//│ │ └── Reply: [success] [Function: mk] -//│ └─┬ Query 2/2 -//│ ├── Prelude: -//│ ├── Code: -//│ ├── res = TestLang.eval(mk(0)); -//│ ├── Intermediate: 0 -//│ └── Reply: [success] 0 //│ res //│ = [Function: mk] @@ -620,7 +384,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.620: fun x = y +//│ ║ l.384: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error diff --git a/shared/src/test/diff/codegen/NuReplHost.mls b/shared/src/test/diff/codegen/NuReplHost.mls new file mode 100644 index 0000000000..415d453c00 --- /dev/null +++ b/shared/src/test/diff/codegen/NuReplHost.mls @@ -0,0 +1,48 @@ +:NewDefs + + +// * FIXME This should crash due to `error`, +// * but the crash is somehow swallowed and we get the result of the previous statement instead! +// * The same happens with any other side effect, like `log(...)` +// * Note: this doesn't happen if the last line is in a spearate diff-test block +:showRepl +fun foo(x) = error +let r = foo(1) +//│ fun foo: anything -> nothing +//│ let r: nothing +//│ ┌ Block at NuReplHost.mls:9 +//│ ├─┬ Prelude +//│ │ ├── Code +//│ │ │ function error() { +//│ │ │ throw new Error("an error was thrown"); +//│ │ │ } +//│ │ │ let res; +//│ │ │ class TypingUnit {} +//│ │ │ const typing_unit = new TypingUnit; +//│ │ └── Reply +//│ │ undefined +//│ ├─┬ Query 1/2 +//│ │ ├── Prelude: +//│ │ ├── Code: +//│ │ ├── globalThis.foo = function foo(x) { +//│ │ ├── return error(); +//│ │ ├── }; +//│ │ ├── Intermediate: [Function: foo] +//│ │ └── Reply: [success] [Function: foo] +//│ └─┬ Query 2/2 +//│ ├── Prelude: +//│ ├── Code: +//│ ├── globalThis.r = foo(1); +//│ └── Reply: [runtime error] Error: an error was thrown +//│ r +//│ = [Function: foo] + +:re +r +//│ nothing +//│ res +//│ Runtime error: +//│ ReferenceError: r is not defined + + + diff --git a/shared/src/test/diff/codegen/ReplHost.mls b/shared/src/test/diff/codegen/ReplHost.mls index 00687d025d..3da3fe7697 100644 --- a/shared/src/test/diff/codegen/ReplHost.mls +++ b/shared/src/test/diff/codegen/ReplHost.mls @@ -1,5 +1,5 @@ -:ShowRepl +:showRepl class Box[T]: { inner: T } method Map: (T -> 'a) -> Box['a] method Map f = Box { inner = f this.inner } @@ -37,7 +37,7 @@ box0 = Box { inner = 0 } //│ box0: Box[0] //│ = Box { inner: 0 } -:ShowRepl +:showRepl box1 = Box { inner = 1 } //│ ┌ Block at ReplHost.mls:41 //│ ├── No prelude @@ -50,7 +50,7 @@ box1 = Box { inner = 1 } //│ box1: Box[1] //│ = Box { inner: 1 } -:ShowRepl +:showRepl case box1 of { Box -> 0 } //│ ┌ Block at ReplHost.mls:54 //│ ├── No prelude @@ -66,7 +66,7 @@ case box1 of { Box -> 0 } //│ res: 0 //│ = 0 -:ShowRepl +:showRepl box1.Map (fun x -> add x 1) box1.Map (fun x -> add x 2) box1.Map (fun x -> Box { inner = x }) diff --git a/shared/src/test/diff/codegen/Super.mls b/shared/src/test/diff/codegen/Super.mls index c56042ec20..18cd9ac2a2 100644 --- a/shared/src/test/diff/codegen/Super.mls +++ b/shared/src/test/diff/codegen/Super.mls @@ -78,14 +78,13 @@ module Test0 extends Foo0, Foo1 //│ = [ 1, 0 ] -:ShowRepl :js :e mixin Foo2 { fun foo2 = super } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.85: fun foo2 = super +//│ ║ l.84: fun foo2 = super //│ ╙── ^^^^^ //│ mixin Foo2() { //│ super: 'super diff --git a/shared/src/test/diff/nu/BadBlocks.mls b/shared/src/test/diff/nu/BadBlocks.mls index 33fa9affaa..11346a5768 100644 --- a/shared/src/test/diff/nu/BadBlocks.mls +++ b/shared/src/test/diff/nu/BadBlocks.mls @@ -124,3 +124,55 @@ test //│ ReferenceError: test8 is not defined +:pe +:ge +fun test = { + fun a = 1 +} +//│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position +//│ ║ l.130: fun a = 1 +//│ ╙── ^^^ +//│ ╔══[PARSE ERROR] Unexpected '=' here +//│ ║ l.130: fun a = 1 +//│ ╙── ^ +//│ fun test: {a: () -> 1} +//│ Code generation encountered an error: +//│ unresolved symbol a + +:pe +:e +fun test = { + val res = a + 1 + fun a = 123 +}.res +//│ ╔══[PARSE ERROR] Unexpected '=' here +//│ ║ l.145: val res = a + 1 +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: res +//│ ║ l.145: val res = a + 1 +//│ ╙── ^^^ +//│ fun test: error + +:pe // TODO support +:e +fun test = (new { + val res = a + 1 + fun a = 123 +}).res +//│ ╔══[PARSE ERROR] Unexpected '=' here +//│ ║ l.159: val res = a + 1 +//│ ╙── ^ +//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword +//│ ║ l.158: fun test = (new { +//│ ║ ^ +//│ ║ l.159: val res = a + 1 +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.160: fun a = 123 +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.161: }).res +//│ ╙── ^ +//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ║ l.158: fun test = (new { +//│ ╙── ^^^ +//│ fun test: error + diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index e51791629b..28f52c358f 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -258,7 +258,7 @@ class DiffTests case "dv" => mode.copy(debugVariance = true) case "ge" => mode.copy(expectCodeGenErrors = true) case "re" => mode.copy(expectRuntimeErrors = true) - case "ShowRepl" => mode.copy(showRepl = true) + case "r" | "showRepl" => mode.copy(showRepl = true) case "escape" => mode.copy(allowEscape = true) case "exit" => out.println(exitMarker) From 4d7b6e17c449a7f37525d1b43fcfb5d5e8aac45b Mon Sep 17 00:00:00 2001 From: Andong Fan <43923564+andongfan@users.noreply.github.com> Date: Thu, 28 Sep 2023 09:51:36 +0800 Subject: [PATCH 460/498] Add codebase doc (ECOOP23 artifact version) (#7) Co-authored-by: NeilKleistGao --- doc/mls-codebase-doc.md | 377 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 doc/mls-codebase-doc.md diff --git a/doc/mls-codebase-doc.md b/doc/mls-codebase-doc.md new file mode 100644 index 0000000000..50d9bac63e --- /dev/null +++ b/doc/mls-codebase-doc.md @@ -0,0 +1,377 @@ +# Documentation of the MLscript Codebase + +This is the documentation of the MLscript codebase. + +## Overview + +This codebase of the MLscript Programming Language has all the basic components +of a static-typed programming language compiler: lexer, parser, typer, and code generator. +For testing, there is a web demo of MLscript as well as a test suite. +We now give a high-level introduction to each compiler component and its correspondence to +our Scala sources. Note that source file paths are rooted in `/shared/src/main/scala/mlscript`. + +### Lexing + +The lexer accepts source strings and returns tokens to be parsed. +The corresponding files are: + +- `NewLexer.scala` contains the lexer class. +- `Token.scala` contains the token data types. + +### Parsing + +The parser accepts tokens generated by the lexer and +returns an abstract syntax tree of the input program in the surface syntax. +The corresponding files are: + +- `NewParser.scala` contains the parser class. +- `syntax.scala` contains the **surface** syntax data types of the language. + +### Typing + +The typer accepts an abstract syntax tree of a program +and performs type checking. +MLscript's typer supports principal type inference with subtyping. +For more information about the type system, +please refer to [MLstruct](https://dl.acm.org/doi/abs/10.1145/3563304). + +The corresponding files are: +- `Typer.scala` contains the typer class. +- `TypeSimplifier.scala` contains type simplification algorithms to simplify +inferred types. +- `ucs/Desugarer.scala` contains class `ucs.Desugarer` which implements desugaring +methods. +- `TypeDefs.scala` and `NuTypeDefs.scala` contain class `TypeDef` and methods for +declarations like classes, interfaces, and type aliases. +- `ConstraitSolver.scala` contains class `ConstraintSolver` which solves subtyping +constraints. +- `NormalForms.scala` contains class `NormalForms` which provides the infrastructure +to solve tricky subtyping constraints with disjunct normal forms (DNF) on the left +and conjunct normal forms (CNF) on the right. +- `TyperDatatypes.scala` contains class `TyperDatatypes` which includes +data types to support **internal** representation of types with mutable states to support +type inference with subtyping. +- `TyperHelpers.scala` contains class `TyperHelpers` that provides helper methods +for the typer. + +Note that the inheritance relationships between these typer classes do *not* have any actual semantics +- we are following Scala's *Cake Pattern*. Typer classes will be finally composed +into the `Typer` class by inheritance. + +### Code Generation + +The code generator translates MLscript AST into JavaScript AST and generates the corresponding JavaScript code. + +The corresponding files are: + +- `codegen/Codegen.scala` contains definitions of JavaScript AST nodes + and methods for JavaScript code generation. +- `codegen/Scope.scala` contains class `Scope` which manages symbols + and provides hygienic runtime name generation. +- `codegen/Symbol.scala` contains classes `NewClassSymbol`, `MixinSymbol`, + and `ModuleSymbol` which include information on `class`, `mixin` and `module` definitions. +- `JSBackend.scala` contains class `JSBackend` that translates an MLscript AST + into a JavaScript AST. Classes `JSWebBackend` and `JSTestBackend` inherit class `JSBackend` + and generate adapted code for the web demo and the test suite. + +### Web Demo and Testing + + +Testing of MLscript works as follows: + - the MLscript compiler reads the given test file one code block at a time (code blocks are separated by empty lines); + - after reading the code block, it outputs the inferred types as well as any type errors encountered; + - after that, it executes the code block in NodeJS (by shelling out to a `node` process) and outputs the results. + +We have a web demo for users to test our implementation in any modern browser. +It has a textbox for MLscript source code input and it produces typing and running +results live. The implementation can be tried online at https://hkust-taco.github.io/superoop/ +and locally in `/js/src/main/scala/Main.scala`. + +We have a "`diff`-based" test suite for our implementation. +It detects changes to MLscript test sources (using git), +generates typing and running results, and inserts those results +into test sources. The diff-based testing implementation is in +`/shared/src/test/scala/mlscript/DiffTests.scala`. +MLscript test sources are in `/shared/src/test/diff`. + +## Detailed Introduction + +We now introduce the implementation of each compiler component +in more detail. + +### Lexing + +Class `NewLexer` in `NewLexer.scala` is the lexer class. It takes an `origin` object, +which contains the original source string together with the source file name, +the number of the first line, and some helper functions. Lazy value `tokens` generates +a list of tokens with their location in the source code. Lazy value `bracketedTokens` +converts the lexed tokens into *structured tokens*, +which use `BRACKETS` constructs instead of `OPEN_BRACKET`/`CLOSE_BRACKET` and `INDENT`/`DEINDENT`. +Token and structured token data types can be found in `Tokens.scala`. + +### Parsing + +Class `NewParser` in `NewParser.scala` is the parser class. It takes a list +of structured tokens with their location information. Method `typingUnit` +calls method `block` to parse the token list into a list of `Statement` or +`IfBody` (defined in `syntax.scala`), filters out unexpected `then/else` +clauses introduced by `Ifbody`, and returns a `TypingUnit` (a list of `Statement`). + +File `syntax.scala` contains *immutable* surface syntax data types of MLscript, +which are different from the internal representations in the typer for later type inference. +Here we introduce several surface syntax data types: + +- Classes `Decl`, `TypeDef`, `MethodDef` are deprecated. +- Class `TypeDefKind` includes type definition kinds: classes and mixins, etc. +- Class `Term` includes MLscript term data types. Case class `Bind` is no longer used. +Case class `Splc` is for the rest of a parameter list, similar to the rest parameter in JavaScript. +Case classes `Forall` and `Inst` are for first-class polymorphism. +- Class `IfBody` includes if-then-else structure data types. +- Class `CaseBranches` includes case branch data types for MLscript pattern matching. +- Class `TypeLike` includes `Type`, `Signature`, and `NuDecl`. +- Class `Type` includes MLscript type data types. Case class `Rem` is for record member removal. +Case class `WithExtension` is for record type extension. For example, `A with {x : int}` +is equivalent to `A\x & {x : int}`. +- Class `TypeVar` represents the type variable. Its identifier can be an `Int` +generated internally by the compiler or `Str` specified by the user. +- Class `NuTypeDef` is a `NuDecl` for type definitions. +Note that it has optional `superAnnot` +and `thisAnnot` for precisely-typed open recursion. +- Class `NuFunDef` is a `NuDecl` for function and let-bindings. + +### Typing + +The MLscript typer (class `Typer`) works with a typing context (class `Ctx`) which +mainly maintains all global and local bindings of names to their types. +The typer accepts a typing unit from the parser, types the typing unit, and returns a typed typing unit. +The typed typing unit +is sent to the type simplifier and is finally expanded, i.e., converted +back to types in the surface syntax for presentation. +The typer has **internal** representations of types +(defined in `TyperDatatypes.scala`) +with mutable states for type inference with subtyping. + +We first introduce several typer data types defined in `TyperDatatypes.scala`: + +- Class `TypeProvenance` stores the location where a type is introduced. +- Class `LazyTypeInfo` is for type definitions including classes, mixins, modules. +Its type is lazily computed to support *mutual recursive* type +definitions. It has a `complete` method to complete typing lazily typed definitions. +- Class `PolymorphicType` represents a type with universally quantified type variables. +By convention, in the type body, type variables of levels greater than +the polymorphic type's level are polymorphic. +- Class `SimpleType` is a general type form of all types. +It requires a method `level` for level-based polymorphism. +- Class `BaseType` includes base types such as function, array, tuple, and class tag types. +It can later be refined by `RecordType`. +- Class `RecordType` is a record type. It has a list of bindings from record fields to their types. +- Class `SpliceType` is not used for now. +- Class `ProxyType` is a derived type form to store more type provenance information. +- Class `TypeRef` is a reference to named types such as type definitions like classes. +It has a list of type arguments. A type reference with type arguments is expanded to +a class tag type with the class's type parameters refined by the corresponding type arguments as type members. +For example, `Foo[Int]` is expanded to `#Foo & {Foo.A: int..int}`. +- Class `TypeTag` has different kinds of type tags including class tags and abstract tags, etc. +- Class `FieldType` represents a term field type or a type member. +When it represents a term field type, `lb` represents if the type is mutable. +Otherwise, `lb` is the lower bound of the type member. +- Class `TypeVariable` represents a type variable, which has upper and lower bounds +for type inference with subtyping. + +Method `typeTypingUnit` in class `NuTypeDefs` accepts the typing unit to type. It inspects each statement +in the typing unit. If the statement is a type definition, a `DelayedTypeInfo` (which is a subclass of `LazyTypeInfo`) +is produced and stored in the typing context (note the typing context only uses `tyDefs2` to store +type definitions). Otherwise, it desugars the statement and calls `typeTerms` to type +the desugared statements. For a single `Term`, it is passed to `typeTerm` to type. +Method `typeTerm` in class `Typer` types a term. If the term needs type information of a `LazyTypeInfo`, +the typing of that lazily typed definition will be completed. Subtyping constraints are generated during typing +and sent to `ConstraintSolver` to propagate constraints to type variables. +For more about type inference of subtyping, please refer to [MLstruct](https://dl.acm.org/doi/abs/10.1145/3563304). + +Of particular interest, +we introduce how classes and mixins are typed to implement precisely-typed open recursion in more detail. +Method `complete` of `DelayedTypeInfoImpl`, +types type definitions: classes, modules, and mixins and let-/fun-bindings. + +When a class (`Cls` which is a `NuTypeDef`) is typed, class fields are first +added into the typing context, and `this` is associated with a fresh type variable. +The `inherit` helper methods deal with the inheritance clauses of the type definitions. +The inheritance process starts with an empty record type as the initial `super` type. +It inspects each parent, accumulates members of parents, and updates the `super` type on the way. +For each parent, +if it is a mixin, and the typing context has that mixin defined, it completes the type of the mixin +and freshens each type variable of the mixin, as each mixin's type should be constrained +differently at different use-sites. Then, two subtyping constraints are generated: +the current `super` type and the final +object type (`this` type) should be subtypes of the mixin's `super` and `this` type refinements. +Finally, the mixin's members are accumulated to the class, and the current `super` type is +updated using `WithType` because methods in mixins are always *overriding*. +After processing the whole inheritance clause, +we update the current `super` type with the class fields' types as `thisType`, and we constrain that +the resulting `thisType` (i.e. the final object type) should be a subtype of `finalType` +which is a type variable with all `this` type refinements of mixins accumulated. + +Typing of mixins is not that surprising. We associate `this` and `super` +with fresh type variables in the typing context and then type the mixin body. + +### Code Generation + +The code generation consists of three steps. +Firstly, class `JSBackend` translates MLscript data types (i.e. class `NuTypeDef`) +into corresponding symbols. Then class `JSBackend` generates JavaScript AST nodes +based on those symbols. +Finally, we generate JavaScript code from JavaScript AST nodes. + +The first step is implemented in the method `declareNewTypeDefs`. +Here we extract information (including name, parameter list, type, members, parents, and so on) +of classes, mixins, and modules from the given `NuTypeDef` list and generate +a hygienic runtime name for each symbol. + +In the second step, we translate `NewClassSymbol`, `MixinSymbol`, and `ModuleSymbol` +into JavaScript AST nodes by using methods `translateNewClassDeclaration`, `translateMixinDeclaration`, and `translateModuleDeclaration`. +These three methods invoke another method `translateNewTypeDefinition` to translate +classes, mixins, and modules into JavaScript classes. +The method `translateNewClassMember` contains the translation of members. +We call `translateParents` to get the parent class of a type. +Assuming we have code: +```ts +module A extends B, C +``` + +The method `translateParents` processes the inheritance clause in a left-to-right way: + +- First, we process the parent `B`: + - If `B` is a `class` or a `module`, the JS class definition would be `class A extends B`. + - If `B` is a `mixin`, we need a base class for `B`. + Here we choose `Object` in JavaScript and the JS class definition would be `class A extends B(Object)` +- Then we process the parent `C`: + - If `C` is a `mixin`, we can use `B(Object)` as `C`'s base class. + The JS class definition would be `class A extends C(B(Object))`. + - Otherwise, we reject the code because a JavaScript class can have only one parent class. + - If module `A` has more parents on the right of `C`, + we process them similarly as we deal with `C`. + +If there are initialization parameters in the parent list, +we move the arguments into the class constructor and pass them to `super()`. +Note we need to reverse the order of arguments of `mixin`. +For example, assume we have MLscript code below: + +```ts +module A extends MixinA(1), MixinB(2, 3), MixinC(4) +``` + +The parameters in `super()` of `A` would be: +```js +super(4, 2, 3, 1); +``` + +We generate the JavaScript classes inside `typing_unit` objects. +Note we create `...rest` parameters in each constructor of `mixin` +because we have no information about the actual parent mixin until the mixin composition is finished. +For modules, we store the instance of the JavaScript class in the cache. +For classes, if they have primitive parameter lists, +we store the arrow functions in the cache as class constructors that instantiate classes. +Mixins have no constructor because of the uncertainty of the `base` parameter of mixins. + +In the final step, we emit the JavaScript code by using `toSourceCode` methods in each JavaScript AST node class. + +For a class in MLscript: +```ts +class Lit(n: int) +``` + +The generated code would be: +```js +class TypingUnit { + #Lit; + constructor() { + } + get Lit() { + const qualifier = this; + if (this.#Lit === undefined) { + class Lit { + #n; + constructor(n) { + this.#n = n; + } + static + unapply(x) { + return [x.#n]; + } + }; + this.#Lit = ((n) => Object.freeze(new Lit(n))); + this.#Lit.class = Lit; + this.#Lit.unapply = Lit.unapply; + } + return this.#Lit; + } +} +const typing_unit = new TypingUnit; +globalThis.Lit = typing_unit.Lit; +``` + +For a mixin in MLscript: +```ts +mixin EvalBase { + fun eval(e) = + if e is + Lit(n) then n: int +} +``` + +The generated code would be: +```js +class TypingUnit { + constructor() { + } + EvalBase(base) { + const qualifier = this; + return (class EvalBase extends base { + constructor(...rest) { + super(...rest); + } + eval(e) { + return ((() => { + let a; + return (a = e, a instanceof Lit.class ? (([n]) => n)(Lit.unapply(e)) : (() => { + throw new Error("non-exhaustive case expression"); + })()); + })()); + } + }); + } +} +const typing_unit = new TypingUnit; +globalThis.EvalBase = ((base) => typing_unit.EvalBase(base)); +``` + +For a module in MLscript: +```ts +module TestLang extends EvalBase, EvalNeg, EvalNegNeg +``` + +The generated code would be like this: +```js +class TypingUnit { + #TestLang; + constructor() { + } + get TestLang() { + const qualifier = this; + if (this.#TestLang === undefined) { + class TestLang extends EvalNegNeg(EvalNeg(EvalBase(Object))) { + constructor() { + super(); + } + } + this.#TestLang = new TestLang(); + this.#TestLang.class = TestLang; + } + return this.#TestLang; + } +} +const typing_unit = new TypingUnit; +globalThis.TestLang = typing_unit.TestLang; +``` + +For more code generation examples, please check the test source `shared/src/test/diff/codegen/Mixin.mls`. From 08dee51c43cef05a2161694c0c3d319c7eaa0756 Mon Sep 17 00:00:00 2001 From: mbroughani81 <80684692+mbroughani81@users.noreply.github.com> Date: Fri, 29 Sep 2023 16:19:25 +0800 Subject: [PATCH 461/498] Named args (#174) Co-authored-by: Lionel Parreaux --- .vscode/settings.json | 3 +- shared/src/main/scala/mlscript/Typer.scala | 107 ++++++ shared/src/test/diff/nu/NamedArgs.mls | 428 +++++++++++++++++++-- 3 files changed, 499 insertions(+), 39 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ed59a9aa71..90f3019795 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,6 @@ "other": "off", "strings": "off" } - } + }, + "files.autoSave": "off" } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3c4b9e60bd..0558bc35d0 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1021,6 +1021,42 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val desug = If(IfThen(lhs, rhs), S(Var("false"))) term.desugaredTerm = S(desug) typeTerm(desug) + case App(f: Term, a @ Tup(fields)) if (fields.exists(x => x._1.isDefined)) => + def getLowerBoundFunctionType(t: SimpleType): List[FunctionType] = t.unwrapProvs match { + case PolymorphicType(_, AliasOf(fun_ty @ FunctionType(_, _))) => + List(fun_ty) + case tt @ FunctionType(_, _) => + List(tt) + case tv: TypeVariable => + tv.lowerBounds.map(getLowerBoundFunctionType(_)).flatten + case ct @ ComposedType(pol, lhs, rhs) => + if (pol === false) { + getLowerBoundFunctionType(lhs) ++ getLowerBoundFunctionType(rhs) + } else + Nil + case _ => + Nil + } + val f_ty = typeTerm(f) + val fun_tys: List[FunctionType] = getLowerBoundFunctionType(f_ty) + + fun_tys match { + case FunctionType(TupleType(fields), _) :: Nil => + val hasUntypedArg = fields.exists(_._1.isEmpty) + if (hasUntypedArg) { + err("Cannot use named arguments as the function type has untyped arguments", a.toLoc) + } else { + val argsList = fields.map(x => x._1 match { + case Some(arg) => arg + case N => die // cannot happen, because already checked with the hasUntypedArg + }) + desugarNamedArgs(term, f, a, argsList, f_ty) + } + case _ :: _ :: _ => + err(msg"More than one function signature found in type `${f_ty.expPos}` for function call with named arguments", f.toLoc) + case Nil | _ :: Nil => + err(msg"Cannot retrieve appropriate function signature from type `${f_ty.expPos}` for applying named arguments", f.toLoc) + } case App(f, a) => val f_ty = typeMonomorphicTerm(f) // * ^ Note: typing the function monomorphically simplifies type inference but @@ -1555,6 +1591,77 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne } else TupleType(fields.reverseIterator.mapValues(_.toUpper(noProv)))(prov) } + def getNewVarName(prefix: Str, nonValidVars: Set[Var]): Str = { + // we check all possibe prefix_num combination, till we find one that is not in the nonValidVars + val ints = LazyList.from(1) + prefix + "_" + ints.find(index => { + !nonValidVars.contains(Var(prefix + "_" + index)) + }).getOrElse(die) + } + + def desugarNamedArgs(term: Term, f: Term, a: Tup, argsList: List[Var], f_ty: ST) + (implicit ctx: Ctx, raise: Raise, vars: Map[Str, SimpleType]): SimpleType = { + def rec (as: List[(String -> Fld) -> Boolean], acc: Map[String, Either[Var, Term]]): Term = { + as match { + case ((v, fld), isNamed) :: tail => + if (isNamed) { + fld.value match { + case _: Lit | _: Var => + rec(tail, acc + (v -> R(fld.value))) + case _ => + val newVar = Var(getNewVarName(v, a.freeVars)) + Let(false, newVar, fld.value, rec(tail, acc + (v -> L(newVar)))) + } + } else { + rec(tail, acc + (v -> R(fld.value))) + } + case Nil => + val y: Term = Tup(argsList.map(x => + acc.get(x.name) match { + case Some(Left(v)) => (None, Fld(FldFlags.empty, v)) + case Some(Right(t)) => (None, Fld(FldFlags.empty, t)) + case None => + err(msg"Argument named '${x.name}' is missing from this function call", a.toLoc) + (None, Fld(FldFlags.empty, Var("error"))) + } + )) + App(f, y) + } + } + val hasDefined = a.fields.exists(x => x._1.isDefined) + val hasEmpty = a.fields.exists(x => x._1.isEmpty) + val areArgsMisplaced = a.fields.indexWhere(x => x._1.isDefined) < a.fields.lastIndexWhere(x => x._1.isEmpty) + if (hasDefined && + hasEmpty && + areArgsMisplaced) { + err(msg"Unnamed arguments should appear first when using named arguments", a.toLoc) + } else + a.fields.sizeCompare(argsList) match { + case 0 => + val as = a.fields.zipWithIndex.map{ + case(x, idx) => + x._1 match { + case Some(value) => + ((value.name, x._2), true) + case N => + ((argsList(idx).name, x._2), false) + }} + val asGroupedByVarName = as.groupBy(x => x._1._1) + if (asGroupedByVarName.sizeCompare(argsList) < 0) { + asGroupedByVarName.foreach(x => + x._2 match { + case x1 :: y1 :: xs => err(msg"Argument for parameter '${x._1}' is duplicated", a.toLoc) + case _ => + }) + } + val desugared = rec(as, Map()) + println("Desugared is here => " + desugared) + term.desugaredTerm = S(desugared) + typeTerm(desugared)(ctx = ctx, raise = raise, vars = vars, genLambdas = false) + case _ => + err(msg"Number of arguments doesn't match function signature `${f_ty.expPos}`", a.toLoc) + } + } /** Convert an inferred SimpleType into the immutable Type representation. */ def expandType(st: TypeLike, stopAtTyVars: Bool = false)(implicit ctx: Ctx): mlscript.TypeLike = { diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index 8e5d9e4328..0d9aa5267c 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -1,7 +1,6 @@ :NewDefs - fun test(x: 'a) = if x is undefined then 0 else x + 1 //│ fun test: (x: Int | undefined) -> Int @@ -10,70 +9,423 @@ test(x: 0) //│ res //│ = 1 +:e +test(x: 0, 1) +//│ ╔══[ERROR] Unnamed arguments should appear first when using named arguments +//│ ║ l.13: test(x: 0, 1) +//│ ╙── ^^^^^^^^^ +//│ error +//│ res +//│ = 1 + :e test(y: 0) -//│ ╔══[ERROR] Wrong tuple field name: found 'y' instead of 'x' -//│ ║ l.14: test(y: 0) +//│ ╔══[ERROR] Argument named 'x' is missing from this function call +//│ ║ l.22: test(y: 0) //│ ╙── ^^^^^^ -//│ Int | error +//│ Int //│ res -//│ = 1 +//│ Runtime error: +//│ Error: an error was thrown -fun test(x) = x + 1 -//│ fun test: Int -> Int +fun test(x: 'a, y: 'b) = [x, y] +//│ fun test: forall 'a 'b. (x: 'a, y: 'b) -> ['a, 'b] + +:e +test(x: 1, 2) +//│ ╔══[ERROR] Unnamed arguments should appear first when using named arguments +//│ ║ l.36: test(x: 1, 2) +//│ ╙── ^^^^^^^^^ +//│ error +//│ res +//│ = [ 1, 2 ] + +:e +test(x: 1, z: 3) +//│ ╔══[ERROR] Argument named 'y' is missing from this function call +//│ ║ l.45: test(x: 1, z: 3) +//│ ╙── ^^^^^^^^^^^^ +//│ [1, nothing] +//│ res +//│ Runtime error: +//│ Error: an error was thrown -// :e // TODO should be an error +:e test(y: 0) +//│ ╔══[ERROR] Number of arguments doesn't match function signature `forall 'a 'b. (x: 'a, y: 'b) -> ['a, 'b]` +//│ ║ l.55: test(y: 0) +//│ ╙── ^^^^^^ +//│ error +//│ res +//│ = [ 0, undefined ] + +:e +test(1, x: 0) +//│ ╔══[ERROR] Argument for parameter 'x' is duplicated +//│ ║ l.64: test(1, x: 0) +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Argument named 'y' is missing from this function call +//│ ║ l.64: test(1, x: 0) +//│ ╙── ^^^^^^^^^ +//│ [0, nothing] +//│ res +//│ Runtime error: +//│ Error: an error was thrown + +// * Notice no let binding is generated for the first argument +:js +test(0, y: 1) +//│ [0, 1] +//│ // Prelude +//│ class TypingUnit9 {} +//│ const typing_unit9 = new TypingUnit9; +//│ // Query 1 +//│ res = test1(0, 1); +//│ // End of generated code +//│ res +//│ = [ 0, 1 ] + +id(test)(0, y: 1) +//│ [0, 1] +//│ res +//│ = [ 0, 1 ] + +id(if true then test else error)(0, y: 1) +//│ [0, 1] +//│ res +//│ = [ 0, 1 ] + +:e +id(if true then test else id)(0, y: 1) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.100: id(if true then test else id)(0, y: 1) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ error +//│ res +//│ = [ 0, 1 ] + +// * No let binding in that value of argument is a var or literal +:js +let tmp = 2 +test(0, y: tmp) +test(0, y: 200) +//│ let tmp: 2 +//│ [0, 200] +//│ // Prelude +//│ class TypingUnit13 {} +//│ const typing_unit13 = new TypingUnit13; +//│ // Query 1 +//│ globalThis.tmp = 2; +//│ // Query 2 +//│ res = test1(0, tmp); +//│ // Query 3 +//│ res = test1(0, 200); +//│ // End of generated code +//│ tmp +//│ = 2 +//│ res +//│ = [ 0, 2 ] +//│ res +//│ = [ 0, 200 ] + + +:js +test(0, y: 1 + 2) +//│ [0, Int] +//│ // Prelude +//│ class TypingUnit14 {} +//│ const typing_unit14 = new TypingUnit14; +//│ // Query 1 +//│ res = ((y_1) => test1(0, y_1))(1 + 2); +//│ // End of generated code +//│ res +//│ = [ 0, 3 ] + + + +fun fff(x: Int, y: Int, z: Int) = (x - y) * z +//│ fun fff: (x: Int, y: Int, z: Int) -> Int + +// * Testing renaming +:e +fff(y: 2, z: y_1 + 1, x: z_1 - 2) +//│ ╔══[ERROR] identifier not found: y_1 +//│ ║ l.152: fff(y: 2, z: y_1 + 1, x: z_1 - 2) +//│ ╙── ^^^ +//│ ╔══[ERROR] identifier not found: z_1 +//│ ║ l.152: fff(y: 2, z: y_1 + 1, x: z_1 - 2) +//│ ╙── ^^^ +//│ Int +//│ Code generation encountered an error: +//│ unresolved symbol z_1 + +:js +let y_1 = 2 +let z_1 = 3 +fff(y: 2, z: y_1 + 1, x: z_1 - 2) +//│ let y_1: 2 +//│ let z_1: 3 +//│ Int +//│ // Prelude +//│ class TypingUnit17 {} +//│ const typing_unit17 = new TypingUnit17; +//│ // Query 1 +//│ globalThis["y_1"] = 2; +//│ // Query 2 +//│ globalThis["z_1"] = 3; +//│ // Query 3 +//│ res = ((z_2) => ((x_1) => fff(x_1, 2, z_2))(z_1 - 2))(y_1 + 1); +//│ // End of generated code +//│ y_1 +//│ = 2 +//│ z_1 +//│ = 3 +//│ res +//│ = -3 + + +class A() { + fun ma(x: Int, y: Int) = x - y + fun mma(x: Int, y: Int) = y - x +} +//│ class A() { +//│ fun ma: (x: Int, y: Int) -> Int +//│ fun mma: (x: Int, y: Int) -> Int +//│ } + +let x = A() +x.ma(y: 2, x: 1) +//│ let x: A +//│ Int +//│ x +//│ = A {} +//│ res +//│ = -1 + +A().ma(x: 1, y: 2) //│ Int //│ res +//│ = -1 + +id(x).ma(y: 2, x: 1) +//│ Int +//│ res +//│ = -1 + + +fun print(x: Int) = (y: Int, z: Int) => log([x, y, z]) +let p = print(0) +//│ fun print: (x: Int) -> (y: Int, z: Int) -> undefined +//│ let p: (y: Int, z: Int) -> undefined +//│ p +//│ = [Function: print] + +p(z: 1, y: 2) +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ [ 0, 2, 1 ] + +:e +fun print(x) = (y, z) => log([x, y, z]) +let p = print(0) +p(z: 1, y: 2) +//│ ╔══[ERROR] Cannot use named arguments as the function type has untyped arguments +//│ ║ l.234: p(z: 1, y: 2) +//│ ╙── ^^^^^^^^^^^^ +//│ fun print: anything -> (anything, anything) -> undefined +//│ let p: (anything, anything) -> undefined +//│ error +//│ p +//│ = [Function: print1] +//│ res +//│ = [Function (anonymous)] + + +class Baz() { + fun f(x: Int, y: Int) = log([x, y]) +} +Baz().f(y: 1, x: 2) +//│ class Baz() { +//│ fun f: (x: Int, y: Int) -> undefined +//│ } +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ [ 2, 1 ] + +let b = Baz() +b.f(y: 1, x: 2) +//│ let b: Baz +//│ undefined +//│ b +//│ = Baz {} +//│ res +//│ = undefined +//│ // Output +//│ [ 2, 1 ] + + +class A(val x: Int, val y: Int) +//│ class A(x: Int, y: Int) + +let z = A(y: 2, x: 1) +z.x +z.y +//│ let z: A +//│ Int +//│ z +//│ = A {} +//│ res //│ = 1 +//│ res +//│ = 2 + +:e +(f => f(x: a)) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.288: (f => f(x: a)) +//│ ╙── ^ +//│ anything -> error +//│ Code generation encountered an error: +//│ unresolved symbol a + +:e +(f => f)(error)(x: a) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.297: (f => f)(error)(x: a) +//│ ╙── ^^^^^^^^^^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol a + +:e +(f => f)(42)(x: a) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.306: (f => f)(42)(x: a) +//│ ╙── ^^^^^^^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol a +:e +(f => f)(if true then 123 else false)(x: a) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.315: (f => f)(if true then 123 else false)(x: a) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol a +(f => f)(if true then (x: Int) => x + 1 else error)(x: 123) +//│ Int +//│ res +//│ = 124 -class Foo(x: Int) -//│ class Foo(x: Int) +:e +(f => if true then f else id)(if true then (x: Int) => x + 1 else id)(x: 123) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.329: (f => if true then f else id)(if true then (x: Int) => x + 1 else id)(x: 123) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ error +//│ res +//│ = 124 -Foo(1) -//│ Foo +:e +(f => if true then f else id)(if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.338: (f => if true then f else id)(if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ error //│ res -//│ = Foo {} +//│ = 124 + -Foo(x: 1) -//│ Foo +fun foo(f: (x: Int) => Int) = f(x: 123) +//│ fun foo: (f: (x: Int) -> Int) -> Int + +fun foo(f: ((x: Int) => Int) & 'a) = [f(x: 123), f] +//│ fun foo: forall 'a 'b. (f: (x: Int) -> Int & 123 -> 'b & 'a) -> ['b, (x: Int) -> Int & 'a] + +foo((x: Int) => 1) +//│ [1, (x: Int) -> 1] //│ res -//│ = Foo {} +//│ = [ 1, [Function (anonymous)] ] + + +:e +fun foo(f: ((x: Int) => Int) | 'a) = f(x: 123) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `'a | (x: Int) -> Int` for applying named arguments +//│ ║ l.360: fun foo(f: ((x: Int) => Int) | 'a) = f(x: 123) +//│ ╙── ^ +//│ fun foo: (f: anything) -> error + -// :e // TODO should be an error -Foo(y: 1) -//│ Foo +// * the result of the if-then-else is a TV with two LBs: the type of x and the function type +:e +fun foo(x) = (if true then (x: Int) => x + 1 else x)(x: 123) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `(x: Int) -> ?a | ?b` for applying named arguments +//│ ║ l.369: fun foo(x) = (if true then (x: Int) => x + 1 else x)(x: 123) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ fun foo: anything -> error + +foo((y: Int) => y) +//│ error //│ res -//│ = Foo {} +//│ = 124 + +:e // TODO later: this could be made to work... +fun foo(x) = (if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `(x: Int) -> (?a | ?b)` for applying named arguments +//│ ║ l.382: fun foo(x) = (if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ fun foo: anything -> error -:e // TODO: Here `x` is not currently treated as a field name -class Bar(x) -//│ ╔══[ERROR] Class parameters currently need type annotations -//│ ║ l.55: class Bar(x) -//│ ╙── ^ -//│ class Bar(x: error) -Bar(1) -//│ Bar +fun foo(x) = if true then (x: Int) => x + 1 else x +//│ fun foo: forall 'a. 'a -> ((x: Int) -> Int | 'a) + +:e +foo((y: Int) => y)(x: 123) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.393: foo((y: Int) => y)(x: 123) +//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ error //│ res -//│ = Bar {} +//│ = 124 -Bar(x: 1) -//│ Bar +:e +foo((x: Int) => x - 1)(x: 123) +//│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments +//│ ║ l.402: foo((x: Int) => x - 1)(x: 123) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ +//│ error //│ res -//│ = Bar {} +//│ = 124 + + +fun foo1(x) = [x + 1, x] +//│ fun foo1: forall 'a. (Int & 'a) -> [Int, 'a] :e -Bar(y: 1) -//│ ╔══[ERROR] Wrong tuple field name: found 'y' instead of 'x' -//│ ║ l.72: Bar(y: 1) -//│ ╙── ^^^^^^ -//│ Bar | error +foo1(x: 123) +//│ ╔══[ERROR] Cannot use named arguments as the function type has untyped arguments +//│ ║ l.415: foo1(x: 123) +//│ ╙── ^^^^^^^^ +//│ error +//│ res +//│ = [ 124, 123 ] + + +fun foo1(x: Int & 'a) = [x + 1, x] +//│ fun foo1: forall 'a. (x: Int & 'a) -> [Int, Int & 'a] + +foo1(x: 123) +//│ [Int, 123] //│ res -//│ = Bar {} +//│ = [ 124, 123 ] From b4d0551b43dce0df2f865c23b7b28a06969dde30 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 29 Sep 2023 18:57:36 +0800 Subject: [PATCH 462/498] Fix misuse of obsolete instanceType parameter The instanceType parameter should eventually be removed --- .../src/main/scala/mlscript/NuTypeDefs.scala | 9 ++- .../main/scala/mlscript/TypeSimplifier.scala | 2 +- .../main/scala/mlscript/TyperHelpers.scala | 6 +- .../src/test/diff/ecoop23/SimpleRegionDSL.mls | 2 +- shared/src/test/diff/nu/MissingTypeArg.mls | 6 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 2 +- .../test/diff/nu/PostHocMixinSignature.mls | 73 +++++++++++++++++++ 7 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 shared/src/test/diff/nu/PostHocMixinSignature.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index c42fddbdde..bee7242715 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -222,7 +222,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sign: ST, inheritedTags: Set[TypeName], parentTP: Map[Str, NuMember] - )(val instanceType: ST, // * only meant to be used in `force` and `variances` + )(val instanceType: ST, // * only meant to be used in `variances` + // * TODO remove `instanceType` and implement proper variance analysis instead ) extends TypedNuTypeDef(Cls) with PolyNuDecl { def decl: NuTypeDef = td @@ -317,7 +318,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, - )(f(pol, instanceType)) + )(/* f(pol, instanceType) */TopType) // TODO remove instanceType def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuCls = TypedNuCls(level, td, @@ -329,10 +330,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap, - )(f(pol, instanceType)) + )(/* f(pol, instanceType) */TopType) // TODO remove instanceType override def toString: Str = s"TypedNuCls($level, ${td.nme},\n\t$tparams,\n\t$params,\n\tthis: $thisTy, ${ - members.lnIndent()},\n\t: $sign, $inheritedTags, $parentTP)" + members.lnIndent()},\n\t: $sign, $inheritedTags, $parentTP)($instanceType)" } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index c4968cdf5c..37938771cb 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -763,7 +763,7 @@ trait TypeSimplifier { self: Typer => // * Note: a more precise version could be the following, // * but it doesn't seem to change anything in our test suite, so I left if commented for now: // // * Only consider recursive those variables that recursive in their *reachable* bounds: - // occNums.contains(true -> v) && v.isPosRecursive_$ || occNums.contains(false -> v) && v.isNegRecursive_$ + // occNums.contains(true -> v) && v.isPosRecursive_$(false) || occNums.contains(false -> v) && v.isNegRecursive_$(false) )).toSet var recVars = computeRecVars diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 03286e9624..8f3d0db44c 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -834,7 +834,7 @@ abstract class TyperHelpers { Typer: Typer => cls.members.valuesIterator.flatMap(childrenPolMem) ++ S(pol.contravar -> cls.thisTy) ++ S(pol.covar -> cls.sign) ++ - S(pol.covar -> cls.instanceType) ++ + // S(pol.covar -> cls.instanceType) ++ // Not a real child; to remove cls.parentTP.valuesIterator.flatMap(childrenPolMem) case trt: TypedNuTrt => trt.tparams.iterator.map(pol.invar -> _._2) ++ @@ -966,8 +966,8 @@ abstract class TyperHelpers { Typer: Typer => cls.auxCtorParams.toList.flatMap(_.values) ++ cls.members.valuesIterator.flatMap(childrenMem) ++ S(cls.thisTy) ++ - S(cls.sign) ++ - S(cls.instanceType) + S(cls.sign) /* ++ + S(cls.instanceType) // Not a real child; to remove */ case trt: TypedNuTrt => trt.tparams.iterator.map(_._2) ++ trt.members.valuesIterator.flatMap(childrenMem) ++ diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls index 01a853089a..897ba7fed9 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls @@ -318,7 +318,7 @@ TestElim.eliminate(circles) //│ forall 'a. 'Region | 'a //│ where //│ 'Region :> Circle | 'a -//│ 'a :> Outside['Region] | Union['Region] | Intersect['Region] | Translate['Region] | Scale['Region] +//│ 'a :> Outside['Region] | Translate['Region] | Scale['Region] | Union['Region] | Intersect['Region] //│ res //│ = Union {} diff --git a/shared/src/test/diff/nu/MissingTypeArg.mls b/shared/src/test/diff/nu/MissingTypeArg.mls index 07fa09fb8f..259de26790 100644 --- a/shared/src/test/diff/nu/MissingTypeArg.mls +++ b/shared/src/test/diff/nu/MissingTypeArg.mls @@ -70,10 +70,10 @@ fun test(pt1, pt2) = pt1.color === pt1.color and let p2 = pt2.parent if p1 is undefined then p2 is undefined else test(p1, p2) -//│ fun test: forall 'a 'b 'c. ('b, 'a) -> Bool +//│ fun test: forall 'a 'b 'c. ('a, 'c) -> Bool //│ where -//│ 'a <: {parent: Object & 'a} -//│ 'b <: {color: Eql['c] & 'c, parent: Object & 'b & ~undefined | undefined} +//│ 'c <: {parent: Object & 'c} +//│ 'a <: {color: Eql['b] & 'b, parent: Object & 'a & ~undefined | undefined} :e // TODO support test(p, p) diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 2555c2e0ed..8ec2180954 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -147,7 +147,7 @@ fun map_expr(f, v) = Numb then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'a 'A 'b 'A0. ('a -> 'A & 'b -> 'A0, Add['a] | Mul['b] | Numb | Var) -> (Add['A] | Mul['A0] | Numb | Var) +//│ fun map_expr: forall 'a 'A 'b 'A0. ('b -> 'A0 & 'a -> 'A, Add['b] | Mul['a] | Numb | Var) -> (Add['A0] | Mul['A] | Numb | Var) mixin EvalExpr { fun eval(sub, v) = diff --git a/shared/src/test/diff/nu/PostHocMixinSignature.mls b/shared/src/test/diff/nu/PostHocMixinSignature.mls new file mode 100644 index 0000000000..5c23e3c3fa --- /dev/null +++ b/shared/src/test/diff/nu/PostHocMixinSignature.mls @@ -0,0 +1,73 @@ +:NewDefs + + +mixin Foo { + fun foo(x) = if x.a then x else foo(x.b) +} +//│ mixin Foo() { +//│ fun foo: 'a -> 'a +//│ } +//│ where +//│ 'a <: {a: Object, b: 'a} + + +module ValA { + val a = false + val b = ValB +} +module ValB { + val a = true + fun b = ValA +} +//│ module ValA { +//│ val a: false +//│ val b: ValB +//│ } +//│ module ValB { +//│ val a: true +//│ fun b: ValA +//│ } + + +module Test extends Foo +//│ module Test { +//│ fun foo: forall 'a. 'a -> 'a +//│ } +//│ where +//│ 'a <: {a: Object, b: 'a} + +[Test.foo(ValA), Test.foo(ValB)] +//│ [ValA | ValB, ValA | ValB] +//│ res +//│ = [ ValB { class: [class ValB] }, ValB { class: [class ValB] } ] + + +type V = {a: Bool, b: V} +//│ type V = {a: Bool, b: V} + +module Test extends Foo { + fun foo: V -> anything +} +//│ module Test { +//│ fun foo: V -> anything +//│ } + +[Test.foo(ValA), Test.foo(ValB)] +//│ [anything, anything] +//│ res +//│ = [ ValB { class: [class ValB] }, ValB { class: [class ValB] } ] + + +module Test extends Foo { + fun foo: V -> V +} +//│ module Test { +//│ fun foo: V -> V +//│ } + +[Test.foo(ValA), Test.foo(ValB)] +//│ [V, V] +//│ res +//│ = [ ValB { class: [class ValB] }, ValB { class: [class ValB] } ] + + From 855945cd23769a80dd388fee84fd908c00ed0361 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Sat, 30 Sep 2023 00:17:13 +0800 Subject: [PATCH 463/498] Implement right-associative ops & case expressions + add tests --- .../src/main/scala/mlscript/JSBackend.scala | 4 +- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 22 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 28 ++- shared/src/main/scala/mlscript/helpers.scala | 14 +- shared/src/main/scala/mlscript/syntax.scala | 3 +- .../diff/codegen/AuxiliaryConstructors.mls | 4 +- shared/src/test/diff/codegen/Modules.mls | 38 +++ shared/src/test/diff/gadt/Exp1.mls | 2 +- shared/src/test/diff/gadt/Exp2.mls | 2 +- shared/src/test/diff/nu/CaseExpr.mls | 124 ++++++++++ shared/src/test/diff/nu/Eval.mls | 228 ++++++++++++++++++ shared/src/test/diff/nu/FlatMonads_repro.mls | 4 +- shared/src/test/diff/nu/GenericClasses.mls | 2 +- shared/src/test/diff/nu/GenericMixins.mls | 10 +- shared/src/test/diff/nu/Misc.mls | 2 +- shared/src/test/diff/nu/PartialApp.mls | 2 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 4 +- shared/src/test/diff/nu/RightAssocOps.mls | 75 ++++++ shared/src/test/diff/nu/SelfRec.mls | 25 ++ .../diff/parser/ControversialIfSplits.mls | 16 +- shared/src/test/diff/parser/IfThenElse.mls | 20 +- shared/src/test/diff/parser/Misc.mls | 16 +- shared/src/test/diff/parser/WeirdIfs.mls | 8 +- shared/src/test/diff/ucs/SplitAfterOp.mls | 4 +- shared/src/test/diff/ucs/TrivialIf.mls | 4 +- shared/src/test/diff/ucs/WeirdIf.mls | 4 +- shared/src/test/diff/ucs/zipWith.mls | 4 +- .../src/test/scala/mlscript/DiffTests.scala | 2 +- 29 files changed, 599 insertions(+), 73 deletions(-) create mode 100644 shared/src/test/diff/codegen/Modules.mls create mode 100644 shared/src/test/diff/nu/CaseExpr.mls create mode 100644 shared/src/test/diff/nu/Eval.mls create mode 100644 shared/src/test/diff/nu/RightAssocOps.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 89a7ed34b1..3ee699d065 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -1232,7 +1232,7 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { JSInvoke(resultsIdent("push"), JSIdent(sym.runtimeName) :: Nil).stmt :: Nil case fd @ NuFunDef(isLetRec, Var(name), _, tys, R(ty)) => Nil - case _: Def | _: TypeDef => + case _: Def | _: TypeDef | _: Constructor => throw CodeGenError("Def and TypeDef are not supported in NewDef files.") case term: Term => val name = translateTerm(term)(topLevelScope) @@ -1476,7 +1476,7 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { } catch { case e: UnimplementedError => JSTestBackend.AbortedQuery(e.getMessage()) } - case _: Def | _: TypeDef => + case _: Def | _: TypeDef | _: Constructor => throw CodeGenError("Def and TypeDef are not supported in NewDef files.") } diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 6d08e2570a..e8e3142149 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -290,6 +290,7 @@ object NewLexer { "if", "then", "else", + "case", "fun", "val", "var", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index e536d4b651..44f92dd2d7 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -147,7 +147,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo (5, 5) case _ => val r = opStr.last - (prec(opStr.head), prec(r) - (if (r === '@' || r === '/' || r === ',') 1 else 0)) + (prec(opStr.head), prec(r) - (if (r === '@' || r === '/' || r === ',' || r === ':') 1 else 0)) } // def pe(msg: Message, l: Loc, rest: (Message, Opt[Loc])*): Unit = @@ -546,7 +546,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo } private def yeetSpaces: Ls[TokLoc] = - cur.dropWhile(_._1 === SPACE && { consume; true }) + cur.dropWhile(tkloc => + (tkloc._1 === SPACE + || tkloc._1.isInstanceOf[COMMENT] // TODO properly retrieve and sotre all comments in AST? + ) && { consume; true }) final def funParams(implicit et: ExpectThen, fe: FoundErr, l: Line): Ls[Tup] = wrap(()) { l => yeetSpaces match { @@ -698,6 +701,17 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo consume val e = expr(0) L(IfElse(e).withLoc(S(l0 ++ e.toLoc))) + case (KEYWORD("case"), l0) :: _ => + consume + exprOrIf(0)(et = true, fe = fe, l = implicitly) match { + case L(body) => + R(Lam(PlainTup(Var("case$scrut")), If(IfOpApp(Var("case$scrut"), Var("is"), body), N))) + case R(rhs) => + err((msg"Expected 'then'/'else' clause after 'case'; found ${rhs.describe} instead" -> rhs.toLoc :: + msg"Note: 'case' expression starts here:" -> S(l0) :: Nil)) + R(Lam(PlainTup(Var("case$scrut")), If(IfElse(rhs), N))) + } + case (KEYWORD("if"), l0) :: _ => consume cur match { @@ -746,8 +760,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo S(e.toLoc.foldRight(l1)(_ ++ _))) case Nil => (msg"${e.describe}", e.toLoc) } - err((msg"Expected 'then'/'else' clause; found $found instead" -> loc :: - msg"Note: 'if' expression started here:" -> S(l0) :: Nil)) + err((msg"Expected 'then'/'else' clause after 'if'; found $found instead" -> loc :: + msg"Note: 'if' expression starts here:" -> S(l0) :: Nil)) R(If(IfThen(e, errExpr), N)) } } diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index bee7242715..98be651e0e 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -648,13 +648,27 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case s :: stmts => val res_ty = s match { case decl: NuDecl => N - case s: Statement => - val (diags, dss) = s.desugared - diags.foreach(raise) - S(typeTerms(dss, false, Nil)(ctx, raise, TypeProvenance(s.toLoc, s match { - case trm: Term => trm.describe - case s => "statement" - }), vars, genLambdas = false)) + case t: Term => + implicit val genLambdas: GenLambdas = true + val ty = typeTerm(t) + /* // TODO next: + if (!topLevel) { + if (t.isInstanceOf[Var] || t.isInstanceOf[Lit]) + warn("Pure expression does nothing in statement position.", t.toLoc) + else + constrain(mkProxy(ty, TypeProvenance(t.toCoveringLoc, "expression in statement position")), UnitType)( + raise = err => raise(WarningReport( // Demote constraint errors from this to warnings + msg"Expression in statement position should have type `unit`." -> N :: + msg"Use the `discard` function to discard non-unit values, making the intent clearer." -> N :: + err.allMsgs, newDefs)), + prov = TypeProvenance(t.toLoc, t.describe), ctx) + } + */ + S(ty) + case s: DesugaredStatement => + err(msg"Illegal position for this ${s.describe} statement.", s.toLoc)(raise) + N + case _ => die } stmts match { case Nil => res_ty diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 116a7a0408..bc2320ca24 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -381,6 +381,7 @@ trait PgrmImpl { self: Pgrm => case ot: Terms => R(ot) case NuFunDef(isLetRec, nme, _, tys, rhs) => R(Def(isLetRec.getOrElse(true), nme, rhs, isLetRec.isEmpty)) + case _: Constructor => die } diags.toList -> res } @@ -468,6 +469,7 @@ trait NuDeclImpl extends Located { self: NuDecl => case _ => N } } + trait TypingUnitImpl extends Located { self: TypingUnit => def showDbg: Str = entities.map { case t: Term => t.toString @@ -479,6 +481,12 @@ trait TypingUnitImpl extends Located { self: TypingUnit => lazy val children: List[Located] = entities } +trait ConstructorImpl { self: Constructor => + // def children: List[Located] = fields.map(_._2) + def describe: Str = "constructor" + // def showDbg: Str = s"constructor(${fields.map(_._1.name).mkString(", ")})" +} + trait TypeNameImpl extends Ordered[TypeName] { self: TypeName => def base: TypeName = this def targs: Ls[Type] = Nil @@ -802,9 +810,9 @@ trait StatementImpl extends Located { self: Statement => lazy val desugared = doDesugar private def doDesugar: Ls[Diagnostic] -> Ls[DesugaredStatement] = this match { - case ctor: Constructor => - import Message._ - (ErrorReport(msg"constructor must be in a class." -> ctor.toLoc :: Nil, newDefs=true) :: Nil) -> Nil + // case ctor: Constructor => + // import Message._ + // (ErrorReport(msg"constructor must be in a class." -> ctor.toLoc :: Nil, newDefs=true) :: Nil) -> Nil case l @ LetS(isrec, pat, rhs) => val (diags, v, args) = desugDefnPattern(pat, Nil) diags -> (Def(isrec, v, L(args.foldRight(rhs)(Lam(_, _))), false).withLocOf(l) :: Nil) // TODO use v, not v.name diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index 3c5cf7bc3d..f33023a395 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -125,7 +125,6 @@ sealed trait Statement extends StatementImpl final case class LetS(isRec: Bool, pat: Term, rhs: Term) extends Statement final case class DataDefn(body: Term) extends Statement final case class DatatypeDefn(head: Term, body: Term) extends Statement -final case class Constructor(params: Tup, body: Blk) extends Statement // constructor(...) { ... } sealed trait DesugaredStatement extends Statement with DesugaredStatementImpl @@ -229,6 +228,8 @@ final case class NuFunDef( def isVirtual: Bool = virtualLoc.nonEmpty || rhs.isRight } +final case class Constructor(params: Tup, body: Blk) extends DesugaredStatement with ConstructorImpl // constructor(...) { ... } + final case class VarianceInfo(isCovariant: Bool, isContravariant: Bool) { diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls index b12ba400a2..97dda3a6e5 100644 --- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -231,10 +231,10 @@ class E { :e constructor(x: Int) -//│ ╔══[ERROR] constructor must be in a class. +//│ ╔══[ERROR] Illegal position for this constructor statement. //│ ║ l.233: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ [] +//│ //│ Code generation encountered an error: //│ unexpected constructor. diff --git a/shared/src/test/diff/codegen/Modules.mls b/shared/src/test/diff/codegen/Modules.mls new file mode 100644 index 0000000000..884d2a7927 --- /dev/null +++ b/shared/src/test/diff/codegen/Modules.mls @@ -0,0 +1,38 @@ +:NewDefs + + +module test { // hello + fun a = 1 +} +//│ module test { +//│ fun a: 1 +//│ } + + +:ge // * FIXME +:js +fun y = 1 +module Foo { + fun x = y +} +//│ fun y: 1 +//│ module Foo { +//│ fun x: 1 +//│ } +//│ Code generation encountered an error: +//│ unresolved symbol y + +:ge // * FIXME +:js +module Foo { + fun x = y +} +fun y = 1 +//│ module Foo { +//│ fun x: 1 +//│ } +//│ fun y: 1 +//│ Code generation encountered an error: +//│ unresolved symbol y + + diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 832217818b..13e6616f56 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -27,7 +27,7 @@ fun f(e) = if e is //│ fun f: forall 'a 'b. (Lit | Pair['a, 'b]) -> (Int | ['a, 'b]) (e: Exp['X]) => f(e) -//│ (e: Exp['X]) -> (Int | [??L, ??R]) +//│ forall 'X. (e: Exp['X]) -> (Int | [??L, ??R]) //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index 8fc5a1176a..85c3d5bad3 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -34,7 +34,7 @@ fun f(e) = if e is //│ ╟── type variable `L` leaks out of its scope //│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] //│ ╙── ^ -//│ (e: Exp['X]) -> (Int | error | [Exp['L], Exp['R]]) +//│ forall 'X 'L 'R. (e: Exp['X]) -> (Int | error | [Exp['L], Exp['R]]) //│ where //│ 'R :> ??R //│ <: ??R0 diff --git a/shared/src/test/diff/nu/CaseExpr.mls b/shared/src/test/diff/nu/CaseExpr.mls new file mode 100644 index 0000000000..79026d0fbf --- /dev/null +++ b/shared/src/test/diff/nu/CaseExpr.mls @@ -0,0 +1,124 @@ +:NewDefs + + +case 0 then true +//│ 0 -> true +//│ res +//│ = [Function: res] + +:pe // TODO support +case 0 then true, 1 then false +//│ ╔══[PARSE ERROR] Expected end of input; found comma instead +//│ ║ l.10: case 0 then true, 1 then false +//│ ╙── ^ +//│ 0 -> true +//│ res +//│ = [Function: res] + +case + 0 then true + 1 then false +//│ (0 | 1) -> Bool +//│ res +//│ = [Function: res] + + +fun foo = case + 0 then true + 1 then false +//│ fun foo: (0 | 1) -> Bool + +[foo(0), foo(1)] +//│ [Bool, Bool] +//│ res +//│ = [ true, false ] + + + +abstract class Option[out A] +class Some[out A](val value: A) extends Option[A] +module None extends Option[nothing] +//│ abstract class Option[A] +//│ class Some[A](value: A) extends Option +//│ module None extends Option + + +fun map(f) = case + Some(x) then Some(f(x)) + None then None +//│ fun map: forall 'a 'A. ('a -> 'A) -> (None | Some['a]) -> (None | Some['A]) + +map(succ) of Some of 123 +//│ None | Some[Int] +//│ res +//│ = Some {} + +map(succ) of None +//│ None | Some[Int] +//│ res +//│ = None { class: [class None extends Option] } + + +:e // TODO support +fun map(f) = case + Some(x) then Some(f(x)) + None as n then n +//│ ╔══[ERROR] Illegal pattern `as` +//│ ║ l.65: None as n then n +//│ ╙── ^^ +//│ fun map: anything -> anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + +:pe +case 1 +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'case'; found integer literal instead +//│ ║ l.75: case 1 +//│ ║ ^ +//│ ╟── Note: 'case' expression starts here: +//│ ║ l.75: case 1 +//│ ╙── ^^^^ +//│ anything -> 1 +//│ res +//│ = [Function: res] + +:pe +case (1 then true) +//│ ╔══[PARSE ERROR] Unexpected 'then' keyword here +//│ ║ l.87: case (1 then true) +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'case'; found integer literal instead +//│ ║ l.87: case (1 then true) +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── Note: 'case' expression starts here: +//│ ║ l.87: case (1 then true) +//│ ╙── ^^^^ +//│ anything -> 1 +//│ res +//│ = [Function: res] + +case else 0 +//│ anything -> 0 +//│ res +//│ = [Function: res] + +:pe +case then 1 else 0 +//│ ╔══[PARSE ERROR] Unexpected 'then' keyword in expression position +//│ ║ l.107: case then 1 else 0 +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'case'; found integer literal instead +//│ ║ l.107: case then 1 else 0 +//│ ║ ^ +//│ ╟── Note: 'case' expression starts here: +//│ ║ l.107: case then 1 else 0 +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Expected end of input; found 'else' keyword instead +//│ ║ l.107: case then 1 else 0 +//│ ╙── ^^^^ +//│ anything -> 1 +//│ res +//│ = [Function: res] + + diff --git a/shared/src/test/diff/nu/Eval.mls b/shared/src/test/diff/nu/Eval.mls new file mode 100644 index 0000000000..b1d8f4f9ed --- /dev/null +++ b/shared/src/test/diff/nu/Eval.mls @@ -0,0 +1,228 @@ +:NewDefs + + + +// * Standard definitions: + + +declare fun String: anything -> Str +//│ fun String: anything -> Str + +fun (++) stringConcat(a, b) = concat(a)(b) +//│ fun (++) stringConcat: (Str, Str) -> Str + +fun (|>) pipe(x, f) = f(x) +fun (<|) pepi(f, x) = f(x) +//│ fun (|>) pipe: forall 'a 'b. ('a, 'a -> 'b) -> 'b +//│ fun (<|) pepi: forall 'c 'd. ('c -> 'd, 'c) -> 'd + + +// * Hack to throw exceptions +declare class throw(arg: anything): nothing +//│ declare class throw(arg: anything): nothing + +:re +throw(1); 0 +//│ 0 +//│ res +//│ Runtime error: +//│ 1 + +fun test = throw(1); 0 +//│ fun test: 0 + +:re +test +//│ 0 +//│ res +//│ Runtime error: +//│ 1 + +fun test = + throw(1) + error +//│ fun test: nothing + +:re +test +//│ nothing +//│ res +//│ Runtime error: +//│ 1 + + +abstract class Option[out A] +class Some[out A](val value: A) extends Option[A] +module None extends Option[nothing] +//│ abstract class Option[A] +//│ class Some[A](value: A) extends Option +//│ module None extends Option + +abstract class List[out A]: Cons[A] | Nil { virtual val length: Int } +class Cons[out A](val head: A, val tail: List[A]) extends List[A] { + val length: Int + val length = tail.length + 1 + fun toString() = "Cons(" ++ String(head) ++ ", " ++ String(tail) ++ ")" +} +module Nil extends List[nothing] { + val length = 0 + fun toString() = "Nil" +} +//│ abstract class List[A]: Cons[A] | Nil { +//│ val length: Int +//│ } +//│ class Cons[A](head: A, tail: List[A]) extends List { +//│ val length: Int +//│ fun toString: () -> Str +//│ } +//│ module Nil extends List { +//│ val length: 0 +//│ fun toString: () -> "Nil" +//│ } + +fun (::) cons(x, xs) = Cons(x, xs) +fun (:::) concatList(xs, ys) = if xs is + Nil then ys + Cons(x, xs) then x :: xs ::: ys +//│ fun (::) cons: forall 'A. ('A, List['A]) -> Cons['A] +//│ fun (:::) concatList: forall 'A0 'a. (Cons['A0] | Nil, List['A0] & 'a) -> (Cons['A0] | 'a) + +module Lists { // TODO use name List when module overloading is supported: + + fun map(f) = case + Nil then Nil + Cons(x, xs) then f(x) :: map(f)(xs) + + fun zip(xs, ys) = if xs is + Nil then Nil + Cons(x, xs) then if ys is + Nil then Nil + Cons(y, ys) then + [x, y] :: zip(xs, ys) + + fun assoc(e) = case + Cons(kv, rest) then + if kv.key === e then Some(kv.value) + else assoc(e)(rest) + Nil then None + +} +//│ module Lists { +//│ fun assoc: forall 'a 'A. 'a -> (Cons[{key: Eql['a], value: 'A}] | Nil) -> (None | Some['A]) +//│ fun map: forall 'b 'A0. ('b -> 'A0) -> (Cons['b] | Nil) -> (Cons['A0] | Nil) +//│ fun zip: forall 'c 'd. (Cons['c] | Nil, Cons['d] | Nil) -> (Cons[['c, 'd]] | Nil) +//│ } + +let xs = 1 :: 2 :: 3 :: Nil +//│ let xs: Cons[1 | 2 | 3] +//│ xs +//│ = Cons {} + +String of xs ::: 4 :: 5 :: Nil +//│ Str +//│ res +//│ = 'Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))' + + +let ls = {key: "a", value: 0} :: Nil +//│ let ls: Cons[{key: "a", value: 0}] +//│ ls +//│ = Cons {} + +ls |> Lists.assoc("a") +//│ None | Some[0] +//│ res +//│ = Some {} + + + +// * Our little language: + + +abstract class Term: Var | App | Lam | Sel | Rcd[Term] +class Var(val name: Str) extends Term +class App(val lhs: Term, val args: List[Term]) extends Term +class Lam(val params: List[Str], val body: Term) extends Term +class Rcd[out Sub](val fields: List[{key: Str, value: Sub}]) extends Term +class Sel(val prefix: Term, val fieldName: Str) extends Term +abstract class Lit[out A](val value: A): IntLit | StrLit extends Term +class IntLit(v: Int) extends Lit[Int](v) +class StrLit(v: Str) extends Lit[Str](v) +//│ abstract class Term: App | Lam | Rcd[Term] | Sel | Var +//│ class Var(name: Str) extends Term +//│ class App(lhs: Term, args: List[Term]) extends Term +//│ class Lam(params: List[Str], body: Term) extends Term +//│ class Rcd[Sub](fields: List[{key: Str, value: Sub}]) extends Term +//│ class Sel(prefix: Term, fieldName: Str) extends Term +//│ abstract class Lit[A](value: A): IntLit | StrLit extends Term +//│ class IntLit(v: Int) extends Lit, Term +//│ class StrLit(v: Str) extends Lit, Term + +type Value = Lam | Lit | Rcd[Value] +//│ type Value = Lam | Lit[anything] | Rcd[Value] + + +fun err(msg) = + throw(concat("Evaluation error: " ++ msg)) + error +//│ fun err: Str -> nothing + +fun eval(t, env) = if t is + Var(nme) then if env |> Lists.assoc(nme) is Some(v) + then v + else err("variable not found: " ++ nme) + Lit then t + Lam then t + App(f, args) then + let fe = eval(f, env) + if fe is Lam(ps, bod) then + val argse = args |> Lists.map(a => eval(a, env)) + if ps.length === argse.length then () else err("wrong number of arguments") + let envp = Lists.zip(ps, argse) |> Lists.map of ([key, value]) => {key, value} + eval(bod, envp ::: env) + else err(String(fe) ++ " cannot be applied") + Sel(pre, nme) then + let pree = eval(pre, env) + if pree is Rcd(xs) and xs |> Lists.assoc(nme) is Some(v) then v + else err(String(pree) ++ " does not have field " ++ nme) + Rcd(fs) then + Rcd of fs |> Lists.map of {key, value} => {key, value: eval(value, env)} +//│ fun eval: forall 'a 'A 'b 'Sub. ('a, Cons[{key: Eql[Str], value: 'b}] & {List#A <: {key: Eql[Str], value: 'b}} & List[{key: Eql[Str], value: 'b}] | Nil & {List#A <: {key: Eql[Str], value: 'b}} & List[{key: Eql[Str], value: 'b}]) -> 'Sub +//│ where +//│ 'b :> 'Sub +//│ <: Object & ~#Rcd | Rcd['b] +//│ 'Sub :> Lam | Lit['A] | Rcd['Sub] | 'b +//│ 'a <: App | Lam | Lit['A] | Rcd['a] | Sel | Var + +eval : (Term, List[{key: Str, value: Value}]) -> Value +//│ (Term, List[{key: Str, value: Value}]) -> Value +//│ res +//│ = [Function: eval] + +let rcd = Rcd({key: "a", value: IntLit(0)} :: Nil) +//│ let rcd: Rcd[IntLit] +//│ rcd +//│ = Rcd {} + +eval of rcd, Nil +//│ 'Sub +//│ where +//│ 'Sub :> Lam | Lit[Int] | Rcd['Sub] +//│ res +//│ = Rcd {} + +eval of Sel(rcd, "a"), Nil +//│ 'Sub +//│ where +//│ 'Sub :> Lam | Lit[nothing] | Rcd['Sub] +//│ res +//│ = IntLit {} + +eval of App(Lam("x" :: Nil, Sel(Var("x"), "a")), rcd :: Nil), Nil +//│ 'Sub +//│ where +//│ 'Sub :> Lam | Lit[nothing] | Rcd['Sub] +//│ res +//│ = IntLit {} + + diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls index 31068b55aa..0324236522 100644 --- a/shared/src/test/diff/nu/FlatMonads_repro.mls +++ b/shared/src/test/diff/nu/FlatMonads_repro.mls @@ -118,7 +118,7 @@ r.run //│ = 42 x => readInt.bind of x -//│ (Int -> IO['AA]) -> Bind[Int, 'AA] +//│ forall 'AA. (Int -> IO['AA]) -> Bind[Int, 'AA] //│ res //│ = [Function: res] @@ -145,7 +145,7 @@ readInt.run //│ = 42 x => Pure(x).run -//│ 'run -> 'run +//│ forall 'run. 'run -> 'run //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 5629b4406d..9a904dd4be 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -322,7 +322,7 @@ TestBad().foo1(1) //│ = 1 x => TestBad().foo1(x) -//│ 'a -> 'a +//│ forall 'a. 'a -> 'a //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index 527338893c..d3f03373d6 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -159,20 +159,18 @@ module D extends C(0) { class C extends Test { // it also fails with Test[Int]... fun arg = 123 } -//│ ╔══[ERROR] Type `#C & {bar: [?A, ?A], baz: ?a, foo: ?A -> ?A}` does not contain member `arg` +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.117: fun baz = foo(this.arg) //│ ╙── ^^^^ -//│ ╔══[ERROR] Type `#C & {bar: [?A, ?A], baz: ?a, foo: ?A -> ?A}` does not contain member `arg` +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.116: fun bar = (this.arg, this.arg) //│ ╙── ^^^^ -//│ ╔══[ERROR] Type `#C & {bar: [?A, ?A], baz: ?a, foo: ?A -> ?A}` does not contain member `arg` +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.116: fun bar = (this.arg, this.arg) //│ ╙── ^^^^ -//│ ╔══[ERROR] Illegal position for this definition statement. -//│ ║ l.160: fun arg = 123 -//│ ╙── ^^^^^^^^^^^^^ //│ class C { //│ constructor() +//│ fun arg: 123 //│ fun bar: [error | 'A, error | 'A] //│ fun baz: error //│ fun foo: 'A -> (error | 'A) diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index 80a59069d8..f30609214a 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -28,7 +28,7 @@ x => x + 1 //│ = [Function: res] { y } => y -//│ {y: 'a} -> 'a +//│ forall 'a. {y: 'a} -> 'a //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/nu/PartialApp.mls b/shared/src/test/diff/nu/PartialApp.mls index 8b845f7ea4..2311edb37c 100644 --- a/shared/src/test/diff/nu/PartialApp.mls +++ b/shared/src/test/diff/nu/PartialApp.mls @@ -27,7 +27,7 @@ _.foo(1) // * ie x => x.foo(1) -//│ {foo: 1 -> 'a} -> 'a +//│ forall 'a. {foo: 1 -> 'a} -> 'a _ + _ diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index 359e5ee3cd..48d7148210 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -32,7 +32,7 @@ trait Base1: Foo //│ ╟── back into type variable `A` //│ ║ l.5: trait Foo[A] { fun x: A } //│ ╙── ^ -//│ (b: Base1) -> Foo['X] +//│ forall 'X. (b: Base1) -> Foo['X] //│ where //│ 'X :> ??A //│ <: ??A0 @@ -90,7 +90,7 @@ trait Base2: Foo['FigureItOut] // :e (b: Base2) => b : Foo['X] -//│ (b: Base2) -> Foo['X] +//│ forall 'X. (b: Base2) -> Foo['X] //│ where //│ 'X :> ??FigureItOut //│ <: ??FigureItOut0 diff --git a/shared/src/test/diff/nu/RightAssocOps.mls b/shared/src/test/diff/nu/RightAssocOps.mls new file mode 100644 index 0000000000..496395b873 --- /dev/null +++ b/shared/src/test/diff/nu/RightAssocOps.mls @@ -0,0 +1,75 @@ +:NewDefs + + +// * Operators that end with `:` are right-associative + + +fun (+:) pre(x: Int, xs) = [[x], xs] +fun (:+) post(xs, x: Int) = [xs, [x]] +fun (++) conc(xs, ys) = [xs, ys] +//│ fun (+:) pre: forall 'a. (x: Int, 'a) -> [[Int], 'a] +//│ fun (:+) post: forall 'b. ('b, x: Int) -> ['b, [Int]] +//│ fun (++) conc: forall 'c 'd. ('c, 'd) -> ['c, 'd] + + +1 +: 2 +: 3 +: [] +//│ [[Int], [[Int], [[Int], []]]] +//│ res +//│ = [ [ 1 ], [ [ 2 ], [ [Array], [] ] ] ] + +[] :+ 1 :+ 2 :+ 3 +//│ [[[[], [Int]], [Int]], [Int]] +//│ res +//│ = [ [ [ [], [Array] ], [ 2 ] ], [ 3 ] ] + +[1, 2, 3] ++ [4, 5, 6] +//│ [[1, 2, 3], [4, 5, 6]] +//│ res +//│ = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] + +:p +1 +: "a" ++ "b" :+ 2 +//│ |1| |+:| |"a"| |++| |"b"| |:+| |2| +//│ AST: TypingUnit(App(Var(+:), Tup(_: IntLit(1), _: App(Var(:+), Tup(_: App(Var(++), Tup(_: StrLit(a), _: StrLit(b))), _: IntLit(2)))))) +//│ Parsed: +:(1, :+(++("a", "b",), 2,),); +//│ [[Int], [["a", "b"], [Int]]] +//│ res +//│ = [ [ 1 ], [ [ 'a', 'b' ], [ 2 ] ] ] + +:p +1 +: "a" :+ 2 ++ "b" +//│ |1| |+:| |"a"| |:+| |2| |++| |"b"| +//│ AST: TypingUnit(App(Var(+:), Tup(_: IntLit(1), _: App(Var(++), Tup(_: App(Var(:+), Tup(_: StrLit(a), _: IntLit(2))), _: StrLit(b)))))) +//│ Parsed: +:(1, ++(:+("a", 2,), "b",),); +//│ [[Int], [["a", [Int]], "b"]] +//│ res +//│ = [ [ 1 ], [ [ 'a', [Array] ], 'b' ] ] + +:p +:e +1 +: "a" ++ 2 +: "b" +//│ |1| |+:| |"a"| |++| |2| |+:| |"b"| +//│ AST: TypingUnit(App(Var(+:), Tup(_: IntLit(1), _: App(Var(+:), Tup(_: App(Var(++), Tup(_: StrLit(a), _: IntLit(2))), _: StrLit(b)))))) +//│ Parsed: +:(1, +:(++("a", 2,), "b",),); +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.50: 1 +: "a" ++ 2 +: "b" +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── tuple literal of type `[?a, ?b]` is not an instance of type `Int` +//│ ║ l.9: fun (++) conc(xs, ys) = [xs, ys] +//│ ║ ^^^^^^ +//│ ╟── but it flows into operator application with expected type `Int` +//│ ║ l.50: 1 +: "a" ++ 2 +: "b" +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.7: fun (+:) pre(x: Int, xs) = [[x], xs] +//│ ╙── ^^^ +//│ [[Int], error | [[Int], "b"]] +//│ res +//│ = [ [ 1 ], [ [ [Array] ], 'b' ] ] + +1 +: "a" ++ (2 +: "b") +//│ [[Int], ["a", [[Int], "b"]]] +//│ res +//│ = [ [ 1 ], [ 'a', [ [Array], 'b' ] ] ] + + diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index e749e4f78c..5e4ffce607 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -220,3 +220,28 @@ class Foo8[A](x: A) { //│ } + + +:e // * FIXME this is caused by the self-annotation... +abstract class List(val length: Int): Cons +class Cons(tail: List) extends List(tail.length + 1) +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.227: class Cons(tail: List) extends List(tail.length + 1) +//│ ╙── ^^^^^^^ +//│ abstract class List(length: Int): Cons +//│ class Cons(tail: List) extends List + +// * Note: full (non-minimized) definitions: + +:e // * FIXME +abstract class List[out A](val length: Int): Cons[A] | Nil +class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) +module Nil extends List[nothing](0) +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.238: class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) +//│ ╙── ^^^^^^^ +//│ abstract class List[A](length: Int): Cons[A] | Nil +//│ class Cons[A](head: A, tail: List[A]) extends List +//│ module Nil extends List + + diff --git a/shared/src/test/diff/parser/ControversialIfSplits.mls b/shared/src/test/diff/parser/ControversialIfSplits.mls index e3c82524ce..3be9c49736 100644 --- a/shared/src/test/diff/parser/ControversialIfSplits.mls +++ b/shared/src/test/diff/parser/ControversialIfSplits.mls @@ -8,12 +8,12 @@ if f of //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here //│ ║ l.5: 0 then "ok" //│ ╙── ^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead //│ ║ l.4: if f of //│ ║ ^^^^ //│ ║ l.5: 0 then "ok" //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.4: if f of //│ ╙── ^^ //│ Parsed: {if (f(0,)) then undefined} @@ -26,7 +26,7 @@ if f ( //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here //│ ║ l.22: 0 then "ok" //│ ╙── ^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead //│ ║ l.21: if f ( //│ ║ ^^^ //│ ║ l.22: 0 then "ok" @@ -35,7 +35,7 @@ if f ( //│ ║ ^^^^^^^^^^^^^ //│ ║ l.24: ) //│ ║ ^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.21: if f ( //│ ╙── ^^ //│ Parsed: {if (f(0,)) then undefined} @@ -48,12 +48,12 @@ if f of //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here //│ ║ l.44: 0 then "ok" //│ ╙── ^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead //│ ║ l.43: if f of //│ ║ ^^^^ //│ ║ l.44: 0 then "ok" //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.43: if f of //│ ╙── ^^ //│ Parsed: {if (f(0,)) then undefined} @@ -65,12 +65,12 @@ if f of //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here //│ ║ l.62: 0 is 0 then "ok" //│ ╙── ^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead //│ ║ l.61: if f of //│ ║ ^^^^ //│ ║ l.62: 0 is 0 then "ok" //│ ║ ^^^^^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.61: if f of //│ ╙── ^^ //│ Parsed: {if (f(is(0,)(0,),)) then undefined} diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 326b5ab561..8b57c4a6d5 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -192,10 +192,10 @@ a == 1 and b == 2 :pe if lol //│ |#if| |lol| -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found reference instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found reference instead //│ ║ l.193: if lol //│ ║ ^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.193: if lol //│ ╙── ^^ //│ Parsed: {if (lol) then undefined} @@ -248,10 +248,10 @@ else :pe if lol else 2 //│ |#if| |lol| |#else| |2| -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found reference followed by 'else' keyword instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found reference followed by 'else' keyword instead //│ ║ l.249: if lol else 2 //│ ║ ^^^^^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.249: if lol else 2 //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected end of input; found 'else' keyword instead @@ -405,10 +405,10 @@ if let Some(x) = v then 123 //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead //│ ║ l.397: if let Some(x) = v then 123 //│ ╙── ^^^^^^^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found let binding instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found let binding instead //│ ║ l.397: if let Some(x) = v then 123 //│ ║ ^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.397: if let Some(x) = v then 123 //│ ╙── ^^ //│ Parsed: {if (let Some = undefined in undefined) then undefined} @@ -426,10 +426,10 @@ if let Some(x) = v and cond then 123 //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead //│ ║ l.418: if let Some(x) = v and cond then 123 //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found let binding instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found let binding instead //│ ║ l.418: if let Some(x) = v and cond then 123 //│ ║ ^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.418: if let Some(x) = v and cond then 123 //│ ╙── ^^ //│ Parsed: {if (let Some = undefined in undefined) then undefined} @@ -531,10 +531,10 @@ if true :pe (if true) //│ |(|#if| |true|)| -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found reference instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found reference instead //│ ║ l.532: (if true) //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.532: (if true) //│ ╙── ^^ //│ Parsed: {'(' if (true) then undefined ')'} diff --git a/shared/src/test/diff/parser/Misc.mls b/shared/src/test/diff/parser/Misc.mls index e0dec04ced..0df0a8c69d 100644 --- a/shared/src/test/diff/parser/Misc.mls +++ b/shared/src/test/diff/parser/Misc.mls @@ -21,7 +21,7 @@ foo of //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.12: None then 0 //│ ╙── ^^^^^^^^^^^^^^^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application followed by newline instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application followed by newline instead //│ ║ l.10: discard of if f of x is //│ ║ ^^^^^^^^^ //│ ║ l.11: Some(v) then v + 1 @@ -32,7 +32,7 @@ foo of //│ ║ ^^^^^^^^^^^^^^ //│ ║ l.14: Some(v) then v + 1 //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.10: discard of if f of x is //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected comma here @@ -45,12 +45,12 @@ foo of //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.15: None then 0, //│ ╙── ^^^^^^^^^^^^^^^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead //│ ║ l.13: if g of y is //│ ║ ^^^^^^^^^ //│ ║ l.14: Some(v) then v + 1 //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.13: if g of y is //│ ╙── ^^ //│ Parsed: {foo({discard(if (f(undefined,)) then undefined,); if (g(undefined,)) then undefined},)} @@ -77,7 +77,7 @@ foo of //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.61: None then 0, //│ ╙── ^^^^^^^^^^^^^^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application followed by newline instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application followed by newline instead //│ ║ l.59: if f of x is //│ ║ ^^^^^^^^^ //│ ║ l.60: Some v then v + 1 @@ -92,7 +92,7 @@ foo of //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ║ l.65: //│ ║ ^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.59: if f of x is //│ ╙── ^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword @@ -108,7 +108,7 @@ foo of //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.64: None then 0, //│ ╙── ^^^^^^^^^^^^^^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found application followed by newline instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application followed by newline instead //│ ║ l.62: if g of y is //│ ║ ^^^^^^^^^ //│ ║ l.63: Some v then v + 1 @@ -117,7 +117,7 @@ foo of //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ║ l.65: //│ ║ ^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.62: if g of y is //│ ╙── ^^ //│ Parsed: {foo({if (f(undefined,)) then undefined; if (g(undefined,)) then undefined},)} diff --git a/shared/src/test/diff/parser/WeirdIfs.mls b/shared/src/test/diff/parser/WeirdIfs.mls index e2c99b339a..0bfb8c3155 100644 --- a/shared/src/test/diff/parser/WeirdIfs.mls +++ b/shared/src/test/diff/parser/WeirdIfs.mls @@ -17,12 +17,12 @@ if x is //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here //│ ║ l.12: else e //│ ╙── ^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application instead //│ ║ l.11: if x is //│ ║ ^^^^ //│ ║ l.12: else e //│ ║ ^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.11: if x is //│ ╙── ^^ //│ Parsed: {if (is(x,)(undefined,)) then undefined} @@ -34,12 +34,12 @@ if x is //│ ╔══[PARSE ERROR] Unexpected 'else' keyword here //│ ║ l.32: P else e //│ ╙── ^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application instead //│ ║ l.31: if x is //│ ║ ^^^^ //│ ║ l.32: P else e //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.31: if x is //│ ╙── ^^ //│ Parsed: {if (is(x,)({P},)) then undefined} diff --git a/shared/src/test/diff/ucs/SplitAfterOp.mls b/shared/src/test/diff/ucs/SplitAfterOp.mls index d79edec279..09e828989c 100644 --- a/shared/src/test/diff/ucs/SplitAfterOp.mls +++ b/shared/src/test/diff/ucs/SplitAfterOp.mls @@ -149,12 +149,12 @@ fun toEnglish(x) = //│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here //│ ║ l.145: else 1 //│ ╙── ^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application instead //│ ║ l.144: if x == //│ ║ ^^^^ //│ ║ l.145: else 1 //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.144: if x == //│ ╙── ^^ //│ ╔══[ERROR] The case when this is false is not handled: ==(x,)(undefined,) diff --git a/shared/src/test/diff/ucs/TrivialIf.mls b/shared/src/test/diff/ucs/TrivialIf.mls index 2d160cb73a..0fa422ee8e 100644 --- a/shared/src/test/diff/ucs/TrivialIf.mls +++ b/shared/src/test/diff/ucs/TrivialIf.mls @@ -78,12 +78,12 @@ fun foo(x) = if x is Some of //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here //│ ║ l.76: 0 then 0 //│ ╙── ^^^^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application instead //│ ║ l.75: fun foo(x) = if x is Some of //│ ║ ^^^^^^^^^^^^ //│ ║ l.76: 0 then 0 //│ ║ ^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.75: fun foo(x) = if x is Some of //│ ╙── ^^ //│ foo: (Some & {value: 0}) -> undefined diff --git a/shared/src/test/diff/ucs/WeirdIf.mls b/shared/src/test/diff/ucs/WeirdIf.mls index 8e76a6124b..5f4d44439e 100644 --- a/shared/src/test/diff/ucs/WeirdIf.mls +++ b/shared/src/test/diff/ucs/WeirdIf.mls @@ -75,12 +75,12 @@ fun f(x) = //│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here //│ ║ l.71: else "bruh" //│ ╙── ^ -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application instead //│ ║ l.70: if x === //│ ║ ^^^^^ //│ ║ l.71: else "bruh" //│ ║ ^^^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.70: if x === //│ ╙── ^^ //│ ╔══[ERROR] The case when this is false is not handled: ===(x, undefined,) diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index 42398ff537..1d59fc9412 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -45,12 +45,12 @@ fun zipWith_wrong(f, xs, ys) = and zipWith_wrong(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) else None -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause; found operator application followed by newline instead +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application followed by newline instead //│ ║ l.43: if xs is Cons(x, xs) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ║ l.44: and ys is Cons(y, ys) //│ ║ ^^ -//│ ╟── Note: 'if' expression started here: +//│ ╟── Note: 'if' expression starts here: //│ ║ l.43: if xs is Cons(x, xs) //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected operator in expression position diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 28f52c358f..23a3e6d79f 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -989,7 +989,7 @@ class DiffTests } other match { case _: TestCode => () // Impossible case. - case IllFormedCode(message) => + case e @ IllFormedCode(message) => totalCodeGenErrors += 1 if (!mode.expectCodeGenErrors && !mode.fixme && !mode.expectTypeErrors) failures += blockLineNum From b14bd8d837ab0acf274ee968fe77f63ed3cfd4e3 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 30 Sep 2023 12:21:18 +0800 Subject: [PATCH 464/498] Fix that execution errors of a term are swallowed when there are functions before the term (#181) --- shared/src/test/diff/codegen/Mixin.mls | 16 +- shared/src/test/diff/codegen/NuFuns.mls | 13 +- shared/src/test/diff/codegen/NuReplHost.mls | 8 +- shared/src/test/diff/nu/FunPoly.mls | 2 +- shared/src/test/diff/nu/Interfaces.mls | 143 +++++++++--------- .../test/diff/nu/IntraBlockPolymorphism.mls | 6 +- shared/src/test/diff/nu/MissingImplBug.mls | 2 +- shared/src/test/diff/nu/NamedArgs.mls | 32 ++-- shared/src/test/diff/nu/SimpleSymbolicOps.mls | 2 +- shared/src/test/diff/ucs/HygienicBindings.mls | 8 +- .../src/test/scala/mlscript/DiffTests.scala | 62 ++++---- 11 files changed, 151 insertions(+), 143 deletions(-) diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 429c72da89..5487ddca95 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -234,7 +234,6 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ globalThis.TestLang = typing_unit5.TestLang; //│ // End of generated code -:js fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) @@ -244,19 +243,8 @@ TestLang.eval(mk(0)) //│ Int //│ where //│ 'E :> Add['E] | Lit | Neg['E] -//│ // Prelude -//│ class TypingUnit6 {} -//│ const typing_unit6 = new TypingUnit6; -//│ // Query 1 -//│ globalThis.mk = function mk(n) { -//│ let a; -//│ return a = n, a === 0 ? Lit(0) : a === 1 ? Neg(mk(n)) : Add(mk(n), mk(n)); -//│ }; -//│ // Query 2 -//│ res = TestLang.eval(mk(0)); -//│ // End of generated code //│ res -//│ = [Function: mk] +//│ = 0 class Foo(x: Int) @@ -384,7 +372,7 @@ mixin Base { fun x = y } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.384: fun x = y +//│ ║ l.372: fun x = y //│ ╙── ^ //│ mixin Base() { //│ fun x: error diff --git a/shared/src/test/diff/codegen/NuFuns.mls b/shared/src/test/diff/codegen/NuFuns.mls index 94ea8c7053..063a7ae3b9 100644 --- a/shared/src/test/diff/codegen/NuFuns.mls +++ b/shared/src/test/diff/codegen/NuFuns.mls @@ -26,17 +26,18 @@ foo //│ fun foo: Int //│ Int //│ res -//│ = [Function: foo1] +//│ = 111 -// FIXME: returns a thunk fun main = log("Hello") main //│ fun main: undefined //│ undefined //│ res -//│ = [Function: main] +//│ = undefined +//│ // Output +//│ Hello fun main = log("Hello") @@ -59,5 +60,9 @@ main //│ fun main: undefined //│ undefined //│ res -//│ = [Function: main2] +//│ = undefined +//│ // Output +//│ 0 +//│ 1 +//│ 2 diff --git a/shared/src/test/diff/codegen/NuReplHost.mls b/shared/src/test/diff/codegen/NuReplHost.mls index 415d453c00..d4805d1c82 100644 --- a/shared/src/test/diff/codegen/NuReplHost.mls +++ b/shared/src/test/diff/codegen/NuReplHost.mls @@ -1,16 +1,17 @@ :NewDefs -// * FIXME This should crash due to `error`, +// * This should crash due to `error`, // * but the crash is somehow swallowed and we get the result of the previous statement instead! // * The same happens with any other side effect, like `log(...)` // * Note: this doesn't happen if the last line is in a spearate diff-test block :showRepl +:re fun foo(x) = error let r = foo(1) //│ fun foo: anything -> nothing //│ let r: nothing -//│ ┌ Block at NuReplHost.mls:9 +//│ ┌ Block at NuReplHost.mls:10 //│ ├─┬ Prelude //│ │ ├── Code //│ │ │ function error() { @@ -35,7 +36,8 @@ let r = foo(1) //│ ├── globalThis.r = foo(1); //│ └── Reply: [runtime error] Error: an error was thrown //│ r -//│ = [Function: foo] +//│ Runtime error: +//│ Error: an error was thrown :re r diff --git a/shared/src/test/diff/nu/FunPoly.mls b/shared/src/test/diff/nu/FunPoly.mls index 8a9a5d5937..9919df0423 100644 --- a/shared/src/test/diff/nu/FunPoly.mls +++ b/shared/src/test/diff/nu/FunPoly.mls @@ -22,7 +22,7 @@ fun id(x) = x //│ fun id: forall 'a. 'a -> 'a //│ [1, true] //│ res -//│ = [Function: id1] +//│ = [ 1, true ] diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 18c37d4c68..cd0cf441ba 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -295,7 +295,7 @@ fts(c) //│ fun fts: (x: Test) -> Int //│ Int //│ res -//│ = [Function: fts] +//│ = 1 fts(oth1) //│ Int @@ -587,10 +587,6 @@ e: ZL & Geo //│ fun fit: (x: EM) -> WP //│ Geo & ZL //│ res -//│ = [Function: fot] -//│ res -//│ = [Function: fit] -//│ res //│ = //│ w is not implemented //│ res @@ -599,6 +595,12 @@ e: ZL & Geo //│ res //│ = //│ e is not implemented +//│ res +//│ = +//│ w is not implemented +//│ res +//│ = +//│ e is not implemented :e fun fto(w: WP): EM = w @@ -606,51 +608,52 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.604: fun fto(w: WP): EM = w +//│ ║ l.606: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.604: fun fto(w: WP): EM = w +//│ ║ l.606: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.604: fun fto(w: WP): EM = w +//│ ║ l.606: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.604: fun fto(w: WP): EM = w +//│ ║ l.606: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.605: z: WP +//│ ║ l.607: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` //│ ║ l.563: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.605: z: WP +//│ ║ l.607: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.605: z: WP +//│ ║ l.607: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.606: g: ZL +//│ ║ l.608: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` //│ ║ l.562: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.606: g: ZL +//│ ║ l.608: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.606: g: ZL +//│ ║ l.608: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP) -> EM //│ WP & ZL //│ res -//│ = [Function: fto] -//│ res //│ = //│ z is not implemented //│ res //│ = //│ g is not implemented +//│ res +//│ = +//│ e is not implemented class Bs(val a: Bool) { virtual fun foo(x) = x + 1 @@ -694,29 +697,29 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.693: fun foo(x) = x && false +//│ ║ l.696: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.693: fun foo(x) = x && false +//│ ║ l.696: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.693: fun foo(x) = x && false +//│ ║ l.696: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.693: fun foo(x) = x && false +//│ ║ l.696: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.656: virtual fun foo(x) = x + 1 +//│ ║ l.659: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.693: fun foo(x) = x && false +//│ ║ l.696: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.693: fun foo(x) = x && false +//│ ║ l.696: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.656: virtual fun foo(x) = x + 1 +//│ ║ l.659: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2 extends Bs, Ele { //│ constructor() @@ -729,25 +732,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.728: class Eh extends Bs(1) +//│ ║ l.731: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `Bool` -//│ ║ l.728: class Eh extends Bs(1) +//│ ║ l.731: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.655: class Bs(val a: Bool) { +//│ ║ l.658: class Bs(val a: Bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.729: class Eh1 extends Bs +//│ ║ l.732: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.656: virtual fun foo(x) = x + 1 +//│ ║ l.659: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `Int` -//│ ║ l.656: virtual fun foo(x) = x + 1 +//│ ║ l.659: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `Int` -//│ ║ l.656: virtual fun foo(x) = x + 1 +//│ ║ l.659: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: Int @@ -756,7 +759,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `Eh3` -//│ ║ l.730: class Eh3 extends Bs(false), Test +//│ ║ l.733: class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool @@ -796,10 +799,10 @@ class Cx(a2: 1 | 2, val b: Bool) extends Ca(a2) :e class Cx(a: 1 | 2, val b: Bool) extends Ca(a) //│ ╔══[ERROR] Inherited parameter named `a` is not virtual and cannot be overridden -//│ ║ l.797: class Cx(a: 1 | 2, val b: Bool) extends Ca(a) +//│ ║ l.800: class Cx(a: 1 | 2, val b: Bool) extends Ca(a) //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.778: class Ca(a: Int) extends Oth { +//│ ║ l.781: class Ca(a: Int) extends Oth { //│ ╙── ^ //│ class Cx(a: 1 | 2, b: Bool) extends Ca, Oth, Test { //│ fun bar: forall 'a. 'a -> 'a @@ -841,7 +844,7 @@ abstract class Bc3 { :e class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] Cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.842: class Bc12() extends Bc1(1), Bc2(true) +//│ ║ l.845: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: @@ -852,10 +855,10 @@ class Bc02() extends Bc1(1:Int) { val foo = 2 } //│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden -//│ ║ l.852: val foo = 2 +//│ ║ l.855: val foo = 2 //│ ║ ^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.830: class Bc1(foo: Int) +//│ ║ l.833: class Bc1(foo: Int) //│ ╙── ^^^ //│ class Bc02() extends Bc1 { //│ val foo: 2 @@ -869,14 +872,14 @@ Bc02().foo :e class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.870: class Bc31(baz: Bool) extends Bc3 +//│ ║ l.873: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.833: let baz : Int +//│ ║ l.836: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.833: let baz : Int +//│ ║ l.836: let baz : Int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: Bool) extends Bc3 @@ -885,10 +888,10 @@ class Bc11 extends Bc1(1) { let foo = true } //│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden -//│ ║ l.885: let foo = true +//│ ║ l.888: let foo = true //│ ║ ^^^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.830: class Bc1(foo: Int) +//│ ║ l.833: class Bc1(foo: Int) //│ ╙── ^^^ //│ class Bc11 extends Bc1 { //│ constructor() @@ -918,7 +921,7 @@ trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.918: fun f = error +//│ ║ l.921: fun f = error //│ ╙── ^^^^^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -949,7 +952,7 @@ bp: Base[(Int, Bool)] :e bp: Base[(Int, Int)] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.950: bp: Base[(Int, Int)] +//│ ║ l.953: bp: Base[(Int, Int)] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -1010,13 +1013,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.1011: class DerBad1 extends Base[Int, Int] +//│ ║ l.1014: class DerBad1 extends Base[Int, Int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared (or its declaration is inherited) but is not implemented in `DerBad1` -//│ ║ l.1011: class DerBad1 extends Base[Int, Int] +//│ ║ l.1014: class DerBad1 extends Base[Int, Int] //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.899: trait Base[A] { fun f: A -> A } +//│ ║ l.902: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^^^^^ //│ class DerBad1 extends Base { //│ constructor() @@ -1028,28 +1031,28 @@ class DerBad1 extends Base[Int, Int] :e class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.1029: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ constructor() @@ -1101,7 +1104,7 @@ trait Tb extends Ta[Int] { virtual val p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1101: virtual val p = false +//│ ║ l.1104: virtual val p = false //│ ╙── ^^^^^^^^^^^^^ //│ trait Tb extends Ta { //│ val g: 'T @@ -1136,14 +1139,14 @@ trait Oz { :e class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1137: class Fischl(age: Bool) extends Oz +//│ ║ l.1140: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1130: let age: Int +//│ ║ l.1133: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1130: let age: Int +//│ ║ l.1133: let age: Int //│ ╙── ^^^^^^^^ //│ class Fischl(age: Bool) extends Oz @@ -1163,29 +1166,29 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1163: fun foo(x) = x && true +//│ ║ l.1166: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1163: fun foo(x) = x && true +//│ ║ l.1166: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1163: fun foo(x) = x && true +//│ ║ l.1166: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1163: fun foo(x) = x && true +//│ ║ l.1166: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1154: virtual fun foo(x) = x + 1 +//│ ║ l.1157: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1163: fun foo(x) = x && true +//│ ║ l.1166: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1163: fun foo(x) = x && true +//│ ║ l.1166: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1154: virtual fun foo(x) = x + 1 +//│ ║ l.1157: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { //│ constructor() @@ -1204,11 +1207,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1205: class Ohhh(x: Bool) extends Ha +//│ ║ l.1208: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1195: class Ha { virtual val x: Int = 1 } +//│ ║ l.1198: class Ha { virtual val x: Int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: Bool) extends Ha diff --git a/shared/src/test/diff/nu/IntraBlockPolymorphism.mls b/shared/src/test/diff/nu/IntraBlockPolymorphism.mls index e0ef8cede4..57c3767c55 100644 --- a/shared/src/test/diff/nu/IntraBlockPolymorphism.mls +++ b/shared/src/test/diff/nu/IntraBlockPolymorphism.mls @@ -13,9 +13,9 @@ let b = i(true) //│ let a: 0 //│ let b: true //│ a -//│ = [Function: i] -//│ b //│ = 0 +//│ b +//│ = true :re // FIXME shouldn't be a reference error let a = i(0) @@ -28,7 +28,7 @@ let b = i(true) //│ Runtime error: //│ ReferenceError: i1 is not defined //│ b -//│ = [Function: i1] +//│ = true :re // FIXME shouldn't be a reference error let a = i(0) diff --git a/shared/src/test/diff/nu/MissingImplBug.mls b/shared/src/test/diff/nu/MissingImplBug.mls index cc81ccebdf..5be4551c2c 100644 --- a/shared/src/test/diff/nu/MissingImplBug.mls +++ b/shared/src/test/diff/nu/MissingImplBug.mls @@ -22,7 +22,7 @@ let StringInstance: { fromCharCode: Int => Str } = String //│ let StringInstance: {fromCharCode: Int -> Str} //│ fun String: nothing //│ makeString -//│ = +//│ = [Function: String] //│ StringInstance //│ = [Function: String] diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index 0d9aa5267c..362aca1868 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -219,7 +219,7 @@ let p = print(0) //│ fun print: (x: Int) -> (y: Int, z: Int) -> undefined //│ let p: (y: Int, z: Int) -> undefined //│ p -//│ = [Function: print] +//│ = [Function (anonymous)] p(z: 1, y: 2) //│ undefined @@ -239,9 +239,11 @@ p(z: 1, y: 2) //│ let p: (anything, anything) -> undefined //│ error //│ p -//│ = [Function: print1] +//│ = [Function (anonymous)] //│ res -//│ = [Function (anonymous)] +//│ = undefined +//│ // Output +//│ [ 0, 1, 2 ] class Baz() { @@ -287,7 +289,7 @@ z.y :e (f => f(x: a)) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.288: (f => f(x: a)) +//│ ║ l.290: (f => f(x: a)) //│ ╙── ^ //│ anything -> error //│ Code generation encountered an error: @@ -296,7 +298,7 @@ z.y :e (f => f)(error)(x: a) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.297: (f => f)(error)(x: a) +//│ ║ l.299: (f => f)(error)(x: a) //│ ╙── ^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: @@ -305,7 +307,7 @@ z.y :e (f => f)(42)(x: a) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.306: (f => f)(42)(x: a) +//│ ║ l.308: (f => f)(42)(x: a) //│ ╙── ^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: @@ -314,7 +316,7 @@ z.y :e (f => f)(if true then 123 else false)(x: a) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.315: (f => f)(if true then 123 else false)(x: a) +//│ ║ l.317: (f => f)(if true then 123 else false)(x: a) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: @@ -328,7 +330,7 @@ z.y :e (f => if true then f else id)(if true then (x: Int) => x + 1 else id)(x: 123) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.329: (f => if true then f else id)(if true then (x: Int) => x + 1 else id)(x: 123) +//│ ║ l.331: (f => if true then f else id)(if true then (x: Int) => x + 1 else id)(x: 123) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ error //│ res @@ -337,7 +339,7 @@ z.y :e (f => if true then f else id)(if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.338: (f => if true then f else id)(if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) +//│ ║ l.340: (f => if true then f else id)(if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ error //│ res @@ -359,7 +361,7 @@ foo((x: Int) => 1) :e fun foo(f: ((x: Int) => Int) | 'a) = f(x: 123) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `'a | (x: Int) -> Int` for applying named arguments -//│ ║ l.360: fun foo(f: ((x: Int) => Int) | 'a) = f(x: 123) +//│ ║ l.362: fun foo(f: ((x: Int) => Int) | 'a) = f(x: 123) //│ ╙── ^ //│ fun foo: (f: anything) -> error @@ -368,7 +370,7 @@ fun foo(f: ((x: Int) => Int) | 'a) = f(x: 123) :e fun foo(x) = (if true then (x: Int) => x + 1 else x)(x: 123) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `(x: Int) -> ?a | ?b` for applying named arguments -//│ ║ l.369: fun foo(x) = (if true then (x: Int) => x + 1 else x)(x: 123) +//│ ║ l.371: fun foo(x) = (if true then (x: Int) => x + 1 else x)(x: 123) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun foo: anything -> error @@ -381,7 +383,7 @@ foo((y: Int) => y) :e // TODO later: this could be made to work... fun foo(x) = (if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `(x: Int) -> (?a | ?b)` for applying named arguments -//│ ║ l.382: fun foo(x) = (if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) +//│ ║ l.384: fun foo(x) = (if true then (x: Int) => x + 1 else (x: Int) => x + 1)(x: 123) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ fun foo: anything -> error @@ -392,7 +394,7 @@ fun foo(x) = if true then (x: Int) => x + 1 else x :e foo((y: Int) => y)(x: 123) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.393: foo((y: Int) => y)(x: 123) +//│ ║ l.395: foo((y: Int) => y)(x: 123) //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ error //│ res @@ -401,7 +403,7 @@ foo((y: Int) => y)(x: 123) :e foo((x: Int) => x - 1)(x: 123) //│ ╔══[ERROR] Cannot retrieve appropriate function signature from type `?a` for applying named arguments -//│ ║ l.402: foo((x: Int) => x - 1)(x: 123) +//│ ║ l.404: foo((x: Int) => x - 1)(x: 123) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ error //│ res @@ -414,7 +416,7 @@ fun foo1(x) = [x + 1, x] :e foo1(x: 123) //│ ╔══[ERROR] Cannot use named arguments as the function type has untyped arguments -//│ ║ l.415: foo1(x: 123) +//│ ║ l.417: foo1(x: 123) //│ ╙── ^^^^^^^^ //│ error //│ res diff --git a/shared/src/test/diff/nu/SimpleSymbolicOps.mls b/shared/src/test/diff/nu/SimpleSymbolicOps.mls index cdd52ef17f..6910d6fbf2 100644 --- a/shared/src/test/diff/nu/SimpleSymbolicOps.mls +++ b/shared/src/test/diff/nu/SimpleSymbolicOps.mls @@ -15,6 +15,6 @@ fun (-) i(x, y) = x //│ fun (-) i: forall 'a. ('a, anything) -> 'a //│ [1, 2, 1, 2] //│ res -//│ = [Function: i1] +//│ = [ 1, 2, 1, 2 ] diff --git a/shared/src/test/diff/ucs/HygienicBindings.mls b/shared/src/test/diff/ucs/HygienicBindings.mls index 9207fb8dce..5e5d577f9c 100644 --- a/shared/src/test/diff/ucs/HygienicBindings.mls +++ b/shared/src/test/diff/ucs/HygienicBindings.mls @@ -136,11 +136,11 @@ h3("anything", "anything", _ => "not me", _ => false) //│ fun h3: forall 'a 'b. (None | Object & 'a & ~#None, 'b, (None | 'a) -> anything, (None | 'a) -> Object) -> ("anyway" | 'b) //│ "anything" | "anyway" //│ res -//│ = [Function: h3] -//│ res //│ = 'not me' //│ res //│ = 'should be me' +//│ res +//│ = 'anyway' // FIXME: Some results are wrong. fun h4(x, y, p) = @@ -155,10 +155,10 @@ h4("anything", "not me", _ => false) //│ fun h4: forall 'a 'b. (None | Object & 'a & ~#None, 'b, (None | 'a) -> Object) -> ("default" | 'b) //│ "default" | "not me" //│ res -//│ = [Function: h4] -//│ res //│ = 'not me' //│ res //│ = 'not me' //│ res //│ = 'should be me' +//│ res +//│ = 'default' diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 23a3e6d79f..686694824c 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -602,9 +602,9 @@ class DiffTests // (Nil, Nil, N) (Nil, Nil, S(p.tops.collect { // case LetS(isRec, pat, bod) => ("res", Nil, Nil, false) - case NuFunDef(isLet @ S(_), nme, snme, tparams, bod) => - (nme.name + " ", nme.name :: Nil, Nil, false) - case t: Term => ("res ", "res" :: Nil, Nil, false) + case NuFunDef(isLet, nme, snme, tparams, bod) => + (nme.name + " ", nme.name :: Nil, Nil, false, isLet.isEmpty) + case t: Term => ("res ", "res" :: Nil, Nil, false, false) })) } else { @@ -731,8 +731,8 @@ class DiffTests // all `Def`s and `Term`s are processed here // generate typescript types if generateTsDeclarations flag is // set in the mode - // The tuple type means: (, , , ) - val typerResults: Ls[(Str, Ls[Str], Ls[Str], Bool)] = newDefsResults getOrElse stmts.map { stmt => + // The tuple type means: (, , , , ) + val typerResults: Ls[(Str, Ls[Str], Ls[Str], Bool, Bool)] = newDefsResults getOrElse stmts.map { stmt => // Because diagnostic lines are after the typing results, // we need to cache the diagnostic blocks and add them to the // `typerResults` buffer after the statement has been processed. @@ -818,9 +818,9 @@ class DiffTests } } typingResults match { - case N => ("", Nil, diagnosticLines.toList, false) + case N => ("", Nil, diagnosticLines.toList, false, false) case S(name -> typingLines) => - (name, typingLines, diagnosticLines.toList, typeBeforeDiags) + (name, typingLines, diagnosticLines.toList, typeBeforeDiags, false) } } @@ -918,7 +918,13 @@ class DiffTests } } - def checkReply(replyQueue: mutable.Queue[(ReplHost.Reply, Str)], prefixLength: Int, errorOnly: Boolean = false): Unit = + def checkReply( + replyQueue: mutable.Queue[(ReplHost.Reply, Str)], + prefixLength: Int, + hide: Boolean, // Show nothing except errors if `hide` is true. + errorOnly: Boolean + ): Unit = { + val indent = " " * prefixLength replyQueue.headOption.foreach { case (head, log) => head match { case ReplHost.Error(isSyntaxError, content) => @@ -941,44 +947,46 @@ class DiffTests totalRuntimeErrors += 1 } content.linesIterator.foreach { s => output(" " + s) } - case ReplHost.Unexecuted(reason) => - output(" " * prefixLength + "= ") - output(" " * (prefixLength + 2) + reason) - case ReplHost.Result(result, _) if (!errorOnly) => + case ReplHost.Unexecuted(reason) if (!hide) => + output(indent + "= ") + output(indent + " " + reason) + case ReplHost.Result(result, _) if (!errorOnly && !hide) => result.linesIterator.zipWithIndex.foreach { case (line, i) => - if (i =:= 0) output(" " * prefixLength + "= " + line) - else output(" " * (prefixLength + 2) + line) + if (i =:= 0) output(indent + "= " + line) + else output(indent + " " + line) } - case ReplHost.Empty if (!errorOnly) => - output(" " * prefixLength + "= ") + case ReplHost.Empty if (!errorOnly && !hide) => + output(indent + "= ") case _ => () } outputLog(log) replyQueue.dequeue() } + } // If code generation fails, show the error message. executionResults match { case R(replies) => val replyQueue = mutable.Queue.from(replies) if (typerResults.isEmpty) - checkReply(replyQueue, 0, true) + checkReply(replyQueue, 0, false, true) else { - typerResults.foreach { case (name, typingLines, diagnosticLines, typeBeforeDiags) => - if (typeBeforeDiags) { - typingLines.foreach(output) - diagnosticLines.foreach(output) - } else { - diagnosticLines.foreach(output) - typingLines.foreach(output) + typerResults.foreach { case (name, typingLines, diagnosticLines, typeBeforeDiags, hide) => + if (!hide) { + if (typeBeforeDiags) { + typingLines.foreach(output) + diagnosticLines.foreach(output) + } else { + diagnosticLines.foreach(output) + typingLines.foreach(output) + } } - val prefixLength = name.length - checkReply(replyQueue, prefixLength) + checkReply(replyQueue, name.length, hide, false) } } case L(other) => // Print type checking results first. - if (!newDefs) typerResults.foreach { case (_, typingLines, diagnosticLines, typeBeforeDiags) => + if (!newDefs) typerResults.foreach { case (_, typingLines, diagnosticLines, typeBeforeDiags, _) => if (typeBeforeDiags) { typingLines.foreach(output) diagnosticLines.foreach(output) From 8ddfd7b7de0e8132dc9f0b438b4378113de2a05b Mon Sep 17 00:00:00 2001 From: Andong Fan <43923564+andongfan@users.noreply.github.com> Date: Mon, 2 Oct 2023 00:20:17 +0800 Subject: [PATCH 465/498] Annotate RegionDSL to simplify types (#184) --- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 475 ++++++++++++++++++ ...eRegionDSL.mls => SimpleRegionDSL_raw.mls} | 0 2 files changed, 475 insertions(+) create mode 100644 shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls rename shared/src/test/diff/ecoop23/{SimpleRegionDSL.mls => SimpleRegionDSL_raw.mls} (100%) diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls new file mode 100644 index 0000000000..26fa71ee9f --- /dev/null +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -0,0 +1,475 @@ +:NewDefs + + +// * Adapted example from Compositional Embeddings of Domain-Specific Languages (OOPSLA 2022) + + +// ******************* Initial System ******************* + +class Vector(val x: Int, val y: Int) +//│ class Vector(x: Int, y: Int) + +class Circle(radius: Int) +class Outside[out Region](a: Region) +class Union[out Region](a: Region, b: Region) +class Intersect[out Region](a: Region, b: Region) +class Translate[out Region](v: Vector, a: Region) +//│ class Circle(radius: Int) +//│ class Outside[Region](a: Region) +//│ class Union[Region](a: Region, b: Region) +//│ class Intersect[Region](a: Region, b: Region) +//│ class Translate[Region](v: Vector, a: Region) + +type BaseLang[T] = Circle | Intersect[T] | Union[T] | Outside[T] | Translate[T] +//│ type BaseLang[T] = Circle | Intersect[T] | Outside[T] | Translate[T] | Union[T] + +mixin SizeBase { + fun size(r) = + if r is + Circle(_) then 1 + Outside(a) then this.size(a) + 1 + Union(a, b) then this.size(a) + this.size(b) + 1 + Intersect(a, b) then this.size(a) + this.size(b) + 1 + Translate(_, a) then this.size(a) + 1 +} +//│ mixin SizeBase() { +//│ this: {size: 'a -> Int} +//│ fun size: (Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a]) -> Int +//│ } + +// ******************* Linguistic Reuse and Meta-Language Optimizations ******************* + +fun round(n: Num): Int = 0 +//│ fun round: (n: Num) -> Int + +fun go(x, offset) = + if x is 0 then Circle(1) + else + let shared = go(x - 1, round(offset / 2)) + Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) +//│ fun go: forall 'Region. (0 | Int & ~0, Int) -> 'Region +//│ where +//│ 'Region :> Circle | Union[Translate['Region]] + +// * Note that first-class polymorphism manages (correctly) to preserve the universal quantification +let circles = go(2, 1024) +//│ let circles: forall 'Region. 'Region +//│ where +//│ 'Region :> Circle | Union[Translate['Region]] +//│ circles +//│ = Union {} + +// ******************* Adding More Language Constructs ******************* + +class Univ() +class Empty() +class Scale[out Region](v: Vector, a: Region) +//│ class Univ() +//│ class Empty() +//│ class Scale[Region](v: Vector, a: Region) + +type ExtLang[T] = Univ | Empty | Scale[T] +//│ type ExtLang[T] = Empty | Scale[T] | Univ + +mixin SizeExt { + fun size(a) = + if a is + Univ then 1 + Empty then 1 + Scale(_, b) then this.size(b) + 1 + else super.size(a) +} +//│ mixin SizeExt() { +//│ super: {size: 'a -> 'b} +//│ this: {size: 'c -> Int} +//│ fun size: (Empty | Object & 'a & ~#Empty & ~#Scale & ~#Univ | Scale['c] | Univ) -> (Int | 'b) +//│ } + +type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] +//│ type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] + +module TestSize extends SizeBase, SizeExt { + fun size: RegionLang -> Int +} +//│ module TestSize { +//│ fun size: RegionLang -> Int +//│ } + +TestSize.size(Empty()) +//│ Int +//│ res +//│ = 1 + +TestSize.size(circles) +//│ Int +//│ res +//│ = 13 + +TestSize.size(Scale(Vector(1, 1), circles)) +//│ Int +//│ res +//│ = 14 + +// ******************* Adding a New Interpretation ******************* +// a stupid power (Int ** Int) implementation +fun pow(x, a) = + if a is 0 then 1 + else x * pow(x, a - 1) +//│ fun pow: (Int, 0 | Int & ~0) -> Int + +mixin Contains { + fun contains(a, p) = + if a is + Circle(r) then pow(p.x, 2) + pow(p.y, 2) <= pow(r, 2) + Outside(a) then not (this.contains(a, p)) + Union(lhs, rhs) then this.contains(lhs, p) || this.contains(rhs, p) + Intersect(lhs, rhs) then this.contains(lhs, p) && this.contains(rhs, p) + Translate(v, a) then this.contains(a, Vector(p.x - v.x, p.y - v.y)) +} +//│ mixin Contains() { +//│ this: {contains: ('a, 'b) -> Bool & ('c, Vector) -> 'd} +//│ fun contains: (Circle | Intersect['a] | Outside['a] | Translate['c] | Union['a], {x: Int, y: Int} & 'b) -> (Bool | 'd) +//│ } + +type BaseRegionLang = BaseLang[BaseRegionLang] +//│ type BaseRegionLang = BaseLang[BaseRegionLang] + +module TestContains extends Contains { + fun contains: (BaseRegionLang, Vector) -> Bool +} +//│ module TestContains { +//│ fun contains: (BaseRegionLang, Vector) -> Bool +//│ } + +TestContains.contains(Translate(Vector(0, 0), Circle(1)), Vector(0, 0)) +//│ Bool +//│ res +//│ = true + +TestContains.contains(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1)), Vector(0, 0)) +//│ Bool +//│ res +//│ = true + +TestContains.contains(circles, Vector(0, 0)) +//│ Bool +//│ res +//│ = false + +// ******************* Dependencies, Complex Interpretations, and Domain-Specific Optimizations ******************* + +fun toString(a: Int): Str = "foo" +fun concat(a: Str, b: Str): Str = a +//│ fun toString: (a: Int) -> Str +//│ fun concat: (a: Str, b: Str) -> Str + +mixin Text { + fun text(e) = + if e is + Circle(r) then concat("a circular region of radius ", toString(r)) + Outside(a) then concat("outside a region of size ", toString(this.size(a))) + Union then concat("the union of two regions of size ", toString(this.size(e))) + Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) + Translate then concat("a translated region of size ", toString(this.size(e))) +} +//│ mixin Text() { +//│ this: {size: (Intersect[nothing] | Translate['Region] | Union[nothing] | 'a) -> Int} +//│ fun text: (Circle | Intersect[anything] | Outside['a] | Translate['Region] | Union[anything]) -> Str +//│ } + +:e +module SizeText extends Text +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.173: Translate then concat("a translated region of size ", toString(this.size(e))) +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.172: Intersect then concat("the intersection of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.171: Union then concat("the union of two regions of size ", toString(this.size(e))) +//│ ╙── ^^^^^ +//│ ╔══[ERROR] Type `#SizeText & {text: ?a -> (?b | ?c | ?d | ?e | ?f)}` does not contain member `size` +//│ ║ l.170: Outside(a) then concat("outside a region of size ", toString(this.size(a))) +//│ ╙── ^^^^^ +//│ module SizeText { +//│ fun text: (Circle | Intersect[anything] | Outside[anything] | Translate[anything] | Union[anything]) -> Str +//│ } + +// * Note: this inferred type got *much worse* after this commit (field access type refinement) +module SizeText extends SizeBase, Text { + fun size: BaseRegionLang -> Int + fun text: BaseRegionLang -> Str +} +//│ module SizeText { +//│ fun size: BaseRegionLang -> Int +//│ fun text: BaseRegionLang -> Str +//│ } + +SizeText.text(circles) +//│ Str +//│ res +//│ = 'the union of two regions of size ' + +SizeText.size(circles) +//│ Int +//│ res +//│ = 13 + +SizeText.text(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) +//│ Str +//│ res +//│ = 'the intersection of two regions of size ' + +SizeText.size(Intersect(Translate(Vector(0, 0), Circle(1)), Circle(1))) +//│ Int +//│ res +//│ = 4 + +mixin IsUniv { + fun isUniv(e) = + if e is + Univ then true + Outside(a) then this.isEmpty(a) + Union(a, b) then this.isUniv(a) || this.isUniv(b) + Intersect(a, b) then this.isUniv(a) && this.isUniv(b) + Translate(_, a) then this.isUniv(a) + Scale(_, a) then this.isUniv(a) + else false +} +//│ mixin IsUniv() { +//│ this: {isEmpty: 'a -> 'b, isUniv: 'c -> Bool & 'd -> 'b} +//│ fun isUniv: (Intersect['c] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['a] | Scale['d] | Translate['d] | Union['c] | Univ) -> (Bool | 'b) +//│ } + +mixin IsEmpty { + fun isEmpty(e) = + if e is + Univ then true + Outside(a) then this.isUniv(a) + Union(a, b) then this.isEmpty(a) || this.isEmpty(b) + Intersect(a, b) then this.isEmpty(a) && this.isEmpty(b) + Translate(_, a) then this.isEmpty(a) + Scale(_, a) then this.isEmpty(a) + else false +} +//│ mixin IsEmpty() { +//│ this: {isEmpty: 'a -> Bool & 'b -> 'c, isUniv: 'd -> 'c} +//│ fun isEmpty: (Intersect['a] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['d] | Scale['b] | Translate['b] | Union['a] | Univ) -> (Bool | 'c) +//│ } + +module IsUnivIsEmpty extends IsUniv, IsEmpty { + fun isEmpty: RegionLang -> Bool + fun isUniv: RegionLang -> Bool +} +//│ module IsUnivIsEmpty { +//│ fun isEmpty: RegionLang -> Bool +//│ fun isUniv: RegionLang -> Bool +//│ } + +module IsUnivIsEmpty extends IsEmpty, IsUniv { + fun isEmpty: RegionLang -> Bool + fun isUniv: RegionLang -> Bool +} +//│ module IsUnivIsEmpty { +//│ fun isEmpty: RegionLang -> Bool +//│ fun isUniv: RegionLang -> Bool +//│ } + +IsUnivIsEmpty.isUniv(circles) +//│ Bool +//│ res +//│ = false + +IsUnivIsEmpty.isEmpty(circles) +//│ Bool +//│ res +//│ = false + +:e // Expected since the annotation only allows Lang variants +class Foo() +IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.290: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Foo` does not match type `BaseLang[RegionLang] | ExtLang[RegionLang]` +//│ ║ l.290: IsUnivIsEmpty.isEmpty(Scale(Vector(1, 2), Intersect(Foo(), circles))) +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.88: type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.88: type RegionLang = BaseLang[RegionLang] | ExtLang[RegionLang] +//│ ╙── ^^^^^^^^^^ +//│ class Foo() +//│ error | false | true +//│ res +//│ = false + +mixin Eliminate { + fun eliminate(e) = + if e is + Outside(Outside(a)) then this.eliminate(a) + Outside(a) then Outside(this.eliminate(a)) + Union(a, b) then Union(this.eliminate(a), this.eliminate(b)) + Intersect(a, b) then Intersect(this.eliminate(a), this.eliminate(b)) + Translate(v, a) then Translate(v, this.eliminate(a)) + Scale(v, a) then Scale(v, this.eliminate(a)) + else e +} +//│ mixin Eliminate() { +//│ this: { +//│ eliminate: 'a -> 'b & 'c -> 'Region & 'd -> 'Region0 & 'e -> 'Region1 & 'f -> 'Region2 & 'g -> 'Region3 +//│ } +//│ fun eliminate: (Intersect['e] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['c & (Object & ~#Outside | Outside['a])] | Scale['g] | Translate['f] | Union['d]) -> (Intersect['Region1] | Outside['Region] | Scale['Region3] | Translate['Region2] | Union['Region0] | 'b) +//│ } + +module TestElim extends Eliminate { + fun eliminate: RegionLang -> RegionLang +} +//│ module TestElim { +//│ fun eliminate: RegionLang -> RegionLang +//│ } + +TestElim.eliminate(Outside(Outside(Univ()))) +//│ RegionLang +//│ res +//│ = Univ {} + +TestElim.eliminate(circles) +//│ RegionLang +//│ res +//│ = Union {} + +fun mk(n) = if n is + 1 then Outside(mk(n)) + 2 then Union(mk(n), mk(n)) + 3 then Intersect(mk(n), mk(n)) + 4 then Translate(Vector(0, 0), mk(n)) + _ then Scale(Vector(0, 0), mk(n)) +//│ fun mk: forall 'Region. Object -> 'Region +//│ where +//│ 'Region :> Intersect['Region] | Outside['Region] | Scale['Region] | Translate['Region] | Union['Region] + +:re +TestElim.eliminate(mk(100)) +//│ RegionLang +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +// ************************************************************************* + +module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate { + fun contains: (BaseRegionLang, Vector) -> Bool + fun eliminate: RegionLang -> RegionLang + fun isEmpty: RegionLang -> Bool + fun isUniv: RegionLang -> Bool + fun size: RegionLang -> Int + fun text: BaseRegionLang -> Str +} +//│ module Lang { +//│ fun contains: (BaseRegionLang, Vector) -> Bool +//│ fun eliminate: RegionLang -> RegionLang +//│ fun isEmpty: RegionLang -> Bool +//│ fun isUniv: RegionLang -> Bool +//│ fun size: RegionLang -> Int +//│ fun text: BaseRegionLang -> Str +//│ } + +Lang.size(circles) +//│ Int +//│ res +//│ = 13 + +Lang.contains(circles, Vector(0, 0)) +//│ Bool +//│ res +//│ = false + +Lang.text(circles) +//│ Str +//│ res +//│ = 'the union of two regions of size ' + +Lang.isUniv(circles) +//│ Bool +//│ res +//│ = false + +Lang.isEmpty(circles) +//│ Bool +//│ res +//│ = false + +Lang.size(Lang.eliminate(circles)) +//│ Int +//│ res +//│ = 13 + +:re +Lang.size(mk(100)) +//│ Int +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:e +:re +Lang.contains(mk(100), Vector(0, 0)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.418: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` +//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.23: type BaseLang[T] = Circle | Intersect[T] | Union[T] | Outside[T] | Translate[T] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] +//│ ╙── ^^^^^^^^^^^^^^ +//│ error | false | true +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:e +:re +Lang.text(mk(100)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.438: Lang.text(mk(100)) +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[BaseRegionLang] | Outside[BaseRegionLang] | Translate[BaseRegionLang] | Union[BaseRegionLang]` +//│ ║ l.348: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.23: type BaseLang[T] = Circle | Intersect[T] | Union[T] | Outside[T] | Translate[T] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.134: type BaseRegionLang = BaseLang[BaseRegionLang] +//│ ╙── ^^^^^^^^^^^^^^ +//│ Str | error +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:re +Lang.isUniv(mk(100)) +//│ Bool +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:re +Lang.isEmpty(mk(100)) +//│ Bool +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:re +Lang.size(Lang.eliminate(mk(100))) +//│ Int +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls similarity index 100% rename from shared/src/test/diff/ecoop23/SimpleRegionDSL.mls rename to shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls From 2183bbca4cad551d8dfae7b737e0b1ee6ca25c99 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 2 Oct 2023 02:02:55 +0800 Subject: [PATCH 466/498] Stop parsing round brackets as arrays --- compiler/shared/test/diff/LiftType.mls | 14 +- compiler/shared/test/diff/LifterBlks.mls | 18 +- shared/src/main/scala/mlscript/NewLexer.scala | 1 + .../src/main/scala/mlscript/NewParser.scala | 44 +++- .../src/test/diff/codegen/ConstructorStmt.mls | 8 +- shared/src/test/diff/codegen/ValLet.mls | 28 ++- .../test/diff/ecoop23/PolymorphicVariants.mls | 30 +-- shared/src/test/diff/gadt/Exp1.mls | 2 +- shared/src/test/diff/gadt/Exp2.mls | 8 +- shared/src/test/diff/gadt/ThisMatching.mls | 4 +- shared/src/test/diff/nu/BadAliases.mls | 2 +- shared/src/test/diff/nu/CaseExpr.mls | 44 ++++ shared/src/test/diff/nu/DiamondInherit.mls | 10 +- shared/src/test/diff/nu/FlatMonads.mls | 2 +- shared/src/test/diff/nu/FunPatterns.mls | 17 +- shared/src/test/diff/nu/GADTMono.mls | 6 +- .../test/diff/nu/GenericClassInheritance.mls | 4 +- shared/src/test/diff/nu/GenericMixins.mls | 8 +- .../src/test/diff/nu/ImplicitMethodPolym.mls | 34 +-- .../diff/nu/InferredInheritanceTypeArgs.mls | 16 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 6 +- shared/src/test/diff/nu/Interfaces.mls | 36 +-- shared/src/test/diff/nu/Jonathan.mls | 16 +- shared/src/test/diff/nu/MemberConfusion.mls | 2 +- .../src/test/diff/nu/MemberIntersections.mls | 2 +- shared/src/test/diff/nu/Misc.mls | 118 +++++++-- shared/src/test/diff/nu/Mut.mls | 63 +++++ shared/src/test/diff/nu/NuAlexJ.mls | 2 +- shared/src/test/diff/nu/Parens.mls | 26 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 18 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 2 +- shared/src/test/diff/nu/Unit.mls | 225 ++++++++++++++---- shared/src/test/diff/nu/WeirdUnions.mls | 22 +- .../diff/nu/repro_PolymorphicVariants.mls | 6 +- shared/src/test/diff/parser/Arrays.mls | 15 +- shared/src/test/diff/parser/BasicSyntax.mls | 71 +++--- shared/src/test/diff/parser/Brackets.mls | 6 +- shared/src/test/diff/parser/Forall.mls | 12 +- shared/src/test/diff/parser/Fun.mls | 16 +- shared/src/test/diff/parser/IfThenElse.mls | 2 +- shared/src/test/diff/parser/Lambdas.mls | 40 ++-- shared/src/test/diff/parser/Misc.mls | 2 +- shared/src/test/diff/parser/NamedArrays.mls | 52 ++-- shared/src/test/diff/parser/Where.mls | 4 +- shared/src/test/diff/ucs/Humiliation.mls | 8 +- shared/src/test/diff/ucs/InterleavedLet.mls | 2 +- shared/src/test/diff/ucs/JSON.mls | 2 +- shared/src/test/diff/ucs/NestedBranches.mls | 71 +++--- shared/src/test/diff/ucs/NestedPattern.mls | 12 +- .../main/scala/ts2mls/types/Converter.scala | 2 +- ts2mls/js/src/test/diff/Array.d.mls | 4 +- ts2mls/js/src/test/diff/Dec.d.mls | 2 +- ts2mls/js/src/test/diff/HighOrderFunc.d.mls | 2 +- ts2mls/js/src/test/diff/InterfaceMember.d.mls | 2 +- ts2mls/js/src/test/diff/Intersection.d.mls | 4 +- ts2mls/js/src/test/diff/Optional.d.mls | 4 +- ts2mls/js/src/test/diff/Overload.d.mls | 4 +- ts2mls/js/src/test/diff/Tuple.d.mls | 28 +-- ts2mls/js/src/test/diff/Type.d.mls | 6 +- ts2mls/js/src/test/diff/Union.d.mls | 4 +- 60 files changed, 830 insertions(+), 391 deletions(-) diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index 3701bf2f2d..b8bfab5a85 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -5,7 +5,7 @@ class CTX{ class A {} fun foo(f: A => A): (A => A) => A = f(new A) } -//│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |=>| |A|)|#:| |(|A| |=>| |A|)| |=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| +//│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |#=>| |A|)|#:| |(|A| |#=>| |A|)| |#=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| //│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A([]) {},) : (A -> A) -> A}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), ‹›))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) @@ -21,9 +21,9 @@ class CTX{ class CTX(x, y){ class A{ fun foo = x} class B: A { fun foo = y} - fun foo(any: (A, B)): (B, A) = (any._2, any._1) + fun foo(any: [A, B]): [B, A] = [any._2, any._1] } -//│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |(|A|,| |B|)|)|#:| |(|B|,| |A|)| |#=| |(|any|._2|,| |any|._1|)|←|↵|}| +//│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |[|A|,| |B|]|)|#:| |[|B|,| |A|]| |#=| |[|any|._2|,| |any|._1|]|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '(' [A, B,] ')',) => '(' [(any)._2, (any)._1,] ')' : [B, A]}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) @@ -40,9 +40,9 @@ class CTX(x, y){ class CTX(x, y){ class A{ fun foo = x} class B: A { fun foo = y} - fun foo(any: {p1: A, p2: B}): (B, A) = (any.p2, any.p1) + fun foo(any: {p1: A, p2: B}): [B, A] = [any.p2, any.p1] } -//│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |{|p1|#:| |A|,| |p2|#:| |B|}|)|#:| |(|B|,| |A|)| |#=| |(|any|.p2|,| |any|.p1|)|←|↵|}| +//│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |{|p1|#:| |A|,| |p2|#:| |B|}|)|#:| |[|B|,| |A|]| |#=| |[|any|.p2|,| |any|.p1|]|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '{' {p1: A, p2: B} '}',) => '(' [(any).p2, (any).p1,] ')' : [B, A]}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) @@ -59,9 +59,9 @@ class CTX(x, y){ class CTX(x, y){ class A{ fun foo = x} class B { fun foo = y} - fun foo(any: (A, B)): ((B, A), A) = (any, any._1) + fun foo(any: [A, B]): [[B, A], A] = [any, any._1] } -//│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|‹|T|›| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |(|A|,| |B|‹|A|›|)|)|#:| |(|(|B|‹|A|›|,| |A|)|,| |A|)| |#=| |(|any|,| |any|._1|)|←|↵|}| +//│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|‹|T|›| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |[|A|,| |B|‹|A|›|]|)|#:| |[|[|B|‹|A|›|,| |A|]|,| |A|]| |#=| |[|any|,| |any|._1|]|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B‹T› {fun foo = y}; fun foo = (any: '(' [A, B‹A›,] ')',) => '(' [any, (any)._1,] ')' : [[B[A], A], A]}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A)))))), Asc(Bra(rcd = false, Tup(_: Var(any), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index b6246e2a69..2ca0c8b44b 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -14,16 +14,16 @@ fun foo = class A{ class B {} - fun foo(x: B) = (x:B) + fun foo(x: B) = (x : B) } -//│ |#class| |A|{|→|#class| |B| |{||}|↵|#fun| |foo|(|x|#:| |B|)| |#=| |(|x|#:|B|)|←|↵|}| -//│ Parsed: {class A {class B {}; fun foo = (x: B,) => '(' [x: B,] ')'}} +//│ |#class| |A|{|→|#class| |B| |{||}|↵|#fun| |foo|(|x|#:| |B|)| |#=| |(|x| |#:| |B|)|←|↵|}| +//│ Parsed: {class A {class B {}; fun foo = (x: B,) => '(' x : B ')'}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(x: Var(B)), Bra(rcd = false, Tup(x: Var(B)))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(x: Var(B)), Bra(rcd = false, Asc(Var(x), TypeName(B)))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {} -//│ class A$1([]) {fun foo = (x: A$1_B$2,) => '(' [x: A$1_B$2,] ')'} +//│ class A$1([]) {fun foo = (x: A$1_B$2,) => '(' x : A$1_B$2 ')'} //│ } //│ @@ -52,7 +52,7 @@ fun foo = class A(y){} let f = x => new A(0){fun bar = x+y} f(0) -//│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| +//│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |#=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| //│ Parsed: {class A(y,) {}; let f = (x,) => new A([0,]) {fun bar = +(x, y,)}; f(0,)} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), ‹fun bar = +(x, y,)›))), App(Var(f), Tup(_: IntLit(0)))) @@ -223,7 +223,7 @@ class A{ fun g: T => B => T } } -//│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f|#:| |T| |=>| |B| |=>| |T| |#=| |x| |=>| |y| |=>| |x|↵|#fun| |g|#:| |T| |=>| |B| |=>| |T|←|↵|}|←|↵|}| +//│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f|#:| |T| |#=>| |B| |#=>| |T| |#=| |x| |#=>| |y| |#=>| |x|↵|#fun| |g|#:| |T| |#=>| |B| |#=>| |T|←|↵|}|←|↵|}| //│ Parsed: {class A‹T› {class B {fun f = (x,) => (y,) => x : T -> B -> T; fun g: T -> B -> T}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, None, [], Asc(Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x))), Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T))))), NuFunDef(None, g, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) @@ -242,7 +242,7 @@ class Foo{ class StackedRectangleBoxes : RectangleBox & { size: N } class Bar: {any: RectangleBox => StackedRectangleBoxes} } -//│ |#class| |Foo|‹|T|›|{|→|#class| |RectangleBox|#:| |Box|‹|T|›| |&| |{| |breadth|#:| |T| |}|↵|#class| |StackedRectangleBoxes|‹|N|›| |#:| |RectangleBox|‹|T|›| |&| |{| |size|#:| |N| |}|↵|#class| |Bar|#:| |{|any|#:| |RectangleBox| |=>| |StackedRectangleBoxes|}|←|↵|}| +//│ |#class| |Foo|‹|T|›|{|→|#class| |RectangleBox|#:| |Box|‹|T|›| |&| |{| |breadth|#:| |T| |}|↵|#class| |StackedRectangleBoxes|‹|N|›| |#:| |RectangleBox|‹|T|›| |&| |{| |size|#:| |N| |}|↵|#class| |Bar|#:| |{|any|#:| |RectangleBox| |#=>| |StackedRectangleBoxes|}|←|↵|}| //│ Parsed: {class Foo‹T› {class RectangleBox: Box[T] & {breadth: T} {}; class StackedRectangleBoxes‹N›: RectangleBox[T] & {size: N} {}; class Bar: {any: RectangleBox -> StackedRectangleBoxes} {}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, Foo, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, RectangleBox, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, StackedRectangleBoxes, ((None,TypeName(N))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, Bar, (), Tup(), (), None, None, TypingUnit())))) @@ -265,7 +265,7 @@ fun ctx(a,b) = foo(new Lambda{ fun apply(x) = a+x }, b) -//│ |#class| |Func|‹|T|,| |U|›| |{|→|#fun| |apply|#:| |T| |=>| |U|←|↵|}|↵|#class| |Lambda|‹|T|,| |U|›| |#:| |Func|‹|T|,| |U|›| |{||}|↵|#fun| |ctx|(|a|,|b|)| |#=|→|#fun| |foo|(|f|#:| |Func|,| |x|)| |#=| |→|f|.apply|(|x|)|←|↵|foo|(|#new| |Lambda|{|→|#fun| |apply|(|x|)| |#=| |a|+|x|←|↵|}|,| |b|)|←| +//│ |#class| |Func|‹|T|,| |U|›| |{|→|#fun| |apply|#:| |T| |#=>| |U|←|↵|}|↵|#class| |Lambda|‹|T|,| |U|›| |#:| |Func|‹|T|,| |U|›| |{||}|↵|#fun| |ctx|(|a|,|b|)| |#=|→|#fun| |foo|(|f|#:| |Func|,| |x|)| |#=| |→|f|.apply|(|x|)|←|↵|foo|(|#new| |Lambda|{|→|#fun| |apply|(|x|)| |#=| |a|+|x|←|↵|}|,| |b|)|←| //│ Parsed: {class Func‹T, U› {fun apply: T -> U}; class Lambda‹T, U›: Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply(x,)}; foo(new Lambda([]) {fun apply = (x,) => +(a, x,)}, b,)}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, Func, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),TypeName(U)))))), NuTypeDef(class, Lambda, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit()), NuFunDef(None, ctx, None, [], Lam(Tup(_: Var(a), _: Var(b)), Blk(...)))) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index e8e3142149..7fd8f324fe 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -36,6 +36,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { private val isSymKeyword = Set( // "->", + "=>", "=", ":", ";;", diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 44f92dd2d7..8b90b53a4d 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -619,19 +619,39 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo exprCont(Var(opStr).withLoc(S(l1)), prec, allowNewlines = false) case (br @ BRACKETS(bk @ (Round | Square | Curly), toks), loc) :: _ => consume - val res = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO + val res = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) val bra = (bk, res) match { case (Curly, _) => Bra(true, Rcd(res.map { - case S(n) -> fld => n -> fld - case N -> (fld @ Fld(_, v: Var)) => v -> fld - case N -> fld => - err(( - msg"Record field should have a name" -> fld.value.toLoc :: Nil)) - Var("") -> fld + case S(n) -> fld => n -> fld + case N -> (fld @ Fld(_, v: Var)) => v -> fld + case N -> fld => + err(( + msg"Record field should have a name" -> fld.value.toLoc :: Nil)) + Var("") -> fld })) case (Round, (N, Fld(FldFlags(false, false, _), elt)) :: Nil) => Bra(false, elt) + case (Round, fs) => + yeetSpaces match { + case (KEYWORD("=>"), l1) :: _ => + consume + val e = expr(0) + Lam(Tup(res), e) + case (IDENT("->", true), l1) :: _ => + consume + val rhs = expr(opPrec("->")._2) + Lam(Tup(res), rhs) + case _ => + res match { + case Nil => + UnitLit(true) + case _ => + err(( + msg"Expected '=>' or '->' after this parameter section" -> S(loc) :: Nil)) + Tup(fs) + } + } case _ => // TODO actually reject round tuples? (except for function arg lists) Bra(false, Tup(res)) @@ -785,10 +805,16 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo final def exprCont(acc: Term, prec: Int, allowNewlines: Bool)(implicit et: ExpectThen, fe: FoundErr, l: Line): IfBody \/ Term = wrap(prec, s"`$acc`", allowNewlines) { l => cur match { - case (IDENT(opStr @ "=>", true), l0) :: (NEWLINE, l1) :: _ if opPrec(opStr)._1 > prec => + case (KEYWORD(opStr @ "=>"), l0) :: (NEWLINE, l1) :: _ if opPrec(opStr)._1 > prec => consume val rhs = Blk(typingUnit.entities) R(Lam(toParams(acc), rhs)) + case (KEYWORD(opStr @ "=>"), l0) :: _ if opPrec(opStr)._1 > prec => + consume + val rhs = expr(1) + // R(Lam(toParams(acc), rhs)) + val res = Lam(toParams(acc), rhs) + exprCont(res, prec, allowNewlines) case (IDENT(".", _), l0) :: (br @ BRACKETS(Square, toks), l1) :: _ => consume consume @@ -815,8 +841,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo err(msg"record literal expected here; found ${rhs.describe}" -> rhs.toLoc :: Nil) acc } - case "=>" => - Lam(toParams(acc), rhs) case ";" => Blk(acc :: rhs :: Nil) case _ => diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 7a8379d262..809f4c394e 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -202,11 +202,11 @@ class Bar { :js class Baz() { val x = 123 - log((1, x)) + log([1, x]) val y = - log((2, x)) + log([2, x]) x + 1 - log((3, y)) + log([3, y]) } //│ class Baz() { //│ val x: 123 @@ -262,7 +262,7 @@ class Baz() { //│ // End of generated code let baz = Baz() -log((baz.x, baz.y)) +log([baz.x, baz.y]) //│ let baz: Baz //│ undefined //│ baz diff --git a/shared/src/test/diff/codegen/ValLet.mls b/shared/src/test/diff/codegen/ValLet.mls index 0f8b1fc5e2..bdb97f41c7 100644 --- a/shared/src/test/diff/codegen/ValLet.mls +++ b/shared/src/test/diff/codegen/ValLet.mls @@ -224,15 +224,41 @@ fun f(val x: Int) = x + 1 //│ ╙── ^^^^^^ //│ fun f: (x: Int) -> Int +:pe :e (val x: 1) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.229: (val x: 1) +//│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] Cannot use `val` in this position -//│ ║ l.228: (val x: 1) +//│ ║ l.229: (val x: 1) //│ ╙── ^^^^ //│ [x: 1] //│ res //│ = [ 1 ] +:pe +:e +(val x: 1) => +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.242: (val x: 1) => +//│ ╙── ^ +//│ ╔══[ERROR] Cannot use `val` in this position +//│ ║ l.242: (val x: 1) => +//│ ╙── ^^^^ +//│ (x: 1) -> undefined +//│ res +//│ = [Function: res] + +:e +(val x: 1) => () +//│ ╔══[ERROR] Cannot use `val` in this position +//│ ║ l.254: (val x: 1) => () +//│ ╙── ^^^^ +//│ (x: 1) -> undefined +//│ res +//│ = [Function: res] + class D(x: Int) { let x = 1 } diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 965fa50bce..7729f38e32 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -61,12 +61,12 @@ mixin EvalLambda { let l1 = this.eval(sub, t1) let l2 = this.eval(sub, t2) if t1 is - Abs(x, t) then this.eval(Cons((x, l2), Nil), t) + Abs(x, t) then this.eval(Cons([x, l2], Nil), t) else App(l1, l2) Abs(x, t) then let s = gensym() - Abs(s, this.eval(Cons((x, Var(s)), sub), t)) + Abs(s, this.eval(Cons([x, Var(s)], sub), t)) else super.eval(sub, v) } @@ -104,7 +104,7 @@ Test1.eval(Nil, Abs("b", Var("a"))) //│ res //│ = Abs {} -Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) +Test1.eval(Cons(["c", Var("d")], Nil), App(Abs("b", Var("b")), Var("c"))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Var @@ -112,7 +112,7 @@ Test1.eval(Cons(("c", Var("d")), Nil), App(Abs("b", Var("b")), Var("c"))) //│ res //│ = Var {} -Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("b", Var("b")), Var("c"))) +Test1.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("b", Var("b")), Var("c"))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Abs[Var] | Var @@ -163,24 +163,24 @@ Test2.eval(Nil, Var("a")) //│ res //│ = Var {} -Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Var("a")) +Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Var("a")) //│ Abs[Var] | Numb | Var //│ res //│ = Var {} -Test2.eval(Cons(("a", Numb(1)), Nil), Var("a")) +Test2.eval(Cons(["a", Numb(1)], Nil), Var("a")) //│ Numb | Var //│ res //│ = Var {} // * This expected error shows that Test2 does not handle Abs expression inputs :e -Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.178: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.178: Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.178: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.131: if v is @@ -193,7 +193,7 @@ Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ Runtime error: //│ Error: non-exhaustive case expression -Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil), Add(Numb(1), Var("a"))) +Test2.eval(Cons(["a", Abs("d", Var("d"))], Nil), Add(Numb(1), Var("a"))) //│ Abs[Var] | Add[Numb | Var] | Numb | Var //│ res //│ = Add {} @@ -211,7 +211,7 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ 'd <: 'c & (Abs['c] | Object & ~#Abs) //│ 'a :> App['A] | Abs['A] -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Abs[Var] | Numb | Var @@ -219,7 +219,7 @@ Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) //│ res //│ = Abs {} -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) +Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Abs[Var] | Add[Numb | Var] | Numb | Var @@ -241,12 +241,12 @@ module Test3 extends EvalVar, EvalLambda, EvalExpr // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.244: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.244: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.244: Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil), Abs("a", Var("a"))) +//│ ║ l.244: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.131: if v is diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 13e6616f56..93212b89ab 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -3,7 +3,7 @@ class Exp[A]: Pair | Lit class Lit(n: Int) extends Exp[Int] -class Pair[L, R](val lhs: L, val rhs: R) extends Exp[(L, R)] +class Pair[L, R](val lhs: L, val rhs: R) extends Exp[[L, R]] //│ class Exp[A]: Lit | Pair[anything, anything] { //│ constructor() //│ } diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index 85c3d5bad3..55421697d5 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -3,7 +3,7 @@ class Exp[A]: Pair | Lit class Lit(val n: Int) extends Exp[Int] -class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] +class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] //│ class Exp[A]: Lit | Pair[?, ?] { //│ constructor() //│ } @@ -32,7 +32,7 @@ fun f(e) = if e is //│ ║ l.30: (e: Exp['X]) => f(e) //│ ║ ^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] +//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] //│ ╙── ^ //│ forall 'X 'L 'R. (e: Exp['X]) -> (Int | error | [Exp['L], Exp['R]]) //│ where @@ -56,7 +56,7 @@ fun f(e) = if e is //│ ║ l.50: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] +//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] //│ ╙── ^ //│ ╔══[ERROR] Type error in definition //│ ║ l.48: fun f(e) = if e is @@ -66,7 +66,7 @@ fun f(e) = if e is //│ ║ l.50: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `R` leaks out of its scope -//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[(L, R)] +//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] //│ ╙── ^ //│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> Int //│ where diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index aa9a52555b..bf3366b3c2 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -141,7 +141,7 @@ class Exp[A]: Pair | Lit { Pair then 1 } class Lit(n: Int) extends Exp[Int] -class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╔══[ERROR] Unhandled cyclic definition //│ ║ l.138: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -161,7 +161,7 @@ class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] //│ ║ l.141: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.144: class Pair[L, R](lhs: L, rhs: R) extends Exp[(L, R)] +//│ ║ l.144: class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╙── ^ //│ class Exp[A]: Lit | Pair[anything, anything] { //│ constructor() diff --git a/shared/src/test/diff/nu/BadAliases.mls b/shared/src/test/diff/nu/BadAliases.mls index c9ec5fd25f..18d8e11ef7 100644 --- a/shared/src/test/diff/nu/BadAliases.mls +++ b/shared/src/test/diff/nu/BadAliases.mls @@ -13,7 +13,7 @@ type A = A | Int // TODO check regularity // :e -type Foo[A] = { x: A, y: Foo[(A, A)] } +type Foo[A] = { x: A, y: Foo[[A, A]] } //│ type Foo[A] = {x: A, y: Foo[[A, A]]} diff --git a/shared/src/test/diff/nu/CaseExpr.mls b/shared/src/test/diff/nu/CaseExpr.mls index 79026d0fbf..59407e65c9 100644 --- a/shared/src/test/diff/nu/CaseExpr.mls +++ b/shared/src/test/diff/nu/CaseExpr.mls @@ -122,3 +122,47 @@ case then 1 else 0 //│ = [Function: res] + +// TODO: + +:pe +:e +case x, y then x + y +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'case'; found reference instead +//│ ║ l.130: case x, y then x + y +//│ ║ ^ +//│ ╟── Note: 'case' expression starts here: +//│ ║ l.130: case x, y then x + y +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Expected end of input; found comma instead +//│ ║ l.130: case x, y then x + y +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.130: case x, y then x + y +//│ ╙── ^ +//│ anything -> error +//│ Code generation encountered an error: +//│ unresolved symbol x + +:pe +:e +case (x, y) then x + y +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.149: case (x, y) then x + y +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] type identifier not found: Tuple#2 +//│ ╙── +//│ nothing -> error +//│ Code generation encountered an error: +//│ unknown match case: Tuple#2 + +:e // * FIXME[UCS] +case [x, y] then x + y +//│ ╔══[ERROR] type identifier not found: Tuple#2 +//│ ╙── +//│ nothing -> error +//│ Code generation encountered an error: +//│ unknown match case: Tuple#2 + + + diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index a93a3e02bf..b65d6e0b18 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -133,7 +133,7 @@ module Bar extends T1, Foo[Int | Str] { trait Base[A] { fun foo: A;; fun bar: A -> A } trait Derived1[A] extends Base[A] -trait Derived2 extends Base[(Int | Str, Int | Str)] +trait Derived2 extends Base[[Int | Str, Int | Str]] //│ trait Base[A] { //│ fun bar: A -> A //│ fun foo: A @@ -150,8 +150,8 @@ trait Derived2 extends Base[(Int | Str, Int | Str)] //│ 'A0 := [Int | Str, Int | Str] //│ 'A := A -class Final extends Derived1[(Int, Int)], Derived2 { - fun foo = (123, 456) +class Final extends Derived1[[Int, Int]], Derived2 { + fun foo = [123, 456] fun bar([x, y]) = [error, error] } //│ class Final extends Base, Derived1, Derived2 { @@ -160,8 +160,8 @@ class Final extends Derived1[(Int, Int)], Derived2 { //│ fun foo: [123, 456] //│ } -class Final extends Derived1[(Int, Int)], Derived2 { - fun foo = (123, 456) +class Final extends Derived1[[Int, Int]], Derived2 { + fun foo = [123, 456] fun bar([x, y]) = [y, x] } //│ class Final extends Base, Derived1, Derived2 { diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index b229fe39c9..25b457e78f 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -401,7 +401,7 @@ declare fun printLine: Str -> IO[()] //│ declare trait IO[A]: forall 'b. (A -> IO['b]) -> IO['b] { //│ fun run: A //│ } -//│ fun printLine: Str -> IO[[]] +//│ fun printLine: Str -> IO[undefined] //│ fun pure: forall 'a. 'a -> IO['a] //│ fun readInt: IO[Int] diff --git a/shared/src/test/diff/nu/FunPatterns.mls b/shared/src/test/diff/nu/FunPatterns.mls index ff752832b8..dc160060f6 100644 --- a/shared/src/test/diff/nu/FunPatterns.mls +++ b/shared/src/test/diff/nu/FunPatterns.mls @@ -8,25 +8,32 @@ fun f(x, y) = x + y // FIXME array pattern...?! fun f1([x, y]) = x + y fun f2([x, y],) = x + y -fun f3([(x, y,),],) = x + y +fun f3([[x, y,],],) = x + y //│ fun f1: ([Int, Int]) -> Int //│ fun f2: ([Int, Int]) -> Int //│ fun f3: ([[Int, Int]]) -> Int +:pe +fun f3([(x, y,),],) = x + y +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.17: fun f3([(x, y,),],) = x + y +//│ ╙── ^^^^^^^ +//│ fun f3: ([[Int, Int]]) -> Int + class Pair(lhs: Int, rhs: Int) //│ class Pair(lhs: Int, rhs: Int) -// TODO +:e // * TODO fun f(Pair(x, y)) = x + y //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.21: fun f(Pair(x, y)) = x + y +//│ ║ l.28: fun f(Pair(x, y)) = x + y //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: x -//│ ║ l.21: fun f(Pair(x, y)) = x + y +//│ ║ l.28: fun f(Pair(x, y)) = x + y //│ ╙── ^ //│ ╔══[ERROR] identifier not found: y -//│ ║ l.21: fun f(Pair(x, y)) = x + y +//│ ║ l.28: fun f(Pair(x, y)) = x + y //│ ╙── ^ //│ fun f: error -> Int diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 2d33db314d..83317fcbf8 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -5,9 +5,9 @@ class LitInt(n: Int) extends Expr[Int] class LitBool(b: Bool) extends Expr[Bool] class Add(x: Expr[Int], y: Expr[Int]) extends Expr[Int] class Cond[T](p: Expr[Bool], t: Expr[T], e: Expr[T]) extends Expr[T] -class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr[(S, T)] -class Fst[S, T](p: Expr[(S, T)]) extends Expr[S] -class Snd[S, T](p: Expr[(S, T)]) extends Expr[T] +class Pair[S, T](a: Expr[S], b: Expr[T]) extends Expr[[S, T]] +class Fst[S, T](p: Expr[[S, T]]) extends Expr[S] +class Snd[S, T](p: Expr[[S, T]]) extends Expr[T] //│ trait Expr[A]: Add | Cond[?] | Fst[?, ?] | LitBool | LitInt | Pair[?, ?] | Snd[?, ?] //│ class LitInt(n: Int) extends Expr //│ class LitBool(b: Bool) extends Expr diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 43eb81cc41..dda26819b3 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -103,7 +103,7 @@ new C1 : C1[Int] mixin M1[A] { fun f1(x: A): A = x - fun f2(x: A): (A, A) = (x, x) + fun f2(x: A): [A, A] = [x, x] } //│ mixin M1[A]() { //│ fun f1: (x: A) -> A @@ -119,7 +119,7 @@ class A1 extends M1 { //│ fun f2: (x: 'A) -> ['A, 'A] //│ } -class A2[S, T] extends M1[(S, T)] +class A2[S, T] extends M1[[S, T]] //│ class A2[S, T] { //│ constructor() //│ fun f1: (x: [S, T]) -> [S, T] diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index d3f03373d6..ecf62c1795 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -112,8 +112,8 @@ class C[A] extends Test[Array[A]] { mixin Test[A] { fun foo: A -> A fun foo = id - fun bar: (A, A) - fun bar = (this.arg, this.arg) + fun bar: [A, A] + fun bar = [this.arg, this.arg] fun baz = foo(this.arg) } //│ mixin Test[A]() { @@ -163,10 +163,10 @@ class C extends Test { // it also fails with Test[Int]... //│ ║ l.117: fun baz = foo(this.arg) //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.116: fun bar = (this.arg, this.arg) +//│ ║ l.116: fun bar = [this.arg, this.arg] //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.116: fun bar = (this.arg, this.arg) +//│ ║ l.116: fun bar = [this.arg, this.arg] //│ ╙── ^^^^ //│ class C { //│ constructor() diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 1c813490f2..64f05835b3 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -79,7 +79,7 @@ module M extends Mx { :e module M extends Mx { - fun id2(x) = (x, x) + fun id2(x) = [x, x] this.id1(0) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation @@ -92,8 +92,8 @@ module M extends Mx { // * Notice that `id1` is no longer generalized! module M extends Mx { - fun id2: 'a => ('a, 'a) - fun id2(x) = (x, x) + fun id2: 'a => ['a, 'a] + fun id2(x) = [x, x] this.id1(0) } //│ module M { @@ -106,14 +106,14 @@ module M extends Mx { :e // FIXME class C { virtual fun id1(x) = x - fun f = (this.id1(true), this.id1(0)) + fun f = [this.id1(true), this.id1(0)] fun id2(x) = x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.109: fun f = (this.id1(true), this.id1(0)) +//│ ║ l.109: fun f = [this.id1(true), this.id1(0)] //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.109: fun f = (this.id1(true), this.id1(0)) +//│ ║ l.109: fun f = [this.id1(true), this.id1(0)] //│ ╙── ^^^^ //│ class C { //│ constructor() @@ -143,6 +143,9 @@ module M extends C { module M extends C { fun g = (this.id2(true), this.id2(0)) } +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.144: fun g = (this.id2(true), this.id2(0)) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.144: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ @@ -182,11 +185,11 @@ module M extends C { fun id1 = succ } //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.182: fun id1 = succ +//│ ║ l.185: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╙── variable of type `?a` is not an instance of type `Int` //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.182: fun id1 = succ +//│ ║ l.185: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from reference: @@ -212,8 +215,11 @@ M.id1 // FIXME? parsing/semantics of this, currently treated as a named tuple... (M: C) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.217: (M: C) +//│ ╙── ^^^^^^ //│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword -//│ ║ l.214: (M: C) +//│ ║ l.217: (M: C) //│ ╙── ^ //│ [M: () -> C] //│ res @@ -233,19 +239,19 @@ module M { fun oops(x) = m := x } //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword in expression position -//│ ║ l.232: mut val m = None +//│ ║ l.238: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.232: mut val m = None +//│ ║ l.238: mut val m = None //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: := -//│ ║ l.233: fun oops(x) = m := x +//│ ║ l.239: fun oops(x) = m := x //│ ╙── ^^ //│ ╔══[ERROR] identifier not found: m -//│ ║ l.233: fun oops(x) = m := x +//│ ║ l.239: fun oops(x) = m := x //│ ╙── ^ //│ ╔══[ERROR] Unexpected equation in this position -//│ ║ l.232: mut val m = None +//│ ║ l.238: mut val m = None //│ ╙── ^^^^^^^^ //│ module M { //│ fun oops: anything -> error diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 8f834c3601..9bbf4abec9 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -2,8 +2,8 @@ mixin Test[A] { - fun bar: (A, A) - fun bar = (this.a, this.a) + fun bar: [A, A] + fun bar = [this.a, this.a] } //│ mixin Test[A]() { //│ this: {a: A} @@ -18,20 +18,20 @@ class A(val a: Int) extends Test :e class A(a: Int) extends Test //│ ╔══[ERROR] Parameter 'a' cannot tbe accessed as a field -//│ ║ l.6: fun bar = (this.a, this.a) +//│ ║ l.6: fun bar = [this.a, this.a] //│ ╙── ^^ //│ ╔══[ERROR] Parameter 'a' cannot tbe accessed as a field -//│ ║ l.6: fun bar = (this.a, this.a) +//│ ║ l.6: fun bar = [this.a, this.a] //│ ╙── ^^ //│ class A(a: Int) { //│ fun bar: [Int, Int] //│ } mixin Test2[S, T] { - fun x: (S, T) - fun x = (this.s, this.t) - fun fb: S => (S, S) - fun fb(h: S) = (this.s, h) + fun x: [S, T] + fun x = [this.s, this.t] + fun fb: S => [S, S] + fun fb(h: S) = [this.s, h] } //│ mixin Test2[S, T]() { //│ this: {s: S, t: T} diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index b5d084c994..a3e0aff6c7 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -16,7 +16,7 @@ trait Nat extends Into[Int] //│ 'T := Int trait Product[A, B] extends Into[A] { - let pair: (A, B) + let pair: [A, B] } //│ trait Product[A, B] extends Into { //│ fun Into: 'T @@ -25,14 +25,14 @@ trait Product[A, B] extends Into[A] { //│ where //│ 'T := A -class TwoInts(val pair: (Int, Int)) extends Product[Int, Int] { +class TwoInts(val pair: [Int, Int]) extends Product[Int, Int] { fun Into = pair._1 + pair._2 } //│ class TwoInts(pair: [Int, Int]) extends Into, Product { //│ fun Into: Int //│ } -let i2 = TwoInts((1,2)) +let i2 = TwoInts([1, 2]) //│ let i2: TwoInts i2: Product[Int, Int] diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index cd0cf441ba..2d7d8a4212 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -473,13 +473,13 @@ fun f(x: Base) = if x is //│ fun f: (x: Base) -> (0 | 1) trait Base: Foo | Bar -class Foo[A](val aa: (A, A)) extends Base +class Foo[A](val aa: [A, A]) extends Base class Bar[B](f: B => B) extends Base //│ trait Base: Bar[?] | Foo[anything] //│ class Foo[A](aa: [A, A]) extends Base //│ class Bar[B](f: B -> B) extends Base -let f: Foo = Foo((1, 2)) +let f: Foo = Foo([1, 2]) //│ let f: Foo[anything] //│ f //│ = Foo {} @@ -910,7 +910,7 @@ class Der1 extends Base[Int] { fun f(x) = x + 1 } //│ fun f: Int -> Int //│ } -class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (x, y) } +class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [x, y] } //│ class Der2[A, B] extends Base { //│ constructor() //│ fun f: forall 'a 'b. (['a, 'b]) -> ['a, 'b] @@ -927,7 +927,7 @@ trait BInt extends Base[Int] { //│ fun f: nothing //│ } -trait BPar[T] extends Base[(Int,T)] +trait BPar[T] extends Base[[Int, T]] //│ trait BPar[T] extends Base { //│ fun f: 'A -> 'A //│ } @@ -943,16 +943,16 @@ let bp: BPar[Bool] //│ bp //│ = -bp: Base[(Int, Bool)] +bp: Base[[Int, Bool]] //│ Base[[Int, Bool]] //│ res //│ = //│ bp is not implemented :e -bp: Base[(Int, Int)] +bp: Base[[Int, Int]] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.953: bp: Base[(Int, Int)] +//│ ║ l.953: bp: Base[[Int, Int]] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -972,7 +972,7 @@ bp.f //│ = //│ bp is not implemented -fun fb[T](x: Base[(Int, T)], y: T) = x.f((1, y)) +fun fb[T](x: Base[[Int, T]], y: T) = x.f([1, y]) //│ fun fb: forall 'T. (x: Base[[Int, 'T]], y: 'T) -> [Int, 'T] fb(bp, false) @@ -982,7 +982,7 @@ fb(bp, false) //│ bp is not implemented class CP() extends BPar[Int] { - fun f(x) = (x._2, x._1) + fun f(x) = [x._2, x._1] } //│ class CP() extends BPar, Base { //│ fun f: forall 'a 'b. {_1: 'a, _2: 'b} -> ['b, 'a] @@ -1029,30 +1029,30 @@ class DerBad1 extends Base[Int, Int] //│ 'A := Int :e -class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.1032: class Der2[A, B] extends Base[(A, B)] { fun f((x, y)) = (y, x) } +//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ constructor() diff --git a/shared/src/test/diff/nu/Jonathan.mls b/shared/src/test/diff/nu/Jonathan.mls index e1dfa8f34f..16753fe9f9 100644 --- a/shared/src/test/diff/nu/Jonathan.mls +++ b/shared/src/test/diff/nu/Jonathan.mls @@ -22,7 +22,7 @@ module Block // * Some example functions fun println(x: anything): Effectful[(), IO] fun readLine: Effectful[Str, IO | Block] -//│ fun println: (x: anything) -> Effectful[[], IO] +//│ fun println: (x: anything) -> Effectful[undefined, IO] //│ fun readLine: Effectful[Str, Block | IO] @@ -39,12 +39,12 @@ fun f(x) = x : NonBlocking fun onMousePressed(listener) = let l(e) = listener(e) : NonBlocking l(0).flatMap of a => l(1).flatMap of b => pure of () -//│ fun onMousePressed: forall 'a. ((0 | 1) -> NonBlocking[anything, 'a]) -> Effectful[[], 'a & ~Block] +//│ fun onMousePressed: forall 'a. ((0 | 1) -> NonBlocking[anything, 'a]) -> Effectful[undefined, 'a & ~Block] // * OK: `println` does not block onMousePressed(event => println("Clicked!")) -//│ Effectful[[], IO & ~Block] +//│ Effectful[undefined, IO & ~Block] // * NOT OK: `readLine` blocks :e @@ -55,7 +55,7 @@ onMousePressed(event => readLine.flatMap(println)) //│ ╟── type `Block` does not match type `~Block` //│ ║ l.24: fun readLine: Effectful[Str, IO | Block] //│ ╙── ^^^^^ -//│ Effectful[[], IO & ~Block] | error +//│ Effectful[undefined, IO & ~Block] | error class Event @@ -72,14 +72,14 @@ module Register fun onMousePressed(listener) = let l(e: MouseEvent) = listener(e) : Effectful[(), 'e \ Block \ Register] () -//│ fun onMousePressed: (MouseEvent -> Effectful[[], ~Block & ~Register]) -> [] +//│ fun onMousePressed: (MouseEvent -> Effectful[undefined, ~Block & ~Register]) -> undefined // def onMouseClick ( f : Event -> Unit \ { ef - Register }): Unit \ { Register } fun onMouseClick(f: Event -> Effectful[(), 'e \ Register]): Effectful[(), Register] -//│ fun onMouseClick: (f: Event -> Effectful[[], ~Register]) -> Effectful[[], Register] +//│ fun onMouseClick: (f: Event -> Effectful[undefined, ~Register]) -> Effectful[undefined, Register] onMouseClick of ev => pure of () -//│ Effectful[[], Register] +//│ Effectful[undefined, Register] :e onMouseClick of ev => @@ -95,6 +95,6 @@ onMouseClick of ev => //│ ╟── type `Register` does not match type `~Register` //│ ║ l.78: fun onMouseClick(f: Event -> Effectful[(), 'e \ Register]): Effectful[(), Register] //│ ╙── ^^^^^^^^ -//│ Effectful[[], Register] | error +//│ Effectful[undefined, Register] | error diff --git a/shared/src/test/diff/nu/MemberConfusion.mls b/shared/src/test/diff/nu/MemberConfusion.mls index f63c6da4fc..3609783f7f 100644 --- a/shared/src/test/diff/nu/MemberConfusion.mls +++ b/shared/src/test/diff/nu/MemberConfusion.mls @@ -46,7 +46,7 @@ class C(val a: Int, val b: Int) extends B, M //│ } let c = C(2, 3) -(c.a, c.b) +[c.a, c.b] //│ let c: C //│ [Int, "hi"] //│ c diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index 04f116577c..787e530bbf 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -4,7 +4,7 @@ trait T1 { fun f[A]: A -> A } -trait T2 { fun f[B, C]: (B, C) -> (B, C) } +trait T2 { fun f[B, C]: (B, C) -> [B, C] } trait T3 extends T1, T2 //│ trait T1 { //│ fun f: forall 'A. 'A -> 'A diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index f30609214a..835cdbd471 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -89,57 +89,133 @@ f([1, 2]) +:pe let f = ((x, y)) => x + y -//│ let f: ([Int, Int]) -> Int +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.93: let f = ((x, y)) => x + y +//│ ╙── ^^^^^^ +//│ let f: (Int, Int) -> Int //│ f //│ = [Function: f5] -:e f(1, 2) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.98: f(1, 2) -//│ ║ ^^^^^^^ -//│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` -//│ ║ l.98: f(1, 2) -//│ ╙── ^^^^^^ -//│ Int | error +//│ Int //│ res -//│ Runtime error: -//│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) - - +//│ = 3 +:pe +:e f((1, 2)) -//│ Int +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.108: f((1, 2)) +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.108: f((1, 2)) +//│ ║ ^^^^^^^^^ +//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` +//│ ║ l.108: f((1, 2)) +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.93: let f = ((x, y)) => x + y +//│ ╙── ^^^^^^ +//│ Int | error //│ res -//│ = 3 +//│ = '1,2undefined' +:e f([1, 2]) -//│ Int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.126: f([1, 2]) +//│ ║ ^^^^^^^^^ +//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` +//│ ║ l.126: f([1, 2]) +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.93: let f = ((x, y)) => x + y +//│ ╙── ^^^^^^ +//│ Int | error //│ res -//│ = 3 +//│ = '1,2undefined' + +:e +f[1, 2] +//│ ╔══[ERROR] Type application syntax is not yet supported +//│ ║ l.141: f[1, 2] +//│ ╙── ^^^^^^^ +//│ (Int, Int) -> Int +//│ res +//│ = [Function: f5] -// TODO don't parse as tuple arg + +:pe let f = (((x, y))) => x + y +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.151: let f = (((x, y))) => x + y +//│ ╙── ^^^^^^ //│ let f: ([Int, Int]) -> Int //│ f //│ = [Function: f6] -// TODO parse as tuple arg! + +// * TODO maybe parse as type lambda? let f = [x, y] => x + y //│ let f: (Int, Int) -> Int //│ f //│ = [Function: f7] +// :e // TODO f(1, 2) //│ Int //│ res //│ = 3 -// TODO... +:e +f([1, 2]) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.173: f([1, 2]) +//│ ║ ^^^^^^^^^ +//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` +//│ ║ l.173: f([1, 2]) +//│ ║ ^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.161: let f = [x, y] => x + y +//│ ╙── ^^^^ +//│ Int | error +//│ res +//│ = '1,2undefined' + + +let f = ([x, y]) => x + y +//│ let f: ([Int, Int]) -> Int +//│ f +//│ = [Function: f8] + +f([1, 2]) +//│ Int +//│ res +//│ = 3 + +:e +f(1, 2) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.199: f(1, 2) +//│ ║ ^^^^^^^ +//│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` +//│ ║ l.199: f(1, 2) +//│ ╙── ^^^^^^ +//│ Int | error +//│ res +//│ Runtime error: +//│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) + + let f = [[[x, y]]] => x + y //│ let f: ([[Int, Int]]) -> Int //│ f -//│ = [Function: f8] +//│ = [Function: f9] +f([[1, 2]]) +//│ Int +//│ res +//│ = 3 diff --git a/shared/src/test/diff/nu/Mut.mls b/shared/src/test/diff/nu/Mut.mls index 6ad699d30e..fdb3fe11ef 100644 --- a/shared/src/test/diff/nu/Mut.mls +++ b/shared/src/test/diff/nu/Mut.mls @@ -81,38 +81,101 @@ v1.x <- 1 //│ error +:pe let v2: (mut Int) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.85: let v2: (mut Int) +//│ ╙── ^^^^^^^^^ //│ let v2: [mut Int] //│ v2 //│ = +:pe let v2 = (mut 1) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.94: let v2 = (mut 1) +//│ ╙── ^^^^^^^ //│ let v2: [mut 'a] //│ where //│ 'a :> 1 //│ v2 //│ = [ 1 ] +:pe let v2: (mut x: Int) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.105: let v2: (mut x: Int) +//│ ╙── ^^^^^^^^^^^^ //│ let v2: [mut x: Int] //│ v2 //│ = +:pe let v2 = (mut 1) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.114: let v2 = (mut 1) +//│ ╙── ^^^^^^^ //│ let v2: [mut 'a] //│ where //│ 'a :> 1 //│ v2 //│ = [ 1 ] +:pe let v2 = (mut x: 1) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.125: let v2 = (mut x: 1) +//│ ╙── ^^^^^^^^^^ //│ let v2: [mut x: 'x] //│ where //│ 'x :> 1 //│ v2 //│ = [ 1 ] +:pe let v2 = (mut y: 1) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.136: let v2 = (mut y: 1) +//│ ╙── ^^^^^^^^^^ +//│ let v2: [mut y: 'y] +//│ where +//│ 'y :> 1 +//│ v2 +//│ = [ 1 ] + + +let v2: [mut Int] +//│ let v2: [mut Int] +//│ v2 +//│ = + +let v2 = [mut 1] +//│ let v2: [mut 'a] +//│ where +//│ 'a :> 1 +//│ v2 +//│ = [ 1 ] + +let v2: [mut x: Int] +//│ let v2: [mut x: Int] +//│ v2 +//│ = + +let v2 = [mut 1] +//│ let v2: [mut 'a] +//│ where +//│ 'a :> 1 +//│ v2 +//│ = [ 1 ] + +let v2 = [mut x: 1] +//│ let v2: [mut x: 'x] +//│ where +//│ 'x :> 1 +//│ v2 +//│ = [ 1 ] + +let v2 = [mut y: 1] //│ let v2: [mut y: 'y] //│ where //│ 'y :> 1 diff --git a/shared/src/test/diff/nu/NuAlexJ.mls b/shared/src/test/diff/nu/NuAlexJ.mls index 726c5c6173..d660e2fe96 100644 --- a/shared/src/test/diff/nu/NuAlexJ.mls +++ b/shared/src/test/diff/nu/NuAlexJ.mls @@ -1,7 +1,7 @@ :NewDefs -fun foo(x) = (x, x) +fun foo(x) = [x, x] //│ fun foo: forall 'a. 'a -> ['a, 'a] id diff --git a/shared/src/test/diff/nu/Parens.mls b/shared/src/test/diff/nu/Parens.mls index 63100f80b0..bcca7fd5af 100644 --- a/shared/src/test/diff/nu/Parens.mls +++ b/shared/src/test/diff/nu/Parens.mls @@ -2,9 +2,9 @@ () -//│ [] +//│ undefined //│ res -//│ = [] +//│ = undefined :pe (,) @@ -28,29 +28,37 @@ //│ res //│ = 1 +:pe (1, 2) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.32: (1, 2) +//│ ╙── ^^^^^^ //│ [1, 2] //│ res //│ = [ 1, 2 ] +:pe (1, 2,) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.41: (1, 2,) +//│ ╙── ^^^^^^^ //│ [1, 2] //│ res //│ = [ 1, 2 ] let x: () -//│ let x: [] +//│ let x: undefined //│ x //│ = :pe let x: (,) //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.48: let x: (,) +//│ ║ l.56: let x: (,) //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.48: let x: (,) +//│ ║ l.56: let x: (,) //│ ╙── ^ //│ let x: undefined //│ x @@ -66,12 +74,20 @@ let x: (1,) //│ x //│ = +:pe let x: (1, 2) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.78: let x: (1, 2) +//│ ╙── ^^^^^^ //│ let x: [1, 2] //│ x //│ = +:pe let x: (1, 2,) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.87: let x: (1, 2,) +//│ ╙── ^^^^^^^ //│ let x: [1, 2] //│ x //│ = diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index 8ec2180954..bc648bf6bf 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -84,12 +84,12 @@ mixin EvalLambda { let l1 = this.eval(sub, t1) let l2 = this.eval(sub, t2) if t1 is - Abs(x, t) then this.eval(Cons((x, l2), Nil()), t) + Abs(x, t) then this.eval(Cons([x, l2], Nil()), t) else App(l1, l2) Abs(x, t) then let s = gensym() - Abs(s, this.eval(Cons((x, Var(s)), sub), t)) + Abs(s, this.eval(Cons([x, Var(s)], sub), t)) else super.eval(sub, v) } @@ -122,13 +122,13 @@ Test1.eval(Nil(), Abs("b", Var("a"))) //│ 'A :> 'a | Var //│ 'a :> App['A] | Abs['A] -Test1.eval(Cons(("c", Var("d")), Nil()), App(Abs("b", Var("b")), Var("c"))) +Test1.eval(Cons(["c", Var("d")], Nil()), App(Abs("b", Var("b")), Var("c"))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Var //│ 'a :> App['A] | Abs['A] -Test1.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("b", Var("b")), Var("c"))) +Test1.eval(Cons(["c", Abs("d", Var("d"))], Nil()), App(Abs("b", Var("b")), Var("c"))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Abs[Var] | Var @@ -175,13 +175,13 @@ module Test2 extends EvalVar, EvalExpr Test2.eval(Nil(), Var("a")) //│ Numb | Var -Test2.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Var("a")) +Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil()), Var("a")) //│ Abs[Var] | Numb | Var -Test2.eval(Cons(("a", Numb(1)), Nil()), Var("a")) +Test2.eval(Cons(["a", Numb(1)], Nil()), Var("a")) //│ Numb | Var -Test2.eval(Cons(("a", Abs("d", Var("d"))), Nil()), Add(Numb(1), Var("a"))) +Test2.eval(Cons(["a", Abs("d", Var("d"))], Nil()), Add(Numb(1), Var("a"))) //│ Abs[Var] | Add[Numb | Var] | Numb | Var module Test3 extends EvalVar, EvalExpr, EvalLambda @@ -196,13 +196,13 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ 'c <: Abs['c] | App['c & (Abs['c] | Object & ~#Abs)] | Object & 'd & ~#Abs & ~#App //│ 'a :> App['A] | Abs['A] -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), Abs("a", Var("a"))) +Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil()), Abs("a", Var("a"))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Abs[Var] | Numb | Var //│ 'a :> App['A] | Abs['A] -Test3.eval(Cons(("c", Abs("d", Var("d"))), Nil()), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) +Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil()), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) //│ forall 'a. 'A | 'a //│ where //│ 'A :> 'a | Abs[Var] | Add[Numb | Var] | Numb | Var diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index 48d7148210..d101afb6a9 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -158,7 +158,7 @@ class Impl2() extends Base2, Foo[Int] { trait Test1[A] { fun x: A } -trait Test2[A]: Test1[(A, A)] +trait Test2[A]: Test1[[A, A]] //│ trait Test1[A] { //│ fun x: A //│ } diff --git a/shared/src/test/diff/nu/Unit.mls b/shared/src/test/diff/nu/Unit.mls index 9ad9617773..d34d64fdf6 100644 --- a/shared/src/test/diff/nu/Unit.mls +++ b/shared/src/test/diff/nu/Unit.mls @@ -2,80 +2,221 @@ () -//│ [] +//│ undefined //│ res -//│ = [] +//│ = undefined fun x: () fun x = () -//│ fun x: [] -//│ fun x: [] +//│ fun x: undefined +//│ fun x: undefined x -//│ [] +//│ undefined //│ res -//│ = [] +//│ = undefined -// :e // TODO – currently we treat () as an empty array; should in fact be JS's `undefined` +:e // we used to treat () as an empty array; should in fact be JS's `undefined` x : Array['a] -//│ Array[nothing] -//│ res -//│ = [] - -// TODO -x : undefined //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.27: x : undefined +//│ ║ l.21: x : Array['a] //│ ║ ^ -//│ ╟── type `[]` does not match type `undefined` +//│ ╟── type `undefined` does not match type `Array['a]` //│ ║ l.9: fun x: () //│ ║ ^^ -//│ ╟── but it flows into reference with expected type `undefined` -//│ ║ l.27: x : undefined +//│ ╟── but it flows into reference with expected type `Array['a]` +//│ ║ l.21: x : Array['a] //│ ║ ^ -//│ ╟── Note: constraint arises from literal type: -//│ ║ l.27: x : undefined +//│ ╟── Note: constraint arises from applied type reference: +//│ ║ l.21: x : Array['a] //│ ╙── ^^^^^^^^^ +//│ Array[nothing] +//│ res +//│ = undefined + +x : undefined //│ undefined //│ res -//│ = [] +//│ = undefined -// TODO fun x: () fun x = undefined -//│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.46: fun x = undefined -//│ ║ ^^^^^^^^^^^^^ -//│ ╟── undefined literal of type `undefined` is not a 0-element tuple -//│ ║ l.46: fun x = undefined -//│ ║ ^^^^^^^^^ -//│ ╟── but it flows into definition of method x with expected type `[]` -//│ ║ l.46: fun x = undefined -//│ ║ ^^^^^^^^^^^^^ -//│ ╟── Note: constraint arises from tuple type: -//│ ║ l.45: fun x: () -//│ ╙── ^^ //│ fun x: undefined -//│ fun x: [] +//│ fun x: undefined :e fun x: () fun x = 1 //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.65: fun x = 1 +//│ ║ l.51: fun x = 1 //│ ║ ^^^^^ -//│ ╟── integer literal of type `1` is not a 0-element tuple -//│ ║ l.65: fun x = 1 +//│ ╟── integer literal of type `1` does not match type `undefined` +//│ ║ l.51: fun x = 1 //│ ║ ^ -//│ ╟── but it flows into definition of method x with expected type `[]` -//│ ║ l.65: fun x = 1 +//│ ╟── but it flows into definition of method x with expected type `undefined` +//│ ║ l.51: fun x = 1 //│ ║ ^^^^^ -//│ ╟── Note: constraint arises from tuple type: -//│ ║ l.64: fun x: () +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.50: fun x: () //│ ╙── ^^ //│ fun x: 1 -//│ fun x: [] +//│ fun x: undefined + + +(1) +//│ 1 +//│ res +//│ = 1 + +// :pe // TODO? +(1,) +//│ 1 +//│ res +//│ = 1 + +:pe +(1,2) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.80: (1,2) +//│ ╙── ^^^^^ +//│ [1, 2] +//│ res +//│ = [ 1, 2 ] + +(let x = 1) +//│ undefined +//│ res +//│ = undefined + +:pe +(let x = 1 in) +//│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here +//│ ║ l.94: (let x = 1 in) +//│ ╙── ^ +//│ undefined +//│ res +//│ = undefined + +(log(1)) +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ 1 + +:pe +(log(1);) +//│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here +//│ ║ l.110: (log(1);) +//│ ╙── ^ +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ 1 + +(log(1); 2) +//│ 2 +//│ res +//│ = 2 +//│ // Output +//│ 1 + +(log(1); ()) +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ 1 + +(((log((()))))) +//│ undefined +//│ res +//│ = undefined +//│ // Output +//│ undefined + + + + +:pe +(1, 2) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.145: (1, 2) +//│ ╙── ^^^^^^ +//│ [1, 2] +//│ res +//│ = [ 1, 2 ] + + +x => x +//│ forall 'a. 'a -> 'a +//│ res +//│ = [Function: res] + +(x) => x +//│ forall 'a. 'a -> 'a +//│ res +//│ = [Function: res] + +(x, y) => x + y +//│ (Int, Int) -> Int +//│ res +//│ = [Function: res] + + +(1, 2) => 3 +//│ (1, 2) -> 3 +//│ res +//│ = [Function: res] + + +:pe +1 => (2, 3) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.177: 1 => (2, 3) +//│ ╙── ^^^^^^ +//│ 1 -> [2, 3] +//│ res +//│ = [Function: res] + + +fun f(x, y) = x + y +//│ fun f: (Int, Int) -> Int + +f(1, 2) +//│ Int +//│ res +//│ = 3 + +f of 1, 2 +//│ Int +//│ res +//│ = 3 + +:pe +:e +f of (1, 2) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.201: f of (1, 2) +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.201: f of (1, 2) +//│ ║ ^^^^^^^^^^^ +//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` +//│ ║ l.201: f of (1, 2) +//│ ║ ^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.186: fun f(x, y) = x + y +//│ ╙── ^^^^^^ +//│ Int | error +//│ res +//│ = '1,2undefined' + + + + diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index b81b6fbe27..8c22b3af18 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -11,14 +11,22 @@ fun f: [Str] | [Str, Int] fun f: (Str | [Str, Int]) //│ fun f: Str | [Str, Int] +:pe fun f: Str | (Str, Int) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.15: fun f: Str | (Str, Int) +//│ ╙── ^^^^^^^^^^ //│ fun f: Str | [Str, Int] fun f: Str | ([Str, Int]) //│ fun f: Str | [Str, Int] +:pe fun f: Str | ((Str, Int)) +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.26: fun f: Str | ((Str, Int)) +//│ ╙── ^^^^^^^^^^ //│ fun f: Str | [Str, Int] @@ -42,10 +50,10 @@ fun f: (Str => Str) & ((Str, Int) => Int) :e f("abc", "abc") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.43: f("abc", "abc") +//│ ║ l.51: f("abc", "abc") //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `["abc", "abc"]` does not match type `nothing` -//│ ║ l.43: f("abc", "abc") +//│ ║ l.51: f("abc", "abc") //│ ╙── ^^^^^^^^^^^^^^ //│ Int | Str | error //│ res @@ -64,19 +72,19 @@ let r = if true then id else [x, y] => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.64: r(error) +//│ ║ l.72: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.64: r(error) +//│ ║ l.72: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.58: let r = if true then id else [x, y] => [y, x] +//│ ║ l.66: let r = if true then id else [x, y] => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.65: r(error, error) +//│ ║ l.73: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.65: r(error, error) +//│ ║ l.73: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res diff --git a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls index 58f555fc3b..93be7df608 100644 --- a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls +++ b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls @@ -15,7 +15,7 @@ class App[A](s: A, t: A) fun eval(sub, v) = if v is Abs(x, t) then - eval(Cons((error, error), Nil), error) + eval(Cons([error, error], Nil), error) eval(Cons(error, sub), error) error //│ fun eval: (Cons[anything] | Nil, Abs[anything]) -> nothing @@ -24,8 +24,8 @@ mixin EvalLambda { fun eval(sub, v) = if v is Abs(x, t) then - this.eval(Cons((error, error), Nil), error) - this.eval(Cons((x, error), sub), error) + this.eval(Cons([error, error], Nil), error) + this.eval(Cons([x, error], sub), error) error } //│ mixin EvalLambda() { diff --git a/shared/src/test/diff/parser/Arrays.mls b/shared/src/test/diff/parser/Arrays.mls index e7c41dbdd0..ff91aed81f 100644 --- a/shared/src/test/diff/parser/Arrays.mls +++ b/shared/src/test/diff/parser/Arrays.mls @@ -19,7 +19,7 @@ () //│ |(||)| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {undefined} (1) //│ |(|1|)| @@ -31,7 +31,10 @@ (1, 2, 3) //│ |(|1|,| |2|,| |3|)| -//│ Parsed: {'(' [1, 2, 3,] ')'} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.32: (1, 2, 3) +//│ ╙── ^^^^^^^^^ +//│ Parsed: {[1, 2, 3,]} 1 @@ -41,14 +44,14 @@ 1, //│ |1|,| //│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.41: 1, +//│ ║ l.44: 1, //│ ╙── ^ //│ Parsed: {1} 1, 2, 3 //│ |1|,| |2|,| |3| //│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.48: 1, 2, 3 +//│ ║ l.51: 1, 2, 3 //│ ╙── ^ //│ Parsed: {1} @@ -83,9 +86,9 @@ let arr = ] //│ |#let| |arr| |#=|↵|[|↵|]| //│ ╔══[PARSE ERROR] Unexpected newline in expression position -//│ ║ l.81: let arr = +//│ ║ l.84: let arr = //│ ║ ^ -//│ ║ l.82: [ +//│ ║ l.85: [ //│ ╙── //│ Parsed: {let arr = '(' [] ')'} diff --git a/shared/src/test/diff/parser/BasicSyntax.mls b/shared/src/test/diff/parser/BasicSyntax.mls index 7e3b3b0f98..3b2d1c4660 100644 --- a/shared/src/test/diff/parser/BasicSyntax.mls +++ b/shared/src/test/diff/parser/BasicSyntax.mls @@ -13,7 +13,7 @@ f 1 () //│ |(||)| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {undefined} f() //│ |f|(||)| @@ -180,7 +180,10 @@ foo foo of (1, 2, 3) //│ |foo|→|#of| |(|1|,| |2|,| |3|)|←| -//│ Parsed: {foo('(' [1, 2, 3,] ')',)} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.181: of (1, 2, 3) +//│ ╙── ^^^^^^^^^ +//│ Parsed: {foo([1, 2, 3,],)} foo of @@ -226,28 +229,28 @@ foo (1 //│ ╔══[PARSE ERROR] Unmatched opening parenthesis -//│ ║ l.227: (1 +//│ ║ l.230: (1 //│ ╙── ^ //│ |1| //│ Parsed: {1} (1)) //│ ╔══[PARSE ERROR] Unexpected closing parenthesis -//│ ║ l.234: (1)) +//│ ║ l.237: (1)) //│ ╙── ^ //│ |(|1|)| //│ Parsed: {'(' 1 ')'} ( //│ ╔══[PARSE ERROR] Unmatched opening parenthesis -//│ ║ l.241: ( +//│ ║ l.244: ( //│ ╙── ^ //│ || //│ Parsed: {} ) //│ ╔══[PARSE ERROR] Unexpected closing parenthesis -//│ ║ l.248: ) +//│ ║ l.251: ) //│ ╙── ^ //│ || //│ Parsed: {} @@ -255,17 +258,17 @@ foo 1+ //│ |1|+| //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.255: 1+ +//│ ║ l.258: 1+ //│ ╙── ^ //│ Parsed: {+(1,)(undefined,)} * //│ |*| //│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.262: * +//│ ║ l.265: * //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.262: * +//│ ║ l.265: * //│ ╙── ^ //│ Parsed: {undefined} @@ -273,7 +276,7 @@ foo f 1 //│ |f| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.273: f 1 +//│ ║ l.276: f 1 //│ ╙── ^^^ //│ Parsed: {f(1,)} @@ -289,7 +292,7 @@ f (1) f 1, 2, 3 //│ |f| |1|,| |2|,| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.289: f 1, 2, 3 +//│ ║ l.292: f 1, 2, 3 //│ ╙── ^^^^^^^^^ //│ Parsed: {f(1, 2, 3,)} @@ -317,21 +320,21 @@ f[1, 2, 3] f{} //│ |f|{||}| //│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.317: f{} +//│ ║ l.320: f{} //│ ╙── ^^ //│ Parsed: {f} f{1} //│ |f|{|1|}| //│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.324: f{1} +//│ ║ l.327: f{1} //│ ╙── ^^^ //│ Parsed: {f} f{1, 2, 3} //│ |f|{|1|,| |2|,| |3|}| //│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.331: f{1, 2, 3} +//│ ║ l.334: f{1, 2, 3} //│ ╙── ^^^^^^^^^ //│ Parsed: {f} @@ -339,10 +342,10 @@ f{1, 2, 3} f 1,, 2 //│ |f| |1|,|,| |2| //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.339: f 1,, 2 +//│ ║ l.342: f 1,, 2 //│ ╙── ^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.339: f 1,, 2 +//│ ║ l.342: f 1,, 2 //│ ╙── ^^^^^^^ //│ Parsed: {f(1, 2,)} @@ -354,10 +357,10 @@ f of x f g x //│ |f| |g| |x| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.354: f g x +//│ ║ l.357: f g x //│ ╙── ^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.354: f g x +//│ ║ l.357: f g x //│ ╙── ^^^^^ //│ Parsed: {f(g(x,),)} @@ -368,7 +371,7 @@ f of g of x f of of g //│ |f| |#of| |#of| |g| //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position -//│ ║ l.368: f of of g +//│ ║ l.371: f of of g //│ ╙── ^^ //│ Parsed: {f(g,)} @@ -376,52 +379,52 @@ f of of g f x: 1 //│ |f| |x|#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.376: f x: 1 +//│ ║ l.379: f x: 1 //│ ╙── ^^^^^^ //│ Parsed: {f(x: 1,)} f x: 1, //│ |f| |x|#:| |1|,| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.383: f x: 1, +//│ ║ l.386: f x: 1, //│ ╙── ^^^^^^ //│ Parsed: {f(x: 1,)} f x : 1 //│ |f| |x| |#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.390: f x : 1 +//│ ║ l.393: f x : 1 //│ ╙── ^^^ //│ Parsed: {f(x : 1,)} f x: 1, y: 2 //│ |f| |x|#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.397: f x: 1, y: 2 +//│ ║ l.400: f x: 1, y: 2 //│ ╙── ^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: 2,)} f x : 1, y: 2 //│ |f| |x| |#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.404: f x : 1, y: 2 +//│ ║ l.407: f x : 1, y: 2 //│ ╙── ^^^^^^^^^^^^^ //│ Parsed: {f(x : 1, y: 2,)} f x: 1, y: 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.411: f x: 1, y: 2, z: 3 +//│ ║ l.414: f x: 1, y: 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: 2, z: 3,)} f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.418: f x: 1, y: g 2, z: 3 +//│ ║ l.421: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.418: f x: 1, y: g 2, z: 3 +//│ ║ l.421: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: g(2, z: 3,),)} @@ -436,10 +439,10 @@ f(x: 1, y: g(2), z: 3) f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.436: f x: 1, y: g 2, z: 3 +//│ ║ l.439: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.436: f x: 1, y: g 2, z: 3 +//│ ║ l.439: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: g(2, z: 3,),)} @@ -450,13 +453,13 @@ f of x: 1, y: g of 2, z: 3 f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ |f| |x|#:| |1| |+| |1|,| |y|#:| |2| |2|,| |z|#:| |3| |+| |2| |4| |-| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.450: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.453: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.450: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.453: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.450: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.453: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: +(1,)(1,), y: 2(2, z: +(3,)(2(-(4,)(1,),),),),)} @@ -468,10 +471,10 @@ x.y .y //│ |.y| //│ ╔══[PARSE ERROR] Unexpected selector in expression position -//│ ║ l.468: .y +//│ ║ l.471: .y //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.468: .y +//│ ║ l.471: .y //│ ╙── ^ //│ Parsed: {undefined} diff --git a/shared/src/test/diff/parser/Brackets.mls b/shared/src/test/diff/parser/Brackets.mls index a6df1948f4..c9d635a214 100644 --- a/shared/src/test/diff/parser/Brackets.mls +++ b/shared/src/test/diff/parser/Brackets.mls @@ -1,7 +1,7 @@ () //│ |(||)| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {undefined} [] //│ |[||]| @@ -20,7 +20,7 @@ //│ ║ l.15: (} //│ ╙── ^ //│ |(||)| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {undefined} (([{}])) //│ |(|(|[|{||}|]|)|)| @@ -46,5 +46,5 @@ fun f = () //│ |#fun| |f| |#=| |(||)| -//│ Parsed: {fun f = '(' [] ')'} +//│ Parsed: {fun f = undefined} diff --git a/shared/src/test/diff/parser/Forall.mls b/shared/src/test/diff/parser/Forall.mls index 539bca4919..d2801d6825 100644 --- a/shared/src/test/diff/parser/Forall.mls +++ b/shared/src/test/diff/parser/Forall.mls @@ -1,17 +1,17 @@ forall 'a: 'a => 'a -//│ |#forall| |'a|#:| |'a| |=>| |'a| +//│ |#forall| |'a|#:| |'a| |#=>| |'a| //│ Parsed: {forall 'a. ('a,) => 'a} -forall 'a, 'b: ('a, 'b) => ('b, 'a) -//│ |#forall| |'a|,| |'b|#:| |(|'a|,| |'b|)| |=>| |(|'b|,| |'a|)| +forall 'a, 'b: ['a, 'b] => ['b, 'a] +//│ |#forall| |'a|,| |'b|#:| |[|'a|,| |'b|]| |#=>| |[|'b|,| |'a|]| //│ Parsed: {forall 'a, 'b. ('a, 'b,) => '(' ['b, 'a,] ')'} fun f: forall 'a: 'a => 'a -//│ |#fun| |f|#:| |#forall| |'a|#:| |'a| |=>| |'a| +//│ |#fun| |f|#:| |#forall| |'a|#:| |'a| |#=>| |'a| //│ Parsed: {fun f: forall 'a. 'a -> 'a} -fun f: forall 'a, 'b: ('a, 'b) => ('b, 'a) -//│ |#fun| |f|#:| |#forall| |'a|,| |'b|#:| |(|'a|,| |'b|)| |=>| |(|'b|,| |'a|)| +fun f: forall 'a, 'b: ['a, 'b] => ['b, 'a] +//│ |#fun| |f|#:| |#forall| |'a|,| |'b|#:| |[|'a|,| |'b|]| |#=>| |[|'b|,| |'a|]| //│ Parsed: {fun f: forall 'a 'b. ('a, 'b) -> ['b, 'a]} diff --git a/shared/src/test/diff/parser/Fun.mls b/shared/src/test/diff/parser/Fun.mls index c1a3f21808..4f1dae5e95 100644 --- a/shared/src/test/diff/parser/Fun.mls +++ b/shared/src/test/diff/parser/Fun.mls @@ -17,13 +17,13 @@ fun f x = x //│ Parsed: {fun f = x} fun f = x => x -//│ |#fun| |f| |#=| |x| |=>| |x| +//│ |#fun| |f| |#=| |x| |#=>| |x| //│ Parsed: {fun f = (x,) => x} // TODO fun x => x -//│ |#fun| |x| |=>| |x| -//│ ╔══[PARSE ERROR] Expected function parameter list; found operator instead +//│ |#fun| |x| |#=>| |x| +//│ ╔══[PARSE ERROR] Expected function parameter list; found '=>' instead //│ ║ l.24: fun x => x //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected ':' or '=' followed by a function body or signature; found identifier instead @@ -32,12 +32,12 @@ fun x => x //│ Parsed: {fun x = undefined} let f = x => x -//│ |#let| |f| |#=| |x| |=>| |x| +//│ |#let| |f| |#=| |x| |#=>| |x| //│ Parsed: {let f = (x,) => x} // TODO let f = fun x => x -//│ |#let| |f| |#=| |#fun| |x| |=>| |x| +//│ |#let| |f| |#=| |#fun| |x| |#=>| |x| //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position //│ ║ l.39: let f = fun x => x //│ ╙── ^^^ @@ -182,13 +182,13 @@ fun add(x: number, y: number): number //│ Parsed: {fun add: (x: number, y: number) -> number} fun apply(x: int, f: int => int): int -//│ |#fun| |apply|(|x|#:| |int|,| |f|#:| |int| |=>| |int|)|#:| |int| +//│ |#fun| |apply|(|x|#:| |int|,| |f|#:| |int| |#=>| |int|)|#:| |int| //│ Parsed: {fun apply: (x: int, f: int -> int) -> int} fun apply2(x: number, f: int => number => number): number -//│ |#fun| |apply2|(|x|#:| |number|,| |f|#:| |int| |=>| |number| |=>| |number|)|#:| |number| +//│ |#fun| |apply2|(|x|#:| |number|,| |f|#:| |int| |#=>| |number| |#=>| |number|)|#:| |number| //│ Parsed: {fun apply2: (x: number, f: int -> number -> number) -> number} fun apply3(x: number, f: (int => number) => number): number -//│ |#fun| |apply3|(|x|#:| |number|,| |f|#:| |(|int| |=>| |number|)| |=>| |number|)|#:| |number| +//│ |#fun| |apply3|(|x|#:| |number|,| |f|#:| |(|int| |#=>| |number|)| |#=>| |number|)|#:| |number| //│ Parsed: {fun apply3: (x: number, f: (int -> number) -> number) -> number} diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 8b57c4a6d5..606640c2f0 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -572,7 +572,7 @@ if true then;; else;; if true then () else;; //│ |#if| |true| |#then| |(||)| |#else|#;;| -//│ Parsed: {if (true) then '(' [] ')' else undefined} +//│ Parsed: {if (true) then undefined else undefined} diff --git a/shared/src/test/diff/parser/Lambdas.mls b/shared/src/test/diff/parser/Lambdas.mls index b0de021f2d..74771e5cbf 100644 --- a/shared/src/test/diff/parser/Lambdas.mls +++ b/shared/src/test/diff/parser/Lambdas.mls @@ -2,17 +2,17 @@ x => x -//│ |x| |=>| |x| +//│ |x| |#=>| |x| //│ Parsed: {(x,) => x} (x) => x -//│ |(|x|)| |=>| |x| +//│ |(|x|)| |#=>| |x| //│ Parsed: {('(' x ')',) => x} // TODO fun x => x -//│ |#fun| |x| |=>| |x| -//│ ╔══[PARSE ERROR] Expected function parameter list; found operator instead +//│ |#fun| |x| |#=>| |x| +//│ ╔══[PARSE ERROR] Expected function parameter list; found '=>' instead //│ ║ l.13: fun x => x //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected ':' or '=' followed by a function body or signature; found identifier instead @@ -22,7 +22,7 @@ fun x => x // TODO let f = fun x => x -//│ |#let| |f| |#=| |#fun| |x| |=>| |x| +//│ |#let| |f| |#=| |#fun| |x| |#=>| |x| //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position //│ ║ l.24: let f = fun x => x //│ ╙── ^^^ @@ -38,26 +38,26 @@ fun f x = x (x, y) => x -//│ |(|x|,| |y|)| |=>| |x| +//│ |(|x|,| |y|)| |#=>| |x| //│ Parsed: {(x, y,) => x} => 1 -//│ |=>| |1| -//│ ╔══[PARSE ERROR] Unexpected operator in expression position +//│ |#=>| |1| +//│ ╔══[PARSE ERROR] Unexpected '=>' in expression position //│ ║ l.45: => 1 //│ ╙── ^^ //│ Parsed: {1} x => -//│ |x| |=>| +//│ |x| |#=>| //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here //│ ║ l.52: x => //│ ╙── ^ //│ Parsed: {(x,) => undefined} (x =>) -//│ |(|x| |=>|)| +//│ |(|x| |#=>|)| //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.59: (x =>) //│ ╙── ^ @@ -68,48 +68,48 @@ a --> b --> c //│ Parsed: {-->(a,)(-->(b,)(c,),)} a => b => c -//│ |a| |=>| |b| |=>| |c| +//│ |a| |#=>| |b| |#=>| |c| //│ Parsed: {(a,) => (b,) => c} (a => b) => c -//│ |(|a| |=>| |b|)| |=>| |c| +//│ |(|a| |#=>| |b|)| |#=>| |c| //│ Parsed: {('(' (a,) => b ')',) => c} a => (b => c) -//│ |a| |=>| |(|b| |=>| |c|)| +//│ |a| |#=>| |(|b| |#=>| |c|)| //│ Parsed: {(a,) => '(' (b,) => c ')'} xs.forall(x => x > 0) -//│ |xs|.forall|(|x| |=>| |x| |>| |0|)| +//│ |xs|.forall|(|x| |#=>| |x| |>| |0|)| //│ Parsed: {(xs).forall((x,) => >(x,)(0,),)} xs.forall of x => x > 0 -//│ |xs|.forall| |#of| |x| |=>| |x| |>| |0| +//│ |xs|.forall| |#of| |x| |#=>| |x| |>| |0| //│ Parsed: {(xs).forall((x,) => >(x,)(0,),)} :pe a => b then c -//│ |a| |=>| |b| |#then| |c| +//│ |a| |#=>| |b| |#then| |c| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause //│ ║ l.91: a => b then c //│ ╙── ^^^^^^^^^^^^^ //│ Parsed: {undefined} if a => b then c -//│ |#if| |a| |=>| |b| |#then| |c| +//│ |#if| |a| |#=>| |b| |#then| |c| //│ Parsed: {if ((a,) => b) then c} if xs.forall(a => b) then c -//│ |#if| |xs|.forall|(|a| |=>| |b|)| |#then| |c| +//│ |#if| |xs|.forall|(|a| |#=>| |b|)| |#then| |c| //│ Parsed: {if ((xs).forall((a,) => b,)) then c} if xs.forall of a => b then c -//│ |#if| |xs|.forall| |#of| |a| |=>| |b| |#then| |c| +//│ |#if| |xs|.forall| |#of| |a| |#=>| |b| |#then| |c| //│ Parsed: {if ((xs).forall((a,) => b,)) then c} id + of x => x + 1 -//│ |id| |+| |#of| |x| |=>| |x| |+| |1| +//│ |id| |+| |#of| |x| |#=>| |x| |+| |1| //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position //│ ║ l.111: id + of x => x + 1 //│ ╙── ^^ diff --git a/shared/src/test/diff/parser/Misc.mls b/shared/src/test/diff/parser/Misc.mls index 0df0a8c69d..0e20bd8aa4 100644 --- a/shared/src/test/diff/parser/Misc.mls +++ b/shared/src/test/diff/parser/Misc.mls @@ -3,7 +3,7 @@ fun discard(x) = () //│ |#fun| |discard|(|x|)| |#=| |(||)| -//│ Parsed: {fun discard = (x,) => '(' [] ')'} +//│ Parsed: {fun discard = (x,) => undefined} // FIXME parses wrong: foo of diff --git a/shared/src/test/diff/parser/NamedArrays.mls b/shared/src/test/diff/parser/NamedArrays.mls index 5feeda316b..18b2dc8a1f 100644 --- a/shared/src/test/diff/parser/NamedArrays.mls +++ b/shared/src/test/diff/parser/NamedArrays.mls @@ -55,34 +55,52 @@ () //│ |(||)| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {undefined} (x: 1) //│ |(|x|#:| |1|)| -//│ Parsed: {'(' [x: 1,] ')'} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.60: (x: 1) +//│ ╙── ^^^^^^ +//│ Parsed: {[x: 1,]} (x:) //│ |(|x|#:|)| //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.64: (x:) +//│ ║ l.67: (x:) //│ ╙── ^ -//│ Parsed: {'(' [x: undefined,] ')'} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.67: (x:) +//│ ╙── ^^^^ +//│ Parsed: {[x: undefined,]} (x: 1,) //│ |(|x|#:| |1|,|)| -//│ Parsed: {'(' [x: 1,] ')'} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.77: (x: 1,) +//│ ╙── ^^^^^^^ +//│ Parsed: {[x: 1,]} (x: 1, 2, 3) //│ |(|x|#:| |1|,| |2|,| |3|)| -//│ Parsed: {'(' [x: 1, 2, 3,] ')'} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.84: (x: 1, 2, 3) +//│ ╙── ^^^^^^^^^^^^ +//│ Parsed: {[x: 1, 2, 3,]} (1, y: 2, 3) //│ |(|1|,| |y|#:| |2|,| |3|)| -//│ Parsed: {'(' [1, y: 2, 3,] ')'} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.91: (1, y: 2, 3) +//│ ╙── ^^^^^^^^^^^^ +//│ Parsed: {[1, y: 2, 3,]} (x: 1, y: 2, z: 3) //│ |(|x|#:| |1|,| |y|#:| |2|,| |z|#:| |3|)| -//│ Parsed: {'(' [x: 1, y: 2, z: 3,] ')'} +//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ║ l.98: (x: 1, y: 2, z: 3) +//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ Parsed: {[x: 1, y: 2, z: 3,]} 1 @@ -96,21 +114,21 @@ x: 1 1, //│ |1|,| //│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.96: 1, -//│ ╙── ^ +//│ ║ l.114: 1, +//│ ╙── ^ //│ Parsed: {1} x: 1, //│ |x|#:| |1|,| //│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.103: x: 1, +//│ ║ l.121: x: 1, //│ ╙── ^ //│ Parsed: {x : 1} 1, 2, 3 //│ |1|,| |2|,| |3| //│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.110: 1, 2, 3 +//│ ║ l.128: 1, 2, 3 //│ ╙── ^ //│ Parsed: {1} @@ -144,10 +162,10 @@ f of z: 3 //│ |f| |#of|→|x|#:| |1|↵|y|#:| |2|↵|z|#:| |3|←| //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.142: x: 1 +//│ ║ l.160: x: 1 //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.143: y: 2 +//│ ║ l.161: y: 2 //│ ╙── ^ //│ Parsed: {f(z: {1; 2; 3},)} @@ -157,7 +175,7 @@ f of z: 3 //│ |f| |#of|→|x|#:| |1|↵|2|↵|z|#:| |3|←| //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.155: x: 1 +//│ ║ l.173: x: 1 //│ ╙── ^ //│ Parsed: {f(z: {1; 2; 3},)} @@ -167,10 +185,10 @@ f of 3 //│ |f| |#of|→|x|#:| |1|↵|y|#:| |2|↵|3|←| //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.165: x: 1 +//│ ║ l.183: x: 1 //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.166: y: 2 +//│ ║ l.184: y: 2 //│ ╙── ^ //│ Parsed: {f({1; 2; 3},)} diff --git a/shared/src/test/diff/parser/Where.mls b/shared/src/test/diff/parser/Where.mls index c4c9fabdc7..d2e6ccef2c 100644 --- a/shared/src/test/diff/parser/Where.mls +++ b/shared/src/test/diff/parser/Where.mls @@ -4,7 +4,7 @@ //│ Parsed: {+(1,)(1,) where {1}} a => a + 1 where foo -//│ |a| |=>| |a| |+| |1| |#where| |foo| +//│ |a| |#=>| |a| |+| |1| |#where| |foo| //│ Parsed: {(a,) => +(a,)(1,) where {foo}} a + 1 where let a = 1 @@ -12,7 +12,7 @@ a + 1 where let a = 1 //│ Parsed: {+(a,)(1,) where {let a = 1}} fun foo: 'a => 'a => 'a where 'a : int -//│ |#fun| |foo|#:| |'a| |=>| |'a| |=>| |'a| |#where| |'a| |#:| |int| +//│ |#fun| |foo|#:| |'a| |#=>| |'a| |#=>| |'a| |#where| |'a| |#:| |int| //│ Parsed: {fun foo: 'a -> 'a -> ('a //│ where //│ 'a <: int)} diff --git a/shared/src/test/diff/ucs/Humiliation.mls b/shared/src/test/diff/ucs/Humiliation.mls index 72c293c0b1..878fb05372 100644 --- a/shared/src/test/diff/ucs/Humiliation.mls +++ b/shared/src/test/diff/ucs/Humiliation.mls @@ -88,17 +88,17 @@ fun foo(x) = if x is :e :ge fun foo(x) = if x is - (Z(), Z()) then "zeros" - (O(), O()) then "ones" + [Z(), Z()] then "zeros" + [O(), O()] then "ones" //│ ╔══[ERROR] The match is not exhaustive. //│ ║ l.90: fun foo(x) = if x is //│ ║ ^^^^ //│ ╟── The scrutinee at this position misses 1 case. -//│ ║ l.91: (Z(), Z()) then "zeros" +//│ ║ l.91: [Z(), Z()] then "zeros" //│ ║ ^^^ //│ ╟── [Missing Case 1/1] `O` //│ ╟── It first appears here. -//│ ║ l.92: (O(), O()) then "ones" +//│ ║ l.92: [O(), O()] then "ones" //│ ╙── ^^^ //│ foo: anything -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index 147e241a3e..ff29a4b367 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -319,7 +319,7 @@ mapPartition2(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) //│ } fun log(x) = () -//│ log: anything -> () +//│ log: anything -> undefined //│ = [Function: log] fun mn(a) = diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index c19a628eb4..435b24f031 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -245,7 +245,7 @@ fun expect(scanner, ch) = eq(ch)(ch') then ParseSuccess((), scanner.advance) else ParseFailure(concat4("expect '", ch, "' but found ", ch'), scanner) None then ParseFailure(concat3("expect '", ch, "' but found EOF"), scanner) -//│ fun expect: (Scanner & {advance: Scanner}, Str) -> (ParseFailure | ParseSuccess[[]]) +//│ fun expect: (Scanner & {advance: Scanner}, Str) -> (ParseFailure | ParseSuccess[undefined]) fun expectWord(scanner, word, result) = if diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index 389e6062f3..ec43e25cb7 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -1,6 +1,7 @@ :NewParser :NewDefs + class Some[A](val value: A) module None class Left[A](val leftValue: A) @@ -16,6 +17,7 @@ class Pair[A, B](val fst: A, val snd: B) //│ class Cons[A](head: A, tail: Cons[A] | Nil) //│ class Pair[A, B](fst: A, snd: B) + fun optionApply(x, y, f) = if x is Some(xv) and y is @@ -95,43 +97,43 @@ mapPartition(f, zeroToThree) //│ res //│ = Pair {} -// TODO make this one work (needs tuple support) +:e // TODO make this one work (needs tuple support) fun mapPartition(f, xs) = if xs is - Nil then (Nil, Nil) - Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is - Left(v) then (Cons(v, l), r) - Right(v) then (l, Cons(v, r)) + Nil then [Nil, Nil] + Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is + Left(v) then [Cons(v, l), r] + Right(v) then [l, Cons(v, r)] //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.99: fun mapPartition(f, xs) = if xs is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.100: Nil then (Nil, Nil) +//│ ║ l.101: fun mapPartition(f, xs) = if xs is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.102: Nil then [Nil, Nil] //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.101: Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is +//│ ║ l.103: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.102: Left(v) then (Cons(v, l), r) +//│ ║ l.104: Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.103: Right(v) then (l, Cons(v, r)) +//│ ║ l.105: Right(v) then [l, Cons(v, r)] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `[Nil, Nil]` is not an instance of type `Object` -//│ ║ l.100: Nil then (Nil, Nil) +//│ ║ l.102: Nil then [Nil, Nil] //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from `case` expression: -//│ ║ l.101: Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is +//│ ║ l.103: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.102: Left(v) then (Cons(v, l), r) +//│ ║ l.104: Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.103: Right(v) then (l, Cons(v, r)) +//│ ║ l.105: Right(v) then [l, Cons(v, r)] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from application: -//│ ║ l.101: Cons(x, xs) and mapPartition(f, xs) is (l, r) and f(x) is +//│ ║ l.103: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun mapPartition: forall 'A. (anything, Cons['A] | Nil) -> (error | [Nil, Nil]) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 -// TODO +:re // TODO mapPartition(f, zeroToThree) //│ error | [Nil, Nil] //│ res @@ -145,44 +147,45 @@ mapPartition(f, zeroToThree) :e :ge fun mapPartition(f, xs) = if xs is - Nil then (Nil, Nil) - Cons(x, xs) and mapPartition(f, xs) is (l, r) - and f(x) is Left(v) then (Cons(v, l), r) - Right(v) then (l, Cons(v, r)) + Nil then [Nil, Nil] + Cons(x, xs) and mapPartition(f, xs) is [l, r] + and f(x) is Left(v) then [Cons(v, l), r] + Right(v) then [l, Cons(v, r)] //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here -//│ ║ l.151: Right(v) then (l, Cons(v, r)) +//│ ║ l.153: Right(v) then [l, Cons(v, r)] //│ ╙── ^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.150: and f(x) is Left(v) then (Cons(v, l), r) +//│ ║ l.152: and f(x) is Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.151: Right(v) then (l, Cons(v, r)) +//│ ║ l.153: Right(v) then [l, Cons(v, r)] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.147: fun mapPartition(f, xs) = if xs is +//│ ║ l.149: fun mapPartition(f, xs) = if xs is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.148: Nil then (Nil, Nil) +//│ ║ l.150: Nil then [Nil, Nil] //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.149: Cons(x, xs) and mapPartition(f, xs) is (l, r) +//│ ║ l.151: Cons(x, xs) and mapPartition(f, xs) is [l, r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.150: and f(x) is Left(v) then (Cons(v, l), r) +//│ ║ l.152: and f(x) is Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.151: Right(v) then (l, Cons(v, r)) +//│ ║ l.153: Right(v) then [l, Cons(v, r)] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `[Nil, Nil]` is not an instance of type `Object` -//│ ║ l.148: Nil then (Nil, Nil) +//│ ║ l.150: Nil then [Nil, Nil] //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from `case` expression: -//│ ║ l.149: Cons(x, xs) and mapPartition(f, xs) is (l, r) +//│ ║ l.151: Cons(x, xs) and mapPartition(f, xs) is [l, r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.150: and f(x) is Left(v) then (Cons(v, l), r) +//│ ║ l.152: and f(x) is Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.151: Right(v) then (l, Cons(v, r)) +//│ ║ l.153: Right(v) then [l, Cons(v, r)] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from application: -//│ ║ l.149: Cons(x, xs) and mapPartition(f, xs) is (l, r) +//│ ║ l.151: Cons(x, xs) and mapPartition(f, xs) is [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ fun mapPartition: forall 'A. (anything, Cons['A] | Nil) -> (error | [Nil, Nil]) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 + diff --git a/shared/src/test/diff/ucs/NestedPattern.mls b/shared/src/test/diff/ucs/NestedPattern.mls index 5d9b919bdc..c292de5570 100644 --- a/shared/src/test/diff/ucs/NestedPattern.mls +++ b/shared/src/test/diff/ucs/NestedPattern.mls @@ -41,8 +41,8 @@ fun crazy(v) = :e fun f(x) = if x is - (0, 0) then "zeros" - (1, 1) then "ones" + [0, 0] then "zeros" + [1, 1] then "ones" _ then "bruh" //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── @@ -51,9 +51,9 @@ fun f(x) = :e fun f(x) = if x is - (0, 0) then "zeros" - (1, 1) then "ones" - (y, 1) then x + [0, 0] then "zeros" + [1, 1] then "ones" + [y, 1] then x _ then "que?" //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── @@ -62,7 +62,7 @@ fun f(x) = :e fun f(p) = if p is - Some((x, y)) then x + y + Some([x, y]) then x + y None() then 0 //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── diff --git a/ts2mls/js/src/main/scala/ts2mls/types/Converter.scala b/ts2mls/js/src/main/scala/ts2mls/types/Converter.scala index 32760642b2..8dadf566c9 100644 --- a/ts2mls/js/src/main/scala/ts2mls/types/Converter.scala +++ b/ts2mls/js/src/main/scala/ts2mls/types/Converter.scala @@ -39,7 +39,7 @@ object Converter { case TSUnionType(lhs, rhs) => s"(${convert(lhs)}) | (${convert(rhs)})" case TSIntersectionType(lhs, rhs) => s"(${convert(lhs)}) & (${convert(rhs)})" case TSTypeParameter(name, _) => name // constraints should be translated where the type parameters were created rather than be used - case TSTupleType(lst) => s"(${lst.foldLeft("")((p, t) => s"$p${convert(t)}, ")})" + case TSTupleType(lst) => s"[${lst.map(convert).mkString(", ")}]" case TSArrayType(element) => s"MutArray<${convert(element)}>" case TSEnumType => "int" case TSMemberType(base, _) => convert(base) // TODO: support private/protected members diff --git a/ts2mls/js/src/test/diff/Array.d.mls b/ts2mls/js/src/test/diff/Array.d.mls index 446fb8f8f4..a6a43ee804 100644 --- a/ts2mls/js/src/test/diff/Array.d.mls +++ b/ts2mls/js/src/test/diff/Array.d.mls @@ -11,7 +11,7 @@ trait I() { fun doCs(c: MutArray): MutArray fun doIs(i: MutArray): MutArray fun inter(x: MutArray<(U) & (T)>): MutArray<(U) & (T)> -fun clean(x: MutArray<(string, number, )>): MutArray<(string, number, )> +fun clean(x: MutArray<[string, number]>): MutArray<[string, number]> fun translate(x: MutArray): MutArray fun uu(x: MutArray<((number) | (false)) | (true)>): MutArray<((number) | (false)) | (true)> class Temp() { @@ -19,6 +19,6 @@ class Temp() { } fun ta(ts: MutArray>): MutArray> fun tat(ts: MutArray>): MutArray> -//│ |#fun| |first|(|x|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |getZero3|(||)|#:| |MutArray|‹|number|›|↵|#fun| |first2|(|fs|#:| |MutArray|‹|(|number|)| |=>| |number|›|)|#:| |(|number|)| |=>| |number|↵|#fun| |doEs|(|e|#:| |MutArray|‹|int|›|)|#:| |MutArray|‹|int|›|↵|#class| |C|(||)| |{||}|↵|#trait| |I|(||)| |{|→|#let| |i|#:| |number|←|↵|}|↵|#fun| |doCs|(|c|#:| |MutArray|‹|C|›|)|#:| |MutArray|‹|C|›|↵|#fun| |doIs|(|i|#:| |MutArray|‹|I|›|)|#:| |MutArray|‹|I|›|↵|#fun| |inter|‹|U|,| |T|›|(|x|#:| |MutArray|‹|(|U|)| |&| |(|T|)|›|)|#:| |MutArray|‹|(|U|)| |&| |(|T|)|›|↵|#fun| |clean|(|x|#:| |MutArray|‹|(|string|,| |number|,| |)|›|)|#:| |MutArray|‹|(|string|,| |number|,| |)|›|↵|#fun| |translate|‹|T|,| |U|›|(|x|#:| |MutArray|‹|T|›|)|#:| |MutArray|‹|U|›|↵|#fun| |uu|(|x|#:| |MutArray|‹|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|›|)|#:| |MutArray|‹|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|›|↵|#class| |Temp|‹|T|›|(||)| |{|→|#let| |x|#:| |T|←|↵|}|↵|#fun| |ta|(|ts|#:| |MutArray|‹|Temp|‹|(|false|)| ||| |(|true|)|›|›|)|#:| |MutArray|‹|Temp|‹|(|false|)| ||| |(|true|)|›|›|↵|#fun| |tat|‹|T|›|(|ts|#:| |MutArray|‹|Temp|‹|T|›|›|)|#:| |MutArray|‹|Temp|‹|T|›|›| +//│ |#fun| |first|(|x|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |getZero3|(||)|#:| |MutArray|‹|number|›|↵|#fun| |first2|(|fs|#:| |MutArray|‹|(|number|)| |#=>| |number|›|)|#:| |(|number|)| |#=>| |number|↵|#fun| |doEs|(|e|#:| |MutArray|‹|int|›|)|#:| |MutArray|‹|int|›|↵|#class| |C|(||)| |{||}|↵|#trait| |I|(||)| |{|→|#let| |i|#:| |number|←|↵|}|↵|#fun| |doCs|(|c|#:| |MutArray|‹|C|›|)|#:| |MutArray|‹|C|›|↵|#fun| |doIs|(|i|#:| |MutArray|‹|I|›|)|#:| |MutArray|‹|I|›|↵|#fun| |inter|‹|U|,| |T|›|(|x|#:| |MutArray|‹|(|U|)| |&| |(|T|)|›|)|#:| |MutArray|‹|(|U|)| |&| |(|T|)|›|↵|#fun| |clean|(|x|#:| |MutArray|‹|[|string|,| |number|]|›|)|#:| |MutArray|‹|[|string|,| |number|]|›|↵|#fun| |translate|‹|T|,| |U|›|(|x|#:| |MutArray|‹|T|›|)|#:| |MutArray|‹|U|›|↵|#fun| |uu|(|x|#:| |MutArray|‹|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|›|)|#:| |MutArray|‹|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|›|↵|#class| |Temp|‹|T|›|(||)| |{|→|#let| |x|#:| |T|←|↵|}|↵|#fun| |ta|(|ts|#:| |MutArray|‹|Temp|‹|(|false|)| ||| |(|true|)|›|›|)|#:| |MutArray|‹|Temp|‹|(|false|)| ||| |(|true|)|›|›|↵|#fun| |tat|‹|T|›|(|ts|#:| |MutArray|‹|Temp|‹|T|›|›|)|#:| |MutArray|‹|Temp|‹|T|›|›| //│ Parsed: {fun first: (x: MutArray[string]) -> string; fun getZero3: () -> MutArray[number]; fun first2: (fs: MutArray[number -> number]) -> number -> number; fun doEs: (e: MutArray[int]) -> MutArray[int]; class C() {}; trait I() {let i: number}; fun doCs: (c: MutArray[C]) -> MutArray[C]; fun doIs: (i: MutArray[I]) -> MutArray[I]; fun inter: (x: MutArray[U & T]) -> MutArray[U & T]; fun clean: (x: MutArray[[string, number]]) -> MutArray[[string, number]]; fun translate: (x: MutArray[T]) -> MutArray[U]; fun uu: (x: MutArray[number | false | true]) -> MutArray[number | false | true]; class Temp‹T›() {let x: T}; fun ta: (ts: MutArray[Temp[bool]]) -> MutArray[Temp[bool]]; fun tat: (ts: MutArray[Temp[T]]) -> MutArray[Temp[T]]} //│ diff --git a/ts2mls/js/src/test/diff/Dec.d.mls b/ts2mls/js/src/test/diff/Dec.d.mls index 47dc24950d..7777ead0bf 100644 --- a/ts2mls/js/src/test/diff/Dec.d.mls +++ b/ts2mls/js/src/test/diff/Dec.d.mls @@ -10,6 +10,6 @@ class Person(name: string, age: number) { } module OOO { } -//│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |=>| |unit|)| ||| |(|#undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#module| |OOO| |{|↵|}| +//│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |#=>| |unit|)| ||| |(|#undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#module| |OOO| |{|↵|}| //│ Parsed: {fun getName: (id: string | number) -> string; fun render: (callback: unit -> unit | undefined) -> string; trait Get() {fun __call: (id: string) -> string}; class Person(name: string, age: number,) {fun getName: (id: number) -> string}; module OOO {}} //│ diff --git a/ts2mls/js/src/test/diff/HighOrderFunc.d.mls b/ts2mls/js/src/test/diff/HighOrderFunc.d.mls index ec24d7bef6..e497bae1d4 100644 --- a/ts2mls/js/src/test/diff/HighOrderFunc.d.mls +++ b/ts2mls/js/src/test/diff/HighOrderFunc.d.mls @@ -3,6 +3,6 @@ fun h1(inc: (number) => number, num: number): number fun h2(hint: string): unit => string fun h3(f: (number) => number, g: (number) => number): (number) => number -//│ |#fun| |h1|(|inc|#:| |(|number|)| |=>| |number|,| |num|#:| |number|)|#:| |number|↵|#fun| |h2|(|hint|#:| |string|)|#:| |unit| |=>| |string|↵|#fun| |h3|(|f|#:| |(|number|)| |=>| |number|,| |g|#:| |(|number|)| |=>| |number|)|#:| |(|number|)| |=>| |number| +//│ |#fun| |h1|(|inc|#:| |(|number|)| |#=>| |number|,| |num|#:| |number|)|#:| |number|↵|#fun| |h2|(|hint|#:| |string|)|#:| |unit| |#=>| |string|↵|#fun| |h3|(|f|#:| |(|number|)| |#=>| |number|,| |g|#:| |(|number|)| |#=>| |number|)|#:| |(|number|)| |#=>| |number| //│ Parsed: {fun h1: (inc: number -> number, num: number) -> number; fun h2: (hint: string) -> unit -> string; fun h3: (f: number -> number, g: number -> number) -> number -> number} //│ diff --git a/ts2mls/js/src/test/diff/InterfaceMember.d.mls b/ts2mls/js/src/test/diff/InterfaceMember.d.mls index 53a5e69d1d..30b8dadda6 100644 --- a/ts2mls/js/src/test/diff/InterfaceMember.d.mls +++ b/ts2mls/js/src/test/diff/InterfaceMember.d.mls @@ -36,6 +36,6 @@ trait Next(): Simple {} trait TTT() { fun ttt(x: T): T } -//│ |#trait| |IFoo|(||)| |{|→|#let| |a|#:| |string|↵|#fun| |b|(|x|#:| |number|)|#:| |number|↵|#fun| |c|(||)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |d|(|x|#:| |string|)|#:| |unit|←|↵|}|↵|#trait| |II|‹|T|›|(||)| |{|→|#fun| |test|(|x|#:| |T|)|#:| |number|←|↵|}|↵|#fun| |create|(||)|#:| |{|v|#:| |number|,|}|↵|#fun| |get|(|x|#:| |{|t|#:| |string|,|}|)|#:| |string|↵|#trait| |IEvent|(||)| |{|→|#fun| |callback|(||)|#:| |(|number|)| |=>| |unit|←|↵|}|↵|#trait| |SearchFunc|(||)| |{|→|#fun| |__call|(|source|#:| |string|,| |subString|#:| |string|)|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |StringArray|(||)| |{|→|#fun| |__index|(|index|#:| |number|)|#:| |string|←|↵|}|↵|#trait| |Counter|(||)| |{|→|#fun| |__call|(|start|#:| |number|)|#:| |string|↵|#let| |interval|#:| |number|↵|#fun| |reset|(||)|#:| |unit|←|↵|}|↵|#trait| |Simple|(||)| |{|→|#let| |a|#:| |number|↵|#fun| |b|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |string|←|↵|}|↵|#trait| |Simple2|‹|T|›|(||)| |{|→|#let| |abc|#:| |T|←|↵|}|↵|#trait| |Next|(||)|#:| |Simple| |{||}|↵|#trait| |TTT|‹|T|›|(||)| |{|→|#fun| |ttt|(|x|#:| |T|)|#:| |T|←|↵|}| +//│ |#trait| |IFoo|(||)| |{|→|#let| |a|#:| |string|↵|#fun| |b|(|x|#:| |number|)|#:| |number|↵|#fun| |c|(||)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |d|(|x|#:| |string|)|#:| |unit|←|↵|}|↵|#trait| |II|‹|T|›|(||)| |{|→|#fun| |test|(|x|#:| |T|)|#:| |number|←|↵|}|↵|#fun| |create|(||)|#:| |{|v|#:| |number|,|}|↵|#fun| |get|(|x|#:| |{|t|#:| |string|,|}|)|#:| |string|↵|#trait| |IEvent|(||)| |{|→|#fun| |callback|(||)|#:| |(|number|)| |#=>| |unit|←|↵|}|↵|#trait| |SearchFunc|(||)| |{|→|#fun| |__call|(|source|#:| |string|,| |subString|#:| |string|)|#:| |(|false|)| ||| |(|true|)|←|↵|}|↵|#trait| |StringArray|(||)| |{|→|#fun| |__index|(|index|#:| |number|)|#:| |string|←|↵|}|↵|#trait| |Counter|(||)| |{|→|#fun| |__call|(|start|#:| |number|)|#:| |string|↵|#let| |interval|#:| |number|↵|#fun| |reset|(||)|#:| |unit|←|↵|}|↵|#trait| |Simple|(||)| |{|→|#let| |a|#:| |number|↵|#fun| |b|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |string|←|↵|}|↵|#trait| |Simple2|‹|T|›|(||)| |{|→|#let| |abc|#:| |T|←|↵|}|↵|#trait| |Next|(||)|#:| |Simple| |{||}|↵|#trait| |TTT|‹|T|›|(||)| |{|→|#fun| |ttt|(|x|#:| |T|)|#:| |T|←|↵|}| //│ Parsed: {trait IFoo() {let a: string; fun b: (x: number) -> number; fun c: () -> bool; fun d: (x: string) -> unit}; trait II‹T›() {fun test: (x: T) -> number}; fun create: () -> {v: number}; fun get: (x: {t: string}) -> string; trait IEvent() {fun callback: () -> number -> unit}; trait SearchFunc() {fun __call: (source: string, subString: string) -> bool}; trait StringArray() {fun __index: (index: number) -> string}; trait Counter() {fun __call: (start: number) -> string; let interval: number; fun reset: () -> unit}; trait Simple() {let a: number; fun b: (x: bool) -> string}; trait Simple2‹T›() {let abc: T}; trait Next(): Simple {}; trait TTT‹T›() {fun ttt: (x: T) -> T}} //│ diff --git a/ts2mls/js/src/test/diff/Intersection.d.mls b/ts2mls/js/src/test/diff/Intersection.d.mls index 50d28c76b4..54213af525 100644 --- a/ts2mls/js/src/test/diff/Intersection.d.mls +++ b/ts2mls/js/src/test/diff/Intersection.d.mls @@ -13,10 +13,10 @@ fun iii(x: (IA) & (IB)): (IA) & (IB) fun uu(x: ((((U) & (T)) | ((U) & (P))) | ((V) & (T))) | ((V) & (P))): ((((U) & (T)) | ((U) & (P))) | ((V) & (T))) | ((V) & (P)) fun iiii(x: ((U) & (T)) & (V)): ((U) & (T)) & (V) fun arr(a: (MutArray) & (MutArray)): (MutArray) & (MutArray) -fun tt(x: ((U, T, )) & ((V, V, ))): ((U, T, )) & ((V, V, )) +fun tt(x: ([U, T]) & ([V, V])): ([U, T]) & ([V, V]) class A() {} class B() {} fun inter(c: (A) & (B)): (A) & (B) -//│ |#fun| |extend|‹|T|,| |U|›|(|first|#:| |T|,| |second|#:| |U|)|#:| |(|T|)| |&| |(|U|)|↵|#fun| |foo|‹|T|,| |U|›|(|x|#:| |(|T|)| |&| |(|U|)|)|#:| |unit|↵|#fun| |over|(|f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|)|#:| |string|↵|#trait| |IA|(||)| |{|→|#let| |x|#:| |number|←|↵|}|↵|#trait| |IB|(||)| |{|→|#let| |y|#:| |number|←|↵|}|↵|#fun| |iii|(|x|#:| |(|IA|)| |&| |(|IB|)|)|#:| |(|IA|)| |&| |(|IB|)|↵|#fun| |uu|‹|U|,| |V|,| |T|,| |P|›|(|x|#:| |(|(|(|(|U|)| |&| |(|T|)|)| ||| |(|(|U|)| |&| |(|P|)|)|)| ||| |(|(|V|)| |&| |(|T|)|)|)| ||| |(|(|V|)| |&| |(|P|)|)|)|#:| |(|(|(|(|U|)| |&| |(|T|)|)| ||| |(|(|U|)| |&| |(|P|)|)|)| ||| |(|(|V|)| |&| |(|T|)|)|)| ||| |(|(|V|)| |&| |(|P|)|)|↵|#fun| |iiii|‹|U|,| |T|,| |V|›|(|x|#:| |(|(|U|)| |&| |(|T|)|)| |&| |(|V|)|)|#:| |(|(|U|)| |&| |(|T|)|)| |&| |(|V|)|↵|#fun| |arr|‹|U|,| |T|›|(|a|#:| |(|MutArray|‹|U|›|)| |&| |(|MutArray|‹|T|›|)|)|#:| |(|MutArray|‹|U|›|)| |&| |(|MutArray|‹|T|›|)|↵|#fun| |tt|‹|U|,| |T|,| |V|›|(|x|#:| |(|(|U|,| |T|,| |)|)| |&| |(|(|V|,| |V|,| |)|)|)|#:| |(|(|U|,| |T|,| |)|)| |&| |(|(|V|,| |V|,| |)|)|↵|#class| |A|(||)| |{||}|↵|#class| |B|(||)| |{||}|↵|#fun| |inter|(|c|#:| |(|A|)| |&| |(|B|)|)|#:| |(|A|)| |&| |(|B|)| +//│ |#fun| |extend|‹|T|,| |U|›|(|first|#:| |T|,| |second|#:| |U|)|#:| |(|T|)| |&| |(|U|)|↵|#fun| |foo|‹|T|,| |U|›|(|x|#:| |(|T|)| |&| |(|U|)|)|#:| |unit|↵|#fun| |over|(|f|#:| |(|(|number|)| |#=>| |string|)| |&| |(|(|object|)| |#=>| |string|)|)|#:| |string|↵|#trait| |IA|(||)| |{|→|#let| |x|#:| |number|←|↵|}|↵|#trait| |IB|(||)| |{|→|#let| |y|#:| |number|←|↵|}|↵|#fun| |iii|(|x|#:| |(|IA|)| |&| |(|IB|)|)|#:| |(|IA|)| |&| |(|IB|)|↵|#fun| |uu|‹|U|,| |V|,| |T|,| |P|›|(|x|#:| |(|(|(|(|U|)| |&| |(|T|)|)| ||| |(|(|U|)| |&| |(|P|)|)|)| ||| |(|(|V|)| |&| |(|T|)|)|)| ||| |(|(|V|)| |&| |(|P|)|)|)|#:| |(|(|(|(|U|)| |&| |(|T|)|)| ||| |(|(|U|)| |&| |(|P|)|)|)| ||| |(|(|V|)| |&| |(|T|)|)|)| ||| |(|(|V|)| |&| |(|P|)|)|↵|#fun| |iiii|‹|U|,| |T|,| |V|›|(|x|#:| |(|(|U|)| |&| |(|T|)|)| |&| |(|V|)|)|#:| |(|(|U|)| |&| |(|T|)|)| |&| |(|V|)|↵|#fun| |arr|‹|U|,| |T|›|(|a|#:| |(|MutArray|‹|U|›|)| |&| |(|MutArray|‹|T|›|)|)|#:| |(|MutArray|‹|U|›|)| |&| |(|MutArray|‹|T|›|)|↵|#fun| |tt|‹|U|,| |T|,| |V|›|(|x|#:| |(|[|U|,| |T|]|)| |&| |(|[|V|,| |V|]|)|)|#:| |(|[|U|,| |T|]|)| |&| |(|[|V|,| |V|]|)|↵|#class| |A|(||)| |{||}|↵|#class| |B|(||)| |{||}|↵|#fun| |inter|(|c|#:| |(|A|)| |&| |(|B|)|)|#:| |(|A|)| |&| |(|B|)| //│ Parsed: {fun extend: (first: T, second: U) -> (T & U); fun foo: (x: T & U) -> unit; fun over: (f: number -> string & object -> string) -> string; trait IA() {let x: number}; trait IB() {let y: number}; fun iii: (x: IA & IB) -> (IA & IB); fun uu: (x: U & T | U & P | V & T | V & P) -> (U & T | U & P | V & T | V & P); fun iiii: (x: U & T & V) -> (U & T & V); fun arr: (a: MutArray[U] & MutArray[T]) -> (MutArray[U] & MutArray[T]); fun tt: (x: [U, T] & [V, V]) -> ([U, T] & [V, V]); class A() {}; class B() {}; fun inter: (c: A & B) -> (A & B)} //│ diff --git a/ts2mls/js/src/test/diff/Optional.d.mls b/ts2mls/js/src/test/diff/Optional.d.mls index bacc22d276..36787b151e 100644 --- a/ts2mls/js/src/test/diff/Optional.d.mls +++ b/ts2mls/js/src/test/diff/Optional.d.mls @@ -13,13 +13,13 @@ fun getOrElse(arr: (MutArray) | (undefined)): object class ABC() {} fun testABC(abc: (ABC) | (undefined)): unit fun testSquareConfig(conf: (SquareConfig) | (undefined)): unit -fun err(msg: ((number, string, )) | (undefined)): unit +fun err(msg: ([number, string]) | (undefined)): unit fun toStr(x: (((number) | (false)) | (true)) | (undefined)): string fun boo(x: ((T) & (U)) | (undefined)): unit class B() { let b: T } fun boom(b: (B) | (undefined)): anything -//│ |#fun| |buildName|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName2|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName3|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |buildName4|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|anything|›|)|#:| |string|↵|#trait| |SquareConfig|(||)| |{|→|#let| |color|#:| |(|string|)| ||| |(|#undefined|)|↵|#let| |width|#:| |(|number|)| ||| |(|#undefined|)|←|↵|}|↵|#fun| |did|(|x|#:| |number|,| |f|#:| |(|(|number|)| |=>| |number|)| ||| |(|#undefined|)|)|#:| |number|↵|#fun| |getOrElse|(|arr|#:| |(|MutArray|‹|object|›|)| ||| |(|#undefined|)|)|#:| |object|↵|#class| |ABC|(||)| |{||}|↵|#fun| |testABC|(|abc|#:| |(|ABC|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |testSquareConfig|(|conf|#:| |(|SquareConfig|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |err|(|msg|#:| |(|(|number|,| |string|,| |)|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |toStr|(|x|#:| |(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |boo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|)| ||| |(|#undefined|)|)|#:| |unit|↵|#class| |B|‹|T|›|(||)| |{|→|#let| |b|#:| |T|←|↵|}|↵|#fun| |boom|(|b|#:| |(|B|‹|nothing|›|)| ||| |(|#undefined|)|)|#:| |anything| +//│ |#fun| |buildName|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName2|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName3|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |buildName4|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|anything|›|)|#:| |string|↵|#trait| |SquareConfig|(||)| |{|→|#let| |color|#:| |(|string|)| ||| |(|#undefined|)|↵|#let| |width|#:| |(|number|)| ||| |(|#undefined|)|←|↵|}|↵|#fun| |did|(|x|#:| |number|,| |f|#:| |(|(|number|)| |#=>| |number|)| ||| |(|#undefined|)|)|#:| |number|↵|#fun| |getOrElse|(|arr|#:| |(|MutArray|‹|object|›|)| ||| |(|#undefined|)|)|#:| |object|↵|#class| |ABC|(||)| |{||}|↵|#fun| |testABC|(|abc|#:| |(|ABC|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |testSquareConfig|(|conf|#:| |(|SquareConfig|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |err|(|msg|#:| |(|[|number|,| |string|]|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |toStr|(|x|#:| |(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |boo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|)| ||| |(|#undefined|)|)|#:| |unit|↵|#class| |B|‹|T|›|(||)| |{|→|#let| |b|#:| |T|←|↵|}|↵|#fun| |boom|(|b|#:| |(|B|‹|nothing|›|)| ||| |(|#undefined|)|)|#:| |anything| //│ Parsed: {fun buildName: (firstName: string, lastName: string | undefined) -> string; fun buildName2: (firstName: string, lastName: string | undefined) -> string; fun buildName3: (firstName: string, lastName: MutArray[string]) -> string; fun buildName4: (firstName: string, lastName: MutArray[anything]) -> string; trait SquareConfig() {let color: string | undefined; let width: number | undefined}; fun did: (x: number, f: number -> number | undefined) -> number; fun getOrElse: (arr: MutArray[object] | undefined) -> object; class ABC() {}; fun testABC: (abc: ABC | undefined) -> unit; fun testSquareConfig: (conf: SquareConfig | undefined) -> unit; fun err: (msg: [number, string] | undefined) -> unit; fun toStr: (x: number | false | true | undefined) -> string; fun boo: (x: T & U | undefined) -> unit; class B‹T›() {let b: T}; fun boom: (b: B[nothing] | undefined) -> anything} //│ diff --git a/ts2mls/js/src/test/diff/Overload.d.mls b/ts2mls/js/src/test/diff/Overload.d.mls index ce7960b267..75a0d3fe9c 100644 --- a/ts2mls/js/src/test/diff/Overload.d.mls +++ b/ts2mls/js/src/test/diff/Overload.d.mls @@ -12,7 +12,7 @@ class N() {} fun id: ((M) => unit) & ((N) => unit) fun tst: (({z: number,}) => {y: string,}) & (({z: (false) | (true),}) => {y: string,}) fun op: ((number) => ((number) | (undefined)) => unit) & ((number) => (((false) | (true)) | (undefined)) => unit) -fun swap: (((number, string, )) => (number, string, )) & (((string, number, )) => (number, string, )) +fun swap: (([number, string]) => [number, string]) & (([string, number]) => [number, string]) fun u: ((((number) | (false)) | (true)) => string) & ((object) => string) fun doSome(x: anything): unit /* warning: the overload of function doSome is not supported yet. */ module XX { @@ -22,6 +22,6 @@ class WWW() { fun F(x: T): anything /* warning: the overload of function F is not supported yet. */ } fun baz(): anything /* warning: the overload of function baz is not supported yet. */ -//│ |#fun| |f|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |=>| |string|)| |&| |(|(|string|)| |=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |=>| |unit|)| |=>| |(|number|)| |=>| |unit|)| |&| |(|(|(|string|)| |=>| |unit|)| |=>| |(|string|)| |=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |=>| |unit| |=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |=>| |unit|)| |&| |(|(|N|)| |=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |=>| |(|(|number|)| ||| |(|#undefined|)|)| |=>| |unit|)| |&| |(|(|number|)| |=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|#undefined|)|)| |=>| |unit|)|↵|#fun| |swap|#:| |(|(|(|number|,| |string|,| |)|)| |=>| |(|number|,| |string|,| |)|)| |&| |(|(|(|string|,| |number|,| |)|)| |=>| |(|number|,| |string|,| |)|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |=>| |string|)| |&| |(|(|object|)| |=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#module| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| +//│ |#fun| |f|#:| |(|(|number|)| |#=>| |string|)| |&| |(|(|string|)| |#=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |#=>| |string|)| |&| |(|(|string|)| |#=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |#=>| |unit|)| |#=>| |(|number|)| |#=>| |unit|)| |&| |(|(|(|string|)| |#=>| |unit|)| |#=>| |(|string|)| |#=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |#=>| |unit| |#=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |#=>| |unit| |#=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |#=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |#=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |#=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |#=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |#=>| |unit|)| |&| |(|(|N|)| |#=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |#=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |#=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |#=>| |(|(|number|)| ||| |(|#undefined|)|)| |#=>| |unit|)| |&| |(|(|number|)| |#=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|#undefined|)|)| |#=>| |unit|)|↵|#fun| |swap|#:| |(|(|[|number|,| |string|]|)| |#=>| |[|number|,| |string|]|)| |&| |(|(|[|string|,| |number|]|)| |#=>| |[|number|,| |string|]|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |#=>| |string|)| |&| |(|(|object|)| |#=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#module| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| //│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | undefined) -> unit & number -> (false | true | undefined) -> unit; fun swap: ([number, string]) -> [number, string] & ([string, number]) -> [number, string]; fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything) -> unit; module XX {fun f: (x: T, n: anything) -> string}; class WWW() {fun F: (x: T) -> anything}; fun baz: () -> anything} //│ diff --git a/ts2mls/js/src/test/diff/Tuple.d.mls b/ts2mls/js/src/test/diff/Tuple.d.mls index 73c4c9b167..672f433a2c 100644 --- a/ts2mls/js/src/test/diff/Tuple.d.mls +++ b/ts2mls/js/src/test/diff/Tuple.d.mls @@ -1,21 +1,21 @@ :NewDefs :ParseOnly -fun key(x: (string, (false) | (true), )): string -fun value(x: (string, (false) | (true), )): (false) | (true) -fun third(x: (number, number, number, )): number -fun vec2(x: number, y: number): (number, number, ) -fun twoFunctions(ff: ((number) => number, (number) => number, ), x: number): number -fun tupleIt(x: string): (unit => string, ) -fun s(flag: (false) | (true)): ((string) | (number), ((number) | (false)) | (true), ) -fun s2(t: ((false) | (true), (string) | (number), )): (string) | (number) -fun ex(x: T, y: U): (T, U, (T) & (U), ) -fun foo(x: ((T) & (U), )): unit -fun conv(x: {y: number,}): ({y: number,}, {z: string,}, ) +fun key(x: [string, (false) | (true)]): string +fun value(x: [string, (false) | (true)]): (false) | (true) +fun third(x: [number, number, number]): number +fun vec2(x: number, y: number): [number, number] +fun twoFunctions(ff: [(number) => number, (number) => number], x: number): number +fun tupleIt(x: string): [unit => string] +fun s(flag: (false) | (true)): [(string) | (number), ((number) | (false)) | (true)] +fun s2(t: [(false) | (true), (string) | (number)]): (string) | (number) +fun ex(x: T, y: U): [T, U, (T) & (U)] +fun foo(x: [(T) & (U)]): unit +fun conv(x: {y: number,}): [{y: number,}, {z: string,}] class A() { let x: number } class B() {} -fun swap(x: (A, B, )): (B, A, ) -//│ |#fun| |key|(|x|#:| |(|string|,| |(|false|)| ||| |(|true|)|,| |)|)|#:| |string|↵|#fun| |value|(|x|#:| |(|string|,| |(|false|)| ||| |(|true|)|,| |)|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |third|(|x|#:| |(|number|,| |number|,| |number|,| |)|)|#:| |number|↵|#fun| |vec2|(|x|#:| |number|,| |y|#:| |number|)|#:| |(|number|,| |number|,| |)|↵|#fun| |twoFunctions|(|ff|#:| |(|(|number|)| |=>| |number|,| |(|number|)| |=>| |number|,| |)|,| |x|#:| |number|)|#:| |number|↵|#fun| |tupleIt|(|x|#:| |string|)|#:| |(|unit| |=>| |string|,| |)|↵|#fun| |s|(|flag|#:| |(|false|)| ||| |(|true|)|)|#:| |(|(|string|)| ||| |(|number|)|,| |(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|,| |)|↵|#fun| |s2|(|t|#:| |(|(|false|)| ||| |(|true|)|,| |(|string|)| ||| |(|number|)|,| |)|)|#:| |(|string|)| ||| |(|number|)|↵|#fun| |ex|‹|T|,| |U|›|(|x|#:| |T|,| |y|#:| |U|)|#:| |(|T|,| |U|,| |(|T|)| |&| |(|U|)|,| |)|↵|#fun| |foo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|,| |)|)|#:| |unit|↵|#fun| |conv|(|x|#:| |{|y|#:| |number|,|}|)|#:| |(|{|y|#:| |number|,|}|,| |{|z|#:| |string|,|}|,| |)|↵|#class| |A|(||)| |{|→|#let| |x|#:| |number|←|↵|}|↵|#class| |B|(||)| |{||}|↵|#fun| |swap|(|x|#:| |(|A|,| |B|,| |)|)|#:| |(|B|,| |A|,| |)| -//│ Parsed: {fun key: (x: [string, bool]) -> string; fun value: (x: [string, bool]) -> bool; fun third: (x: [number, number, number]) -> number; fun vec2: (x: number, y: number) -> [number, number]; fun twoFunctions: (ff: [number -> number, number -> number], x: number) -> number; fun tupleIt: (x: string) -> unit -> string; fun s: (flag: bool) -> [string | number, number | false | true]; fun s2: (t: [bool, string | number]) -> (string | number); fun ex: (x: T, y: U) -> [T, U, T & U]; fun foo: (x: T & U) -> unit; fun conv: (x: {y: number}) -> [{y: number}, {z: string}]; class A() {let x: number}; class B() {}; fun swap: (x: [A, B]) -> [B, A]} +fun swap(x: [A, B]): [B, A] +//│ |#fun| |key|(|x|#:| |[|string|,| |(|false|)| ||| |(|true|)|]|)|#:| |string|↵|#fun| |value|(|x|#:| |[|string|,| |(|false|)| ||| |(|true|)|]|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |third|(|x|#:| |[|number|,| |number|,| |number|]|)|#:| |number|↵|#fun| |vec2|(|x|#:| |number|,| |y|#:| |number|)|#:| |[|number|,| |number|]|↵|#fun| |twoFunctions|(|ff|#:| |[|(|number|)| |#=>| |number|,| |(|number|)| |#=>| |number|]|,| |x|#:| |number|)|#:| |number|↵|#fun| |tupleIt|(|x|#:| |string|)|#:| |[|unit| |#=>| |string|]|↵|#fun| |s|(|flag|#:| |(|false|)| ||| |(|true|)|)|#:| |[|(|string|)| ||| |(|number|)|,| |(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|]|↵|#fun| |s2|(|t|#:| |[|(|false|)| ||| |(|true|)|,| |(|string|)| ||| |(|number|)|]|)|#:| |(|string|)| ||| |(|number|)|↵|#fun| |ex|‹|T|,| |U|›|(|x|#:| |T|,| |y|#:| |U|)|#:| |[|T|,| |U|,| |(|T|)| |&| |(|U|)|]|↵|#fun| |foo|‹|T|,| |U|›|(|x|#:| |[|(|T|)| |&| |(|U|)|]|)|#:| |unit|↵|#fun| |conv|(|x|#:| |{|y|#:| |number|,|}|)|#:| |[|{|y|#:| |number|,|}|,| |{|z|#:| |string|,|}|]|↵|#class| |A|(||)| |{|→|#let| |x|#:| |number|←|↵|}|↵|#class| |B|(||)| |{||}|↵|#fun| |swap|(|x|#:| |[|A|,| |B|]|)|#:| |[|B|,| |A|]| +//│ Parsed: {fun key: (x: [string, bool]) -> string; fun value: (x: [string, bool]) -> bool; fun third: (x: [number, number, number]) -> number; fun vec2: (x: number, y: number) -> [number, number]; fun twoFunctions: (ff: [number -> number, number -> number], x: number) -> number; fun tupleIt: (x: string) -> [unit -> string]; fun s: (flag: bool) -> [string | number, number | false | true]; fun s2: (t: [bool, string | number]) -> (string | number); fun ex: (x: T, y: U) -> [T, U, T & U]; fun foo: (x: [T & U]) -> unit; fun conv: (x: {y: number}) -> [{y: number}, {z: string}]; class A() {let x: number}; class B() {}; fun swap: (x: [A, B]) -> [B, A]} //│ diff --git a/ts2mls/js/src/test/diff/Type.d.mls b/ts2mls/js/src/test/diff/Type.d.mls index 6b81712d9c..1839cd27cb 100644 --- a/ts2mls/js/src/test/diff/Type.d.mls +++ b/ts2mls/js/src/test/diff/Type.d.mls @@ -9,7 +9,7 @@ trait Some() { } type Option = (None) | (Some) type Func = (number) => number -type S2 = (string, string, ) +type S2 = [string, string] trait I1() {} trait I2() {} type I3 = (I1) & (I2) @@ -17,7 +17,7 @@ type StringArray = Array type SomeInterface = {x: number,y: number,} class ABC() {} type DEF = ABC -type TP = (A, B, C, ) +type TP = [A, B, C] module NA { fun fb(b: string): unit type B = string @@ -28,6 +28,6 @@ class NC() { type G = ABC let none: {_tag: "None",} fun some(a: A): (None) | (Some) -//│ |#trait| |None|(||)| |{|→|#let| |_tag|#:| |"None"|←|↵|}|↵|#trait| |Some|‹|A|›|(||)| |{|→|#let| |_tag|#:| |"Some"|↵|#let| |value|#:| |A|←|↵|}|↵|#type| |Option|‹|A|›| |#=| |(|None|)| ||| |(|Some|‹|A|›|)|↵|#type| |Func| |#=| |(|number|)| |=>| |number|↵|#type| |S2| |#=| |(|string|,| |string|,| |)|↵|#trait| |I1|(||)| |{||}|↵|#trait| |I2|(||)| |{||}|↵|#type| |I3| |#=| |(|I1|)| |&| |(|I2|)|↵|#type| |StringArray| |#=| |Array|‹|string|›|↵|#type| |SomeInterface| |#=| |{|x|#:| |number|,|y|#:| |number|,|}|↵|#class| |ABC|(||)| |{||}|↵|#type| |DEF| |#=| |ABC|↵|#type| |TP|‹|A|,| |B|,| |C|›| |#=| |(|A|,| |B|,| |C|,| |)|↵|#module| |NA| |{|→|#fun| |fb|(|b|#:| |string|)|#:| |unit|↵|#type| |B| |#=| |string|←|↵|}|↵|#class| |NC|(||)| |{|→|#let| |b|#:| |string|←|↵|}|↵|#type| |G| |#=| |ABC|↵|#let| |none|#:| |{|_tag|#:| |"None"|,|}|↵|#fun| |some|‹|A|›|(|a|#:| |A|)|#:| |(|None|)| ||| |(|Some|‹|A|›|)| +//│ |#trait| |None|(||)| |{|→|#let| |_tag|#:| |"None"|←|↵|}|↵|#trait| |Some|‹|A|›|(||)| |{|→|#let| |_tag|#:| |"Some"|↵|#let| |value|#:| |A|←|↵|}|↵|#type| |Option|‹|A|›| |#=| |(|None|)| ||| |(|Some|‹|A|›|)|↵|#type| |Func| |#=| |(|number|)| |#=>| |number|↵|#type| |S2| |#=| |[|string|,| |string|]|↵|#trait| |I1|(||)| |{||}|↵|#trait| |I2|(||)| |{||}|↵|#type| |I3| |#=| |(|I1|)| |&| |(|I2|)|↵|#type| |StringArray| |#=| |Array|‹|string|›|↵|#type| |SomeInterface| |#=| |{|x|#:| |number|,|y|#:| |number|,|}|↵|#class| |ABC|(||)| |{||}|↵|#type| |DEF| |#=| |ABC|↵|#type| |TP|‹|A|,| |B|,| |C|›| |#=| |[|A|,| |B|,| |C|]|↵|#module| |NA| |{|→|#fun| |fb|(|b|#:| |string|)|#:| |unit|↵|#type| |B| |#=| |string|←|↵|}|↵|#class| |NC|(||)| |{|→|#let| |b|#:| |string|←|↵|}|↵|#type| |G| |#=| |ABC|↵|#let| |none|#:| |{|_tag|#:| |"None"|,|}|↵|#fun| |some|‹|A|›|(|a|#:| |A|)|#:| |(|None|)| ||| |(|Some|‹|A|›|)| //│ Parsed: {trait None() {let _tag: "None"}; trait Some‹A›() {let _tag: "Some"; let value: A}; type alias Option‹A›: None | Some[A] {}; type alias Func: number -> number {}; type alias S2: [string, string] {}; trait I1() {}; trait I2() {}; type alias I3: I1 & I2 {}; type alias StringArray: Array[string] {}; type alias SomeInterface: {x: number, y: number} {}; class ABC() {}; type alias DEF: ABC {}; type alias TP‹A, B, C›: [A, B, C] {}; module NA {fun fb: (b: string) -> unit; type alias B: string {}}; class NC() {let b: string}; type alias G: ABC {}; let none: {_tag: "None"}; fun some: (a: A) -> (None | Some[A])} //│ diff --git a/ts2mls/js/src/test/diff/Union.d.mls b/ts2mls/js/src/test/diff/Union.d.mls index de8187d0da..8ad24730be 100644 --- a/ts2mls/js/src/test/diff/Union.d.mls +++ b/ts2mls/js/src/test/diff/Union.d.mls @@ -4,9 +4,9 @@ fun getString(x: (((string) | (number)) | (false)) | (true)): string fun test(x: (false) | (true)): (string) | (number) fun run(f: ((number) => number) | ((number) => string)): anything fun get(arr: (MutArray) | (MutArray)): unit -fun get2(t: ((string, string, )) | ((number, string, ))): string +fun get2(t: ([string, string]) | ([number, string])): string fun typeVar(x: (T) | (U)): (T) | (U) fun uuuu(x: (((string) | (number)) | (false)) | (true)): (((string) | (number)) | (false)) | (true) -//│ |#fun| |getString|(|x|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)|)|#:| |string|↵|#fun| |test|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |(|string|)| ||| |(|number|)|↵|#fun| |run|(|f|#:| |(|(|number|)| |=>| |number|)| ||| |(|(|number|)| |=>| |string|)|)|#:| |anything|↵|#fun| |get|(|arr|#:| |(|MutArray|‹|number|›|)| ||| |(|MutArray|‹|string|›|)|)|#:| |unit|↵|#fun| |get2|(|t|#:| |(|(|string|,| |string|,| |)|)| ||| |(|(|number|,| |string|,| |)|)|)|#:| |string|↵|#fun| |typeVar|‹|T|,| |U|›|(|x|#:| |(|T|)| ||| |(|U|)|)|#:| |(|T|)| ||| |(|U|)|↵|#fun| |uuuu|(|x|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)|)|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)| +//│ |#fun| |getString|(|x|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)|)|#:| |string|↵|#fun| |test|(|x|#:| |(|false|)| ||| |(|true|)|)|#:| |(|string|)| ||| |(|number|)|↵|#fun| |run|(|f|#:| |(|(|number|)| |#=>| |number|)| ||| |(|(|number|)| |#=>| |string|)|)|#:| |anything|↵|#fun| |get|(|arr|#:| |(|MutArray|‹|number|›|)| ||| |(|MutArray|‹|string|›|)|)|#:| |unit|↵|#fun| |get2|(|t|#:| |(|[|string|,| |string|]|)| ||| |(|[|number|,| |string|]|)|)|#:| |string|↵|#fun| |typeVar|‹|T|,| |U|›|(|x|#:| |(|T|)| ||| |(|U|)|)|#:| |(|T|)| ||| |(|U|)|↵|#fun| |uuuu|(|x|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)|)|#:| |(|(|(|string|)| ||| |(|number|)|)| ||| |(|false|)|)| ||| |(|true|)| //│ Parsed: {fun getString: (x: string | number | false | true) -> string; fun test: (x: bool) -> (string | number); fun run: (f: number -> number | number -> string) -> anything; fun get: (arr: MutArray[number] | MutArray[string]) -> unit; fun get2: (t: [string, string] | [number, string]) -> string; fun typeVar: (x: T | U) -> (T | U); fun uuuu: (x: string | number | false | true) -> (string | number | false | true)} //│ From 99bea65b0aea9141a64b362651b9c603edc19309 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 2 Oct 2023 02:25:36 +0800 Subject: [PATCH 467/498] Display `undefined` as `()` in pretty-printer --- shared/src/main/scala/mlscript/helpers.scala | 3 +- .../src/test/diff/codegen/ConstructorStmt.mls | 4 +-- shared/src/test/diff/codegen/NuFuns.mls | 12 +++---- shared/src/test/diff/codegen/ValLet.mls | 4 +-- shared/src/test/diff/nu/ArrayProg.mls | 6 ++-- shared/src/test/diff/nu/BadBlocks.mls | 4 +-- shared/src/test/diff/nu/FlatMonads.mls | 36 +++++++++---------- shared/src/test/diff/nu/FlatMonads_repro.mls | 8 ++--- shared/src/test/diff/nu/Jonathan.mls | 16 ++++----- shared/src/test/diff/nu/LetRec.mls | 6 ++-- shared/src/test/diff/nu/MissingTypeArg.mls | 10 +++--- shared/src/test/diff/nu/NamedArgs.mls | 18 +++++----- shared/src/test/diff/nu/Object.mls | 2 +- shared/src/test/diff/nu/Parens.mls | 8 ++--- shared/src/test/diff/nu/Subscripts.mls | 2 +- shared/src/test/diff/nu/UndefMatching.mls | 14 ++++---- shared/src/test/diff/nu/Unit.mls | 34 +++++++++--------- shared/src/test/diff/parser/NamedArrays.mls | 2 +- shared/src/test/diff/ucs/JSON.mls | 2 +- shared/src/test/diff/ucs/zipWith.mls | 2 +- ts2mls/js/src/test/diff/BasicFunctions.d.mls | 2 +- ts2mls/js/src/test/diff/Dec.d.mls | 2 +- ts2mls/js/src/test/diff/Optional.d.mls | 2 +- ts2mls/js/src/test/diff/Overload.d.mls | 2 +- 24 files changed, 101 insertions(+), 100 deletions(-) diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index bc2320ca24..64fba3bf1c 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -105,7 +105,8 @@ trait TypeLikeImpl extends Located { self: TypeLike => case Literal(IntLit(n)) => n.toString case Literal(DecLit(n)) => n.toString case Literal(StrLit(s)) => "\"" + s + "\"" - case Literal(UnitLit(b)) => if (b) "undefined" else "null" + case Literal(UnitLit(b)) => + if (b) if (ctx.newDefs) "()" else "undefined" else "null" case PolyType(Nil, body) => body.showIn(ctx, outerPrec) case PolyType(targs, body) => parensIf( s"${targs.iterator.map(_.fold(_.name, _.showIn(ctx, 0))) diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 809f4c394e..400e409897 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -2,7 +2,7 @@ log("Hello!") -//│ undefined +//│ () //│ res //│ = undefined //│ // Output @@ -264,7 +264,7 @@ class Baz() { let baz = Baz() log([baz.x, baz.y]) //│ let baz: Baz -//│ undefined +//│ () //│ baz //│ = Baz {} //│ // Output diff --git a/shared/src/test/diff/codegen/NuFuns.mls b/shared/src/test/diff/codegen/NuFuns.mls index 063a7ae3b9..2c29fcf69f 100644 --- a/shared/src/test/diff/codegen/NuFuns.mls +++ b/shared/src/test/diff/codegen/NuFuns.mls @@ -32,8 +32,8 @@ foo fun main = log("Hello") main -//│ fun main: undefined -//│ undefined +//│ fun main: () +//│ () //│ res //│ = undefined //│ // Output @@ -41,10 +41,10 @@ main fun main = log("Hello") -//│ fun main: undefined +//│ fun main: () main -//│ undefined +//│ () //│ res //│ = undefined //│ // Output @@ -57,8 +57,8 @@ fun main = module M extends B log(2) main -//│ fun main: undefined -//│ undefined +//│ fun main: () +//│ () //│ res //│ = undefined //│ // Output diff --git a/shared/src/test/diff/codegen/ValLet.mls b/shared/src/test/diff/codegen/ValLet.mls index bdb97f41c7..1d12ae033c 100644 --- a/shared/src/test/diff/codegen/ValLet.mls +++ b/shared/src/test/diff/codegen/ValLet.mls @@ -246,7 +246,7 @@ fun f(val x: Int) = x + 1 //│ ╔══[ERROR] Cannot use `val` in this position //│ ║ l.242: (val x: 1) => //│ ╙── ^^^^ -//│ (x: 1) -> undefined +//│ (x: 1) -> () //│ res //│ = [Function: res] @@ -255,7 +255,7 @@ fun f(val x: Int) = x + 1 //│ ╔══[ERROR] Cannot use `val` in this position //│ ║ l.254: (val x: 1) => () //│ ╙── ^^^^ -//│ (x: 1) -> undefined +//│ (x: 1) -> () //│ res //│ = [Function: res] diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index ee0263af73..ebaf155c3c 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -33,12 +33,12 @@ fun zip(xs, ys) = mapi of xs, (x, i) => if ys.[i] is undefined then error y then [x, y] -//│ fun zip: forall 'c 'd. (Array['c], Array[Object & 'd & ~undefined]) -> Array[['c, 'd]] -//│ fun zip: forall 'a 'b. (Array['a], Array[Object & 'b & ~undefined]) -> Array[['a, 'b]] +//│ fun zip: forall 'c 'd. (Array['c], Array[Object & 'd & ~()]) -> Array[['c, 'd]] +//│ fun zip: forall 'a 'b. (Array['a], Array[Object & 'b & ~()]) -> Array[['a, 'b]] zip -//│ forall 'a 'b. (Array['a], Array[Object & 'b & ~undefined]) -> Array[['a, 'b]] +//│ forall 'a 'b. (Array['a], Array[Object & 'b & ~()]) -> Array[['a, 'b]] //│ res //│ = [Function: zip1] diff --git a/shared/src/test/diff/nu/BadBlocks.mls b/shared/src/test/diff/nu/BadBlocks.mls index 11346a5768..cc6e4cc868 100644 --- a/shared/src/test/diff/nu/BadBlocks.mls +++ b/shared/src/test/diff/nu/BadBlocks.mls @@ -8,10 +8,10 @@ fun test = //│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. //│ ║ l.6: fun lol = log("ok") //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ fun test: [undefined, undefined] +//│ fun test: [(), ()] test -//│ [undefined, undefined] +//│ [(), ()] //│ res //│ = [ undefined, undefined ] //│ // Output diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index 25b457e78f..a1ebe26e77 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -38,11 +38,11 @@ class printLine(str: Str) extends IO[undefined] { fun run = log(str) } //│ fun run: Int //│ } //│ class printLine(str: Str) extends IO { -//│ fun bind: forall 'B0. ('A0 -> IO['B0]) -> Bind[undefined & 'A0, 'B0] -//│ fun run: undefined +//│ fun bind: forall 'B0. ('A0 -> IO['B0]) -> Bind[() & 'A0, 'B0] +//│ fun run: () //│ } //│ where -//│ 'A0 := undefined +//│ 'A0 := () //│ 'A := Int @@ -55,7 +55,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ val main: Bind[undefined, 'B] +//│ val main: Bind[(), 'B] //│ where //│ 'B :> Int //│ main @@ -79,7 +79,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ val main: Bind[undefined, 'B] +//│ val main: Bind[(), 'B] //│ where //│ 'B :> Int //│ main @@ -103,7 +103,7 @@ printLine("").bind of [] => error //│ ╟── type `[?A]` does not match type `[]` //│ ║ l.15: class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { //│ ╙── ^ -//│ Bind[undefined, 'B] | error +//│ Bind[(), 'B] | error //│ res //│ = Bind {} @@ -187,7 +187,7 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)) #> _ => sum -//│ val main: Bind[undefined, 'B] +//│ val main: Bind[(), 'B] //│ where //│ 'B :> Int //│ main @@ -205,7 +205,7 @@ fun loop = printLine("Input a positive number: ") #>> _ => readInt #>> n => if n < 0 then loop else Pure(n) -//│ fun loop: forall 'B. Bind[undefined, 'B] +//│ fun loop: forall 'B. Bind[(), 'B] //│ where //│ 'B :> Int @@ -270,7 +270,7 @@ fun loop(ctx) = //│ } -> 'b let r = loop(defaultCtx) -//│ let r: Bind[undefined, 'B] +//│ let r: Bind[(), 'B] //│ where //│ 'B :> Int //│ r @@ -309,10 +309,10 @@ class printLine(str: Str) extends IO { fun run = log(str) } //│ } //│ class printLine(str: Str) extends IO { //│ fun bind: forall 'B0. ('A0 -> IO['B0]) -> Bind['A0, 'B0] -//│ fun run: undefined +//│ fun run: () //│ } //│ where -//│ 'A0 :> undefined +//│ 'A0 :> () //│ 'A :> 42 val main = @@ -322,14 +322,14 @@ val main = val sum = n + m printLine(concat("The sum is: ")(String of sum)).bind of _ => Pure(sum) -//│ val main: Bind[in 'A out undefined | 'A, 'B] +//│ val main: Bind[in 'A out () | 'A, 'B] //│ where //│ 'B :> Int //│ main //│ = Bind {} main -//│ Bind[in 'A out undefined | 'A, 'B] +//│ Bind[in 'A out () | 'A, 'B] //│ where //│ 'B :> Int //│ res @@ -341,13 +341,13 @@ let r = printLine("").bind of 0 => Pure(1) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.340: let r = printLine("").bind of 0 => Pure(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── application of type `undefined` does not match type `0` +//│ ╟── application of type `()` does not match type `0` //│ ║ l.305: class printLine(str: Str) extends IO { fun run = log(str) } //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from integer literal: //│ ║ l.340: let r = printLine("").bind of 0 => Pure(1) //│ ╙── ^ -//│ let r: Bind[in 0 & 'A out undefined | 'A, 'B] | error +//│ let r: Bind[in 0 & 'A out () | 'A, 'B] | error //│ where //│ 'B :> 1 //│ r @@ -364,7 +364,7 @@ Pure(1) //│ ║ ^^^^^^^^^ //│ ║ l.359: Pure(1) //│ ║ ^^^^^^^ -//│ ╟── application of type `undefined` does not have field 'a' +//│ ╟── application of type `()` does not have field 'a' //│ ║ l.305: class printLine(str: Str) extends IO { fun run = log(str) } //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from field selection: @@ -373,7 +373,7 @@ Pure(1) //│ ╟── from reference: //│ ║ l.358: log(x.a) //│ ╙── ^ -//│ let r: Bind[in {a: anything} & 'A out undefined | 'A, 'B] | error +//│ let r: Bind[in {a: anything} & 'A out () | 'A, 'B] | error //│ where //│ 'B :> 1 //│ r @@ -401,7 +401,7 @@ declare fun printLine: Str -> IO[()] //│ declare trait IO[A]: forall 'b. (A -> IO['b]) -> IO['b] { //│ fun run: A //│ } -//│ fun printLine: Str -> IO[undefined] +//│ fun printLine: Str -> IO[()] //│ fun pure: forall 'a. 'a -> IO['a] //│ fun readInt: IO[Int] diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls index 0324236522..938516f499 100644 --- a/shared/src/test/diff/nu/FlatMonads_repro.mls +++ b/shared/src/test/diff/nu/FlatMonads_repro.mls @@ -177,14 +177,14 @@ fun loop = val x: Bind['A, 'B] where undefined : 'A;; 'A : 'B //│ val x: forall 'A 'B. Bind['A, 'B] //│ where -//│ 'A :> undefined +//│ 'A :> () //│ <: 'B -//│ 'B :> undefined +//│ 'B :> () //│ x //│ = x.run -//│ undefined +//│ () //│ res //│ = //│ x is not implemented @@ -192,7 +192,7 @@ x.run val x: Bind['A, 'B] where 'A : undefined;; 'A : 'B //│ val x: forall 'A 'B. Bind['A, 'B] //│ where -//│ 'A <: undefined & 'B +//│ 'A <: () & 'B //│ x //│ = diff --git a/shared/src/test/diff/nu/Jonathan.mls b/shared/src/test/diff/nu/Jonathan.mls index 16753fe9f9..076d38e5ae 100644 --- a/shared/src/test/diff/nu/Jonathan.mls +++ b/shared/src/test/diff/nu/Jonathan.mls @@ -22,7 +22,7 @@ module Block // * Some example functions fun println(x: anything): Effectful[(), IO] fun readLine: Effectful[Str, IO | Block] -//│ fun println: (x: anything) -> Effectful[undefined, IO] +//│ fun println: (x: anything) -> Effectful[(), IO] //│ fun readLine: Effectful[Str, Block | IO] @@ -39,12 +39,12 @@ fun f(x) = x : NonBlocking fun onMousePressed(listener) = let l(e) = listener(e) : NonBlocking l(0).flatMap of a => l(1).flatMap of b => pure of () -//│ fun onMousePressed: forall 'a. ((0 | 1) -> NonBlocking[anything, 'a]) -> Effectful[undefined, 'a & ~Block] +//│ fun onMousePressed: forall 'a. ((0 | 1) -> NonBlocking[anything, 'a]) -> Effectful[(), 'a & ~Block] // * OK: `println` does not block onMousePressed(event => println("Clicked!")) -//│ Effectful[undefined, IO & ~Block] +//│ Effectful[(), IO & ~Block] // * NOT OK: `readLine` blocks :e @@ -55,7 +55,7 @@ onMousePressed(event => readLine.flatMap(println)) //│ ╟── type `Block` does not match type `~Block` //│ ║ l.24: fun readLine: Effectful[Str, IO | Block] //│ ╙── ^^^^^ -//│ Effectful[undefined, IO & ~Block] | error +//│ Effectful[(), IO & ~Block] | error class Event @@ -72,14 +72,14 @@ module Register fun onMousePressed(listener) = let l(e: MouseEvent) = listener(e) : Effectful[(), 'e \ Block \ Register] () -//│ fun onMousePressed: (MouseEvent -> Effectful[undefined, ~Block & ~Register]) -> undefined +//│ fun onMousePressed: (MouseEvent -> Effectful[(), ~Block & ~Register]) -> () // def onMouseClick ( f : Event -> Unit \ { ef - Register }): Unit \ { Register } fun onMouseClick(f: Event -> Effectful[(), 'e \ Register]): Effectful[(), Register] -//│ fun onMouseClick: (f: Event -> Effectful[undefined, ~Register]) -> Effectful[undefined, Register] +//│ fun onMouseClick: (f: Event -> Effectful[(), ~Register]) -> Effectful[(), Register] onMouseClick of ev => pure of () -//│ Effectful[undefined, Register] +//│ Effectful[(), Register] :e onMouseClick of ev => @@ -95,6 +95,6 @@ onMouseClick of ev => //│ ╟── type `Register` does not match type `~Register` //│ ║ l.78: fun onMouseClick(f: Event -> Effectful[(), 'e \ Register]): Effectful[(), Register] //│ ╙── ^^^^^^^^ -//│ Effectful[undefined, Register] | error +//│ Effectful[(), Register] | error diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index e2c7a238c8..c5e80d7775 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -91,21 +91,21 @@ f fun test = let rec f = f -//│ fun test: undefined +//│ fun test: () //│ Code generation encountered an error: //│ unguarded recursive use of by-value binding f :ge // TODO this one should actually be accepted by codegen! fun test = let rec f() = f() -//│ fun test: undefined +//│ fun test: () //│ Code generation encountered an error: //│ unguarded recursive use of by-value binding f :ge // TODO this one should actually be accepted by codegen! fun test = let rec lol = () => lol -//│ fun test: undefined +//│ fun test: () //│ Code generation encountered an error: //│ unguarded recursive use of by-value binding lol diff --git a/shared/src/test/diff/nu/MissingTypeArg.mls b/shared/src/test/diff/nu/MissingTypeArg.mls index 259de26790..f1e4827e70 100644 --- a/shared/src/test/diff/nu/MissingTypeArg.mls +++ b/shared/src/test/diff/nu/MissingTypeArg.mls @@ -13,14 +13,14 @@ fun test(pt1, pt2) = pt1.color === pt1.color and else test(p1, p2) //│ fun test: forall 'a 'b 'c. ('a, 'c) -> Bool //│ where -//│ 'c <: {parent: Object & 'c & ~undefined | undefined} -//│ 'a <: {color: Eql['b] & 'b, parent: Object & 'a & ~undefined | undefined} +//│ 'c <: {parent: Object & 'c & ~() | ()} +//│ 'a <: {color: Eql['b] & 'b, parent: Object & 'a & ~() | ()} // * This works out fine: class MyPoint1[Col](val color: Col, val parent: MyPoint1[Col] | undefined) -//│ class MyPoint1[Col](color: Col, parent: MyPoint1[Col] | undefined) +//│ class MyPoint1[Col](color: Col, parent: MyPoint1[Col] | ()) val p = MyPoint1(0, undefined) //│ val p: MyPoint1['Col] @@ -39,7 +39,7 @@ test(p, p) // * the error is not helpful at all: class MyPoint2[Col](val color: Col, val parent: MyPoint2 | undefined) -//│ class MyPoint2[Col](color: Col, parent: MyPoint2[anything] | undefined) +//│ class MyPoint2[Col](color: Col, parent: MyPoint2[anything] | ()) val p = MyPoint2(0, undefined) //│ val p: MyPoint2[0] @@ -73,7 +73,7 @@ fun test(pt1, pt2) = pt1.color === pt1.color and //│ fun test: forall 'a 'b 'c. ('a, 'c) -> Bool //│ where //│ 'c <: {parent: Object & 'c} -//│ 'a <: {color: Eql['b] & 'b, parent: Object & 'a & ~undefined | undefined} +//│ 'a <: {color: Eql['b] & 'b, parent: Object & 'a & ~() | ()} :e // TODO support test(p, p) diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index 362aca1868..8c4d4606f1 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -2,7 +2,7 @@ fun test(x: 'a) = if x is undefined then 0 else x + 1 -//│ fun test: (x: Int | undefined) -> Int +//│ fun test: (x: Int | ()) -> Int test(x: 0) //│ Int @@ -216,13 +216,13 @@ id(x).ma(y: 2, x: 1) fun print(x: Int) = (y: Int, z: Int) => log([x, y, z]) let p = print(0) -//│ fun print: (x: Int) -> (y: Int, z: Int) -> undefined -//│ let p: (y: Int, z: Int) -> undefined +//│ fun print: (x: Int) -> (y: Int, z: Int) -> () +//│ let p: (y: Int, z: Int) -> () //│ p //│ = [Function (anonymous)] p(z: 1, y: 2) -//│ undefined +//│ () //│ res //│ = undefined //│ // Output @@ -235,8 +235,8 @@ p(z: 1, y: 2) //│ ╔══[ERROR] Cannot use named arguments as the function type has untyped arguments //│ ║ l.234: p(z: 1, y: 2) //│ ╙── ^^^^^^^^^^^^ -//│ fun print: anything -> (anything, anything) -> undefined -//│ let p: (anything, anything) -> undefined +//│ fun print: anything -> (anything, anything) -> () +//│ let p: (anything, anything) -> () //│ error //│ p //│ = [Function (anonymous)] @@ -251,9 +251,9 @@ class Baz() { } Baz().f(y: 1, x: 2) //│ class Baz() { -//│ fun f: (x: Int, y: Int) -> undefined +//│ fun f: (x: Int, y: Int) -> () //│ } -//│ undefined +//│ () //│ res //│ = undefined //│ // Output @@ -262,7 +262,7 @@ Baz().f(y: 1, x: 2) let b = Baz() b.f(y: 1, x: 2) //│ let b: Baz -//│ undefined +//│ () //│ b //│ = Baz {} //│ res diff --git a/shared/src/test/diff/nu/Object.mls b/shared/src/test/diff/nu/Object.mls index 24a69b95ac..b8df29c71d 100644 --- a/shared/src/test/diff/nu/Object.mls +++ b/shared/src/test/diff/nu/Object.mls @@ -82,7 +82,7 @@ fun foo = forall 'a; (x: 'a) => if x is A then true else false //│ ╔══[PARSE ERROR] Expected end of input; found operator instead //│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false //│ ╙── ^ -//│ fun foo: undefined +//│ fun foo: () diff --git a/shared/src/test/diff/nu/Parens.mls b/shared/src/test/diff/nu/Parens.mls index bcca7fd5af..e0b7691159 100644 --- a/shared/src/test/diff/nu/Parens.mls +++ b/shared/src/test/diff/nu/Parens.mls @@ -2,7 +2,7 @@ () -//│ undefined +//│ () //│ res //│ = undefined @@ -14,7 +14,7 @@ //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.10: (,) //│ ╙── ^ -//│ undefined +//│ () //│ res //│ = undefined @@ -48,7 +48,7 @@ let x: () -//│ let x: undefined +//│ let x: () //│ x //│ = @@ -60,7 +60,7 @@ let x: (,) //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.56: let x: (,) //│ ╙── ^ -//│ let x: undefined +//│ let x: () //│ x //│ = diff --git a/shared/src/test/diff/nu/Subscripts.mls b/shared/src/test/diff/nu/Subscripts.mls index 49c60d0089..eb2812dbb6 100644 --- a/shared/src/test/diff/nu/Subscripts.mls +++ b/shared/src/test/diff/nu/Subscripts.mls @@ -19,7 +19,7 @@ xs.[0] + 1 //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.18: xs.[0] + 1 //│ ║ ^^^^^^^^ -//│ ╟── possibly-undefined array access of type `undefined` is not an instance of type `Int` +//│ ╟── possibly-undefined array access of type `()` is not an instance of type `Int` //│ ║ l.18: xs.[0] + 1 //│ ╙── ^^^^ //│ Int | error diff --git a/shared/src/test/diff/nu/UndefMatching.mls b/shared/src/test/diff/nu/UndefMatching.mls index 131a49bf97..57453f5d99 100644 --- a/shared/src/test/diff/nu/UndefMatching.mls +++ b/shared/src/test/diff/nu/UndefMatching.mls @@ -3,7 +3,7 @@ fun foo(x: 'a | undefined) = if x is undefined then error else x -//│ fun foo: forall 'a. (x: Object & 'a & ~undefined | undefined) -> 'a +//│ fun foo: forall 'a. (x: Object & 'a & ~() | ()) -> 'a class Abstract[A] { @@ -22,10 +22,10 @@ class Abstract[A] { } //│ class Abstract[A] { //│ constructor() -//│ fun bar0: (x: Object & A | undefined) -> (Object & A & ~undefined) -//│ fun bar1: (x: Object & A | undefined) -> (Object & A & ~undefined) -//│ fun bar2: (x: Object & A | undefined) -> (Object & A & ~undefined | undefined) -//│ fun baz: (a: Object & A) -> [Object & A & ~undefined, Object & A & ~undefined, Object & A & ~undefined | undefined] +//│ fun bar0: (x: Object & A | ()) -> (Object & A & ~()) +//│ fun bar1: (x: Object & A | ()) -> (Object & A & ~()) +//│ fun bar2: (x: Object & A | ()) -> (Object & A & ~() | ()) +//│ fun baz: (a: Object & A) -> [Object & A & ~(), Object & A & ~(), Object & A & ~() | ()] //│ } @@ -37,7 +37,7 @@ class Abstract[A] { //│ ╔══[ERROR] Type mismatch in `case` expression: //│ ║ l.35: if x is undefined then error else x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `A & ~undefined` is not an instance of type `Object` +//│ ╟── type `A & ~()` is not an instance of type `Object` //│ ║ l.34: fun bar(x: A & ~undefined | undefined) = //│ ║ ^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `Object` @@ -45,7 +45,7 @@ class Abstract[A] { //│ ╙── ^ //│ class Abstract[A] { //│ constructor() -//│ fun bar: (x: undefined | A & ~undefined) -> (A & ~undefined) +//│ fun bar: (x: () | A & ~()) -> (A & ~()) //│ } diff --git a/shared/src/test/diff/nu/Unit.mls b/shared/src/test/diff/nu/Unit.mls index d34d64fdf6..568e79c51c 100644 --- a/shared/src/test/diff/nu/Unit.mls +++ b/shared/src/test/diff/nu/Unit.mls @@ -2,17 +2,17 @@ () -//│ undefined +//│ () //│ res //│ = undefined fun x: () fun x = () -//│ fun x: undefined -//│ fun x: undefined +//│ fun x: () +//│ fun x: () x -//│ undefined +//│ () //│ res //│ = undefined @@ -22,7 +22,7 @@ x : Array['a] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.21: x : Array['a] //│ ║ ^ -//│ ╟── type `undefined` does not match type `Array['a]` +//│ ╟── type `()` does not match type `Array['a]` //│ ║ l.9: fun x: () //│ ║ ^^ //│ ╟── but it flows into reference with expected type `Array['a]` @@ -36,14 +36,14 @@ x : Array['a] //│ = undefined x : undefined -//│ undefined +//│ () //│ res //│ = undefined fun x: () fun x = undefined -//│ fun x: undefined -//│ fun x: undefined +//│ fun x: () +//│ fun x: () :e @@ -52,17 +52,17 @@ fun x = 1 //│ ╔══[ERROR] Type mismatch in definition: //│ ║ l.51: fun x = 1 //│ ║ ^^^^^ -//│ ╟── integer literal of type `1` does not match type `undefined` +//│ ╟── integer literal of type `1` does not match type `()` //│ ║ l.51: fun x = 1 //│ ║ ^ -//│ ╟── but it flows into definition of method x with expected type `undefined` +//│ ╟── but it flows into definition of method x with expected type `()` //│ ║ l.51: fun x = 1 //│ ║ ^^^^^ //│ ╟── Note: constraint arises from literal type: //│ ║ l.50: fun x: () //│ ╙── ^^ //│ fun x: 1 -//│ fun x: undefined +//│ fun x: () (1) @@ -86,7 +86,7 @@ fun x = 1 //│ = [ 1, 2 ] (let x = 1) -//│ undefined +//│ () //│ res //│ = undefined @@ -95,12 +95,12 @@ fun x = 1 //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.94: (let x = 1 in) //│ ╙── ^ -//│ undefined +//│ () //│ res //│ = undefined (log(1)) -//│ undefined +//│ () //│ res //│ = undefined //│ // Output @@ -111,7 +111,7 @@ fun x = 1 //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.110: (log(1);) //│ ╙── ^ -//│ undefined +//│ () //│ res //│ = undefined //│ // Output @@ -125,14 +125,14 @@ fun x = 1 //│ 1 (log(1); ()) -//│ undefined +//│ () //│ res //│ = undefined //│ // Output //│ 1 (((log((()))))) -//│ undefined +//│ () //│ res //│ = undefined //│ // Output diff --git a/shared/src/test/diff/parser/NamedArrays.mls b/shared/src/test/diff/parser/NamedArrays.mls index 18b2dc8a1f..5b510ad0f6 100644 --- a/shared/src/test/diff/parser/NamedArrays.mls +++ b/shared/src/test/diff/parser/NamedArrays.mls @@ -39,7 +39,7 @@ //│ ╔══[PARSE ERROR] Unexpected end of square bracket section; an expression was expected here //│ ║ l.34: [x:, y:] //│ ╙── ^ -//│ Parsed: {'(' [x: y : undefined,] ')'} +//│ Parsed: {'(' [x: y : (),] ')'} [x: 1, 2, 3] //│ |[|x|#:| |1|,| |2|,| |3|]| diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index 435b24f031..245463cbcd 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -245,7 +245,7 @@ fun expect(scanner, ch) = eq(ch)(ch') then ParseSuccess((), scanner.advance) else ParseFailure(concat4("expect '", ch, "' but found ", ch'), scanner) None then ParseFailure(concat3("expect '", ch, "' but found EOF"), scanner) -//│ fun expect: (Scanner & {advance: Scanner}, Str) -> (ParseFailure | ParseSuccess[undefined]) +//│ fun expect: (Scanner & {advance: Scanner}, Str) -> (ParseFailure | ParseSuccess[()]) fun expectWord(scanner, word, result) = if diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index 1d59fc9412..bc15416c22 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -70,7 +70,7 @@ fun zipWith_wrong(f, xs, ys) = //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.47: else None //│ ╙── ^^^^^^^^^^^ -//│ fun zipWith_wrong: (anything, anything, anything) -> undefined +//│ fun zipWith_wrong: (anything, anything, anything) -> () // FIXME parsing diff --git a/ts2mls/js/src/test/diff/BasicFunctions.d.mls b/ts2mls/js/src/test/diff/BasicFunctions.d.mls index b4ef115545..00356e3ad8 100644 --- a/ts2mls/js/src/test/diff/BasicFunctions.d.mls +++ b/ts2mls/js/src/test/diff/BasicFunctions.d.mls @@ -25,5 +25,5 @@ trait Barrrrrrrrr() { fun inn2(b: Barrrrrrrrr): unit fun out2(): Barrrrrrrrr //│ |#fun| |hello|(||)|#:| |unit|↵|#fun| |add|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |sub|(|x|#:| |number|,| |y|#:| |number|)|#:| |number|↵|#fun| |foo|(||)|#:| |number|↵|#fun| |id|(|x|#:| |anything|)|#:| |anything|↵|#fun| |odd|(|x|#:| |number|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |isnull|(|x|#:| |anything|)|#:| |(|false|)| ||| |(|true|)|↵|#fun| |bar|(||)|#:| |anything|↵|#fun| |nu|(|n|#:| |#null|)|#:| |#null|↵|#fun| |un|(|n|#:| |#undefined|)|#:| |#undefined|↵|#fun| |fail|(||)|#:| |nothing|↵|#fun| |create|(||)|#:| |object|↵|#fun| |pa|(|x|#:| |number|)|#:| |number|↵|#fun| |wtf|(|x|#:| |anything|)|#:| |unit|↵|#class| |Foooooo|(||)| |{|→|#let| |ooooooo|#:| |number|←|↵|}|↵|#fun| |inn|(|f|#:| |Foooooo|)|#:| |unit|↵|#fun| |out1|(||)|#:| |Foooooo|↵|#trait| |Barrrrrrrrr|(||)| |{|→|#let| |rrrrrrr|#:| |number|←|↵|}|↵|#fun| |inn2|(|b|#:| |Barrrrrrrrr|)|#:| |unit|↵|#fun| |out2|(||)|#:| |Barrrrrrrrr| -//│ Parsed: {fun hello: () -> unit; fun add: (x: number, y: number) -> number; fun sub: (x: number, y: number) -> number; fun foo: () -> number; fun id: (x: anything) -> anything; fun odd: (x: number) -> bool; fun isnull: (x: anything) -> bool; fun bar: () -> anything; fun nu: (n: null) -> null; fun un: (n: undefined) -> undefined; fun fail: () -> nothing; fun create: () -> object; fun pa: (x: number) -> number; fun wtf: (x: anything) -> unit; class Foooooo() {let ooooooo: number}; fun inn: (f: Foooooo) -> unit; fun out1: () -> Foooooo; trait Barrrrrrrrr() {let rrrrrrr: number}; fun inn2: (b: Barrrrrrrrr) -> unit; fun out2: () -> Barrrrrrrrr} +//│ Parsed: {fun hello: () -> unit; fun add: (x: number, y: number) -> number; fun sub: (x: number, y: number) -> number; fun foo: () -> number; fun id: (x: anything) -> anything; fun odd: (x: number) -> bool; fun isnull: (x: anything) -> bool; fun bar: () -> anything; fun nu: (n: null) -> null; fun un: (n: ()) -> (); fun fail: () -> nothing; fun create: () -> object; fun pa: (x: number) -> number; fun wtf: (x: anything) -> unit; class Foooooo() {let ooooooo: number}; fun inn: (f: Foooooo) -> unit; fun out1: () -> Foooooo; trait Barrrrrrrrr() {let rrrrrrr: number}; fun inn2: (b: Barrrrrrrrr) -> unit; fun out2: () -> Barrrrrrrrr} //│ diff --git a/ts2mls/js/src/test/diff/Dec.d.mls b/ts2mls/js/src/test/diff/Dec.d.mls index 7777ead0bf..6ad560cd71 100644 --- a/ts2mls/js/src/test/diff/Dec.d.mls +++ b/ts2mls/js/src/test/diff/Dec.d.mls @@ -11,5 +11,5 @@ class Person(name: string, age: number) { module OOO { } //│ |#fun| |getName|(|id|#:| |(|string|)| ||| |(|number|)|)|#:| |string|↵|#fun| |render|(|callback|#:| |(|unit| |#=>| |unit|)| ||| |(|#undefined|)|)|#:| |string|↵|#trait| |Get|(||)| |{|→|#fun| |__call|(|id|#:| |string|)|#:| |string|←|↵|}|↵|#class| |Person|(|name|#:| |string|,| |age|#:| |number|)| |{|→|#fun| |getName|(|id|#:| |number|)|#:| |string|←|↵|}|↵|#module| |OOO| |{|↵|}| -//│ Parsed: {fun getName: (id: string | number) -> string; fun render: (callback: unit -> unit | undefined) -> string; trait Get() {fun __call: (id: string) -> string}; class Person(name: string, age: number,) {fun getName: (id: number) -> string}; module OOO {}} +//│ Parsed: {fun getName: (id: string | number) -> string; fun render: (callback: unit -> unit | ()) -> string; trait Get() {fun __call: (id: string) -> string}; class Person(name: string, age: number,) {fun getName: (id: number) -> string}; module OOO {}} //│ diff --git a/ts2mls/js/src/test/diff/Optional.d.mls b/ts2mls/js/src/test/diff/Optional.d.mls index 36787b151e..10ed5607fa 100644 --- a/ts2mls/js/src/test/diff/Optional.d.mls +++ b/ts2mls/js/src/test/diff/Optional.d.mls @@ -21,5 +21,5 @@ class B() { } fun boom(b: (B) | (undefined)): anything //│ |#fun| |buildName|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName2|(|firstName|#:| |string|,| |lastName|#:| |(|string|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |buildName3|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|string|›|)|#:| |string|↵|#fun| |buildName4|(|firstName|#:| |string|,| |lastName|#:| |MutArray|‹|anything|›|)|#:| |string|↵|#trait| |SquareConfig|(||)| |{|→|#let| |color|#:| |(|string|)| ||| |(|#undefined|)|↵|#let| |width|#:| |(|number|)| ||| |(|#undefined|)|←|↵|}|↵|#fun| |did|(|x|#:| |number|,| |f|#:| |(|(|number|)| |#=>| |number|)| ||| |(|#undefined|)|)|#:| |number|↵|#fun| |getOrElse|(|arr|#:| |(|MutArray|‹|object|›|)| ||| |(|#undefined|)|)|#:| |object|↵|#class| |ABC|(||)| |{||}|↵|#fun| |testABC|(|abc|#:| |(|ABC|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |testSquareConfig|(|conf|#:| |(|SquareConfig|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |err|(|msg|#:| |(|[|number|,| |string|]|)| ||| |(|#undefined|)|)|#:| |unit|↵|#fun| |toStr|(|x|#:| |(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| ||| |(|#undefined|)|)|#:| |string|↵|#fun| |boo|‹|T|,| |U|›|(|x|#:| |(|(|T|)| |&| |(|U|)|)| ||| |(|#undefined|)|)|#:| |unit|↵|#class| |B|‹|T|›|(||)| |{|→|#let| |b|#:| |T|←|↵|}|↵|#fun| |boom|(|b|#:| |(|B|‹|nothing|›|)| ||| |(|#undefined|)|)|#:| |anything| -//│ Parsed: {fun buildName: (firstName: string, lastName: string | undefined) -> string; fun buildName2: (firstName: string, lastName: string | undefined) -> string; fun buildName3: (firstName: string, lastName: MutArray[string]) -> string; fun buildName4: (firstName: string, lastName: MutArray[anything]) -> string; trait SquareConfig() {let color: string | undefined; let width: number | undefined}; fun did: (x: number, f: number -> number | undefined) -> number; fun getOrElse: (arr: MutArray[object] | undefined) -> object; class ABC() {}; fun testABC: (abc: ABC | undefined) -> unit; fun testSquareConfig: (conf: SquareConfig | undefined) -> unit; fun err: (msg: [number, string] | undefined) -> unit; fun toStr: (x: number | false | true | undefined) -> string; fun boo: (x: T & U | undefined) -> unit; class B‹T›() {let b: T}; fun boom: (b: B[nothing] | undefined) -> anything} +//│ Parsed: {fun buildName: (firstName: string, lastName: string | ()) -> string; fun buildName2: (firstName: string, lastName: string | ()) -> string; fun buildName3: (firstName: string, lastName: MutArray[string]) -> string; fun buildName4: (firstName: string, lastName: MutArray[anything]) -> string; trait SquareConfig() {let color: string | (); let width: number | ()}; fun did: (x: number, f: number -> number | ()) -> number; fun getOrElse: (arr: MutArray[object] | ()) -> object; class ABC() {}; fun testABC: (abc: ABC | ()) -> unit; fun testSquareConfig: (conf: SquareConfig | ()) -> unit; fun err: (msg: [number, string] | ()) -> unit; fun toStr: (x: number | false | true | ()) -> string; fun boo: (x: T & U | ()) -> unit; class B‹T›() {let b: T}; fun boom: (b: B[nothing] | ()) -> anything} //│ diff --git a/ts2mls/js/src/test/diff/Overload.d.mls b/ts2mls/js/src/test/diff/Overload.d.mls index 75a0d3fe9c..b8977f71e5 100644 --- a/ts2mls/js/src/test/diff/Overload.d.mls +++ b/ts2mls/js/src/test/diff/Overload.d.mls @@ -23,5 +23,5 @@ class WWW() { } fun baz(): anything /* warning: the overload of function baz is not supported yet. */ //│ |#fun| |f|#:| |(|(|number|)| |#=>| |string|)| |&| |(|(|string|)| |#=>| |string|)|↵|#class| |M|(||)| |{|→|#let| |foo|#:| |(|(|number|)| |#=>| |string|)| |&| |(|(|string|)| |#=>| |string|)|←|↵|}|↵|#fun| |app|#:| |(|(|(|string|)| |#=>| |unit|)| |#=>| |(|number|)| |#=>| |unit|)| |&| |(|(|(|string|)| |#=>| |unit|)| |#=>| |(|string|)| |#=>| |unit|)|↵|#fun| |create|#:| |(|(|number|)| |#=>| |unit| |#=>| |(|false|)| ||| |(|true|)|)| |&| |(|(|(|false|)| ||| |(|true|)|)| |#=>| |unit| |#=>| |(|false|)| ||| |(|true|)|)|↵|#fun| |g0|#:| |(|(|MutArray|‹|string|›|)| |#=>| |string|)| |&| |(|(|MutArray|‹|object|›|)| |#=>| |string|)|↵|#fun| |db|#:| |(|(|number|)| |#=>| |MutArray|‹|number|›|)| |&| |(|(|object|)| |#=>| |MutArray|‹|number|›|)|↵|#class| |N|(||)| |{||}|↵|#fun| |id|#:| |(|(|M|)| |#=>| |unit|)| |&| |(|(|N|)| |#=>| |unit|)|↵|#fun| |tst|#:| |(|(|{|z|#:| |number|,|}|)| |#=>| |{|y|#:| |string|,|}|)| |&| |(|(|{|z|#:| |(|false|)| ||| |(|true|)|,|}|)| |#=>| |{|y|#:| |string|,|}|)|↵|#fun| |op|#:| |(|(|number|)| |#=>| |(|(|number|)| ||| |(|#undefined|)|)| |#=>| |unit|)| |&| |(|(|number|)| |#=>| |(|(|(|false|)| ||| |(|true|)|)| ||| |(|#undefined|)|)| |#=>| |unit|)|↵|#fun| |swap|#:| |(|(|[|number|,| |string|]|)| |#=>| |[|number|,| |string|]|)| |&| |(|(|[|string|,| |number|]|)| |#=>| |[|number|,| |string|]|)|↵|#fun| |u|#:| |(|(|(|(|number|)| ||| |(|false|)|)| ||| |(|true|)|)| |#=>| |string|)| |&| |(|(|object|)| |#=>| |string|)|↵|#fun| |doSome|‹|T|,| |U|›|(|x|#:| |anything|)|#:| |unit| |/* warning: the overload of function doSome is not supported yet. */|↵|#module| |XX| |{|→|#fun| |f|‹|T|›|(|x|#:| |T|,| |n|#:| |anything|)|#:| |string| |/* warning: the overload of function f is not supported yet. */|←|↵|}|↵|#class| |WWW|(||)| |{|→|#fun| |F|‹|T|›|(|x|#:| |T|)|#:| |anything| |/* warning: the overload of function F is not supported yet. */|←|↵|}|↵|#fun| |baz|(||)|#:| |anything| |/* warning: the overload of function baz is not supported yet. */| -//│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | undefined) -> unit & number -> (false | true | undefined) -> unit; fun swap: ([number, string]) -> [number, string] & ([string, number]) -> [number, string]; fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything) -> unit; module XX {fun f: (x: T, n: anything) -> string}; class WWW() {fun F: (x: T) -> anything}; fun baz: () -> anything} +//│ Parsed: {fun f: number -> string & string -> string; class M() {let foo: number -> string & string -> string}; fun app: (string -> unit) -> number -> unit & (string -> unit) -> string -> unit; fun create: number -> unit -> bool & bool -> unit -> bool; fun g0: MutArray[string] -> string & MutArray[object] -> string; fun db: number -> MutArray[number] & object -> MutArray[number]; class N() {}; fun id: M -> unit & N -> unit; fun tst: {z: number} -> {y: string} & {z: bool} -> {y: string}; fun op: number -> (number | ()) -> unit & number -> (false | true | ()) -> unit; fun swap: ([number, string]) -> [number, string] & ([string, number]) -> [number, string]; fun u: (number | false | true) -> string & object -> string; fun doSome: (x: anything) -> unit; module XX {fun f: (x: T, n: anything) -> string}; class WWW() {fun F: (x: T) -> anything}; fun baz: () -> anything} //│ From 5a2fd3dda463b60e7bd131df63a54352f2f3f2b4 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 2 Oct 2023 23:12:56 +0800 Subject: [PATCH 468/498] Fix small inconsistencies in parsing of tupled parameters --- compiler/shared/test/diff/LiftType.mls | 18 ++-- .../src/main/scala/mlscript/NewParser.scala | 15 +-- shared/src/test/diff/nu/FlatMonads.mls | 52 ++++++---- shared/src/test/diff/nu/Misc.mls | 97 +++++++++---------- shared/src/test/diff/nu/RightAssocOps.mls | 2 +- shared/src/test/diff/nu/WeirdUnions.mls | 9 +- shared/src/test/diff/parser/Arrays.mls | 24 ++--- shared/src/test/diff/parser/Brackets.mls | 6 +- shared/src/test/diff/parser/Forall.mls | 4 +- shared/src/test/diff/parser/NamedArrays.mls | 20 ++-- shared/src/test/diff/parser/Subscripts.mls | 12 +-- shared/src/test/diff/ucs/NestedBranches.mls | 4 +- 12 files changed, 136 insertions(+), 127 deletions(-) diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index b8bfab5a85..454a20d26a 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -24,15 +24,15 @@ class CTX(x, y){ fun foo(any: [A, B]): [B, A] = [any._2, any._1] } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |[|A|,| |B|]|)|#:| |[|B|,| |A|]| |#=| |[|any|._2|,| |any|._1|]|←|↵|}| -//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '(' [A, B,] ')',) => '(' [(any)._2, (any)._1,] ')' : [B, A]}} +//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: [A, B,],) => [(any)._2, (any)._1,] : [B, A]}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: Var(B))), Asc(Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} //│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { -//│ fun foo = (any: '(' [CTX$1_A$2, CTX$1_B$3,] ')',) => '(' [(any)._2, (any)._1,] ')' : [CTX$1_B$3, CTX$1_A$2] +//│ fun foo = (any: [CTX$1_A$2, CTX$1_B$3,],) => [(any)._2, (any)._1,] : [CTX$1_B$3, CTX$1_A$2] //│ } //│ } //│ @@ -43,15 +43,15 @@ class CTX(x, y){ fun foo(any: {p1: A, p2: B}): [B, A] = [any.p2, any.p1] } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |{|p1|#:| |A|,| |p2|#:| |B|}|)|#:| |[|B|,| |A|]| |#=| |[|any|.p2|,| |any|.p1|]|←|↵|}| -//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '{' {p1: A, p2: B} '}',) => '(' [(any).p2, (any).p1,] ')' : [B, A]}} +//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '{' {p1: A, p2: B} '}',) => [(any).p2, (any).p1,] : [B, A]}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Bra(rcd = false, Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1))), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} //│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { -//│ fun foo = (any: '{' {p1: CTX$1_A$2, p2: CTX$1_B$3} '}',) => '(' [(any).p2, (any).p1,] ')' : [CTX$1_B$3, CTX$1_A$2] +//│ fun foo = (any: '{' {p1: CTX$1_A$2, p2: CTX$1_B$3} '}',) => [(any).p2, (any).p1,] : [CTX$1_B$3, CTX$1_A$2] //│ } //│ } //│ @@ -62,15 +62,15 @@ class CTX(x, y){ fun foo(any: [A, B]): [[B, A], A] = [any, any._1] } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|‹|T|›| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |[|A|,| |B|‹|A|›|]|)|#:| |[|[|B|‹|A|›|,| |A|]|,| |A|]| |#=| |[|any|,| |any|._1|]|←|↵|}| -//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B‹T› {fun foo = y}; fun foo = (any: '(' [A, B‹A›,] ')',) => '(' [any, (any)._1,] ')' : [[B[A], A], A]}} +//│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B‹T› {fun foo = y}; fun foo = (any: [A, B‹A›,],) => [any, (any)._1,] : [[B[A], A], A]}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = false, Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A)))))), Asc(Bra(rcd = false, Tup(_: Var(any), _: Sel(Var(any), _1))), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A))))), Asc(Tup(_: Var(any), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} //│ class CTX$1_B$3[T]([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { -//│ fun foo = (any: '(' [CTX$1_A$2, CTX$1_B$3‹CTX$1_A$2›,] ')',) => '(' [any, (any)._1,] ')' : [[CTX$1_B$3[CTX$1_A$2], CTX$1_A$2], CTX$1_A$2] +//│ fun foo = (any: [CTX$1_A$2, CTX$1_B$3‹CTX$1_A$2›,],) => [any, (any)._1,] : [[CTX$1_B$3[CTX$1_A$2], CTX$1_A$2], CTX$1_A$2] //│ } //│ } //│ diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 8b90b53a4d..8445d82f9d 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -248,11 +248,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo TypingUnit(Nil) } - final def toParams(t: Term): Tup = t match { - case t: Tup => t - case Bra(false, t: Tup) => t - case _ => Tup((N, Fld(FldFlags.empty, t)) :: Nil) - } final def toParamsTy(t: Type): Tuple = t match { case t: Tuple => t case _ => Tuple((N, Field(None, t)) :: Nil) @@ -653,8 +648,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo } } case _ => - // TODO actually reject round tuples? (except for function arg lists) - Bra(false, Tup(res)) + Tup(res) } exprCont(bra.withLoc(S(loc)), prec, allowNewlines = false) case (KEYWORD("forall"), l0) :: _ => @@ -808,12 +802,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (KEYWORD(opStr @ "=>"), l0) :: (NEWLINE, l1) :: _ if opPrec(opStr)._1 > prec => consume val rhs = Blk(typingUnit.entities) - R(Lam(toParams(acc), rhs)) + R(Lam(PlainTup(acc), rhs)) case (KEYWORD(opStr @ "=>"), l0) :: _ if opPrec(opStr)._1 > prec => consume val rhs = expr(1) - // R(Lam(toParams(acc), rhs)) - val res = Lam(toParams(acc), rhs) + val res = Lam(PlainTup(acc), rhs) exprCont(res, prec, allowNewlines) case (IDENT(".", _), l0) :: (br @ BRACKETS(Square, toks), l1) :: _ => consume @@ -845,7 +838,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo Blk(acc :: rhs :: Nil) case _ => if (newDefs) App(v, PlainTup(acc, rhs)) - else App(App(v, toParams(acc)), toParams(rhs)) + else App(App(v, PlainTup(acc)), PlainTup(rhs)) }, prec, allowNewlines) } case (KEYWORD(":"), l0) :: _ if prec <= outer.prec(':') => diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index a1ebe26e77..452bd802ad 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -94,12 +94,25 @@ main.run //│ The sum is: 84 -// * TODO improve this error (parameter list repr.) +// * TODO improve this error – missing provenance for '0-element tuple' :e printLine("").bind of [] => error //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.99: printLine("").bind of [] => error //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `()` is not a 0-element tuple +//│ ║ l.35: class printLine(str: Str) extends IO[undefined] { fun run = log(str) } +//│ ╙── ^^^^^^^^^ +//│ Bind[out (), 'B] | error +//│ res +//│ = Bind {} + +// * TODO improve this error (parameter list repr.) +:e +printLine("").bind of () => error +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.112: printLine("").bind of () => error +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `[?A]` does not match type `[]` //│ ║ l.15: class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { //│ ╙── ^ @@ -107,6 +120,11 @@ printLine("").bind of [] => error //│ res //│ = Bind {} +printLine("").bind of (()) => error +//│ Bind[(), 'B] +//│ res +//│ = Bind {} + // * Using a shortand operator for `bind`... What's the use of a `do` notation?! :^) @@ -176,9 +194,9 @@ val main = fun (>>) compose(f, g) = x => g(f(x)) fun (#>>) bind(x, f) = x.bind(f) fun (#>) map(x, f) = x.bind(f >> Pure) -//│ fun (>>) compose: forall 'a 'b 'c. ('c -> 'a, 'a -> 'b) -> 'c -> 'b +//│ fun (>>) compose: forall 'a 'b 'c. ('a -> 'b, 'b -> 'c) -> 'a -> 'c //│ fun (#>>) bind: forall 'd 'e. ({bind: 'd -> 'e}, 'd) -> 'e -//│ fun (#>) map: forall 'f 'A 'g. ({bind: ('f -> Pure['A]) -> 'g}, 'f -> 'A) -> 'g +//│ fun (#>) map: forall 'f 'g 'A. ({bind: ('g -> Pure['A]) -> 'f}, 'g -> 'A) -> 'f val main = printLine("Hi! Input two numbers: ") #>> _ => @@ -227,9 +245,9 @@ fun main(ctx) = ctx.printLine(concat("The sum is: ")(String of sum)) #>> _ => ctx.pure(sum) //│ fun main: forall 'a 'b 'c 'd 'e. { -//│ printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'a) -> 'e} & Str -> {bind: (anything -> 'd) -> 'c}, -//│ pure: Int -> 'd, -//│ readInt: {bind: (Int -> 'b) -> 'a & (Int -> 'c) -> 'b} +//│ printLine: "Hi! Input two numbers: " -> {bind: (anything -> 'd) -> 'e} & Str -> {bind: (anything -> 'a) -> 'b}, +//│ pure: Int -> 'a, +//│ readInt: {bind: (Int -> 'c) -> 'd & (Int -> 'b) -> 'c} //│ } -> 'e val defaultCtx = {printLine, readInt, pure: Pure} @@ -286,13 +304,13 @@ let r = loop(defaultCtx).run :e not(r) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.287: not(r) +//│ ║ l.305: not(r) //│ ║ ^^^^^^ //│ ╟── type `Int` is not an instance of type `Bool` //│ ║ l.34: module readInt extends IO[Int] { fun run: Int = 42 } //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `Bool` -//│ ║ l.287: not(r) +//│ ║ l.305: not(r) //│ ╙── ^ //│ error | false | true //│ res @@ -339,13 +357,13 @@ main :e let r = printLine("").bind of 0 => Pure(1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.340: let r = printLine("").bind of 0 => Pure(1) +//│ ║ l.358: let r = printLine("").bind of 0 => Pure(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `()` does not match type `0` -//│ ║ l.305: class printLine(str: Str) extends IO { fun run = log(str) } +//│ ║ l.323: class printLine(str: Str) extends IO { fun run = log(str) } //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from integer literal: -//│ ║ l.340: let r = printLine("").bind of 0 => Pure(1) +//│ ║ l.358: let r = printLine("").bind of 0 => Pure(1) //│ ╙── ^ //│ let r: Bind[in 0 & 'A out () | 'A, 'B] | error //│ where @@ -358,20 +376,20 @@ let r = printLine("").bind of x => log(x.a) Pure(1) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.357: let r = printLine("").bind of x => +//│ ║ l.375: let r = printLine("").bind of x => //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.358: log(x.a) +//│ ║ l.376: log(x.a) //│ ║ ^^^^^^^^^ -//│ ║ l.359: Pure(1) +//│ ║ l.377: Pure(1) //│ ║ ^^^^^^^ //│ ╟── application of type `()` does not have field 'a' -//│ ║ l.305: class printLine(str: Str) extends IO { fun run = log(str) } +//│ ║ l.323: class printLine(str: Str) extends IO { fun run = log(str) } //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.358: log(x.a) +//│ ║ l.376: log(x.a) //│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.358: log(x.a) +//│ ║ l.376: log(x.a) //│ ╙── ^ //│ let r: Bind[in {a: anything} & 'A out () | 'A, 'B] | error //│ where diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index 835cdbd471..821a12d2c7 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -94,55 +94,43 @@ let f = ((x, y)) => x + y //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section //│ ║ l.93: let f = ((x, y)) => x + y //│ ╙── ^^^^^^ -//│ let f: (Int, Int) -> Int +//│ let f: ([Int, Int]) -> Int //│ f //│ = [Function: f5] +:e f(1, 2) -//│ Int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.102: f(1, 2) +//│ ║ ^^^^^^^ +//│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` +//│ ║ l.102: f(1, 2) +//│ ╙── ^^^^^^ +//│ Int | error //│ res -//│ = 3 +//│ Runtime error: +//│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) :pe -:e f((1, 2)) //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.108: f((1, 2)) +//│ ║ l.115: f((1, 2)) //│ ╙── ^^^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.108: f((1, 2)) -//│ ║ ^^^^^^^^^ -//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` -//│ ║ l.108: f((1, 2)) -//│ ║ ^^^^^^^^ -//│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.93: let f = ((x, y)) => x + y -//│ ╙── ^^^^^^ -//│ Int | error +//│ Int //│ res -//│ = '1,2undefined' +//│ = 3 -:e f([1, 2]) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.126: f([1, 2]) -//│ ║ ^^^^^^^^^ -//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` -//│ ║ l.126: f([1, 2]) -//│ ║ ^^^^^^^^ -//│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.93: let f = ((x, y)) => x + y -//│ ╙── ^^^^^^ -//│ Int | error +//│ Int //│ res -//│ = '1,2undefined' +//│ = 3 :e f[1, 2] //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.141: f[1, 2] +//│ ║ l.129: f[1, 2] //│ ╙── ^^^^^^^ -//│ (Int, Int) -> Int +//│ ([Int, Int]) -> Int //│ res //│ = [Function: f5] @@ -150,7 +138,7 @@ f[1, 2] :pe let f = (((x, y))) => x + y //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.151: let f = (((x, y))) => x + y +//│ ║ l.139: let f = (((x, y))) => x + y //│ ╙── ^^^^^^ //│ let f: ([Int, Int]) -> Int //│ f @@ -159,30 +147,27 @@ let f = (((x, y))) => x + y // * TODO maybe parse as type lambda? let f = [x, y] => x + y -//│ let f: (Int, Int) -> Int +//│ let f: ([Int, Int]) -> Int //│ f //│ = [Function: f7] -// :e // TODO +:e f(1, 2) -//│ Int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.155: f(1, 2) +//│ ║ ^^^^^^^ +//│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` +//│ ║ l.155: f(1, 2) +//│ ╙── ^^^^^^ +//│ Int | error //│ res -//│ = 3 +//│ Runtime error: +//│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) -:e f([1, 2]) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.173: f([1, 2]) -//│ ║ ^^^^^^^^^ -//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` -//│ ║ l.173: f([1, 2]) -//│ ║ ^^^^^^^^ -//│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.161: let f = [x, y] => x + y -//│ ╙── ^^^^ -//│ Int | error +//│ Int //│ res -//│ = '1,2undefined' +//│ = 3 let f = ([x, y]) => x + y @@ -198,10 +183,10 @@ f([1, 2]) :e f(1, 2) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.199: f(1, 2) +//│ ║ l.184: f(1, 2) //│ ║ ^^^^^^^ //│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` -//│ ║ l.199: f(1, 2) +//│ ║ l.184: f(1, 2) //│ ╙── ^^^^^^ //│ Int | error //│ res @@ -210,12 +195,20 @@ f(1, 2) let f = [[[x, y]]] => x + y -//│ let f: ([[Int, Int]]) -> Int +//│ let f: ([[[Int, Int]]]) -> Int //│ f //│ = [Function: f9] +:e f([[1, 2]]) -//│ Int +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.203: f([[1, 2]]) +//│ ║ ^^^^^^^^^^^ +//│ ╟── tuple literal of type `[1, 2]` does not match type `[[?a, ?b]]` +//│ ║ l.203: f([[1, 2]]) +//│ ╙── ^^^^^^ +//│ Int | error //│ res -//│ = 3 +//│ Runtime error: +//│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) diff --git a/shared/src/test/diff/nu/RightAssocOps.mls b/shared/src/test/diff/nu/RightAssocOps.mls index 496395b873..15a34aaad7 100644 --- a/shared/src/test/diff/nu/RightAssocOps.mls +++ b/shared/src/test/diff/nu/RightAssocOps.mls @@ -56,7 +56,7 @@ fun (++) conc(xs, ys) = [xs, ys] //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `[?a, ?b]` is not an instance of type `Int` //│ ║ l.9: fun (++) conc(xs, ys) = [xs, ys] -//│ ║ ^^^^^^ +//│ ║ ^^^^^^^^ //│ ╟── but it flows into operator application with expected type `Int` //│ ║ l.50: 1 +: "a" ++ 2 +: "b" //│ ║ ^^^^^^^^ diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 8c22b3af18..31c87b4a47 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -63,7 +63,7 @@ f("abc", "abc") // * Mismatched argument list sizes yields surprising results: -let r = if true then id else [x, y] => [y, x] +let r = if true then id else (x, y) => [y, x] //│ let r: (...nothing) -> [nothing, nothing] //│ r //│ = [Function: id] @@ -78,7 +78,7 @@ r(error, error) //│ ║ l.72: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.66: let r = if true then id else [x, y] => [y, x] +//│ ║ l.66: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.73: r(error, error) @@ -105,5 +105,10 @@ r of [0, 1] //│ res //│ = [ 0, 1 ] +// Also currently parses the same: +let r = if true then id else [x, y] => [y, x] +//│ let r: forall 'a 'b 'c. (['a, 'b] & 'c) -> (['b, 'a] | 'c) +//│ r +//│ = [Function: id] diff --git a/shared/src/test/diff/parser/Arrays.mls b/shared/src/test/diff/parser/Arrays.mls index ff91aed81f..56248ffb8a 100644 --- a/shared/src/test/diff/parser/Arrays.mls +++ b/shared/src/test/diff/parser/Arrays.mls @@ -3,19 +3,19 @@ [] //│ |[||]| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {[]} [1] //│ |[|1|]| -//│ Parsed: {'(' [1,] ')'} +//│ Parsed: {[1,]} [1,] //│ |[|1|,|]| -//│ Parsed: {'(' [1,] ')'} +//│ Parsed: {[1,]} [1, 2, 3] //│ |[|1|,| |2|,| |3|]| -//│ Parsed: {'(' [1, 2, 3,] ')'} +//│ Parsed: {[1, 2, 3,]} () //│ |(||)| @@ -74,12 +74,12 @@ f of let arr = [] //│ |#let| |arr| |#=| |[||]| -//│ Parsed: {let arr = '(' [] ')'} +//│ Parsed: {let arr = []} let arr = [ ] //│ |#let| |arr| |#=| |[|↵|]| -//│ Parsed: {let arr = '(' [] ')'} +//│ Parsed: {let arr = []} let arr = [ @@ -90,26 +90,26 @@ let arr = //│ ║ ^ //│ ║ l.85: [ //│ ╙── -//│ Parsed: {let arr = '(' [] ')'} +//│ Parsed: {let arr = []} let arr = [ 1 ] //│ |#let| |arr| |#=| |[|→|1|←|↵|]| -//│ Parsed: {let arr = '(' [1,] ')'} +//│ Parsed: {let arr = [1,]} let arr = [ 1, 2 ] //│ |#let| |arr| |#=| |[|→|1|,| |2|←|↵|]| -//│ Parsed: {let arr = '(' [1, 2,] ')'} +//│ Parsed: {let arr = [1, 2,]} let arr = [ 1, 2 ] //│ |#let| |arr| |#=| |[|→|1|,|↵|2|←|↵|]| -//│ Parsed: {let arr = '(' [1, 2,] ')'} +//│ Parsed: {let arr = [1, 2,]} // :pe f [1, 2, 3] @@ -118,10 +118,10 @@ f [1, 2, 3] f([1, 2, 3]) //│ |f|(|[|1|,| |2|,| |3|]|)| -//│ Parsed: {f('(' [1, 2, 3,] ')',)} +//│ Parsed: {f([1, 2, 3,],)} f of [1, 2, 3] //│ |f| |#of| |[|1|,| |2|,| |3|]| -//│ Parsed: {f('(' [1, 2, 3,] ')',)} +//│ Parsed: {f([1, 2, 3,],)} diff --git a/shared/src/test/diff/parser/Brackets.mls b/shared/src/test/diff/parser/Brackets.mls index c9d635a214..b12bb26104 100644 --- a/shared/src/test/diff/parser/Brackets.mls +++ b/shared/src/test/diff/parser/Brackets.mls @@ -5,7 +5,7 @@ [] //│ |[||]| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {[]} {} //│ |{||}| @@ -24,7 +24,7 @@ (([{}])) //│ |(|(|[|{||}|]|)|)| -//│ Parsed: {'(' '(' '(' ['{' {} '}',] ')' ')' ')'} +//│ Parsed: {'(' '(' ['{' {} '}',] ')' ')'} :pe (([{})]) @@ -41,7 +41,7 @@ //│ ║ l.30: (([{})]) //│ ╙── ^ //│ |(|(|[|{||}|]|)|)| -//│ Parsed: {'(' '(' '(' ['{' {} '}',] ')' ')' ')'} +//│ Parsed: {'(' '(' ['{' {} '}',] ')' ')'} fun f = () diff --git a/shared/src/test/diff/parser/Forall.mls b/shared/src/test/diff/parser/Forall.mls index d2801d6825..c6296bf9ab 100644 --- a/shared/src/test/diff/parser/Forall.mls +++ b/shared/src/test/diff/parser/Forall.mls @@ -5,7 +5,7 @@ forall 'a: 'a => 'a forall 'a, 'b: ['a, 'b] => ['b, 'a] //│ |#forall| |'a|,| |'b|#:| |[|'a|,| |'b|]| |#=>| |[|'b|,| |'a|]| -//│ Parsed: {forall 'a, 'b. ('a, 'b,) => '(' ['b, 'a,] ')'} +//│ Parsed: {forall 'a, 'b. (['a, 'b,],) => ['b, 'a,]} fun f: forall 'a: 'a => 'a //│ |#fun| |f|#:| |#forall| |'a|#:| |'a| |#=>| |'a| @@ -13,5 +13,5 @@ fun f: forall 'a: 'a => 'a fun f: forall 'a, 'b: ['a, 'b] => ['b, 'a] //│ |#fun| |f|#:| |#forall| |'a|,| |'b|#:| |[|'a|,| |'b|]| |#=>| |[|'b|,| |'a|]| -//│ Parsed: {fun f: forall 'a 'b. ('a, 'b) -> ['b, 'a]} +//│ Parsed: {fun f: forall 'a 'b. (['a, 'b]) -> ['b, 'a]} diff --git a/shared/src/test/diff/parser/NamedArrays.mls b/shared/src/test/diff/parser/NamedArrays.mls index 5b510ad0f6..6151c63dbb 100644 --- a/shared/src/test/diff/parser/NamedArrays.mls +++ b/shared/src/test/diff/parser/NamedArrays.mls @@ -3,33 +3,33 @@ [] //│ |[||]| -//│ Parsed: {'(' [] ')'} +//│ Parsed: {[]} [x: 1] //│ |[|x|#:| |1|]| -//│ Parsed: {'(' [x: 1,] ')'} +//│ Parsed: {[x: 1,]} [x : 1] //│ |[|x| |#:| |1|]| -//│ Parsed: {'(' [x : 1,] ')'} +//│ Parsed: {[x : 1,]} [x: 1,] //│ |[|x|#:| |1|,|]| -//│ Parsed: {'(' [x: 1,] ')'} +//│ Parsed: {[x: 1,]} [x: 1, y:] //│ |[|x|#:| |1|,| |y|#:|]| //│ ╔══[PARSE ERROR] Unexpected end of square bracket section; an expression was expected here //│ ║ l.20: [x: 1, y:] //│ ╙── ^ -//│ Parsed: {'(' [x: 1, y: undefined,] ')'} +//│ Parsed: {[x: 1, y: undefined,]} [x:, y: 1] //│ |[|x|#:|,| |y|#:| |1|]| //│ ╔══[PARSE ERROR] Unexpected comma in expression position //│ ║ l.27: [x:, y: 1] //│ ╙── ^ -//│ Parsed: {'(' [x: y : 1,] ')'} +//│ Parsed: {[x: y : 1,]} [x:, y:] //│ |[|x|#:|,| |y|#:|]| @@ -39,19 +39,19 @@ //│ ╔══[PARSE ERROR] Unexpected end of square bracket section; an expression was expected here //│ ║ l.34: [x:, y:] //│ ╙── ^ -//│ Parsed: {'(' [x: y : (),] ')'} +//│ Parsed: {[x: y : (),]} [x: 1, 2, 3] //│ |[|x|#:| |1|,| |2|,| |3|]| -//│ Parsed: {'(' [x: 1, 2, 3,] ')'} +//│ Parsed: {[x: 1, 2, 3,]} [1, y: 2, 3] //│ |[|1|,| |y|#:| |2|,| |3|]| -//│ Parsed: {'(' [1, y: 2, 3,] ')'} +//│ Parsed: {[1, y: 2, 3,]} [x: 1, y: 2, z: 3] //│ |[|x|#:| |1|,| |y|#:| |2|,| |z|#:| |3|]| -//│ Parsed: {'(' [x: 1, y: 2, z: 3,] ')'} +//│ Parsed: {[x: 1, y: 2, z: 3,]} () //│ |(||)| diff --git a/shared/src/test/diff/parser/Subscripts.mls b/shared/src/test/diff/parser/Subscripts.mls index 21846e563a..a37f7ea274 100644 --- a/shared/src/test/diff/parser/Subscripts.mls +++ b/shared/src/test/diff/parser/Subscripts.mls @@ -53,30 +53,30 @@ a + [22] [333] //│ |a| |+|→|111|→|[|22|]|←|↵|[|333|]|←| -//│ Parsed: {+(a,)({111‹22›; '(' [333,] ')'},)} +//│ Parsed: {+(a,)({111‹22›; [333,]},)} Foo(bar) + 1 [1] [2] //│ |Foo|(|bar|)| |+|→|1|→|[|1|]|←|↵|[|2|]|←| -//│ Parsed: {+(Foo(bar,),)({1‹1›; '(' [2,] ')'},)} +//│ Parsed: {+(Foo(bar,),)({1‹1›; [2,]},)} a of [333] //│ |a| |#of| |[|333|]| -//│ Parsed: {a('(' [333,] ')',)} +//│ Parsed: {a([333,],)} a of [333] //│ |a| |#of|→|[|333|]|←| -//│ Parsed: {a('(' [333,] ')',)} +//│ Parsed: {a([333,],)} a of 111 [22] [333] //│ |a| |#of|→|111|→|[|22|]|←|↵|[|333|]|←| -//│ Parsed: {a({111‹22›; '(' [333,] ')'},)} +//│ Parsed: {a({111‹22›; [333,]},)} a( 111 @@ -84,5 +84,5 @@ a( [333] ) //│ |a|(|→|111|→|[|22|]|←|↵|[|333|]|←|↵|)| -//│ Parsed: {a({111‹22›; '(' [333,] ')'},)} +//│ Parsed: {a({111‹22›; [333,]},)} diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index ec43e25cb7..9a45add38c 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -118,7 +118,7 @@ fun mapPartition(f, xs) = if xs is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `[Nil, Nil]` is not an instance of type `Object` //│ ║ l.102: Nil then [Nil, Nil] -//│ ║ ^^^^^^^^ +//│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from `case` expression: //│ ║ l.103: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,7 +174,7 @@ fun mapPartition(f, xs) = if xs is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `[Nil, Nil]` is not an instance of type `Object` //│ ║ l.150: Nil then [Nil, Nil] -//│ ║ ^^^^^^^^ +//│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from `case` expression: //│ ║ l.151: Cons(x, xs) and mapPartition(f, xs) is [l, r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From e7f6a142882732d72718781caae1a26f397d27a1 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 2 Oct 2023 23:16:35 +0800 Subject: [PATCH 469/498] Warn against statements with type different from unit --- .../src/main/scala/mlscript/NuTypeDefs.scala | 4 +- .../scala/mlscript/codegen/Polyfill.scala | 3 ++ .../main/scala/mlscript/codegen/Scope.scala | 1 + shared/src/test/diff/codegen/Nested.mls | 2 +- shared/src/test/diff/nu/Eval.mls | 28 ++++++++++ shared/src/test/diff/nu/Extrusion.mls | 12 ++--- shared/src/test/diff/nu/FunSigs.mls | 4 +- shared/src/test/diff/nu/Metaprog.mls | 2 +- shared/src/test/diff/nu/Unit.mls | 53 ++++++++++++++++--- .../diff/nu/repro_PolymorphicVariants.mls | 2 +- 10 files changed, 90 insertions(+), 21 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 98be651e0e..9d72467b6d 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -651,8 +651,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case t: Term => implicit val genLambdas: GenLambdas = true val ty = typeTerm(t) - /* // TODO next: - if (!topLevel) { + if (!topLevel && !stmts.isEmpty) { if (t.isInstanceOf[Var] || t.isInstanceOf[Lit]) warn("Pure expression does nothing in statement position.", t.toLoc) else @@ -663,7 +662,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err.allMsgs, newDefs)), prov = TypeProvenance(t.toLoc, t.describe), ctx) } - */ S(ty) case s: DesugaredStatement => err(msg"Illegal position for this ${s.describe} statement.", s.toLoc)(raise) diff --git a/shared/src/main/scala/mlscript/codegen/Polyfill.scala b/shared/src/main/scala/mlscript/codegen/Polyfill.scala index c5d1b52309..9a01564ddc 100644 --- a/shared/src/main/scala/mlscript/codegen/Polyfill.scala +++ b/shared/src/main/scala/mlscript/codegen/Polyfill.scala @@ -176,6 +176,9 @@ object Polyfill { buffer += BuiltinFunc( "log", fn(_, param("x")) { `return` { id("console.info")(id("x")) } } ) + buffer += BuiltinFunc( + "discard", fn(_, param("x"))() + ) buffer.toList } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index fdb288251e..80afdc3111 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -59,6 +59,7 @@ class Scope(val name: Str, enclosing: Opt[Scope]) { "eq", "unit", "log", + "discard", ) foreach { name => register(BuiltinSymbol(name, name)) } diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index afd2ac3ed9..680d182b10 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -1430,7 +1430,7 @@ module Test { log(0) module Foo { log(2) } log(1) - Foo + discard of Foo log(3) Foo } diff --git a/shared/src/test/diff/nu/Eval.mls b/shared/src/test/diff/nu/Eval.mls index b1d8f4f9ed..550bf3ee54 100644 --- a/shared/src/test/diff/nu/Eval.mls +++ b/shared/src/test/diff/nu/Eval.mls @@ -21,14 +21,28 @@ fun (<|) pepi(f, x) = f(x) declare class throw(arg: anything): nothing //│ declare class throw(arg: anything): nothing +:w // * Due to current limitations of self types :re throw(1); 0 +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in application: +//│ ║ l.26: throw(1); 0 +//│ ║ ^^^^^^^^ +//│ ╙── application of type `throw` does not match type `()` //│ 0 //│ res //│ Runtime error: //│ 1 +:w fun test = throw(1); 0 +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in application: +//│ ║ l.39: fun test = throw(1); 0 +//│ ║ ^^^^^^^^ +//│ ╙── application of type `throw` does not match type `()` //│ fun test: 0 :re @@ -38,9 +52,16 @@ test //│ Runtime error: //│ 1 +:w fun test = throw(1) error +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in application: +//│ ║ l.57: throw(1) +//│ ║ ^^^^^^^^ +//│ ╙── application of type `throw` does not match type `()` //│ fun test: nothing :re @@ -162,9 +183,16 @@ type Value = Lam | Lit | Rcd[Value] //│ type Value = Lam | Lit[anything] | Rcd[Value] +:w fun err(msg) = throw(concat("Evaluation error: " ++ msg)) error +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in application: +//│ ║ l.188: throw(concat("Evaluation error: " ++ msg)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── application of type `throw` does not match type `()` //│ fun err: Str -> nothing fun eval(t, env) = if t is diff --git a/shared/src/test/diff/nu/Extrusion.mls b/shared/src/test/diff/nu/Extrusion.mls index bc5fc9af3f..1642e4d890 100644 --- a/shared/src/test/diff/nu/Extrusion.mls +++ b/shared/src/test/diff/nu/Extrusion.mls @@ -3,7 +3,7 @@ fun f(y) = let local = forall 'A: (x: 'A) => - y(x) + 1 + discard of y(x) + 1 x y //│ fun f: forall 'a. (??A -> Int & 'a) -> 'a @@ -17,12 +17,12 @@ f(id) //│ ║ l.5: let local = forall 'A: (x: 'A) => //│ ║ ^^ //│ ╟── into application of type `Int` -//│ ║ l.6: y(x) + 1 -//│ ║ ^^^^ +//│ ║ l.6: discard of y(x) + 1 +//│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.6: y(x) + 1 -//│ ╙── ^ +//│ ║ l.6: discard of y(x) + 1 +//│ ╙── ^ //│ forall 'a. error | 'a -> 'a //│ res //│ = [Function: id] @@ -30,7 +30,7 @@ f(id) fun f(y) = let local = forall 'A: (x: 'A) => - (y : forall 'a: 'a -> 'a)(x) + discard of (y : forall 'a: 'a -> 'a)(x) x y //│ fun f: forall 'b. (forall 'a. 'a -> 'a & 'b) -> 'b diff --git a/shared/src/test/diff/nu/FunSigs.mls b/shared/src/test/diff/nu/FunSigs.mls index 9e8614a496..ebe09b852a 100644 --- a/shared/src/test/diff/nu/FunSigs.mls +++ b/shared/src/test/diff/nu/FunSigs.mls @@ -2,8 +2,8 @@ -fun log(msg: Str): unit -//│ fun log: (msg: Str) -> unit +fun log(msg: Str): () +//│ fun log: (msg: Str) -> () let f = log("ok") diff --git a/shared/src/test/diff/nu/Metaprog.mls b/shared/src/test/diff/nu/Metaprog.mls index 49429e55ea..f099d59e89 100644 --- a/shared/src/test/diff/nu/Metaprog.mls +++ b/shared/src/test/diff/nu/Metaprog.mls @@ -21,7 +21,7 @@ fun test(f) = bind of IntLit(42), n => f(n) Add(n, IntLit(1)) -//│ fun test: (Code[Int, ??cc] -> anything) -> Code[Int, nothing] +//│ fun test: (Code[Int, ??cc] -> ()) -> Code[Int, nothing] abstract class Test[C] { diff --git a/shared/src/test/diff/nu/Unit.mls b/shared/src/test/diff/nu/Unit.mls index 568e79c51c..1070be52b2 100644 --- a/shared/src/test/diff/nu/Unit.mls +++ b/shared/src/test/diff/nu/Unit.mls @@ -140,11 +140,10 @@ fun x = 1 - :pe (1, 2) //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.145: (1, 2) +//│ ║ l.144: (1, 2) //│ ╙── ^^^^^^ //│ [1, 2] //│ res @@ -176,7 +175,7 @@ x => x :pe 1 => (2, 3) //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.177: 1 => (2, 3) +//│ ║ l.176: 1 => (2, 3) //│ ╙── ^^^^^^ //│ 1 -> [2, 3] //│ res @@ -200,16 +199,16 @@ f of 1, 2 :e f of (1, 2) //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.201: f of (1, 2) +//│ ║ l.200: f of (1, 2) //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.201: f of (1, 2) +//│ ║ l.200: f of (1, 2) //│ ║ ^^^^^^^^^^^ //│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` -//│ ║ l.201: f of (1, 2) +//│ ║ l.200: f of (1, 2) //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.186: fun f(x, y) = x + y +//│ ║ l.185: fun f(x, y) = x + y //│ ╙── ^^^^^^ //│ Int | error //│ res @@ -217,6 +216,46 @@ f of (1, 2) +:w +0; 0 +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.220: 0; 0 +//│ ╙── ^ +//│ 0 +//│ res +//│ = 0 + +:w +succ(0); 0 +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in application: +//│ ║ l.229: succ(0); 0 +//│ ║ ^^^^^^^ +//│ ╙── application of type `Int` does not match type `()` +//│ 0 +//│ res +//│ = 0 + +discard(succ(0)); 0 +//│ 0 +//│ res +//│ = 0 + +discard of succ(0);; 0 +//│ 0 +//│ res +//│ = undefined +//│ res +//│ = 0 + +let _ = succ(0);; 0 +//│ let _: Int +//│ 0 +//│ _ +//│ = 1 +//│ res +//│ = 0 diff --git a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls index 93be7df608..461bada4e8 100644 --- a/shared/src/test/diff/nu/repro_PolymorphicVariants.mls +++ b/shared/src/test/diff/nu/repro_PolymorphicVariants.mls @@ -29,7 +29,7 @@ mixin EvalLambda { error } //│ mixin EvalLambda() { -//│ this: {eval: (Cons[[string, nothing] | 'A], nothing) -> anything} +//│ this: {eval: (Cons[[string, nothing] | 'A], nothing) -> ()} //│ fun eval: (Cons['A] | Nil, Abs[anything]) -> nothing //│ } From a00d04bdf04fb251a7056b81f5a46dd5cc6bf6ab Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Mon, 2 Oct 2023 23:45:28 +0800 Subject: [PATCH 470/498] Add minor test case --- shared/src/test/diff/nu/Unit.mls | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/shared/src/test/diff/nu/Unit.mls b/shared/src/test/diff/nu/Unit.mls index 1070be52b2..a2df12657c 100644 --- a/shared/src/test/diff/nu/Unit.mls +++ b/shared/src/test/diff/nu/Unit.mls @@ -259,3 +259,25 @@ let _ = succ(0);; 0 +:e +fun foo = + let tmp = 0 +foo + 1 +//│ ╔══[ERROR] Type mismatch in operator application: +//│ ║ l.265: foo + 1 +//│ ║ ^^^^^^^ +//│ ╟── definition of method foo of type `()` is not an instance of type `Int` +//│ ║ l.263: fun foo = +//│ ║ ^^^^^ +//│ ║ l.264: let tmp = 0 +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `Int` +//│ ║ l.265: foo + 1 +//│ ╙── ^^^ +//│ fun foo: () +//│ Int | error +//│ res +//│ = NaN + + + From 3bb6e2bc4ce272d92afa7abb41b8d242bf69c2bb Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 3 Oct 2023 12:56:18 +0800 Subject: [PATCH 471/498] Fix variance computation; remove redundant instanceType field --- .../src/main/scala/mlscript/NuTypeDefs.scala | 18 +++---- shared/src/test/diff/nu/GenericClasses.mls | 49 ++++++++++++++++--- shared/src/test/diff/nu/SelfRec.mls | 26 +++++----- shared/src/test/diff/nu/TODO_Classes.mls | 2 +- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 9d72467b6d..8aa26ed388 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -222,8 +222,6 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sign: ST, inheritedTags: Set[TypeName], parentTP: Map[Str, NuMember] - )(val instanceType: ST, // * only meant to be used in `variances` - // * TODO remove `instanceType` and implement proper variance analysis instead ) extends TypedNuTypeDef(Cls) with PolyNuDecl { def decl: NuTypeDef = td @@ -277,7 +275,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } }() } - Trav(PolMap.pos)(instanceType) + members.foreach { + case (_, m: NuParam) if m.isType => + case (_, m) => Trav.applyMem(PolMap.pos)(m) + } // TODO check consistency with explicitVariances val res = store ++ tparams.iterator.collect { case (_, tv, S(vi)) => tv -> vi } @@ -304,7 +305,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sign.freshenAbove(lim, rigidify), inheritedTags, parentTP.mapValuesIter(_.freshenAbove(lim, rigidify)).toMap, - )(this.instanceType.freshenAbove(lim, rigidify)) + ) }} def mapPol(pol: Opt[Bool], smart: Bool)(f: (Opt[Bool], SimpleType) => SimpleType) @@ -318,7 +319,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPol(pol, smart)(f)).toMap, - )(/* f(pol, instanceType) */TopType) // TODO remove instanceType + ) def mapPolMap(pol: PolMap)(f: (PolMap, SimpleType) => SimpleType) (implicit ctx: Ctx): TypedNuCls = TypedNuCls(level, td, @@ -330,10 +331,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => f(pol, sign), inheritedTags, parentTP.mapValuesIter(_.mapPolMap(pol)(f)).toMap, - )(/* f(pol, instanceType) */TopType) // TODO remove instanceType + ) override def toString: Str = s"TypedNuCls($level, ${td.nme},\n\t$tparams,\n\t$params,\n\tthis: $thisTy, ${ - members.lnIndent()},\n\t: $sign, $inheritedTags, $parentTP)($instanceType)" + members.lnIndent()},\n\t: $sign, $inheritedTags, $parentTP)" } @@ -1706,8 +1707,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => sig_ty, inheritedTags, tparamMembers - )(thisType) - .tap(_.variances) // * Force variance computation + ).tap(_.variances) // * Force variance computation } case Mxn => diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 9a904dd4be..4d71d0c012 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -250,7 +250,9 @@ class Test(n: A) { //│ } Test(1) -//│ Test[1] +//│ Test['A] +//│ where +//│ 'A :> 1 //│ res //│ = Test {} @@ -265,7 +267,9 @@ Test("ok").foo //│ = 'ok' let t = Test(1) -//│ let t: Test[1] +//│ let t: Test['A] +//│ where +//│ 'A :> 1 //│ t //│ = Test {} @@ -298,13 +302,13 @@ class TestBad() { fun foo2(x: A) = x + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.298: fun foo2(x: A) = x + 1 +//│ ║ l.302: fun foo2(x: A) = x + 1 //│ ║ ^^^^^ //│ ╟── reference of type `A` is not an instance of type `Int` -//│ ║ l.298: fun foo2(x: A) = x + 1 +//│ ║ l.302: fun foo2(x: A) = x + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.296: class TestBad() { +//│ ║ l.300: class TestBad() { //│ ╙── ^ //│ class TestBad[A]() { //│ fun foo1: (x: A) -> A @@ -395,7 +399,7 @@ not(w.x.n) :e not(w.x.a) //│ ╔══[ERROR] Type `C['a]` does not contain member `a` -//│ ║ l.396: not(w.x.a) +//│ ║ l.400: not(w.x.a) //│ ╙── ^^ //│ Bool //│ res @@ -403,3 +407,36 @@ not(w.x.a) +abstract class Cls[A](val x: A) { fun g: A -> Int } +//│ abstract class Cls[A](x: A) { +//│ fun g: A -> Int +//│ } + +module M extends Cls(123) { fun g = id } +//│ module M extends Cls { +//│ fun g: forall 'a. 'a -> 'a +//│ } + +M: Cls['a] +//│ Cls['a] +//│ where +//│ 'a :> 123 +//│ <: Int +//│ res +//│ = M { class: [class M extends Cls] } + + +class Cls[A](val x: A) { fun g: A -> Int;; fun g(x) = 42 } +//│ class Cls[A](x: A) { +//│ fun g: A -> Int +//│ } + +Cls(123) +//│ Cls['A] +//│ where +//│ 'A :> 123 +//│ res +//│ = Cls {} + + + diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 5e4ffce607..9b4fa8bb81 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -89,8 +89,10 @@ class Foo3[A](val x: A) { } //│ class Foo3[A](x: A) { //│ fun foo: (x: A) -> Foo3[A] -//│ fun test: Foo3[1] +//│ fun test: forall 'A. Foo3['A] //│ } +//│ where +//│ 'A :> 1 Foo3 //│ forall 'A. (x: 'A) -> Foo3['A] @@ -101,7 +103,9 @@ Foo3 //│ } Foo3(1) -//│ Foo3[1] +//│ Foo3['A] +//│ where +//│ 'A :> 1 //│ res //│ = Foo3 {} @@ -123,7 +127,7 @@ class Foo4 { fun test = [Foo4.test] } //│ ╔══[ERROR] Class Foo4 cannot be instantiated as it exposes no such constructor -//│ ║ l.123: fun test = [Foo4.test] +//│ ║ l.127: fun test = [Foo4.test] //│ ╙── ^^^^ //│ class Foo4 { //│ constructor() @@ -135,7 +139,7 @@ class Foo5(x: Int) { fun test = [Foo5(5).test] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.135: fun test = [Foo5(5).test] +//│ ║ l.139: fun test = [Foo5(5).test] //│ ╙── ^^^^^ //│ class Foo5(x: Int) { //│ fun test: [error] @@ -148,13 +152,13 @@ class Foo6[A](x: A) { fun test3 = [Foo6([x]).test3] } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.146: fun test1 = [Foo6(x).test1] +//│ ║ l.150: fun test1 = [Foo6(x).test1] //│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.147: fun test2 = [Foo6(123).test2] +//│ ║ l.151: fun test2 = [Foo6(123).test2] //│ ╙── ^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.148: fun test3 = [Foo6([x]).test3] +//│ ║ l.152: fun test3 = [Foo6([x]).test3] //│ ╙── ^^^^^^ //│ class Foo6[A](x: A) { //│ fun test1: [error] @@ -172,7 +176,7 @@ class Foo7[A](head: A, tail: Foo7[A] | N) { _ then tail.test1 } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.172: _ then tail.test1 +//│ ║ l.176: _ then tail.test1 //│ ╙── ^^^^^^ //│ class Foo7[A](head: A, tail: Foo7[A] | N) { //│ fun test1: error | A @@ -213,7 +217,7 @@ class Foo8[A](x: A) { x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.212: let tmp = Foo8(y).test1(x) +//│ ║ l.216: let tmp = Foo8(y).test1(x) //│ ╙── ^^^^^^ //│ class Foo8[A](x: A) { //│ fun test1: (y: anything) -> A @@ -226,7 +230,7 @@ class Foo8[A](x: A) { abstract class List(val length: Int): Cons class Cons(tail: List) extends List(tail.length + 1) //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.227: class Cons(tail: List) extends List(tail.length + 1) +//│ ║ l.231: class Cons(tail: List) extends List(tail.length + 1) //│ ╙── ^^^^^^^ //│ abstract class List(length: Int): Cons //│ class Cons(tail: List) extends List @@ -238,7 +242,7 @@ abstract class List[out A](val length: Int): Cons[A] | Nil class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) module Nil extends List[nothing](0) //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.238: class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) +//│ ║ l.242: class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) //│ ╙── ^^^^^^^ //│ abstract class List[A](length: Int): Cons[A] | Nil //│ class Cons[A](head: A, tail: List[A]) extends List diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index 4b70ba4385..1ebff6886b 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -94,7 +94,7 @@ class Cls[A] { fun x: A = x } //│ } let c = new Cls -//│ let c: forall 'A. Cls['A] +//│ let c: Cls[nothing] //│ c //│ = Cls {} From debf5c545890b1650459432f225ef638e37bf2b3 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 4 Oct 2023 15:49:17 +0800 Subject: [PATCH 472/498] Adjust detection of non-unit statements + add some tests --- .../src/main/scala/mlscript/NuTypeDefs.scala | 29 ++-- .../src/test/diff/codegen/ConstructorStmt.mls | 30 +++- shared/src/test/diff/codegen/Nested.mls | 4 +- shared/src/test/diff/nu/AuxCtors.mls | 6 +- shared/src/test/diff/nu/BadClasses.mls | 28 ++-- shared/src/test/diff/nu/BadScopes.mls | 4 +- shared/src/test/diff/nu/BasicClasses.mls | 11 ++ .../src/test/diff/nu/ImplicitMethodPolym.mls | 44 +++--- .../src/test/diff/nu/ThisRefinedClasses.mls | 26 +++- shared/src/test/diff/nu/Unit.mls | 74 +++++++++- shared/src/test/diff/scalac/i13162.mls | 131 ++++++++++++++++++ 11 files changed, 332 insertions(+), 55 deletions(-) create mode 100644 shared/src/test/diff/scalac/i13162.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8aa26ed388..4bf98646ec 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -644,6 +644,11 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => }) ctx ++= completedInfos + val returnsLastExpr = outer.map(_.kind) match { + case N | S(Block | Val) => true + case S(_: TypeDefKind) => false + } + // * Type the block statements def go(stmts: Ls[Statement]): Opt[ST] = stmts match { case s :: stmts => @@ -652,16 +657,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case t: Term => implicit val genLambdas: GenLambdas = true val ty = typeTerm(t) - if (!topLevel && !stmts.isEmpty) { - if (t.isInstanceOf[Var] || t.isInstanceOf[Lit]) - warn("Pure expression does nothing in statement position.", t.toLoc) - else - constrain(mkProxy(ty, TypeProvenance(t.toCoveringLoc, "expression in statement position")), UnitType)( - raise = err => raise(WarningReport( // Demote constraint errors from this to warnings - msg"Expression in statement position should have type `unit`." -> N :: - msg"Use the `discard` function to discard non-unit values, making the intent clearer." -> N :: - err.allMsgs, newDefs)), - prov = TypeProvenance(t.toLoc, t.describe), ctx) + if (!topLevel && !(stmts.isEmpty && returnsLastExpr)) { + t match { + // * We do not include `_: Var` because references to `fun`s and lazily-initialized + // * definitions may have side effects. + case _: Lit | _: Lam => + warn("Pure expression does nothing in statement position.", t.toLoc) + case _ => + constrain(mkProxy(ty, TypeProvenance(t.toCoveringLoc, "expression in statement position")), UnitType)( + raise = err => raise(WarningReport( // Demote constraint errors from this to warnings + msg"Expression in statement position should have type `unit`." -> N :: + msg"Use the `discard` function to discard non-unit values, making the intent clearer." -> N :: + err.allMsgs, newDefs)), + prov = TypeProvenance(t.toLoc, t.describe), ctx) + } } S(ty) case s: DesugaredStatement => diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 400e409897..a61301347e 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -139,13 +139,25 @@ let ab = A(0) //│ 0 :e +:w :js class Foo { this: { x: Int } } //│ ╔══[ERROR] Type `#Foo` does not contain member `x` -//│ ║ l.144: this: { x: Int } +//│ ║ l.145: this: { x: Int } //│ ╙── ^ +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in type ascription: +//│ ║ l.145: this: { x: Int } +//│ ║ ^^^^ +//│ ╟── type `{x: Int}` does not match type `()` +//│ ║ l.145: this: { x: Int } +//│ ║ ^^^^^^^^^^ +//│ ╟── but it flows into expression in statement position with expected type `()` +//│ ║ l.145: this: { x: Int } +//│ ╙── ^^^^ //│ class Foo { //│ constructor() //│ } @@ -168,16 +180,28 @@ class Foo { //│ // End of generated code :e +:w :js class Bar { super: { x: Int } } //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.173: super: { x: Int } +//│ ║ l.186: super: { x: Int } //│ ╙── ^^^^^ //│ ╔══[ERROR] Type `#Bar` does not contain member `x` -//│ ║ l.173: super: { x: Int } +//│ ║ l.186: super: { x: Int } //│ ╙── ^ +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in type ascription: +//│ ║ l.186: super: { x: Int } +//│ ║ ^^^^^ +//│ ╟── type `{x: Int}` does not match type `()` +//│ ║ l.186: super: { x: Int } +//│ ║ ^^^^^^^^^^ +//│ ╟── but it flows into expression in statement position with expected type `()` +//│ ║ l.186: super: { x: Int } +//│ ╙── ^^^^^ //│ class Bar { //│ constructor() //│ } diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 680d182b10..10843c74aa 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -1430,9 +1430,9 @@ module Test { log(0) module Foo { log(2) } log(1) - discard of Foo + discard(Foo) log(3) - Foo + discard(Foo) } //│ module Test { //│ module Foo diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index 038deb6eee..583a7bf830 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -168,10 +168,14 @@ new C(1, 2) //│ [ 1, 1 ] :pe +:w class C { constructor(x: Int);; constructor(y: Int) } //│ ╔══[PARSE ERROR] A class may have at most one explicit constructor -//│ ║ l.171: class C { constructor(x: Int);; constructor(y: Int) } +//│ ║ l.172: class C { constructor(x: Int);; constructor(y: Int) } //│ ╙── ^^^^^ +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.172: class C { constructor(x: Int);; constructor(y: Int) } +//│ ╙── ^^ //│ class C { //│ constructor(x: Int) //│ } diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 0498d01ebe..2fc62489c2 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -96,14 +96,24 @@ hello :e +:w class Foo[A] { 42: A } //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.99: class Foo[A] { 42: A } -//│ ║ ^^ +//│ ║ l.100: class Foo[A] { 42: A } +//│ ║ ^^ //│ ╟── integer literal of type `42` does not match type `A` //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.99: class Foo[A] { 42: A } -//│ ╙── ^ +//│ ║ l.100: class Foo[A] { 42: A } +//│ ╙── ^ +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in type ascription: +//│ ║ l.100: class Foo[A] { 42: A } +//│ ║ ^^ +//│ ╟── expression in statement position of type `A` does not match type `()` +//│ ╟── Note: type parameter A is defined at: +//│ ║ l.100: class Foo[A] { 42: A } +//│ ╙── ^ //│ class Foo[A] { //│ constructor() //│ } @@ -112,7 +122,7 @@ class Foo[A] { 42: A } :e class C1 { fun oops = this.x } //│ ╔══[ERROR] Type `#C1` does not contain member `x` -//│ ║ l.113: class C1 { fun oops = this.x } +//│ ║ l.123: class C1 { fun oops = this.x } //│ ╙── ^^ //│ class C1 { //│ constructor() @@ -123,10 +133,10 @@ class C1 { fun oops = this.x } :e class C { fun x: Int } //│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C` -//│ ║ l.124: class C { fun x: Int } +//│ ║ l.134: class C { fun x: Int } //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.124: class C { fun x: Int } +//│ ║ l.134: class C { fun x: Int } //│ ╙── ^^^^^^^^^^ //│ class C { //│ constructor() @@ -136,10 +146,10 @@ class C { fun x: Int } :e class C { val x: Int } //│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `C` -//│ ║ l.137: class C { val x: Int } +//│ ║ l.147: class C { val x: Int } //│ ║ ^ //│ ╟── Declared here: -//│ ║ l.137: class C { val x: Int } +//│ ║ l.147: class C { val x: Int } //│ ╙── ^^^^^^^^^^ //│ class C { //│ constructor() diff --git a/shared/src/test/diff/nu/BadScopes.mls b/shared/src/test/diff/nu/BadScopes.mls index c8b797dced..9c66a019a9 100644 --- a/shared/src/test/diff/nu/BadScopes.mls +++ b/shared/src/test/diff/nu/BadScopes.mls @@ -26,12 +26,10 @@ x :e -class Foo(x: Int) class Bar { x } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.30: class Bar { x } +//│ ║ l.29: class Bar { x } //│ ╙── ^ -//│ class Foo(x: Int) //│ class Bar { //│ constructor() //│ } diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index b668405ca8..0fc43083b4 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -217,6 +217,17 @@ class Annots(base: 0 | 1) { a: Int fun a = base } +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in type ascription: +//│ ║ l.217: a: Int +//│ ║ ^ +//│ ╟── type `Int` does not match type `()` +//│ ║ l.217: a: Int +//│ ║ ^^^ +//│ ╟── but it flows into expression in statement position with expected type `()` +//│ ║ l.217: a: Int +//│ ╙── ^ //│ class Annots(base: 0 | 1) { //│ fun a: 0 | 1 //│ } diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 64f05835b3..94642a1a7f 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -26,9 +26,10 @@ M.id1(0) module M { fun id1(x) = x - id1(0) + let _ = id1(0) } //│ module M { +//│ let _: 0 //│ fun id1: forall 'a. 'a -> 'a //│ } @@ -69,7 +70,7 @@ module M extends Mx { this.id1(0) } //│ ╔══[ERROR] Type `#M & {id1: ?a -> ?b}` does not contain member `id2` -//│ ║ l.60: fun id1(x) = this.id2(x) +//│ ║ l.61: fun id1(x) = this.id2(x) //│ ╙── ^^^^ //│ module M { //│ fun id1: anything -> error @@ -83,7 +84,7 @@ module M extends Mx { this.id1(0) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.60: fun id1(x) = this.id2(x) +//│ ║ l.61: fun id1(x) = this.id2(x) //│ ╙── ^^^^ //│ module M { //│ fun id1: anything -> error @@ -94,9 +95,10 @@ module M extends Mx { module M extends Mx { fun id2: 'a => ['a, 'a] fun id2(x) = [x, x] - this.id1(0) + let _ = this.id1(0) } //│ module M { +//│ let _: [0 | 'a, 0 | 'a] //│ fun id1: 'a -> [0 | 'a, 0 | 'a] //│ fun id2: forall 'a0. 'a0 -> ['a0, 'a0] //│ } @@ -110,10 +112,10 @@ class C { fun id2(x) = x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.109: fun f = [this.id1(true), this.id1(0)] +//│ ║ l.111: fun f = [this.id1(true), this.id1(0)] //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.109: fun f = [this.id1(true), this.id1(0)] +//│ ║ l.111: fun f = [this.id1(true), this.id1(0)] //│ ╙── ^^^^ //│ class C { //│ constructor() @@ -128,10 +130,10 @@ module M extends C { this.id2(true) } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.128: this.id2(true) +//│ ║ l.130: this.id2(true) //│ ╙── ^^^^ //│ ╔══[ERROR] Cannot access `this` during object initialization -//│ ║ l.128: this.id2(true) +//│ ║ l.130: this.id2(true) //│ ╙── ^^^^ //│ module M extends C { //│ fun f: [error, error] @@ -144,13 +146,13 @@ module M extends C { fun g = (this.id2(true), this.id2(0)) } //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.144: fun g = (this.id2(true), this.id2(0)) +//│ ║ l.146: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.144: fun g = (this.id2(true), this.id2(0)) +//│ ║ l.146: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.144: fun g = (this.id2(true), this.id2(0)) +//│ ║ l.146: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ //│ module M extends C { //│ fun f: [error, error] @@ -185,15 +187,15 @@ module M extends C { fun id1 = succ } //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.185: fun id1 = succ +//│ ║ l.187: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╙── variable of type `?a` is not an instance of type `Int` //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.185: fun id1 = succ +//│ ║ l.187: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from reference: -//│ ║ l.108: virtual fun id1(x) = x +//│ ║ l.110: virtual fun id1(x) = x //│ ╙── ^ //│ module M extends C { //│ fun f: [error, error] @@ -216,10 +218,10 @@ M.id1 // FIXME? parsing/semantics of this, currently treated as a named tuple... (M: C) //│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.217: (M: C) +//│ ║ l.219: (M: C) //│ ╙── ^^^^^^ //│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword -//│ ║ l.217: (M: C) +//│ ║ l.219: (M: C) //│ ╙── ^ //│ [M: () -> C] //│ res @@ -239,19 +241,19 @@ module M { fun oops(x) = m := x } //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword in expression position -//│ ║ l.238: mut val m = None +//│ ║ l.240: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.238: mut val m = None +//│ ║ l.240: mut val m = None //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: := -//│ ║ l.239: fun oops(x) = m := x +//│ ║ l.241: fun oops(x) = m := x //│ ╙── ^^ //│ ╔══[ERROR] identifier not found: m -//│ ║ l.239: fun oops(x) = m := x +//│ ║ l.241: fun oops(x) = m := x //│ ╙── ^ //│ ╔══[ERROR] Unexpected equation in this position -//│ ║ l.238: mut val m = None +//│ ║ l.240: mut val m = None //│ ╙── ^^^^^^^^ //│ module M { //│ fun oops: anything -> error diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index 839defa279..dea56120c3 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -47,6 +47,17 @@ class Foo { //│ ╔══[ERROR] Type `#Foo` does not contain member `x` //│ ║ l.44: this: { x: 'a } //│ ╙── ^ +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in type ascription: +//│ ║ l.44: this: { x: 'a } +//│ ║ ^^^^ +//│ ╟── type `{x: 'a}` does not match type `()` +//│ ║ l.44: this: { x: 'a } +//│ ║ ^^^^^^^^^ +//│ ╟── but it flows into expression in statement position with expected type `()` +//│ ║ l.44: this: { x: 'a } +//│ ╙── ^^^^ //│ class Foo { //│ constructor() //│ } @@ -56,11 +67,22 @@ class Foo { // * All on one line: class Test { this: { x: Int};; fun test = this.x } //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.57: class Test { this: { x: Int};; fun test = this.x } +//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } //│ ╙── ^^ //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.57: class Test { this: { x: Int};; fun test = this.x } +//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } //│ ╙── ^ +//│ ╔══[WARNING] Expression in statement position should have type `unit`. +//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╟── Type mismatch in type ascription: +//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } +//│ ║ ^^^^ +//│ ╟── type `{x: Int}` does not match type `()` +//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } +//│ ║ ^^^^^^^^^ +//│ ╟── but it flows into expression in statement position with expected type `()` +//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } +//│ ╙── ^^^^ //│ class Test { //│ constructor() //│ fun test: error diff --git a/shared/src/test/diff/nu/Unit.mls b/shared/src/test/diff/nu/Unit.mls index a2df12657c..9c8b6a46eb 100644 --- a/shared/src/test/diff/nu/Unit.mls +++ b/shared/src/test/diff/nu/Unit.mls @@ -258,21 +258,87 @@ let _ = succ(0);; 0 //│ = 0 +x => x; () +//│ () -> () +//│ res +//│ = [Function: res] + +x => x;; () +//│ () +//│ res +//│ = [Function: res] +//│ res +//│ = undefined + +:w +fun f = + x => x;; () +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.275: x => x;; () +//│ ╙── ^^^^^^ +//│ fun f: () + +fun f = + discard of x => x;; () +//│ fun f: () + +:w +fun f = + x => x + () +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.287: x => x +//│ ╙── ^^^^^^ +//│ fun f: () + + +:w +module Test { + 123 +} +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.297: 123 +//│ ╙── ^^^ +//│ module Test + +:w +module Test { + 123 + 456 +} +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.306: 123 +//│ ╙── ^^^ +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.307: 456 +//│ ╙── ^^^ +//│ module Test + +:w +module Test { + x => x +} +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.319: x => x +//│ ╙── ^^^^^^ +//│ module Test + + :e fun foo = let tmp = 0 foo + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.265: foo + 1 +//│ ║ l.331: foo + 1 //│ ║ ^^^^^^^ //│ ╟── definition of method foo of type `()` is not an instance of type `Int` -//│ ║ l.263: fun foo = +//│ ║ l.329: fun foo = //│ ║ ^^^^^ -//│ ║ l.264: let tmp = 0 +//│ ║ l.330: let tmp = 0 //│ ║ ^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `Int` -//│ ║ l.265: foo + 1 +//│ ║ l.331: foo + 1 //│ ╙── ^^^ //│ fun foo: () //│ Int | error diff --git a/shared/src/test/diff/scalac/i13162.mls b/shared/src/test/diff/scalac/i13162.mls new file mode 100644 index 0000000000..90e605fb7b --- /dev/null +++ b/shared/src/test/diff/scalac/i13162.mls @@ -0,0 +1,131 @@ +:NewDefs + + +// https://github.com/lampepfl/dotty/issues/13162 + +fun method = + class Person(val name: Str) + module Person_ { // TODO change when module overloading is supported + val me = Person("Cameron") + } + let m = Person_.me + m +method.name +//│ fun method: Person +//│ Str +//│ res +//│ = 'Cameron' + + +// https://github.com/lampepfl/dotty/issues/13162#issuecomment-887557311 + +// * We don't currently have self bindings + +// def method(): Unit = { +// final case class Person(name: String) +// object Person { self => +// val me = self.apply("Cameron") +// } +// val _ = Person.me +// } +// method() + +:w +:e +fun method: () = + class Person(val name: Str) + module Person_ { self => // * defines a useless lambda! + val me = self.apply("Cameron") + } + let m = Person_.me + m +method +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.37: module Person_ { self => // * defines a useless lambda! +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.38: val me = self.apply("Cameron") +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type `Person_` does not contain member `me` +//│ ║ l.40: let m = Person_.me +//│ ╙── ^^^ +//│ fun method: () +//│ () +//│ res +//│ = undefined + + +// https://github.com/lampepfl/dotty/issues/13162#issuecomment-888188804 + +:re +module Person { + fun f: () + fun f = Person2.f +} +module Person2 { + fun f = () + val me = Person.f +} +//│ module Person { +//│ fun f: () +//│ } +//│ module Person2 { +//│ fun f: () +//│ val me: () +//│ } +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +fun test = Person2.me +//│ fun test: () + + +// * FIXME initialization check? or different codegen? +fun test = + module Person { + fun f: () + fun f = Person2.f + } + module Person2 { + fun f = () + val me = Person.f + } + Person2.me +//│ fun test: () + +:re +test +//│ () +//│ res +//│ Runtime error: +//│ ReferenceError: Cannot access 'Person2' before initialization + +module Test { + module Person { + fun f: () + fun f = Person2.f + } + module Person2 { + fun f = () + val me = Person.f + } + fun test = Person2.me +} +//│ module Test { +//│ module Person { +//│ fun f: () +//│ } +//│ module Person2 { +//│ fun f: () +//│ val me: () +//│ } +//│ fun test: () +//│ } + +:re +Test.test +//│ () +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + + From 2976832014ccb324f16bc891b55b76424382167b Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 4 Oct 2023 23:56:21 +0800 Subject: [PATCH 473/498] Fix handling of polymorphic type aliases & add tests --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- .../main/scala/mlscript/TyperHelpers.scala | 61 ++-- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/test/diff/basics/Datatypes.fun | 2 +- shared/src/test/diff/fcp/QML_exist_nu.mls | 339 ++++++++++++++++++ shared/src/test/diff/nu/Ascription.mls | 2 +- shared/src/test/diff/nu/MIscPoly.mls | 78 ++++ .../test/diff/nu/NuPolymorphicTypeAliases.mls | 93 +++++ shared/src/test/diff/parser/Where.mls | 4 +- 9 files changed, 543 insertions(+), 40 deletions(-) create mode 100644 shared/src/test/diff/fcp/QML_exist_nu.mls create mode 100644 shared/src/test/diff/nu/MIscPoly.mls create mode 100644 shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 4bf98646ec..7d3de82639 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -1434,7 +1434,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val body_ty = td.sig match { case S(sig) => - typeType(sig) + ctx.nextLevel { implicit ctx: Ctx => typeType(sig) } case N => err(msg"Type alias definition requires a right-hand side", td.toLoc) } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 8f3d0db44c..80228b3fc5 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -921,11 +921,32 @@ abstract class TyperHelpers { Typer: Typer => res.toSortedMap } - private def childrenMem(m: NuMember): List[ST] = m match { - case NuParam(nme, ty, pub) => ty.lb.toList ::: ty.ub :: Nil - case TypedNuFun(level, fd, ty) => ty :: Nil + private def childrenMem(m: NuMember): IterableOnce[ST] = m match { + case tf: TypedNuFun => + tf.bodyType :: Nil + case als: TypedNuAls => + als.tparams.iterator.map(_._2) ++ S(als.body) + case mxn: TypedNuMxn => + mxn.tparams.iterator.map(_._2) ++ + mxn.members.valuesIterator.flatMap(childrenMem) ++ + S(mxn.superTy) ++ + S(mxn.thisTy) + case cls: TypedNuCls => + cls.tparams.iterator.map(_._2) ++ + cls.params.toList.flatMap(_.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil)) ++ + cls.auxCtorParams.toList.flatMap(_.values) ++ + cls.members.valuesIterator.flatMap(childrenMem) ++ + S(cls.thisTy) ++ + S(cls.sign) + case trt: TypedNuTrt => + trt.tparams.iterator.map(_._2) ++ + trt.members.valuesIterator.flatMap(childrenMem) ++ + S(trt.thisTy) ++ + S(trt.sign) ++ + trt.parentTP.valuesIterator.flatMap(childrenMem) + case p: NuParam => + p.ty.lb.toList ::: p.ty.ub :: Nil case TypedNuDummy(d) => Nil - case _ => ??? // TODO } def children(includeBounds: Bool): List[SimpleType] = this match { case tv @ AssignedVariable(ty) => if (includeBounds) ty :: Nil else Nil @@ -949,35 +970,7 @@ abstract class TyperHelpers { Typer: Typer => case ConstrainedType(cs, und) => cs.flatMap(lu => lu._1 :: lu._2 :: Nil) ::: und :: Nil case SpliceType(fs) => fs.flatMap{ case L(l) => l :: Nil case R(r) => r.lb.toList ::: r.ub :: Nil} case OtherTypeLike(tu) => - // tu.childrenPol(PolMap.neu).map(tp => tp._1) - val ents = tu.implementedMembers.flatMap { - case tf: TypedNuFun => - tf.bodyType :: Nil - case als: TypedNuAls => - als.tparams.iterator.map(_._2) ++ S(als.body) - case mxn: TypedNuMxn => - mxn.tparams.iterator.map(_._2) ++ - mxn.members.valuesIterator.flatMap(childrenMem) ++ - S(mxn.superTy) ++ - S(mxn.thisTy) - case cls: TypedNuCls => - cls.tparams.iterator.map(_._2) ++ - cls.params.toList.flatMap(_.flatMap(p => p._2.lb.toList ::: p._2.ub :: Nil)) ++ - cls.auxCtorParams.toList.flatMap(_.values) ++ - cls.members.valuesIterator.flatMap(childrenMem) ++ - S(cls.thisTy) ++ - S(cls.sign) /* ++ - S(cls.instanceType) // Not a real child; to remove */ - case trt: TypedNuTrt => - trt.tparams.iterator.map(_._2) ++ - trt.members.valuesIterator.flatMap(childrenMem) ++ - S(trt.thisTy) ++ - S(trt.sign) ++ - trt.parentTP.valuesIterator.flatMap(childrenMem) - case p: NuParam => - p.ty.lb.toList ::: p.ty.ub :: Nil - case TypedNuDummy(d) => Nil - } + val ents = tu.implementedMembers.flatMap(childrenMem) ents ::: tu.result.toList } @@ -1105,7 +1098,7 @@ abstract class TyperHelpers { Typer: Typer => info.result match { case S(td: TypedNuAls) => assert(td.tparams.size === targs.size) - substSyntax(td.body)(td.tparams.lazyZip(targs).map { + subst(td.body, td.tparams.lazyZip(targs).map { case (tp, ta) => SkolemTag(tp._2)(noProv) -> ta }.toMap) case S(td: TypedNuTrt) => diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index 64fba3bf1c..c6061ce28d 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -622,7 +622,7 @@ trait TermImpl extends StatementImpl { self: Term => try R(toType_!.withLocOf(this)) catch { case e: NotAType => import Message._ - L(ErrorReport(msg"not a recognized type" -> e.trm.toLoc::Nil, newDefs=true)) } + L(ErrorReport(msg"Not a recognized type" -> e.trm.toLoc::Nil, newDefs=true)) } protected def toType_! : Type = (this match { case Var(name) if name.startsWith("`") => TypeVar(R(name.tail), N) case Var(name) if name.startsWith("'") => TypeVar(R(name), N) diff --git a/shared/src/test/diff/basics/Datatypes.fun b/shared/src/test/diff/basics/Datatypes.fun index 6dd65dc09d..2b2b0e7379 100644 --- a/shared/src/test/diff/basics/Datatypes.fun +++ b/shared/src/test/diff/basics/Datatypes.fun @@ -115,7 +115,7 @@ data type List a of Nil Cons (head: a) (tail: List a) //│ Parsed: data type List(...a) of {Nil; Cons(...'(' {[head: a,]} ')')(...'(' {[tail: List(...a),]} ')')}; -//│ ╔══[ERROR] not a recognized type +//│ ╔══[ERROR] Not a recognized type //│ ║ l.116: Cons (head: a) (tail: List a) //│ ╙── ^^^^^^ //│ Desugared: type alias List[a] = Nil[a] | Cons[a] diff --git a/shared/src/test/diff/fcp/QML_exist_nu.mls b/shared/src/test/diff/fcp/QML_exist_nu.mls new file mode 100644 index 0000000000..39fa4e19e9 --- /dev/null +++ b/shared/src/test/diff/fcp/QML_exist_nu.mls @@ -0,0 +1,339 @@ +// * TODO also a GADT version of this where we use `Arrays[A]: ArraysImpl[A, ?]` + +:NewDefs + +:DontDistributeForalls // * Also works without this + + + +declare module Math { + fun trunc: Num -> Int +} +//│ declare module Math { +//│ fun trunc: Num -> Int +//│ } + +fun div(a, b) = Math.trunc(a/b) +fun mod(a, b) = if a < b then a else mod(a - b, b) +//│ fun div: (Num, Num) -> Int +//│ fun mod: (Int, Int) -> Int + + + +abstract class ArraysImpl[A, Rep] { + fun init: A -> Rep + fun sub: (Rep, Int) -> A + fun update: (Rep, Int, A) -> Rep + fun fold: (Rep, 'b, A -> 'b -> 'b) -> 'b +} +//│ abstract class ArraysImpl[A, Rep] { +//│ fun fold: forall 'b. (Rep, 'b, A -> 'b -> 'b) -> 'b +//│ fun init: A -> Rep +//│ fun sub: (Rep, Int) -> A +//│ fun update: (Rep, Int, A) -> Rep +//│ } + +type ArraysImplConsumer[A, R] = forall 'rep: ArraysImpl[A, 'rep] -> R +//│ type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R + +abstract class Arrays[A] { + fun use: ArraysImplConsumer[A, 'res] -> 'res +} +//│ abstract class Arrays[A] { +//│ fun use: forall 'res. ArraysImplConsumer[A, 'res] -> 'res +//│ } + + +class BaseImpl[A]() extends ArraysImpl[A, A] { + fun init (a) = a + fun sub (r, i) = r + fun update(r, i, a) = a + fun fold (r, b, f) = f(r)(b) +} +//│ class BaseImpl[A]() extends ArraysImpl { +//│ fun fold: forall 'a 'b 'c. ('a, 'b, 'a -> 'b -> 'c) -> 'c +//│ fun init: forall 'd. 'd -> 'd +//│ fun sub: forall 'e. ('e, anything) -> 'e +//│ fun update: forall 'f. (anything, anything, 'f) -> 'f +//│ } + +class StepImpl[A, R](underlying: ArraysImpl[A, R]) extends ArraysImpl[A, [R, R]] { + fun init(a) = [underlying.init(a), underlying.init(a)] + fun sub([r0, r1], i) = + if mod(i, 2) === 0 + then underlying.sub(r0, div(i, 2)) + else underlying.sub(r1, div(i, 2)) + fun update([r0, r1], i, a) = + if mod(i, 2) == 0 + then [underlying.update(r0, div(i, 2), a), r1] + else [r0, underlying.update(r1, div(i, 2), a)] + fun fold([r0, r1], b, f) = + underlying.fold(r0, underlying.fold(r1, b, f), f) +} +//│ class StepImpl[A, R](underlying: ArraysImpl[A, R]) extends ArraysImpl { +//│ fun fold: forall 'b 'b0. ([R, R], 'b & 'b0, A -> ('b -> ('b & 'b0) & 'b0 -> 'b0)) -> 'b0 +//│ fun init: A -> [R, R] +//│ fun sub: ([R, R], Eql[0] & Int) -> A +//│ fun update: ([R, R], Int, A) -> [R, R] +//│ } + + +class Base[A]() extends Arrays[A] { + val impl = BaseImpl() + fun use(k) = k(impl) +} +//│ class Base[A]() extends Arrays { +//│ val impl: BaseImpl[A] +//│ fun use: forall 'a. (BaseImpl[A] -> 'a) -> 'a +//│ } + +class Step[A](from: Arrays[A]) extends Arrays[A] { + + // * Note: expansion of alias is capture-avoiding of polymorphic levels + fun use(k: ArraysImplConsumer[A, 'res]) = from.use of + forall 'rep: + (impl: ArraysImpl[A, 'rep]) => k(StepImpl(impl)) + +} +//│ class Step[A](from: Arrays[A]) extends Arrays { +//│ fun use: forall 'res. (k: ArraysImplConsumer[A, 'res]) -> 'res +//│ } + +// * A version with fewer annotations +class Step[A](from: Arrays[A]) extends Arrays[A] { + + fun use(k: ArraysImplConsumer[A, 'res]) = + from.use of impl => k(StepImpl(impl)) + + // * Spelling out the type synonym: + fun use': ArraysImplConsumer[A, 'res] -> 'res + fun use'(k: forall 'rep: ArraysImpl[A, 'rep] -> 'res) = + from.use of impl => k of StepImpl(impl) + +} +//│ class Step[A](from: Arrays[A]) extends Arrays { +//│ fun use: forall 'res. (k: ArraysImplConsumer[A, 'res]) -> 'res +//│ fun use': forall 'res0. ArraysImplConsumer[A, 'res0] -> 'res0 +//│ } + +// * Note: the annotation on `k` is required, otherwise we leak the locally-polymorphic `impl` +// * (We don't currently do any bidirectional typing.) +:e +class Step'[A](from: Arrays[A]) extends Arrays[A] { + fun use(k) = + from.use of impl => k(StepImpl(impl)) +} +//│ ╔══[ERROR] Type error in definition of method use +//│ ║ l.123: fun use(k) = +//│ ║ ^^^^^^^^ +//│ ║ l.124: from.use of impl => k(StepImpl(impl)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `'rep` leaks out of its scope +//│ ║ l.36: type ArraysImplConsumer[A, R] = forall 'rep: ArraysImpl[A, 'rep] -> R +//│ ║ ^^^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this reference: +//│ ║ l.124: from.use of impl => k(StepImpl(impl)) +//│ ║ ^^^^ +//│ ╟── • this signature of member `use`: +//│ ║ l.40: fun use: ArraysImplConsumer[A, 'res] -> 'res +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── • this field selection: +//│ ║ l.124: from.use of impl => k(StepImpl(impl)) +//│ ╙── ^^^^^^^^ +//│ class Step'[A](from: Arrays[A]) extends Arrays { +//│ fun use: forall 'R 'a. (StepImpl[A, in ??rep & 'R out 'R | ??rep0] -> 'a) -> 'a +//│ } +//│ Syntax error: +//│ Unexpected string + + +let ssb = Step(Step(Base())) +//│ let ssb: Step['A] +//│ ssb +//│ = Step {} + +ssb.use of impl => + let r = impl.update(impl.init(true), 1, false) + log(r) + [impl.sub(r, 0), impl.sub(r, 1)] +//│ [Bool, Bool] +//│ res +//│ = [ true, false ] +//│ // Output +//│ [ [ true, true ], [ false, true ] ] + +fun mkMonoArray(n) = + if n === 0 then Base() else Step(mkMonoArray(n - 1)) +//│ fun mkMonoArray: forall 'A. (Eql[0] & Int) -> (Base['A] | Step['A]) + +let snb = mkMonoArray(3) +//│ let snb: Base['A] | Step['A] +//│ snb +//│ = Step {} + +snb.use of impl => + let r = impl.update(impl.init(true), 1, false) + log(r) +//│ () +//│ res +//│ = undefined +//│ // Output +//│ [ +//│ [ [ true, true ], [ true, true ] ], +//│ [ [ false, true ], [ true, true ] ] +//│ ] + +// * Here we are trying to leak the internally-quantified representation, resulting in the `??rep` extrusion +snb.use of impl => impl.init(true) +// :d +//│ true | ??rep +//│ res +//│ = [ +//│ [ [ true, true ], [ true, true ] ], +//│ [ [ true, true ], [ true, true ] ] +//│ ] + + +// * An alternative implementation of Step with the existential opened outside the function. + +class StepAlt[A](from: Arrays[A]) extends Arrays[A] { + val use = from.use of impl => + (k: ArraysImplConsumer[A, 'res]) => k(StepImpl(impl)) +} +//│ class StepAlt[A](from: Arrays[A]) extends Arrays { +//│ val use: forall 'res. (k: ArraysImplConsumer[A, 'res]) -> 'res +//│ } + +// * With the following, we get "type variable `'rep` leaks out of its scope" +:e +class StepAlt'[A](from: Arrays[A]) extends Arrays[A] { + val use = from.use of impl => + k => k(StepImpl(impl)) + // * ^ This is because we leak impl's representation to `k` in the local `k =>` lambda, + // * which flows to the type of `use`, where it's extruded: + // * forall 'r; (StepImpl[A, ??impl] -> 'r) -> 'r + // * Interestingly, once we use first-class existentials to extrude things, + // * this should start working, because we'll get + // * exists impl; forall 'r; (StepImpl[A, impl] -> 'r) -> 'r + // * which is a sutbype of the required + // * (forall 'rep; ArraysImpl[A, 'rep] -> 'res) -> 'res + // * because we can 0-rigidify `impl` and then subtype + // * 0. (StepImpl[A, impl] -> 'r) -> 'r <: (forall 'rep; ArraysImpl[A, 'rep] -> 'res) -> 'res + // * ie, constraining the parameters and 1-instantiating `forall 'rep`: + // * 1. ArraysImpl[A, 'rep] -> 'res <: (StepImpl[A, impl] -> 'r) -> 'r + // * which eventually leads to 'rep := impl and 'r := 'res. +} +//│ ╔══[ERROR] Type error in application +//│ ║ l.211: val use = from.use of impl => +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ║ l.212: k => k(StepImpl(impl)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `'rep` leaks out of its scope +//│ ║ l.36: type ArraysImplConsumer[A, R] = forall 'rep: ArraysImpl[A, 'rep] -> R +//│ ║ ^^^^ +//│ ╟── adding a type annotation to any of the following terms may help resolve the problem +//│ ╟── • this function: +//│ ║ l.211: val use = from.use of impl => +//│ ║ ^^^^^^^ +//│ ║ l.212: k => k(StepImpl(impl)) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── • this signature of member `use`: +//│ ║ l.40: fun use: ArraysImplConsumer[A, 'res] -> 'res +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── • this field selection: +//│ ║ l.211: val use = from.use of impl => +//│ ╙── ^^^^^^^^ +//│ class StepAlt'[A](from: Arrays[A]) extends Arrays { +//│ val use: forall 'R 'a. error | (StepImpl[A, 'R] -> 'a) -> 'a +//│ } +//│ where +//│ 'R :> ??rep +//│ <: ??rep0 +//│ Syntax error: +//│ Unexpected string + + +// * An alternative implementation of Step which only allocates one StepImpl per instance! + +class StepAlt[A](from: Arrays[A]) extends Arrays[A] { + + // * The explicit `forall 'res` is needed with distributivity turned off + val use = forall 'res: from.use of impl => + val impl2 = StepImpl(impl) + (k: ArraysImplConsumer[A, 'res]) => k(impl2) + + // * Version with full annotations (not necessary): + val use2: ArraysImplConsumer[A, 'res] -> 'res + val use2 = forall 'res: from.use of forall 'rr: (impl : ArraysImpl[A, 'rr]) => + val impl2 = StepImpl(impl) + (k: ArraysImplConsumer[A, 'res]) => k(impl2) + +} +//│ class StepAlt[A](from: Arrays[A]) extends Arrays { +//│ val use: forall 'res. (k: ArraysImplConsumer[A, 'res]) -> 'res +//│ val use2: forall 'res0. ArraysImplConsumer[A, 'res0] -> 'res0 +//│ } + + +// * A variation of the above without explicitly binding 'res, so it has to be distributed out + +:DistributeForalls // * Distributivity is needed here! + +class StepAlt[A](from: Arrays[A]) extends Arrays[A] { + val use = from.use of impl => + val impl2 = StepImpl(impl) + (k: ArraysImplConsumer[A, 'res]) => k(impl2) +} +//│ class StepAlt[A](from: Arrays[A]) extends Arrays { +//│ val use: forall 'res. (k: ArraysImplConsumer[A, 'res]) -> 'res +//│ } + + +// * Works the same: + +let ssb = StepAlt(StepAlt(Base())) +//│ let ssb: StepAlt['A] +//│ ssb +//│ = StepAlt {} + +ssb.use of impl => + let r = impl.update(impl.init(true), 1, false) + log(r) + [impl.sub(r, 0), impl.sub(r, 1)] +//│ [Bool, Bool] +//│ res +//│ = [ true, false ] +//│ // Output +//│ [ [ true, true ], [ false, true ] ] + +fun mkMonoArray(n) = + if n === 0 then Base() else StepAlt(mkMonoArray(n - 1)) +//│ fun mkMonoArray: forall 'A. (Eql[0] & Int) -> (forall 'A0. Base['A0] | StepAlt['A]) + +let snb = mkMonoArray(3) +//│ let snb: forall 'A 'A0. Base['A] | StepAlt['A0] +//│ snb +//│ = StepAlt {} + +snb.use of impl => + let r = impl.update(impl.init(true), 1, false) + log(r) +//│ () +//│ res +//│ = undefined +//│ // Output +//│ [ +//│ [ [ true, true ], [ true, true ] ], +//│ [ [ false, true ], [ true, true ] ] +//│ ] + +snb.use of impl => impl.init(true) +//│ true | ??rep +//│ res +//│ = [ +//│ [ [ true, true ], [ true, true ] ], +//│ [ [ true, true ], [ true, true ] ] +//│ ] + + diff --git a/shared/src/test/diff/nu/Ascription.mls b/shared/src/test/diff/nu/Ascription.mls index 5306d74f54..ff022d5c0c 100644 --- a/shared/src/test/diff/nu/Ascription.mls +++ b/shared/src/test/diff/nu/Ascription.mls @@ -13,7 +13,7 @@ // TODO? :e 1 : Int : Int -//│ ╔══[ERROR] not a recognized type +//│ ╔══[ERROR] Not a recognized type //│ ║ l.15: 1 : Int : Int //│ ╙── ^^^ //│ anything diff --git a/shared/src/test/diff/nu/MIscPoly.mls b/shared/src/test/diff/nu/MIscPoly.mls new file mode 100644 index 0000000000..3d9c94a5af --- /dev/null +++ b/shared/src/test/diff/nu/MIscPoly.mls @@ -0,0 +1,78 @@ +:NewDefs + + + +[(x: 'a) => x] +//│ [forall 'a. (x: 'a) -> 'a] +//│ res +//│ = [ [Function (anonymous)] ] + +[forall 'a: (x: 'a) => x] +//│ [forall 'a. (x: 'a) -> 'a] +//│ res +//│ = [ [Function (anonymous)] ] + + + +abstract class C0[A] { + fun use: forall 'r: [A, 'r -> 'r] +} +//│ abstract class C0[A] { +//│ fun use: forall 'r. [A, 'r -> 'r] +//│ } + +class C1 extends C0[Int] { + fun use = [0, id] +} +//│ class C1 extends C0 { +//│ constructor() +//│ fun use: [0, forall 'a. 'a -> 'a] +//│ } + +class C1[AA](aa: AA) extends C0[AA] { + fun use = [aa, id] +} +//│ class C1[AA](aa: AA) extends C0 { +//│ fun use: [AA, forall 'a. 'a -> 'a] +//│ } + + + +// * FIXME currently we always distribute `forall` types; +// * but this is not sound when distributing into a non-function such as an object type +// * as long as we perform object type intersection merges (which we want to) + +class C[A](){fun f: A -> A = id} +//│ class C[A]() { +//│ fun f: A -> A +//│ } + +let c = C() +//│ let c: forall 'A. C['A] +//│ c +//│ = C {} + +// :e // FIXME +let d = c : C[Int] & C[Str] +//│ let d: C[in Int | Str out nothing] +//│ d +//│ = C {} + +// :e // FIXME +let r = d.f(0) +//│ let r: nothing +//│ r +//│ = 0 + +:re +r() +//│ nothing +//│ res +//│ Runtime error: +//│ TypeError: r is not a function + + + + + + diff --git a/shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls b/shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls new file mode 100644 index 0000000000..649faaad34 --- /dev/null +++ b/shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls @@ -0,0 +1,93 @@ +:NewDefs + + +type F[A] = forall 'a: (A, 'a) -> [A, 'a] +//│ type F[A] = forall 'a. (A, 'a) -> [A, 'a] + + +fun f[B] = + ((x: B, y) => [x, y]) : F[B] +//│ fun f: forall 'B. F['B] + +fun f = forall 'B: + ((x: 'B, y) => [x, y]) : F['B] +//│ fun f: forall 'B. F['B] + + +module A { + type F[A] = forall 'a: (A, 'a) -> [A, 'a] +} +//│ module A { +//│ type F[A] = forall 'a. (A, 'a) -> [A, 'a] +//│ } + +:e // TODO +fun f[B] = + ((x: B, y) => [x, y]) : A.F[B] +//│ ╔══[ERROR] Not a recognized type +//│ ║ l.26: ((x: B, y) => [x, y]) : A.F[B] +//│ ╙── ^^^^^^ +//│ fun f: anything + + +class Test[B] { + fun f(f: F[B]): F[B] = (x, y) => f(x, y) +} +//│ class Test[B] { +//│ constructor() +//│ fun f: (f: F[B]) -> F[B] +//│ } + +class Test[B](f: F[B]) { + fun g: F[B] = (x, y) => f(x, y) +} +//│ class Test[B](f: F[B]) { +//│ fun g: F[B] +//│ } + +class Test[B] { + discard of ((x: B, y) => [x, y]) : F[B] +} +//│ class Test[B] { +//│ constructor() +//│ } + + +type F[A] = (A, 'a) -> [A, 'a] +//│ type F[A] = (A, 'a) -> [A, 'a] + + +fun f[B] = + ((x: B, y) => [x, y]) : F[B] +//│ fun f: forall 'B. F['B] + +fun f = forall 'B: + ((x: 'B, y) => [x, y]) : F['B] +//│ fun f: forall 'B. F['B] + + +class Test[B] { + fun f(f: F[B]): F[B] = (x, y) => f(x, y) +} +//│ class Test[B] { +//│ constructor() +//│ fun f: (f: F[B]) -> F[B] +//│ } + + + +// * Note: NOT polymorphic! +type T = 'a -> 'a +//│ type T = 'a -> 'a + +(id : T)(0) +//│ 0 +//│ res +//│ = 0 + +(id : T)(true) +//│ 0 | true +//│ res +//│ = true + + diff --git a/shared/src/test/diff/parser/Where.mls b/shared/src/test/diff/parser/Where.mls index d2e6ccef2c..43ff785a10 100644 --- a/shared/src/test/diff/parser/Where.mls +++ b/shared/src/test/diff/parser/Where.mls @@ -20,7 +20,7 @@ fun foo: 'a => 'a => 'a where 'a : int :e fun foo: 'a + 'a + 'a where 'a : int //│ |#fun| |foo|#:| |'a| |+| |'a| |+| |'a| |#where| |'a| |#:| |int| -//│ ╔══[ERROR] not a recognized type +//│ ╔══[ERROR] Not a recognized type //│ ║ l.21: fun foo: 'a + 'a + 'a where 'a : int //│ ╙── ^^^^^^^ //│ Parsed: {fun foo: anything} @@ -28,7 +28,7 @@ fun foo: 'a + 'a + 'a where 'a : int :e fun foo: 'a -> 'a -> 'a where 'a : int //│ |#fun| |foo|#:| |'a| |->| |'a| |->| |'a| |#where| |'a| |#:| |int| -//│ ╔══[ERROR] not a recognized type +//│ ╔══[ERROR] Not a recognized type //│ ║ l.29: fun foo: 'a -> 'a -> 'a where 'a : int //│ ╙── ^^^^^^^^^^^^^^ //│ Parsed: {fun foo: anything} From 40331354fc7df6e2815871ea1510f18f6a8ff775 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 6 Oct 2023 15:41:45 +0800 Subject: [PATCH 474/498] Fix recursive type "unskidding" Previously, unskidding was making some incorrect transformation (where some types lost precision). For instance, see the change in shared/src/test/diff/gadt/ThisMatching.mls. --- .../scala/mlscript/ConstraintSolver.scala | 2 +- .../main/scala/mlscript/TypeSimplifier.scala | 3 +- .../main/scala/mlscript/TyperDatatypes.scala | 12 +- .../main/scala/mlscript/TyperHelpers.scala | 16 +- shared/src/test/diff/basics/Simplesub1.fun | 39 +- shared/src/test/diff/codegen/Mixin.mls | 12 +- .../test/diff/ecoop23/ExpressionProblem.mls | 20 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 90 ++--- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 12 +- .../test/diff/ecoop23/SimpleRegionDSL_raw.mls | 56 ++- .../test/diff/fcp-lit/variations_PolyML.mls | 6 +- shared/src/test/diff/fcp/Church_CT.mls | 48 +-- shared/src/test/diff/fcp/FunnyId.mls | 90 ++--- shared/src/test/diff/fcp/ListBuild.mls | 21 +- shared/src/test/diff/fcp/NestedDataTypes.mls | 16 +- shared/src/test/diff/fcp/NoRecursiveTypes.mls | 15 + shared/src/test/diff/fcp/OCamlList.mls | 4 +- shared/src/test/diff/fcp/PaperTable.mls | 80 ++--- .../test/diff/fcp/QML_exist_Records_ND.mls | 41 ++- shared/src/test/diff/fcp/SystemF.mls | 2 +- shared/src/test/diff/fcp/SystemF_2.mls | 150 ++++---- shared/src/test/diff/gadt/ThisMatching.mls | 29 +- .../test/diff/gen/genTests_v1-0.14-15-x2.fun | 8 +- .../diff/mlf-examples/ex_casparticuliers.mls | 4 +- .../test/diff/mlf-examples/ex_concrete.mls | 4 +- shared/src/test/diff/mlf-examples/ex_demo.mls | 194 +++++----- .../test/diff/mlf-examples/ex_predicative.mls | 130 +++---- .../src/test/diff/mlf-examples/ex_selfapp.mls | 63 ++-- .../test/diff/mlf-examples/ex_validate.mls | 26 +- .../mlf-examples/merge_regression_min.mls | 16 +- shared/src/test/diff/mlscript/Addable.mls | 6 +- .../src/test/diff/mlscript/ByNameByValue.mls | 8 +- shared/src/test/diff/mlscript/David2.mls | 48 +-- shared/src/test/diff/mlscript/DavidB.mls | 34 +- shared/src/test/diff/mlscript/ExprProb.mls | 89 +++-- shared/src/test/diff/mlscript/ExprProb2.mls | 59 +-- .../src/test/diff/mlscript/ExprProb_Inv.mls | 95 ++--- .../test/diff/mlscript/Group_2022_06_09.mls | 22 +- shared/src/test/diff/mlscript/HeadOption.mls | 6 +- shared/src/test/diff/mlscript/Neg.mls | 4 +- .../test/diff/mlscript/NestedClassArgs.mls | 79 ++-- .../test/diff/mlscript/NestedClassArgs_Co.mls | 20 +- .../diff/mlscript/NestedRecursiveMatch.mls | 12 +- shared/src/test/diff/mlscript/Paper.mls | 16 +- shared/src/test/diff/mlscript/PolyVariant.mls | 10 +- .../diff/mlscript/PolyVariantCodeReuse.mls | 293 ++++++++------- shared/src/test/diff/mlscript/RecErrors.mls | 2 +- .../src/test/diff/mlscript/RecursiveTypes.mls | 129 ++++--- shared/src/test/diff/nu/ArrayProg.mls | 12 +- shared/src/test/diff/nu/Eval.mls | 22 +- shared/src/test/diff/nu/EvalNegNeg.mls | 12 +- shared/src/test/diff/nu/MutualRec.mls | 12 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 52 ++- shared/src/test/diff/nu/repro0.mls | 5 +- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 4 +- shared/src/test/diff/tapl/NuUntyped.mls | 2 +- shared/src/test/diff/tapl/SimplyTyped.mls | 337 ++++++++++++------ shared/src/test/diff/tapl/Untyped.mls | 298 ++++++++++------ shared/src/test/diff/tricky/Pottier.fun | 10 +- shared/src/test/diff/ucs/InterleavedLet.mls | 69 ++-- 60 files changed, 1619 insertions(+), 1357 deletions(-) create mode 100644 shared/src/test/diff/fcp/NoRecursiveTypes.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index 4a4913390e..e509a48579 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -1586,7 +1586,7 @@ class ConstraintSolver extends NormalForms { self: Typer => case tr @ TypeRef(d, ts) => TypeRef(d, ts.map(freshen(_)))(tr.prov) case pt @ PolymorphicType(polyLvl, bod) if pt.level <= above => pt // is this really useful? case pt @ PolymorphicType(polyLvl, bod) => - if (lvl > polyLvl) freshen(pt.raiseLevelTo(lvl)) + if (lvl > polyLvl) freshen(pt.raiseLevelToImpl(lvl, leaveAlone)) else PolymorphicType(polyLvl, freshenImpl(bod, below = below min polyLvl)) case ct @ ConstrainedType(cs, bod) => val cs2 = cs.map(lu => freshen(lu._1) -> freshen(lu._2)) diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index 37938771cb..f50c8285e5 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -1126,7 +1126,7 @@ trait TypeSimplifier { self: Typer => case (tv, S(pol)) => if (pol) (true, tv.lowerBounds.foldLeft(BotType: ST)(_ | _)) -> tv else (false, tv.upperBounds.foldLeft(TopType: ST)(_ &- _)) -> tv - }.toMap + }.filter { case ((pol, bnd), tv) => bnd.getVarsImpl(includeBounds = false).contains(tv) }.toMap println(s"consed: $consed") @@ -1308,7 +1308,6 @@ trait TypeSimplifier { self: Typer => // * by merging things like function types together... // * So we need another pass of simplification! cur = simplifyType(cur, removePolarVars, pol) - // cur = simplifyType(simplifyType(cur)(ct) debugOutput(s"⬤ Resim: ${cur}") debugOutput(s" where: ${cur.showBounds}") diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 306c82c566..45da2dc7ad 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -592,14 +592,19 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => } /** None: not recursive in this bound; Some(Some(pol)): polarly-recursive; Some(None): nonpolarly-recursive. * Note that if we have something like 'a :> Bot <: 'a -> Top, 'a is not truly recursive - * and its bounds can actually be inlined. */ + * and its bounds can actually be inlined. + * Also note that unfortunately, contrary to whta I previously thought, + * it is not sound to ignore quantified variables during the getVarsPol search. + * indeed, we can be in freaky situations like in `ListBuild.mls` + * where we have `'a :> Ls[('x, forall 'a. 'a)]`! */ private[mlscript] final def lbRecOccs_$(omitIrrelevantVars: Bool)(implicit ctx: Ctx): Opt[Opt[Bool]] = { // println("+", this, assignedTo getOrElse lowerBounds) // assignedTo.getOrElse(TupleType(lowerBounds.map(N -> _.toUpper(noProv)))(noProv)).getVarsPol(PolMap.pos, ignoreTopLevelOccs = true).get(this) val bs = assignedTo.fold(lowerBounds)(_ :: Nil) bs.foldLeft(BotType: ST)(_ | _).getVarsPol(PolMap.pos, ignoreTopLevelOccs = omitIrrelevantVars, - ignoreQuantifiedVars = omitIrrelevantVars, + // ignoreQuantifiedVars = omitIrrelevantVars, + ignoreQuantifiedVars = false, ).get(this) } private[mlscript] final def ubRecOccs_$(omitIrrelevantVars: Bool)(implicit ctx: Ctx): Opt[Opt[Bool]] ={ @@ -608,7 +613,8 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => val bs = assignedTo.fold(upperBounds)(_ :: Nil) bs.foldLeft(TopType: ST)(_ & _).getVarsPol(PolMap.posAtNeg, ignoreTopLevelOccs = omitIrrelevantVars, - ignoreQuantifiedVars = omitIrrelevantVars, + // ignoreQuantifiedVars = omitIrrelevantVars, + ignoreQuantifiedVars = false, ).get(this) // .tap(r => println(s"= $r")) } diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 80228b3fc5..d73bfc9f7b 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -92,6 +92,7 @@ abstract class TyperHelpers { Typer: Typer => def subst(st: SimpleType, map: Map[SimpleType, SimpleType], substInMap: Bool = false) (implicit ctx: Ctx): SimpleType = { val cache: MutMap[TypeVariable, SimpleType] = MutMap.empty + implicit val freshened: MutMap[TV, ST] = MutMap.empty val subsLvl: Level = map.valuesIterator.map(_.level).reduceOption(_ max _).getOrElse(MinLevel) def go(st: SimpleType): SimpleType = { // trace(s"subst($st)") { @@ -116,7 +117,7 @@ abstract class TyperHelpers { Typer: Typer => v }) case poly: PolymorphicType if poly.polymLevel < subsLvl => - go(poly.raiseLevelTo(subsLvl)) + go(poly.raiseLevelToImpl(subsLvl, Set.empty)) case _ => st.map(go(_)) } } @@ -974,18 +975,19 @@ abstract class TyperHelpers { Typer: Typer => ents ::: tu.result.toList } - def getVars: SortedSet[TypeVariable] = { + def getVarsImpl(includeBounds: Bool): SortedSet[TypeVariable] = { val res = MutSet.empty[TypeVariable] @tailrec def rec(queue: List[TypeLike]): Unit = queue match { case (tv: TypeVariable) :: tys => if (res(tv)) rec(tys) - else { res += tv; rec(tv.children(includeBounds = true) ::: tys) } - case ty :: tys => rec(ty.children(includeBounds = true) ::: tys) + else { res += tv; rec(tv.children(includeBounds = includeBounds) ::: tys) } + case ty :: tys => rec(ty.children(includeBounds = includeBounds) ::: tys) case Nil => () } rec(this :: Nil) SortedSet.from(res)(Ordering.by(_.uid)) } + def getVars: SortedSet[TypeVariable] = getVarsImpl(includeBounds = true) def showBounds: String = getVars.iterator.filter(tv => tv.assignedTo.nonEmpty || (tv.upperBounds ++ tv.lowerBounds).nonEmpty).map { @@ -1016,9 +1018,13 @@ abstract class TyperHelpers { Typer: Typer => } def raiseLevelTo(newPolymLevel: Level, leaveAlone: Set[TV] = Set.empty) (implicit ctx: Ctx): PolymorphicType = { + implicit val freshened: MutMap[TV, ST] = MutMap.empty + raiseLevelToImpl(newPolymLevel, leaveAlone) + } + def raiseLevelToImpl(newPolymLevel: Level, leaveAlone: Set[TV]) + (implicit ctx: Ctx, freshened: MutMap[TV, ST]): PolymorphicType = { require(newPolymLevel >= polymLevel) if (newPolymLevel === polymLevel) return this - implicit val freshened: MutMap[TV, ST] = MutMap.empty PolymorphicType(newPolymLevel, Typer.freshenAbove(polymLevel, body, leaveAlone = leaveAlone)( ctx.copy(lvl = newPolymLevel + 1), // * Q: is this really fine? cf. stashing/unstashing etc. diff --git a/shared/src/test/diff/basics/Simplesub1.fun b/shared/src/test/diff/basics/Simplesub1.fun index 09188fee1d..4b50a34f6e 100644 --- a/shared/src/test/diff/basics/Simplesub1.fun +++ b/shared/src/test/diff/basics/Simplesub1.fun @@ -220,14 +220,14 @@ x => {l: x x, r: x } //│ ║ l.+1: (f => (x => f (v => (x x) v)) (x => f (v => (x x) v))) (f => x => f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ res: error | 'a +//│ res: error | anything -> anything -> anything -> 'a //│ where -//│ 'a :> anything -> 'a +//│ 'a :> forall 'a. anything -> 'a res 1 2 -//│ res: error | 'a +//│ res: error | anything -> 'a //│ where -//│ 'a :> anything -> 'a +//│ 'a :> forall 'a. anything -> 'a let rec trutru = g => trutru (g true) @@ -359,30 +359,26 @@ x => (y => (x (y y))) //│ res: ('a -> 'b) -> ('c -> 'a & 'c) -> 'b (let rec x = (let y = (x x); (z => z)); x) -//│ res: 'x +//│ res: 'a -> 'a //│ where -//│ 'x :> 'a -> 'a -//│ 'a :> 'x +//│ 'a :> 'a -> 'a (let rec x = (y => (let z = (x x); y)); x) -//│ res: 'x +//│ res: 'a -> 'a //│ where -//│ 'x :> 'a -> 'a -//│ 'a :> 'x +//│ 'a :> 'a -> 'a (let rec x = (y => {u: y, v: (x x)}); x) -//│ res: 'x +//│ res: 'a -> 'b //│ where -//│ 'x :> 'a -> 'b +//│ 'a :> 'a -> 'b //│ 'b :> {u: 'a, v: 'b} -//│ 'a :> 'x (let rec x = (y => {u: (x x), v: y}); x) -//│ res: 'x +//│ res: 'a -> 'b //│ where -//│ 'x :> 'a -> 'b +//│ 'a :> 'a -> 'b //│ 'b :> {u: 'b, v: 'a} -//│ 'a :> 'x (let rec x = (y => (let z = (y x); y)); x) //│ res: 'x @@ -394,10 +390,9 @@ x => (y => (x (y y))) //│ res: ('v -> anything & {v: 'v}) -> 0 let rec x = (let y = (x x); (z => z)); (x (y => y.u)) // [test:T1] -//│ x: 'x +//│ x: 'a -> 'a //│ where -//│ 'x :> 'a -> 'a -//│ 'a :> 'x +//│ 'a :> 'a -> 'a //│ res: ({u: 'u} & 'a) -> ('u | 'a) | 'b //│ where //│ 'a :> forall 'u. ({u: 'u} & 'a) -> ('u | 'a) @@ -437,15 +432,15 @@ let rec x = (let y = (x x); (z => z)) (f => (x => f (v => (x x) v)) (x => f (v => (x x) v))) //│ res: ((forall 'a 'b. 'a -> 'b //│ where -//│ forall 'c 'd. 'd -> 'c +//│ forall 'c 'd. 'c -> 'd //│ where //│ 'e <: (forall 'f 'g. 'f -> 'g //│ where -//│ 'd <: 'd -> 'f -> 'g) -> 'c <: (forall 'c 'd. 'd -> 'c +//│ 'c <: 'c -> 'f -> 'g) -> 'd <: (forall 'c 'd. 'c -> 'd //│ where //│ 'e <: (forall 'f 'g. 'f -> 'g //│ where -//│ 'd <: 'd -> 'f -> 'g) -> 'c) -> 'a -> 'b) -> 'h & 'e) -> 'h +//│ 'c <: 'c -> 'f -> 'g) -> 'd) -> 'a -> 'b) -> 'h & 'e) -> 'h // * Function that takes arbitrarily many arguments: // :e // Works thanks to inconsistent constrained types... diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 5487ddca95..3e28fb8da9 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -205,12 +205,12 @@ mixin EvalNegNeg { :js module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang { -//│ fun eval: 'a -> Int +//│ fun eval: (Neg['A] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'a <: Neg['A] | Object & 'b & ~#Neg -//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit | Neg['a] +//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'b <: Neg['A] | Object & 'a & ~#Neg +//│ 'a <: Add['b] | Lit | Neg['b] //│ // Prelude //│ class TypingUnit5 { //│ #TestLang; @@ -239,10 +239,10 @@ fun mk(n) = if n is 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) TestLang.eval(mk(0)) -//│ fun mk: forall 'E. Object -> 'E +//│ fun mk: forall 'a. Object -> (Lit | 'a) //│ Int //│ where -//│ 'E :> Add['E] | Lit | Neg['E] +//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] //│ res //│ = 0 diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index b4f16d2cfa..88115a08ff 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -192,27 +192,27 @@ mixin EvalNegNeg { module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang { -//│ fun eval: 'a -> Int +//│ fun eval: (Neg['A] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'a <: Neg['A] | Object & 'b & ~#Neg -//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit | Neg['a] +//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'b <: Neg['A] | Object & 'a & ~#Neg +//│ 'a <: Add['b] | Lit | Neg['b] fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ fun mk: forall 'E. Object -> 'E +//│ fun mk: forall 'a. Object -> (Lit | 'a) //│ where -//│ 'E :> Add['E] | Lit | Neg['E] +//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] TestLang.eval -//│ 'a -> Int +//│ (Neg['A] | Object & 'a & ~#Neg) -> Int //│ where -//│ 'a <: Neg['A] | Object & 'b & ~#Neg -//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit | Neg['a] +//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'b <: Neg['A] | Object & 'a & ~#Neg +//│ 'a <: Add['b] | Lit | Neg['b] //│ res //│ = [Function: eval] diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 7729f38e32..8496e8efea 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -80,43 +80,48 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'A}] | Nil, Abs['b] | App['c] | Var) -> ('A | 'a) +//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, Abs['b] | App['c] | Var) -> 'a //│ } //│ where //│ 'b <: Abs['b] | App['c] | Var //│ 'c <: 'b & (Abs['b] | Object & ~#Abs) -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> Var | App['A] | Abs['A0] +//│ 'A0 :> 'a +//│ 'A :> 'a Test1.eval(Nil, Var("a")) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['A] | Abs['A0] | Var +//│ 'A0 :> 'a +//│ 'A :> 'a //│ res //│ = Var {} Test1.eval(Nil, Abs("b", Var("a"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> Var | App['A] | Abs['A0] +//│ 'A0 :> 'a +//│ 'A :> 'a //│ res //│ = Abs {} Test1.eval(Cons(["c", Var("d")], Nil), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['A] | Abs['A0] | Var +//│ 'A0 :> 'a +//│ 'A :> 'a //│ res //│ = Var {} Test1.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Abs[Var] | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['A] | Abs['A0] | Abs[Var] | Var +//│ 'A0 :> 'a +//│ 'A :> 'a //│ res //│ = Var {} @@ -177,16 +182,16 @@ Test2.eval(Cons(["a", Numb(1)], Nil), Var("a")) :e Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.178: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.183: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.178: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.183: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.131: if v is +//│ ║ l.136: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.141: let vv = map_expr(eta, v) +//│ ║ l.146: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Numb | Var | error //│ res @@ -200,63 +205,66 @@ Test2.eval(Cons(["a", Abs("d", Var("d"))], Nil), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: 'b}] | Nil, Abs['c] | App['d] | Object & 'e & ~#Abs & ~#App) -> ('A | 'a) +//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, Abs['b] | App['c] | Object & 'd & ~#Abs & ~#App) -> 'e //│ } //│ where -//│ 'b :> 'A +//│ 'a :> 'e //│ <: Object -//│ 'A :> 'a | Numb | Var | 'b | 'e -//│ 'e <: Add['c] | Mul['c] | Numb | Var -//│ 'c <: Abs['c] | App['d] | Object & 'e & ~#Abs & ~#App -//│ 'd <: 'c & (Abs['c] | Object & ~#Abs) -//│ 'a :> App['A] | Abs['A] +//│ 'e :> App['A] | Abs['A0] | Numb | Var | 'a | 'd +//│ 'd <: Add['b] | Mul['b] | Numb | Var +//│ 'b <: Abs['b] | App['c] | Object & 'd & ~#Abs & ~#App +//│ 'c <: 'b & (Abs['b] | Object & ~#Abs) +//│ 'A0 :> 'e +//│ 'A :> 'e Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Abs[Var] | Numb | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['A] | Abs['A0] | Abs[Var] | Numb | Var +//│ 'A0 :> 'a +//│ 'A :> 'a //│ res //│ = Abs {} Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Abs[Var] | Add[Numb | Var] | Numb | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['A] | Abs['A0] | Abs[Var] | Add[Numb | Var] | Numb | Var +//│ 'A0 :> 'a +//│ 'A :> 'a //│ res //│ = Var {} // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('A | 'a | 'b) +//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) //│ } //│ where -//│ 'a :> 'A | 'b +//│ 'a :> 'c | 'b //│ <: Object //│ 'b <: Add['b] | Mul['b] | Numb | Var -//│ 'A :> Numb | 'a | Abs['A] | App['A] | Var +//│ 'c :> Abs[Numb | 'a | 'c] | App[Numb | 'a | 'c] | Numb | Var | 'a // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.244: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.252: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.244: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.252: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.131: if v is +//│ ║ l.136: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.141: let vv = map_expr(eta, v) +//│ ║ l.146: let vv = map_expr(eta, v) //│ ╙── ^ -//│ error | 'A +//│ Abs[Var] | error | 'a //│ where -//│ 'A :> Abs[Var] | Numb | Abs['A] | App['A] | Var +//│ 'a :> Abs[Abs[Var] | Numb | 'a] | App[Abs[Var] | Numb | 'a] | Numb | Var //│ res //│ Runtime error: //│ Error: non-exhaustive case expression diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index 26fa71ee9f..d2b54c6799 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -47,15 +47,15 @@ fun go(x, offset) = else let shared = go(x - 1, round(offset / 2)) Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) -//│ fun go: forall 'Region. (0 | Int & ~0, Int) -> 'Region +//│ fun go: forall 'a. (0 | Int & ~0, Int) -> (Circle | 'a) //│ where -//│ 'Region :> Circle | Union[Translate['Region]] +//│ 'a :> Union[Translate[Circle | 'a]] // * Note that first-class polymorphism manages (correctly) to preserve the universal quantification let circles = go(2, 1024) -//│ let circles: forall 'Region. 'Region +//│ let circles: forall 'a. Circle | 'a //│ where -//│ 'Region :> Circle | Union[Translate['Region]] +//│ 'a :> Union[Translate[Circle | 'a]] //│ circles //│ = Union {} @@ -346,9 +346,9 @@ fun mk(n) = if n is 3 then Intersect(mk(n), mk(n)) 4 then Translate(Vector(0, 0), mk(n)) _ then Scale(Vector(0, 0), mk(n)) -//│ fun mk: forall 'Region. Object -> 'Region +//│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'Region :> Intersect['Region] | Outside['Region] | Scale['Region] | Translate['Region] | Union['Region] +//│ 'a :> Outside['a] | Scale['a] | Union['a] | Intersect['a] | Translate['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls index 897ba7fed9..30bde46679 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls @@ -44,15 +44,15 @@ fun go(x, offset) = else let shared = go(x - 1, round(offset / 2)) Union(Translate(Vector(0 - offset, 0), shared), Translate(Vector(offset, 0), shared)) -//│ fun go: forall 'Region. (0 | Int & ~0, Int) -> 'Region +//│ fun go: forall 'a. (0 | Int & ~0, Int) -> (Circle | 'a) //│ where -//│ 'Region :> Circle | Union[Translate['Region]] +//│ 'a :> Union[Translate[Circle | 'a]] // * Note that first-class polymorphism manages (correctly) to preserve the universal quantification let circles = go(2, 1024) -//│ let circles: forall 'Region. 'Region +//│ let circles: forall 'a. Circle | 'a //│ where -//│ 'Region :> Circle | Union[Translate['Region]] +//│ 'a :> Union[Translate[Circle | 'a]] //│ circles //│ = Union {} @@ -299,26 +299,23 @@ mixin Eliminate { module TestElim extends Eliminate //│ module TestElim { -//│ fun eliminate: forall 'a. 'b -> ('Region | 'a) +//│ fun eliminate: 'a -> 'b //│ } //│ where -//│ 'b <: Intersect['b] | Object & 'Region & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['b & (Object & ~#Outside | Outside['b])] | Scale['b] | Translate['b] | Union['b] -//│ 'Region :> 'a -//│ 'a :> Outside['Region] | Union['Region] | Intersect['Region] | Translate['Region] | Scale['Region] +//│ 'a <: Intersect['a] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a])] | Scale['a] | Translate['a] | Union['a] +//│ 'b :> Union['b] | Intersect['b] | Translate['b] | Scale['b] | Outside['b] TestElim.eliminate(Outside(Outside(Univ()))) -//│ forall 'a. 'Region | 'a +//│ 'a //│ where -//│ 'Region :> Univ | 'a -//│ 'a :> Outside['Region] | Union['Region] | Intersect['Region] | Translate['Region] | Scale['Region] +//│ 'a :> Univ | Intersect['a] | Translate[Univ | 'a] | Scale[Univ | 'a] | Outside[Univ | 'a] | Union[Univ | 'a] //│ res //│ = Univ {} TestElim.eliminate(circles) -//│ forall 'a. 'Region | 'a +//│ 'a //│ where -//│ 'Region :> Circle | 'a -//│ 'a :> Outside['Region] | Translate['Region] | Scale['Region] | Union['Region] | Intersect['Region] +//│ 'a :> Circle | Scale[Circle | 'a] | Outside[Circle | 'a] | Union[Circle | 'a] | Intersect['a] | Translate[Circle | 'a] //│ res //│ = Union {} @@ -328,13 +325,13 @@ fun mk(n) = if n is 3 then Intersect(mk(n), mk(n)) 4 then Translate(Vector(0, 0), mk(n)) _ then Scale(Vector(0, 0), mk(n)) -//│ fun mk: forall 'Region. Object -> 'Region +//│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'Region :> Intersect['Region] | Outside['Region] | Scale['Region] | Translate['Region] | Union['Region] +//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] :re TestElim.eliminate(mk(100)) -//│ forall 'a. 'a +//│ 'a //│ where //│ 'a :> Outside['a] | Union['a] | Intersect['a] | Translate['a] | Scale['a] //│ res @@ -346,22 +343,19 @@ TestElim.eliminate(mk(100)) module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminate //│ module Lang { //│ fun contains: ('a, {x: Int, y: Int}) -> Bool -//│ fun eliminate: forall 'b. 'c -> ('Region | 'b) +//│ fun eliminate: 'b -> 'c //│ fun isEmpty: 'd -> Bool //│ fun isUniv: 'e -> Bool //│ fun size: 'f -> Int -//│ fun text: 'g -> Str +//│ fun text: (Circle | Intersect['g] | Outside['g] | Translate['g] | Union['g]) -> Str //│ } //│ where -//│ 'g <: Circle | Intersect['h] | Outside['h] | Translate['h] | Union['h] -//│ 'h <: Empty | Object & 'g & ~#Empty & ~#Scale & ~#Univ | Scale['h] | Univ -//│ 'f <: Empty | Object & 'i & ~#Empty & ~#Scale & ~#Univ | Scale['f] | Univ -//│ 'i <: Circle | Intersect['f] | Outside['f] | Translate['f] | Union['f] +//│ 'g <: Empty | Object & (Circle | Intersect['g] | Outside['g] | Translate['g] | Union['g]) & ~#Empty & ~#Scale & ~#Univ | Scale['g] | Univ +//│ 'f <: Empty | Object & (Circle | Intersect['f] | Outside['f] | Translate['f] | Union['f]) & ~#Empty & ~#Scale & ~#Univ | Scale['f] | Univ //│ 'e <: Intersect['e] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['e] | Scale['e] | Translate['e] | Union['e] | Univ //│ 'd <: Intersect['d] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['d] | Scale['d] | Translate['d] | Union['d] | Univ -//│ 'c <: Intersect['c] | Object & 'Region & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['c & (Object & ~#Outside | Outside['c])] | Scale['c] | Translate['c] | Union['c] -//│ 'Region :> 'b -//│ 'b :> Outside['Region] | Union['Region] | Intersect['Region] | Translate['Region] | Scale['Region] +//│ 'b <: Intersect['b] | Object & 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['b & (Object & ~#Outside | Outside['b])] | Scale['b] | Translate['b] | Union['b] +//│ 'c :> Scale['c] | Outside['c] | Union['c] | Intersect['c] | Translate['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] Lang.size(circles) @@ -405,10 +399,10 @@ Lang.size(mk(100)) :re Lang.contains(mk(100), Vector(0, 0)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.406: Lang.contains(mk(100), Vector(0, 0)) +//│ ║ l.400: Lang.contains(mk(100), Vector(0, 0)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.330: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.327: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.113: if a is @@ -428,13 +422,13 @@ Lang.contains(mk(100), Vector(0, 0)) :re Lang.text(mk(100)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.429: Lang.text(mk(100)) +//│ ║ l.423: Lang.text(mk(100)) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Scale[?Region]` does not match type `Circle | Intersect[?Region0] | Outside[?Region1] | Translate[?Region2] | Union[?Region3]` -//│ ║ l.330: _ then Scale(Vector(0, 0), mk(n)) +//│ ║ l.327: _ then Scale(Vector(0, 0), mk(n)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into application with expected type `Circle | Intersect[?Region4] | Outside[?Region5] | Translate[?Region6] | Union[?Region7]` -//│ ║ l.429: Lang.text(mk(100)) +//│ ║ l.423: Lang.text(mk(100)) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.156: if e is diff --git a/shared/src/test/diff/fcp-lit/variations_PolyML.mls b/shared/src/test/diff/fcp-lit/variations_PolyML.mls index 64f6308d3d..9a971c8160 100644 --- a/shared/src/test/diff/fcp-lit/variations_PolyML.mls +++ b/shared/src/test/diff/fcp-lit/variations_PolyML.mls @@ -57,10 +57,10 @@ def simple_and_double c = let l1 = c.Fold (fun y -> fun x -> Cons x y) Nil in let l2 = c.Fold (fun y -> fun x -> Cons ((x, x),) y) Nil in (l1, l2) -//│ simple_and_double: Collection['a] -> (forall 'tail. 'tail, forall 'tail0. 'tail0,) +//│ simple_and_double: Collection['a] -> (forall 'b. Nil | 'b, forall 'c. Nil | 'c,) //│ where -//│ 'tail0 :> (Cons[('a, 'a,)] with {tail: 'tail0}) | Nil -//│ 'tail :> (Cons['a] with {tail: 'tail}) | Nil +//│ 'c :> Cons[('a, 'a,)] with {tail: forall 'c. Nil | 'c} +//│ 'b :> Cons['a] with {tail: forall 'b. Nil | 'b} diff --git a/shared/src/test/diff/fcp/Church_CT.mls b/shared/src/test/diff/fcp/Church_CT.mls index 1f279fcf2a..3ab215b05e 100644 --- a/shared/src/test/diff/fcp/Church_CT.mls +++ b/shared/src/test/diff/fcp/Church_CT.mls @@ -1088,8 +1088,8 @@ to_church_ty = to_ch_simplif //│ where //│ 'a :> forall 'b 'c 'd 'e. 'b -> ('c -> 'e //│ where -//│ 'a <: 'b -> 'c -> 'd -//│ 'b <: 'd -> 'e) +//│ 'b <: 'd -> 'e +//│ 'a <: 'b -> 'c -> 'd) //│ ╙── //│ anything -> 'a -> ('b -> 'c //│ where @@ -1102,7 +1102,7 @@ to_church_ty = to_ch_simplif //│ 'e <: 'f -> 'g -> 'h) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Cyclic-looking constraint while typing def definition; a type annotation may be required //│ ║ l.1086: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -1113,20 +1113,20 @@ to_church_ty = to_ch_simplif rec def to_ch_simplif n = s (to_ch_simplif n) //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a :> forall 'b 'c 'd 'e. 'b -> ('c -> 'e +//│ 'a :> forall 'b 'c 'd 'e. 'c -> ('d -> 'b //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd) +//│ 'a <: 'c -> 'd -> 'e +//│ 'c <: 'e -> 'b) //│ ╙── //│ to_ch_simplif: anything -> 'a -> ('b -> 'c //│ where -//│ 'd <: 'a -> 'b -> 'e -//│ 'a <: 'e -> 'c) +//│ 'a <: 'd -> 'c +//│ 'e <: 'a -> 'b -> 'd) //│ where -//│ 'd :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i //│ where //│ 'f <: 'h -> 'i -//│ 'd <: 'f -> 'g -> 'h) +//│ 'e <: 'f -> 'g -> 'h) //│ = [Function: to_ch_simplif1] :e // * Since the removal of "recursive definition hacks" @@ -1135,21 +1135,21 @@ to_church_ty = to_ch_simplif //│ where //│ 'a :> forall 'b 'c 'd 'e. 'b -> ('c -> 'e //│ where -//│ 'b <: 'd -> 'e -//│ 'a <: 'b -> 'c -> 'd) +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'd -> 'e) //│ ╙── //│ anything -> 'a -> ('b -> 'c //│ where //│ 'a <: 'd -> 'c //│ 'e <: 'a -> 'b -> 'd) //│ where -//│ 'e :> forall 'f 'g 'h 'i. 'g -> ('h -> 'f +//│ 'e :> forall 'f 'g 'h 'i. 'f -> ('g -> 'i //│ where -//│ 'g <: 'i -> 'f -//│ 'e <: 'g -> 'h -> 'i) +//│ 'f <: 'h -> 'i +//│ 'e <: 'f -> 'g -> 'h) //│ <: to_church_ty: //│ int -> ChurchInt -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?to_ch_simplif. ?to_ch_simplif <: int -> ChurchInt` exceeded recursion depth limit (250) +//│ ╔══[ERROR] Cyclic-looking constraint while typing def definition; a type annotation may be required //│ ║ l.1133: to_church_ty = to_ch_simplif //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. @@ -1160,19 +1160,19 @@ to_church_ty = to_ch_simplif to_church_ty = to_ch_A1 //│ ╔══[ERROR] Inferred recursive type: 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. (? & 'e) -> (('a & 'c) -> ('c | 'd) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. (? & 'd) -> (('e & 'c) -> ('c | 'b) //│ where -//│ ChurchInt <: 'e -> 'a -> 'b -//│ 'e <: 'b -> 'd)) +//│ 'd <: 'a -> 'b +//│ ChurchInt <: 'd -> 'e -> 'a)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ ╙── //│ 'to_ch_A1 //│ where -//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. 'd -> (('c & 'a) -> ('a | 'b) +//│ 'to_ch_A1 :> forall 'to_ch_A1. int -> (forall 'a 'b 'c 'd 'e. 'd -> (('e & 'b) -> ('b | 'c) //│ where -//│ 'd <: 'e -> 'b -//│ ChurchInt <: 'd -> 'c -> 'e)) +//│ ChurchInt <: 'd -> 'e -> 'a +//│ 'd <: 'a -> 'c)) //│ where //│ 'to_ch_A1 <: int -> ChurchInt //│ <: to_church_ty: @@ -1187,8 +1187,8 @@ to_church_ty = to_ch_A1 to_church_ty = to_church_mix //│ int -> 'a -> ('b -> ('b | 'c) //│ where -//│ 'a <: 'd -> 'c -//│ ChurchInt <: 'a -> 'b -> 'd) +//│ ChurchInt <: 'a -> 'b -> 'd +//│ 'a <: 'd -> 'c) //│ <: to_church_ty: //│ int -> ChurchInt //│ = [Function: to_church_mix] diff --git a/shared/src/test/diff/fcp/FunnyId.mls b/shared/src/test/diff/fcp/FunnyId.mls index 0a5dcc5145..9558b97672 100644 --- a/shared/src/test/diff/fcp/FunnyId.mls +++ b/shared/src/test/diff/fcp/FunnyId.mls @@ -35,10 +35,9 @@ rec def id x = let tmp = id id x in x //│ <: ? & 'a //│ ║ l.30: rec def id x = let tmp = id id x in x //│ ╙── ^^^^^ -//│ id: 'id +//│ id: 'a -> 'a //│ where -//│ 'id :> 'a -> 'a -//│ 'a :> 'id +//│ 'a :> 'a -> 'a //│ <: 'a -> anything //│ = [Function: id1] @@ -53,10 +52,10 @@ id 1 //│ ║ l.30: rec def id x = let tmp = id id x in x //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.47: id 1 +//│ ║ l.46: id 1 //│ ║ ^^^^ //│ ╟── integer literal of type `1` is not a function -//│ ║ l.47: id 1 +//│ ║ l.46: id 1 //│ ║ ^ //│ ╟── Note: constraint arises from application: //│ ║ l.30: rec def id x = let tmp = id id x in x @@ -80,15 +79,14 @@ id_ty = id //│ <: ? & 'a //│ ║ l.30: rec def id x = let tmp = id id x in x //│ ╙── ^^^^^ -//│ 'id +//│ 'a -> 'a //│ where -//│ 'id :> 'a -> 'a -//│ 'a :> 'id +//│ 'a :> 'a -> 'a //│ <: 'a -> anything //│ <: id_ty: //│ 'a -> 'a //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.75: id_ty = id +//│ ║ l.74: id_ty = id //│ ║ ^^^^^^^^^^ //│ ╟── type `'a` is not a function //│ ║ l.4: def id_ty: forall 'a. 'a -> 'a @@ -133,19 +131,17 @@ rec def id x = if true then x else id id x //│ <: 'c //│ 'c :> 'b -> 'c //│ <: 'a -//│ ║ l.128: rec def id x = if true then x else id id x +//│ ║ l.126: rec def id x = if true then x else id id x //│ ╙── ^^^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.128: rec def id x = if true then x else id id x +//│ ║ l.126: rec def id x = if true then x else id id x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ id: 'id +//│ id: 'a -> 'b //│ where -//│ 'id :> 'a -> 'b -//│ 'a :> 'id +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id3] :e @@ -157,28 +153,26 @@ id_ty = id //│ 'c :> 'a | 'c -> 'b //│ <: 'a //│ 'a <: 'b -//│ ║ l.128: rec def id x = if true then x else id id x +//│ ║ l.126: rec def id x = if true then x else id id x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ 'id +//│ 'a -> 'b //│ where -//│ 'id :> 'a -> 'b -//│ 'a :> 'id +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ <: id_ty: //│ 'a -> 'a //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.152: id_ty = id +//│ ║ l.148: id_ty = id //│ ║ ^^^^^^^^^^ //│ ╟── type `'a` is not a function //│ ║ l.4: def id_ty: forall 'a. 'a -> 'a //│ ║ ^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.128: rec def id x = if true then x else id id x +//│ ║ l.126: rec def id x = if true then x else id id x //│ ║ ^^^^^^^ //│ ╟── from reference: -//│ ║ l.128: rec def id x = if true then x else id id x +//│ ║ l.126: rec def id x = if true then x else id id x //│ ║ ^ //│ ╟── Note: quantified type variable 'a is defined at: //│ ║ l.4: def id_ty: forall 'a. 'a -> 'a @@ -195,47 +189,35 @@ def choose: 'a -> 'a -> 'a //│ choose: 'a -> 'a -> 'a rec def id1 x = choose x (id1 id1 x) -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b id1 id -//│ res: 'a -> 'b | 'id +//│ res: ('a & 'b) -> 'a //│ where -//│ 'a :> forall 'id 'c 'd. 'a -> 'b | 'id -//│ <: 'b -//│ 'b :> forall 'id 'c 'd. 'id -//│ <: 'a -> 'b -//│ 'id :> 'c -> 'd -//│ 'c :> 'id -//│ <: 'd -//│ 'd :> 'id -//│ <: 'c -> 'd +//│ 'a :> forall 'c 'd. ('a & 'b & 'd) -> 'a +//│ <: ((forall 'c 'd. 'd -> 'c) | 'b) -> 'a +//│ 'd :> 'd -> 'c +//│ <: 'c +//│ 'c := 'd -> 'c rec def id1 x = if true then x else id1 id1 x -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b id1 id -//│ res: 'a -> 'b | 'id +//│ res: ('a & 'b) -> 'a //│ where -//│ 'a :> forall 'id 'c 'd. 'a -> 'b | 'id -//│ <: 'b -//│ 'b :> forall 'id 'c 'd. 'id -//│ <: 'a -> 'b -//│ 'id :> 'c -> 'd -//│ 'c :> 'id +//│ 'a :> forall 'c 'd. ('a & 'b & 'c) -> 'a +//│ <: ((forall 'c 'd. 'c -> 'd) | 'b) -> 'a +//│ 'c :> 'c -> 'd //│ <: 'd -//│ 'd :> 'id -//│ <: 'c -> 'd +//│ 'd := 'c -> 'd diff --git a/shared/src/test/diff/fcp/ListBuild.mls b/shared/src/test/diff/fcp/ListBuild.mls index 2d68dfb39a..1dfe4f4548 100644 --- a/shared/src/test/diff/fcp/ListBuild.mls +++ b/shared/src/test/diff/fcp/ListBuild.mls @@ -70,15 +70,16 @@ def build0 (g: forall 'b. ('a -> 'a -> 'b) -> 'b) = g (fun x -> fun y -> single( //│ = //│ single is not implemented -:e // * This is recursive because we place the list-typed value inside a new list along with the head +:e // * This is recursive because we place the list-typed value inside a new list along with the head. def build0 (g: forall 'b. ('a -> 'b -> 'b) -> 'b) = g (fun x -> fun y -> single((x, y))) //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a :> Ls[(?, 'a,)] -//│ ╙── +//│ 'a :> Ls[(?, forall 'a. 'a,)] +//│ ║ l.74: def build0 (g: forall 'b. ('a -> 'b -> 'b) -> 'b) = g (fun x -> fun y -> single((x, y))) +//│ ╙── ^^^^^^^^^^^^^^ //│ build0: (forall 'b. ('a -> 'b -> 'b) -> 'b) -> 'c //│ where -//│ 'c :> Ls[('a, 'c,)] +//│ 'c :> Ls[('a, forall 'c. 'c,)] //│ = //│ single is not implemented @@ -184,13 +185,13 @@ build: forall 'a. (forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> Ls['a] :e build: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.185: build: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] +//│ ║ l.186: build: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] //│ ║ ^^^^^ //│ ╟── type `Ls['a]` does not match type `'b` -//│ ║ l.185: build: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] +//│ ║ l.186: build: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.142: def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> cons (x, xs)) nil +//│ ║ l.143: def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> cons (x, xs)) nil //│ ╙── ^^ //│ res: (('a -> Ls['a] -> Ls['a]) -> Ls['a] -> Ls['a]) -> Ls['a] //│ = [Function: build] @@ -264,16 +265,16 @@ b g x = build_ g x //│ <: b: //│ (forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> Ls['a] //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.262: b g x = build_ g x +//│ ║ l.263: b g x = build_ g x //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type `Ls['a]` is not a function //│ ║ l.22: def nil: Ls['a] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.262: b g x = build_ g x +//│ ║ l.263: b g x = build_ g x //│ ║ ^^^^^^^^^^ //│ ╟── from application: -//│ ║ l.203: def build_ = fun g -> g (fun x -> fun xs -> cons (x, xs)) nil +//│ ║ l.204: def build_ = fun g -> g (fun x -> fun xs -> cons (x, xs)) nil //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ = [Function: b3] diff --git a/shared/src/test/diff/fcp/NestedDataTypes.mls b/shared/src/test/diff/fcp/NestedDataTypes.mls index 402062b150..65fbaf1062 100644 --- a/shared/src/test/diff/fcp/NestedDataTypes.mls +++ b/shared/src/test/diff/fcp/NestedDataTypes.mls @@ -220,9 +220,11 @@ rec def map f tree = case tree of { //│ ║ l.67: } //│ ║ ^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ map: ('value -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'value0) & 'a -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'b & 'A) & 'c -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'd & 'A) & 'e -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'f & 'A) & 'g -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'h & 'A)) -> 'i -> 'subTree +//│ map: ('value -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'value0) & 'a -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'b & 'A) & 'c -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'd & 'A) & 'e -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'f & 'A) & 'g -> (Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two[Two['A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'A] & 'h & 'A)) -> 'i -> (Leaf[((nothing, (nothing, nothing,) | 'd,) | 'b, ((nothing, nothing,) | 'h, nothing,) | 'f,) | 'value0] | 'j) //│ where -//│ 'subTree :> Leaf[((nothing, (nothing, nothing,) | 'd,) | 'b, ((nothing, nothing,) | 'h, nothing,) | 'f,) | 'value0] | (Node['A] with {subTree: 'subTree}) +//│ 'j :> Node['A] with { +//│ subTree: Leaf[((nothing, (nothing, nothing,) | 'd,) | 'b, ((nothing, nothing,) | 'h, nothing,) | 'f,) | 'value0] | 'j +//│ } //│ 'i <: Leaf[?] & { //│ value: ((anything, (anything, anything,) & 'c,) & 'a, ((anything, anything,) & 'g, anything,) & 'e,) & 'value //│ } | (Node[?] with {subTree: 'i}) @@ -259,15 +261,15 @@ rec def map f tree = case tree of { map succ n4 //│ ╔══[ERROR] Inferred recursive type: 'map //│ where -//│ 'map :> forall 'A 'subTree 'value 'subTree0 'a 'value0. 'a -> ((Leaf[?] & {value: 'value} | (Node[?] with {subTree: 'subTree0})) -> (Leaf['value0] | (Node['A] with {subTree: 'subTree})) +//│ 'map :> forall 'value 'value0 'subTree 'A 'subTree0. 'a -> ((Leaf[?] & {value: 'value0} | (Node[?] with {subTree: 'subTree})) -> (Leaf['value] | (Node['A] with {subTree: 'subTree0})) //│ where //│ 'map <: (forall 'b 'c 'd 'e. (('b, 'd,),) -> ('c, 'e,) //│ where -//│ 'a <: 'b -> 'c & 'd -> 'e) -> 'subTree0 -> (PerfectTree[Two['A]] & 'subTree) -//│ 'a <: 'value -> 'value0) +//│ 'a <: 'b -> 'c & 'd -> 'e) -> 'subTree -> (PerfectTree[Two['A]] & 'subTree0) +//│ 'a <: 'value0 -> 'value) //│ ╙── -//│ ╔══[ERROR] Subtyping constraint of the form `?a <: (forall ?b. ?b) -> ?c` exceeded recursion depth limit (250) -//│ ║ l.259: map succ n4 +//│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required +//│ ║ l.261: map succ n4 //│ ║ ^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error diff --git a/shared/src/test/diff/fcp/NoRecursiveTypes.mls b/shared/src/test/diff/fcp/NoRecursiveTypes.mls new file mode 100644 index 0000000000..1775cd71d8 --- /dev/null +++ b/shared/src/test/diff/fcp/NoRecursiveTypes.mls @@ -0,0 +1,15 @@ +:NoRecursiveTypes + + +:e +foo = + let rec f x = f x.a in 0 +//│ ╔══[ERROR] Inferred recursive type: 'a +//│ where +//│ 'a <: {a: 'a} +//│ ║ l.6: let rec f x = f x.a in 0 +//│ ╙── ^^^ +//│ foo: 0 +//│ = 0 + + diff --git a/shared/src/test/diff/fcp/OCamlList.mls b/shared/src/test/diff/fcp/OCamlList.mls index 23cf1512cc..04f1c9b7da 100644 --- a/shared/src/test/diff/fcp/OCamlList.mls +++ b/shared/src/test/diff/fcp/OCamlList.mls @@ -714,9 +714,7 @@ def concat_map = let rec r = { | Nil -> r.concat_map f xs | Cons(y, ys) -> r.prepend_concat_map ys f xs } in r.concat_map -//│ ('A -> List[?]) -> List['A] -> 'a -//│ where -//│ 'a :> List[nothing] +//│ ('A -> List[?]) -> List['A] -> (List[nothing] | 'a) //│ <: concat_map: //│ ('a -> List['b]) -> List['a] -> List['b] diff --git a/shared/src/test/diff/fcp/PaperTable.mls b/shared/src/test/diff/fcp/PaperTable.mls index 14fe4909b6..f7306471b1 100644 --- a/shared/src/test/diff/fcp/PaperTable.mls +++ b/shared/src/test/diff/fcp/PaperTable.mls @@ -612,13 +612,11 @@ rec def id1 x = if true then x else id1 id1 x //│ ║ l.601: rec def id1 x = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id11] :e @@ -667,7 +665,7 @@ id1 id1 //│ ║ l.601: rec def id1 x = if true then x else id1 id1 x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Subtyping constraint of the form `forall ?id1. ?id1 <: (forall ?id10. ?id10) -> ?a` exceeded recursion depth limit (250) -//│ ║ l.626: id1 id1 +//│ ║ l.624: id1 id1 //│ ║ ^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error @@ -677,7 +675,7 @@ id1 id1 :e auto auto //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.678: auto auto +//│ ║ l.676: auto auto //│ ║ ^^^^^^^^^ //│ ╟── type `'a` is not a function //│ ║ l.163: def auto : (forall 'a. 'a -> 'a) -> (forall 'b. 'b -> 'b) @@ -696,7 +694,7 @@ auto auto :e (fun x -> x x) (fun x -> x x) //│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d. ?c -> ?d) -> ?e` exceeded recursion depth limit (250) -//│ ║ l.697: (fun x -> x x) (fun x -> x x) +//│ ║ l.695: (fun x -> x x) (fun x -> x x) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error @@ -1010,19 +1008,17 @@ rec def id1 x = if true then x else id1 id1 x //│ <: 'c //│ 'c :> 'b -> 'c //│ <: 'a -//│ ║ l.1005: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.1003: rec def id1 x = if true then x else id1 id1 x //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: ?id1` exceeded recursion depth limit (250) -//│ ║ l.1005: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.1003: rec def id1 x = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id12] :e @@ -1068,10 +1064,10 @@ id1 id1 //│ 'b :> 'b -> 'c //│ <: 'c //│ 'c := 'b -> 'c -//│ ║ l.1005: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.1003: rec def id1 x = if true then x else id1 id1 x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Subtyping constraint of the form `forall ?id1. ?id1 <: (forall ?id10. ?id10) -> ?a` exceeded recursion depth limit (250) -//│ ║ l.1030: id1 id1 +//│ ║ l.1026: id1 id1 //│ ║ ^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error @@ -1081,7 +1077,7 @@ id1 id1 :e auto auto //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.1082: auto auto +//│ ║ l.1078: auto auto //│ ║ ^^^^^^^^^ //│ ╟── type `'a` is not a function //│ ║ l.163: def auto : (forall 'a. 'a -> 'a) -> (forall 'b. 'b -> 'b) @@ -1100,7 +1096,7 @@ auto auto :e (fun x -> x x) (fun x -> x x) //│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: (forall ?c ?d. ?c -> ?d) -> ?e` exceeded recursion depth limit (250) -//│ ║ l.1101: (fun x -> x x) (fun x -> x x) +//│ ║ l.1097: (fun x -> x x) (fun x -> x x) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error @@ -1414,19 +1410,17 @@ rec def id1 x = if true then x else id1 id1 x //│ <: 'c //│ 'c :> 'b -> 'c //│ <: 'a -//│ ║ l.1409: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.1405: rec def id1 x = if true then x else id1 id1 x //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.1409: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.1405: rec def id1 x = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id13] :e @@ -1449,10 +1443,10 @@ id1 id1 //│ 'b :> 'b -> 'c //│ <: 'c //│ 'c := 'b -> 'c -//│ ║ l.1409: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.1405: rec def id1 x = if true then x else id1 id1 x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1434: id1 id1 +//│ ║ l.1428: id1 id1 //│ ║ ^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error @@ -1462,7 +1456,7 @@ id1 id1 :e auto auto //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.1463: auto auto +//│ ║ l.1457: auto auto //│ ║ ^^^^^^^^^ //│ ╟── type `'a` is not a function //│ ║ l.163: def auto : (forall 'a. 'a -> 'a) -> (forall 'b. 'b -> 'b) @@ -1481,7 +1475,7 @@ auto auto :e (fun x -> x x) (fun x -> x x) //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1482: (fun x -> x x) (fun x -> x x) +//│ ║ l.1476: (fun x -> x x) (fun x -> x x) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error @@ -1787,35 +1781,29 @@ to_ch: int -> ChurchInt // G8 rec def id1 x = if true then x else id1 id1 x -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id14] // G9 id1 id1 -//│ res: 'a -> 'b | 'id1 +//│ res: ('a & 'b) -> 'a //│ where -//│ 'a :> forall 'id1 'c 'd. 'a -> 'b | 'id1 -//│ <: 'b -//│ 'b :> forall 'id1 'c 'd. 'id1 -//│ <: 'a -> 'b -//│ 'id1 :> 'c -> 'd -//│ 'c :> 'id1 +//│ 'a :> forall 'c 'd. ('a & 'b & 'c) -> ('a | 'd) +//│ <: ((forall 'c 'd. 'c -> 'd) | 'b) -> 'a +//│ 'c :> 'c -> 'd //│ <: 'd -//│ 'd :> 'id1 -//│ <: 'c -> 'd +//│ 'd := 'c -> 'd //│ = [Function: id14] // Gn :e auto auto //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.1816: auto auto +//│ ║ l.1804: auto auto //│ ║ ^^^^^^^^^ //│ ╟── type `'a` is not a function //│ ║ l.163: def auto : (forall 'a. 'a -> 'a) -> (forall 'b. 'b -> 'b) @@ -1834,7 +1822,7 @@ auto auto :e (fun x -> x x) (fun x -> x x) //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1835: (fun x -> x x) (fun x -> x x) +//│ ║ l.1823: (fun x -> x x) (fun x -> x x) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error diff --git a/shared/src/test/diff/fcp/QML_exist_Records_ND.mls b/shared/src/test/diff/fcp/QML_exist_Records_ND.mls index 34a93be3fa..dd130a67e7 100644 --- a/shared/src/test/diff/fcp/QML_exist_Records_ND.mls +++ b/shared/src/test/diff/fcp/QML_exist_Records_ND.mls @@ -177,17 +177,22 @@ def helper (impl: ArraysImpl['a, 'rep]) (k: ArraysImplConsumer['b, 'res]) = k (s // * FIXME this works with `:Fuel 4000000` but takes ~10s!! // * Why require so much fuel? (notably, more than in the same `helper` but *without* the impl annot) // * -> probably due to 'b being generalized too early +// * Note [2023-10-06]: +// * It seems the fuel might be needed because of TV reconstraining after extrusion, +// * which is currently implemented in a very naive and wasteful way! +// * Indeed, if we set (includeBounds = true) in the `getVars` method, +// * which is used for reconstraining, then this no longer require extra fuel! :e def step (arr: Arrays['a]) = arr helper //│ Arrays['a] -> error //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Subtyping constraint of the form `Arrays['a] <: (forall 'a0 'rep. ArraysImpl['a0, 'rep] -> (forall ?a 'res 'b. ArraysImplConsumer['b, 'res] -> ?a)) -> ?b` took too many steps and ran out of fuel (10000) -//│ ║ l.181: def step (arr: Arrays['a]) = arr helper +//│ ║ l.186: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Subtyping constraint of the form `forall 'a ?a. Arrays['a] -> ?a <: forall 'a0. Arrays['a0] -> Arrays['a0]` took too many steps and ran out of fuel (10000) -//│ ║ l.181: def step (arr: Arrays['a]) = arr helper +//│ ║ l.186: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ = [Function: step3] @@ -248,39 +253,39 @@ def step (arr: Arrays['a]) = arr helper //│ <: step: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in application -//│ ║ l.235: def step (arr: Arrays['a]) = arr helper +//│ ║ l.240: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.19: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this function: -//│ ║ l.225: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) +//│ ║ l.230: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.235: def step (arr: Arrays['a]) = arr helper +//│ ║ l.240: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^ //│ ╟── • this reference: -//│ ║ l.235: def step (arr: Arrays['a]) = arr helper +//│ ║ l.240: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^ //│ ╟── Note: constraint arises from type variable: //│ ║ l.93: def stepImpl (arrImpl: ArraysImpl['a, 'r]) = { //│ ╙── ^^ //│ ╔══[ERROR] Type error in def definition -//│ ║ l.235: def step (arr: Arrays['a]) = arr helper +//│ ║ l.240: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.19: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this function: -//│ ║ l.225: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) +//│ ║ l.230: def helper (impl: ArraysImpl['a, 'rep]) k = k (stepImpl impl) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── • this reference: -//│ ║ l.235: def step (arr: Arrays['a]) = arr helper +//│ ║ l.240: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^^^^ //│ ╟── • this reference: -//│ ║ l.235: def step (arr: Arrays['a]) = arr helper +//│ ║ l.240: def step (arr: Arrays['a]) = arr helper //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.95: sub = fun ((r0, r1)) -> fun i -> arrImpl.sub r0 i; @@ -531,17 +536,17 @@ def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (ste //│ <: step2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.529: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.534: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'rep` leaks out of its scope //│ ║ l.19: type ArraysImplConsumer[A, R] = forall 'rep. ArraysImpl[A, 'rep] -> R //│ ║ ^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.529: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.534: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^ //│ ╟── • this reference: -//│ ║ l.529: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.534: def step2 = forall 'a. fun (arr: Arrays['a]) -> fun k -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^ //│ ╟── Note: constraint arises from type variable: //│ ║ l.88: def stepImpl_ty: ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] @@ -556,7 +561,7 @@ def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr ( //│ <: step2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.552: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.557: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'r` leaks out of its scope //│ ║ l.22: type Arrays[A] = forall 'r. ArraysImplConsumer[A, 'r] -> 'r @@ -566,7 +571,7 @@ def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr ( //│ ║ ^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this application: -//│ ║ l.552: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.557: def step2 = forall 'a. fun arr -> fun (k: ArraysImplConsumer['a, 'rep]) -> arr (fun impl -> k (stepImpl_ty impl)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ = [Function: step26] @@ -600,7 +605,7 @@ step2 = s //│ <: step2: //│ Arrays['a] -> Arrays['a] //│ ╔══[ERROR] Type error in def definition -//│ ║ l.598: step2 = s +//│ ║ l.603: step2 = s //│ ║ ^^^^^^^^^ //│ ╟── type variable `'r` leaks out of its scope //│ ║ l.22: type Arrays[A] = forall 'r. ArraysImplConsumer[A, 'r] -> 'r @@ -610,10 +615,10 @@ step2 = s //│ ║ ^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this reference: -//│ ║ l.598: step2 = s +//│ ║ l.603: step2 = s //│ ║ ^ //│ ╟── • this application: -//│ ║ l.575: def s arr (k: ArraysImplConsumer['a, 'rep]) = arr (fun impl -> k (stepImpl_ty impl)) +//│ ║ l.580: def s arr (k: ArraysImplConsumer['a, 'rep]) = arr (fun impl -> k (stepImpl_ty impl)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ = [Function: s] diff --git a/shared/src/test/diff/fcp/SystemF.mls b/shared/src/test/diff/fcp/SystemF.mls index 720eff2952..903f7b261a 100644 --- a/shared/src/test/diff/fcp/SystemF.mls +++ b/shared/src/test/diff/fcp/SystemF.mls @@ -399,7 +399,7 @@ E q = q id // shallow (not (not true)) -- Shallow encoding. // λid.id(λb t f.b f t)(id(λb t f.b f t)(λx y.x)) sh id = (id not) ((id not) tru) -//│ sh: ((forall 'a 'b 'c. ('a -> 'b -> 'c) -> 'b -> 'a -> 'c) -> ('d -> 'e & (forall 'f. 'f -> anything -> 'f) -> 'd)) -> 'e +//│ sh: ((forall 'a 'b 'c. ('b -> 'c -> 'a) -> 'c -> 'b -> 'a) -> ('d -> 'e & (forall 'f. 'f -> anything -> 'f) -> 'd)) -> 'e //│ = [Function: sh] // E[forall X.X->X->X](shallow (not( not true))) diff --git a/shared/src/test/diff/fcp/SystemF_2.mls b/shared/src/test/diff/fcp/SystemF_2.mls index 932b3da42d..7246a3e9b2 100644 --- a/shared/src/test/diff/fcp/SystemF_2.mls +++ b/shared/src/test/diff/fcp/SystemF_2.mls @@ -40,10 +40,10 @@ iter2 iter2 K //│ where //│ 'a :> ? -> ? -> 'a //│ ╙── -//│ res: 'a -> 'b +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> 'b -//│ 'b :> anything -> anything -> 'a +//│ 'a :> anything -> 'b +//│ 'b :> anything -> 'a //│ = [Function (anonymous)] iter2 iter2 iter2 @@ -128,7 +128,7 @@ c2_ c2_ K //│ ╔══[ERROR] Inferred recursive type: 'a //│ where //│ 'a :> ? -> ('a | 'b | 'c | 'd) -//│ 'c :> ? -> ('b | 'd) | 'd +//│ 'c :> ? -> ('b | 'c | 'd) //│ 'd :> ? -> ('b | 'c) //│ 'b :> ? -> ('a | 'b) //│ ╙── @@ -154,10 +154,10 @@ c2__ c2__ K //│ where //│ 'a :> ? -> ? -> 'a //│ ╙── -//│ res: 'a -> 'b +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> 'b -//│ 'b :> anything -> anything -> 'a +//│ 'a :> anything -> 'b +//│ 'b :> anything -> 'a //│ = [Function (anonymous)] @@ -165,36 +165,36 @@ c2__ c2__ K :RecursiveTypes iter2 iter2 K -//│ res: 'a -> 'b +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> 'b -//│ 'b :> anything -> anything -> 'a +//│ 'a :> anything -> 'b +//│ 'b :> anything -> 'a //│ = [Function (anonymous)] res id -//│ res: 'a +//│ res: anything -> 'a //│ where -//│ 'a :> forall 'b. anything -> anything -> ('b -> 'b | 'a) +//│ 'a :> forall 'b. anything -> 'b -> ('a | 'b) //│ = [Function (anonymous)] r1 = res id id id id id -//│ r1: 'a -> 'a | 'b +//│ r1: 'a -> ('b | 'a) //│ where -//│ 'b :> forall 'c. anything -> 'c -> ('b | 'c) +//│ 'b :> forall 'c. 'c -> (anything -> 'b | 'c) //│ = [Function: id] r1 iter2 iter2 K -//│ res: ('a & 'b & 'c) -> (anything -> anything -> 'b | 'd | 'c | 'e) +//│ res: ('a & 'b & 'c) -> (anything -> (anything -> 'b | 'd) | 'e | 'c) //│ where -//│ 'd :> forall 'f. anything -> 'f -> ('d | 'f) -//│ 'a :> 'e -//│ 'e :> anything -> anything -> 'a +//│ 'e :> forall 'f. anything -> 'f -> ('e | 'f) +//│ 'a :> anything -> 'd +//│ 'd :> anything -> 'a //│ = [Function (anonymous)] r = r1 iter2 iter2 -//│ r: ('a -> 'b & 'b -> 'c & 'd -> 'e & 'e -> ('d & 'f)) -> ('a & 'd) -> ('c | 'f) | 'g +//│ r: ('a -> 'b & 'b -> 'c & 'd -> 'e & 'e -> ('d & 'f)) -> (('a & 'd) -> ('c | 'f) | 'g) //│ where -//│ 'g :> forall 'h. anything -> 'h -> ('g | 'h) +//│ 'g :> forall 'h. 'h -> (anything -> 'g | 'h) //│ = [Function (anonymous)] r iter2 @@ -229,17 +229,17 @@ iter2 f x = f(f x) iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'e -> 'd //│ where -//│ 'c <: 'd -> 'e & 'e -> 'f) <: 'a -> 'g & 'g -> 'b +//│ 'c <: 'e -> 'f & 'f -> 'd) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] id iter2 iter2 //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'e -> 'd +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where -//│ 'c <: 'e -> 'f & 'f -> 'd) <: 'a -> 'g & 'g -> 'b +//│ 'c <: 'd -> 'e & 'e -> 'f) <: 'a -> 'g & 'g -> 'b //│ = [Function (anonymous)] @@ -334,10 +334,10 @@ c2 c2 K c2_ = succ_ (succ_ n0) //│ c2_: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'h -> 'g //│ where -//│ 'e <: 'g -> 'h -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'f -> 'g) <: 'a -> 'b -> 'c +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'e -> 'h -> 'f +//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c //│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] @@ -347,20 +347,20 @@ c2_ c2_ //│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where //│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f) <: (forall 'g. 'g -> (forall 'h 'i 'j. 'j -> 'i +//│ 'c <: 'e -> 'f) <: (forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where -//│ 'g <: 'h -> 'i +//│ 'g <: 'i -> 'j //│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n //│ where -//│ 'k <: 'm -> 'n -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm) <: 'g -> 'j -> 'h)) -> 'a -> 'o -//│ forall 'g. 'g -> (forall 'h 'i 'j. 'j -> 'i +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm +//│ 'k <: 'm -> 'n) <: 'g -> 'h -> 'i)) -> 'a -> 'o +//│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where -//│ 'g <: 'h -> 'i +//│ 'g <: 'i -> 'j //│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n //│ where -//│ 'k <: 'm -> 'n -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm) <: 'g -> 'j -> 'h) <: 'o -> 'b +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm +//│ 'k <: 'm -> 'n) <: 'g -> 'h -> 'i) <: 'o -> 'b //│ = [Function (anonymous)] :e @@ -370,70 +370,70 @@ c2_ c2_ K //│ 'a :> forall 'b 'c 'd 'e. ('b & 'e) -> (? -> 'e | 'd) //│ where //│ 'a <: 'c -> 'd -//│ forall 'f. 'f -> (forall 'g 'h 'i. 'g -> 'i +//│ forall 'f. 'f -> (forall 'g 'h 'i. 'i -> 'h //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'g -> 'h -//│ 'f <: 'h -> 'i) <: 'a -> 'b -> 'c +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'f -> 'i -> 'g +//│ 'f <: 'g -> 'h) <: 'a -> 'b -> 'c //│ ╙── //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'f -> 'e +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'c -> 'f -> 'd -//│ 'c <: 'd -> 'e) <: (forall 'g 'h 'i. 'i -> 'h +//│ 'c <: 'e -> 'f +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'c -> 'd -> 'e) <: (forall 'g 'h 'i. 'g -> 'i //│ where -//│ 'j <: 'g -> 'h -//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n +//│ forall 'j. 'j -> (forall 'k 'l 'm. 'k -> 'm //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm -//│ 'k <: 'm -> 'n) <: 'j -> 'i -> 'g) -> 'a -> 'o -//│ forall 'g 'h 'i. 'i -> 'h +//│ 'j <: 'l -> 'm +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'j -> 'k -> 'l) <: 'n -> 'g -> 'h +//│ 'n <: 'h -> 'i) -> 'a -> 'o +//│ forall 'g 'h 'i. 'g -> 'i //│ where -//│ 'j <: 'g -> 'h -//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n +//│ forall 'j. 'j -> (forall 'k 'l 'm. 'k -> 'm //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'k -> 'l -> 'm -//│ 'k <: 'm -> 'n) <: 'j -> 'i -> 'g <: 'o -> 'b +//│ 'j <: 'l -> 'm +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 'j -> 'k -> 'l) <: 'n -> 'g -> 'h +//│ 'n <: 'h -> 'i <: 'o -> 'b //│ where -//│ 'j :> forall 'p 'q 'r 's. ('p & 's) -> (anything -> 's | 'r) +//│ 'n :> forall 'p 'q 'r 's. ('p & 's) -> (anything -> 's | 'r) //│ where //│ forall 't. 't -> (forall 'u 'v 'w. 'u -> 'w //│ where -//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'u -> 'v -//│ 't <: 'v -> 'w) <: 'j -> 'p -> 'q -//│ 'j <: 'q -> 'r +//│ 't <: 'v -> 'w +//│ forall 'X. ('X -> 'X) -> 'X -> 'X <: 't -> 'u -> 'v) <: 'n -> 'p -> 'q +//│ 'n <: 'q -> 'r //│ = [Function (anonymous)] c2__ = succ_ (succ_ n0_) //│ c2__: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ 'a <: 'c -> 'd -//│ forall 'e. 'e -> (forall 'f 'g 'h. 'f -> 'h +//│ forall 'e. 'e -> (forall 'f 'g 'h. 'h -> 'g //│ where -//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'f -> 'g -//│ 'e <: 'g -> 'h) <: 'a -> 'b -> 'c) +//│ anything -> (forall 'i. 'i -> 'i) <: 'e -> 'h -> 'f +//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c +//│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] c2__ c2__ //│ res: 'a -> 'b //│ where -//│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ forall 'c. 'c -> (forall 'd 'e 'f. 'e -> 'd //│ where +//│ 'c <: 'f -> 'd //│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where -//│ 'g <: 'i -> 'j -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f) <: 'l -> 'b +//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i +//│ 'g <: 'i -> 'j) <: 'c -> 'e -> 'f) <: 'l -> 'b //│ forall 'm. 'm -> (forall 'n 'o 'p. 'n -> 'p //│ where -//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'n -> 'o -//│ 'm <: 'o -> 'p) <: (forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f +//│ 'm <: 'o -> 'p +//│ anything -> (forall 'k. 'k -> 'k) <: 'm -> 'n -> 'o) <: (forall 'c. 'c -> (forall 'd 'e 'f. 'e -> 'd //│ where +//│ 'c <: 'f -> 'd //│ forall 'g. 'g -> (forall 'h 'i 'j. 'h -> 'j //│ where -//│ 'g <: 'i -> 'j -//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f)) -> 'a -> 'l +//│ anything -> (forall 'k. 'k -> 'k) <: 'g -> 'h -> 'i +//│ 'g <: 'i -> 'j) <: 'c -> 'e -> 'f)) -> 'a -> 'l //│ = [Function (anonymous)] c2__ c2__ K @@ -441,20 +441,20 @@ c2__ c2__ K //│ where //│ forall 'c. 'c -> (forall 'd 'e 'f. 'd -> 'f //│ where -//│ anything -> (forall 'g. 'g -> 'g) <: 'c -> 'd -> 'e -//│ 'c <: 'e -> 'f) <: (forall 'h 'i 'j. 'h -> 'j +//│ 'c <: 'e -> 'f +//│ anything -> (forall 'g. 'g -> 'g) <: 'c -> 'd -> 'e) <: (forall 'h 'i 'j. 'h -> 'j //│ where -//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n +//│ forall 'k. 'k -> (forall 'l 'm 'n. 'm -> 'l //│ where -//│ anything -> (forall 'g. 'g -> 'g) <: 'k -> 'l -> 'm -//│ 'k <: 'm -> 'n) <: (forall 'o. 'o -> anything -> 'o) -> 'h -> 'i +//│ 'k <: 'n -> 'l +//│ anything -> (forall 'g. 'g -> 'g) <: 'k -> 'm -> 'n) <: (forall 'o. 'o -> anything -> 'o) -> 'h -> 'i //│ forall 'o. 'o -> anything -> 'o <: 'i -> 'j) -> 'a -> 'p //│ forall 'h 'i 'j. 'h -> 'j //│ where -//│ forall 'k. 'k -> (forall 'l 'm 'n. 'l -> 'n +//│ forall 'k. 'k -> (forall 'l 'm 'n. 'm -> 'l //│ where -//│ anything -> (forall 'g. 'g -> 'g) <: 'k -> 'l -> 'm -//│ 'k <: 'm -> 'n) <: (forall 'o. 'o -> anything -> 'o) -> 'h -> 'i +//│ 'k <: 'n -> 'l +//│ anything -> (forall 'g. 'g -> 'g) <: 'k -> 'm -> 'n) <: (forall 'o. 'o -> anything -> 'o) -> 'h -> 'i //│ forall 'o. 'o -> anything -> 'o <: 'i -> 'j <: 'p -> 'b //│ = [Function (anonymous)] diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index bf3366b3c2..9178a42293 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -27,20 +27,19 @@ Dummy.introspect //│ = 'duh!' -// * TODO: simplify `forall 'a. Int | 'a` – seems it's not because it shares a var... class Funny: Int { fun test = this + 1 } -//│ class Funny: Int | 'a { +//│ class Funny: Int { //│ constructor() -//│ fun test: forall 'a. Int | 'a +//│ fun test: Int //│ } :e class Unfunny { fun test = this + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.38: class Unfunny { fun test = this + 1 } +//│ ║ l.37: class Unfunny { fun test = this + 1 } //│ ║ ^^^^^^^^ //│ ╟── reference of type `#Unfunny` is not an instance of type `Int` -//│ ║ l.38: class Unfunny { fun test = this + 1 } +//│ ║ l.37: class Unfunny { fun test = this + 1 } //│ ╙── ^^^^ //│ class Unfunny { //│ constructor() @@ -100,7 +99,7 @@ class Exp: Pair | Lit { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.98: Pair(l, r) then l.test + r.test +//│ ║ l.97: Pair(l, r) then l.test + r.test //│ ╙── ^^^^^ //│ class Exp: Lit | Pair { //│ constructor() @@ -143,25 +142,25 @@ class Exp[A]: Pair | Lit { class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.138: class Exp[A]: Pair | Lit { +//│ ║ l.137: class Exp[A]: Pair | Lit { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.139: fun test = if this is +//│ ║ l.138: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.140: Lit then 0 +//│ ║ l.139: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.141: Pair then 1 +//│ ║ l.140: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.142: } +//│ ║ l.141: } //│ ╙── ^ //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.139: fun test = if this is +//│ ║ l.138: fun test = if this is //│ ║ ^^^^^^^ -//│ ║ l.140: Lit then 0 +//│ ║ l.139: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.141: Pair then 1 +//│ ║ l.140: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.144: class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] +//│ ║ l.143: class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╙── ^ //│ class Exp[A]: Lit | Pair[anything, anything] { //│ constructor() diff --git a/shared/src/test/diff/gen/genTests_v1-0.14-15-x2.fun b/shared/src/test/diff/gen/genTests_v1-0.14-15-x2.fun index 4cb68f818d..7743c733e1 100644 --- a/shared/src/test/diff/gen/genTests_v1-0.14-15-x2.fun +++ b/shared/src/test/diff/gen/genTests_v1-0.14-15-x2.fun @@ -2579,9 +2579,9 @@ add //│ res: {u: forall 'a. 'a -> 'a} (let rec x = {v: (y => x)}; {u: x.v}) -//│ res: {u: 'v} +//│ res: {u: anything -> 'x} //│ where -//│ 'v :> anything -> {v: 'v} +//│ 'x :> {v: anything -> 'x} (x => 0.v) //│ ╔══[ERROR] Type mismatch in field selection: @@ -2940,9 +2940,9 @@ add //│ res: {v: int -> int -> int} (let rec x = {v: {v: x}}; x.v) -//│ res: 'v +//│ res: {v: 'x} //│ where -//│ 'v :> {v: {v: 'v}} +//│ 'x :> {v: {v: 'x}} 0.u //│ ╔══[ERROR] Type mismatch in field selection: diff --git a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls index 6dbbf0de84..495ff59ed1 100644 --- a/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls +++ b/shared/src/test/diff/mlf-examples/ex_casparticuliers.mls @@ -593,8 +593,8 @@ succ' succ' {} //│ res: 'a -> (forall 'b 'c 'd. 'b -> 'd //│ where -//│ 'a <: 'c -> 'd -//│ anything <: 'a -> 'b -> 'c) +//│ anything <: 'a -> 'b -> 'c +//│ 'a <: 'c -> 'd) //│ = [Function (anonymous)] // :e // * Error delayed by inconsistent constrained types diff --git a/shared/src/test/diff/mlf-examples/ex_concrete.mls b/shared/src/test/diff/mlf-examples/ex_concrete.mls index fb2be246d2..a90987d1db 100644 --- a/shared/src/test/diff/mlf-examples/ex_concrete.mls +++ b/shared/src/test/diff/mlf-examples/ex_concrete.mls @@ -51,9 +51,9 @@ rec def map f l = case l of { Nil -> Nil | Cons -> Cons (f l.head, map f l.tail) } -//│ map: ('head -> 'head0) -> 'a -> 'tail +//│ map: ('head -> 'head0) -> 'a -> (Nil | 'b) //│ where -//│ 'tail :> (Cons['head0] with {tail: 'tail}) | Nil +//│ 'b :> Cons['head0] with {tail: Nil | 'b} //│ 'a <: (Cons[?] with {head: 'head, tail: 'a}) | Nil //│ = [Function: map] :NoRecursiveTypes diff --git a/shared/src/test/diff/mlf-examples/ex_demo.mls b/shared/src/test/diff/mlf-examples/ex_demo.mls index 055eafa42b..2bc5aa996b 100644 --- a/shared/src/test/diff/mlf-examples/ex_demo.mls +++ b/shared/src/test/diff/mlf-examples/ex_demo.mls @@ -254,13 +254,11 @@ rec def id1 x = if true then x else id1 id1 x //│ ║ l.243: rec def id1 x = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id1] @@ -280,13 +278,11 @@ def id1 x = if true then x else idy_ty idy_ty x // * but it does need at least recursive types: :RecursiveTypes rec def id1 x = if true then x else id1 id1 x -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id11] id1 id //│ res: ('a & 'b) -> 'b | 'c @@ -297,36 +293,32 @@ id1 id //│ <: 'a -> 'b & 'c //│ = [Function: id] id1 id1 -//│ res: 'a -> 'b | 'id1 +//│ res: ('a & 'b) -> 'a //│ where -//│ 'a :> forall 'id1 'c 'd. 'a -> 'b | 'id1 -//│ <: 'b -//│ 'b :> forall 'id1 'c 'd. 'id1 -//│ <: 'a -> 'b -//│ 'id1 :> 'c -> 'd -//│ 'c :> 'id1 +//│ 'a :> forall 'c 'd. ('a & 'b & 'c) -> ('a | 'd) +//│ <: ((forall 'c 'd. 'c -> 'd) | 'b) -> 'a +//│ 'c :> 'c -> 'd //│ <: 'd -//│ 'd :> 'id1 -//│ <: 'c -> 'd +//│ 'd := 'c -> 'd //│ = [Function: id11] // * Note that it can't be applied when typed with :precise-rec-typing AND :DontDistributeForalls :DontDistributeForalls :precise-rec-typing rec def id1_p x = if true then x else id1_p id1_p x -//│ id1_p: 'id1_p +//│ id1_p: 'a -> 'b //│ where -//│ 'id1_p :> forall 'a. ('a & 'b) -> 'a -//│ 'a :> 'c -//│ 'c :> 'id1_p -//│ <: 'b -> 'c -//│ 'b :> 'id1_p -//│ <: 'c +//│ 'a <: 'b & 'c +//│ 'b :> 'd +//│ 'd :> forall 'a 'b. 'a -> 'b +//│ <: 'c -> 'd +//│ 'c :> forall 'a 'b. 'a -> 'b +//│ <: 'd //│ = [Function: id1_p] // * Can't apply it: :e id1_p id //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.327: id1_p id +//│ ║ l.319: id1_p id //│ ║ ^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error | ('a & 'b) -> 'a | 'c @@ -344,21 +336,17 @@ id1_p id // * TODO type pp – inline id1? :e id1 -//│ ╔══[ERROR] Inferred recursive type: 'id1 +//│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ ╙── -//│ res: 'id1 +//│ res: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id11] :e @@ -368,19 +356,19 @@ id1: nothing //│ 'a := 'b -> 'a //│ 'b :> 'b -> 'a //│ <: 'a -//│ ║ l.282: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.280: rec def id1 x = if true then x else id1 id1 x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.365: id1: nothing +//│ ║ l.353: id1: nothing //│ ║ ^^^ //│ ╟── function of type `?a -> ?b` does not match type `nothing` -//│ ║ l.282: rec def id1 x = if true then x else id1 id1 x +//│ ║ l.280: rec def id1 x = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.365: id1: nothing +//│ ║ l.353: id1: nothing //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.365: id1: nothing +//│ ║ l.353: id1: nothing //│ ╙── ^^^^^^^ //│ res: nothing //│ = [Function: id11] @@ -391,7 +379,7 @@ rec def id1_ x = id1_ id1_ x //│ where //│ 'a <: ('b -> 'c | 'b) -> 'c //│ 'c <: 'a -//│ ║ l.389: rec def id1_ x = id1_ id1_ x +//│ ║ l.377: rec def id1_ x = id1_ id1_ x //│ ╙── ^^^^^^^^^ //│ id1_: anything -> nothing //│ = [Function: id1_] @@ -401,46 +389,46 @@ rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ╔══[ERROR] Inferred recursive type: 'b //│ where //│ 'b <: (forall 'a. 'a -> 'a) -> (??a & 'b) -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ╙── ^^^^^^^ //│ ╔══[ERROR] Type mismatch in binding of lambda expression: -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'a` is not a function -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^ //│ ╟── but it flows into quantified type variable with expected type `'a0 -> 'a0` -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^ //│ ╟── Note: constraint arises from function type: -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Type error in binding of lambda expression -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'a` leaks out of its scope -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^^^^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this application: -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Type error in binding of lambda expression -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'a` leaks out of its scope -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^^^^^^^ //│ ╟── adding a type annotation to any of the following terms may help resolve the problem //│ ╟── • this application: -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.400: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x +//│ ║ l.388: rec def id1 (x: forall 'a. 'a -> 'a) = if true then x else id1 id1 x //│ ╙── ^^^^^^^^^ //│ id1: (forall 'a. 'a -> 'a) -> 'a0 -> 'a0 //│ = [Function: id12] @@ -487,7 +475,7 @@ ex1_1 (fun ((x, f)) -> f x) //│ A String ex1_2 = if true then make_ex1 ((42, print_int)) else ex1_1 -//│ ex1_2: (forall 'a 'a0. (('a0, 'a0 -> unit,),) -> 'b & (('a, 'a -> unit,),) -> 'b) -> 'b +//│ ex1_2: (forall 'a 'a0. (('a, 'a -> unit,),) -> 'b & (('a0, 'a0 -> unit,),) -> 'b) -> 'b //│ = [Function (anonymous)] ex1_2 (fun ((x, f)) -> f x) @@ -525,7 +513,7 @@ ex_list1 = cons (make_ex1 (("A String", print_string))) ex_list2 = cons (make_ex2 (("String", "String", eqstring))) (cons (make_ex2 ((1250, 4890, eqint))) (cons (make_ex2 ((true, false, eqbool))) nil)) -//│ ex_list2: List[forall 'b. (forall 'a 'c 'a0 'a1. (('a, 'a, 'a -> 'a -> (forall 'c. bool | 'c),),) -> 'b & (('a0, 'a0, 'a0 -> 'a0 -> (bool | false | 'c),),) -> 'b & (('a1, 'a1, 'a1 -> 'a1 -> (forall 'c. bool | 'c),),) -> 'b) -> 'b] +//│ ex_list2: List[forall 'b. (forall 'a 'a0 'a1. (('a1, 'a1, 'a1 -> 'a1 -> bool,),) -> 'b & (('a, 'a, 'a -> 'a -> (bool | false),),) -> 'b & (('a0, 'a0, 'a0 -> 'a0 -> bool,),) -> 'b) -> 'b] //│ = Cons { //│ head: [Function (anonymous)], //│ tail: Cons { @@ -943,17 +931,17 @@ def c_mul m (n: Fint) = m (c_add n) c_i0 //│ = [Function: c_mul] def c_mul_ m n = m (c_add_ n) c_i0 -//│ c_mul_: ((forall 'a. ((forall 'b 'c 'd 'e. ('d -> 'e -> 'b) -> ('c -> 'e & 'd) -> 'c -> 'b) -> 'f -> 'a) -> 'a) -> (forall 'g. anything -> 'g -> 'g) -> 'h) -> 'f -> 'h +//│ c_mul_: ((forall 'a. ((forall 'b 'c 'd 'e. ('b -> 'c -> 'd) -> ('e -> 'c & 'b) -> 'e -> 'd) -> 'f -> 'a) -> 'a) -> (forall 'g. anything -> 'g -> 'g) -> 'h) -> 'f -> 'h //│ = [Function: c_mul_] // let c_pow n (m:Int) = m (c_mul n) c_i1 def c_pow m (n: Fint) = m (c_mul n) c_i1 -//│ c_pow: ((Fint -> (forall 'b 'a. (('a | 'b) -> 'a) -> 'b -> ('a | 'b) | Fint)) -> (forall 'c 'd. ('c -> 'd) -> 'c -> 'd) -> 'e) -> Fint -> 'e +//│ c_pow: ((Fint -> (forall 'a 'b. (('a | 'b) -> 'a) -> 'b -> ('a | 'b) | Fint)) -> (forall 'c 'd. ('c -> 'd) -> 'c -> 'd) -> 'e) -> Fint -> 'e //│ = [Function: c_pow] def c_pow_ m n = m (c_mul_ n) c_i1 -//│ c_pow_: (('a -> 'b) -> (forall 'c 'd. ('c -> 'd) -> 'c -> 'd) -> 'e) -> ((forall 'f. ((forall 'g 'h 'i 'j. ('g -> 'h -> 'i) -> ('j -> 'h & 'g) -> 'j -> 'i) -> 'a -> 'f) -> 'f) -> (forall 'k. anything -> 'k -> 'k) -> 'b) -> 'e +//│ c_pow_: (('a -> 'b) -> (forall 'c 'd. ('c -> 'd) -> 'c -> 'd) -> 'e) -> ((forall 'f. ((forall 'g 'h 'i 'j. ('j -> 'g -> 'h) -> ('i -> 'g & 'j) -> 'i -> 'h) -> 'a -> 'f) -> 'f) -> (forall 'k. anything -> 'k -> 'k) -> 'b) -> 'e //│ = [Function: c_pow_] @@ -973,7 +961,7 @@ def c_pred_ n = let s = fun p -> c_pair (c_2_2_ p) (c_succ_ (c_2_2_ p)) in let z = c_pair c_i0 c_i0 in c_1_2_ (n s z) -//│ c_pred_: ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('f -> 'd -> 'a & 'b)) -> ('b -> (('c -> 'd & 'f) -> 'c -> 'a) -> 'e) -> 'e) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k +//│ c_pred_: ((forall 'a 'b 'c 'd 'e 'f. ((forall 'g. anything -> 'g -> 'g) -> ('a -> 'd -> 'e & 'f)) -> ('f -> (('b -> 'd & 'a) -> 'b -> 'e) -> 'c) -> 'c) -> (forall 'h. ((forall 'i. anything -> 'i -> 'i) -> (forall 'i. anything -> 'i -> 'i) -> 'h) -> 'h) -> (forall 'j. 'j -> anything -> 'j) -> 'k) -> 'k //│ = [Function: c_pred_] @@ -1071,7 +1059,7 @@ def c_fact_A: Fint -> Fint def c_fact_A n = c_if (c_iszero n) (fun u -> c_i1) (fun u -> c_mul n (c_fact_A (c_pred n))) -//│ (Fint & (Fint -> (forall 'a 'b. (('a | 'b) -> 'a) -> 'b -> 'a | Fint)) -> (forall 'c. anything -> 'c -> 'c) -> 'd) -> (('e -> 'f) -> 'e -> 'f | 'd) +//│ (Fint & (Fint -> (forall 'b 'a. (('a | 'b) -> 'a) -> 'b -> 'a | Fint)) -> (forall 'c. anything -> 'c -> 'c) -> 'd) -> (('e -> 'f) -> 'e -> 'f | 'd) //│ <: c_fact_A: //│ Fint -> Fint //│ = @@ -1085,28 +1073,28 @@ rec def c_fact_ n = (fun _ -> c_mul_ n (c_fact_ (c_pred_ n))) //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (? -> 'j) -> 'k & (forall 'l. ((forall 'm 'n 'o 'p. ('m -> 'n -> 'o) -> ('p -> 'n & 'm) -> 'p -> 'o) -> 'k -> 'l) -> 'l) -> (forall 'c. ? -> 'c -> 'c) -> 'j & (forall 'q 'r 's 't 'u 'v. ((forall 'w. ? -> 'w -> 'w) -> ('s -> 'v -> 'q & 'r)) -> ('r -> (('t -> 'v & 's) -> 't -> 'q) -> 'u) -> 'u) -> 'a) -//│ ║ l.975: c_1_2_ (n s z) +//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (? -> 'j) -> 'k & (forall 'l. ((forall 'm 'n 'o 'p. ('m -> 'n -> 'o) -> ('p -> 'n & 'm) -> 'p -> 'o) -> 'k -> 'l) -> 'l) -> (forall 'c. ? -> 'c -> 'c) -> 'j & (forall 'q 'r 's 't 'u 'v. ((forall 'w. ? -> 'w -> 'w) -> ('u -> 'v -> 'r & 't)) -> ('t -> (('s -> 'v & 'u) -> 's -> 'r) -> 'q) -> 'q) -> 'a) +//│ ║ l.963: c_1_2_ (n s z) //│ ╙── ^^^ //│ c_fact_: 'a -> 'b //│ where -//│ 'a <: (forall 'c. anything -> anything -> ((forall 'd. 'd -> 'd) -> 'c) -> 'c) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (forall 'f 'g. anything -> ('f -> 'g) -> 'f -> 'g) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l 'm. ('k -> 'l -> 'm) -> ('j -> 'l & 'k) -> 'j -> 'm) -> 'b -> 'i) -> 'i) -> (forall 'n. anything -> 'n -> 'n) -> 'h & (forall 'o 'p 'q 'r 's 't. ((forall 'u. anything -> 'u -> 'u) -> ('r -> 's -> 't & 'o)) -> ('o -> (('q -> 's & 'r) -> 'q -> 't) -> 'p) -> 'p) -> (forall 'v. ((forall 'n. anything -> 'n -> 'n) -> (forall 'n. anything -> 'n -> 'n) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a +//│ 'a <: (forall 'c. anything -> anything -> ((forall 'd. 'd -> 'd) -> 'c) -> 'c) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (forall 'f 'g. anything -> ('f -> 'g) -> 'f -> 'g) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l 'm. ('j -> 'k -> 'l) -> ('m -> 'k & 'j) -> 'm -> 'l) -> 'b -> 'i) -> 'i) -> (forall 'n. anything -> 'n -> 'n) -> 'h & (forall 'o 'p 'q 'r 's 't. ((forall 'u. anything -> 'u -> 'u) -> ('q -> 's -> 'p & 'o)) -> ('o -> (('t -> 's & 'q) -> 't -> 'p) -> 'r) -> 'r) -> (forall 'v. ((forall 'n. anything -> 'n -> 'n) -> (forall 'n. anything -> 'n -> 'n) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a //│ = [Function: c_fact_] :e // * The type we infer without any annotations can't be checked against the desired signature c_fact_A = c_fact_ //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (forall 'j. ? -> (? -> 'j -> 'j | 'k)) -> 'l & (forall 'm. ((forall 'n 'o 'p 'q. ('n -> 'o -> 'p) -> ('q -> 'o & 'n) -> 'q -> 'p) -> (forall 'r 's. ('r -> 's) -> 'r -> 's | 'l) -> 'm) -> 'm) -> (forall 'c. ? -> 'c -> 'c) -> 'k & (forall 't 'u 'v 'w 'x 'y. ((forall 'z. ? -> 'z -> 'z) -> ('t -> 'y -> 'x & 'v)) -> ('v -> (('u -> 'y & 't) -> 'u -> 'x) -> 'w) -> 'w) -> 'a) -//│ ║ l.975: c_1_2_ (n s z) +//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (forall 'j. ? -> (? -> 'j -> 'j | 'k)) -> 'l & (forall 'm. ((forall 'n 'o 'p 'q. ('q -> 'n -> 'o) -> ('p -> 'n & 'q) -> 'p -> 'o) -> (forall 'r 's. ('r -> 's) -> 'r -> 's | 'l) -> 'm) -> 'm) -> (forall 'c. ? -> 'c -> 'c) -> 'k & (forall 't 'u 'v 'w 'x 'y. ((forall 'z. ? -> 'z -> 'z) -> ('t -> 'x -> 'w & 'u)) -> ('u -> (('v -> 'x & 't) -> 'v -> 'w) -> 'y) -> 'y) -> 'a) +//│ ║ l.963: c_1_2_ (n s z) //│ ╙── ^^^ //│ 'a -> 'b //│ where -//│ 'a <: (forall 'c. anything -> anything -> ((forall 'd. 'd -> 'd) -> 'c) -> 'c) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (forall 'f 'g. anything -> ('f -> 'g) -> 'f -> 'g) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l 'm. ('j -> 'k -> 'l) -> ('m -> 'k & 'j) -> 'm -> 'l) -> 'b -> 'i) -> 'i) -> (forall 'n. anything -> 'n -> 'n) -> 'h & (forall 'o 'p 'q 'r 's 't. ((forall 'u. anything -> 'u -> 'u) -> ('s -> 't -> 'o & 'q)) -> ('q -> (('r -> 't & 's) -> 'r -> 'o) -> 'p) -> 'p) -> (forall 'v. ((forall 'n. anything -> 'n -> 'n) -> (forall 'n. anything -> 'n -> 'n) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a +//│ 'a <: (forall 'c. anything -> anything -> ((forall 'd. 'd -> 'd) -> 'c) -> 'c) -> (forall 'e. ((forall 'd. 'd -> 'd) -> 'e) -> anything -> 'e) -> (forall 'f 'g. anything -> ('f -> 'g) -> 'f -> 'g) -> (anything -> 'h) -> 'b & (forall 'i. ((forall 'j 'k 'l 'm. ('j -> 'k -> 'l) -> ('m -> 'k & 'j) -> 'm -> 'l) -> 'b -> 'i) -> 'i) -> (forall 'n. anything -> 'n -> 'n) -> 'h & (forall 'o 'p 'q 'r 's 't. ((forall 'u. anything -> 'u -> 'u) -> ('p -> 's -> 'r & 'q)) -> ('q -> (('o -> 's & 'p) -> 'o -> 'r) -> 't) -> 't) -> (forall 'v. ((forall 'n. anything -> 'n -> 'n) -> (forall 'n. anything -> 'n -> 'n) -> 'v) -> 'v) -> (forall 'w. 'w -> anything -> 'w) -> 'a //│ <: c_fact_A: //│ Fint -> Fint //│ ╔══[ERROR] Cyclic-looking constraint while typing def definition; a type annotation may be required -//│ ║ l.1097: c_fact_A = c_fact_ +//│ ║ l.1085: c_fact_A = c_fact_ //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ = [Function: c_fact_] @@ -1137,11 +1125,11 @@ def print_fact_ n = print_string "\n" //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (forall 'j. ? -> (? -> 'j -> 'j | 'k)) -> 'l & (forall 'm. ((forall 'n 'o 'p 'q. ('q -> 'n -> 'o) -> ('p -> 'n & 'q) -> 'p -> 'o) -> (forall 'r 's. ('r -> 's) -> 'r -> 's | 'l) -> 'm) -> 'm) -> (forall 'c. ? -> 'c -> 'c) -> 'k & (forall 't 'u 'v 'w 'x 'y. ((forall 'z. ? -> 'z -> 'z) -> ('y -> 'v -> 'u & 'x)) -> ('x -> (('t -> 'v & 'y) -> 't -> 'u) -> 'w) -> 'w) -> 'a) -//│ ║ l.975: c_1_2_ (n s z) +//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (forall 'j. ? -> (? -> 'j -> 'j | 'k)) -> 'l & (forall 'm. ((forall 'n 'o 'p 'q. ('n -> 'o -> 'p) -> ('q -> 'o & 'n) -> 'q -> 'p) -> (forall 'r 's. ('r -> 's) -> 'r -> 's | 'l) -> 'm) -> 'm) -> (forall 'c. ? -> 'c -> 'c) -> 'k & (forall 't 'u 'v 'w 'x 'y. ((forall 'z. ? -> 'z -> 'z) -> ('x -> 'u -> 'y & 'w)) -> ('w -> (('t -> 'u & 'x) -> 't -> 'y) -> 'v) -> 'v) -> 'a) +//│ ║ l.963: c_1_2_ (n s z) //│ ╙── ^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1136: let _ = c_printint_ (c_fact_ (to_church_ n)) in +//│ ║ l.1124: let _ = c_printint_ (c_fact_ (to_church_ n)) in //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ print_fact_: int -> unit @@ -1172,11 +1160,11 @@ def print_fact2_ n = (c_printint2_ (c_fact_ (to_church_ n))) )) //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (forall 'j. ? -> (? -> 'j -> 'j | 'k)) -> 'l & (forall 'm. ((forall 'n 'o 'p 'q. ('p -> 'q -> 'n) -> ('o -> 'q & 'p) -> 'o -> 'n) -> (forall 'r 's. ('r -> 's) -> 'r -> 's | 'l) -> 'm) -> 'm) -> (forall 'c. ? -> 'c -> 'c) -> 'k & (forall 't 'u 'v 'w 'x 'y. ((forall 'z. ? -> 'z -> 'z) -> ('t -> 'v -> 'x & 'y)) -> ('y -> (('w -> 'v & 't) -> 'w -> 'x) -> 'u) -> 'u) -> 'a) -//│ ║ l.975: c_1_2_ (n s z) +//│ 'a <: (forall 'b. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'b) -> 'b) -> (forall 'd. 'd -> ? -> 'd) -> ((forall 'e. ? -> ? -> ((forall 'f. 'f -> 'f) -> 'e) -> 'e) -> (forall 'g. ((forall 'f. 'f -> 'f) -> 'g) -> ? -> 'g) -> (forall 'h 'i. ? -> ('h -> 'i) -> 'h -> 'i) -> (forall 'j. ? -> (? -> 'j -> 'j | 'k)) -> 'l & (forall 'm. ((forall 'n 'o 'p 'q. ('n -> 'o -> 'p) -> ('q -> 'o & 'n) -> 'q -> 'p) -> (forall 'r 's. ('r -> 's) -> 'r -> 's | 'l) -> 'm) -> 'm) -> (forall 'c. ? -> 'c -> 'c) -> 'k & (forall 't 'u 'v 'w 'x 'y. ((forall 'z. ? -> 'z -> 'z) -> ('t -> 'w -> 'y & 'v)) -> ('v -> (('u -> 'w & 't) -> 'u -> 'y) -> 'x) -> 'x) -> 'a) +//│ ║ l.963: c_1_2_ (n s z) //│ ╙── ^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1172: (c_printint2_ (c_fact_ (to_church_ n))) )) +//│ ║ l.1160: (c_printint2_ (c_fact_ (to_church_ n))) )) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ print_fact2_: int -> string @@ -1222,14 +1210,14 @@ this_should_be_98_ = let c_98_ = c_pred_ c_99_ in c_printint2_ c_98_ //│ ╔══[ERROR] Inferred recursive type: nothing -//│ ║ l.743: type Fint = forall 'a. ('a -> 'a) -> ('a -> 'a) +//│ ║ l.731: type Fint = forall 'a. ('a -> 'a) -> ('a -> 'a) //│ ╙── ^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1219: let c_i10_ = c_mul_ c_i5_ c_i2_ in +//│ ║ l.1207: let c_i10_ = c_mul_ c_i5_ c_i2_ in //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1220: let c_i9_ = c_pred_ c_i10_ in +//│ ║ l.1208: let c_i9_ = c_pred_ c_i10_ in //│ ║ ^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ this_should_be_98_: string @@ -1252,15 +1240,15 @@ c_i5_ = c_add_ c_i3_ c_i2_ :e c_i10_ = c_mul_ c_i5_ c_i2_ //│ ╔══[ERROR] Inferred recursive type: nothing -//│ ║ l.743: type Fint = forall 'a. ('a -> 'a) -> ('a -> 'a) +//│ ║ l.731: type Fint = forall 'a. ('a -> 'a) -> ('a -> 'a) //│ ╙── ^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1253: c_i10_ = c_mul_ c_i5_ c_i2_ +//│ ║ l.1241: c_i10_ = c_mul_ c_i5_ c_i2_ //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ c_i10_: error | ((forall 'a 'b 'c. ('a -> 'b & 'b -> 'c) -> 'a -> 'c | 'd) -> ('e -> 'f -> ('g & 'h & 'i & 'j & 'k & 'l & 'm) & 'n) & (('o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 's) -> 'o -> 'r | 'n) -> ('t -> 'u -> ('h & 'i & 'j & 'k & 'l & 'm) & 'v) & (('w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's) -> 'w -> 'g | 'v) -> ('x -> 'y -> ('i & 'j & 'k & 'l & 'm) & 'z) & (('a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't) -> 'a1 -> 'h | 'z) -> ('b1 -> 'c1 -> ('j & 'k & 'l & 'm) & 'd1) & (('e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x) -> 'e1 -> 'i | 'd1) -> ('f1 -> 'g1 -> ('k & 'l & 'm) & 'h1) & (('i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1) -> 'i1 -> 'j | 'h1) -> ('j1 -> 'k1 -> ('l & 'm) & 'l1) & (('m1 -> ('g1 & 'i1) & 'i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1 & 'f1) -> 'm1 -> 'k | 'l1) -> ('n1 -> 'o1 -> 'm & 'p1) & (('q1 -> ('k1 & 'm1) & 'm1 -> ('g1 & 'i1) & 'i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1 & 'f1 & 'j1) -> 'q1 -> 'l | 'p1) -> ('r1 & 's1)) -> ('s -> 'p -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'd) -> (('t1 -> ('o1 & 'q1) & 'q1 -> ('k1 & 'm1) & 'm1 -> ('g1 & 'i1) & 'i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1 & 'f1 & 'j1 & 'n1) -> 't1 -> 'm | 'r1) | 's1 +//│ c_i10_: error | ((forall 'a 'b 'c. ('b -> 'c & 'c -> 'a) -> 'b -> 'a | 'd) -> ('e -> 'f -> ('g & 'h & 'i & 'j & 'k & 'l & 'm) & 'n) & (('o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 's) -> 'o -> 'r | 'n) -> ('t -> 'u -> ('h & 'i & 'j & 'k & 'l & 'm) & 'v) & (('w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's) -> 'w -> 'g | 'v) -> ('x -> 'y -> ('i & 'j & 'k & 'l & 'm) & 'z) & (('a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't) -> 'a1 -> 'h | 'z) -> ('b1 -> 'c1 -> ('j & 'k & 'l & 'm) & 'd1) & (('e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x) -> 'e1 -> 'i | 'd1) -> ('f1 -> 'g1 -> ('k & 'l & 'm) & 'h1) & (('i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1) -> 'i1 -> 'j | 'h1) -> ('j1 -> 'k1 -> ('l & 'm) & 'l1) & (('m1 -> ('g1 & 'i1) & 'i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1 & 'f1) -> 'm1 -> 'k | 'l1) -> ('n1 -> 'o1 -> 'm & 'p1) & (('q1 -> ('k1 & 'm1) & 'm1 -> ('g1 & 'i1) & 'i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1 & 'f1 & 'j1) -> 'q1 -> 'l | 'p1) -> ('r1 & 's1)) -> ('s -> 'p -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'd) -> (('t1 -> ('o1 & 'q1) & 'q1 -> ('k1 & 'm1) & 'm1 -> ('g1 & 'i1) & 'i1 -> ('c1 & 'e1) & 'e1 -> ('y & 'a1) & 'a1 -> ('u & 'w) & 'w -> ('f & 'o) & 'o -> 'p & 'p -> 'q & 'q -> ('g & 'h & 'i & 'j & 'k & 'l & 'm & 'r) & 'e & 's & 't & 'x & 'b1 & 'f1 & 'j1 & 'n1) -> 't1 -> 'm | 'r1) | 's1 //│ where -//│ 's1 <: (forall 'u1 'v1 'w1 'x1. ('u1 -> 'v1 -> 'w1) -> ('x1 -> 'v1 & 'u1) -> 'x1 -> 'w1) -> (forall 'y1 'z1 'a2. ('y1 -> 'z1 & 'z1 -> 'a2) -> 'y1 -> 'a2) -> 's1 +//│ 's1 <: (forall 'u1 'v1 'w1 'x1. ('u1 -> 'v1 -> 'w1) -> ('x1 -> 'v1 & 'u1) -> 'x1 -> 'w1) -> (forall 'y1 'z1 'a2. ('a2 -> 'y1 & 'y1 -> 'z1) -> 'a2 -> 'z1) -> 's1 //│ = [Function (anonymous)] //│ constrain calls : 1274 //│ annoying calls : 0 @@ -1288,11 +1276,11 @@ c_i9_ = c_pred_ c_i10_ c_99_ = c_add_ (c_mul_ c_i9_ c_i10_) c_i9_ //│ ╔══[ERROR] Inferred recursive type: 'b //│ where -//│ 'b <: (forall 'c 'd 'e 'f. ('c -> 'd -> 'e) -> ('f -> 'd & 'c) -> 'f -> 'e) -> ((forall 'a 'g 'a0 'a1 'a2. (('a0 | 'g) -> 'a0 & ('a1 | 'g) -> 'a1 & ('a2 | 'g) -> 'a2 & ('a | 'g) -> 'a) -> 'g -> ('a0 | 'a1 | 'a2 | 'a) | Fint) -> ? & (forall 'a3 'h 'a4. (('a3 | 'h) -> 'a3 & ('a4 | 'h) -> 'a4) -> 'h -> ('a3 | 'a4) | Fint) -> anything) -//│ ║ l.915: def c_succ_ n = fun f -> fun x -> n f (f x) +//│ 'b <: (forall 'c 'd 'e 'f. ('c -> 'd -> 'e) -> ('f -> 'd & 'c) -> 'f -> 'e) -> ((forall 'a 'a0 'a1 'g 'a2. (('a | 'g) -> 'a & ('a1 | 'g) -> 'a1 & ('a2 | 'g) -> 'a2 & ('a0 | 'g) -> 'a0) -> 'g -> ('a | 'a1 | 'a2 | 'a0) | Fint) -> ? & (forall 'a3 'h 'a4. (('a3 | 'h) -> 'a3 & ('a4 | 'h) -> 'a4) -> 'h -> ('a3 | 'a4) | Fint) -> anything) +//│ ║ l.903: def c_succ_ n = fun f -> fun x -> n f (f x) //│ ╙── ^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.1288: c_99_ = c_add_ (c_mul_ c_i9_ c_i10_) c_i9_ +//│ ║ l.1276: c_99_ = c_add_ (c_mul_ c_i9_ c_i10_) c_i9_ //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ c_99_: error | ('a -> 'a & 'b -> 'b & 'c -> 'c & 'd -> 'd) -> ('a & 'b & 'c & 'd) -> error @@ -1392,10 +1380,10 @@ def c_succ_ n = fun f -> fun x -> n f (f x) //│ where //│ 'b <: 'a -> 'a & 'c -> 'a)) //│ = [Function: c_succ1] -//│ c_succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'c -> 'e +//│ c_succ_: 'a -> (forall 'b. 'b -> (forall 'c 'd 'e. 'e -> 'd //│ where -//│ 'a <: 'b -> 'd -> 'e -//│ 'b <: 'c -> 'd)) +//│ 'a <: 'b -> 'c -> 'd +//│ 'b <: 'e -> 'c)) //│ = [Function: c_succ_1] def c_add_ n m = m c_succ_ n @@ -1419,12 +1407,12 @@ def c_i2_ = c_succ_ c_i1 //│ where //│ 'b <: 'a -> 'a & 'c -> 'a) //│ = [Function: c_i22] -//│ c_i2_: 'a -> (forall 'b 'c 'd. 'd -> 'c +//│ c_i2_: 'a -> (forall 'b 'c 'd. 'c -> 'b //│ where -//│ 'a <: 'd -> 'b +//│ 'a <: 'c -> 'd //│ forall 'e. 'e -> (forall 'f 'g. 'f -> 'g //│ where -//│ 'e <: 'f -> 'g) <: 'a -> 'b -> 'c) +//│ 'e <: 'f -> 'g) <: 'a -> 'd -> 'b) //│ = [Function: c_i2_1] // let c_i3 = c_succ c_i2 @@ -1453,23 +1441,23 @@ c_i5_ = c_add_ c_i3_ c_i2 //│ 'b <: 'c -> 'e -> 'f //│ forall 'h. 'h -> (forall 'i 'j 'k. 'k -> 'j //│ where -//│ 'h <: 'k -> 'i //│ forall 'l. 'l -> (forall 'a 'm. 'm -> 'a //│ where -//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j) <: 'c -> 'd -> 'f) +//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j +//│ 'h <: 'k -> 'i) <: 'c -> 'd -> 'f) //│ ╙── //│ c_i5_: 'b //│ where -//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'f -> 'e +//│ 'b :> forall 'c. 'c -> (forall 'd 'e 'f 'g. 'g -> 'f //│ where -//│ 'c <: 'f -> 'd & 'f -> 'g -//│ forall 'h. 'h -> (forall 'i 'j 'k. 'k -> 'j +//│ 'c <: 'g -> 'e & 'g -> 'd +//│ forall 'h. 'h -> (forall 'i 'j 'k. 'i -> 'k //│ where -//│ 'h <: 'k -> 'i +//│ 'h <: 'i -> 'j //│ forall 'l. 'l -> (forall 'a 'm. 'm -> 'a //│ where -//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'i -> 'j) <: 'c -> 'g -> 'e -//│ 'b <: 'c -> 'd -> 'e) +//│ 'l <: 'a -> 'a & 'm -> 'a) <: 'h -> 'j -> 'k) <: 'c -> 'd -> 'f +//│ 'b <: 'c -> 'e -> 'f) //│ = [Function (anonymous)] //│ constrain calls : 140 //│ annoying calls : 0 @@ -1479,10 +1467,10 @@ c_i5_ = c_add_ c_i3_ c_i2 :e c_i10_ = c_mul_ c_i5_ c_i2_ //│ ╔══[ERROR] Inferred recursive type: nothing -//│ ║ l.743: type Fint = forall 'a. ('a -> 'a) -> ('a -> 'a) +//│ ║ l.731: type Fint = forall 'a. ('a -> 'a) -> ('a -> 'a) //│ ╙── ^^ -//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c. ?c -> ?a -> ?b <: (forall ?d. ?d) -> ?e` exceeded recursion depth limit (250) -//│ ║ l.1480: c_i10_ = c_mul_ c_i5_ c_i2_ +//│ ╔══[ERROR] Subtyping constraint of the form `forall ?a ?b ?c. ?b -> ?a -> ?c <: (forall ?d. ?d) -> ?e` exceeded recursion depth limit (250) +//│ ║ l.1468: c_i10_ = c_mul_ c_i5_ c_i2_ //│ ║ ^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ c_i10_: error diff --git a/shared/src/test/diff/mlf-examples/ex_predicative.mls b/shared/src/test/diff/mlf-examples/ex_predicative.mls index 708c5a75ba..ca9d05090b 100644 --- a/shared/src/test/diff/mlf-examples/ex_predicative.mls +++ b/shared/src/test/diff/mlf-examples/ex_predicative.mls @@ -286,15 +286,14 @@ def t_ y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) //│ ╔══[ERROR] Inferred recursive type: ? -> (((forall 'a. nothing -> ('a -> 'a | ?) | ?) | 'b) -> ((forall 'c. ? -> 'c -> 'c) -> nothing & 'd) & (forall 'e 'f. ((forall 'c. ? -> 'c -> 'c) -> (forall 'c. ? -> 'c -> 'c) -> 'e & 'f) -> (? -> 'f | 'e) | 'd | ?) -> ((forall 'c. ? -> 'c -> 'c) -> nothing & 'b)) //│ ║ l.285: def t_ y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) three //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ t_: ('a -> ('b -> 'c & 'd & 'e)) -> ('a & 'f) -> ((forall 'g. anything -> 'g -> 'g) -> ((forall 'h 'i 'j 'k 'l 'm. ((forall 'g. anything -> 'g -> 'g) -> ('j -> 'h -> 'm & 'k)) -> ('k -> (forall 'n. ('m -> 'n & 'j) -> 'h -> 'n) -> 'l) -> ('i -> 'i | 'l) | 'o | 'd) -> (forall 'p 'q. ((forall 'g. anything -> 'g -> 'g) -> (forall 'g. anything -> 'g -> 'g) -> 'p & 'q) -> (anything -> 'q | 'p) | 'r | 's | 't | 'c | 'u) -> 'b & 'v) & 't) -> ('c | 'u) +//│ t_: ('a -> ((forall 'b 'c. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'b & 'c) -> (anything -> 'c | 'b) | 'e | 'f | 'g | 'h | 'i | 'j) -> 'i & 'k)) -> ('a & 'l) -> ((forall 'd. anything -> 'd -> 'd) -> ((forall 'm 'n 'o 'p 'q 'r. ((forall 'd. anything -> 'd -> 'd) -> ('m -> 'r -> 'p & 'q)) -> ('q -> (forall 's. ('p -> 's & 'm) -> 'r -> 's) -> 'n) -> ('o -> 'o | 'n) | 't | 'k) -> (forall 'u 'v. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'u & 'v) -> (anything -> 'v | 'u) | 'w | 'g | 'h | 'i | 'j) -> 'f & 'x) & 'h) -> ('i | 'j) //│ where -//│ 'b :> forall 'w 'x. ((forall 'g. anything -> 'g -> 'g) -> (forall 'g. anything -> 'g -> 'g) -> 'w & 'x & 'w) -> (anything -> 'x | 'w) | 's | 't | 'c | 'u -//│ <: (forall 'g. anything -> 'g -> 'g) -> nothing -> nothing -> anything -//│ 's :> forall 'y 'z. ((forall 'a1 'b1. anything -> 'a1 -> ('b1 -> 'b1 | 'a1) | 'v) -> (forall 'c1. ('b -> 'c1 & 'o) -> ('b & 'r) -> 'c1) -> 'y) -> ('z -> 'z | 'y) | 'c -//│ <: (forall 'g. anything -> 'g -> 'g) -> (nothing -> nothing -> anything & 'd1) -//│ 'c <: (forall 'g. anything -> 'g -> 'g) -> ((forall 'h 'i 'j 'k 'l 'm. ((forall 'g. anything -> 'g -> 'g) -> ('j -> 'h -> 'm & 'k)) -> ('k -> (forall 'n. ('m -> 'n & 'j) -> 'h -> 'n) -> 'l) -> ('i -> 'i | 'l) | 'o | 'd) -> (forall 'e1 'f1. ((forall 'g. anything -> 'g -> 'g) -> (forall 'g. anything -> 'g -> 'g) -> 'e1 & 'f1) -> (anything -> 'f1 | 'e1) | 'r | 's | 't | 'c | 'u) -> 'b & 'v & 'd1) -//│ 'd1 <: (forall 'g1. anything -> anything -> 'g1 -> 'g1) -> (forall 'h1. 'h1 -> anything -> 'h1) -> (forall 'i1 'j1. ('i1 -> 'j1) -> 'i1 -> 'j1) -> ('a -> ('b & 'r & 'k1) -> 'c) -> 'f -> ('s -> ((forall 'g. anything -> 'g -> 'g) -> ((forall 'h 'i 'j 'k 'l 'm. ((forall 'g. anything -> 'g -> 'g) -> ('j -> 'h -> 'm & 'k)) -> ('k -> (forall 'n. ('m -> 'n & 'j) -> 'h -> 'n) -> 'l) -> ('i -> 'i | 'l) | 'o | 'd) -> (forall 'l1 'm1. ((forall 'g. anything -> 'g -> 'g) -> (forall 'g. anything -> 'g -> 'g) -> 'm1 & 'l1) -> (anything -> 'l1 | 'm1) | 'r | 's | 't | 'c | 'u) -> 'b & 'v) & 'u) & (forall 'n1 'o1. ((forall 'g. anything -> 'g -> 'g) -> (forall 'g. anything -> 'g -> 'g) -> 'n1 & 'o1) -> (anything -> 'o1 | 'n1) | 't | 'c | 'u) -> 's) & (forall 'h 'j 'k 'l 'm. ((forall 'g. anything -> 'g -> 'g) -> ('j -> 'h -> 'm & 'k)) -> ('k -> (forall 'n. ('m -> 'n & 'j) -> 'h -> 'n) -> 'l) -> 'l) -> (forall 'p1. ((forall 'g. anything -> 'g -> 'g) -> (forall 'g. anything -> 'g -> 'g) -> 'p1) -> 'p1) -> (forall 'h1. 'h1 -> anything -> 'h1) -> anything & 'd -> 'e -//│ 'e <: (forall 'q1 'r1. ((forall 'g. anything -> 'g -> 'g) -> (forall 'g. anything -> 'g -> 'g) -> 'q1 & 'r1) -> (anything -> 'r1 | 'q1) | 'k1 | 's | 't | 'c | 'u) -> 'c +//│ 'f :> forall 'y 'z. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'y & 'z & 'y) -> (anything -> 'z | 'y) | 'g | 'h | 'i | 'j +//│ <: (forall 'd. anything -> 'd -> 'd) -> nothing -> nothing -> anything +//│ 'g :> forall 'a1 'b1. ((forall 'c1 'd1. anything -> 'c1 -> ('d1 -> 'd1 | 'c1) | 'x) -> (forall 'e1. ('f -> 'e1 & 't) -> ('f & 'w) -> 'e1) -> 'a1) -> ('b1 -> 'b1 | 'a1) | 'i +//│ <: (forall 'd. anything -> 'd -> 'd) -> (nothing -> nothing -> anything & 'f1) +//│ 'i <: (forall 'd. anything -> 'd -> 'd) -> ((forall 'm 'n 'o 'p 'q 'r. ((forall 'd. anything -> 'd -> 'd) -> ('m -> 'r -> 'p & 'q)) -> ('q -> (forall 's. ('p -> 's & 'm) -> 'r -> 's) -> 'n) -> ('o -> 'o | 'n) | 't | 'k) -> (forall 'g1 'h1. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'g1 & 'h1) -> (anything -> 'h1 | 'g1) | 'w | 'g | 'h | 'i | 'j) -> 'f & 'x & 'f1) +//│ 'f1 <: (forall 'i1. anything -> anything -> 'i1 -> 'i1) -> (forall 'j1. 'j1 -> anything -> 'j1) -> (forall 'k1 'l1. ('k1 -> 'l1) -> 'k1 -> 'l1) -> ('a -> ('f & 'w & 'e) -> 'i) -> 'l -> ('g -> ((forall 'd. anything -> 'd -> 'd) -> ((forall 'm 'n 'o 'p 'q 'r. ((forall 'd. anything -> 'd -> 'd) -> ('m -> 'r -> 'p & 'q)) -> ('q -> (forall 's. ('p -> 's & 'm) -> 'r -> 's) -> 'n) -> ('o -> 'o | 'n) | 't | 'k) -> (forall 'm1 'n1. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'm1 & 'n1) -> (anything -> 'n1 | 'm1) | 'w | 'g | 'h | 'i | 'j) -> 'f & 'x) & 'j) & (forall 'o1 'p1. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'o1 & 'p1) -> (anything -> 'p1 | 'o1) | 'h | 'i | 'j) -> 'g) & (forall 'm 'n 'p 'q 'r. ((forall 'd. anything -> 'd -> 'd) -> ('m -> 'r -> 'p & 'q)) -> ('q -> (forall 's. ('p -> 's & 'm) -> 'r -> 's) -> 'n) -> 'n) -> (forall 'q1. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'q1) -> 'q1) -> (forall 'j1. 'j1 -> anything -> 'j1) -> anything & 'k -> (forall 'r1 's1. ((forall 'd. anything -> 'd -> 'd) -> (forall 'd. anything -> 'd -> 'd) -> 'r1 & 's1) -> (anything -> 's1 | 'r1) | 'e | 'g | 'h | 'i | 'j) -> 'i //│ = [Function: t_2] :ResetFuel @@ -312,11 +311,14 @@ t id succ 0 :stats :e // * Strange recursive error. The bounds graph is quite large and hard to analyze for debugging... t_ id succ 0 -//│ ╔══[ERROR] Inferred recursive type: nothing +//│ ╔══[ERROR] Inferred recursive type: 'a +//│ where +//│ 'a :> int -> int +//│ <: (forall 'b 'c 'd 'e 'f 'g 'h. ((forall 'i. ? -> 'i -> 'i) -> (forall 'i. ? -> 'i -> 'i) -> 'c & 'h) -> (? -> 'h | 'c) | ? | ((forall 'i. ? -> 'i -> 'i) -> (forall 'i. ? -> 'i -> 'i) -> 'e & 'f & 'b) -> (? -> 'b | 'e | 'f) | nothing -> ('d -> 'd | ?) | 'j | nothing -> ('g -> 'g | ?)) -> nothing //│ ║ l.285: def t_ y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) three -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.314: t_ id succ 0 +//│ ║ l.313: t_ id succ 0 //│ ║ ^^^^^^^^^^ //│ ╟── function of type `?a -> ?b` is not an instance of type `int` //│ ║ l.285: def t_ y = (fun h -> h (h (h (fun x -> y)))) (fun f -> fun n -> n (fun v -> k2) k app (fun g -> fun x -> n (f (n (fun p -> fun s -> s (p k2) (fun f -> fun x -> f (p k2 f x))) (fun s -> s k2 k2) k) g) x)) three @@ -325,7 +327,7 @@ t_ id succ 0 //│ = 6 //│ constrain calls : 352 //│ annoying calls : 0 -//│ subtyping calls : 2632 +//│ subtyping calls : 3162 // let t (z : 0) = let x = (fun (y: ['t > 0] 'a -> 't) -> y z y) in x x;; @@ -357,7 +359,7 @@ def t (z: nothing) = let x = fun (y: forall 't. 'a -> 't) -> y z in x x :e (fun x -> x x) (fun x -> x x) //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.358: (fun x -> x x) (fun x -> x x) +//│ ║ l.360: (fun x -> x x) (fun x -> x x) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error @@ -370,22 +372,21 @@ def t (z: nothing) = let x = fun (y: forall 't. 'a -> 't) -> y z in x x :e (fun f -> fun x -> f (f x)) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) -//│ ╔══[ERROR] Inferred recursive type: 'a +//│ ╔══[ERROR] Inferred recursive type: ? -> ? -> ? +//│ ║ l.374: (fun f -> fun x -> f (f x)) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) +//│ ╙── ^^^ +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> anything -> anything -> 'a -//│ ╙── -//│ res: 'a -> 'b -//│ where -//│ 'a :> 'b -//│ 'b :> anything -> anything -> 'a +//│ 'a :> anything -> 'b +//│ 'b :> anything -> 'a //│ = [Function (anonymous)] :RecursiveTypes (fun f -> fun x -> f (f x)) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) -//│ res: 'a -> 'b +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> 'b -//│ 'b :> anything -> anything -> 'a +//│ 'a :> anything -> 'b +//│ 'b :> anything -> 'a //│ = [Function (anonymous)] :NoRecursiveTypes @@ -395,22 +396,21 @@ def t (z: nothing) = let x = fun (y: forall 't. 'a -> 't) -> y z in x x :e (fun two -> fun k -> two two k) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) -//│ ╔══[ERROR] Inferred recursive type: 'a +//│ ╔══[ERROR] Inferred recursive type: ? -> ? -> ? +//│ ║ l.398: (fun two -> fun k -> two two k) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) +//│ ╙── ^^^ +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> anything -> anything -> 'a -//│ ╙── -//│ res: 'a -> 'b -//│ where -//│ 'a :> 'b -//│ 'b :> anything -> anything -> 'a +//│ 'a :> anything -> 'b +//│ 'b :> anything -> 'a //│ = [Function (anonymous)] :RecursiveTypes (fun two -> fun k -> two two k) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) -//│ res: 'a -> 'b +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> 'b -//│ 'b :> anything -> anything -> 'a +//│ 'a :> anything -> 'b +//│ 'b :> anything -> 'a //│ = [Function (anonymous)] :NoRecursiveTypes @@ -418,26 +418,28 @@ def t (z: nothing) = let x = fun (y: forall 't. 'a -> 't) -> y z in x x // * Rank 5, causes huge blowup. Do not attempt to output skeletons ! // (fun two k -> two two two k)(fun f -x -> f (f x)) (fun v w -> v) +// :d :e (fun two -> fun k -> two two two k) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) -//│ ╔══[ERROR] Inferred recursive type: 'a +//│ ╔══[ERROR] Inferred recursive type: ? -> 'a //│ where -//│ 'a :> anything -> 'a -//│ ╙── -//│ res: 'a -> 'b +//│ 'a :> ? -> (? | 'a) +//│ ║ l.423: (fun two -> fun k -> two two two k) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) +//│ ╙── ^^^ +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> 'b | 'c -//│ 'b :> anything -> 'c -//│ 'c :> anything -> 'a | 'b +//│ 'a :> forall 'c. anything -> 'b | 'c +//│ 'b :> forall 'c. 'c +//│ 'c :> anything -> ('a | 'b) //│ = [Function (anonymous)] :RecursiveTypes (fun two -> fun k -> two two two k) (fun f -> fun x -> f (f x)) (fun v -> fun w -> v) -//│ res: 'a -> 'b +//│ res: 'a -> anything -> 'b //│ where -//│ 'a :> 'b | 'c -//│ 'b :> anything -> 'c -//│ 'c :> anything -> 'a | 'b +//│ 'a :> forall 'c. 'c +//│ 'c :> anything -> ('a | 'b) +//│ 'b :> forall 'c. 'c //│ = [Function (anonymous)] :NoRecursiveTypes @@ -448,43 +450,43 @@ def t (z: nothing) = let x = fun (y: forall 't. 'a -> 't) -> y z in x x //│ where //│ forall 'c. 'c //│ where -//│ forall 'd 'e 'f. 'd -> ('e -> 'f +//│ forall 'd 'e 'f. 'e -> ('f -> 'd //│ where -//│ 'd <: (forall 'g. 'g +//│ 'e <: (forall 'g. 'g //│ where -//│ 'd <: 'e -> 'g) -> 'f) <: (forall 'h. 'h +//│ 'e <: 'f -> 'g) -> 'd) <: (forall 'h. 'h //│ where //│ forall 'i. 'i //│ where -//│ forall 'd 'j 'k. 'd -> ('j -> 'k +//│ forall 'j 'k 'e. 'e -> ('j -> 'k //│ where -//│ 'd <: (forall 'l. 'l +//│ 'e <: (forall 'l. 'l //│ where -//│ 'd <: 'j -> 'l) -> 'k) <: (forall 'd 'm 'n. 'd -> ('m -> 'n +//│ 'e <: 'j -> 'l) -> 'k) <: (forall 'm 'n 'e. 'e -> ('m -> 'n //│ where -//│ 'd <: (forall 'o. 'o +//│ 'e <: (forall 'o. 'o //│ where -//│ 'd <: 'm -> 'o) -> 'n)) -> 'i <: (forall 'p. 'p -> anything -> 'p) -> 'h) -> 'c <: (forall 'q. 'q +//│ 'e <: 'm -> 'o) -> 'n)) -> 'i <: (forall 'p. 'p -> anything -> 'p) -> 'h) -> 'c <: (forall 'q. 'q //│ where //│ forall 'c. 'c //│ where -//│ forall 'd 'e 'f. 'd -> ('e -> 'f +//│ forall 'd 'e 'f. 'e -> ('f -> 'd //│ where -//│ 'd <: (forall 'g. 'g +//│ 'e <: (forall 'g. 'g //│ where -//│ 'd <: 'e -> 'g) -> 'f) <: (forall 'h. 'h +//│ 'e <: 'f -> 'g) -> 'd) <: (forall 'h. 'h //│ where //│ forall 'i. 'i //│ where -//│ forall 'd 'j 'k. 'd -> ('j -> 'k +//│ forall 'j 'k 'e. 'e -> ('j -> 'k //│ where -//│ 'd <: (forall 'l. 'l +//│ 'e <: (forall 'l. 'l //│ where -//│ 'd <: 'j -> 'l) -> 'k) <: (forall 'd 'm 'n. 'd -> ('m -> 'n +//│ 'e <: 'j -> 'l) -> 'k) <: (forall 'm 'n 'e. 'e -> ('m -> 'n //│ where -//│ 'd <: (forall 'o. 'o +//│ 'e <: (forall 'o. 'o //│ where -//│ 'd <: 'm -> 'o) -> 'n)) -> 'i <: (forall 'p. 'p -> anything -> 'p) -> 'h) -> 'c <: 'a -> 'q) -> 'b +//│ 'e <: 'm -> 'o) -> 'n)) -> 'i <: (forall 'p. 'p -> anything -> 'p) -> 'h) -> 'c <: 'a -> 'q) -> 'b //│ = [Function (anonymous)] :NoConstrainedTypes @@ -500,15 +502,15 @@ def t (z: nothing) = let x = fun (y: forall 't. 'a -> 't) -> y z in x x (fun h -> (fun x -> h (x x)) (fun x -> h (x x))) (fun f -> fun n -> n (fun v -> fun x -> fun y -> y) k (fun f -> fun x -> f x)(fun g -> fun x -> n (f (n (fun p -> fun s -> s (p (fun x -> fun y -> y)) (fun f -> fun x -> f (p (fun x -> fun y -> y) f x))) (fun s -> s (fun f -> fun x -> x) (fun f -> fun x -> x)) k) g) x)) (fun f -> fun x -> f (f x)) //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a <: (('b & 'c & 'd) -> ('e | 'd) | 'f) -> 'c -> 'd & (forall 'g 'h 'i 'j 'k. ((forall 'l. ? -> 'l -> 'l) -> 'k & (forall 'm. ? -> 'm -> 'm) -> 'h -> 'i -> 'j) -> ('k -> (forall 'n. ('j -> 'n & 'h) -> 'i -> 'n) -> 'g) -> 'g) -> (forall 'o. ((forall 'p. ? -> 'p -> 'p) -> (forall 'q. ? -> 'q -> 'q) -> 'o) -> 'o) -> (forall 'r. 'r -> ? -> 'r) -> 'a & (forall 's. ? -> ? -> 's -> 's) -> (forall 'r. 'r -> ? -> 'r) -> (forall 't 'u. ('t -> 'u) -> 't -> 'u) -> (('b -> 'e & 'f & 'v) -> ('c & 'd) -> 'd) -> 'v -> 'f -//│ ║ l.500: (fun h -> (fun x -> h (x x)) (fun x -> h (x x))) (fun f -> fun n -> n (fun v -> fun x -> fun y -> y) k (fun f -> fun x -> f x)(fun g -> fun x -> n (f (n (fun p -> fun s -> s (p (fun x -> fun y -> y)) (fun f -> fun x -> f (p (fun x -> fun y -> y) f x))) (fun s -> s (fun f -> fun x -> x) (fun f -> fun x -> x)) k) g) x)) (fun f -> fun x -> f (f x)) +//│ 'a <: (('b & 'c & 'd) -> ('e | 'd) | 'f) -> 'c -> 'd & (forall 'g 'h 'i 'j 'k. ((forall 'l. ? -> 'l -> 'l) -> 'h & (forall 'm. ? -> 'm -> 'm) -> 'k -> 'g -> 'i) -> ('h -> (forall 'n. ('i -> 'n & 'k) -> 'g -> 'n) -> 'j) -> 'j) -> (forall 'o. ((forall 'p. ? -> 'p -> 'p) -> (forall 'q. ? -> 'q -> 'q) -> 'o) -> 'o) -> (forall 'r. 'r -> ? -> 'r) -> 'a & (forall 's. ? -> ? -> 's -> 's) -> (forall 'r. 'r -> ? -> 'r) -> (forall 't 'u. ('t -> 'u) -> 't -> 'u) -> (('b -> 'e & 'f & 'v) -> ('c & 'd) -> 'd) -> 'v -> 'f +//│ ║ l.502: (fun h -> (fun x -> h (x x)) (fun x -> h (x x))) (fun f -> fun n -> n (fun v -> fun x -> fun y -> y) k (fun f -> fun x -> f x)(fun g -> fun x -> n (f (n (fun p -> fun s -> s (p (fun x -> fun y -> y)) (fun f -> fun x -> f (p (fun x -> fun y -> y) f x))) (fun s -> s (fun f -> fun x -> x) (fun f -> fun x -> x)) k) g) x)) (fun f -> fun x -> f (f x)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.500: (fun h -> (fun x -> h (x x)) (fun x -> h (x x))) (fun f -> fun n -> n (fun v -> fun x -> fun y -> y) k (fun f -> fun x -> f x)(fun g -> fun x -> n (f (n (fun p -> fun s -> s (p (fun x -> fun y -> y)) (fun f -> fun x -> f (p (fun x -> fun y -> y) f x))) (fun s -> s (fun f -> fun x -> x) (fun f -> fun x -> x)) k) g) x)) (fun f -> fun x -> f (f x)) +//│ ║ l.502: (fun h -> (fun x -> h (x x)) (fun x -> h (x x))) (fun f -> fun n -> n (fun v -> fun x -> fun y -> y) k (fun f -> fun x -> f x)(fun g -> fun x -> n (f (n (fun p -> fun s -> s (p (fun x -> fun y -> y)) (fun f -> fun x -> f (p (fun x -> fun y -> y) f x))) (fun s -> s (fun f -> fun x -> x) (fun f -> fun x -> x)) k) g) x)) (fun f -> fun x -> f (f x)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.500: (fun h -> (fun x -> h (x x)) (fun x -> h (x x))) (fun f -> fun n -> n (fun v -> fun x -> fun y -> y) k (fun f -> fun x -> f x)(fun g -> fun x -> n (f (n (fun p -> fun s -> s (p (fun x -> fun y -> y)) (fun f -> fun x -> f (p (fun x -> fun y -> y) f x))) (fun s -> s (fun f -> fun x -> x) (fun f -> fun x -> x)) k) g) x)) (fun f -> fun x -> f (f x)) +//│ ║ l.502: (fun h -> (fun x -> h (x x)) (fun x -> h (x x))) (fun f -> fun n -> n (fun v -> fun x -> fun y -> y) k (fun f -> fun x -> f x)(fun g -> fun x -> n (f (n (fun p -> fun s -> s (p (fun x -> fun y -> y)) (fun f -> fun x -> f (p (fun x -> fun y -> y) f x))) (fun s -> s (fun f -> fun x -> x) (fun f -> fun x -> x)) k) g) x)) (fun f -> fun x -> f (f x)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ res: error diff --git a/shared/src/test/diff/mlf-examples/ex_selfapp.mls b/shared/src/test/diff/mlf-examples/ex_selfapp.mls index e3655e3662..16d071a205 100644 --- a/shared/src/test/diff/mlf-examples/ex_selfapp.mls +++ b/shared/src/test/diff/mlf-examples/ex_selfapp.mls @@ -73,9 +73,9 @@ rec def foo xs = elim xs ( rec def foo = fun xs -> case xs of Nil -> Nil, Cons -> Cons (xs.head + 1, foo (foo xs.tail)) -//│ foo: 'a -> 'tail +//│ foo: 'a -> (Nil | 'b) //│ where -//│ 'tail :> (Cons[int] with {tail: 'tail}) | Nil +//│ 'b :> Cons[int] with {tail: Nil | 'b} //│ 'a <: (Cons[?] with {head: int, tail: 'a}) | Nil //│ = [Function: foo2] // * An simplified version, easier to type check, just for the record @@ -83,9 +83,9 @@ rec def foo = fun xs -> case xs of { Nil -> Nil | Cons -> Cons (xs.head + 1, foo xs.tail) } -//│ foo: 'a -> 'tail +//│ foo: 'a -> (Nil | 'b) //│ where -//│ 'tail :> (Cons[int] with {tail: 'tail}) | Nil +//│ 'b :> Cons[int] with {tail: Nil | 'b} //│ 'a <: (Cons[?] with {head: int, tail: 'a}) | Nil //│ = [Function: foo3] :NoRecursiveTypes @@ -133,6 +133,11 @@ def build_ = fun g -> g (fun x -> fun xs -> Cons (x, xs)) Nil :e // * Expected: List is a structural equirecursive types and recursive types are disabled build_ : forall 'a. (forall 'b. (('a -> 'b -> 'b) -> 'b -> 'b)) -> List['a] +//│ ╔══[ERROR] Inferred recursive type: 'a +//│ where +//│ 'a :> Cons[?] with {tail: forall 'a. Nil | 'a} +//│ ║ l.130: def build_ = fun g -> g (fun x -> fun xs -> Cons (x, xs)) Nil +//│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing type ascription; a type annotation may be required //│ ║ l.135: build_ : forall 'a. (forall 'b. (('a -> 'b -> 'b) -> 'b -> 'b)) -> List['a] //│ ║ ^^^^^^ @@ -144,21 +149,22 @@ build_ : forall 'a. (forall 'b. (('a -> 'b -> 'b) -> 'b -> 'b)) -> List['a] def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> Cons (x, xs)) Nil //│ ╔══[ERROR] Inferred recursive type: 'a //│ where -//│ 'a :> Cons[?]\tail & {tail: Nil | 'a} -//│ ╙── +//│ 'a :> Cons[?] with {tail: forall 'a. Nil | 'a} +//│ ║ l.149: def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> Cons (x, xs)) Nil +//│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Cyclic-looking constraint while typing application; a type annotation may be required -//│ ║ l.144: def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> Cons (x, xs)) Nil +//│ ║ l.149: def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> Cons (x, xs)) Nil //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ build: (forall 'b. ('head -> 'b -> 'b) -> 'b -> 'b) -> (Nil | error | 'a) //│ where -//│ 'a :> Cons['head] with {tail: Nil | 'a} +//│ 'a :> Cons['head] with {tail: forall 'a. Nil | 'a} //│ = [Function: build] :RecursiveTypes def build = fun (g: forall 'b. ('a -> 'b -> 'b) -> 'b -> 'b) -> g (fun x -> fun xs -> Cons (x, xs)) Nil //│ build: (forall 'b. ('head -> 'b -> 'b) -> 'b -> 'b) -> (Nil | 'a) //│ where -//│ 'a :> Cons['head] with {tail: Nil | 'a} +//│ 'a :> Cons['head] with {tail: forall 'a. Nil | 'a} //│ = [Function: build1] :NoRecursiveTypes @@ -207,7 +213,7 @@ rec def foldr = fun k -> fun z -> fun xs -> //│ ╔══[ERROR] Inferred recursive type: 'a //│ where //│ 'a <: {head: ?, tail: Cons[?] & 'a} -//│ ║ l.204: case xs of +//│ ║ l.210: case xs of //│ ╙── ^^ //│ foldr: ('head -> 'a -> 'a) -> 'a -> 'b -> 'a //│ where @@ -265,7 +271,7 @@ rec def k = fun x -> fun (xs: Ba) -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ <: k: //│ int -> Ba -> Ba //│ ╔══[ERROR] Type error in binding of lambda expression -//│ ║ l.263: rec def k = fun x -> fun (xs: Ba) -> fun c -> fun n -> c (x + 1) (xs k z c n) +//│ ║ l.269: rec def k = fun x -> fun (xs: Ba) -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'b` leaks out of its scope //│ ║ l.100: type Ba = forall 'b. (int -> 'b -> 'b) -> 'b -> 'b @@ -277,7 +283,7 @@ rec def k = fun x -> fun (xs: Ba) -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ ║ l.101: type Baa = forall 'a 'b. ('a -> 'b -> 'b) -> 'b -> 'b //│ ╙── ^^ //│ ╔══[ERROR] Type error in def definition -//│ ║ l.263: rec def k = fun x -> fun (xs: Ba) -> fun c -> fun n -> c (x + 1) (xs k z c n) +//│ ║ l.269: rec def k = fun x -> fun (xs: Ba) -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type variable `'b` leaks out of its scope //│ ║ l.100: type Ba = forall 'b. (int -> 'b -> 'b) -> 'b -> 'b @@ -302,10 +308,10 @@ k = k_ //│ <: k: //│ int -> Ba -> Ba //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.298: k = k_ +//│ ║ l.304: k = k_ //│ ║ ^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b -> ?b)` does not match type `'b` -//│ ║ l.223: def z_ = fun c -> fun n -> n +//│ ║ l.229: def z_ = fun c -> fun n -> n //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type variable: //│ ║ l.100: type Ba = forall 'b. (int -> 'b -> 'b) -> 'b -> 'b @@ -340,10 +346,10 @@ def bfoo xs = build (foldr k z xs) :e def bfoo_ xs = build_ (foldr k_ z_ xs) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.341: def bfoo_ xs = build_ (foldr k_ z_ xs) +//│ ║ l.347: def bfoo_ xs = build_ (foldr k_ z_ xs) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── function of type `?b -> (forall ?c. ?c -> ?c)` does not match type `Cons[?a] | Nil` -//│ ║ l.223: def z_ = fun c -> fun n -> n +//│ ║ l.229: def z_ = fun c -> fun n -> n //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.33: type List[a] = Nil | Cons[a] @@ -357,9 +363,9 @@ def bfoo_ xs = build_ (foldr k_ z_ xs) //│ = [Function: bfoo_] // * Alt (requires :RecursiveTypes): def bfoo_ xs = build_ (foldr k z_ xs) -//│ bfoo_: 'a -> 'tail +//│ bfoo_: 'a -> (Nil | 'b) //│ where -//│ 'tail :> (Cons[int] with {tail: 'tail}) | Nil +//│ 'b :> Cons[int] with {tail: forall 'b. Nil | 'b} //│ 'a <: (Cons[?] with {head: int, tail: 'a}) | Nil //│ = [Function: bfoo_1] @@ -401,9 +407,9 @@ bfoo lst0 //│ } bfoo_ lst0 -//│ res: 'tail +//│ res: Nil | 'a //│ where -//│ 'tail :> (Cons[int] with {tail: 'tail}) | Nil +//│ 'a :> Cons[int] with {tail: forall 'a. Nil | 'a} //│ = Cons { //│ head: 1, //│ tail: Cons { head: 2, tail: Cons { head: 4, tail: [Cons] } } @@ -430,10 +436,10 @@ def k = fun x -> fun (xs: Baa) -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ <: k: //│ int -> Baa -> Baa //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.428: def k = fun x -> fun (xs: Baa) -> fun c -> fun n -> c (x + 1) (xs k z c n) +//│ ║ l.434: def k = fun x -> fun (xs: Baa) -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `int` does not match type `'a` -//│ ║ l.428: def k = fun x -> fun (xs: Baa) -> fun c -> fun n -> c (x + 1) (xs k z c n) +//│ ║ l.434: def k = fun x -> fun (xs: Baa) -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type variable: //│ ║ l.101: type Baa = forall 'a 'b. ('a -> 'b -> 'b) -> 'b -> 'b @@ -454,10 +460,10 @@ k = k_ // nope //│ <: k: //│ int -> Baa -> Baa //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.452: k = k_ // nope +//│ ║ l.458: k = k_ // nope //│ ║ ^^^^^^ //│ ╟── operator application of type `int` does not match type `'a` -//│ ║ l.446: def k_ = fun x -> fun xs -> fun c -> fun n -> c (x + 1) (xs k z c n) +//│ ║ l.452: def k_ = fun x -> fun xs -> fun c -> fun n -> c (x + 1) (xs k z c n) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type variable: //│ ║ l.101: type Baa = forall 'a 'b. ('a -> 'b -> 'b) -> 'b -> 'b @@ -484,16 +490,15 @@ k = k_ // nope //│ 'a <: 'c -> 'd //│ 'c :> 'e -> 'f -> 'd //│ <: 'g -//│ 'e :> 'k_ +//│ 'e :> int -> 'g -> 'e -> 'f -> 'd //│ <: int -> 'a & ? -> 'b -> 'b //│ 'b :> 'e -> 'f -> 'd //│ <: 'g -//│ 'k_ :> int -> 'g -> 'e -> 'f -> 'd +//│ 'g <: (int -> 'g -> 'e -> 'f -> 'd) -> Baa -> 'h //│ 'd :> 'e -> 'f -> 'd //│ <: 'c & 'h -//│ 'g <: 'k_ -> Baa -> 'h //│ 'h <: 'e -> (Baa | 'f) -> 'c -//│ ║ l.470: rec def k_ = fun x -> fun xs -> fun c -> fun n -> c (x + 1) (xs k_ z c n) +//│ ║ l.476: rec def k_ = fun x -> fun xs -> fun c -> fun n -> c (x + 1) (xs k_ z c n) //│ ╙── ^^^^^^^^^ //│ 'k_ //│ where @@ -501,7 +506,7 @@ k = k_ // nope //│ <: k: //│ int -> Baa -> Baa //│ ╔══[ERROR] Cyclic-looking constraint while typing def definition; a type annotation may be required -//│ ║ l.481: k = k_ // nope +//│ ║ l.487: k = k_ // nope //│ ║ ^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ = [Function: k_1] diff --git a/shared/src/test/diff/mlf-examples/ex_validate.mls b/shared/src/test/diff/mlf-examples/ex_validate.mls index 51ab627abb..85d6c4459c 100644 --- a/shared/src/test/diff/mlf-examples/ex_validate.mls +++ b/shared/src/test/diff/mlf-examples/ex_validate.mls @@ -938,13 +938,11 @@ rec def id_ x = if true then x else id_ id_ x //│ ║ l.927: rec def id_ x = if true then x else id_ id_ x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ id_: 'id_ +//│ id_: 'a -> 'b //│ where -//│ 'id_ :> 'a -> 'b -//│ 'a :> 'id_ +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id_ -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = [Function: id_] // let rec (id:sid) x = if true then x else id id x @@ -963,32 +961,30 @@ rec def id x = if true then x else id id x //│ <: 'c //│ 'c :> 'b -> 'c //│ <: 'a -//│ ║ l.958: rec def id x = if true then x else id id x +//│ ║ l.956: rec def id x = if true then x else id id x //│ ╙── ^^^^^ -//│ 'id +//│ 'a -> 'b //│ where -//│ 'id :> 'a -> 'b -//│ 'a :> 'id +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ <: id: //│ Sid //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.958: rec def id x = if true then x else id id x +//│ ║ l.956: rec def id x = if true then x else id id x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.958: rec def id x = if true then x else id id x +//│ ║ l.956: rec def id x = if true then x else id id x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'a` is not a function //│ ║ l.765: type Sid = forall 'a. 'a -> 'a //│ ║ ^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.958: rec def id x = if true then x else id id x +//│ ║ l.956: rec def id x = if true then x else id id x //│ ║ ^^^^^^^ //│ ╟── from reference: -//│ ║ l.958: rec def id x = if true then x else id id x +//│ ║ l.956: rec def id x = if true then x else id id x //│ ║ ^ //│ ╟── Note: quantified type variable 'a is defined at: //│ ║ l.765: type Sid = forall 'a. 'a -> 'a diff --git a/shared/src/test/diff/mlf-examples/merge_regression_min.mls b/shared/src/test/diff/mlf-examples/merge_regression_min.mls index 52140e4eb4..4f17ce611b 100644 --- a/shared/src/test/diff/mlf-examples/merge_regression_min.mls +++ b/shared/src/test/diff/mlf-examples/merge_regression_min.mls @@ -6,13 +6,11 @@ def choose: 'a -> 'a -> 'a //│ = rec def id1 x = choose x (id1 id1 x) -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = //│ choose is not implemented @@ -40,13 +38,11 @@ id1 id //│ id1 and choose are not implemented rec def id1 x = choose x (id1 id1 x) -//│ id1: 'id1 +//│ id1: 'a -> 'b //│ where -//│ 'id1 :> 'a -> 'b -//│ 'a :> 'id1 +//│ 'a :> 'a -> 'b //│ <: 'b -//│ 'b :> 'id1 -//│ <: 'a -> 'b +//│ 'b := 'a -> 'b //│ = //│ choose is not implemented diff --git a/shared/src/test/diff/mlscript/Addable.mls b/shared/src/test/diff/mlscript/Addable.mls index e08d70a831..c6deb71626 100644 --- a/shared/src/test/diff/mlscript/Addable.mls +++ b/shared/src/test/diff/mlscript/Addable.mls @@ -101,12 +101,10 @@ addNTimes n 12 rec def addNTimes a n = if n <= 0 then 0 else a.Add addNTimes a (n - 1) -//│ addNTimes: 'addNTimes +//│ addNTimes: 'a -> int -> 'b //│ where -//│ 'addNTimes :> 'a -> int -> 'b //│ 'a <: Addable['A] -//│ 'A :> 'addNTimes -//│ <: 'a -> int -> 'b +//│ 'A := 'a -> int -> 'b //│ 'b :> 0 addNTimes n 12 diff --git a/shared/src/test/diff/mlscript/ByNameByValue.mls b/shared/src/test/diff/mlscript/ByNameByValue.mls index e47b2b32ee..3e87640778 100644 --- a/shared/src/test/diff/mlscript/ByNameByValue.mls +++ b/shared/src/test/diff/mlscript/ByNameByValue.mls @@ -142,15 +142,15 @@ rec def xs = Cons 0 (Cons 1 xs) //│ return Cons1(0)(Cons1(1)(xs())); //│ }; //│ // End of generated code -//│ xs: 'tail +//│ xs: 'a //│ where -//│ 'tail :> Cons[0 | 1] with {head: 0, tail: Cons[0 | 1] with {head: 1, tail: 'tail}} +//│ 'a :> Cons[0 | 1] with {head: 0, tail: Cons[0 | 1] with {head: 1, tail: forall 'a. 'a}} //│ = [Function: xs] :re xs -//│ res: 'tail +//│ res: 'a //│ where -//│ 'tail :> Cons[0 | 1] with {head: 0, tail: Cons[0 | 1] with {head: 1, tail: 'tail}} +//│ 'a :> Cons[0 | 1] with {head: 0, tail: Cons[0 | 1] with {head: 1, tail: forall 'a. 'a}} //│ Runtime error: //│ RangeError: Maximum call stack size exceeded diff --git a/shared/src/test/diff/mlscript/David2.mls b/shared/src/test/diff/mlscript/David2.mls index 58944c9abe..cc4e599152 100644 --- a/shared/src/test/diff/mlscript/David2.mls +++ b/shared/src/test/diff/mlscript/David2.mls @@ -18,9 +18,9 @@ addOne1 x = case x of { rec def loopy() = Integer { value = 1; addOne = fun x -> loopy() } -//│ loopy: () -> 'a +//│ loopy: () -> (Integer with {addOne: 'addOne, value: 1}) //│ where -//│ 'a :> Integer with {addOne: anything -> 'a, value: 1} +//│ 'addOne :> anything -> (Integer with {addOne: 'addOne, value: 1}) //│ = [Function: loopy] addOne1 (loopy()) @@ -38,9 +38,9 @@ res : Integer // * so it could be anything; example: funny = loopy() with { value = "oops!" } -//│ funny: 'a\value & {value: "oops!"} +//│ funny: Integer with {addOne: 'addOne, value: "oops!"} //│ where -//│ 'a :> Integer with {addOne: anything -> 'a, value: 1} +//│ 'addOne :> anything -> (Integer with {addOne: 'addOne, value: 1}) //│ = Integer { value: 'oops!', addOne: [Function: addOne] } addOne1 funny @@ -70,15 +70,15 @@ addOne1 (Integer { value = 1; addOne = id }) // * Now for properly closing the loop with a constructor for Integer: rec def mkInteger value = Integer { value; addOne = fun n -> mkInteger (n.value + 1) } -//│ mkInteger: int -> 'a +//│ mkInteger: int -> (Integer with {addOne: 'addOne}) //│ where -//│ 'a :> Integer with {addOne: {value: int} -> 'a} +//│ 'addOne :> {value: int} -> (Integer with {addOne: 'addOne}) //│ = [Function: mkInteger] n = mkInteger 42 -//│ n: 'a +//│ n: Integer with {addOne: 'addOne} //│ where -//│ 'a :> Integer with {addOne: {value: int} -> 'a} +//│ 'addOne :> {value: int} -> (Integer with {addOne: 'addOne}) //│ = Integer { value: 42, addOne: [Function: addOne] } n : Integer @@ -102,9 +102,9 @@ def mkInteger2: int -> Integer def mkInteger2 = mkInteger //│ mkInteger2: int -> Integer //│ = -//│ int -> 'a +//│ int -> (Integer with {addOne: 'addOne}) //│ where -//│ 'a :> Integer with {addOne: {value: int} -> 'a} +//│ 'addOne :> {value: int} -> (Integer with {addOne: 'addOne}) //│ <: mkInteger2: //│ int -> Integer //│ = [Function: mkInteger2] @@ -119,9 +119,9 @@ def mkInteger_oops: (int & 'a) -> (Integer & { value: 'a }) :e rec def mkInteger_oops value = Integer { value; addOne = fun n -> mkInteger_oops (n.value + 1) } -//│ int -> 'a +//│ int -> (Integer with {addOne: 'addOne}) //│ where -//│ 'a :> Integer with {addOne: {value: int} -> 'a} +//│ 'addOne :> {value: int} -> (Integer with {addOne: 'addOne}) //│ <: mkInteger_oops: //│ (int & 'a) -> (Integer\addOne with {value: 'a}) //│ ╔══[ERROR] Type mismatch in def definition: @@ -140,7 +140,9 @@ rec def mkInteger_oops value = Integer { value; addOne = fun n -> mkInteger_oops :precise-rec-typing rec def mkInteger_oops value = Integer { value; addOne = fun n -> mkInteger_oops (n.value + 1) } -//│ (int & 'value) -> (Integer with {addOne: {value: int} -> (Integer with {addOne: nothing}), value: 'value}) +//│ (int & 'value) -> (Integer with {addOne: forall 'a. {value: int} -> 'a, value: 'value}) +//│ where +//│ 'a :> Integer with {addOne: forall 'a. {value: int} -> 'a} //│ <: mkInteger_oops: //│ (int & 'a) -> (Integer\addOne with {value: 'a}) //│ = [Function: mkInteger_oops1] @@ -155,9 +157,9 @@ def mkIntegerPrecise value = Integer { value; addOne = addOne1 } //│ = [Function: mkIntegerPrecise] def mkIntegerPrecise value = Integer { value; addOne = fun n -> mkInteger (n.value + 1) } -//│ mkIntegerPrecise: (int & 'value) -> (Integer with {addOne: forall 'a. {value: int} -> 'a, value: 'value}) +//│ mkIntegerPrecise: (int & 'value) -> (Integer with {addOne: forall 'addOne. 'addOne, value: 'value}) //│ where -//│ 'a :> Integer with {addOne: {value: int} -> 'a} +//│ 'addOne :> {value: int} -> (Integer with {addOne: 'addOne}) //│ = [Function: mkIntegerPrecise1] def mkIntegerPrecise value = Integer { value; addOne = fun (n: Integer) -> mkInteger2 (n.value + 1) } @@ -200,19 +202,19 @@ def mkIntegerPrecise3: (int & 'a) -> (Integer & { value: 'a }) // * Note: works with :precise-rec-typing when typing mkInteger :e def mkIntegerPrecise3 = mkInteger -//│ int -> 'a +//│ int -> (Integer with {addOne: 'addOne}) //│ where -//│ 'a :> Integer with {addOne: {value: int} -> 'a} +//│ 'addOne :> {value: int} -> (Integer with {addOne: 'addOne}) //│ <: mkIntegerPrecise3: //│ (int & 'a) -> (Integer\addOne with {value: 'a}) //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.202: def mkIntegerPrecise3 = mkInteger +//│ ║ l.204: def mkIntegerPrecise3 = mkInteger //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `int` does not match type `'a` //│ ║ l.72: rec def mkInteger value = Integer { value; addOne = fun n -> mkInteger (n.value + 1) } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.196: def mkIntegerPrecise3: (int & 'a) -> (Integer & { value: 'a }) +//│ ║ l.198: def mkIntegerPrecise3: (int & 'a) -> (Integer & { value: 'a }) //│ ╙── ^^ //│ = [Function: mkIntegerPrecise3] @@ -220,10 +222,10 @@ def mkIntegerPrecise3 = mkInteger :e addOne1 (Stri { value = ""; addOne = error }) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.221: addOne1 (Stri { value = ""; addOne = error }) +//│ ║ l.223: addOne1 (Stri { value = ""; addOne = error }) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Stri & {addOne: ?addOne, value: ?value}` does not match type `Integer & ?a` -//│ ║ l.221: addOne1 (Stri { value = ""; addOne = error }) +//│ ║ l.223: addOne1 (Stri { value = ""; addOne = error }) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.11: addOne1 x = case x of { @@ -255,9 +257,9 @@ def mkStr: string -> Stri rec def mkStr value = Stri { value; addOne = fun s -> mkStr (concat s.value "1") } //│ mkStr: string -> Stri //│ = -//│ string -> 'a +//│ string -> (Stri with {addOne: 'addOne}) //│ where -//│ 'a :> Stri with {addOne: {value: string} -> 'a} +//│ 'addOne :> {value: string} -> (Stri with {addOne: 'addOne}) //│ <: mkStr: //│ string -> Stri //│ = [Function: mkStr] diff --git a/shared/src/test/diff/mlscript/DavidB.mls b/shared/src/test/diff/mlscript/DavidB.mls index 68486a5a2d..e6c3e3f8cc 100644 --- a/shared/src/test/diff/mlscript/DavidB.mls +++ b/shared/src/test/diff/mlscript/DavidB.mls @@ -151,31 +151,31 @@ rec def foo xs = case xs of let tmp = foo xs.t.t in if xs.h then Con { h = xs.t.h; t = tmp } else tmp, N -> xs -//│ foo: 'a -> 'T +//│ foo: 'a -> 'b //│ where -//│ 'a <: Con[?, ?] & {h: bool, t: {h: 'h, t: 'a}} | N & 'T -//│ 'T :> Con['h, 'T] +//│ 'a <: Con[?, ?] & {h: bool, t: {h: 'h, t: 'a}} | N & 'b +//│ 'b :> Con['h, 'b] //│ = [Function: foo1] rec def foo xs = case xs of Con -> if xs.h then Con { h = xs.t.h; t = foo xs.t.t } else foo xs.t.t, N -> xs -//│ foo: 'a -> 'T +//│ foo: 'a -> 'b //│ where -//│ 'a <: Con[?, ?] & {h: bool, t: {h: 'h, t: 'a}} | N & 'T -//│ 'T :> Con['h, 'T] +//│ 'a <: Con[?, ?] & {h: bool, t: {h: 'h, t: 'a}} | N & 'b +//│ 'b :> Con['h, 'b] //│ = [Function: foo2] foo (N{}) -//│ res: 'T +//│ res: 'a //│ where -//│ 'T :> Con[nothing, 'T] | N +//│ 'a :> Con[nothing, 'a] | N //│ = N {} foo (Con{ h = true; t = Con{ h = 0; t = N{} } }) -//│ res: 'T +//│ res: 'a //│ where -//│ 'T :> Con[0, 'T] | N +//│ 'a :> Con[0, 'a] | N //│ = Con { h: 0, t: N {} } def inf: Con[true, Con[0, 'I]] as 'I @@ -185,9 +185,9 @@ def inf: Con[true, Con[0, 'I]] as 'I //│ = foo inf -//│ res: 'T +//│ res: 'a //│ where -//│ 'T :> Con[0, 'T] +//│ 'a :> Con[0, 'a] //│ = //│ inf is not implemented @@ -195,12 +195,12 @@ foo inf rec def foo2 xs = case xs of Con -> if xs.h then Con { h = xs.t.h; t = foo xs.t.t } else foo xs.t.t, N -> N{} -//│ foo2: (Con[?, ?] & {h: bool, t: {h: 'h, t: 'a & 'b}} | N) -> (Con['h, forall 'T. 'T] | N | 'T0) +//│ foo2: (Con[?, ?] & {h: bool, t: {h: 'h, t: 'a & 'b}} | N) -> (Con['h, forall 'c. 'c | 'd] | N | 'e) //│ where -//│ 'T :> Con['h0, 'T] | 'c -//│ 'b <: Con[?, ?] & {h: bool, t: {h: 'h1, t: 'b}} | N & 'T0 -//│ 'T0 :> Con['h1, 'T0] -//│ 'a <: Con[?, ?] & {h: bool, t: {h: 'h0, t: 'a}} | N & 'c +//│ 'c :> Con['h0, 'c | 'd] | 'd +//│ 'b <: Con[?, ?] & {h: bool, t: {h: 'h1, t: 'b}} | N & 'e +//│ 'e :> Con['h1, 'e] +//│ 'a <: Con[?, ?] & {h: bool, t: {h: 'h0, t: 'a}} | N & 'd //│ = [Function: foo21] diff --git a/shared/src/test/diff/mlscript/ExprProb.mls b/shared/src/test/diff/mlscript/ExprProb.mls index 29a7f4ab23..4425dbc979 100644 --- a/shared/src/test/diff/mlscript/ExprProb.mls +++ b/shared/src/test/diff/mlscript/ExprProb.mls @@ -281,12 +281,13 @@ rec def prettier11 k ev e = case e of { } //│ prettier11: ('a -> string) -> ('rhs -> number) -> 'b -> string //│ where -//│ 'b <: Add[?] & {lhs: 'c, rhs: 'rhs & 'b} | Lit | 'a & ~#Add & ~#Lit -//│ 'c <: Add[?] & {lhs: 'c, rhs: 'c} | Lit | 'a & ~#Add & ~#Lit +//│ 'b <: Add[?] & {lhs: Add[?] & 'c | Lit | 'a & ~#Add & ~#Lit, rhs: 'rhs & 'b} | Lit | 'a & ~#Add & ~#Lit +//│ 'c <: {lhs: 'd, rhs: 'd} +//│ 'd <: Add[?] & 'c | Lit | 'a & ~#Add & ~#Lit //│ = [Function: prettier11] //│ constrain calls : 191 //│ annoying calls : 0 -//│ subtyping calls : 746 +//│ subtyping calls : 799 // Doesn't make much sense, but generates very ugly type unless aggressively simplified: :stats @@ -297,14 +298,15 @@ rec def prettier12 k ev e = case e of { in if ev e == 0 then tmp else concat tmp (pretty1 k e.rhs) | _ -> k e } -//│ prettier12: ('a -> string & 'b -> 'c) -> ('d -> number) -> (Add[?] & {lhs: 'e, rhs: 'f} & 'd | Lit | 'b & ~#Add & ~#Lit) -> (string | 'c) +//│ prettier12: ('a -> string & 'b -> 'c) -> ('d -> number) -> (Add[?] & {lhs: Add[?] & 'e | Lit | 'a & ~#Add & ~#Lit, rhs: 'f} & 'd | Lit | 'b & ~#Add & ~#Lit) -> (string | 'c) //│ where //│ 'f <: Add[?] & {lhs: 'f, rhs: 'f} | Lit | 'a & ~#Add & ~#Lit -//│ 'e <: Add[?] & {lhs: 'e, rhs: 'e} | Lit | 'a & ~#Add & ~#Lit +//│ 'e <: {lhs: 'g, rhs: 'g} +//│ 'g <: Add[?] & 'e | Lit | 'a & ~#Add & ~#Lit //│ = [Function: prettier12] //│ constrain calls : 166 //│ annoying calls : 0 -//│ subtyping calls : 788 +//│ subtyping calls : 841 :stats @@ -404,16 +406,19 @@ rec def prettier22 k ev = prettier12 (fun x -> case x of { | Nega -> concat "-" (prettier22 k ev x.arg) | _ -> k x }) ev -//│ prettier22: ('a -> string) -> ('b -> number) -> 'arg -> string -//│ where -//│ 'b <: {lhs: 'c, rhs: 'd} -//│ 'd <: Add[?] & {lhs: 'd, rhs: 'd} | Lit | Nega[?] & {arg: 'arg} | 'a & ~#Add & ~#Lit & ~#Nega -//│ 'c <: Add[?] & {lhs: 'c, rhs: 'c} | Lit | Nega[?] & {arg: 'arg} | 'a & ~#Add & ~#Lit & ~#Nega -//│ 'arg <: Add[?] & 'b | Lit | (Nega[?] & {arg: 'arg} | 'a & ~#Nega) & ~#Add & ~#Lit +//│ prettier22: ('a -> string) -> ('b -> number) -> (Add[?] & 'b | Lit | 'c & ~#Add & ~#Lit) -> string +//│ where +//│ 'b <: {lhs: Add[?] & 'd | Lit | 'e & ~#Add & ~#Lit, rhs: 'f} +//│ 'f <: Add[?] & {lhs: 'f, rhs: 'f} | Lit | Nega[?] & {arg: 'arg} | 'a & ~#Add & ~#Lit & ~#Nega +//│ 'd <: {lhs: 'g, rhs: 'g} +//│ 'g <: Add[?] & 'd | Lit | 'e & ~#Add & ~#Lit +//│ 'e <: Nega[?] & {arg: 'arg} | 'a & ~#Nega +//│ 'arg <: Add[?] & 'b | Lit | 'c & ~#Add & ~#Lit +//│ 'c <: Nega[?] & {arg: 'arg} | 'a & ~#Nega //│ = [Function: prettier22] //│ constrain calls : 208 //│ annoying calls : 0 -//│ subtyping calls : 1025 +//│ subtyping calls : 1063 @@ -471,13 +476,15 @@ prettier2 done //│ = [Function (anonymous)] prettier22 done -//│ res: ('a -> number) -> 'arg -> string +//│ res: ('a -> number) -> (Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit) -> string //│ where -//│ 'a <: {lhs: 'b, rhs: 'c} -//│ 'c <: Add[?] & {lhs: 'c, rhs: 'c} | Lit | 'd -//│ 'b <: Add[?] & {lhs: 'b, rhs: 'b} | Lit | 'd +//│ 'a <: {lhs: Add[?] & 'c | Lit | 'd & ~#Add & ~#Lit, rhs: 'e} +//│ 'e <: Add[?] & {lhs: 'e, rhs: 'e} | Lit | Nega[?] & {arg: 'arg} +//│ 'c <: {lhs: 'f, rhs: 'f} +//│ 'f <: Add[?] & 'c | Lit | 'd & ~#Add & ~#Lit //│ 'd <: Nega[?] & {arg: 'arg} -//│ 'arg <: Add[?] & 'a | Lit | 'd & ~#Add & ~#Lit +//│ 'arg <: Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit +//│ 'b <: Nega[?] & {arg: 'arg} //│ = [Function (anonymous)] :stats @@ -496,12 +503,15 @@ prettier2 done (eval1 done) prettier22 done (eval1 done) -//│ res: 'arg -> string -//│ where -//│ 'arg <: Add[?] & {lhs: 'a, rhs: 'a} & 'b | Lit | 'c & ~#Add & ~#Lit -//│ 'b <: Add[?] & {lhs: 'b, rhs: 'b} | Lit -//│ 'a <: Add[?] & {lhs: 'a, rhs: 'a} | Lit | 'c -//│ 'c <: Nega[?] & {arg: 'arg} +//│ res: (Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit) -> string +//│ where +//│ 'a <: {lhs: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit, rhs: 'd} & 'e +//│ 'e <: Add[?] & {lhs: 'e, rhs: 'e} | Lit +//│ 'd <: Add[?] & {lhs: 'd, rhs: 'd} | Lit | Nega[?] & {arg: 'arg} +//│ 'c <: {lhs: 'f, rhs: 'f} +//│ 'f <: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit +//│ 'b <: Nega[?] & {arg: 'arg} +//│ 'arg <: Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit //│ = [Function (anonymous)] // * TODO could probably merge `c` and `b` here! @@ -532,13 +542,16 @@ prettier2 done (eval2 done) d2 prettier22 done (eval2 done) prettier22 done (eval2 done) e2 prettier22 done (eval2 done) d2 -//│ res: 'arg -> string -//│ where -//│ 'arg <: Add[?] & {lhs: 'a, rhs: 'a} & 'b | Lit | 'c & ~#Add & ~#Lit -//│ 'b <: Add[?] & {lhs: 'b, rhs: 'b} | Lit | 'd & ~#Add & ~#Lit -//│ 'd <: Nega[?] & {arg: 'b} -//│ 'a <: Add[?] & {lhs: 'a, rhs: 'a} | Lit | 'c -//│ 'c <: Nega[?] & {arg: 'arg} +//│ res: (Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit) -> string +//│ where +//│ 'a <: {lhs: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit, rhs: 'd} & 'e +//│ 'e <: Add[?] & {lhs: 'e, rhs: 'e} | Lit | 'f & ~#Add & ~#Lit +//│ 'f <: Nega[?] & {arg: 'e} +//│ 'd <: Add[?] & {lhs: 'd, rhs: 'd} | Lit | Nega[?] & {arg: 'arg} +//│ 'c <: {lhs: 'g, rhs: 'g} +//│ 'g <: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit +//│ 'b <: Nega[?] & {arg: 'arg} +//│ 'arg <: Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit //│ = [Function (anonymous)] //│ res: string //│ = '1-123' @@ -546,7 +559,7 @@ prettier22 done (eval2 done) d2 //│ = '-1' //│ constrain calls : 1178 //│ annoying calls : 390 -//│ subtyping calls : 10194 +//│ subtyping calls : 10299 @@ -563,7 +576,7 @@ eval1 done e2 //│ ║ l.+1: eval1 done e2 //│ ║ ^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` does not match type `nothing` -//│ ║ l.368: def nega arg = Nega { arg } +//│ ║ l.370: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.4: def done x = case x of {} @@ -618,7 +631,7 @@ prettier2 done (eval1 done) e2 //│ ║ l.+1: prettier2 done (eval1 done) e2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` does not match type `nothing` -//│ ║ l.368: def nega arg = Nega { arg } +//│ ║ l.370: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.4: def done x = case x of {} @@ -690,7 +703,7 @@ prettier2 done eval2 e1 //│ ║ l.18: def lit val = Lit { val } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.377: | _ -> k x +//│ ║ l.379: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.262: else if ev e.rhs == 0 then prettier1 k ev e.lhs @@ -728,7 +741,7 @@ prettier2 done eval2 e2 //│ ║ l.18: def lit val = Lit { val } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.377: | _ -> k x +//│ ║ l.379: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.262: else if ev e.rhs == 0 then prettier1 k ev e.lhs @@ -763,10 +776,10 @@ prettier2 done eval2 d2 //│ ║ l.+1: prettier2 done eval2 d2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` is not a function -//│ ║ l.368: def nega arg = Nega { arg } +//│ ║ l.370: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.377: | _ -> k x +//│ ║ l.379: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.262: else if ev e.rhs == 0 then prettier1 k ev e.lhs diff --git a/shared/src/test/diff/mlscript/ExprProb2.mls b/shared/src/test/diff/mlscript/ExprProb2.mls index 4638c57f69..f607f6a637 100644 --- a/shared/src/test/diff/mlscript/ExprProb2.mls +++ b/shared/src/test/diff/mlscript/ExprProb2.mls @@ -75,13 +75,12 @@ eval1_fixed_1 e1 rec def eval1_fixed_2 = eval1f (fun x -> eval1f eval1_fixed_2 x) -//│ eval1_fixed_2: (Add[?] & 'a | (Lit with {val: 'val})) -> (int | 'val) +//│ eval1_fixed_2: (Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit\val & {val: 'val}) -> (int | 'val) //│ where -//│ 'a <: { -//│ lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, -//│ rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit -//│ } -//│ 'rhs <: Add[?] & 'a | Lit +//│ 'lhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'lhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit +//│ 'rhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'rhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit //│ = [Function: eval1_fixed_2] eval1_fixed_2 e1 @@ -94,14 +93,20 @@ def eval1_fixed_3 = let fixed fixed = eval1f (fun x -> eval1f (fixed fixed) x) in fixed fixed! //│ eval1_fixed_3: (Add[?] & { -//│ lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, -//│ rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit -//│ } | (Lit with {val: 'val})) -> (int | 'val) -//│ where -//│ 'rhs <: Add[?] & { -//│ lhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit, -//│ rhs: Add[?] & {lhs: 'rhs, rhs: 'rhs} | Lit +//│ lhs: Add[?] & { +//│ lhs: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit, +//│ rhs: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit +//│ } | Lit, +//│ rhs: Add[?] & { +//│ lhs: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit, +//│ rhs: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit //│ } | Lit +//│ } | Lit\val & {val: 'val}) -> (int | 'val) +//│ where +//│ 'lhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'lhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit +//│ 'rhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'rhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit //│ = [Function: eval1_fixed_3] eval1_fixed_3 e1 @@ -170,11 +175,9 @@ def fix f = let fixed = fun x -> f (fun v -> (x x) v) in fixed fixed! //│ = [Function: fix] def eval2_fixed_2 = fix eval2f -//│ eval2_fixed_2: (Add[?] & 'a | (Lit with {val: 'val}) | Nega[?] & 'b) -> (int | 'val) +//│ eval2_fixed_2: (Add[?] & {lhs: 'a, rhs: 'a} | (Lit with {val: 'val}) | Nega[?] & {arg: 'a}) -> (int | 'val) //│ where -//│ 'a <: {lhs: 'c, rhs: 'c} -//│ 'c <: Add[?] & 'a | Lit | Nega[?] & 'b -//│ 'b <: {arg: 'c} +//│ 'a <: Add[?] & {lhs: 'a, rhs: 'a} | Lit | Nega[?] & {arg: 'a} //│ = [Function: eval2_fixed_2] :stats @@ -213,10 +216,12 @@ rec def eval1_fixed = eval1f (eval1f eval1_fixed) //│ return eval1f(eval1f(eval1_fixed())); //│ }; //│ // End of generated code -//│ eval1_fixed: (Add[?] & 'a | Lit\val & {val: 'val}) -> (int | 'val) +//│ eval1_fixed: (Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit\val & {val: 'val}) -> (int | 'val) //│ where -//│ 'a <: {lhs: Add[?] & 'b | Lit, rhs: Add[?] & 'b | Lit} -//│ 'b <: {lhs: Add[?] & 'a | Lit, rhs: Add[?] & 'a | Lit} +//│ 'lhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'lhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit +//│ 'rhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'rhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit //│ = [Function: eval1_fixed] :re @@ -226,10 +231,12 @@ eval1_fixed e1 //│ RangeError: Maximum call stack size exceeded rec def eval1_fixed() = eval1f (eval1f (eval1_fixed())) -//│ eval1_fixed: () -> (Add[?] & 'a | Lit\val & {val: 'val}) -> (int | 'val) +//│ eval1_fixed: () -> (Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit\val & {val: 'val}) -> (int | 'val) //│ where -//│ 'a <: {lhs: Add[?] & 'b | Lit, rhs: Add[?] & 'b | Lit} -//│ 'b <: {lhs: Add[?] & 'a | Lit, rhs: Add[?] & 'a | Lit} +//│ 'lhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'lhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit +//│ 'rhs <: Add[?] & {lhs: 'lhs0, rhs: 'rhs0} | Lit +//│ 'rhs0 <: Add[?] & {lhs: 'lhs, rhs: 'rhs} | Lit //│ = [Function: eval1_fixed1] :re @@ -352,7 +359,7 @@ eval2_broken eval2_broken! e2 //│ ║ l.20: | Add -> eval1 eval1 e.lhs + eval1 eval1 e.rhs //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── from field selection: -//│ ║ l.338: | Nega -> e.arg +//│ ║ l.345: | Nega -> e.arg //│ ╙── ^^^^^ //│ res: error | int @@ -369,13 +376,13 @@ fix eval2f_oops e2 //│ ║ l.+1: fix eval2f_oops e2 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` does not match type `Add[?] & ?c | Lit & ?d` -//│ ║ l.168: def fix f = let fixed = fun x -> f (fun v -> (x x) v) in fixed fixed! +//│ ║ l.173: def fix f = let fixed = fun x -> f (fun v -> (x x) v) in fixed fixed! //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.18: def eval1 eval1 e = case e of { //│ ║ ^ //│ ╟── from reference: -//│ ║ l.360: def eval2f_oops eval2 e = case e of { +//│ ║ l.367: def eval2f_oops eval2 e = case e of { //│ ╙── ^ //│ res: error diff --git a/shared/src/test/diff/mlscript/ExprProb_Inv.mls b/shared/src/test/diff/mlscript/ExprProb_Inv.mls index b2b77fce0c..40e3cb75a7 100644 --- a/shared/src/test/diff/mlscript/ExprProb_Inv.mls +++ b/shared/src/test/diff/mlscript/ExprProb_Inv.mls @@ -283,12 +283,13 @@ rec def prettier11 k ev e = case e of { } //│ prettier11: ('a -> string) -> ('rhs -> number) -> 'b -> string //│ where -//│ 'b <: (Add[?] with {lhs: 'c, rhs: 'rhs & 'b}) | Lit | 'a & ~#Add & ~#Lit -//│ 'c <: (Add[?] with {lhs: 'c, rhs: 'c}) | Lit | 'a & ~#Add & ~#Lit +//│ 'b <: (Add[?] with {lhs: Add[?] & 'c | Lit | 'a & ~#Add & ~#Lit, rhs: 'rhs & 'b}) | Lit | 'a & ~#Add & ~#Lit +//│ 'c <: {lhs: 'd, rhs: 'd} +//│ 'd <: Add[?] & 'c | Lit | 'a & ~#Add & ~#Lit //│ = [Function: prettier11] //│ constrain calls : 191 //│ annoying calls : 0 -//│ subtyping calls : 782 +//│ subtyping calls : 820 // Doesn't make much sense, but generates very ugly type unless aggressively simplified: :stats @@ -299,14 +300,15 @@ rec def prettier12 k ev e = case e of { in if ev e == 0 then tmp else concat tmp (pretty1 k e.rhs) | _ -> k e } -//│ prettier12: ('a -> string & 'b -> 'c) -> ('d -> number) -> (Add[?]\lhs\rhs & {lhs: 'e, rhs: 'f} & 'd | Lit | 'b & ~#Add & ~#Lit) -> (string | 'c) +//│ prettier12: ('a -> string & 'b -> 'c) -> ('d -> number) -> ((Add[?] with {lhs: Add[?] & 'e | Lit | 'a & ~#Add & ~#Lit, rhs: 'f}) & 'd | Lit | 'b & ~#Add & ~#Lit) -> (string | 'c) //│ where -//│ 'f <: Add[?]\lhs\rhs & {lhs: 'f, rhs: 'f} | Lit | 'a & ~#Add & ~#Lit -//│ 'e <: Add[?]\lhs\rhs & {lhs: 'e, rhs: 'e} | Lit | 'a & ~#Add & ~#Lit +//│ 'f <: (Add[?] with {lhs: 'f, rhs: 'f}) | Lit | 'a & ~#Add & ~#Lit +//│ 'e <: {lhs: 'g, rhs: 'g} +//│ 'g <: Add[?] & 'e | Lit | 'a & ~#Add & ~#Lit //│ = [Function: prettier12] //│ constrain calls : 166 //│ annoying calls : 0 -//│ subtyping calls : 833 +//│ subtyping calls : 877 :stats @@ -406,16 +408,19 @@ rec def prettier22 k ev = prettier12 (fun x -> case x of { | Nega -> concat "-" (prettier22 k ev x.arg) | _ -> k x }) ev -//│ prettier22: ('a -> string) -> ('b -> number) -> 'arg -> string -//│ where -//│ 'b <: {lhs: 'c, rhs: 'd} -//│ 'd <: Add[?]\lhs\rhs & {lhs: 'd, rhs: 'd} | Lit | Nega[?] & {arg: 'arg} | 'a & ~#Add & ~#Lit & ~#Nega -//│ 'c <: Add[?]\lhs\rhs & {lhs: 'c, rhs: 'c} | Lit | Nega[?] & {arg: 'arg} | 'a & ~#Add & ~#Lit & ~#Nega -//│ 'arg <: Add[?] & 'b | Lit | (Nega[?] & {arg: 'arg} | 'a & ~#Nega) & ~#Add & ~#Lit +//│ prettier22: ('a -> string) -> ('b -> number) -> (Add[?] & 'b | Lit | 'c & ~#Add & ~#Lit) -> string +//│ where +//│ 'b <: {lhs: Add[?] & 'd | Lit | 'e & ~#Add & ~#Lit, rhs: 'f} +//│ 'f <: Add[?]\lhs\rhs & {lhs: 'f, rhs: 'f} | Lit | Nega[?] & {arg: 'arg} | 'a & ~#Add & ~#Lit & ~#Nega +//│ 'd <: {lhs: 'g, rhs: 'g} +//│ 'g <: Add[?] & 'd | Lit | 'e & ~#Add & ~#Lit +//│ 'e <: Nega[?] & {arg: 'arg} | 'a & ~#Nega +//│ 'arg <: Add[?] & 'b | Lit | 'c & ~#Add & ~#Lit +//│ 'c <: Nega[?] & {arg: 'arg} | 'a & ~#Nega //│ = [Function: prettier22] //│ constrain calls : 208 //│ annoying calls : 0 -//│ subtyping calls : 1053 +//│ subtyping calls : 1083 @@ -473,13 +478,15 @@ prettier2 done //│ = [Function (anonymous)] prettier22 done -//│ res: ('a -> number) -> 'arg -> string +//│ res: ('a -> number) -> (Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit) -> string //│ where -//│ 'a <: {lhs: 'b, rhs: 'c} -//│ 'c <: Add[?]\lhs\rhs & {lhs: 'c, rhs: 'c} | Lit | 'd -//│ 'b <: Add[?]\lhs\rhs & {lhs: 'b, rhs: 'b} | Lit | 'd +//│ 'a <: {lhs: Add[?] & 'c | Lit | 'd & ~#Add & ~#Lit, rhs: 'e} +//│ 'e <: Add[?]\lhs\rhs & {lhs: 'e, rhs: 'e} | Lit | Nega[?] & {arg: 'arg} +//│ 'c <: {lhs: 'f, rhs: 'f} +//│ 'f <: Add[?] & 'c | Lit | 'd & ~#Add & ~#Lit //│ 'd <: Nega[?] & {arg: 'arg} -//│ 'arg <: Add[?] & 'a | Lit | 'd & ~#Add & ~#Lit +//│ 'arg <: Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit +//│ 'b <: Nega[?] & {arg: 'arg} //│ = [Function (anonymous)] :stats @@ -497,12 +504,15 @@ prettier2 done (eval1 done) prettier22 done (eval1 done) -//│ res: 'arg -> string -//│ where -//│ 'arg <: Add[?] & {lhs: 'a, rhs: 'a} & 'b | Lit | 'c & ~#Add & ~#Lit -//│ 'b <: (Add[?] with {lhs: 'b, rhs: 'b}) | Lit -//│ 'a <: (Add[?] with {lhs: 'a, rhs: 'a}) | Lit | 'c -//│ 'c <: Nega[?] & {arg: 'arg} +//│ res: (Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit) -> string +//│ where +//│ 'a <: {lhs: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit, rhs: 'd} & 'e +//│ 'e <: (Add[?] with {lhs: 'e, rhs: 'e}) | Lit +//│ 'd <: (Add[?] with {lhs: 'd, rhs: 'd}) | Lit | Nega[?] & {arg: 'arg} +//│ 'c <: {lhs: 'f, rhs: 'f} +//│ 'f <: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit +//│ 'b <: Nega[?] & {arg: 'arg} +//│ 'arg <: Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit //│ = [Function (anonymous)] // TODO could probably merge `a` and `b` here! @@ -533,13 +543,16 @@ prettier2 done (eval2 done) d2 prettier22 done (eval2 done) prettier22 done (eval2 done) e2 prettier22 done (eval2 done) d2 -//│ res: 'arg -> string -//│ where -//│ 'arg <: Add[?] & {lhs: 'a, rhs: 'a} & 'b | Lit | 'c & ~#Add & ~#Lit -//│ 'b <: (Add[?] with {lhs: 'b, rhs: 'b}) | Lit | 'd & ~#Add & ~#Lit -//│ 'd <: Nega[?] & {arg: 'b} -//│ 'a <: (Add[?] with {lhs: 'a, rhs: 'a}) | Lit | 'c -//│ 'c <: Nega[?] & {arg: 'arg} +//│ res: (Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit) -> string +//│ where +//│ 'a <: {lhs: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit, rhs: 'd} & 'e +//│ 'e <: (Add[?] with {lhs: 'e, rhs: 'e}) | Lit | 'f & ~#Add & ~#Lit +//│ 'f <: Nega[?] & {arg: 'e} +//│ 'd <: (Add[?] with {lhs: 'd, rhs: 'd}) | Lit | Nega[?] & {arg: 'arg} +//│ 'c <: {lhs: 'g, rhs: 'g} +//│ 'g <: Add[?] & 'c | Lit | 'b & ~#Add & ~#Lit +//│ 'b <: Nega[?] & {arg: 'arg} +//│ 'arg <: Add[?] & 'a | Lit | 'b & ~#Add & ~#Lit //│ = [Function (anonymous)] //│ res: string //│ = '1-123' @@ -547,7 +560,7 @@ prettier22 done (eval2 done) d2 //│ = '-1' //│ constrain calls : 1178 //│ annoying calls : 390 -//│ subtyping calls : 10266 +//│ subtyping calls : 10358 @@ -564,7 +577,7 @@ eval1 done e2 //│ ║ l.+1: eval1 done e2 //│ ║ ^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` does not match type `nothing` -//│ ║ l.370: def nega arg = Nega { arg } +//│ ║ l.372: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.4: def done x = case x of {} @@ -619,7 +632,7 @@ prettier2 done (eval1 done) e2 //│ ║ l.+1: prettier2 done (eval1 done) e2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` does not match type `nothing` -//│ ║ l.370: def nega arg = Nega { arg } +//│ ║ l.372: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.4: def done x = case x of {} @@ -640,7 +653,7 @@ prettier2 done eval2 //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+1: prettier2 done eval2 //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b ?c. ?b | ?c)` is not an instance of type `number` +//│ ╟── function of type `?a -> (forall ?b ?c. ?c | ?b)` is not an instance of type `number` //│ ║ l.72: rec def eval1 k e = case e of { //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.73: | Lit -> e.val @@ -691,7 +704,7 @@ prettier2 done eval2 e1 //│ ║ l.19: def lit val = Lit { val } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.379: | _ -> k x +//│ ║ l.381: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.264: else if ev e.rhs == 0 then prettier1 k ev e.lhs @@ -708,7 +721,7 @@ prettier2 done eval2 e2 //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.+1: prettier2 done eval2 e2 //│ ║ ^^^^^^^^^^^^^^^^^^^^ -//│ ╟── function of type `?a -> (forall ?b ?c. ?b | ?c)` is not an instance of type `number` +//│ ╟── function of type `?a -> (forall ?b ?c. ?c | ?b)` is not an instance of type `number` //│ ║ l.72: rec def eval1 k e = case e of { //│ ║ ^^^^^^^^^^^^^^^ //│ ║ l.73: | Lit -> e.val @@ -729,7 +742,7 @@ prettier2 done eval2 e2 //│ ║ l.19: def lit val = Lit { val } //│ ║ ^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.379: | _ -> k x +//│ ║ l.381: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.264: else if ev e.rhs == 0 then prettier1 k ev e.lhs @@ -764,10 +777,10 @@ prettier2 done eval2 d2 //│ ║ l.+1: prettier2 done eval2 d2 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Nega[?E] & {Nega#E = ?E, arg: ?arg}` is not a function -//│ ║ l.370: def nega arg = Nega { arg } +//│ ║ l.372: def nega arg = Nega { arg } //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.379: | _ -> k x +//│ ║ l.381: | _ -> k x //│ ║ ^^^ //│ ╟── from field selection: //│ ║ l.264: else if ev e.rhs == 0 then prettier1 k ev e.lhs diff --git a/shared/src/test/diff/mlscript/Group_2022_06_09.mls b/shared/src/test/diff/mlscript/Group_2022_06_09.mls index 6b803e4c36..cc0953fd1e 100644 --- a/shared/src/test/diff/mlscript/Group_2022_06_09.mls +++ b/shared/src/test/diff/mlscript/Group_2022_06_09.mls @@ -132,12 +132,13 @@ def evalComposed evalComposed = evalN evalN! (eval evalComposed) // * of the need for an algorithm to tie recursive TV knots and inline the rest; // * once we inline, `b` we should get the expected simplified recursive type. ev2 = evalComposed evalComposed! -//│ ev2: ((Add with {lhs: Neg & 'a | 'b & ~#Neg, rhs: Neg & 'a | 'b & ~#Neg}) | (Lit with {n: 'n}) | (Neg with {e: 'c})) -> (int | 'n) +//│ ev2: (Add\lhs\rhs & {lhs: Neg\e & {e: 'a} | 'b & ~#Neg, rhs: Neg\e & {e: 'a} | 'b & ~#Neg} | Lit\n & {n: 'n} | Neg\e & {e: 'c}) -> (int | 'n) //│ where -//│ 'c <: (Add with {lhs: Neg & 'a | 'b & ~#Neg, rhs: Neg & 'a | 'b & ~#Neg}) | Lit | (Neg with {e: 'c}) -//│ 'a <: {e: 'd} -//│ 'd <: 'b | (Neg with {e: 'd}) -//│ 'b <: Add & {lhs: Neg & 'a | 'b & ~#Neg, rhs: Neg & 'a | 'b & ~#Neg} | Lit +//│ 'c <: Add\lhs\rhs & {lhs: Neg\e & {e: 'a} | 'b & ~#Neg, rhs: Neg\e & {e: 'a} | 'b & ~#Neg} | Lit | Neg\e & {e: 'c} +//│ 'a <: Add\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Lit | Neg\e & {e: 'a} +//│ 'lhs <: Neg\e & {e: 'a} | 'b & ~#Neg +//│ 'b <: Add\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Lit +//│ 'rhs <: Neg\e & {e: 'a} | 'b & ~#Neg //│ = [Function (anonymous)] ev2 e3 @@ -152,12 +153,13 @@ def ev2_ty: (Add & { lhs: 'a; rhs: 'a } | Lit | Neg & { e: 'a } as 'a) -> int //│ = ev2_ty = ev2 -//│ ((Add with {lhs: Neg & 'a | 'b & ~#Neg, rhs: Neg & 'a | 'b & ~#Neg}) | (Lit with {n: 'n}) | (Neg with {e: 'c})) -> (int | 'n) +//│ (Add\lhs\rhs & {lhs: Neg\e & {e: 'a} | 'b & ~#Neg, rhs: Neg\e & {e: 'a} | 'b & ~#Neg} | Lit\n & {n: 'n} | Neg\e & {e: 'c}) -> (int | 'n) //│ where -//│ 'c <: (Add with {lhs: Neg & 'a | 'b & ~#Neg, rhs: Neg & 'a | 'b & ~#Neg}) | Lit | (Neg with {e: 'c}) -//│ 'a <: {e: 'd} -//│ 'd <: 'b | (Neg with {e: 'd}) -//│ 'b <: Add & {lhs: Neg & 'a | 'b & ~#Neg, rhs: Neg & 'a | 'b & ~#Neg} | Lit +//│ 'c <: Add\lhs\rhs & {lhs: Neg\e & {e: 'a} | 'b & ~#Neg, rhs: Neg\e & {e: 'a} | 'b & ~#Neg} | Lit | Neg\e & {e: 'c} +//│ 'a <: Add\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Lit | Neg\e & {e: 'a} +//│ 'lhs <: Neg\e & {e: 'a} | 'b & ~#Neg +//│ 'b <: Add\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Lit +//│ 'rhs <: Neg\e & {e: 'a} | 'b & ~#Neg //│ <: ev2_ty: //│ 'a -> int //│ where diff --git a/shared/src/test/diff/mlscript/HeadOption.mls b/shared/src/test/diff/mlscript/HeadOption.mls index 16fed63996..0326c02209 100644 --- a/shared/src/test/diff/mlscript/HeadOption.mls +++ b/shared/src/test/diff/mlscript/HeadOption.mls @@ -132,12 +132,12 @@ Cons.HeadOption lr1 :stats rec def lr2 = Cons { head = 0; tail = Cons { head = 1; tail = Cons { head = 3; tail = lr2 } } } -//│ lr2: 'tail +//│ lr2: Cons[0] with {tail: 'tail} //│ where -//│ 'tail :> Cons[0] with {tail: Cons[1] with {tail: Cons[3] with {tail: 'tail}}} +//│ 'tail :> Cons[1] with {tail: Cons[3] with {tail: Cons[0] with {tail: 'tail}}} //│ constrain calls : 49 //│ annoying calls : 0 -//│ subtyping calls : 258 +//│ subtyping calls : 280 :stats Cons.HeadOption lr2 diff --git a/shared/src/test/diff/mlscript/Neg.mls b/shared/src/test/diff/mlscript/Neg.mls index edae4853fb..e3f02f9719 100644 --- a/shared/src/test/diff/mlscript/Neg.mls +++ b/shared/src/test/diff/mlscript/Neg.mls @@ -136,13 +136,13 @@ def f: (~{x: 1 | 2} & 'a | ~{x: 2 | 3} & 'a) -> 'a f = id //│ 'a -> 'a //│ <: f: -//│ 'a -> 'a +//│ nothing -> nothing //│ = [Function: id] f x = case x of {} //│ nothing -> nothing //│ <: f: -//│ 'a -> 'a +//│ nothing -> nothing //│ = [Function: f2] def f: (~{x: 1 | 2} & ~lit & 'a | ~{x: 2 | 3} & ~lit & 'a) -> 'a diff --git a/shared/src/test/diff/mlscript/NestedClassArgs.mls b/shared/src/test/diff/mlscript/NestedClassArgs.mls index 340efed85d..5e7d5250a5 100644 --- a/shared/src/test/diff/mlscript/NestedClassArgs.mls +++ b/shared/src/test/diff/mlscript/NestedClassArgs.mls @@ -72,16 +72,15 @@ mkC = mkC' //│ 'a -> C2['a] rec def rc = mkC(rc) -//│ rc: 'b +//│ rc: C2['a] //│ where -//│ 'b :> C2['a] -//│ 'a :> 'b +//│ 'a :> C2['a] rec def rc = mkC'(rc) //│ rc: 'a //│ where -//│ 'a :> C2['A] with {a: 'a} -//│ 'A :> 'a +//│ 'a :> C2['A] & {a: forall 'a. 'a} +//│ 'A :> forall 'a. 'a @@ -141,17 +140,17 @@ def c: 'a -> C5['a] //│ c: 'a -> C5['a] rec def c5 a = C5{ a = C2 { a = c5 a } } -//│ c5: anything -> 'a +//│ c5: anything -> (C5['A] with {a: 'a}) //│ where -//│ 'a :> C5['A] with {a: C2['A0] with {a: 'a}} -//│ 'A0 :> C5['A] | 'a +//│ 'a :> C2['A0] with {a: C5['A] with {a: 'a}} +//│ 'A0 :> (C5['A] with {a: 'a}) | C5['A] //│ <: C5['A] c = c5 -//│ anything -> 'a +//│ anything -> (C5['A] with {a: 'a}) //│ where -//│ 'a :> C5['A] with {a: C2['A0] with {a: 'a}} -//│ 'A0 :> C5['A] | 'a +//│ 'a :> C2['A0] with {a: C5['A] with {a: 'a}} +//│ 'A0 :> (C5['A] with {a: 'a}) | C5['A] //│ <: C5['A] //│ <: c: //│ 'a -> C5['a] @@ -168,24 +167,24 @@ def c: 'a -> C6['a] //│ c: 'a -> C6['a] rec def c6 a = C6{ a = c5 (c6 a) } -//│ c6: anything -> (C6['A] with {a: forall 'a 'A0 'A1. 'a}) +//│ c6: anything -> (C6['A] with {a: forall 'A0 'a 'A1. C5['A0] with {a: 'a}}) //│ where -//│ 'a :> C5['A0] with {a: C2['A1] with {a: 'a}} -//│ 'A1 :> C5['A0] | 'a +//│ 'a :> C2['A1] with {a: C5['A0] with {a: 'a}} +//│ 'A1 :> (C5['A0] with {a: 'a}) | C5['A0] //│ <: C5['A0] :stats c = c6 -//│ anything -> (C6['A] with {a: forall 'a 'A0 'A1. 'a}) +//│ anything -> (C6['A] with {a: forall 'A0 'a 'A1. C5['A0] with {a: 'a}}) //│ where -//│ 'a :> C5['A0] with {a: C2['A1] with {a: 'a}} -//│ 'A1 :> C5['A0] | 'a +//│ 'a :> C2['A1] with {a: C5['A0] with {a: 'a}} +//│ 'A1 :> (C5['A0] with {a: 'a}) | C5['A0] //│ <: C5['A0] //│ <: c: //│ 'a -> C6['a] //│ constrain calls : 70 //│ annoying calls : 34 -//│ subtyping calls : 400 +//│ subtyping calls : 476 // Reproduction of an issue found while trying out TypeRef ctor typing: @@ -256,23 +255,23 @@ s2 = S{v=S{v=1}}:O[O['_]] L{h=error;t=s1} L{h=error;t=s2} //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.256: L{h=error;t=s1} +//│ ║ l.255: L{h=error;t=s1} //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `L` -//│ ║ l.246: s1 = S{v=1}:O['_] +//│ ║ l.245: s1 = S{v=1}:O['_] //│ ║ ^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.234: class L[T]: { h: T; t: O[L[T]] } +//│ ║ l.233: class L[T]: { h: T; t: O[L[T]] } //│ ╙── ^^^^ //│ res: error //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.257: L{h=error;t=s2} +//│ ║ l.256: L{h=error;t=s2} //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type `S['_]` is not an instance of type `L` -//│ ║ l.233: type O[T] = S[T] | N +//│ ║ l.232: type O[T] = S[T] | N //│ ║ ^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.234: class L[T]: { h: T; t: O[L[T]] } +//│ ║ l.233: class L[T]: { h: T; t: O[L[T]] } //│ ╙── ^^^^ //│ res: error @@ -291,16 +290,16 @@ def append ls elem = L { h = elem; t = S { v = ls } } :ns append -//│ res: forall 'h 'a 'b 'T 't 'v 'T0 'c. 'c -> 'a -> 'b +//│ res: forall 'v 'T 'h 'a 'b 'T0 't 'c. 'b -> 'c -> 'a //│ where -//│ 'b :> #L & {h: 'h, t: 't, L#T = 'T0} -//│ 't :> #S & {v: 'v, S#T = 'T} -//│ <: O[L['T0]] -//│ 'a <: 'h -//│ 'h <: 'T0 -//│ 'c <: 'v -//│ 'v <: L['T0] & 'T -//│ 'T := L['T0] +//│ 'a :> #L & {h: 'h, t: 't, L#T = 'T} +//│ 't :> #S & {v: 'v, S#T = 'T0} +//│ <: O[L['T]] +//│ 'c <: 'h +//│ 'h <: 'T +//│ 'b <: 'v +//│ 'v <: L['T] & 'T0 +//│ 'T0 := L['T] append error //│ res: ('h & 'T) -> (L['T] with {h: 'h, t: S[L['T]] & {v: nothing}}) @@ -332,16 +331,16 @@ append_ty_2 = append //│ <: append_ty_2: //│ (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] with {h: 'h, t: S['T0] with {v: 'v}}) //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.330: append_ty_2 = append +//│ ║ l.329: append_ty_2 = append //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'T0` is not an instance of type `L` -//│ ║ l.323: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) +//│ ║ l.322: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) //│ ║ ^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.234: class L[T]: { h: T; t: O[L[T]] } +//│ ║ l.233: class L[T]: { h: T; t: O[L[T]] } //│ ║ ^^^^ //│ ╟── Note: class type parameter T is defined at: -//│ ║ l.230: class S[T]: { v: T } +//│ ║ l.229: class S[T]: { v: T } //│ ╙── ^ append_ty = append_ty_2 @@ -355,13 +354,13 @@ append_ty_2 = append_ty //│ <: append_ty_2: //│ (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] with {h: 'h, t: S['T0] with {v: 'v}}) //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.353: append_ty_2 = append_ty +//│ ║ l.352: append_ty_2 = append_ty //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'T0` is not an instance of type `L` -//│ ║ l.323: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) +//│ ║ l.322: def append_ty_2: (L['T] & 'v & 'T0) -> ('T & 'h) -> (L['T] & {h: 'h; t: S['T0] & {v: 'v}}) //│ ║ ^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.309: def append_ty: (L['T] & 'v) -> ('T & 'h) -> (L['T] & {h: 'h; t: S[L['T]] & {v: 'v}}) +//│ ║ l.308: def append_ty: (L['T] & 'v) -> ('T & 'h) -> (L['T] & {h: 'h; t: S[L['T]] & {v: 'v}}) //│ ╙── ^^^^^ diff --git a/shared/src/test/diff/mlscript/NestedClassArgs_Co.mls b/shared/src/test/diff/mlscript/NestedClassArgs_Co.mls index d7bf10c750..0afb617bd5 100644 --- a/shared/src/test/diff/mlscript/NestedClassArgs_Co.mls +++ b/shared/src/test/diff/mlscript/NestedClassArgs_Co.mls @@ -68,9 +68,9 @@ rec def rc = mkC(rc) //│ 'a :> C2['a] rec def rc = mkC'(rc) -//│ rc: 'A +//│ rc: 'a //│ where -//│ 'A :> C2['A] +//│ 'a :> C2[forall 'a. 'a] @@ -130,14 +130,14 @@ def c: 'a -> C5['a] //│ c: 'a -> C5['a] rec def c5 a = C5{ a = C2 { a = c5 a } } -//│ c5: anything -> 'A +//│ c5: anything -> (C5[nothing] with {a: 'a}) //│ where -//│ 'A :> C5[nothing] with {a: C2['A]} +//│ 'a :> C2[C5[nothing] with {a: 'a}] c = c5 -//│ anything -> 'A +//│ anything -> (C5[nothing] with {a: 'a}) //│ where -//│ 'A :> C5[nothing] with {a: C2['A]} +//│ 'a :> C2[C5[nothing] with {a: 'a}] //│ <: c: //│ 'a -> C5['a] @@ -157,14 +157,14 @@ def c: 'a -> C6['a] // rec def c a = C6{ a = c5 (c a) } rec def c6 a = C6{ a = c5 (c6 a) } -//│ c6: anything -> (C6[nothing] with {a: forall 'A. 'A}) +//│ c6: anything -> (C6[nothing] with {a: forall 'a. C5[nothing] with {a: 'a}}) //│ where -//│ 'A :> C5[nothing] with {a: C2['A]} +//│ 'a :> C2[C5[nothing] with {a: 'a}] c = c6 -//│ anything -> (C6[nothing] with {a: forall 'A. 'A}) +//│ anything -> (C6[nothing] with {a: forall 'a. C5[nothing] with {a: 'a}}) //│ where -//│ 'A :> C5[nothing] with {a: C2['A]} +//│ 'a :> C2[C5[nothing] with {a: 'a}] //│ <: c: //│ 'a -> C6['a] diff --git a/shared/src/test/diff/mlscript/NestedRecursiveMatch.mls b/shared/src/test/diff/mlscript/NestedRecursiveMatch.mls index 9ab3441bb1..432c25b2da 100644 --- a/shared/src/test/diff/mlscript/NestedRecursiveMatch.mls +++ b/shared/src/test/diff/mlscript/NestedRecursiveMatch.mls @@ -34,9 +34,9 @@ rec def f w = case w of Some -> let m = (tmp0).value in Some (m,) -//│ f: 'right -> (None | Some[in 'a out 'a | 0]) +//│ f: (Leaf | Node & 'b) -> (None | Some[in 'a out 'a | 0]) //│ where -//│ 'right <: Leaf | Node & {left: 'right, right: 'right} +//│ 'b <: {left: Leaf | Node & 'b, right: Leaf | Node & 'b} // * Minimizations: @@ -49,9 +49,9 @@ rec def f w = case w of Some -> let m = (tmp0).value in Some (m,) -//│ f: 'b -> Some[in 'a out 'a | 0] +//│ f: 'left -> Some[in 'a out 'a | 0] //│ where -//│ 'b <: Node & {left: 'b} +//│ 'left <: Node & {left: 'left} rec def f w = case w of Node -> @@ -71,7 +71,7 @@ def f w = None -> Some 0, Some -> let m = tmp0.value in Some m -//│ f: {left: 'b} -> Some[in 'a out 0 | 'a] +//│ f: 'b -> Some[in 'a out 0 | 'a] //│ where -//│ 'b <: Node & {left: 'b} +//│ 'b <: {left: Node & 'b} diff --git a/shared/src/test/diff/mlscript/Paper.mls b/shared/src/test/diff/mlscript/Paper.mls index 84f5176b76..d33d5d27d7 100644 --- a/shared/src/test/diff/mlscript/Paper.mls +++ b/shared/src/test/diff/mlscript/Paper.mls @@ -114,9 +114,9 @@ type List[A] = Cons[A] | None rec def mapList f ls = case ls of Cons -> Cons{value = f ls.value; tail = mapList f ls.tail}, None -> None{} -//│ mapList: ('value -> 'value0) -> 'a -> 'tail +//│ mapList: ('value -> 'value0) -> 'a -> (None | 'b) //│ where -//│ 'tail :> (Cons['value0] with {tail: 'tail}) | None +//│ 'b :> Cons['value0] with {tail: None | 'b} //│ 'a <: (Cons[?] with {tail: 'a, value: 'value}) | None //│ = [Function: mapList] @@ -134,10 +134,10 @@ rec def unzip xs = case xs of None -> { fst = None; snd = None }, Some -> let tmp = unzip xs.tail in { fst = Cons xs.value.fst tmp.fst ; snd = Cons xs.value.snd tmp.snd } -//│ unzip: 'a -> {fst: 'tail, snd: 'tail0} +//│ unzip: 'a -> {fst: None | 'b, snd: None | 'c} //│ where -//│ 'tail0 :> (Cons['value] with {tail: 'tail0}) | None -//│ 'tail :> (Cons['value0] with {tail: 'tail}) | None +//│ 'c :> Cons['value] with {tail: None | 'c} +//│ 'b :> Cons['value0] with {tail: None | 'b} //│ 'a <: None | Some[?] & {tail: 'a, value: {fst: 'value0, snd: 'value}} //│ = [Function: unzip] @@ -156,10 +156,10 @@ def unzip_ty = unzip //│ <: Cons_ty: //│ 'a -> (List['a] & 'b) -> (Cons['a] with {tail: 'b}) //│ = [Function: Cons_ty] -//│ 'a -> {fst: 'tail, snd: 'tail0} +//│ 'a -> {fst: None | 'b, snd: None | 'c} //│ where -//│ 'tail0 :> (Cons['value] with {tail: 'tail0}) | None -//│ 'tail :> (Cons['value0] with {tail: 'tail}) | None +//│ 'c :> Cons['value] with {tail: None | 'c} +//│ 'b :> Cons['value0] with {tail: None | 'b} //│ 'a <: None | Some[?] & {tail: 'a, value: {fst: 'value0, snd: 'value}} //│ <: unzip_ty: //│ List[{fst: 'a, snd: 'b}] -> {fst: List['a], snd: List['b]} diff --git a/shared/src/test/diff/mlscript/PolyVariant.mls b/shared/src/test/diff/mlscript/PolyVariant.mls index feadc37b21..af5df93f64 100644 --- a/shared/src/test/diff/mlscript/PolyVariant.mls +++ b/shared/src/test/diff/mlscript/PolyVariant.mls @@ -104,16 +104,16 @@ rec def map f l = case l of { | Nil -> l | Cons -> Cons (f l.head) (map f l.tail) } -//│ map: ('head -> ('head0 & 'A)) -> 'a -> 'tail +//│ map: ('head -> ('head0 & 'A)) -> 'a -> 'b //│ where -//│ 'a <: (Cons[?] with {head: 'head, tail: 'a}) | Nil & List['A] & 'tail -//│ 'tail :> Cons['A] with {head: 'head0, tail: 'tail} +//│ 'a <: (Cons[?] with {head: 'head, tail: 'a}) | Nil & List['A] & 'b +//│ 'b :> Cons['A] with {head: 'head0, tail: 'b} //│ = [Function: map] map (fun x -> "lol") (Cons 2 (Cons 3 Nil)) -//│ res: 'tail +//│ res: Nil | 'a //│ where -//│ 'tail :> (Cons["lol"] with {tail: 'tail}) | Nil +//│ 'a :> Cons["lol"] with {tail: Nil | 'a} //│ = Cons { head: 'lol', tail: Cons { head: 'lol', tail: Nil {} } } //************** EXAMPLE 3: ROUGH APPROXIMATIONS ************* diff --git a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls index d93cc227ee..10cbaa988e 100644 --- a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls +++ b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls @@ -84,9 +84,9 @@ def eval_var sub v = case v of { | Success -> res.result } } -//│ eval_var: 'a -> (Var & 'result) -> 'result +//│ eval_var: (Cons[?] & 'a | Nil) -> (Var & 'result) -> 'result //│ where -//│ 'a <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'a}) | Nil +//│ 'a <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'a | Nil} //│ = //│ list_assoc and eq are not implemented @@ -129,26 +129,31 @@ def eval_lambda eval_rec subst v = case v of { Abs { name = new_name; body = eval_rec (Cons (Tuple v.name (Var { name = new_name })) subst) v.body } } -//│ eval_lambda: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('body & 'result & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | App[?] & {lhs: 'lhs, rhs: 'lhs} | Var & 'result) -> (Abs['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | 'result) +//│ eval_lambda: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('body & 'result & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & (Cons[?] & 'b | Nil) & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | App[?] & {lhs: 'lhs, rhs: 'lhs} | Var & 'result) -> (Abs['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | 'result) //│ where -//│ 'b <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'b}) | Nil +//│ 'b <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'b | Nil} //│ = //│ eval_var, list_assoc and eq are not implemented rec def eval1 subst = eval_lambda eval1 subst -//│ eval1: (List[?] & 'tail) -> 'b -> 'rhs +//│ eval1: ('tail & (Cons[?] & List[?] & 'b | Nil & List[?])) -> 'c -> 'd //│ where -//│ 'tail <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'tail}) | Nil -//│ 'result :> 'rhs -//│ <: 'b & (Abs[?] & 'c | 'lhs & ~#Abs) -//│ 'rhs :> 'result | 'd | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Abs['rhs] -//│ 'd :> Var -//│ <: 'b & (Abs[?] & 'c | {name: string} & 'lhs & ~#Abs) -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Var -//│ <: 'a & 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'rhs}) | 'rhs -//│ 'c <: {body: 'b, name: string} -//│ 'b <: Abs[?] & {body: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Var & 'd +//│ 'tail <: Cons[?] & 'b | Nil +//│ 'b <: {head: {_1: string, _2: 'result}, tail: 'tail} +//│ 'result :> 'd +//│ <: Abs[?] & 'e & 'f | 'lhs & (Abs[?] & 'f & ~#Abs | App[?] & 'g | Var & 'h) +//│ 'd :> 'result | 'i | App['a]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Abs['d] +//│ 'i :> Var +//│ <: Abs[?] & 'e & 'f | 'lhs & (Abs[?] & 'f & ~#Abs | App[?] & {name: string} & 'g | Var & 'h) +//│ 'lhs :> App['a]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Var +//│ <: 'a & 'c +//│ 'a :> App['a]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | 'd +//│ 'rhs :> 'd +//│ 'e <: {body: 'c, name: string} +//│ 'c <: Abs[?] & 'f | App[?] & 'g | Var & 'h +//│ 'h <: Var & 'i +//│ 'g <: {lhs: 'c, rhs: 'c} +//│ 'f <: {body: 'c, name: string} //│ = //│ eval_lambda, eval_var, list_assoc and eq are not implemented @@ -206,18 +211,18 @@ rec def eval_expr eval_rec subst v = } | Numb -> vv // _ -> vv } -//│ eval_expr: ('a -> 'rhs -> 'rhs0) -> ('a & 'b) -> (Add[?] & {lhs: 'rhs, rhs: 'rhs} | Mul[?] & {lhs: 'rhs, rhs: 'rhs} | Numb & 'result | Var & 'result) -> (Add['rhs0] | Mul['rhs0] | Numb | 'result) +//│ eval_expr: ('a -> 'rhs -> 'rhs0) -> ('a & (Cons[?] & 'b | Nil)) -> (Add[?] & {lhs: 'rhs, rhs: 'rhs} | Mul[?] & {lhs: 'rhs, rhs: 'rhs} | Numb & 'result | Var & 'result) -> (Add['rhs0] | Mul['rhs0] | Numb | 'result) //│ where -//│ 'b <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'b}) | Nil +//│ 'b <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'b | Nil} //│ = //│ eval_var, list_assoc and eq are not implemented rec def eval2 subst = eval_expr eval2 subst -//│ eval2: 'a -> 'b -> 'result +//│ eval2: (Cons[?] & 'a | Nil) -> 'b -> (Numb | 'result) //│ where //│ 'b <: Add[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & 'result | Var & 'result -//│ 'a <: (Cons[?] with {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: 'a}) | Nil -//│ 'result :> Numb | Add['result] | Mul['result] +//│ 'a <: {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: Cons[?] & 'a | Nil} +//│ 'result :> Mul[Numb | 'result] | Add[Numb | 'result] //│ = //│ eval_expr, eval_var, list_assoc and eq are not implemented @@ -254,30 +259,34 @@ def eval_lexpr eval_rec subst v = case v of { | Lambda -> eval_lambda eval_rec subst v | Expr -> eval_expr eval_rec subst v } -//│ eval_lexpr: ((Cons[('a, Var | 'body,) | 'A]\head\tail & {head: ('a, Var | 'body,), tail: Nil | 'tail} | 'tail) -> 'lhs -> ('body & 'result & (Abs[?]\body\name & {body: 'lhs, name: 'a} | 'lhs0 & ~#Abs))) -> (List['A] & 'b & 'c & 'tail) -> (Abs[?]\body\name & {body: 'lhs, name: 'a} | Add[?] & {lhs: 'lhs, rhs: 'lhs} | App[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | App['lhs0 | 'body]\lhs\rhs & {lhs: 'lhs0, rhs: 'body} | Mul['body] | Numb | 'result) +//│ eval_lexpr: ((Cons[('a, Var | 'body,) | 'A]\head\tail & {head: ('a, Var | 'body,), tail: Nil | 'tail} | 'tail) -> 'lhs -> ('body & 'result & (Abs[?]\body\name & {body: 'lhs, name: 'a} | 'lhs0 & ~#Abs))) -> (List['A] & (Cons[?] & 'b | Nil) & (Cons[?] & 'c | Nil) & 'tail) -> (Abs[?]\body\name & {body: 'lhs, name: 'a} | Add[?] & {lhs: 'lhs, rhs: 'lhs} | App[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | App['lhs0 | 'body]\lhs\rhs & {lhs: 'lhs0, rhs: 'body} | Mul['body] | Numb | 'result) //│ where -//│ 'c <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'c} | Nil -//│ 'b <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'b} | Nil +//│ 'c <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'c | Nil} +//│ 'b <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'b | Nil} //│ = //│ eval_lambda, eval_var, list_assoc and eq are not implemented rec def eval3 subst = eval_lexpr eval3 subst -//│ eval3: (List[?] & 'tail & 'tail0) -> 'b -> 'rhs +//│ eval3: ('tail & 'tail0 & (Cons[?] & List[?] & 'b & 'c | Nil & List[?])) -> 'd -> 'e //│ where -//│ 'tail0 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail0} | Nil -//│ 'tail <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail} | Nil -//│ 'result :> Var | 'rhs | Numb -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Numb | ~#Abs & ~#Numb)) -//│ 'rhs :> Abs['rhs] | App['a]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | 'result | 'd | 'e -//│ 'a :> Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | App['a]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | 'rhs -//│ 'lhs :> Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | App['a]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | Numb | Var -//│ <: 'b & 'a -//│ 'b <: Abs[?] & {body: 'b} | Add[?] & {lhs: 'b, rhs: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & (Add[?] & 'e | Mul[?] & 'e | Numb & 'result | Var & 'd) | Var & 'd -//│ 'd :> Var -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Numb & {name: string} | {name: string} & ~#Abs & ~#Numb)) -//│ 'e :> Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} -//│ <: 'b & (Abs[?] & {lhs: anything, rhs: anything} & 'c | 'lhs & (Numb & {lhs: anything, rhs: anything} | {lhs: anything, rhs: anything} & ~#Abs & ~#Numb)) -//│ 'c <: {body: 'b, name: string} +//│ 'tail0 <: Cons[?] & 'c | Nil +//│ 'c <: {head: {_1: string, _2: 'result}, tail: 'tail0} +//│ 'tail <: Cons[?] & 'b | Nil +//│ 'b <: {head: {_1: string, _2: 'result}, tail: 'tail} +//│ 'result :> Var | 'e | Numb +//│ <: Abs[?] & 'f & 'g | 'lhs & (Lambda & 'f & ~#Abs | 'h & (Expr & ~#Numb | Numb)) +//│ 'e :> Abs['e] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | 'result | 'i | 'j | (Add['e] with {lhs: 'e, rhs: 'e}) | (Mul['e] with {lhs: 'e, rhs: 'e}) +//│ 'a :> (Add['e] with {lhs: 'e, rhs: 'e}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['e] with {lhs: 'e, rhs: 'e}) | Var | 'e +//│ 'lhs :> (Add['e] with {lhs: 'e, rhs: 'e}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['e] with {lhs: 'e, rhs: 'e}) | Numb | Var +//│ <: 'd & 'a +//│ 'd <: Expr & 'h | Lambda & 'f +//│ 'h <: Add[?] & {lhs: 'd, rhs: 'd} | Mul[?] & {lhs: 'd, rhs: 'd} | Numb & 'result | Var & 'j +//│ 'j <: Var & (Abs[?] & 'f & 'g | 'lhs & (Lambda & {name: string} & 'f & ~#Abs | 'h & (Expr & {name: string} & ~#Numb | Numb & {name: string}))) +//│ 'f <: Abs[?] & {body: 'd} | App[?] & {lhs: 'd, rhs: 'd} | Var & 'i +//│ 'i :> Var +//│ <: Abs[?] & 'f & 'g | 'lhs & (Lambda & {name: string} & 'f & ~#Abs | 'h & (Expr & {name: string} & ~#Numb | Numb & {name: string})) +//│ 'g <: {body: 'd, name: string} +//│ 'rhs :> 'e //│ = //│ eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented @@ -314,12 +323,12 @@ rec def eval3 subst = eval_lexpr eval3 subst // ************************** Tests ******************************* eval3 Nil (Var { name = "s" }) -//│ res: 'result +//│ res: 'b //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b -//│ 'b :> Add['result] | Mul['result] +//│ 'b :> Abs['b] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Var | Numb | (Add['b] with {lhs: 'b, rhs: 'b}) | (Mul['b] with {lhs: 'b, rhs: 'b}) +//│ 'a :> 'lhs | 'b +//│ 'lhs :> (Add['b] with {lhs: 'b, rhs: 'b}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | Var +//│ 'rhs :> 'b //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented // ------------- OCaml's type ------------- @@ -333,49 +342,49 @@ eval3 Nil (Var { name = "s" }) eval3 Nil (Abs { name = "s"; body = Var { name = "s" } }) -//│ res: 'result +//│ res: 'b //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b -//│ 'b :> Add['result] | Mul['result] +//│ 'b :> Abs['b] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Var | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | (Add['b] with {lhs: 'b, rhs: 'b}) +//│ 'a :> 'lhs | 'b +//│ 'lhs :> (Add['b] with {lhs: 'b, rhs: 'b}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | Var +//│ 'rhs :> 'b //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented eval2 Nil (Numb { num = 1 }) -//│ res: 'rhs +//│ res: Numb | 'a //│ where -//│ 'rhs :> Numb | Add['rhs] | Mul['rhs] +//│ 'a :> Add[Numb | 'a] | Mul[Numb | 'a] //│ = //│ eval2, eval_expr, eval_var, list_assoc and eq are not implemented eval3 Nil (Numb { num = 1 }) -//│ res: 'result +//│ res: 'b //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b -//│ 'b :> Add['result] | Mul['result] +//│ 'b :> Abs['b] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Var | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | (Add['b] with {lhs: 'b, rhs: 'b}) +//│ 'a :> 'lhs | 'b +//│ 'lhs :> (Add['b] with {lhs: 'b, rhs: 'b}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | Var +//│ 'rhs :> 'b //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented eval3 Nil (App { lhs = Numb {num = 0}; rhs = Numb {num = 0}}) -//│ res: 'result +//│ res: 'b //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b -//│ 'b :> Add['result] | Mul['result] +//│ 'b :> Abs['b] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Var | Numb | (Add['b] with {lhs: 'b, rhs: 'b}) | (Mul['b] with {lhs: 'b, rhs: 'b}) +//│ 'a :> 'lhs | 'b +//│ 'lhs :> (Add['b] with {lhs: 'b, rhs: 'b}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | Var +//│ 'rhs :> 'b //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented eval3 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Numb { num = 1 } } }) -//│ res: 'result +//│ res: 'b //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b -//│ 'b :> Add['result] | Mul['result] +//│ 'b :> Abs['b] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Var | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | (Add['b] with {lhs: 'b, rhs: 'b}) +//│ 'a :> 'lhs | 'b +//│ 'lhs :> (Add['b] with {lhs: 'b, rhs: 'b}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | Var +//│ 'rhs :> 'b //│ = //│ eval3, eval_lexpr, eval_lambda, eval_var, list_assoc and eq are not implemented @@ -394,51 +403,70 @@ def eval_lexpr' eval_rec subst v = case v of { | Add -> eval_expr eval_rec subst v | Mul -> eval_expr eval_rec subst v } -//│ eval_lexpr': ((Cons[('b, Var | 'body,) | 'A]\head\tail & {head: ('b, Var | 'body,), tail: Nil | 'tail} | 'tail) -> 'body0 -> ('body & 'result & (Abs[?]\body\name & {body: 'body0, name: 'b} | 'lhs & 'a & (Abs[?]\body\name & {body: 'body0, name: 'b} & ~#Abs | 'lhs & 'a & ~#Abs)))) -> (List['A] & 'c & 'd & 'e & 'f & 'g & 'tail & 'h) -> (Abs[?]\body\name & {body: 'body0, name: 'b} | Add[?] & {lhs: 'body0, rhs: 'body0} | App[?] & {lhs: 'body0, rhs: 'body0} | Mul[?] & {lhs: 'body0, rhs: 'body0} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | App['a | 'body]\lhs\rhs & {lhs: 'lhs, rhs: 'body} | Mul['body] | Numb | 'result) +//│ eval_lexpr': ((Cons[('b, Var | 'body,) | 'A]\head\tail & {head: ('b, Var | 'body,), tail: Nil | 'tail} | 'tail) -> 'body0 -> ('body & 'result & (Abs[?]\body\name & {body: 'body0, name: 'b} | 'lhs & 'a & (Abs[?]\body\name & {body: 'body0, name: 'b} & ~#Abs | 'lhs & 'a & ~#Abs)))) -> (List['A] & (Cons[?] & 'c | Nil) & (Cons[?] & 'd | Nil) & (Cons[?] & 'e | Nil) & (Cons[?] & 'f | Nil) & (Cons[?] & 'g | Nil) & 'tail & (Cons[?] & 'h | Nil)) -> (Abs[?]\body\name & {body: 'body0, name: 'b} | Add[?] & {lhs: 'body0, rhs: 'body0} | App[?] & {lhs: 'body0, rhs: 'body0} | Mul[?] & {lhs: 'body0, rhs: 'body0} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | App['a | 'body]\lhs\rhs & {lhs: 'lhs, rhs: 'body} | Mul['body] | Numb | 'result) //│ where -//│ 'h <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'h} | Nil -//│ 'g <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'g} | Nil -//│ 'f <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'f} | Nil -//│ 'e <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'e} | Nil -//│ 'd <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'd} | Nil -//│ 'c <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'c} | Nil +//│ 'h <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'h | Nil} +//│ 'g <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'g | Nil} +//│ 'f <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'f | Nil} +//│ 'e <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'e | Nil} +//│ 'd <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'd | Nil} +//│ 'c <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'c | Nil} //│ = //│ eval_var, list_assoc and eq are not implemented :e rec def eval4 subst = eval_lexpr' eval4 subst //│ ╔══[ERROR] Subtyping constraint of the form `?a -> ?b <: ?eval4` took too many steps and ran out of fuel (10000) -//│ ║ l.409: rec def eval4 subst = eval_lexpr' eval4 subst +//│ ║ l.418: rec def eval4 subst = eval_lexpr' eval4 subst //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ eval4: (List[?] & 'tail & 'tail0 & 'tail1 & 'tail2 & 'tail3 & 'tail4) -> 'a -> 'result +//│ eval4: ('tail & 'tail0 & 'tail1 & 'tail2 & 'tail3 & 'tail4 & (Cons[?] & List[?] & 'a & 'b & 'c & 'd & 'e & 'f | Nil & List[?])) -> 'g -> (App[nothing] | 'result | 'h) //│ where -//│ 'tail4 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result0}, tail: 'tail4} | Nil -//│ 'tail3 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result0}, tail: 'tail3} | Nil -//│ 'tail2 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: 'tail2} | Nil -//│ 'tail1 <: Cons[?]\head\tail & { -//│ head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, +//│ 'tail4 <: Cons[?] & 'f | Nil +//│ 'f <: {head: {_1: string, _2: 'result0}, tail: 'tail4} +//│ 'tail3 <: Cons[?] & 'e | Nil +//│ 'e <: {head: {_1: string, _2: 'result0}, tail: 'tail3} +//│ 'tail2 <: Cons[?] & 'd | Nil +//│ 'd <: {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: 'tail2} +//│ 'tail1 <: Cons[?] & 'c | Nil +//│ 'c <: { +//│ head: { +//│ _1: string, +//│ _2: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) +//│ }, //│ tail: 'tail1 -//│ } | Nil -//│ 'tail0 <: Cons[?]\head\tail & { -//│ head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, +//│ } +//│ 'tail0 <: Cons[?] & 'b | Nil +//│ 'b <: { +//│ head: { +//│ _1: string, +//│ _2: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) +//│ }, //│ tail: 'tail0 -//│ } | Nil -//│ 'tail <: Cons[?]\head\tail & { -//│ head: {_1: string, _2: 'result & 'a & (Abs[?] & 'b | 'lhs & (Numb | ~#Abs & ~#Numb))}, +//│ } +//│ 'tail <: Cons[?] & 'a | Nil +//│ 'a <: { +//│ head: { +//│ _1: string, +//│ _2: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) +//│ }, //│ tail: 'tail -//│ } | Nil -//│ 'result :> Mul['result] | Add['result] | Abs['result] | App['lhs] & {lhs: 'lhs, rhs: nothing} | 'result0 | 'c | 'd | 'e -//│ 'result0 :> Var | Numb -//│ <: 'a & (Numb | ~#Numb) -//│ 'a <: Abs[?] | Add[?] & {lhs: 'a, rhs: 'a} | App[?] & {rhs: 'a} | Mul[?] & {lhs: 'a, rhs: 'a} | Numb & (Add[?] & 'e | Mul[?] & 'e | Numb & 'result0 | Var & 'd) | Var & 'c -//│ 'c :> Var -//│ <: 'a & (Abs[?] & 'b | 'lhs & (Numb & {name: string} | {name: string} & ~#Abs & ~#Numb)) -//│ 'b <: {body: 'a, name: string} -//│ 'd <: 'a & (Numb & {name: string} | {name: string} & ~#Numb) -//│ 'e :> 'result -//│ <: 'a & (Numb & {lhs: anything, rhs: anything} | {lhs: anything, rhs: anything} & ~#Numb) +//│ } +//│ 'result :> Abs[Abs[nothing] | App[nothing] | 'result | 'h] | App['lhs] & {lhs: 'lhs, rhs: nothing} | 'h | Numb | Var | Add[Abs[nothing] | App[nothing] | 'result | 'h] | Mul[Abs[nothing] | App[nothing] | 'result | 'h] | 'result0 | 'p +//│ 'h :> Var +//│ <: Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & {name: string} & 'k | App[?] & {name: string} & 'l | Mul[?] & {name: string} & 'm | Var & 'n | 'o & (Numb & {name: string} | Numb & {name: string} & ~#Numb)) //│ 'lhs :> App['lhs] & {lhs: 'lhs, rhs: nothing} | Var +//│ 'i <: {body: 'g, name: string} +//│ 'g <: Abs[?] & 'j | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Numb & 'o | Var & 'n +//│ 'k <: Add[?] & {lhs: 'g, rhs: 'g} | Mul[?] & {lhs: 'g, rhs: 'g} | Numb & 'result | Var & 'p +//│ 'p <: Var & (Abs[?] & 'j | Add[?] & {name: string} & 'k | App[?] & {name: string} & 'l | Mul[?] & {name: string} & 'm | Var & 'n | 'o & (Numb & {name: string} | Numb & {name: string} & ~#Numb)) +//│ 'o <: Add[?] & {lhs: 'g, rhs: 'g} | Mul[?] & {lhs: 'g, rhs: 'g} | Numb & 'result0 | Var & 'p +//│ 'result0 :> Var | Numb +//│ <: Abs[?] & 'j | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb) +//│ 'n <: Var & 'h +//│ 'm <: Add[?] & {lhs: 'g, rhs: 'g} | Mul[?] & {lhs: 'g, rhs: 'g} | Numb & 'result | Var +//│ 'l <: Abs[?] & {body: 'g} | App[?] & {rhs: 'g} | Var & 'h +//│ 'j <: Abs[?] | App[?] | Var & 'h //│ = //│ eval_lexpr', eval_var, list_assoc and eq are not implemented @@ -446,43 +474,60 @@ rec def eval4 subst = eval_lexpr' eval4 subst :stats rec def eval4 subst = eval_lexpr' eval4 subst -//│ eval4: (List[?] & 'tail & 'tail0 & 'tail1 & 'tail2 & 'tail3 & 'tail4) -> 'b -> 'rhs +//│ eval4: ('tail & 'tail0 & 'tail1 & 'tail2 & 'tail3 & 'tail4 & (Cons[?] & List[?] & 'b & 'c & 'd & 'e & 'f & 'g | Nil & List[?])) -> 'h -> 'i //│ where -//│ 'tail4 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail4} | Nil -//│ 'tail3 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail3} | Nil -//│ 'tail2 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail2} | Nil -//│ 'tail1 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail1} | Nil -//│ 'tail0 <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail0} | Nil -//│ 'tail <: Cons[?]\head\tail & {head: {_1: string, _2: 'result}, tail: 'tail} | Nil -//│ 'result :> Var | 'rhs | Numb -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Abs[?] & 'c & ~#Abs | 'lhs0 & (Numb | ~#Abs & ~#Numb))) -//│ 'rhs :> Abs['rhs] | App['a]\lhs\rhs & {lhs: 'lhs | 'lhs0, rhs: 'rhs} | 'result | 'd | 'e | Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} -//│ 'a :> Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | App['a]\lhs\rhs & {lhs: 'lhs | 'lhs0, rhs: 'rhs} | Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | 'rhs -//│ 'lhs :> Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | App['a]\lhs\rhs & {lhs: 'lhs | 'lhs0, rhs: 'rhs} | Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | Numb | Var -//│ <: 'b & 'a -//│ 'lhs0 :> Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | App['a]\lhs\rhs & {lhs: 'lhs | 'lhs0, rhs: 'rhs} | Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | Numb | Var -//│ <: 'b & 'a -//│ 'b <: Abs[?] & {body: 'b} | Add[?] & {lhs: 'b, rhs: 'b} | App[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & (Add[?] & 'e | Mul[?] & 'e | Numb & 'result | Var & 'd) | Var & 'd -//│ 'd :> Var -//│ <: 'b & (Abs[?] & 'c | 'lhs & (Abs[?] & 'c & ~#Abs | 'lhs0 & (Numb & {name: string} | {name: string} & ~#Abs & ~#Numb))) -//│ 'e :> Mul['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} | Add['rhs]\lhs\rhs & {lhs: 'rhs, rhs: 'rhs} -//│ <: 'b & (Abs[?] & {lhs: anything, rhs: anything} & 'c | 'lhs & (Abs[?] & {lhs: anything, rhs: anything} & 'c & ~#Abs | 'lhs0 & (Numb & {lhs: anything, rhs: anything} | {lhs: anything, rhs: anything} & ~#Abs & ~#Numb))) -//│ 'c <: {body: 'b, name: string} +//│ 'tail4 <: Cons[?] & 'd | Nil +//│ 'd <: {head: {_1: string, _2: 'result}, tail: 'tail4} +//│ 'tail3 <: Cons[?] & 'c | Nil +//│ 'c <: {head: {_1: string, _2: 'result0}, tail: 'tail3} +//│ 'tail2 <: Cons[?] & 'b | Nil +//│ 'b <: {head: {_1: string, _2: 'result0}, tail: 'tail2} +//│ 'tail1 <: Cons[?] & 'g | Nil +//│ 'g <: {head: {_1: string, _2: 'result0}, tail: 'tail1} +//│ 'tail0 <: Cons[?] & 'f | Nil +//│ 'f <: {head: {_1: string, _2: 'result}, tail: 'tail0} +//│ 'tail <: Cons[?] & 'e | Nil +//│ 'e <: {head: {_1: string, _2: 'result}, tail: 'tail} +//│ 'result :> Var | 'i | Numb +//│ <: Abs[?] & 'j & 'k & 'l | 'lhs & 'lhs0 & (Add[?] & 'm | App[?] & 'n | Mul[?] & 'o | Var & 'p | 'q & (Numb | Numb & ~#Numb)) +//│ 'i :> 'result0 | 'r | Abs['i] | App['a]\lhs\rhs & {lhs: 'lhs0, rhs: 'rhs} | 'result | 's | Add['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | Mul['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | App['a0]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs0} +//│ 'result0 :> 'i +//│ <: Abs[?] & 'j & 'k & 'l | 'lhs0 & (Abs[?] & 'k & 'l & ~#Abs | 'lhs & (Add[?] & 'm | App[?] & 'n | Mul[?] & 'o | Var & 'p | 'q & (Numb | Numb & ~#Numb))) +//│ 'j <: {body: 'h, name: string} +//│ 'h <: Abs[?] & 'k | Add[?] & 'm | App[?] & 'n | Mul[?] & 'o | Numb & 'q | Var & 'p +//│ 'k <: Abs[?] & {body: 'h} | App[?] & {lhs: 'h, rhs: 'h} | Var & 'r +//│ 'r :> Var +//│ <: Abs[?] & 'j & 'k & 'l | 'lhs0 & (Abs[?] & 'k & 'l & ~#Abs | 'lhs & (Add[?] & {name: string} & 'm | App[?] & {name: string} & 'n | Mul[?] & {name: string} & 'o | Var & 'p | 'q & (Numb & {name: string} | Numb & {name: string} & ~#Numb))) +//│ 'm <: Add[?] & {lhs: 'h, rhs: 'h} | Mul[?] & {lhs: 'h, rhs: 'h} | Numb & 'result | Var & 's +//│ 's <: Var & (Abs[?] & 'j & 'k & 'l | 'lhs & 'lhs0 & (Add[?] & {name: string} & 'm | App[?] & {name: string} & 'n | Mul[?] & {name: string} & 'o | Var & 'p | 'q & (Numb & {name: string} | Numb & {name: string} & ~#Numb))) +//│ 'q <: Add[?] & {lhs: 'h, rhs: 'h} | Mul[?] & {lhs: 'h, rhs: 'h} | Numb & 'result | Var & 's +//│ 'p <: Var & 'r +//│ 'o <: Add[?] & {lhs: 'h, rhs: 'h} | Mul[?] & {lhs: 'h, rhs: 'h} | Numb & 'result | Var & 's +//│ 'n <: Abs[?] & {body: 'h} | App[?] & {lhs: 'h, rhs: 'h} | Var & 'r +//│ 'lhs0 :> Add['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | App['a0 | 'a]\lhs\rhs & {lhs: 'lhs0 | 'lhs, rhs: 'rhs0 | 'rhs} | Mul['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | Numb | Var +//│ <: 'h & 'a +//│ 'a0 :> Add['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | App['a0 | 'a]\lhs\rhs & {lhs: 'lhs0 | 'lhs, rhs: 'rhs0 | 'rhs} | Mul['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | 'i +//│ 'a :> Add['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | App['a0 | 'a]\lhs\rhs & {lhs: 'lhs0 | 'lhs, rhs: 'rhs0 | 'rhs} | Mul['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | 'i +//│ 'lhs :> Add['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | App['a0 | 'a]\lhs\rhs & {lhs: 'lhs0 | 'lhs, rhs: 'rhs0 | 'rhs} | Mul['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | Numb | Var +//│ <: 'h & 'a0 +//│ 'rhs :> 'i +//│ 'rhs0 :> 'i +//│ 'l <: {body: 'h, name: string} //│ = //│ eval_lexpr', eval_var, list_assoc and eq are not implemented //│ constrain calls : 16185 //│ annoying calls : 2300 -//│ subtyping calls : 587191 +//│ subtyping calls : 602211 :ResetFuel eval4 Nil (Abs { name = "s"; body = Add { lhs = Var { name = "s" }; rhs = Numb { num = 1 } } }) -//│ res: 'result +//│ res: 'b //│ where -//│ 'result :> Var | Abs['result] | (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | 'b -//│ 'a :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'result | 'b -//│ 'lhs :> (App['a] with {lhs: 'lhs, rhs: 'result}) | Numb | Var | 'b -//│ 'b :> Add['result] | Mul['result] +//│ 'b :> Var | Abs['b] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | Numb | (Add['b] with {lhs: 'b, rhs: 'b}) | (Mul['b] with {lhs: 'b, rhs: 'b}) +//│ 'a :> 'lhs | 'b +//│ 'lhs :> (Add['b] with {lhs: 'b, rhs: 'b}) | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | (Mul['b] with {lhs: 'b, rhs: 'b}) | Numb | Var +//│ 'rhs :> 'b //│ = //│ eval4, eval_lexpr', eval_var, list_assoc and eq are not implemented diff --git a/shared/src/test/diff/mlscript/RecErrors.mls b/shared/src/test/diff/mlscript/RecErrors.mls index 8e5bd72448..06849f7e7d 100644 --- a/shared/src/test/diff/mlscript/RecErrors.mls +++ b/shared/src/test/diff/mlscript/RecErrors.mls @@ -57,7 +57,7 @@ rec def lefts() = //│ ╙── ^^^^^^^ //│ lefts: () -> 'a //│ where -//│ 'a :> Left with {v: 'a} +//│ 'a :> Left & {v: forall 'a. 'a} diff --git a/shared/src/test/diff/mlscript/RecursiveTypes.mls b/shared/src/test/diff/mlscript/RecursiveTypes.mls index 4a8abfc9db..6bcef07a2f 100644 --- a/shared/src/test/diff/mlscript/RecursiveTypes.mls +++ b/shared/src/test/diff/mlscript/RecursiveTypes.mls @@ -141,33 +141,27 @@ if true then l else r rec def l (a: int) b = if true then l else b rec def r (a: int) b c = if true then r else if true then b else c -//│ l: 'l +//│ l: int -> 'a -> 'a //│ where -//│ 'l :> int -> 'a -> 'a -//│ 'a :> 'l +//│ 'a :> int -> 'a -> 'a //│ = [Function: l4] -//│ r: 'r +//│ r: int -> 'a -> 'a -> 'a //│ where -//│ 'r :> int -> 'a -> 'a -> 'a -//│ 'a :> 'r +//│ 'a :> int -> 'a -> 'a -> 'a //│ = [Function: r5] if true then l else r -//│ res: 'l | 'r +//│ res: int -> ('a & 'b) -> ('a -> 'a | 'b) //│ where -//│ 'r :> int -> 'a -> 'a -> 'a -//│ 'a :> 'r -//│ 'l :> int -> 'b -> 'b -//│ 'b :> 'l +//│ 'b :> int -> 'b -> 'b +//│ 'a :> int -> 'a -> 'a -> 'a //│ = [Function: l4] if true then l else r -//│ res: 'l | 'r +//│ res: int -> ('a & 'b) -> ('a -> 'a | 'b) //│ where -//│ 'r :> int -> 'a -> 'a -> 'a -//│ 'a :> 'r -//│ 'l :> int -> 'b -> 'b -//│ 'b :> 'l +//│ 'b :> int -> 'b -> 'b +//│ 'a :> int -> 'a -> 'a -> 'a //│ = [Function: l4] @@ -206,11 +200,11 @@ class C[A]: { a: A } :ns rec def foo (c: C['a]) = foo (c.a) -//│ foo: forall 'a 'b 'foo 'a0. 'foo +//│ foo: forall 'foo 'a 'a0 'b. 'foo //│ where -//│ 'foo := C['a0] -> 'b -//│ 'a0 <: 'a -//│ 'a <: C['a0] +//│ 'foo := C['a] -> 'b +//│ 'a <: 'a0 +//│ 'a0 <: C['a] foo //│ res: 'a -> nothing @@ -358,16 +352,16 @@ bar2_ty2 = bar_ty2 //│ where //│ 'r :> {x: 'r} //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.352: bar2_ty2 = bar_ty2 +//│ ║ l.346: bar2_ty2 = bar_ty2 //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type `forall 'r. 'r` does not match type `{x: 'r0}` -//│ ║ l.285: def bar_ty2: C['r] as 'r +//│ ║ l.279: def bar_ty2: C['r] as 'r //│ ║ ^^^^^ //│ ╟── but it flows into reference with expected type `{x: 'r1}` -//│ ║ l.352: bar2_ty2 = bar_ty2 +//│ ║ l.346: bar2_ty2 = bar_ty2 //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from record type: -//│ ║ l.332: def bar2_ty2: { x: 'r } as 'r +//│ ║ l.326: def bar2_ty2: { x: 'r } as 'r //│ ╙── ^^^^^^^^^ :e @@ -380,16 +374,16 @@ bar_ty2 = bar2_ty2 //│ where //│ 'r :> C['r] //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.374: bar_ty2 = bar2_ty2 +//│ ║ l.368: bar_ty2 = bar2_ty2 //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── type `{x: 'r}` is not an instance of type `C` -//│ ║ l.332: def bar2_ty2: { x: 'r } as 'r +//│ ║ l.326: def bar2_ty2: { x: 'r } as 'r //│ ║ ^^^^^^^^^ //│ ╟── but it flows into reference with expected type `C[?]` -//│ ║ l.374: bar_ty2 = bar2_ty2 +//│ ║ l.368: bar_ty2 = bar2_ty2 //│ ║ ^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.285: def bar_ty2: C['r] as 'r +//│ ║ l.279: def bar_ty2: C['r] as 'r //│ ╙── ^^^^^ @@ -411,17 +405,17 @@ f 1 :ns rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x -//│ f: forall 'a 'b 'c 'f 'd 'e 'g. 'f +//│ f: forall 'b 'a 'c 'd 'e 'g 'f. 'f //│ where -//│ 'f := 'b -> 'c +//│ 'f := 'b -> 'd //│ 'b :> 'b\a & {a: 'e} -//│ <: ({a: 'a} | ~{a: 'e} | ~{})\a & ({a: 'a} | ~{a: 'e})\a & (number | ~{a: 'e} | ~{})\a & (number | ~{a: 'e})\a & (int | ~{a: 'e} | ~{})\a & (int | ~{a: 'e})\a & 'd & int & number -//│ 'a <: 'd +//│ <: ({a: 'a} | ~{a: 'e} | ~{})\a & ({a: 'a} | ~{a: 'e})\a & (number | ~{a: 'e} | ~{})\a & (number | ~{a: 'e})\a & (int | ~{a: 'e} | ~{})\a & (int | ~{a: 'e})\a & 'g & int & number +//│ 'a <: 'g +//│ 'g :> 'b\a & {a: 'e} +//│ <: 'd //│ 'd :> 'b\a & {a: 'e} //│ <: 'c //│ 'c :> 'b\a & {a: 'e} -//│ <: 'g -//│ 'g :> 'b\a & {a: 'e} //│ <: {a: 'a} //│ 'e :> int @@ -429,10 +423,9 @@ f //│ res: 'a -> 'b //│ where //│ 'a :> 'a\a & {a: int} -//│ <: int & (int | ~{a: int})\a & (number | ~{a: int})\a & ('c | ~{a: int})\a & 'b -//│ 'c <: {a: 'b} +//│ <: int & (int | ~{a: int})\a & (number | ~{a: int})\a & ({a: 'b} | ~{a: int})\a & 'b //│ 'b :> 'a\a & {a: int} -//│ <: 'c +//│ <: {a: 'b} // Notice how what is most likely an the error is reported in call sites, // due to the delaying effect of the field removal type... @@ -442,13 +435,13 @@ f :e f 1 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.443: f 1 +//│ ║ l.436: f 1 //│ ║ ^^^ //│ ╟── operator application of type `int` does not have field 'a' -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ║ ^^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: error | int | 'a\a & {a: int} //│ where @@ -457,13 +450,13 @@ f 1 :e f { a = 1 } //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.458: f { a = 1 } +//│ ║ l.451: f { a = 1 } //│ ║ ^^^^^^^^^^^ //│ ╟── operator application of type `int` does not have field 'a' -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ║ ^^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: error @@ -480,13 +473,13 @@ f ainf //│ where //│ 'ainf :> {a: 'ainf} //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.478: f ainf +//│ ║ l.471: f ainf //│ ║ ^^^^^^ //│ ╟── operator application of type `int` does not have field 'a' -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ║ ^^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: error @@ -497,13 +490,13 @@ f infina //│ where //│ 'infina :> 0 & {a: 'infina} //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.495: f infina +//│ ║ l.488: f infina //│ ║ ^^^^^^^^ //│ ╟── operator application of type `int` does not have field 'a' -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ║ ^^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.413: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x +//│ ║ l.407: rec def f x = if x > 0 then (f (x with { a = x - 1 })).a else x //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: error | int | 'infina | 'a\a & {a: int} //│ where @@ -520,16 +513,16 @@ def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as :e f_manual 1 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.521: f_manual 1 +//│ ║ l.514: f_manual 1 //│ ║ ^^^^^^^^^^ //│ ╟── integer literal of type `1` does not have field 'a' -//│ ║ l.521: f_manual 1 +//│ ║ l.514: f_manual 1 //│ ║ ^ //│ ╟── Note: constraint arises from record type: -//│ ║ l.514: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) +//│ ║ l.507: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── from intersection type: -//│ ║ l.514: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) +//│ ║ l.507: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ res: error | 'e //│ where @@ -538,16 +531,16 @@ f_manual 1 :e f_manual { a = 1 } //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.539: f_manual { a = 1 } +//│ ║ l.532: f_manual { a = 1 } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` does not have field 'a' -//│ ║ l.539: f_manual { a = 1 } +//│ ║ l.532: f_manual { a = 1 } //│ ║ ^ //│ ╟── Note: constraint arises from record type: -//│ ║ l.514: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) +//│ ║ l.507: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── from intersection type: -//│ ║ l.514: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) +//│ ║ l.507: def f_manual: (({a: 'b & 'a & 'c} as 'a) & 'd) -> ('c | ('d | 'e\a & {a: int} as 'e)) //│ ╙── ^^^^^^^^^^^^ //│ res: 1 | error | 'e //│ where @@ -570,26 +563,26 @@ f_manual ainf // Notice the simplified type is NOT the same as that of `f`... def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) -//│ f_manual_ns: in forall 'd 'c 'b 'f 'c0. ('f & 'b & (int & ~{a: int} | (int & 'c)\a & 'c0\a & int)) -> ('b | 'd) out forall 'd 'c 'b 'f 'c0. ((int & 'c & 'c0 | ~{a: int})\a & int & 'b & 'f) -> ('b | 'd) +//│ f_manual_ns: in forall 'd 'b 'c 'c0 'f. ('b & 'f & (int & ~{a: int} | (int & 'c0)\a & 'c\a & int)) -> ('b | 'd) out forall 'd 'b 'c 'c0 'f. ((int & 'c0 & 'c | ~{a: int})\a & int & 'b & 'f) -> ('b | 'd) //│ where -//│ 'c0 <: {a: 'd & 'c0} -//│ 'c <: {a: 'c & 'd} -//│ 'b :> 'b\a & {a: int} +//│ 'c <: {a: 'd & 'c} +//│ 'c0 <: {a: 'c0 & 'd} //│ 'f <: {a: 'f} +//│ 'b :> 'b\a & {a: int} :e f_manual_ns ainf //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.581: f_manual_ns ainf +//│ ║ l.574: f_manual_ns ainf //│ ║ ^^^^^^^^^^^^^^^^ //│ ╟── type `int` does not have field 'a' -//│ ║ l.572: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) +//│ ║ l.565: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) //│ ║ ^^^ //│ ╟── Note: constraint arises from record type: -//│ ║ l.572: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) +//│ ║ l.565: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) //│ ║ ^^^^^^^^^^^^ //│ ╟── from local type binding: -//│ ║ l.572: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) +//│ ║ l.565: def f_manual_ns: 'a | ('b & (({a: 'd & 'c} as 'c) | ~{a: 'e | int} | ~{})\a & (({a: 'd & 'c} as 'c) | ~{a: 'e | int})\a & (({a: 'f} as 'c) as 'f) & (int | ~{a: 'e | int} | ~{})\a & (int | ~{a: 'e | int})\a & int & int) -> ('g | 'd | ('b | 'h\a & {a: 'e | int} as 'h)) //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ res: error @@ -630,13 +623,13 @@ r + 1 :e r.a //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.631: r.a +//│ ║ l.624: r.a //│ ║ ^^^ //│ ╟── integer literal of type `1` does not have field 'a' -//│ ║ l.622: r = f 1 +//│ ║ l.615: r = f 1 //│ ║ ^ //│ ╟── but it flows into reference with expected type `{a: ?a}` -//│ ║ l.631: r.a +//│ ║ l.624: r.a //│ ╙── ^ //│ res: error | int diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index ebaf155c3c..d8b1402fd3 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -56,9 +56,9 @@ class Pair[A, B](a: A, b: B) fun unbox(x) = if x is Numbr(n) then n Vectr(xs) then map of xs, unbox -//│ fun unbox: forall 'a. (Numbr | Vectr) -> 'a +//│ fun unbox: forall 'a. (Numbr | Vectr) -> (Int | 'a) //│ where -//│ 'a :> Int | Array['a] +//│ 'a :> Array[Int | 'a] fun add(e) = if e is @@ -88,9 +88,9 @@ let v = Vectr of [Numbr(10), Numbr(20), Numbr(30)] //│ = Vectr {} unbox(v) -//│ forall 'a. 'a +//│ forall 'a. Int | 'a //│ where -//│ 'a :> Int | Array['a] +//│ 'a :> Array[Int | 'a] //│ res //│ = [ 10, 20, 30 ] @@ -101,9 +101,9 @@ let res = add of Pair of (Vectr of [Numbr(1), Numbr(2)]), (Vectr of [Numbr(3), v //│ = Vectr {} unbox(res) -//│ forall 'a. 'a +//│ forall 'a. Int | 'a //│ where -//│ 'a :> Int | Array['a] +//│ 'a :> Array[Int | 'a] //│ res //│ = [ 4, [ 12, 22, 32 ] ] diff --git a/shared/src/test/diff/nu/Eval.mls b/shared/src/test/diff/nu/Eval.mls index 550bf3ee54..2e0961e10d 100644 --- a/shared/src/test/diff/nu/Eval.mls +++ b/shared/src/test/diff/nu/Eval.mls @@ -215,12 +215,12 @@ fun eval(t, env) = if t is else err(String(pree) ++ " does not have field " ++ nme) Rcd(fs) then Rcd of fs |> Lists.map of {key, value} => {key, value: eval(value, env)} -//│ fun eval: forall 'a 'A 'b 'Sub. ('a, Cons[{key: Eql[Str], value: 'b}] & {List#A <: {key: Eql[Str], value: 'b}} & List[{key: Eql[Str], value: 'b}] | Nil & {List#A <: {key: Eql[Str], value: 'b}} & List[{key: Eql[Str], value: 'b}]) -> 'Sub +//│ fun eval: forall 'a 'b 'c. ('b, Cons[{key: Eql[Str], value: 'c}] & {List#A <: {key: Eql[Str], value: 'c}} & List[{key: Eql[Str], value: 'c}] | Nil & {List#A <: {key: Eql[Str], value: 'c}} & List[{key: Eql[Str], value: 'c}]) -> 'a //│ where -//│ 'b :> 'Sub -//│ <: Object & ~#Rcd | Rcd['b] -//│ 'Sub :> Lam | Lit['A] | Rcd['Sub] | 'b -//│ 'a <: App | Lam | Lit['A] | Rcd['a] | Sel | Var +//│ 'c :> 'a +//│ <: Object & ~#Rcd | Rcd['c] +//│ 'a :> 'c | Rcd[Lam | Lit[nothing] | 'a] | Lam | Lit[nothing] +//│ 'b <: App | Lam | Lit[anything] | Rcd['b] | Sel | Var eval : (Term, List[{key: Str, value: Value}]) -> Value //│ (Term, List[{key: Str, value: Value}]) -> Value @@ -233,23 +233,23 @@ let rcd = Rcd({key: "a", value: IntLit(0)} :: Nil) //│ = Rcd {} eval of rcd, Nil -//│ 'Sub +//│ 'a //│ where -//│ 'Sub :> Lam | Lit[Int] | Rcd['Sub] +//│ 'a :> Lam | Lit[Int] | Rcd[Lam | Lit[Int] | 'a] //│ res //│ = Rcd {} eval of Sel(rcd, "a"), Nil -//│ 'Sub +//│ 'a //│ where -//│ 'Sub :> Lam | Lit[nothing] | Rcd['Sub] +//│ 'a :> Lam | Lit[nothing] | Rcd[Lam | Lit[nothing] | 'a] //│ res //│ = IntLit {} eval of App(Lam("x" :: Nil, Sel(Var("x"), "a")), rcd :: Nil), Nil -//│ 'Sub +//│ 'a //│ where -//│ 'Sub :> Lam | Lit[nothing] | Rcd['Sub] +//│ 'a :> Lam | Lit[nothing] | Rcd[Lam | Lit[nothing] | 'a] //│ res //│ = IntLit {} diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index 81cab6f15a..e9e90e00d5 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -49,21 +49,21 @@ mixin EvalNegNeg { module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ module TestLang { -//│ fun eval: 'a -> Int +//│ fun eval: (Neg['A] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'a <: Neg['A] | Object & 'b & ~#Neg -//│ 'A <: Neg['a & 'A] | Neg['A] & ~#Neg | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit | Neg['a] +//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'b <: Neg['A] | Object & 'a & ~#Neg +//│ 'a <: Add['b] | Lit | Neg['b] fun mk(n) = if n is 0 then Lit(3) 1 then Neg(mk(n - 1)) _ then Add(mk(n - 1), mk(n - 1)) -//│ fun mk: forall 'E. (0 | 1 | Int & ~0 & ~1) -> 'E +//│ fun mk: forall 'a. (0 | 1 | Int & ~0 & ~1) -> (Lit | 'a) //│ where -//│ 'E :> Add['E] | Lit | Neg['E] +//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] TestLang.eval(mk(0)) //│ Int diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 0220f31374..8f4d21c958 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -78,9 +78,9 @@ foo :re foo.x -//│ 'x +//│ {y: 'foo} //│ where -//│ 'x :> {y: {x: 'x}} +//│ 'foo :> {x: {y: 'foo}} //│ res //│ Runtime error: //│ RangeError: Maximum call stack size exceeded @@ -115,11 +115,11 @@ foo fun foo(a) = {h1: a, t1: bar(a)} fun bar(b) = {h2: b, t2: foo(b)} -//│ fun foo: forall 'a 'b 'c. 'c -> 'a -//│ fun bar: forall 'b 'c. 'c -> 'b +//│ fun foo: forall 'a 'b 'c. 'c -> {h1: 'c, t1: 'a} +//│ fun bar: forall 'b 'c. 'c -> {h2: 'c, t2: 'b} //│ where -//│ 'a :> {h1: 'c, t1: 'b} -//│ 'b :> {h2: 'c, t2: 'a} +//│ 'a :> {h2: 'c, t2: 'b} +//│ 'b :> {h1: 'c, t1: 'a} diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index bc648bf6bf..c394d2af85 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -103,36 +103,31 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'A}], 'b) -> ('A | 'a) +//│ fun eval: (List[{_1: Str, _2: 'a}], 'b) -> 'a //│ } //│ where //│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Var -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['a] | Abs['a] | Var Test1.eval(Nil(), Var("a")) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['a] | Abs['a] | Var Test1.eval(Nil(), Abs("b", Var("a"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['a] | Abs['a] | Var Test1.eval(Cons(["c", Var("d")], Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['a] | Abs['a] | Var Test1.eval(Cons(["c", Abs("d", Var("d"))], Nil()), App(Abs("b", Var("b")), Var("c"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Abs[Var] | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var class Numb(n: Int) class Add(l: A, r: A) @@ -186,35 +181,32 @@ Test2.eval(Cons(["a", Abs("d", Var("d"))], Nil()), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: 'b}], 'c) -> ('A | 'a) +//│ fun eval: (List[{_1: Str, _2: 'a}], 'b) -> 'c //│ } //│ where -//│ 'b :> 'A +//│ 'a :> 'c //│ <: Object -//│ 'A :> 'a | Numb | Var | 'b | 'd -//│ 'd <: Add['c] | Mul['c] | Numb | Var -//│ 'c <: Abs['c] | App['c & (Abs['c] | Object & ~#Abs)] | Object & 'd & ~#Abs & ~#App -//│ 'a :> App['A] | Abs['A] +//│ 'c :> App['c] | Abs['c] | Numb | Var | 'a | 'd +//│ 'd <: Add['b] | Mul['b] | Numb | Var +//│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Object & 'd & ~#Abs & ~#App Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil()), Abs("a", Var("a"))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Abs[Var] | Numb | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Numb | Var Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil()), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) -//│ forall 'a. 'A | 'a +//│ 'a //│ where -//│ 'A :> 'a | Abs[Var] | Add[Numb | Var] | Numb | Var -//│ 'a :> App['A] | Abs['A] +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Numb | Var] | Numb | Var module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: (List[{_1: Str, _2: 'a}], 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('A | 'a | 'b) +//│ fun eval: (List[{_1: Str, _2: 'a}], 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) //│ } //│ where -//│ 'a :> 'b | 'A +//│ 'a :> 'b | 'c //│ <: Object -//│ 'A :> Numb | 'a | Abs['A] | App['A] | Var +//│ 'c :> Abs[Numb | 'a | 'c] | App[Numb | 'a | 'c] | Numb | Var | 'a //│ 'b <: Add['b] | Mul['b] | Numb | Var diff --git a/shared/src/test/diff/nu/repro0.mls b/shared/src/test/diff/nu/repro0.mls index 72b3f9fadf..b9f0b47ce7 100644 --- a/shared/src/test/diff/nu/repro0.mls +++ b/shared/src/test/diff/nu/repro0.mls @@ -12,12 +12,11 @@ let res = EvalAddLit.eval(add11) //│ class Add[E](lhs: E) //│ val add11: 'E //│ module EvalAddLit { -//│ fun eval: forall 'lhs 'A. (e: 'lhs) -> nothing +//│ fun eval: forall 'A. (e: Add['A]) -> nothing //│ } //│ let res: nothing //│ where -//│ 'lhs <: Add['A] -//│ 'A <: 'lhs +//│ 'A <: Add['A] //│ 'E :> Add['E] diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index 50eee1b07d..99f982406f 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -37,9 +37,9 @@ fun mk(n) = if n is 0 then Lit(0) 1 then Neg(mk(n)) _ then Add(mk(n), mk(n)) -//│ fun mk: forall 'E. Object -> 'E +//│ fun mk: forall 'a. Object -> (Lit | 'a) //│ where -//│ 'E :> Add['E] | Lit | Neg['E] +//│ 'a :> Neg[Lit | 'a] | Add[Lit | 'a] :stats TestLang.eval(mk(0)) diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index d9dbb5202b..29ff0ec935 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -319,7 +319,7 @@ fun subst(t, n, v) = _ then Abs(Var(name), subst(body, n, v)) App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t -//│ fun subst: forall 'a. (Abs | App | Term & Object & 'a & ~#Abs & ~#App & ~#Var | Var, anything, Term & Object & 'a) -> (Abs | App | Var | 'a) +//│ fun subst: forall 'a. (Abs | App | Term & Object & 'a & ~#Abs & ~#App & ~#Var | Var, anything, Term & Object & 'a) -> ('a | Abs | App | Var) fun showSubst(t, n, v) = showTerm(t) ++ " [" ++ n ++ " / " ++ showTerm(v) ++ "]" ++ " => " ++ showTerm(subst(t, n, v)) diff --git a/shared/src/test/diff/tapl/SimplyTyped.mls b/shared/src/test/diff/tapl/SimplyTyped.mls index 771fee6190..400be3d6e9 100644 --- a/shared/src/test/diff/tapl/SimplyTyped.mls +++ b/shared/src/test/diff/tapl/SimplyTyped.mls @@ -129,21 +129,26 @@ fun find(t, k) = Empty then None() //│ empty: Empty //│ = [Function: empty] -//│ insert: ('a, string & 'key, 'value,) -> 'right +//│ insert: (Empty | Node & 'a, string & 'key, 'value,) -> (Node & {key: 'key, left: Empty | 'left, right: Empty | 'right, value: 'value} | 'b) //│ where -//│ 'right :> Node & { -//│ key: 'key, -//│ left: Empty | 'left | 'right, -//│ right: Empty | 'right | 'right0, +//│ 'b :> Node & { +//│ key: 'key0, +//│ left: Node & {key: 'key, left: Empty | 'left, right: Empty | 'right, value: 'value} | 'b, +//│ right: 'right, +//│ value: 'value +//│ } | Node & { +//│ key: 'key0, +//│ left: 'left, +//│ right: Node & {key: 'key, left: Empty | 'left, right: Empty | 'right, value: 'value} | 'b, //│ value: 'value //│ } -//│ 'a <: Empty | Node & {key: string & 'key, left: 'left, right: 'right0} -//│ 'right0 <: 'a -//│ 'left <: 'a +//│ 'a <: {key: string & 'key0, left: 'left, right: 'right} +//│ 'right <: Empty | Node & 'a +//│ 'left <: Empty | Node & 'a //│ = [Function: insert] -//│ find: ('right, string,) -> (Some & {value: 'value} | None) +//│ find: (Empty | Node & 'a, string,) -> (Some & {value: 'value} | None) //│ where -//│ 'right <: Empty | Node & {key: string, left: 'right, right: 'right, value: 'value} +//│ 'a <: {key: string, left: Empty | Node & 'a, right: Empty | Node & 'a, value: 'value} //│ = [Function: find] fun showType(ty) = @@ -151,9 +156,12 @@ fun showType(ty) = FunctionType(PrimitiveType(name), rhs) then concat3(name, " -> ", showType(rhs)) FunctionType(lhs, rhs) then concat4("(", showType(lhs), ") -> ", showType(rhs)) PrimitiveType(name) then name -//│ showType: 'lhs -> string +//│ showType: (FunctionType & 'a | PrimitiveType & {name: string}) -> string //│ where -//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} +//│ 'a <: { +//│ lhs: FunctionType & 'a | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'a | PrimitiveType & {name: string} +//│ } //│ = [Function: showType] showType(_t("int")) @@ -175,10 +183,16 @@ fun typeEqual(t1, t2) = t1 is FunctionType(lhs1, rhs1) and t2 is FunctionType(lhs2, rhs2) then typeEqual(lhs1, lhs2) and typeEqual(rhs1, rhs2) _ then false -//│ typeEqual: ('rhs, 'rhs0,) -> bool +//│ typeEqual: (FunctionType & 'a | PrimitiveType | ~FunctionType & ~PrimitiveType, FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType,) -> bool //│ where -//│ 'rhs0 <: FunctionType & {lhs: 'rhs0, rhs: 'rhs0} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'rhs <: FunctionType & {lhs: 'rhs, rhs: 'rhs} | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ 'b <: { +//│ lhs: FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'a <: { +//│ lhs: FunctionType & 'a | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'a | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } //│ = [Function: typeEqual] fun showTerm(t) = @@ -189,10 +203,24 @@ fun showTerm(t) = App(Abs(lhs0, ty, lhs1), rhs) then concat5("((", showTerm(Abs(lhs0, ty, rhs)), ") ", showTerm(rhs), ")") App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) -//│ showTerm: 'rhs -> string +//│ showTerm: (Abs & 'a | App & 'b | Lit | Var) -> string //│ where -//│ 'rhs <: Abs & {lhs: 'rhs, lty: 'lty, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, lty: 'lty} | ~#Abs), rhs: 'rhs} | Lit | Var -//│ 'lty <: FunctionType & {lhs: 'lty & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lty} | PrimitiveType & {name: string} +//│ 'a <: { +//│ lhs: Abs & 'a | App & 'b | Lit | Var, +//│ lty: FunctionType & 'c | PrimitiveType & {name: string}, +//│ rhs: Abs & 'a | App & 'b | Lit | Var +//│ } +//│ 'b <: { +//│ lhs: App & 'b | Lit | Var | 'a & (Abs & { +//│ lhs: Abs & 'a | App & 'b | Lit | Var, +//│ lty: FunctionType & 'c | PrimitiveType & {name: string} +//│ } | Abs & ~#Abs), +//│ rhs: Abs & 'a | App & 'b | Lit | Var +//│ } +//│ 'c <: { +//│ lhs: FunctionType & 'c | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'c | PrimitiveType & {name: string} +//│ } //│ = [Function: showTerm] showTerm(Var("x")) @@ -227,141 +255,234 @@ fun typeTerm(t, ctx) = Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) Err(message) then Err(message) //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.212: fun typeTerm(t, ctx) = +//│ ║ l.240: fun typeTerm(t, ctx) = //│ ║ ^^^^^^^^^^ -//│ ║ l.213: if t is +//│ ║ l.241: if t is //│ ║ ^^^^^^^^^ -//│ ║ l.214: Lit(_, ty) then Ok(ty) +//│ ║ l.242: Lit(_, ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.215: Var(name) and find(ctx, name) is +//│ ║ l.243: Var(name) and find(ctx, name) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.216: Some(ty) then Ok(ty) +//│ ║ l.244: Some(ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.217: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ l.245: None then Err(concat3("unbound variable `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.218: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ l.246: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.219: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ l.247: Ok(resTy) then Ok(FunctionType(ty, resTy)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.220: Err(message) then Err(message) +//│ ║ l.248: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.221: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ l.249: App(lhs, rhs) and typeTerm(lhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.222: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ l.250: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.223: Ok(aTy) and +//│ ║ l.251: Ok(aTy) and //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.224: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ l.252: typeEqual(pTy, aTy) then Ok(resTy) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.225: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ l.253: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.226: Err(message) then Err(message) +//│ ║ l.254: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.227: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ l.255: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.228: Err(message) then Err(message) +//│ ║ l.256: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. //│ ╔══[ERROR] Cyclic-looking constraint while typing binding of lambda expression; a type annotation may be required -//│ ║ l.212: fun typeTerm(t, ctx) = +//│ ║ l.240: fun typeTerm(t, ctx) = //│ ║ ^^^^^^^^^^ -//│ ║ l.213: if t is +//│ ║ l.241: if t is //│ ║ ^^^^^^^^^ -//│ ║ l.214: Lit(_, ty) then Ok(ty) +//│ ║ l.242: Lit(_, ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.215: Var(name) and find(ctx, name) is +//│ ║ l.243: Var(name) and find(ctx, name) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.216: Some(ty) then Ok(ty) +//│ ║ l.244: Some(ty) then Ok(ty) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.217: None then Err(concat3("unbound variable `", name, "`")) +//│ ║ l.245: None then Err(concat3("unbound variable `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.218: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is +//│ ║ l.246: Abs(Var(name), ty, body) and typeTerm(body, insert(ctx, name, ty)) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.219: Ok(resTy) then Ok(FunctionType(ty, resTy)) +//│ ║ l.247: Ok(resTy) then Ok(FunctionType(ty, resTy)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.220: Err(message) then Err(message) +//│ ║ l.248: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.221: App(lhs, rhs) and typeTerm(lhs, ctx) is +//│ ║ l.249: App(lhs, rhs) and typeTerm(lhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.222: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is +//│ ║ l.250: Ok(FunctionType(pTy, resTy)) and typeTerm(rhs, ctx) is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.223: Ok(aTy) and +//│ ║ l.251: Ok(aTy) and //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.224: typeEqual(pTy, aTy) then Ok(resTy) +//│ ║ l.252: typeEqual(pTy, aTy) then Ok(resTy) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.225: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) +//│ ║ l.253: _ then Err(concat5("expect the argument to be of type `", showType(pTy), "` but found `", showType(aTy), "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.226: Err(message) then Err(message) +//│ ║ l.254: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.227: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) +//│ ║ l.255: Ok(PrimitiveType(name)) then Err(concat3("cannot apply primitive type `", name, "`")) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.228: Err(message) then Err(message) +//│ ║ l.256: Err(message) then Err(message) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── Note: use flag `:ex` to see internal error info. -//│ typeTerm: ('rhs, 'right,) -> (Err & {message: 'message} | Ok & {value: 'ty}) -//│ where -//│ 'right <: 'right0 & (Empty | Node & {key: string, left: 'right, right: 'right}) -//│ 'right0 <: Empty | Node & { -//│ key: string, -//│ left: 'right0, -//│ right: 'right0, -//│ value: 'lhs & 'ty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) -//│ } -//│ 'rhs <: Abs & { -//│ lhs: Var & {name: string}, -//│ lty: 'lhs & 'rhs0 & 'lhs0 & 'lty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)), -//│ rhs: 'rhs -//│ } | App & {lhs: 'rhs, rhs: 'rhs} | Lit & { -//│ ty: 'lhs & 'ty & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) -//│ } | Var & {name: string} -//│ 'a <: {lhs: 'rhs0 & 'lhs0, rhs: 'rhs1} -//│ 'rhs1 :> 'ty -//│ <: 'lhs & (PrimitiveType & {name: string} | 'a & (FunctionType & 'b | FunctionType & ~#FunctionType)) -//│ 'b <: {lhs: 'rhs2, rhs: 'rhs2} -//│ 'rhs2 <: FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'ty :> 'lty | FunctionType & {lhs: 'lty, rhs: 'ty} | 'rhs1 -//│ 'lhs0 <: FunctionType & {lhs: 'lhs0 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs0} | PrimitiveType & {name: string} -//│ 'rhs0 <: FunctionType & {lhs: 'rhs0, rhs: 'rhs0} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} +//│ typeTerm: (Abs & 'a | App & 'b | Lit & {ty: 'ty & (FunctionType & 'c & 'd & 'e | PrimitiveType & {name: string})} | Var & {name: string}, Empty | Node & 'f & 'g,) -> (Err & { +//│ message: forall 'message 'message0 'message1. string | 'message | 'message0 | 'message1 +//│ } | Ok & {value: forall 'h. 'lty | 'rhs | 'ty | 'h}) +//│ where +//│ 'message :> forall 'message0 'message1. string | 'message0 | 'message1 +//│ 'message0 :> forall 'message 'message1. 'message | 'message1 +//│ 'message1 :> forall 'message 'message0. 'message | 'message0 +//│ 'g <: {key: string, left: Empty | Node & 'f & 'g, right: Empty | Node & 'f & 'g} +//│ 'f <: { +//│ key: string, +//│ left: Empty | Node & 'f, +//│ right: Empty | Node & 'f, +//│ value: 'ty & (FunctionType & 'c & 'd & 'e | PrimitiveType & {name: string}) +//│ } +//│ 'a <: { +//│ lhs: Var & {name: string}, +//│ lty: 'lty & (FunctionType & 'c & 'd & 'e & 'i & 'j | PrimitiveType & {name: string}), +//│ rhs: Abs & 'a | App & 'b | Lit & {ty: 'ty & (FunctionType & 'c & 'd & 'e | PrimitiveType & {name: string})} | Var & {name: string} +//│ } +//│ 'b <: { +//│ lhs: Abs & 'a | App & 'b | Lit & {ty: 'ty & (FunctionType & 'c & 'd & 'e | PrimitiveType & {name: string})} | Var & {name: string}, +//│ rhs: Abs & 'a | App & 'b | Lit & {ty: 'ty & (FunctionType & 'c & 'd & 'e | PrimitiveType & {name: string})} | Var & {name: string} +//│ } +//│ 'e <: { +//│ lhs: PrimitiveType & {name: string} | 'j & (FunctionType & 'i | FunctionType & ~#FunctionType), +//│ rhs: 'rhs +//│ } +//│ 'rhs :> forall 'value. 'value +//│ <: FunctionType & 'c & 'd & 'e | PrimitiveType & {name: string} +//│ 'value :> forall 'h. 'lty | 'rhs | 'ty | 'h +//│ 'h :> FunctionType & {lhs: 'lty, rhs: forall 'value. 'value} +//│ 'i <: { +//│ lhs: FunctionType & 'i | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'i | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'j <: { +//│ lhs: FunctionType & 'j | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'j | PrimitiveType & {name: string} +//│ } +//│ 'd <: { +//│ lhs: FunctionType & 'd | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'd | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'c <: { +//│ lhs: FunctionType & 'c | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'c | PrimitiveType & {name: string} +//│ } //│ = [Function: typeTerm] fun showTypeTerm(t, ctx) = if typeTerm(t, ctx) is Ok(ty) then concat3(showTerm(t), " : ", showType(ty)) Err(message) then concat2("Type error: ", message) -//│ showTypeTerm: ('rhs & 'rhs0, 'right & (Empty | Node & 'a),) -> string +//│ showTypeTerm: (Abs & 'a & 'b | App & 'c & 'd | Lit & {ty: FunctionType & 'e & 'f & 'g & 'h | PrimitiveType & {name: string}} | Var & {name: string}, Empty | Node & 'i & 'j,) -> string //│ where -//│ 'a <: {key: string, left: 'right0, right: 'right0} -//│ 'right0 <: 'right1 & (Empty | Node & 'a) -//│ 'right1 <: Empty | Node & {key: string, left: 'right1, right: 'right1, value: 'rhs1} -//│ 'rhs1 <: 'lhs & 'lhs0 & (FunctionType & {lhs: 'rhs2 & 'lhs1, rhs: 'rhs1} & ~#FunctionType | FunctionType & {lhs: 'rhs2 & 'lhs1, rhs: 'rhs1} & 'b | PrimitiveType & {name: string}) -//│ 'b <: {lhs: 'rhs3, rhs: 'rhs3} -//│ 'rhs3 <: FunctionType & 'b | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs1 <: FunctionType & {lhs: 'lhs1 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs1} | PrimitiveType & {name: string} -//│ 'rhs2 <: FunctionType & {lhs: 'rhs2, rhs: 'rhs2} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs0 <: FunctionType & {lhs: 'lhs0 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs0} | PrimitiveType & {name: string} -//│ 'right <: Empty | Node & {key: string, left: 'right, right: 'right, value: 'rhs4} -//│ 'rhs4 <: 'lhs2 & 'lhs & (FunctionType & {lhs: 'rhs5 & 'lhs3, rhs: 'rhs4} & ~#FunctionType | FunctionType & {lhs: 'rhs5 & 'lhs3, rhs: 'rhs4} & 'c | PrimitiveType & {name: string}) -//│ 'c <: {lhs: 'rhs6, rhs: 'rhs6} -//│ 'rhs6 <: FunctionType & 'c | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs3 <: FunctionType & {lhs: 'lhs3 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs3} | PrimitiveType & {name: string} -//│ 'rhs5 <: FunctionType & {lhs: 'rhs5, rhs: 'rhs5} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs2 <: FunctionType & {lhs: 'lhs2 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs2} | PrimitiveType & {name: string} -//│ 'rhs0 <: Abs & {lhs: 'rhs0, lty: 'lty, rhs: 'rhs0} | App & {lhs: 'rhs0 & (Abs & {lhs: 'rhs0, lty: 'lty} | ~#Abs), rhs: 'rhs0} | Lit | Var -//│ 'lty <: FunctionType & {lhs: 'lty & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lty} | PrimitiveType & {name: string} -//│ 'rhs <: Abs & { +//│ 'j <: { +//│ key: string, +//│ left: Empty | Node & 'j, +//│ right: Empty | Node & 'j, +//│ value: FunctionType & 'h & 'k & 'l & 'm | PrimitiveType & {name: string} +//│ } +//│ 'm <: { +//│ lhs: PrimitiveType & {name: string} | 'n & (FunctionType & 'o | FunctionType & ~#FunctionType), +//│ rhs: FunctionType & 'h & 'k & 'l & 'm | PrimitiveType & {name: string} +//│ } +//│ 'o <: { +//│ lhs: FunctionType & 'o | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'o | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'n <: { +//│ lhs: FunctionType & 'n | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'n | PrimitiveType & {name: string} +//│ } +//│ 'l <: { +//│ lhs: FunctionType & 'l | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'l | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'k <: { +//│ lhs: FunctionType & 'k | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'k | PrimitiveType & {name: string} +//│ } +//│ 'i <: {key: string, left: Empty | Node & 'i & 'p, right: Empty | Node & 'i & 'p} +//│ 'p <: { +//│ key: string, +//│ left: Empty | Node & 'p, +//│ right: Empty | Node & 'p, +//│ value: FunctionType & 'h & 'q & 'r & 's | PrimitiveType & {name: string} +//│ } +//│ 's <: { +//│ lhs: PrimitiveType & {name: string} | 't & (FunctionType & 'u | FunctionType & ~#FunctionType), +//│ rhs: FunctionType & 'h & 'q & 'r & 's | PrimitiveType & {name: string} +//│ } +//│ 'u <: { +//│ lhs: FunctionType & 'u | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'u | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 't <: { +//│ lhs: FunctionType & 't | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 't | PrimitiveType & {name: string} +//│ } +//│ 'r <: { +//│ lhs: FunctionType & 'r | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'r | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'q <: { +//│ lhs: FunctionType & 'q | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'q | PrimitiveType & {name: string} +//│ } +//│ 'b <: { +//│ lhs: Abs & 'b | App & 'd | Lit | Var, +//│ lty: FunctionType & 'v | PrimitiveType & {name: string}, +//│ rhs: Abs & 'b | App & 'd | Lit | Var +//│ } +//│ 'd <: { +//│ lhs: App & 'd | Lit | Var | 'b & (Abs & { +//│ lhs: Abs & 'b | App & 'd | Lit | Var, +//│ lty: FunctionType & 'v | PrimitiveType & {name: string} +//│ } | Abs & ~#Abs), +//│ rhs: Abs & 'b | App & 'd | Lit | Var +//│ } +//│ 'v <: { +//│ lhs: FunctionType & 'v | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'v | PrimitiveType & {name: string} +//│ } +//│ 'a <: { //│ lhs: Var & {name: string}, -//│ lty: 'lhs4 & 'rhs7 & 'lhs5 & 'lhs & (PrimitiveType & {name: string} | 'd & (FunctionType & 'e | FunctionType & ~#FunctionType)), -//│ rhs: 'rhs -//│ } | App & {lhs: 'rhs, rhs: 'rhs} | Lit & {ty: 'rhs8} | Var & {name: string} -//│ 'd <: {lhs: 'rhs7 & 'lhs5, rhs: 'rhs8} -//│ 'rhs8 <: 'lhs4 & 'lhs & (PrimitiveType & {name: string} | 'd & (FunctionType & 'e | FunctionType & ~#FunctionType)) -//│ 'e <: {lhs: 'rhs9, rhs: 'rhs9} -//│ 'rhs9 <: FunctionType & 'e | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs <: FunctionType & {lhs: 'lhs & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs} | PrimitiveType & {name: string} -//│ 'lhs5 <: FunctionType & {lhs: 'lhs5 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs5} | PrimitiveType & {name: string} -//│ 'rhs7 <: FunctionType & {lhs: 'rhs7, rhs: 'rhs7} | PrimitiveType | ~FunctionType & ~PrimitiveType -//│ 'lhs4 <: FunctionType & {lhs: 'lhs4 & (PrimitiveType & {name: string} | ~#PrimitiveType), rhs: 'lhs4} | PrimitiveType & {name: string} +//│ lty: FunctionType & 'e & 'f & 'g & 'w & 'x & 'h | PrimitiveType & {name: string}, +//│ rhs: Abs & 'a | App & 'c | Lit & {ty: FunctionType & 'e & 'f & 'g & 'h | PrimitiveType & {name: string}} | Var & {name: string} +//│ } +//│ 'c <: { +//│ lhs: Abs & 'a | App & 'c | Lit & {ty: FunctionType & 'e & 'f & 'g & 'h | PrimitiveType & {name: string}} | Var & {name: string}, +//│ rhs: Abs & 'a | App & 'c | Lit & {ty: FunctionType & 'e & 'f & 'g & 'h | PrimitiveType & {name: string}} | Var & {name: string} +//│ } +//│ 'g <: { +//│ lhs: PrimitiveType & {name: string} | 'x & (FunctionType & 'w | FunctionType & ~#FunctionType), +//│ rhs: FunctionType & 'e & 'f & 'g & 'h | PrimitiveType & {name: string} +//│ } +//│ 'h <: { +//│ lhs: FunctionType & 'h | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'h | PrimitiveType & {name: string} +//│ } +//│ 'w <: { +//│ lhs: FunctionType & 'w | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'w | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'x <: { +//│ lhs: FunctionType & 'x | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'x | PrimitiveType & {name: string} +//│ } +//│ 'f <: { +//│ lhs: FunctionType & 'f | PrimitiveType | ~FunctionType & ~PrimitiveType, +//│ rhs: FunctionType & 'f | PrimitiveType | ~FunctionType & ~PrimitiveType +//│ } +//│ 'e <: { +//│ lhs: FunctionType & 'e | PrimitiveType & {name: string}, +//│ rhs: FunctionType & 'e | PrimitiveType & {name: string} +//│ } //│ = [Function: showTypeTerm] // FIXME diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls index 1eafbd9ade..65d6ead649 100644 --- a/shared/src/test/diff/tapl/Untyped.mls +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -146,10 +146,10 @@ fun listConcat(xs, ys) = if xs is Nil() then ys Cons(x, xs') then Cons(x, listConcat(xs', ys)) -//│ listConcat: ('tail, 'tail0,) -> 'tail0 +//│ listConcat: (Cons & 'a | Nil, 'b,) -> 'b //│ where -//│ 'tail0 :> Cons & {head: 'head, tail: 'tail0} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ 'b :> Cons & {head: 'head, tail: 'b} +//│ 'a <: {head: 'head, tail: Cons & 'a | Nil} //│ = [Function: listConcat] fun listContains(xs, x) = @@ -158,9 +158,9 @@ fun listContains(xs, x) = Cons(x', xs') and eq(x)(x') then true _ then listContains(xs', x) -//│ listContains: ('tail, anything,) -> Bool +//│ listContains: (Cons & 'a | Nil, anything,) -> Bool //│ where -//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ 'a <: {head: anything, tail: Cons & 'a | Nil} //│ = [Function: listContains] // Remove all occurrences of x from xs. @@ -170,10 +170,10 @@ fun listWithout(xs, x) = Cons(x', xs') and eq(x)(x') then listWithout(xs', x) _ then Cons(x', listWithout(xs', x)) -//│ listWithout: ('tail, anything,) -> 'tail0 +//│ listWithout: (Cons & 'a | Nil, anything,) -> 'b //│ where -//│ 'tail0 :> Nil | Cons & {head: 'head, tail: 'tail0} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ 'b :> Nil | Cons & {head: 'head, tail: 'b} +//│ 'a <: {head: 'head, tail: Cons & 'a | Nil} //│ = [Function: listWithout] fun listJoin(xs, sep) = @@ -181,9 +181,9 @@ fun listJoin(xs, sep) = Nil() then "" Cons(x, Nil()) then toString(x) Cons(x, xs') then concat3(toString(x), sep, listJoin(xs', sep)) -//│ listJoin: ('tail, string,) -> string +//│ listJoin: (Cons & 'a | Nil, string,) -> string //│ where -//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ 'a <: {head: anything, tail: Cons & 'a | Nil} //│ = [Function: listJoin] listJoin(list3("x", "y", "z"), ", ") @@ -214,9 +214,13 @@ fun showTerm(t) = App(Abs(lhs0, lhs1), rhs) then concat8("((", "&", showTerm(lhs0), ". ", showTerm(lhs1), ") ", showTerm(rhs), ")") App(lhs, rhs) then par(concat3(showTerm(lhs), " ", showTerm(rhs))) -//│ showTerm: 'rhs -> string +//│ showTerm: (Abs & 'a | App & 'b | Var) -> string //│ where -//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ 'a <: {lhs: Abs & 'a | App & 'b | Var, rhs: Abs & 'a | App & 'b | Var} +//│ 'b <: { +//│ lhs: App & 'b | Var | 'a & (Abs & 'a | Abs & ~#Abs), +//│ rhs: Abs & 'a | App & 'b | Var +//│ } //│ = [Function: showTerm] showTerm(Var("x")) @@ -258,17 +262,29 @@ fun hasFree(t, n) = Abs(Var(name), body) then hasFree(body, n) App(lhs, rhs) then hasFree(lhs, n) || hasFree(rhs, n) _ then false -//│ hasFree: ('rhs, anything,) -> bool +//│ hasFree: (Abs & 'a | App & 'b | Var | ~Abs & ~App & ~Var, anything,) -> bool //│ where -//│ 'rhs <: Abs & {rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var | ~Abs & ~App & ~Var +//│ 'a <: {lhs: anything, rhs: Abs & 'a | App & 'b | Var | ~Abs & ~App & ~Var} +//│ 'b <: { +//│ lhs: Abs & 'a | App & 'b | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'a | App & 'b | Var | ~Abs & ~App & ~Var +//│ } //│ = [Function: hasFree] fun showHasFree(t, n) = concat4(showTerm(t), if hasFree(t, n) then " has " else " DOES NOT have ", "free variable ", n) -//│ showHasFree: ('rhs & 'rhs0, string,) -> string +//│ showHasFree: (Abs & 'a & 'b | App & 'c & 'd | Var, string,) -> string //│ where -//│ 'rhs0 <: Abs & {rhs: 'rhs0} | App & {lhs: 'rhs0, rhs: 'rhs0} | Var | ~Abs & ~App & ~Var -//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ 'b <: {lhs: anything, rhs: Abs & 'b | App & 'd | Var | ~Abs & ~App & ~Var} +//│ 'd <: { +//│ lhs: Abs & 'b | App & 'd | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'b | App & 'd | Var | ~Abs & ~App & ~Var +//│ } +//│ 'a <: {lhs: Abs & 'a | App & 'c | Var, rhs: Abs & 'a | App & 'c | Var} +//│ 'c <: { +//│ lhs: App & 'c | Var | 'a & (Abs & 'a | Abs & ~#Abs), +//│ rhs: Abs & 'a | App & 'c | Var +//│ } //│ = [Function: showHasFree] showHasFree(Var("x"), "x") @@ -313,13 +329,20 @@ fun fv(t) = Var(name) then list1(name) Abs(Var(name), body) then listWithout(fv(body), name) App(lhs, rhs) then listConcat(fv(lhs), fv(rhs)) -//│ fv: 'rhs -> 'a +//│ fv: (Abs & 'a | App & 'b | Var & {name: 'name}) -> (Cons & {head: 'name, tail: Nil} | 'c | 'd) //│ where -//│ 'a :> forall 'tail 'tail0. Cons & {head: 'name, tail: Nil} | 'tail | 'tail0 -//│ 'tail0 :> Cons & {head: 'head, tail: 'tail0} | 'a -//│ 'tail :> Nil | Cons & {head: 'head, tail: 'tail} -//│ 'head :> 'name -//│ 'rhs <: Abs & {lhs: Var, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var & {name: 'name} +//│ 'd :> forall 'e. 'f | 'e +//│ 'e :> Cons & {head: forall 'head. 'head, tail: 'f | 'e} +//│ 'f :> forall 'g. Cons & {head: 'name, tail: Nil} | 'g | 'd +//│ 'g :> Nil | Cons & {head: forall 'head0. 'head0, tail: 'g} +//│ 'c :> Nil | Cons & {head: forall 'head0. 'head0, tail: 'c} +//│ 'head0 :> forall 'head. 'head | 'name +//│ 'head :> forall 'head0. 'head0 | 'name +//│ 'a <: {lhs: Var, rhs: Abs & 'a | App & 'b | Var & {name: 'name}} +//│ 'b <: { +//│ lhs: Abs & 'a | App & 'b | Var & {name: 'name}, +//│ rhs: Abs & 'a | App & 'b | Var & {name: 'name} +//│ } //│ = [Function: fv] fun showFv(t) = @@ -327,11 +350,17 @@ fun showFv(t) = Nil then " DOES NOT have free variables" _ then concat2(" has free variables: ", listJoin(fv(t), ", ")) ) -//│ showFv: ('rhs & 'rhs0 & 'rhs1) -> string +//│ showFv: (Abs & 'a & 'b & 'c | App & 'd & 'e & 'f | Var) -> string //│ where -//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var -//│ 'rhs0 <: Abs & {lhs: Var, rhs: 'rhs0} | App & {lhs: 'rhs0, rhs: 'rhs0} | Var -//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ 'c <: {lhs: Var, rhs: Abs & 'c | App & 'f | Var} +//│ 'f <: {lhs: Abs & 'c | App & 'f | Var, rhs: Abs & 'c | App & 'f | Var} +//│ 'b <: {lhs: Var, rhs: Abs & 'b | App & 'e | Var} +//│ 'e <: {lhs: Abs & 'b | App & 'e | Var, rhs: Abs & 'b | App & 'e | Var} +//│ 'a <: {lhs: Abs & 'a | App & 'd | Var, rhs: Abs & 'a | App & 'd | Var} +//│ 'd <: { +//│ lhs: App & 'd | Var | 'a & (Abs & 'a | Abs & ~#Abs), +//│ rhs: Abs & 'a | App & 'd | Var +//│ } //│ = [Function: showFv] showFv(Var("x")) @@ -358,9 +387,9 @@ fun tryNextAlphabet(initialCode, currentCode, freeNames) = let name = fromCharCode(currentCode) listContains(freeNames, name) then tryNextAlphabet(initialCode, currentCode + 1, freeNames) _ then Some(name) -//│ tryNextAlphabet: (number, int, 'tail,) -> (None | Some & {value: string}) +//│ tryNextAlphabet: (number, int, Cons & 'a | Nil,) -> (Some & {value: string} | None) //│ where -//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ 'a <: {head: anything, tail: Cons & 'a | Nil} //│ = [Function: tryNextAlphabet] tryNextAlphabet(97, 97, list1("a")) @@ -368,15 +397,15 @@ tryNextAlphabet(97, 98, list1("a")) tryNextAlphabet(97, 98, list2("a", "b")) tryNextAlphabet(121, 122, list1("y")) tryNextAlphabet(121, 122, list2("y", "z")) -//│ res: None | Some & {value: string} +//│ res: Some & {value: string} | None //│ = None {} -//│ res: None | Some & {value: string} +//│ res: Some & {value: string} | None //│ = Some { value: 'b' } -//│ res: None | Some & {value: string} +//│ res: Some & {value: string} | None //│ = Some { value: 'c' } -//│ res: None | Some & {value: string} +//│ res: Some & {value: string} | None //│ = Some { value: 'z' } -//│ res: None | Some & {value: string} +//│ res: Some & {value: string} | None //│ = Some { value: 'a' } fun tryAppendDigits(name, index, freeNames) = @@ -385,9 +414,9 @@ fun tryAppendDigits(name, index, freeNames) = listContains(freeNames, currentName) then tryAppendDigits(name, index + 1, freeNames) _ then currentName -//│ tryAppendDigits: (string, int, 'tail,) -> string +//│ tryAppendDigits: (string, int, Cons & 'a | Nil,) -> string //│ where -//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ 'a <: {head: anything, tail: Cons & 'a | Nil} //│ = [Function: tryAppendDigits] // Note: some weird behavior here... Just try the commented code. @@ -398,19 +427,20 @@ fun findFreshName(name, freeNames) = tryNextAlphabet(charCode, charCode + 1, freeNames) is Some(newName) then newName _ then tryAppendDigits(name, 0, freeNames) -//│ findFreshName: (string, 'tail & 'tail0 & 'tail1,) -> string +//│ findFreshName: (string, Cons & 'a & 'b & 'c | Nil,) -> string //│ where -//│ 'tail1 <: Cons & {tail: 'tail1} | Nil -//│ 'tail0 <: Cons & {tail: 'tail0} | Nil -//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ 'c <: {head: anything, tail: Cons & 'c | Nil} +//│ 'b <: {head: anything, tail: Cons & 'b | Nil} +//│ 'a <: {head: anything, tail: Cons & 'a | Nil} //│ = [Function: findFreshName] // Find a fresh name to replace `name` that does not conflict with any bound // variables in the `body`. fun freshName(name, body) = findFreshName(name, fv(body)) -//│ freshName: (string, 'rhs,) -> string +//│ freshName: (string, Abs & 'a | App & 'b | Var,) -> string //│ where -//│ 'rhs <: Abs & {lhs: Var, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var +//│ 'a <: {lhs: Var, rhs: Abs & 'a | App & 'b | Var} +//│ 'b <: {lhs: Abs & 'a | App & 'b | Var, rhs: Abs & 'a | App & 'b | Var} //│ = [Function: freshName] fun subst(t, n, v) = @@ -422,37 +452,64 @@ fun subst(t, n, v) = _ then Abs(Var(name), subst(body, n, v)) App(lhs, rhs) then App(subst(lhs, n, v), subst(rhs, n, v)) _ then t -//│ subst: ('rhs, anything, 'rhs & 'rhs0 & 'rhs1 & 'rhs2,) -> 'rhs0 +//│ subst: (Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var, anything, 'e & (Var & 'c | 'b & 'f & (App & ~#App | App & 'g) | 'a & 'h & (Abs & ~#Abs | Abs & 'i) | 'd & (Abs & 'h & ~#Abs | App & 'f & ~#App | Var & ~#Var)),) -> (Var & {name: string} | 'e | 'c | 'a | 'd) //│ where -//│ 'rhs2 <: Abs & {rhs: 'rhs2} | App & {lhs: 'rhs2, rhs: 'rhs2} | Var | ~Abs & ~App & ~Var -//│ 'rhs <: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var -//│ 'a :> Abs & {lhs: Var & {name: string}, rhs: 'rhs0} | 'e -//│ <: 'rhs1 & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} & 'b | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} & 'c | {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'rhs0 :> Var & {name: string} | 'c | 'a | 'd | (forall 'e. 'e) | App & {lhs: 'rhs0, rhs: 'rhs0} -//│ 'e :> Abs & {lhs: Var & {name: 'name}, rhs: 'rhs0} -//│ 'name <: string +//│ 'g <: { +//│ lhs: Abs & 'i | App & 'g | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'i | App & 'g | Var | ~Abs & ~App & ~Var +//│ } +//│ 'i <: {lhs: anything, rhs: Abs & 'i | App & 'g | Var | ~Abs & ~App & ~Var} +//│ 'a :> Abs & {lhs: Var & {name: string}, rhs: Var & {name: string} | 'rhs | 'e | 'c | 'a | 'd} +//│ <: Abs & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'a & 'h | App & 'b & 'f | Var & 'c} & 'h | App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'a & 'h | App & 'b & 'f | Var & 'c} & 'b & 'f | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'a & 'h | App & 'b & 'f | Var & 'c} & 'c | 'd & (App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'a & 'h | App & 'b & 'f | Var & 'c} & 'f & ~#App | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'a & 'h | App & 'b & 'f | Var & 'c} & ~#Var) +//│ 'rhs :> Var & {name: string} | 'e | 'c | 'a | 'd +//│ 'e :> Var & {name: string} | 'c | 'a | 'd | App & { +//│ lhs: Var & {name: string} | 'e | 'c | 'a | 'd, +//│ rhs: Var & {name: string} | 'e | 'c | 'a | 'd +//│ } | Abs & {lhs: Var & {name: string}, rhs: 'rhs} //│ 'c :> Var & {name: string} -//│ <: 'rhs1 & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'd <: 'rhs1 & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) -//│ 'b <: {lhs: 'rhs, rhs: 'rhs} -//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var +//│ <: Abs & {name: anything} & 'a & 'h | App & {name: anything} & 'b & 'f | Var | 'd & (Abs & {name: anything} & 'h & ~#Abs | App & {name: anything} & 'f & ~#App) +//│ 'b <: { +//│ lhs: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var, +//│ rhs: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var +//│ } +//│ 'd <: Var & ~#Var | Var & 'c | 'f & (App & ~#App | App & 'b) | 'h & (Abs & ~#Abs | Abs & 'a) +//│ 'h <: {lhs: Var, rhs: Abs & 'h | App & 'f | Var} +//│ 'f <: {lhs: Abs & 'h | App & 'f | Var, rhs: Abs & 'h | App & 'f | Var} //│ = [Function: subst] fun showSubst(t, n, v) = concat8(showTerm(t), " [", n, " / ", showTerm(v), "]", " => ", showTerm(subst(t, n, v))) -//│ showSubst: ('rhs & 'rhs0, string, 'rhs0 & 'rhs1 & 'lhs & 'rhs2 & 'rhs3 & 'rhs4,) -> string +//│ showSubst: (Abs & 'a & 'b | App & 'c & 'd | Var & 'e, string, Abs & 'b & 'f & 'g & 'h & 'i | App & 'j & 'd & 'k & 'l & 'm | Var & 'e,) -> string //│ where -//│ 'rhs4 <: Abs & {rhs: 'rhs4} | App & {lhs: 'rhs4, rhs: 'rhs4} | Var | ~Abs & ~App & ~Var -//│ 'rhs3 <: Abs & {lhs: 'rhs3, rhs: 'rhs3} | App & {lhs: 'rhs3 & (Abs & {lhs: 'rhs3, rhs: 'rhs3} | ~#Abs), rhs: 'rhs3} | Var -//│ 'rhs0 <: Abs & 'a | App & 'b | Var & 'c | 'd & ~#Abs & ~#App & ~#Var -//│ 'a <: 'lhs & 'rhs2 & 'rhs1 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'b | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'c | {lhs: Var & {name: string} | ~Var, rhs: 'rhs0 & 'rhs1} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'c <: 'lhs & 'rhs2 & 'rhs1 & (Abs & {name: anything} & 'a | App & {name: anything} & 'b | Var | {name: anything} & 'd & ~#Abs & ~#App & ~#Var) -//│ 'd <: 'lhs & 'rhs2 & 'rhs1 & (Abs & 'a | App & 'b | Var & 'c | ~#Abs & ~#App & ~#Var) -//│ 'b <: {lhs: 'rhs0, rhs: 'rhs0} -//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var -//│ 'lhs <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | ~Abs -//│ 'rhs2 <: Abs & {lhs: 'rhs2, rhs: 'rhs2} | App & {lhs: 'lhs & 'rhs2, rhs: 'rhs2} | Var -//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var +//│ 'i <: {lhs: anything, rhs: Abs & 'i | App & 'm | Var | ~Abs & ~App & ~Var} +//│ 'm <: { +//│ lhs: Abs & 'i | App & 'm | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'i | App & 'm | Var | ~Abs & ~App & ~Var +//│ } +//│ 'h <: {lhs: Abs & 'h | App & 'l | Var, rhs: Abs & 'h | App & 'l | Var} +//│ 'l <: { +//│ lhs: App & 'l | Var | 'h & (Abs & 'h | Abs & ~#Abs), +//│ rhs: Abs & 'h | App & 'l | Var +//│ } +//│ 'b <: Abs & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'b & 'f | App & 'j & 'd | Var & 'e} & 'f & 'g | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'b & 'f | App & 'j & 'd | Var & 'e} & 'e | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'b & 'f | App & 'j & 'd | Var & 'e} & 'n & ~#Var | 'j & 'k & (App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'b & 'f | App & 'j & 'd | Var & 'e} & 'd | App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'b & 'f | App & 'j & 'd | Var & 'e} & 'n & ~#App) +//│ 'd <: { +//│ lhs: Abs & 'b | App & 'd | Var & 'e | 'n & ~#Abs & ~#App & ~#Var, +//│ rhs: Abs & 'b | App & 'd | Var & 'e | 'n & ~#Abs & ~#App & ~#Var +//│ } +//│ 'e <: Var | 'j & 'k & (App & {name: anything} & 'd | App & {name: anything} & 'n & ~#App) | 'f & 'g & (Abs & {name: anything} & 'n & ~#Abs | Abs & {name: anything} & 'b) +//│ 'n <: Var & ~#Var | Var & 'e | 'j & 'k & (App & ~#App | App & 'd) | 'f & 'g & (Abs & ~#Abs | Abs & 'b) +//│ 'k <: { +//│ lhs: App & 'k | Var | 'g & (Abs & ~#Abs | Abs & 'g), +//│ rhs: Abs & 'g | App & 'k | Var +//│ } +//│ 'g <: {lhs: Abs & 'g | App & 'k | Var, rhs: Abs & 'g | App & 'k | Var} +//│ 'f <: {lhs: Var, rhs: Abs & 'f | App & 'j | Var} +//│ 'j <: {lhs: Abs & 'f | App & 'j | Var, rhs: Abs & 'f | App & 'j | Var} +//│ 'a <: {lhs: Abs & 'a | App & 'c | Var, rhs: Abs & 'a | App & 'c | Var} +//│ 'c <: { +//│ lhs: App & 'c | Var | 'a & (Abs & 'a | Abs & ~#Abs), +//│ rhs: Abs & 'a | App & 'c | Var +//│ } //│ = [Function: showSubst] showSubst(Var("x"), "x", Var("y")) @@ -482,25 +539,40 @@ fun stepByValue(t) = None and lhs is Abs(Var(name), body) then Some(subst(body, name, rhs)) _ then None() -//│ stepByValue: 'a -> (None | Some & {value: 'value}) -//│ where -//│ 'value :> 'value0 | App & {lhs: 'value, rhs: 'rhs} | App & {lhs: 'lhs, rhs: 'value} -//│ 'a <: Abs | App & {lhs: 'lhs, rhs: 'rhs} | Var -//│ 'lhs <: 'a & (Abs & {rhs: 'rhs0} | ~#Abs) -//│ 'rhs0 <: Abs & 'b | App & 'c | Var & 'd | 'e & ~#Abs & ~#App & ~#Var -//│ 'b :> Abs & {lhs: Var & {name: string}, rhs: 'value0} | 'f -//│ <: 'rhs1 & (Abs & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} | App & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} & 'c | Var & {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} & 'd | {lhs: Var & {name: 'name} | ~Var, rhs: 'rhs2} & 'e & ~#Abs & ~#App & ~#Var) -//│ 'value0 :> Var & {name: string} | 'rhs | 'd | 'b | 'e | (forall 'f. 'f) | App & {lhs: 'value0, rhs: 'value0} -//│ 'f :> Abs & {lhs: Var & {name: 'name}, rhs: 'value0} -//│ 'name <: string -//│ 'd :> Var & {name: string} -//│ <: 'rhs1 & (Abs & {name: anything} & 'b | App & {name: anything} & 'c | Var | {name: anything} & 'e & ~#Abs & ~#App & ~#Var) -//│ 'e <: 'rhs1 & (Abs & 'b | App & 'c | Var & 'd | ~#Abs & ~#App & ~#Var) -//│ 'c <: {lhs: 'rhs0, rhs: 'rhs0} -//│ 'rhs <: 'a & 'rhs2 & 'rhs3 -//│ 'rhs3 <: Abs & {rhs: 'rhs3} | App & {lhs: 'rhs3, rhs: 'rhs3} | Var | ~Abs & ~App & ~Var -//│ 'rhs2 <: 'rhs0 & 'rhs1 -//│ 'rhs1 <: Abs & {lhs: Var, rhs: 'rhs1} | App & {lhs: 'rhs1, rhs: 'rhs1} | Var +//│ stepByValue: (Abs | App & 'a | Var) -> (None | Some & { +//│ value: Var & {name: string} | 'rhs | App & { +//│ lhs: Var & {name: string} | 'rhs | App & {lhs: 'lhs, rhs: Var & {name: string} | 'rhs | 'b | 'c | 'd | 'e} | 'b | 'c | 'd | 'e, +//│ rhs: 'rhs +//│ } | App & {lhs: 'lhs, rhs: Var & {name: string} | 'rhs | 'b | 'c | 'd | 'e} | 'b | 'c | 'd | 'e +//│ }) +//│ where +//│ 'a <: {lhs: 'lhs, rhs: 'rhs} +//│ 'lhs <: Abs & {rhs: Abs & 'c | App & 'f | Var & 'b | 'e & ~#Abs & ~#App & ~#Var} | Abs & ~#Abs | App & 'a | Var +//│ 'c :> Abs & { +//│ lhs: Var & {name: string}, +//│ rhs: Var & {name: string} | 'rhs0 | 'rhs | 'b | 'c | 'd | 'e +//│ } +//│ <: Abs & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'c & 'g | App & 'h & 'f | Var & 'b} & 'g | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'c & 'g | App & 'h & 'f | Var & 'b} & 'b | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'c & 'g | App & 'h & 'f | Var & 'b} & 'e & ~#Var | 'h & (App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'c & 'g | App & 'h & 'f | Var & 'b} & 'f | App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'c & 'g | App & 'h & 'f | Var & 'b} & 'e & ~#App) +//│ 'rhs0 :> Var & {name: string} | 'rhs | 'b | 'c | 'd | 'e +//│ 'd :> Var & {name: string} | 'rhs | 'b | 'c | 'e | Abs & {lhs: Var & {name: string}, rhs: 'rhs0} | App & { +//│ lhs: Var & {name: string} | 'rhs | 'b | 'c | 'd | 'e, +//│ rhs: Var & {name: string} | 'rhs | 'b | 'c | 'd | 'e +//│ } +//│ 'rhs <: Abs & 'c & 'g & 'i | App & 'a & 'h & 'f & 'j | Var & 'b +//│ 'f <: { +//│ lhs: Abs & 'c | App & 'f | Var & 'b | 'e & ~#Abs & ~#App & ~#Var, +//│ rhs: Abs & 'c | App & 'f | Var & 'b | 'e & ~#Abs & ~#App & ~#Var +//│ } +//│ 'b :> Var & {name: string} +//│ <: Var | 'h & (App & {name: anything} & 'f | App & {name: anything} & 'e & ~#App) | 'g & (Abs & {name: anything} & 'e & ~#Abs | Abs & {name: anything} & 'c) +//│ 'e <: Var & ~#Var | Var & 'b | 'h & (App & ~#App | App & 'f) | 'g & (Abs & ~#Abs | Abs & 'c) +//│ 'i <: {lhs: anything, rhs: Abs & 'i | App & 'j | Var | ~Abs & ~App & ~Var} +//│ 'j <: { +//│ lhs: Abs & 'i | App & 'j | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'i | App & 'j | Var | ~Abs & ~App & ~Var +//│ } +//│ 'g <: {lhs: Var, rhs: Abs & 'g | App & 'h | Var} +//│ 'h <: {lhs: Abs & 'g | App & 'h | Var, rhs: Abs & 'g | App & 'h | Var} //│ = [Function: stepByValue] fun showStepByValue(t) = @@ -508,23 +580,36 @@ fun showStepByValue(t) = Some(t) then showTerm(t) None then "stuck" ) -//│ showStepByValue: ('rhs & (Abs | App & 'a | Var)) -> string +//│ showStepByValue: (Abs & 'a | App & 'b & 'c | Var) -> string //│ where -//│ 'a <: { -//│ lhs: 'lhs & 'rhs0 & (Abs & {rhs: 'rhs1} | Abs & ~#Abs | App & 'a | Var), -//│ rhs: 'lhs & 'rhs0 & 'rhs2 & 'rhs3 & (Abs | App & 'a | Var) +//│ 'c <: { +//│ lhs: App & 'c & 'd | Var | 'e & (Abs & {rhs: Abs & 'f | App & 'g | Var & 'h | 'i & ~#Abs & ~#App & ~#Var} | Abs & ~#Abs), +//│ rhs: Abs & 'f & 'j & 'e & 'k | App & 'c & 'l & 'g & 'd & 'm | Var & 'h +//│ } +//│ 'k <: {lhs: anything, rhs: Abs & 'k | App & 'm | Var | ~Abs & ~App & ~Var} +//│ 'm <: { +//│ lhs: Abs & 'k | App & 'm | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'k | App & 'm | Var | ~Abs & ~App & ~Var +//│ } +//│ 'f <: Abs & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'f & 'j | App & 'l & 'g | Var & 'h} & 'j & 'e | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'f & 'j | App & 'l & 'g | Var & 'h} & 'h | Var & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'f & 'j | App & 'l & 'g | Var & 'h} & 'i & ~#Var | 'l & 'd & (App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'f & 'j | App & 'l & 'g | Var & 'h} & 'g | App & {lhs: Var & {name: string} | ~Var, rhs: Abs & 'f & 'j | App & 'l & 'g | Var & 'h} & 'i & ~#App) +//│ 'g <: { +//│ lhs: Abs & 'f | App & 'g | Var & 'h | 'i & ~#Abs & ~#App & ~#Var, +//│ rhs: Abs & 'f | App & 'g | Var & 'h | 'i & ~#Abs & ~#App & ~#Var +//│ } +//│ 'h <: Var | 'l & 'd & (App & {name: anything} & 'g | App & {name: anything} & 'i & ~#App) | 'j & 'e & (Abs & {name: anything} & 'i & ~#Abs | Abs & {name: anything} & 'f) +//│ 'i <: Var & ~#Var | Var & 'h | 'l & 'd & (App & ~#App | App & 'g) | 'j & 'e & (Abs & ~#Abs | Abs & 'f) +//│ 'j <: {lhs: Var, rhs: Abs & 'j | App & 'l | Var} +//│ 'l <: {lhs: Abs & 'j | App & 'l | Var, rhs: Abs & 'j | App & 'l | Var} +//│ 'd <: { +//│ lhs: App & 'd | Var | 'e & (Abs & ~#Abs | Abs & 'e), +//│ rhs: Abs & 'e | App & 'd | Var +//│ } +//│ 'e <: {lhs: Abs & 'e | App & 'd | Var, rhs: Abs & 'e | App & 'd | Var} +//│ 'a <: {lhs: Abs & 'a | App & 'b | Var, rhs: Abs & 'a | App & 'b | Var} +//│ 'b <: { +//│ lhs: App & 'b | Var | 'a & (Abs & 'a | Abs & ~#Abs), +//│ rhs: Abs & 'a | App & 'b | Var //│ } -//│ 'rhs2 <: Abs & {rhs: 'rhs2} | App & {lhs: 'rhs2, rhs: 'rhs2} | Var | ~Abs & ~App & ~Var -//│ 'rhs1 <: Abs & 'b | App & 'c | Var & 'd | 'e & ~#Abs & ~#App & ~#Var -//│ 'b <: 'lhs & 'rhs0 & 'rhs4 & (Abs & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} | App & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'c | Var & {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'd | {lhs: Var & {name: string} | ~Var, rhs: 'rhs3} & 'e & ~#Abs & ~#App & ~#Var) -//│ 'd <: 'lhs & 'rhs0 & 'rhs4 & (Abs & {name: anything} & 'b | App & {name: anything} & 'c | Var | {name: anything} & 'e & ~#Abs & ~#App & ~#Var) -//│ 'e <: 'lhs & 'rhs0 & 'rhs4 & (Abs & 'b | App & 'c | Var & 'd | ~#Abs & ~#App & ~#Var) -//│ 'c <: {lhs: 'rhs1, rhs: 'rhs1} -//│ 'rhs3 <: 'rhs1 & 'rhs4 -//│ 'rhs4 <: Abs & {lhs: Var, rhs: 'rhs4} | App & {lhs: 'rhs4, rhs: 'rhs4} | Var -//│ 'lhs <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | ~Abs -//│ 'rhs0 <: Abs & {lhs: 'rhs0, rhs: 'rhs0} | App & {lhs: 'lhs & 'rhs0, rhs: 'rhs0} | Var -//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs & (Abs & {lhs: 'rhs, rhs: 'rhs} | ~#Abs), rhs: 'rhs} | Var //│ = [Function: showStepByValue] showStepByValue(Var("x")) @@ -546,9 +631,14 @@ fun equalTerm(a, b) = Abs(la, ra) and b is Abs(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) App(la, ra) and b is App(lb, rb) then equalTerm(la, lb) && equalTerm(ra, rb) _ then false -//│ equalTerm: ('rhs, 'rhs0,) -> bool +//│ equalTerm: (Abs & 'a | App & 'a | Var | ~Abs & ~App & ~Var, Abs & 'b | App & 'b | Var | ~Abs & ~App & ~Var,) -> bool //│ where -//│ 'rhs0 <: Abs & 'a | App & 'a | Var | ~Abs & ~App & ~Var -//│ 'a <: {lhs: 'rhs0, rhs: 'rhs0} -//│ 'rhs <: Abs & {lhs: 'rhs, rhs: 'rhs} | App & {lhs: 'rhs, rhs: 'rhs} | Var | ~Abs & ~App & ~Var +//│ 'b <: { +//│ lhs: Abs & 'b | App & 'b | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'b | App & 'b | Var | ~Abs & ~App & ~Var +//│ } +//│ 'a <: { +//│ lhs: Abs & 'a | App & 'a | Var | ~Abs & ~App & ~Var, +//│ rhs: Abs & 'a | App & 'a | Var | ~Abs & ~App & ~Var +//│ } //│ = [Function: equalTerm] diff --git a/shared/src/test/diff/tricky/Pottier.fun b/shared/src/test/diff/tricky/Pottier.fun index cc0bcee14f..31db27735a 100644 --- a/shared/src/test/diff/tricky/Pottier.fun +++ b/shared/src/test/diff/tricky/Pottier.fun @@ -26,12 +26,14 @@ let rec f = x => y => add (f x.tail y) (f y.tail x) //│ f: 'a -> 'a -> int //│ where //│ 'a <: {tail: 'a} -//│ f: 'a -> 'a -> int +//│ f: 'a -> 'b -> int //│ where -//│ 'a <: {tail: 'a} -//│ f: 'a -> 'a -> int +//│ 'a <: {tail: 'a} & 'b +//│ 'b <: {tail: 'a} +//│ f: 'a -> 'b -> int //│ where -//│ 'a <: {tail: 'a} +//│ 'a <: {tail: 'a} & 'b +//│ 'b <: {tail: 'a} let f = x => y => if true then { l: x; r: y } else { l: y; r: x } // 2-crown //│ f: 'a -> 'a -> {l: 'a, r: 'a} diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index ff29a4b367..cb69a5eebc 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -227,9 +227,9 @@ fun showList(xs) = //│ })()); //│ }; //│ // End of generated code -//│ showList: 'tail -> string +//│ showList: (Cons & 'a | Nil) -> string //│ where -//│ 'tail <: Cons & {tail: 'tail} | Nil +//│ 'a <: {head: anything, tail: Cons & 'a | Nil} //│ = [Function: showList] let zeroToThree = Cons(0, Cons(1, Cons(2, Cons(3, Nil())))) @@ -255,18 +255,21 @@ fun mapPartition(f, xs) = let r = res.snd Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), 'tail,) -> (Pair & {fst: 'fst, snd: 'snd}) +//│ mapPartition: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}), Cons & 'a | Nil,) -> (Pair & {fst: forall 'b 'c. Nil | 'c | 'b, snd: Nil | Cons & {head: 'rightValue, tail: Nil}}) //│ where -//│ 'snd :> Cons & {head: 'rightValue, tail: 'snd} -//│ 'fst :> Cons & {head: 'leftValue, tail: 'fst} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ 'b :> Cons & {head: 'leftValue, tail: forall 'd. Nil | 'd} +//│ 'c :> Cons & {head: 'leftValue, tail: forall 'd. Nil | 'd} +//│ 'a <: {head: 'head, tail: Cons & 'a | Nil} //│ = [Function: mapPartition] mapPartition(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) -//│ res: Pair & {fst: 'fst, snd: 'snd} -//│ where -//│ 'snd :> Cons & {head: 0 | 1 | 2 | 3, tail: 'snd} | Nil -//│ 'fst :> Nil | Cons & {head: 0 | 1 | 2 | 3, tail: 'fst} +//│ res: Pair & { +//│ fst: forall 'a 'b. Nil | 'b | 'a, +//│ snd: Nil | Cons & {head: 0 | 1 | 2 | 3, tail: Nil} +//│ } +//│ where +//│ 'a :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'c. Nil | 'c} +//│ 'b :> Cons & {head: 0 | 1 | 2 | 3, tail: forall 'c. Nil | 'c} //│ = Pair { //│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, //│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } @@ -279,40 +282,38 @@ fun mapPartition2(f, xs) = Cons(x, xs) and mapPartition(f, xs) is res and res.fst is l and res.snd is r and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ mapPartition2: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}) & 'head0 -> (Left & {leftValue: 'leftValue0} | Right & {rightValue: 'rightValue0}), Cons & {head: 'head0, tail: 'tail} | Nil,) -> (Pair & { -//│ fst: forall 'fst. Cons & { +//│ mapPartition2: ('head -> (Left & {leftValue: 'leftValue} | Right & {rightValue: 'rightValue}) & 'head0 -> (Left & {leftValue: 'leftValue0} | Right & {rightValue: 'rightValue0}), Cons & {head: 'head0, tail: Cons & 'a | Nil} | Nil,) -> (Pair & { +//│ fst: forall 'b. Cons & { //│ head: 'leftValue0, -//│ tail: forall 'fst0. Nil | 'fst0 | Cons & {head: 'leftValue, tail: Nil | 'fst0} -//│ } | Nil | 'fst | Cons & {head: 'leftValue, tail: Nil | 'fst}, -//│ snd: forall 'snd. Cons & { -//│ head: 'rightValue0, -//│ tail: forall 'snd0. Nil | 'snd0 | Cons & {head: 'rightValue, tail: Nil | 'snd0} -//│ } | Nil | 'snd | Cons & {head: 'rightValue, tail: Nil | 'snd} +//│ tail: forall 'c. Nil | 'c | Cons & {head: 'leftValue, tail: forall 'fst. Nil | 'fst} +//│ } | Nil | 'b | Cons & {head: 'leftValue, tail: forall 'fst0. Nil | 'fst0}, +//│ snd: Cons & {head: 'rightValue0, tail: Nil | Cons & {head: 'rightValue, tail: Nil}} | Nil | Cons & {head: 'rightValue, tail: Nil} //│ }) //│ where -//│ 'snd :> Nil | Cons & {head: 'rightValue, tail: 'snd} -//│ 'snd0 :> Nil | Cons & {head: 'rightValue, tail: 'snd0} -//│ 'fst :> Nil | Cons & {head: 'leftValue, tail: 'fst} -//│ 'fst0 :> Nil | Cons & {head: 'leftValue, tail: 'fst0} -//│ 'tail <: Cons & {head: 'head, tail: 'tail} | Nil +//│ 'b :> Cons & {head: 'leftValue, tail: forall 'fst0. Nil | 'fst0} +//│ 'fst0 :> forall 'd. Nil | 'd +//│ 'd :> Cons & {head: 'leftValue, tail: forall 'fst0. Nil | 'fst0} +//│ 'c :> Cons & {head: 'leftValue, tail: forall 'fst. Nil | 'fst} +//│ 'fst :> forall 'e. Nil | 'e +//│ 'e :> Cons & {head: 'leftValue, tail: forall 'fst. Nil | 'fst} +//│ 'a <: {head: 'head, tail: Cons & 'a | Nil} //│ = [Function: mapPartition2] mapPartition2(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) //│ res: Pair & { -//│ fst: forall 'fst. Cons & { -//│ head: 0, -//│ tail: forall 'fst0. Nil | 'fst0 | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst0} -//│ } | Nil | 'fst | Cons & {head: 1 | 2 | 3, tail: Nil | 'fst}, -//│ snd: forall 'snd. Cons & { +//│ fst: forall 'a. Cons & { //│ head: 0, -//│ tail: forall 'snd0. Nil | 'snd0 | Cons & {head: 1 | 2 | 3, tail: Nil | 'snd0} -//│ } | Nil | 'snd | Cons & {head: 1 | 2 | 3, tail: Nil | 'snd} +//│ tail: forall 'b. Nil | 'b | Cons & {head: 1 | 2 | 3, tail: forall 'fst. Nil | 'fst} +//│ } | Nil | 'a | Cons & {head: 1 | 2 | 3, tail: forall 'fst0. Nil | 'fst0}, +//│ snd: Cons & {head: 0, tail: Nil | Cons & {head: 1 | 2 | 3, tail: Nil}} | Nil | Cons & {head: 1 | 2 | 3, tail: Nil} //│ } //│ where -//│ 'snd :> Nil | Cons & {head: 1 | 2 | 3, tail: 'snd} -//│ 'snd0 :> Nil | Cons & {head: 1 | 2 | 3, tail: 'snd0} -//│ 'fst :> Nil | Cons & {head: 1 | 2 | 3, tail: 'fst} -//│ 'fst0 :> Nil | Cons & {head: 1 | 2 | 3, tail: 'fst0} +//│ 'a :> Cons & {head: 1 | 2 | 3, tail: forall 'fst0. Nil | 'fst0} +//│ 'fst0 :> forall 'c. Nil | 'c +//│ 'c :> Cons & {head: 1 | 2 | 3, tail: forall 'fst0. Nil | 'fst0} +//│ 'b :> Cons & {head: 1 | 2 | 3, tail: forall 'fst. Nil | 'fst} +//│ 'fst :> forall 'd. Nil | 'd +//│ 'd :> Cons & {head: 1 | 2 | 3, tail: forall 'fst. Nil | 'fst} //│ = Pair { //│ fst: Cons { head: 0, tail: Cons { head: 2, tail: Nil {} } }, //│ snd: Cons { head: 1, tail: Cons { head: 3, tail: Nil {} } } From ed08423d61931f93c2fd7e8e4e2d3509c6d05718 Mon Sep 17 00:00:00 2001 From: HarrisL2 Date: Wed, 11 Oct 2023 12:30:46 +0800 Subject: [PATCH 475/498] Fix unary minus behaviour (#188) --- shared/src/main/scala/mlscript/NewLexer.scala | 19 ++-- .../src/main/scala/mlscript/NewParser.scala | 17 +++- shared/src/test/diff/nu/UnaryMinus.mls | 93 +++++++++++++++++++ shared/src/test/diff/parser/NegativeLits.mls | 4 +- 4 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 shared/src/test/diff/nu/UnaryMinus.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 7fd8f324fe..2bd9f0e614 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -168,19 +168,14 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { // go(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n))) lex(j, ind, next(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n)))) case _ if isOpChar(c) => - if (c === '-' && isDigit(bytes(i + 1))) { - val (str, j) = takeWhile(i + 1)(isDigit) - lex(j, ind, next(j, LITVAL(IntLit(-BigInt(str))))) - } else { - val (n, j) = takeWhile(i)(isOpChar) - if (n === "." && j < length && isIdentFirstChar(bytes(j))) { - val (name, k) = takeWhile(j)(isIdentChar) - // go(k, SELECT(name)) - lex(k, ind, next(k, SELECT(name))) - } - // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) - else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) + val (n, j) = takeWhile(i)(isOpChar) + if (n === "." && j < length && isIdentFirstChar(bytes(j))) { + val (name, k) = takeWhile(j)(isIdentChar) + // go(k, SELECT(name)) + lex(k, ind, next(k, SELECT(name))) } + // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) + else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) case _ if isDigit(c) => val (str, j) = takeWhile(i)(isDigit) // go(j, LITVAL(IntLit(BigInt(str)))) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 8445d82f9d..22be9ea17b 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -787,6 +787,18 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case ((KEYWORD(";;") /* | NEWLINE */ /* | BRACKETS(Curly, _) */, l0) :: _) => R(UnitLit(true).withLoc(S(l0))) // R(errExpr) // TODO + case (IDENT("-", true), l0) :: _ /*if opPrec("-")._1 > prec*/ => // Unary minus + consume + val v = Var("-").withLoc(S(l0)) + expr(opPrec("-")._2) match { + case IntLit(i) => // Special case for negative literals + exprCont(IntLit(-i), prec, false) + case rhs: Term => // General case + exprCont( + if (newDefs) App(v, PlainTup(IntLit(BigInt(0)), rhs)) + else App(App(v, PlainTup(IntLit(BigInt(0)))), PlainTup(rhs)) + , prec, false) + } case (tk, l0) :: _ => err(msg"Unexpected ${tk.describe} in expression position" -> S(l0) :: Nil) consume @@ -1128,7 +1140,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (SPACE, _) :: _ => consume argsOrIf(acc, seqAcc, allowNewlines, prec) - case (NEWLINE | IDENT(_, true), _) :: _ => // TODO: | ... + case (NEWLINE, _) :: _ => // TODO: | ... + assert(seqAcc.isEmpty) + acc.reverse + case (IDENT(nme, true), _) :: _ if nme =/= "-" => // TODO: | ... assert(seqAcc.isEmpty) acc.reverse case _ => diff --git a/shared/src/test/diff/nu/UnaryMinus.mls b/shared/src/test/diff/nu/UnaryMinus.mls new file mode 100644 index 0000000000..389426bfe5 --- /dev/null +++ b/shared/src/test/diff/nu/UnaryMinus.mls @@ -0,0 +1,93 @@ +:NewDefs + +-1 +//│ -1 +//│ res +//│ = -1 + +- 1 +//│ -1 +//│ res +//│ = -1 + +1+1 +//│ Int +//│ res +//│ = 2 + +1-3 +//│ Int +//│ res +//│ = -2 + +3-1 +//│ Int +//│ res +//│ = 2 + +1 - (3 - 5) +//│ Int +//│ res +//│ = -7 + +3 - 1 +//│ Int +//│ res +//│ = 2 + +1 -1 +//│ Int +//│ res +//│ = 0 + +1-1 +//│ Int +//│ res +//│ = 0 + +1+ -1 +//│ Int +//│ res +//│ = 0 + +1 - (1 - 1) +//│ Int +//│ res +//│ = -1 + +1 - 1 +//│ Int +//│ res +//│ = 0 + +1 - - 1 +//│ Int +//│ res +//│ = 2 + +1 - - - - 1 +//│ Int +//│ res +//│ = 2 + +fun f() = 6 +-f() +//│ fun f: () -> 6 +//│ Int +//│ res +//│ = -6 + +fun inv(x: Int) = -x +inv(15) +inv(inv(15)) +//│ fun inv: (x: Int) -> Int +//│ Int +//│ res +//│ = -15 +//│ res +//│ = 15 + +inv(f()) +//│ Int +//│ res +//│ = -6 diff --git a/shared/src/test/diff/parser/NegativeLits.mls b/shared/src/test/diff/parser/NegativeLits.mls index 6dbcfff444..4290b760b4 100644 --- a/shared/src/test/diff/parser/NegativeLits.mls +++ b/shared/src/test/diff/parser/NegativeLits.mls @@ -2,7 +2,7 @@ :ParseOnly type MinusOne = -1 -//│ |#type| |MinusOne| |#=| |-1| +//│ |#type| |MinusOne| |#=| |-|1| //│ Parsed: {type alias MinusOne: -1 {}} fun f(x: MinusOne) = x @@ -10,5 +10,5 @@ fun f(x: MinusOne) = x //│ Parsed: {fun f = (x: MinusOne,) => x} f(-1) -//│ |f|(|-1|)| +//│ |f|(|-|1|)| //│ Parsed: {f(-1,)} From f13624f4d97883246d08d12e6f8e321342a5930f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 12 Oct 2023 14:37:03 +0800 Subject: [PATCH 476/498] Approximate overloads less + add tests and notes --- .../main/scala/mlscript/TyperDatatypes.scala | 5 +- shared/src/test/diff/basics/Intersections.fun | 112 ++----- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 2 +- shared/src/test/diff/fcp/Overloads.mls | 71 +--- shared/src/test/diff/mlscript/BadPolym.mls | 30 +- shared/src/test/diff/nu/ArrayProg.mls | 15 +- shared/src/test/diff/nu/HeungTung.mls | 316 ++++++++++++++++++ shared/src/test/diff/nu/WeirdUnions.mls | 27 +- 8 files changed, 385 insertions(+), 193 deletions(-) create mode 100644 shared/src/test/diff/nu/HeungTung.mls diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 45da2dc7ad..fae7992dc3 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -200,7 +200,10 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => Overload(alts.map(ft => FunctionType(f(pol.contravar, ft.lhs), f(pol, ft.rhs))(ft.prov)))(prov) def approximatePos: FunctionType = { val (lhss, rhss) = alts.map(ft => ft.lhs -> ft.rhs).unzip - FunctionType(lhss.reduce(_ & _), rhss.reduce(_ | _))(prov) + FunctionType(lhss.reduce(_ | _), rhss.reduce(_ | _))(prov) + // * Note: technically the following is another valid (but probably less useful) + // * approximation of the same function type: + // FunctionType(lhss.reduce(_ & _), rhss.reduce(_ & _))(prov) } lazy val level: Level = levelBelow(MaxLevel)(MutSet.empty) def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index 0c2144396c..95d264faf1 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -31,31 +31,7 @@ foo(1) // returns int & bool, equivalent to nothing succ / foo(1) foo(true) not / foo(true) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.30: foo(1) // returns int & bool, equivalent to nothing -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.30: foo(1) // returns int & bool, equivalent to nothing -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.30: foo(1) // returns int & bool, equivalent to nothing -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ -//│ res: bool | error | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.31: succ / foo(1) -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.31: succ / foo(1) -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.31: succ / foo(1) -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ +//│ res: bool | int //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.31: succ / foo(1) //│ ║ ^^^^^^^^^^^^^ @@ -66,31 +42,7 @@ not / foo(true) //│ ║ l.31: succ / foo(1) //│ ╙── ^^^^^^ //│ res: error | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.32: foo(true) -//│ ║ ^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.32: foo(true) -//│ ║ ^^^^ -//│ ╟── but it flows into argument with expected type `int` -//│ ║ l.32: foo(true) -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^ -//│ res: bool | error | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.33: not / foo(true) -//│ ║ ^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.33: not / foo(true) -//│ ║ ^^^^ -//│ ╟── but it flows into argument with expected type `int` -//│ ║ l.33: not / foo(true) -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^ +//│ res: bool | int //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.33: not / foo(true) //│ ║ ^^^^^^^^^^^^^^^ @@ -106,76 +58,52 @@ not / foo(true) not / foo(1) foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.106: not / foo(1) -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.106: not / foo(1) -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.106: not / foo(1) -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.106: not / foo(1) -//│ ║ ^^^^^^^^^^^^ +//│ ║ l.58: not / foo(1) +//│ ║ ^^^^^^^^^^^^ //│ ╟── reference of type `int` is not an instance of type `bool` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `bool` -//│ ║ l.106: not / foo(1) -//│ ╙── ^^^^^^ +//│ ║ l.58: not / foo(1) +//│ ╙── ^^^^^^ //│ res: bool | error -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.59: foo(1) as Nothing +//│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `int` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `nothing` -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^^^^ +//│ ║ l.59: foo(1) as Nothing +//│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.107: foo(1) as Nothing -//│ ╙── ^^^^^^^ +//│ ║ l.59: foo(1) as Nothing +//│ ╙── ^^^^^^^ //│ res: nothing :e foo as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.157: foo as Nothing -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.85: foo as Nothing +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── type intersection of type `int -> int & bool -> bool` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.157: foo as Nothing -//│ ║ ^^^ +//│ ║ l.85: foo as Nothing +//│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.157: foo as Nothing -//│ ╙── ^^^^^^^ +//│ ║ l.85: foo as Nothing +//│ ╙── ^^^^^^^ //│ res: nothing :e let oops = (&) //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.173: let oops = (&) +//│ ║ l.101: let oops = (&) //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.173: let oops = (&) +//│ ║ l.101: let oops = (&) //│ ╙── ^^^ //│ oops: error diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index d2b54c6799..ae9192d9df 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -348,7 +348,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Scale['a] | Union['a] | Intersect['a] | Translate['a] +//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 5a713da7a9..71a328bb55 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -31,12 +31,12 @@ IISS : ZZII //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.30: IISS : ZZII //│ ║ ^^^^ -//│ ╟── type `0` is not an instance of type `string` -//│ ║ l.7: type ZZII = 0 -> 0 & int -> int -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: +//│ ╟── type `int` does not match type `0` //│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ +//│ ║ ^^^ +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.7: type ZZII = 0 -> 0 & int -> int +//│ ╙── ^ //│ res: ZZII :e @@ -44,12 +44,9 @@ IISS : BBNN //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.43: IISS : BBNN //│ ║ ^^^^ -//│ ╟── type `bool` is not an instance of type `int` +//│ ╟── type `bool` does not match type `int | string` //│ ║ l.6: type BBNN = bool -> bool & number -> number -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^ +//│ ╙── ^^^^ //│ res: BBNN @@ -61,53 +58,20 @@ IISS : int -> int IISS : (0 | 1) -> number //│ res: (0 | 1) -> number -:e IISS : 'a -> 'a -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.65: IISS : 'a -> 'a -//│ ║ ^^^^ -//│ ╟── type `int` is not an instance of type `string` -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^^^^ -//│ ╟── from type variable: -//│ ║ l.65: IISS : 'a -> 'a -//│ ╙── ^^ -//│ res: nothing -> (error | int | string) +//│ res: ('a & (int | string)) -> (int | string | 'a) -:e IISS 0 -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.81: IISS 0 -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `string` -//│ ║ l.81: IISS 0 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ -//│ res: error | int | string +//│ res: int | string (IISS : int -> int) 0 //│ res: int -:e (if true then IISS else BBNN) 0 -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.97: (if true then IISS else BBNN) 0 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `string` -//│ ║ l.97: (if true then IISS else BBNN) 0 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ -//│ res: bool | error | number | string +//│ res: bool | number | string fun x -> (if true then IISS else BBNN) x -//│ res: nothing -> (bool | number | string) +//│ res: int -> (bool | number | string) if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -121,14 +85,11 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.122: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `0` is not an instance of type `string` -//│ ║ l.122: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ +//│ ║ l.86: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `true` does not match type `int | string` +//│ ║ l.86: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ╙── ^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/mlscript/BadPolym.mls b/shared/src/test/diff/mlscript/BadPolym.mls index 44dbedef45..d8695bb76e 100644 --- a/shared/src/test/diff/mlscript/BadPolym.mls +++ b/shared/src/test/diff/mlscript/BadPolym.mls @@ -22,12 +22,12 @@ foo = fooImpl //│ ╔══[ERROR] Type mismatch in def definition: //│ ║ l.18: foo = fooImpl //│ ║ ^^^^^^^^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `string` -//│ ║ l.13: fooImpl f = f 1 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: +//│ ╟── type `int` is not a 0-element tuple //│ ║ l.9: def foo: (int -> int & string -> string) -> () -//│ ╙── ^^^^^^ +//│ ║ ^^^ +//│ ╟── Note: constraint arises from tuple type: +//│ ║ l.9: def foo: (int -> int & string -> string) -> () +//│ ╙── ^^ //│ = [Function: fooImpl] foo id @@ -39,35 +39,25 @@ fooImpl id //│ = 1 -:e fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ║ ^^^ -//│ ╟── integer literal of type `1` is not an instance of type `string` -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ╙── ^^^^^^ -//│ fooImpl2: (int -> int & string -> string) -> (error | int | string) +//│ fooImpl2: (int -> int & string -> string) -> (int | string) //│ = [Function: fooImpl2] fooImpl2 id -//│ res: error | int | string +//│ res: int | string //│ = 1 :e :re res "oops" //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.62: res "oops" +//│ ║ l.52: res "oops" //│ ║ ^^^^^^^^^^ //│ ╟── type `int` is not a function -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 +//│ ║ l.42: fooImpl2 (f: int -> int & string -> string) = f 1 //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `"oops" -> ?a` -//│ ║ l.62: res "oops" +//│ ║ l.52: res "oops" //│ ╙── ^^^ //│ res: error //│ Runtime error: diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index d8b1402fd3..b33cb35fab 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -154,6 +154,11 @@ module A { //│ fun g: Int -> Int & Str -> Str //│ } +A.g(0) +//│ Int | Str +//│ res +//│ = 0 + @@ -176,17 +181,7 @@ s([Numbr(0),Numbr(0)]) //│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) //│ ╙── ^^^^^^^^^^^^^ //│ Int | error - -:e -A.g(0) // g <: 0 -> 'a -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.+1: A.g(0) -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `Str` -//│ ║ l.+1: A.g(0) -//│ ╙── ^ -//│ Int | Str | error :e fun add(e) = diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls new file mode 100644 index 0000000000..091301565c --- /dev/null +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -0,0 +1,316 @@ +:NewDefs + + + +trait A +trait B +//│ trait A +//│ trait B + +module AA extends A, B +//│ module AA extends A, B + +fun x: A & B +fun x = AA +//│ fun x: AA +//│ fun x: A & B + +x : A +//│ A +//│ res +//│ = AA { class: [class AA extends Object] } + + + +abstract class Foo[A, B] { fun x: A & B } +//│ abstract class Foo[A, B] { +//│ fun x: A & B +//│ } + +module Bar extends Foo[Int, Bool] { fun x = x } +//│ module Bar extends Foo { +//│ fun x: nothing +//│ } + +module Bar extends Foo { fun x = () } +//│ module Bar extends Foo { +//│ fun x: () +//│ } + +Bar : Foo['a, 'b] +//│ Foo['a, 'b] +//│ where +//│ 'b :> () +//│ 'a :> () +//│ res +//│ = Bar { class: [class Bar extends Foo] } + + +// * An overloaded function type +fun f: (Int -> Int) & (Bool -> Bool) +fun f = id +//│ fun f: forall 'a. 'a -> 'a +//│ fun f: Int -> Int & Bool -> Bool + + +// * Widen the results +fun h: (Int -> (Int | Bool)) & (Bool -> (Int | Bool)) +fun h = f +//│ fun h: Int -> Int & Bool -> Bool +//│ fun h: (Bool | Int) -> (Int | false | true) + +// * Merge intersected functions with same domain +fun g: (Int | Bool) -> (Int | Bool) +fun g = h +//│ fun g: (Bool | Int) -> (Int | false | true) +//│ fun g: (Bool | Int) -> (Int | false | true) + +// * In one step +fun g: (Int | Bool) -> (Int | Bool) +fun g = f +//│ fun g: Int -> Int & Bool -> Bool +//│ fun g: (Bool | Int) -> (Int | false | true) + + +// * Can also widen into intersection +fun i: ((Int & Bool) -> Int) & ((Int & Bool) -> Bool) +fun i = f +//│ fun i: Int -> Int & Bool -> Bool +//│ fun i: nothing -> nothing + +// * Merge intersected functions with same codomain +fun j: (Int & Bool) -> (Int & Bool) +fun j = i +//│ fun j: nothing -> nothing +//│ fun j: nothing -> nothing + +:e // * Note: currently it doesn't work when done in a single step +fun j: (Int & Bool) -> (Int & Bool) +fun j = f +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.89: fun j = f +//│ ║ ^^^^^ +//│ ╙── expression of type `Int` does not match type `nothing` +//│ fun j: Int -> Int & Bool -> Bool +//│ fun j: nothing -> nothing + + +// * Or widen even further with both an intersection and a union, into this +fun g: (Int & Bool) -> (Int | Bool) +fun g = f +//│ fun g: Int -> Int & Bool -> Bool +//│ fun g: nothing -> (Int | false | true) + + +// * Note: we currently approximate uses of overloaded function types! +// * With match-type-based constraint solving, we could return Int here + +f(0) +//│ Int | false | true +//│ res +//│ = 0 + +// f(0) : case 0 of { Int => Int; Bool => Bool } == Int + + +x => f(x) +//│ (Bool | Int) -> (Int | false | true) +//│ res +//│ = [Function: res] + +// : forall 'a: 'a -> case 'a of { Int => Int; Bool => Bool } where 'a <: Int | Bool + + +f(if true then 0 else false) +//│ Int | false | true +//│ res +//│ = 0 + +// * With match-type-based constraint solving, we could *also* return Int here + +:e // TODO implement this syntax +:w +f(refined if true then 0 else false) // this one can be precise again! +//│ ╔══[WARNING] Paren-less applications should use the 'of' keyword +//│ ║ l.133: f(refined if true then 0 else false) // this one can be precise again! +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] identifier not found: refined +//│ ║ l.133: f(refined if true then 0 else false) // this one can be precise again! +//│ ╙── ^^^^^^^ +//│ Int | false | true +//│ Code generation encountered an error: +//│ unresolved symbol refined + + + +// * Notes on constraint solving + + +// * Easy: + +// ?a -> ?b <: (Int -> Int) & (Bool -> Bool) +// to: +// ?a -> ?b <: (Int -> Int) AND ?a -> ?b <: (Bool -> Bool) + +// * Hard; but can solve with match types: + +// (Int -> Int) & (Bool -> Bool) <: ?a -> ?b +// to: +// ?a <: Int | Bool AND (case ?a of { Int => Int; Bool => Bool }) <: ?b + +// We can still widen if needed; consider: +// ?a := Int | Bool +// then: +// (case (Int | Bool) of { Int => Int; Bool => Bool }) <: ?b +// to: +// Int <: ?b AND Bool <: ?b + +// An simple match-type constraint example: +// (case ?a of { Int => Int; Bool => Bool }) <: Int +// to: +// ?a <: Int + +// A more complicated match-type constraint example: +// (case ?a of { Int => ?b; Bool => ?c }) <: T +// to: +// ?b <: (case ?a of { Int => T; Bool => Top }) AND ?c <: (case ?a of { Int => Top; Bool => T }) + + + +class List[A] +//│ class List[A] { +//│ constructor() +//│ } + +// * Note: match type `T match { case List[t] => ... t ... }` could be encoded as: + +type M = (forall 't: List['t] => 't) +//│ type M = forall 't. List['t] -> 't + +type T = List[Int] +//│ type T = List[Int] + +:e // TODO application types +type Res = M(T) +//│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 +//│ ║ l.194: type Res = M(T) +//│ ╙── ^^^^ +//│ type Res = M + + + +let f = x => [x, x] +//│ let f: forall 'a. 'a -> ['a, 'a] +//│ f +//│ = [Function: f2] + +[f(1), f(true)] +//│ [[1, 1], [true, true]] +//│ res +//│ = [ [ 1, 1 ], [ true, true ] ] + + + +:e // TODO support +fun f: Int -> Int +fun f: Bool -> Bool +fun f = id +//│ ╔══[ERROR] A type signature for 'f' was already given +//│ ║ l.216: fun f: Bool -> Bool +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ fun f: forall 'a. 'a -> 'a +//│ fun f: Int -> Int + +:e // TODO support +f: (Int -> Int) & (Bool -> Bool) +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) +//│ ║ ^ +//│ ╟── type `Bool` is not an instance of `Int` +//│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.215: fun f: Int -> Int +//│ ╙── ^^^ +//│ Int -> Int & Bool -> Bool +//│ res +//│ = [Function: id] + +// t: S t: T +// ------------- +// t: S & T + + + +// * Weird MLstruct rule (only sound when we don't have FCP): +// forall 'a: 'a -> 'a <: (Int -> Int) & (Bool -> Bool) == (Int | Bool) -> (Int & Bool) +// ~{ a: Int } <: Str -> Str + +// * Notice: in positive position, this is equivalent to Bottom +fun x: ~{ a: Int } +//│ fun x: nothing + + +class A() +class B() +//│ class A() +//│ class B() + +A() : ~B +//│ ~B +//│ res +//│ = A {} + +// A <: ~B +// <=> +// A <: ~B | Bot +// <=> +// A & B <: Bot + +fun x: A & B +//│ fun x: nothing + + +fun test(x) = if x is + A then 0 + _ then x +//│ fun test: forall 'a. (A | Object & 'a & ~#A) -> (0 | 'a) + +test(B()) +//│ 0 | B +//│ res +//│ = B {} + +test(A()) +//│ 0 +//│ res +//│ = 0 + +// A <: A | Object & 'a & ~A +// A & ~A <: Object & 'a & ~A +// Bot <: Object & 'a & ~A + + +:e // TODO implement this syntax +:w +fun test(x) = refined if x is + A then 0 + B then 1 +//│ ╔══[WARNING] Paren-less applications should use the 'of' keyword +//│ ║ l.296: fun test(x) = refined if x is +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.297: A then 0 +//│ ║ ^^^^^^^^^^ +//│ ║ l.298: B then 1 +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] identifier not found: refined +//│ ║ l.296: fun test(x) = refined if x is +//│ ╙── ^^^^^^^ +//│ fun test: (A | B) -> error +//│ Code generation encountered an error: +//│ unresolved symbol refined + +// forall 'a: 'a -> (case 'a of A -> 0, B & ~A -> 1) + + + diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 31c87b4a47..0b4e81c386 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -47,15 +47,14 @@ fun f: (Str => Str) & ((Str, Int) => Int) //│ fun f: Str -> Str & (Str, Int) -> Int // * ...resulting in approximation at call sites (we don't handle overloading) -:e f("abc", "abc") -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.51: f("abc", "abc") -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── argument list of type `["abc", "abc"]` does not match type `nothing` -//│ ║ l.51: f("abc", "abc") -//│ ╙── ^^^^^^^^^^^^^^ -//│ Int | Str | error +//│ Int | Str +//│ res +//│ = +//│ f is not implemented + +f("abcabc") +//│ Int | Str //│ res //│ = //│ f is not implemented @@ -72,19 +71,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: r(error) +//│ ║ l.71: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.72: r(error) +//│ ║ l.71: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.66: let r = if true then id else (x, y) => [y, x] +//│ ║ l.65: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.73: r(error, error) +//│ ║ l.72: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.73: r(error, error) +//│ ║ l.72: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res @@ -107,7 +106,7 @@ r of [0, 1] // Also currently parses the same: let r = if true then id else [x, y] => [y, x] -//│ let r: forall 'a 'b 'c. (['a, 'b] & 'c) -> (['b, 'a] | 'c) +//│ let r: forall 'a 'b 'c. (['b, 'c] & 'a) -> (['c, 'b] | 'a) //│ r //│ = [Function: id] From 9d91cdecfbef3ddfba924123451ae3f76662205c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 12 Oct 2023 14:53:17 +0800 Subject: [PATCH 477/498] Add various tests --- shared/src/test/diff/nu/CallByName.mls | 39 ++++++++++ shared/src/test/diff/nu/CtorSubtraction.mls | 37 +++++++++ .../test/diff/nu/PrivateMemberOverriding.mls | 63 +++++++++++++++ shared/src/test/diff/ucs/AppSplits.mls | 76 +++++++++++++++++++ shared/src/test/diff/ucs/ThenIndent.mls | 31 ++++++++ 5 files changed, 246 insertions(+) create mode 100644 shared/src/test/diff/nu/CallByName.mls create mode 100644 shared/src/test/diff/nu/CtorSubtraction.mls create mode 100644 shared/src/test/diff/nu/PrivateMemberOverriding.mls create mode 100644 shared/src/test/diff/ucs/AppSplits.mls create mode 100644 shared/src/test/diff/ucs/ThenIndent.mls diff --git a/shared/src/test/diff/nu/CallByName.mls b/shared/src/test/diff/nu/CallByName.mls new file mode 100644 index 0000000000..6258b19520 --- /dev/null +++ b/shared/src/test/diff/nu/CallByName.mls @@ -0,0 +1,39 @@ +:NewDefs + + +let x = log("ok") +//│ let x: () +//│ x +//│ = undefined +//│ // Output +//│ ok + +x +//│ () +//│ res +//│ = undefined + +x +//│ () +//│ res +//│ = undefined + + +fun x = log("ok") +//│ fun x: () + +x +//│ () +//│ res +//│ = undefined +//│ // Output +//│ ok + +x +//│ () +//│ res +//│ = undefined +//│ // Output +//│ ok + + diff --git a/shared/src/test/diff/nu/CtorSubtraction.mls b/shared/src/test/diff/nu/CtorSubtraction.mls new file mode 100644 index 0000000000..38d37eaaac --- /dev/null +++ b/shared/src/test/diff/nu/CtorSubtraction.mls @@ -0,0 +1,37 @@ +:NewDefs + + +class Cls +//│ class Cls { +//│ constructor() +//│ } + +fun x: ('a & Object) -> ('a \ Cls) +fun x = case + Cls then error + y then y +//│ fun x: forall 'b. (Cls | Object & 'b & ~#Cls) -> 'b +//│ fun x: forall 'a. (Object & 'a) -> ('a & ~Cls) + +x : Int -> Int +//│ Int -> Int +//│ res +//│ = [Function: x1] + +x : Cls -> nothing +//│ Cls -> nothing +//│ res +//│ = [Function: x1] + + +fun x: (Int | Str | Cls) \ Cls +fun x = 42 +//│ fun x: 42 +//│ fun x: Int & ~Cls | Str & ~Cls + +x : Int | Str +//│ Int | Str +//│ res +//│ = 42 + + diff --git a/shared/src/test/diff/nu/PrivateMemberOverriding.mls b/shared/src/test/diff/nu/PrivateMemberOverriding.mls new file mode 100644 index 0000000000..3b1fc703a6 --- /dev/null +++ b/shared/src/test/diff/nu/PrivateMemberOverriding.mls @@ -0,0 +1,63 @@ +:NewDefs + + +class Foo(x: Int) +//│ class Foo(x: Int) + +:e // FIXME this should be allowed +class Bar() extends Foo(123) { fun x = true } +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.8: class Bar() extends Foo(123) { fun x = true } +//│ ║ ^^^^^^^^ +//│ ╟── Originally declared here: +//│ ║ l.4: class Foo(x: Int) +//│ ╙── ^ +//│ class Bar() extends Foo { +//│ fun x: true +//│ } + +Bar().x +//│ true +//│ res +//│ = true + + +:e // FIXME this should be allowed +class Bar(val x: Bool) extends Foo(123) +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.26: class Bar(val x: Bool) extends Foo(123) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.4: class Foo(x: Int) +//│ ╙── ^ +//│ class Bar(x: Bool) extends Foo + +Bar(true).x +//│ Bool +//│ res +//│ = true + + +:e // FIXME this should be allowed +class Bar(x: Bool) extends Foo(123) +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.42: class Bar(x: Bool) extends Foo(123) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.4: class Foo(x: Int) +//│ ╙── ^ +//│ class Bar(x: Bool) extends Foo + +:e // * Expected +Bar(true).x +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.52: Bar(true).x +//│ ║ ^^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.42: class Bar(x: Bool) extends Foo(123) +//│ ╙── ^ +//│ error | false | true +//│ res +//│ = undefined + + diff --git a/shared/src/test/diff/ucs/AppSplits.mls b/shared/src/test/diff/ucs/AppSplits.mls new file mode 100644 index 0000000000..f6f81f1736 --- /dev/null +++ b/shared/src/test/diff/ucs/AppSplits.mls @@ -0,0 +1,76 @@ +:NewDefs + + +fun foo(x) = x > 1 +//│ fun foo: Num -> Bool + +:pe // TODO +:e +if foo of + 0 then "a" + 1 then "b" +//│ ╔══[PARSE ERROR] Unexpected 'then' keyword here +//│ ║ l.10: 0 then "a" +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead +//│ ║ l.9: if foo of +//│ ║ ^^^^^^ +//│ ║ l.10: 0 then "a" +//│ ║ ^^^^ +//│ ╟── Note: 'if' expression starts here: +//│ ║ l.9: if foo of +//│ ╙── ^^ +//│ ╔══[ERROR] The case when this is false is not handled: foo(0,) +//│ ║ l.9: if foo of +//│ ║ ^^^^^^ +//│ ║ l.10: 0 then "a" +//│ ╙── ^^^^ +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:pe // TODO +:e +if foo of 1, + 0 then "a" + 1 then "b" +//│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause +//│ ║ l.35: 0 then "a" +//│ ║ ^^^^^^^^^^ +//│ ║ l.36: 1 then "b" +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead +//│ ║ l.34: if foo of 1, +//│ ║ ^^^^^^^^^ +//│ ║ l.35: 0 then "a" +//│ ║ ^^ +//│ ╟── Note: 'if' expression starts here: +//│ ║ l.34: if foo of 1, +//│ ╙── ^^ +//│ ╔══[ERROR] The case when this is false is not handled: foo(1, undefined,) +//│ ║ l.34: if foo of 1, +//│ ║ ^^^^^^^^^ +//│ ║ l.35: 0 then "a" +//│ ╙── ^^ +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:pe // TODO +:e +if foo + (0) then "a" + (1) then "b" +//│ ╔══[PARSE ERROR] Unexpected parenthesis section here +//│ ║ l.63: (1) then "b" +//│ ╙── ^^^ +//│ ╔══[ERROR] The case when this is false is not handled: foo(0,) +//│ ║ l.61: if foo +//│ ║ ^^^ +//│ ║ l.62: (0) then "a" +//│ ╙── ^^^^^ +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + + diff --git a/shared/src/test/diff/ucs/ThenIndent.mls b/shared/src/test/diff/ucs/ThenIndent.mls new file mode 100644 index 0000000000..1ca90defc9 --- /dev/null +++ b/shared/src/test/diff/ucs/ThenIndent.mls @@ -0,0 +1,31 @@ +:NewDefs + + +// FIXME +x => if x == + 0 + then "a" + _ then "b" +//│ ╔══[PARSE ERROR] Unexpected indented block here +//│ ║ l.7: then "a" +//│ ║ ^^^^^^^^^^^^ +//│ ║ l.8: _ then "b" +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application instead +//│ ║ l.5: x => if x == +//│ ║ ^^^^ +//│ ║ l.6: 0 +//│ ║ ^^^ +//│ ╟── Note: 'if' expression starts here: +//│ ║ l.5: x => if x == +//│ ╙── ^^ +//│ ╔══[ERROR] The case when this is false is not handled: ==(x, {0},) +//│ ║ l.5: x => if x == +//│ ║ ^^^^ +//│ ║ l.6: 0 +//│ ╙── ^^^ +//│ anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + From 27752e93a45b0b163fab7f37518ed6b354371410 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 12 Oct 2023 14:58:57 +0800 Subject: [PATCH 478/498] Allow 'overriding' private members --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 + shared/src/test/diff/nu/BadClassInherit.mls | 62 ++++++------- shared/src/test/diff/nu/Interfaces.mls | 87 +++++++------------ shared/src/test/diff/nu/ParamPassing.mls | 49 +++++------ .../test/diff/nu/PrivateMemberOverriding.mls | 40 ++++----- 5 files changed, 101 insertions(+), 139 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 7d3de82639..033964e0a4 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -29,6 +29,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def level: Level def isImplemented: Bool def isPublic: Bool + def isPrivate: Bool = !isPublic // * We currently don't support `protected` def isValueParam: Bool = this match { case p: NuParam => !p.isType @@ -1267,6 +1268,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (m: TypedNuTermDef, S(fun: TypedNuTermDef)) => fun match { // * If the implementation and the declaration are in the same class, // * it does not require to be virtual. + case _ if fun.isPrivate => () // * Private members are not actually inherited case td: TypedNuFun if (!td.fd.isVirtual && !clsSigns.contains(fun)) => err(msg"${m.kind.str.capitalize} member `${m.name }` is not virtual and cannot be overridden" -> m.toLoc :: diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index cb696fc26e..0d1240eb56 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -11,12 +11,6 @@ class C2(x: Int) extends C1(y) { //│ ╔══[ERROR] identifier not found: y //│ ║ l.8: class C2(x: Int) extends C1(y) { //│ ╙── ^ -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.8: class C2(x: Int) extends C1(y) { -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class C1(x: Int) -//│ ╙── ^ //│ class C2(x: Int) extends C1 { //│ val y: Int //│ } @@ -28,7 +22,7 @@ abstract class C2 extends C1(y) { val y: Int } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.27: abstract class C2 extends C1(y) { +//│ ║ l.21: abstract class C2 extends C1(y) { //│ ╙── ^ //│ abstract class C2 extends C1 { //│ val y: Int @@ -41,7 +35,7 @@ abstract class C2 extends C1(this.y) { val y: Int } //│ ╔══[ERROR] identifier not found: this -//│ ║ l.40: abstract class C2 extends C1(this.y) { +//│ ║ l.34: abstract class C2 extends C1(this.y) { //│ ╙── ^^^^ //│ abstract class C2 extends C1 { //│ val y: Int @@ -54,7 +48,7 @@ class C1(x: C1) :e class C2 extends C1(this) //│ ╔══[ERROR] identifier not found: this -//│ ║ l.55: class C2 extends C1(this) +//│ ║ l.49: class C2 extends C1(this) //│ ╙── ^^^^ //│ class C2 extends C1 { //│ constructor() @@ -70,19 +64,19 @@ class Foo { virtual fun x: Int = 1 } :e class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.71: class Bar extends Foo { fun x = false } +//│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.71: class Bar extends Foo { fun x = false } +//│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.71: class Bar extends Foo { fun x = false } +//│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -95,19 +89,19 @@ class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.94: fun x: Bool +//│ ║ l.88: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.94: fun x: Bool +//│ ║ l.88: fun x: Bool //│ ║ ^^^^ //│ ╟── but it flows into signature of member `x` with expected type `Int` -//│ ║ l.94: fun x: Bool +//│ ║ l.88: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -122,19 +116,19 @@ mixin M { fun x = false } :e class Bar extends Foo, M //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.117: mixin M { fun x = false } +//│ ║ l.111: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.117: mixin M { fun x = false } +//│ ║ l.111: mixin M { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.117: mixin M { fun x = false } +//│ ║ l.111: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -162,19 +156,19 @@ trait B { class X { fun g = 1 } } :e class C extends A, B //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.163: class C extends A, B +//│ ║ l.157: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.147: trait B { class X { fun g = 1 } } +//│ ║ l.141: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Intersection of class member and class members currently unsupported -//│ ║ l.163: class C extends A, B +//│ ║ l.157: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.146: class A { class X { fun f = 1 } } +//│ ║ l.140: class A { class X { fun f = 1 } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.147: trait B { class X { fun g = 1 } } +//│ ║ l.141: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A, B { //│ constructor() @@ -189,14 +183,14 @@ class C extends A { class X { fun g = 1 } } //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.188: class C extends A { +//│ ║ l.182: class C extends A { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.189: class X { fun g = 1 } +//│ ║ l.183: class X { fun g = 1 } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.190: } +//│ ║ l.184: } //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.146: class A { class X { fun f = 1 } } +//│ ║ l.140: class A { class X { fun f = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A { //│ constructor() @@ -211,7 +205,7 @@ class C extends A { :e class Foo2 extends Foo2 //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.212: class Foo2 extends Foo2 +//│ ║ l.206: class Foo2 extends Foo2 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ //│ class Foo2 extends Foo2 { //│ constructor() diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 2d7d8a4212..34ab4936b8 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -796,14 +796,7 @@ class Cx(a2: 1 | 2, val b: Bool) extends Ca(a2) //│ fun foo: 1 //│ } -:e class Cx(a: 1 | 2, val b: Bool) extends Ca(a) -//│ ╔══[ERROR] Inherited parameter named `a` is not virtual and cannot be overridden -//│ ║ l.800: class Cx(a: 1 | 2, val b: Bool) extends Ca(a) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.781: class Ca(a: Int) extends Oth { -//│ ╙── ^ //│ class Cx(a: 1 | 2, b: Bool) extends Ca, Oth, Test { //│ fun bar: forall 'a. 'a -> 'a //│ fun cool: anything -> false @@ -844,22 +837,15 @@ abstract class Bc3 { :e class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] Cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.845: class Bc12() extends Bc1(1), Bc2(true) +//│ ║ l.838: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: //│ unexpected parent symbol new class Bc2. -:e class Bc02() extends Bc1(1:Int) { val foo = 2 } -//│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden -//│ ║ l.855: val foo = 2 -//│ ║ ^^^^^^^ -//│ ╟── Originally declared here: -//│ ║ l.833: class Bc1(foo: Int) -//│ ╙── ^^^ //│ class Bc02() extends Bc1 { //│ val foo: 2 //│ } @@ -872,27 +858,20 @@ Bc02().foo :e class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.873: class Bc31(baz: Bool) extends Bc3 +//│ ║ l.859: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.836: let baz : Int +//│ ║ l.829: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.836: let baz : Int +//│ ║ l.829: let baz : Int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: Bool) extends Bc3 -:e class Bc11 extends Bc1(1) { let foo = true } -//│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden -//│ ║ l.888: let foo = true -//│ ║ ^^^^^^^^^^ -//│ ╟── Originally declared here: -//│ ║ l.833: class Bc1(foo: Int) -//│ ╙── ^^^ //│ class Bc11 extends Bc1 { //│ constructor() //│ let foo: true @@ -921,7 +900,7 @@ trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.921: fun f = error +//│ ║ l.900: fun f = error //│ ╙── ^^^^^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -952,7 +931,7 @@ bp: Base[[Int, Bool]] :e bp: Base[[Int, Int]] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.953: bp: Base[[Int, Int]] +//│ ║ l.932: bp: Base[[Int, Int]] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -1013,13 +992,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.1014: class DerBad1 extends Base[Int, Int] -//│ ╙── ^^^^^^^^^^^^^ +//│ ║ l.993: class DerBad1 extends Base[Int, Int] +//│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared (or its declaration is inherited) but is not implemented in `DerBad1` -//│ ║ l.1014: class DerBad1 extends Base[Int, Int] -//│ ║ ^^^^^^^ +//│ ║ l.993: class DerBad1 extends Base[Int, Int] +//│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.902: trait Base[A] { fun f: A -> A } +//│ ║ l.881: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^^^^^ //│ class DerBad1 extends Base { //│ constructor() @@ -1031,28 +1010,28 @@ class DerBad1 extends Base[Int, Int] :e class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ constructor() @@ -1104,7 +1083,7 @@ trait Tb extends Ta[Int] { virtual val p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1104: virtual val p = false +//│ ║ l.1083: virtual val p = false //│ ╙── ^^^^^^^^^^^^^ //│ trait Tb extends Ta { //│ val g: 'T @@ -1139,14 +1118,14 @@ trait Oz { :e class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1140: class Fischl(age: Bool) extends Oz +//│ ║ l.1119: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1133: let age: Int +//│ ║ l.1112: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1133: let age: Int +//│ ║ l.1112: let age: Int //│ ╙── ^^^^^^^^ //│ class Fischl(age: Bool) extends Oz @@ -1166,29 +1145,29 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1157: virtual fun foo(x) = x + 1 +//│ ║ l.1136: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1157: virtual fun foo(x) = x + 1 +//│ ║ l.1136: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { //│ constructor() @@ -1207,11 +1186,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1208: class Ohhh(x: Bool) extends Ha +//│ ║ l.1187: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1198: class Ha { virtual val x: Int = 1 } +//│ ║ l.1177: class Ha { virtual val x: Int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: Bool) extends Ha diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 57cbf7b8ef..4eacce0f29 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -7,14 +7,7 @@ class Foo(x: Int) class Bar(z: Int, y: Int) extends Foo(z + y) //│ class Bar(z: Int, y: Int) extends Foo -:e class Bar(x: Int, y: Int) extends Foo(x + y) -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.11: class Bar(x: Int, y: Int) extends Foo(x + y) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar(x: Int, y: Int) extends Foo @@ -31,7 +24,7 @@ Bar.x :e // FIXME module Bar extends Foo(11) { fun get = this.x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.32: module Bar extends Foo(11) { fun get = this.x } +//│ ║ l.25: module Bar extends Foo(11) { fun get = this.x } //│ ╙── ^^ //│ module Bar extends Foo { //│ fun get: error @@ -62,10 +55,10 @@ class Foo(x: Int) :e Foo(1).x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.63: Foo(1).x +//│ ║ l.56: Foo(1).x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.59: class Foo(x: Int) +//│ ║ l.52: class Foo(x: Int) //│ ╙── ^ //│ Int | error //│ res @@ -74,10 +67,10 @@ Foo(1).x :e Foo(1).#x //│ ╔══[ERROR] identifier not found: .# -//│ ║ l.75: Foo(1).#x +//│ ║ l.68: Foo(1).#x //│ ╙── ^^ //│ ╔══[ERROR] identifier not found: x -//│ ║ l.75: Foo(1).#x +//│ ║ l.68: Foo(1).#x //│ ╙── ^ //│ error //│ Code generation encountered an error: @@ -106,20 +99,20 @@ if Foo(1) is Foo(x) then x :e class Bar(x: Int) extends Foo(x) //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.107: class Bar(x: Int) extends Foo(x) +//│ ║ l.100: class Bar(x: Int) extends Foo(x) //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ class Bar(x: Int) extends Foo :e Bar(11).x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.117: Bar(11).x +//│ ║ l.110: Bar(11).x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.107: class Bar(x: Int) extends Foo(x) +//│ ║ l.100: class Bar(x: Int) extends Foo(x) //│ ╙── ^ //│ Int | error //│ res @@ -129,10 +122,10 @@ Bar(11).x :e class Bar(val x: Int) extends Foo(x + 1) //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.130: class Bar(val x: Int) extends Foo(x + 1) +//│ ║ l.123: class Bar(val x: Int) extends Foo(x + 1) //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ class Bar(x: Int) extends Foo @@ -144,10 +137,10 @@ Bar(11).x :e class Bar extends Foo(1) { val x: 2 } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.145: class Bar extends Foo(1) { val x: 2 } +//│ ║ l.138: class Bar extends Foo(1) { val x: 2 } //│ ║ ^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ class Bar extends Foo { //│ constructor() @@ -157,10 +150,10 @@ class Bar extends Foo(1) { val x: 2 } :e module Bar extends Foo(1) { fun x = 2 } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.158: module Bar extends Foo(1) { fun x = 2 } +//│ ║ l.151: module Bar extends Foo(1) { fun x = 2 } //│ ║ ^^^^^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ module Bar extends Foo { //│ fun x: 2 @@ -188,10 +181,10 @@ module B extends A(42) :e B.x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.189: B.x +//│ ║ l.182: B.x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.182: class A(x: Int) +//│ ║ l.175: class A(x: Int) //│ ╙── ^ //│ Int | error //│ res @@ -230,16 +223,16 @@ module Bazz extends Foo(0) { val x: 2 } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.230: val x: 2 +//│ ║ l.223: val x: 2 //│ ║ ^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } +//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } //│ ╙── ^ //│ ╔══[ERROR] Member `i` is declared (or its declaration is inherited) but is not implemented in `Bazz` -//│ ║ l.229: module Bazz extends Foo(0) { +//│ ║ l.222: module Bazz extends Foo(0) { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } +//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } //│ ╙── ^^^^^^^^^^^^^ //│ module Bazz extends Foo { //│ fun i: 'A -> 'A diff --git a/shared/src/test/diff/nu/PrivateMemberOverriding.mls b/shared/src/test/diff/nu/PrivateMemberOverriding.mls index 3b1fc703a6..e7977a41df 100644 --- a/shared/src/test/diff/nu/PrivateMemberOverriding.mls +++ b/shared/src/test/diff/nu/PrivateMemberOverriding.mls @@ -4,14 +4,7 @@ class Foo(x: Int) //│ class Foo(x: Int) -:e // FIXME this should be allowed class Bar() extends Foo(123) { fun x = true } -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.8: class Bar() extends Foo(123) { fun x = true } -//│ ║ ^^^^^^^^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar() extends Foo { //│ fun x: true //│ } @@ -21,15 +14,13 @@ Bar().x //│ res //│ = true +if Bar() is Foo(a) then a +//│ Int +//│ res +//│ = 123 + -:e // FIXME this should be allowed class Bar(val x: Bool) extends Foo(123) -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.26: class Bar(val x: Bool) extends Foo(123) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar(x: Bool) extends Foo Bar(true).x @@ -37,27 +28,30 @@ Bar(true).x //│ res //│ = true +if Bar(true) is Foo(a) then a +//│ Int +//│ res +//│ = 123 + -:e // FIXME this should be allowed class Bar(x: Bool) extends Foo(123) -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.42: class Bar(x: Bool) extends Foo(123) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar(x: Bool) extends Foo :e // * Expected Bar(true).x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.52: Bar(true).x +//│ ║ l.41: Bar(true).x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.42: class Bar(x: Bool) extends Foo(123) +//│ ║ l.37: class Bar(x: Bool) extends Foo(123) //│ ╙── ^ //│ error | false | true //│ res //│ = undefined +if Bar(true) is Foo(a) then a +//│ Int +//│ res +//│ = 123 + From 38bf8fcba649d78bcba94ac23a8e7136979f6736 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 10 Oct 2023 15:04:42 +0800 Subject: [PATCH 479/498] Update NodeTest --- shared/src/test/scala/mlscript/NodeTest.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/test/scala/mlscript/NodeTest.scala b/shared/src/test/scala/mlscript/NodeTest.scala index e9628619f4..1d23160af2 100644 --- a/shared/src/test/scala/mlscript/NodeTest.scala +++ b/shared/src/test/scala/mlscript/NodeTest.scala @@ -16,6 +16,7 @@ class NodeTests extends org.scalatest.funsuite.AnyFunSuite { || v.startsWith("v17") || v.startsWith("v18") || v.startsWith("v19") + || v.startsWith("v20") ) } From f5e98264664fbd30490f6c5e21337aa9671a2fb3 Mon Sep 17 00:00:00 2001 From: HarrisL2 Date: Thu, 12 Oct 2023 17:52:51 +0800 Subject: [PATCH 480/498] Add defunctionalizer prototype (#185) Co-authored-by: YKY --- .../scala/mlscript/compiler/ClassLifter.scala | 256 ++-- .../scala/mlscript/compiler/DataType.scala | 36 + .../mlscript/compiler/DataTypeInferer.scala | 18 + .../scala/mlscript/compiler/Helpers.scala | 196 +++ .../mlscript/compiler/mono/Monomorph.scala | 334 +++++ .../compiler/mono/MonomorphContext.scala | 33 + .../compiler/mono/MonomorphError.scala | 3 + .../mono/specializer/BoundedExpr.scala | 226 ++++ .../compiler/mono/specializer/Builtin.scala | 95 ++ .../compiler/mono/specializer/Context.scala | 21 + .../mono/specializer/Predicates.scala | 6 + .../mono/specializer/Specializer.scala | 228 ++++ .../compiler/printer/ExprPrinter.scala | 73 + .../main/scala/mlscript/compiler/syntax.scala | 271 ++++ compiler/shared/test/diff/LambLift.mls | 87 ++ compiler/shared/test/diff/LiftType.mls | 14 +- compiler/shared/test/diff/Lifter.mls | 161 +-- compiler/shared/test/diff/LifterBlks.mls | 130 +- compiler/shared/test/diff/mono.mls | 1204 +++++++++++++++++ .../test/scala/mlscript/compiler/Test.scala | 29 +- .../main/scala/mlscript/codegen/Helpers.scala | 2 +- .../src/test/scala/mlscript/DiffTests.scala | 5 +- 22 files changed, 3204 insertions(+), 224 deletions(-) create mode 100644 compiler/shared/main/scala/mlscript/compiler/DataType.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/Helpers.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/syntax.scala create mode 100644 compiler/shared/test/diff/LambLift.mls create mode 100644 compiler/shared/test/diff/mono.mls diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index e54df8e064..5c0c8da40b 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -6,8 +6,10 @@ import mlscript.utils.shorthands.* import scala.collection.mutable.StringBuilder as StringBuilder import scala.collection.mutable.Map as MutMap import scala.collection.mutable.Set as MutSet +import scala.collection.mutable.ArrayBuffer as ArrayBuffer import mlscript.codegen.Helpers.inspect as showStructure import mlscript.codegen.CodeGenError +import mlscript.compiler.mono.MonomorphError class ClassLifter(logDebugMsg: Boolean = false) { type ClassName = String @@ -28,6 +30,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { LocalContext(vSet ++ inters.map(x => Var(x.name)), tSet -- inters) } def intersect(rst: LocalContext) = LocalContext(vSet intersect rst.vSet, tSet intersect rst.tSet) + def intersectV(rst: Set[Var]) = LocalContext(vSet.intersect(rst), tSet) def contains(v: Var) = vSet.contains(v) || tSet.contains(TypeName(v.name)) def contains(tv: TypeName) = vSet.contains(Var(tv.name)) || tSet.contains(tv) override def toString(): String = "(" ++ vSet.mkString(", ") ++ "; " ++ tSet.mkString(", ") ++ ")" @@ -37,6 +40,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { private def asContext(t: TypeName) = LocalContext(Set(), Set(t)) private def asContextT(tS: IterableOnce[TypeName]) = LocalContext(Set(), tS.iterator.toSet) private def emptyCtx = LocalContext(Set(), Set()) + private def emptyCtxObj = LocalContext(Set(Var("this")), Set()) case class ClassInfoCache( originNm: TypeName, @@ -55,6 +59,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { type NamePath = List[String] var retSeq: List[NuTypeDef] = Nil + val globalFunctions: ArrayBuffer[NuFunDef] = ArrayBuffer() var anonymCnt: Int = 0 var clsCnt: Int = 0 val logOutput: StringBuilder = new StringBuilder @@ -144,7 +149,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { (tmp._1.flatten, tmp._2.flatten, tmp._3.flatten) } - private def genClassNm(orgNm: String)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): TypeName = { + private def genClassNm(orgNm: String)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): TypeName = { TypeName(outer match{ case None => clsCnt = clsCnt+1 @@ -153,11 +158,15 @@ class ClassLifter(logDebugMsg: Boolean = false) { }) } - private def getFreeVars(stmt: Located)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): LocalContext = stmt match{ - case v:Var => - log(s"get free var find $v: ${ctx.vSet.contains(v)}/${buildPathToVar(v).isDefined}/${cache.contains(TypeName(v.name))}/${v.name.equals("this")}") - if(ctx.vSet.contains(v) || buildPathToVar(v).isDefined || cache.contains(TypeName(v.name)) || v.name.equals("this") || primiTypes.contains(v.name)) then emptyCtx else asContext(v) - case t: NamedType => + private def getFreeVars(stmt: Located)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): LocalContext = stmt match{ + case v:Var => + val caseEmpty = ctx.vSet.contains(v) || cache.contains(TypeName(v.name)) || globFuncs.contains(v) || primiTypes.contains(v.name) + val caseThis = buildPathToVar(v).isDefined && !ctx.vSet.contains(Var("this")) + log(s"get free var find $v: $caseEmpty/$caseThis") + if(caseEmpty) then emptyCtx + else if(caseThis) asContext(Var("this")) + else asContext(v) + case t: NamedType => log(s"get type $t under $ctx, $cache, $outer") asContextT(t.collectTypeNames.map(TypeName(_)).filterNot(x => ctx.contains(x) || cache.contains(x) || primiTypes.contains(x.name))) case Lam(lhs, rhs) => @@ -181,7 +190,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { case TyApp(trm, tpLst) => getFreeVars(trm).addT(tpLst.flatMap(_.collectTypeNames.map(TypeName(_)))) case NuTypeDef(_, nm, tps, param, _, _, pars, _, _, body) => - val prmVs = getFreeVars(param.getOrElse(Tup(Nil)))(using emptyCtx, Map(), None) + val prmVs = getFreeVars(param.getOrElse(Tup(Nil)))(using emptyCtx, Map(), globFuncs, None) val newVs = prmVs.vSet ++ getFields(body.entities) + Var(nm.name) val nCtx = ctx.addV(newVs).addT(nm).addT(tps.map(_._2)) val parVs = pars.map(getFreeVars(_)(using nCtx)).fold(emptyCtx)(_ ++ _) @@ -196,20 +205,20 @@ class ClassLifter(logDebugMsg: Boolean = false) { others.children.map(getFreeVars).fold(emptyCtx)(_ ++ _) } - private def collectClassInfo(cls: NuTypeDef, preClss: Set[TypeName])(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): ClassInfoCache = { + private def collectClassInfo(cls: NuTypeDef, preClss: Set[TypeName])(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): ClassInfoCache = { val NuTypeDef(_, nm, tps, param, _, _, pars, _, _, body) = cls - log(s"grep context of ${cls.nme.name} under {\n$ctx\n$cache\n$outer\n}\n") + log(s"grep context of ${cls.nme.name} under $ctx # $cache # $globFuncs # $outer ") val (clses, funcs, trms) = splitEntities(cls.body.entities) val (supNms, rcdFlds) = pars.map(getSupClsInfoByTerm).unzip val flds = rcdFlds.flatten.map{ - case (v, Fld(_, trm)) => - val tmp = getFreeVars(trm)(using emptyCtx) + case (v, Fld(_, trm)) => + val tmp = getFreeVars(trm)(using emptyCtxObj) val ret = tmp.tSet ++ tmp.vSet.map(x => TypeName(x.name)) (v, ret) }.unzip log(s"par record: ${flds._2.flatten}") val fields = (param.fold(Nil)(t => t.fields).flatMap(tupleEntityToVar) ++ funcs.map(_.nme) ++ clses.map(x => Var(x.nme.name)) ++ trms.flatMap(grepFieldsInTrm) ++ flds._1).toSet - val nCtx = ctx.addV(fields).addV(flds._1).extT(tps.map(_._2)) + val nCtx = ctx.addV(fields).addV(flds._1).extT(tps.map(_._2)).addV(Var("this")) val tmpCtx = ((body.entities.map(getFreeVars(_)(using nCtx)) ++ pars.map(getFreeVars(_)(using nCtx))).fold(emptyCtx)(_ ++ _).moveT2V(preClss) ).addT(flds._2.flatten.toSet).extV(supNms.flatten.map(x => Var(x.name))) @@ -218,8 +227,8 @@ class ClassLifter(logDebugMsg: Boolean = false) { ret } - private def liftCaseBranch(brn: CaseBranches)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (CaseBranches, LocalContext) = brn match{ - case Case(v: Var, body, rest) => + private def liftCaseBranch(brn: CaseBranches)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (CaseBranches, LocalContext) = brn match{ + case Case(v: Var, body, rest) => val nTrm = liftTerm(body)(using ctx.addV(v)) val nRest = liftCaseBranch(rest) (Case(v, nTrm._1, nRest._1), nTrm._2 ++ nRest._2) @@ -233,18 +242,18 @@ class ClassLifter(logDebugMsg: Boolean = false) { case NoCases => (brn, emptyCtx) } - private def liftIf(body: IfBody)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (IfBody, LocalContext) = body match{ - case IfElse(expr) => + private def liftIf(body: IfBody)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (IfBody, LocalContext) = body match{ + case IfElse(expr) => val ret = liftTerm(expr) (IfElse(ret._1), ret._2) case IfThen(expr, rhs) => val nE = liftTerm(expr) val nR = liftTerm(rhs) (IfThen(nE._1, nR._1), nE._2 ++ nR._2) - case _ => ??? + case _ => throw MonomorphError(s"Unknown IfBody: ${body}") } - private def liftTuple(tup: Tup)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Tup, LocalContext) = { + private def liftTuple(tup: Tup)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Tup, LocalContext) = { val ret = tup.fields.map{ case (None, Fld(flags, trm)) => val tmp = liftTerm(trm) @@ -256,7 +265,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { (Tup(ret._1), ret._2.fold(emptyCtx)(_ ++ _)) } - private def liftConstr(tp: TypeName, prm: Tup)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (TypeName, Tup, LocalContext) = { + private def liftConstr(tp: TypeName, prm: Tup)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (TypeName, Tup, LocalContext) = { def findAncestor(crt: ClassInfoCache, target: Option[ClassInfoCache]): Option[(List[String], Option[String])] = { (crt.outerCls, target) match{ case (None, None) => None @@ -290,8 +299,13 @@ class ClassLifter(logDebugMsg: Boolean = false) { } } - private def liftTerm(target: Term)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Term, LocalContext) = target match { - case v: Var => + private def newLambObj(lhs: Term, rhs: Term) = + New(None, TypingUnit(List(NuFunDef(None, Var("apply"), None, Nil, Left(Lam(lhs, rhs)))(N, N, N, N, false)))) //TODO: Use Proper Arguments + + private def liftTerm(target: Term)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Term, LocalContext) = + log(s"liftTermNew $target in $ctx, $cache, $globFuncs, $outer") + target match{ + case v: Var => if(ctx.contains(v) || v.name.equals("this") || primiTypes.contains(v.name)) (v, emptyCtx) else if(cache.contains(TypeName(v.name))){ val ret = liftConstr(TypeName(v.name), Tup(Nil)) @@ -303,12 +317,16 @@ class ClassLifter(logDebugMsg: Boolean = false) { case None => (v, asContext(v)) } } - case Lam(lhs, rhs) => - val lctx = getFreeVars(lhs)(using emptyCtx, cache, None) - val (ltrm, _) = liftTerm(lhs)(using ctx.addV(lctx.vSet)) - val (rtrm, rctx) = liftTerm(rhs)(using ctx.addV(lctx.vSet)) - (Lam(ltrm, rtrm), rctx -+ lctx) - case t: Tup => + case Lam(lhs, rhs) => + val prmCnt = getFreeVars(lhs)(using emptyCtx, cache, globFuncs, None).vSet.size + val nTpNm = TypeName(genAnoName("Lambda"+prmCnt)) + val anoCls = NuTypeDef( + Cls, nTpNm, Nil, S(Tup(Nil)), N, N, Nil, N, N, + TypingUnit(List(NuFunDef(None, Var("apply"), N, Nil, Left(Lam(lhs, rhs)))(N, N, N, N, false))))(N, N) //TODO: Use Proper Arguments + val nSta = New(Some((nTpNm, Tup(Nil))), TypingUnit(Nil)) + val ret = liftEntities(List(anoCls, nSta)) + (Blk(ret._1), ret._2) + case t: Tup => liftTuple(t) case Rcd(fields) => val ret = fields.map{ @@ -324,7 +342,12 @@ class ClassLifter(logDebugMsg: Boolean = false) { case App(v: Var, prm: Tup) if cache.contains(TypeName(v.name)) => val ret = liftConstr(TypeName(v.name), prm) (App(Var(ret._1.name), ret._2), ret._3) - case App(lhs, rhs) => + case App(v: Var, prm: Tup) if globFuncs.contains(v) => + val (nFuncName, nCtxs) = globFuncs.get(v).get + val addiArgs = nCtxs.vSet.toList.map(toFldsEle(_)) + val nPrm = liftTuple(prm) + (App(nFuncName, Tup(nPrm._1.fields ++ addiArgs)), nPrm._2) + case App(lhs, rhs) => val (ltrm, lctx) = liftTerm(lhs) val (rtrm, rctx) = liftTerm(rhs) (App(ltrm, rtrm), lctx ++ rctx) @@ -357,7 +380,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { case Sel(receiver, fieldName) => val nRec = liftTerm(receiver) (Sel(nRec._1, fieldName), nRec._2) - case Splc(fields) => ??? + case Splc(fields) => throw MonomorphError(s"Unimplemented liftTerm: ${target}") case Subs(arr, idx) => val (ltrm, lctx) = liftTerm(arr) val (rtrm, rctx) = liftTerm(idx) @@ -370,7 +393,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val ret = liftTerm(lhs) val nTs = targs.map(liftType).unzip (TyApp(ret._1, nTs._1), nTs._2.fold(ret._2)(_ ++ _)) - case With(trm, fields) => ??? + case With(trm, fields) => throw MonomorphError(s"Unimplemented liftTerm: ${target}") case New(Some((t: TypeName, prm: Tup)), TypingUnit(Nil)) => val ret = liftConstr(t, prm) (New(Some((ret._1, ret._2)), TypingUnit(Nil)), ret._3) @@ -390,7 +413,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nSta = New(Some((nTpNm, Tup(Nil))), TypingUnit(Nil)) val ret = liftEntities(List(anoCls, nSta)) (Blk(ret._1), ret._2) - case New(head, body) => ??? + case New(head, body) => throw MonomorphError(s"Unimplemented liftTerm: ${target}") case Blk(stmts) => val ret = liftEntities(stmts) (Blk(ret._1), ret._2) @@ -405,12 +428,12 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (bod2, ctx) = liftTerm(bod) val (sts2, ctx2) = liftEntities(sts) (Where(bod2, sts2), ctx2) - case _: Eqn | _: Super => ??? // TODO - case patmat: AdtMatchWith => lastWords(s"Cannot liftTerm ${patmat}") + case _: Eqn | _: Super => throw MonomorphError(s"Unimplemented liftTerm: ${target}") // TODO + case patmat: AdtMatchWith => lastWords(s"Cannot liftTermNew ${patmat}") } //serves for lifting Tup(Some(_), Fld(_, _, trm)), where trm refers to a type - private def liftTermAsType(target: Term)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Term, LocalContext) = + private def liftTermAsType(target: Term)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Term, LocalContext) = log(s"liftTermAsType $target in $ctx, $cache") target match{ case v: Var => @@ -442,24 +465,24 @@ class ClassLifter(logDebugMsg: Boolean = false) { ((v, Fld(flags, tmp._1)), tmp._2) }.unzip (Rcd(ret._1), ret._2.fold(emptyCtx)(_ ++ _)) - case _ => ??? + case _ => throw MonomorphError(s"Unimplemented liftTermAsType: ${target}") } - private def liftTypeName(target: TypeName)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (TypeName, LocalContext) = { + private def liftTypeName(target: TypeName)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (TypeName, LocalContext) = { if(ctx.contains(target) || primiTypes.contains(target.name)) { target -> emptyCtx } else { cache.get(target).map(x => (x.liftedNm -> emptyCtx)).getOrElse(target -> asContext(target)) } } - private def liftTypeField(target: Field)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Field, LocalContext) = { + private def liftTypeField(target: Field)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Field, LocalContext) = { val (inT, iCtx) = target.in.map(liftType).unzip val (outT, oCtx) = liftType(target.out) Field(inT, outT) -> (iCtx.getOrElse(emptyCtx) ++ oCtx) } - private def liftType(target: Type)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Type, LocalContext) = target match{ - case AppliedType(base, targs) => + private def liftType(target: Type)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Type, LocalContext) = target match{ + case AppliedType(base, targs) => val (nTargs, nCtx) = targs.map(liftType).unzip val (nBase, bCtx) = liftTypeName(base) AppliedType(nBase, nTargs) -> (nCtx.fold(emptyCtx)(_ ++ _) ++ bCtx) @@ -536,18 +559,24 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (body2, ctx) = liftType(body) PolyType(targs, body2) -> ctx case Top | Bot | _: Literal | _: TypeTag | _: TypeVar => target.asInstanceOf[Type] -> emptyCtx - case _: Selection => ??? // TODO + case _: Selection => throw MonomorphError(s"Unimplemented liftType: ${target}") // TODO } - private def liftFunc(func: NuFunDef)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (NuFunDef, LocalContext) = { - log(s"liftFunc $func under $ctx # $cache # $outer") + private def liftMemberFunc(func: NuFunDef)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (NuFunDef, LocalContext) = { + log(s"liftMemberFunc $func under $ctx # $cache # $globFuncs # $outer") val NuFunDef(rec, nm, sn, tpVs, body) = func - body match { - case Left(value) => - val ret = liftTerm(value)(using ctx.addV(nm).addT(tpVs)) - (func.copy(rhs = Left(ret._1))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), ret._2) - case Right(PolyType(targs, body)) => + body match{ + case Left(Lam(lhs@Tup(etts), rhs)) => + val lctx = getFreeVars(lhs)(using emptyCtx, cache, globFuncs, None) + val lret = liftTuple(lhs)(using ctx.addV(lctx.vSet)) + val ret = liftTerm(rhs)(using ctx.addV(lctx.vSet).addT(tpVs)) + (func.copy(rhs = Left(Lam(lret._1, ret._1)))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), ret._2 -+ lret._2) //TODO: Check correctness + case Left(value) => + // will be treated as Lam(Tup(Nil), rhs) + val ret = liftTerm(value)(using ctx.addT(tpVs)) + (func.copy(rhs = Left(Lam(Tup(Nil), ret._1)))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), ret._2) //TODO: Check correctness + case Right(PolyType(targs, body)) => val nBody = liftType(body)(using ctx.addT(tpVs)) val nTargs = targs.map { case L(tp) => liftTypeName(tp)(using ctx.addT(tpVs)).mapFirst(Left.apply) @@ -555,9 +584,39 @@ class ClassLifter(logDebugMsg: Boolean = false) { }.unzip (func.copy(rhs = Right(PolyType(nTargs._1, nBody._1)))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), nTargs._2.fold(nBody._2)(_ ++ _)) - case _ => ??? // TODO + case _ => throw MonomorphError(s"Unimplemented liftMemberFunc: ${func}") // TODO } } + + private def liftGlobalFunc(func: NuFunDef)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): Unit = { + log(s"liftGlobalFunc $func under $ctx # $cache # $globFuncs # $outer") + val NuFunDef(rec, nm, _, tpVs, body) = func + val nTpVs = tpVs ++ globFuncs.get(nm).get._2.tSet.toList + globalFunctions.addOne(body match{ + case Left(Lam(lhs@Tup(etts), rhs)) => + val tmp = globFuncs.get(nm).get._2.vSet.toList.map(toFldsEle) + val lctx = getFreeVars(lhs)(using emptyCtx, cache, globFuncs, None) + val lret = liftTuple(lhs)(using ctx.addV(lctx.vSet) ++ globFuncs.get(nm).get._2, cache, globFuncs) + val ret = liftTerm(rhs)(using ctx.addV(lctx.vSet) ++ globFuncs.get(nm).get._2, cache, globFuncs) + NuFunDef(rec, globFuncs.get(nm).get._1, N, nTpVs, Left(Lam(Tup(lret._1.fields ++ tmp), ret._1)))(N, N, N, N, true) //TODO: Use proper arguments + case Left(rhs) => + // will be treated as Lam(Tup(Nil), rhs) + val tmp = globFuncs.get(nm).get._2.vSet.toList.map(toFldsEle) + val ret = liftTerm(rhs)(using ctx ++ globFuncs.get(nm).get._2, cache, globFuncs) + NuFunDef(rec, globFuncs.get(nm).get._1, N, nTpVs, Left(Lam(Tup(tmp), ret._1)))(N, N, N, N, true) //TODO: Use proper arguments + // val ret = liftTermNew(value)(using ctx.addV(nm) ++ globFuncs.get(nm).get._2, cache, globFuncs) + // NuFunDef(rec, globFuncs.get(nm).get._1, nTpVs, Left(ret._1)) + case Right(PolyType(targs, body)) => + val nBody = liftType(body)(using ctx ++ globFuncs.get(nm).get._2, cache, globFuncs, None) + val nTargs = targs.map({ + case L(tn) => + liftTypeName(tn)(using ctx.addT(nTpVs), cache, globFuncs, None) match + case (tn, ctx) => (L(tn), ctx) + case R(tv) => R(tv) -> emptyCtx}).unzip + NuFunDef(rec, globFuncs.get(nm).get._1, N, nTpVs, Right(PolyType(nTargs._1, nBody._1)))(N, N, N, N, true) //TODO: Use proper arguments + case _ => throw MonomorphError(s"Unimplemented liftGlobalFunc: ${func}") + }) + } private def grepFieldsInTrm(trm: Term): Option[Var] = trm match{ @@ -565,35 +624,48 @@ class ClassLifter(logDebugMsg: Boolean = false) { case _ => None } - private def mixClsInfos(clsInfos: Map[TypeName, ClassInfoCache], newClsNms: Set[Var])(using cache: ClassCache): Map[TypeName, ClassInfoCache] = { - val nameInfoMap: MutMap[TypeName, ClassInfoCache] = MutMap(clsInfos.toSeq: _*) - log(s"mix cls infos $nameInfoMap") + private def mixClsInfos(clsInfos: Map[String, ClassInfoCache], funcInfos: Map[String, LocalContext])(using cache: ClassCache): (Map[String, ClassInfoCache], Map[String, LocalContext]) = { + val nameInfoMap: MutMap[String, ClassInfoCache] = MutMap(clsInfos.toSeq: _*) + val nameFuncMap: MutMap[String, LocalContext] = MutMap(funcInfos.toSeq: _*) + log(s"mix cls infos $nameInfoMap, $nameFuncMap") // val fullMp = cache ++ nameInfoMap - val clsNmsAsTypeNm = newClsNms.map(x => TypeName(x.name)) - val len = clsInfos.size - for(_ <- 1 to len){ - val tmp = nameInfoMap.toList - tmp.foreach{case (nmOfCls, infoOfCls@ClassInfoCache(_, _, ctx, flds, inners, sups, _, _, _)) => { - val usedClsNmList = ctx.vSet.map(x => TypeName(x.name)).intersect(clsNmsAsTypeNm) - val newCtxForCls = usedClsNmList.foldLeft(ctx)((c1, c2) => c1 ++ nameInfoMap.get(c2).get.capturedParams) + val clsNmsAsTypeNm = clsInfos.keySet.map(x => TypeName(x)) + val len = clsInfos.size + nameFuncMap.size + for(_ <- 0 to len){ + nameInfoMap.toList.foreach{case (nmOfCls, infoOfCls@ClassInfoCache(_, _, ctx, flds, inners, sups, _, _, _)) => { + val usedClsNmList = ctx.vSet.map(_.name).intersect(clsInfos.keySet) + val newCtxForCls_tmp = usedClsNmList.foldLeft(ctx)((c1, c2) => c1 ++ nameInfoMap.get(c2).get.capturedParams) + + val usedFuncNmList = ctx.vSet.map(_.name).intersect(funcInfos.keySet) + val newCtxForCls = usedFuncNmList.foldLeft(newCtxForCls_tmp)((c, x) => c ++ nameFuncMap.get(x).get) + val supClsNmList = infoOfCls.supClses - val newFields = supClsNmList.foreach(c2 => flds.addAll( - nameInfoMap.get(c2).map(_.fields).getOrElse(cache.get(c2).map(_.fields).getOrElse(Nil)) + supClsNmList.foreach(c2 => flds.addAll( + nameInfoMap.get(c2.name).map(_.fields).getOrElse(cache.get(c2).map(_.fields).getOrElse(Nil)) )) - val newInners = supClsNmList.foreach(c2 => inners.addAll( - nameInfoMap.get(c2).map(_.innerClses).getOrElse(cache.get(c2).map(_.innerClses).getOrElse(Nil)) + supClsNmList.foreach(c2 => inners.addAll( + nameInfoMap.get(c2.name).map(_.innerClses).getOrElse(cache.get(c2).map(_.innerClses).getOrElse(Nil)) )) - val newCtxFromSup = supClsNmList.map(c2 => - nameInfoMap.get(c2).map(_.capturedParams).getOrElse(cache.get(c2).map(_.capturedParams).getOrElse(emptyCtx)) + val newCtxFromSup = supClsNmList.map(c2 => + nameInfoMap.get(c2.name).map(_.capturedParams).getOrElse(cache.get(c2).map(_.capturedParams).getOrElse(emptyCtx)) ).fold(emptyCtx)(_ ++ _) infoOfCls.capturedParams = newCtxForCls ++ newCtxFromSup }} + nameFuncMap.toList.foreach((nm, ctx) => { + val usedClsNmList = ctx.vSet.map(_.name).intersect(clsInfos.keySet) + val usedFuncNmList = ctx.vSet.map(_.name).intersect(funcInfos.keySet) + val nCtx = (usedClsNmList.map(x => nameInfoMap.get(x).get.capturedParams) ++ usedFuncNmList.map(x => nameFuncMap.get(x).get)).foldLeft(ctx)(_ ++ _) + nameFuncMap.update(nm, nCtx) + }) } - nameInfoMap.foreach((x1, x2) => x2.capturedParams = (x2.capturedParams extV newClsNms).extT(x2.innerClses.keySet)) - nameInfoMap.toMap + nameInfoMap.foreach((x1, x2) => x2.capturedParams = (x2.capturedParams.extV(clsInfos.keySet.map(Var(_)))).extV(funcInfos.keySet.map(Var(_))).extT(x2.innerClses.keySet)) + nameFuncMap.toList.foreach((x, c) => nameFuncMap.update(x, c.extV(clsInfos.keySet.map(Var(_))).extV(funcInfos.keySet.map(Var(_))))) + log(s"mix result: $nameInfoMap, $nameFuncMap") + nameInfoMap.toMap -> nameFuncMap.toMap } + - private def liftEntities(etts: List[Statement])(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (List[Statement], LocalContext) = { + private def liftEntities(etts: List[Statement])(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (List[Statement], LocalContext) = { log("liftEntities: " ++ etts.headOption.map(_.toString()).getOrElse("")) val (newCls, newFuncs, rstTrms) = splitEntities(etts) val newClsNms = newCls.map(x => Var(x.nme.name)).toSet @@ -601,30 +673,39 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nmsInTrm = rstTrms.flatMap(grepFieldsInTrm) val clsInfos = newCls.map(x => { val infos = collectClassInfo(x, newCls.map(_.nme).toSet)(using emptyCtx) - infos.capturedParams = infos.capturedParams.copy(vSet = infos.capturedParams.vSet.intersect(ctx.vSet ++ newClsNms ++ newFuncNms ++ nmsInTrm)) - x.nme -> infos}).toMap + infos.capturedParams = infos.capturedParams.intersect(ctx.addT(infos.capturedParams.tSet).addV(newClsNms ++ newFuncNms ++ nmsInTrm -- globFuncs.keySet ++ outer.map(_ => Var("this")))) + x.nme.name -> infos}).toMap + val funcInfos = + newFuncs.map(x => x.nme.name -> (x.rhs match { + case Left(trm) => getFreeVars(trm)(using emptyCtx) + .intersect(ctx.addV(newClsNms ++ newFuncNms ++ nmsInTrm -- globFuncs.keySet ++ outer.map(_ => Var("this")))) + .extT(x.tparams) + case _ => emptyCtx}) + ).toMap log("captured cls infos: \n" ++ clsInfos.toString()) - val refinedInfo = mixClsInfos(clsInfos, newClsNms) - val newCache = cache ++ refinedInfo - refinedInfo.foreach((_, clsi) => completeClsInfo(clsi)(using newCache)) - - newCls.foreach(x => liftTypeDefNew(x)(using newCache)) - val (liftedFuns, funVs) = newFuncs.map(liftFunc(_)(using ctx.addV(newFuncNms), newCache)).unzip - val (liftedTerms, termVs) = rstTrms.map(liftTerm(_)(using ctx.addV(newFuncNms), newCache)).unzip - (liftedFuns ++ liftedTerms, (funVs ++ termVs).fold(emptyCtx)(_ ++ _)) + log("captured func infos: \n" ++ funcInfos.toString()) + val (refinedClsInfo, refinedFuncInfo) = mixClsInfos(clsInfos, funcInfos) + val newCache = cache ++ refinedClsInfo.map(x => (TypeName(x._1) -> x._2)) + refinedClsInfo.foreach((_, clsi) => completeClsInfo(clsi)(using newCache)) + val newGlobalFuncs = refinedFuncInfo.map((nm, vs) => (Var(nm) -> (Var(genAnoName(nm)), vs))) + + newCls.foreach(x => liftTypeDef(x)(using newCache, globFuncs ++ newGlobalFuncs)) + (newFuncs zip refinedFuncInfo).foreach((f, c) => liftGlobalFunc(f)(using ctx, newCache, globFuncs ++ newGlobalFuncs)) + val (liftedTerms, termVs) = rstTrms.map(liftTerm(_)(using ctx.addV(newFuncNms), newCache, globFuncs ++ newGlobalFuncs)).unzip + (liftedTerms, (termVs).fold(emptyCtx)(_ ++ _)) } - private def completeClsInfo(clsInfo: ClassInfoCache)(using cache: ClassCache): Unit = { + private def completeClsInfo(clsInfo: ClassInfoCache)(using cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)]): Unit = { val ClassInfoCache(_, nName, freeVs, flds, inners, _, _, cls, _) = clsInfo val (clsList, _, _) = splitEntities(cls.body.entities) val innerClsNmSet = clsList.map(_.nme).toSet - val innerClsInfos = clsList.map(x => x.nme -> collectClassInfo(x, innerClsNmSet)(using asContextV(freeVs.vSet ++ flds), cache, Some(clsInfo))).toMap - val refinedInfos = mixClsInfos(innerClsInfos, innerClsNmSet.map(x => Var(x.name))) + val innerClsInfos = clsList.map(x => x.nme.name -> collectClassInfo(x, innerClsNmSet)(using asContextV(freeVs.vSet ++ flds), cache, globFuncs, Some(clsInfo))).toMap + val refinedInfos = mixClsInfos(innerClsInfos, Map())._1.map(x => (TypeName(x._1) -> x._2)) refinedInfos.foreach((_, info) => completeClsInfo(info)(using cache ++ refinedInfos)) inners.addAll(refinedInfos) } - private def liftTypeDefNew(target: NuTypeDef)(using cache: ClassCache, outer: Option[ClassInfoCache]): Unit = { + private def liftTypeDef(target: NuTypeDef)(using cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): Unit = { def getAllInners(sups: Set[TypeName]): ClassCache = { sups.flatMap( t => cache.get(t).map(x => getAllInners(x.supClses) ++ x.innerClses) @@ -644,10 +725,10 @@ class ClassLifter(logDebugMsg: Boolean = false) { outer.map(x => List(toFldsEle(Var(genParName(x.liftedNm.name))))).getOrElse(Nil) ++ params.fold(Nil)(t => t.fields) ++ freeVs.vSet.map(toFldsEle) - val nPars = pars.map(liftTerm(_)(using emptyCtx, nCache, nOuter)).unzip - val nFuncs = funcList.map(liftFunc(_)(using emptyCtx, nCache, nOuter)).unzip - val nTerms = termList.map(liftTerm(_)(using emptyCtx, nCache, nOuter)).unzip - clsList.foreach(x => liftTypeDefNew(x)(using nCache, nOuter)) + val nPars = pars.map(liftTerm(_)(using emptyCtx, nCache, globFuncs, nOuter)).unzip + val nFuncs = funcList.map(liftMemberFunc(_)(using emptyCtx, nCache, globFuncs, nOuter)).unzip + val nTerms = termList.map(liftTerm(_)(using emptyCtx, nCache, globFuncs, nOuter)).unzip + clsList.foreach(x => liftTypeDef(x)(using nCache, globFuncs, nOuter)) retSeq = retSeq.appended(NuTypeDef( kind, nName, nTps.map((None, _)), S(Tup(nParams)), None, None, nPars._1, None, None, TypingUnit(nFuncs._1 ++ nTerms._1))(None, None)) @@ -657,9 +738,10 @@ class ClassLifter(logDebugMsg: Boolean = false) { log("=========================\n") log(s"lifting: \n${showStructure(rawUnit)}\n") retSeq = Nil - val re = liftEntities(rawUnit.entities)(using emptyCtx, Map(), None) + globalFunctions.clear() + val re = liftEntities(rawUnit.entities)(using emptyCtx, Map(), Map(), None) log(s"freeVars: ${re._2}") // println(logOutput.toString()) - TypingUnit(retSeq.toList++re._1) + TypingUnit(retSeq.toList ++ globalFunctions.toList ++ re._1) } } diff --git a/compiler/shared/main/scala/mlscript/compiler/DataType.scala b/compiler/shared/main/scala/mlscript/compiler/DataType.scala new file mode 100644 index 0000000000..ca3ba27b08 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/DataType.scala @@ -0,0 +1,36 @@ +package mlscript.compiler + +abstract class DataType + +object DataType: + sealed class Singleton(value: Expr.Literal, dataType: DataType) extends DataType: + override def toString(): String = value.toString() + + enum Primitive(name: String) extends DataType: + case Integer extends Primitive("int") + case Decimal extends Primitive("real") + case Boolean extends Primitive("bool") + case String extends Primitive("str") + override def toString(): String = this.name + end Primitive + + sealed case class Tuple(elementTypes: List[DataType]) extends DataType: + override def toString(): String = elementTypes.mkString("(", ", ", ")") + + sealed case class Class(declaration: Item.TypeDecl) extends DataType: + override def toString(): String = s"class ${declaration.name.name}" + + sealed case class Function(parameterTypes: List[DataType], returnType: DataType) extends DataType: + def this(returnType: DataType, parameterTypes: DataType*) = + this(parameterTypes.toList, returnType) + override def toString(): String = + val parameterList = parameterTypes.mkString("(", ", ", ")") + s"$parameterList -> $returnType" + + sealed case class Record(fields: Map[String, DataType]) extends DataType: + def this(fields: (String, DataType)*) = this(Map.from(fields)) + override def toString(): String = + fields.iterator.map { (name, ty) => s"$name: $ty" }.mkString("{", ", ", "}") + + case object Unknown extends DataType: + override def toString(): String = "unknown" diff --git a/compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala b/compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala new file mode 100644 index 0000000000..117a8a3b75 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala @@ -0,0 +1,18 @@ +package mlscript.compiler +import mlscript.compiler.mono.MonomorphError + +trait DataTypeInferer: + import DataType._ + + def findClassByName(name: String): Option[Item.TypeDecl] + + def infer(expr: Expr, compatiableType: Option[DataType]): DataType = + expr match + case Expr.Tuple(elements) => DataType.Tuple(elements.map(infer(_, None))) + case lit @ Expr.Literal(value: BigInt) => Singleton(lit, Primitive.Integer) + case lit @ Expr.Literal(value: BigDecimal) => Singleton(lit, Primitive.Decimal) + case lit @ Expr.Literal(value: String) => Singleton(lit, Primitive.String) + case lit @ Expr.Literal(value: Boolean) => Singleton(lit, Primitive.Boolean) + case Expr.Apply(Expr.Ref(name), args) => + findClassByName(name).fold(DataType.Unknown)(DataType.Class(_)) + case _ => throw MonomorphError(s"I can't infer the type of $expr now") \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/Helpers.scala b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala new file mode 100644 index 0000000000..a49bd85bd3 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala @@ -0,0 +1,196 @@ +package mlscript.compiler + +import mlscript.{App, Asc, Assign, Bind, Blk, Bra, CaseOf, Lam, Let, Lit, + New, Rcd, Sel, Subs, Term, Test, Tup, With, Var, Fld, FldFlags, If, PolyType} +import mlscript.{IfBody, IfThen, IfElse, IfLet, IfOpApp, IfOpsApp, IfBlock} +import mlscript.UnitLit +import mlscript.codegen.Helpers.inspect as showStructure +import mlscript.compiler.mono.MonomorphError +import mlscript.NuTypeDef +import mlscript.NuFunDef +import scala.collection.mutable.ArrayBuffer +import mlscript.CaseBranches +import mlscript.Case +import mlscript.NoCases +import mlscript.Wildcard +import mlscript.DecLit +import mlscript.IntLit +import mlscript.StrLit +import mlscript.AppliedType +import mlscript.TypeName +import mlscript.TypeDefKind +import mlscript.compiler.mono.Monomorph + +object Helpers: + /** + * Extract parameters for monomorphization from a `Tup`. + */ + def toFuncParams(term: Term): Iterator[Parameter] = term match + case Tup(fields) => fields.iterator.flatMap { + // The new parser emits `Tup(_: UnitLit(true))` from `fun f() = x`. + case (_, Fld(FldFlags(_, _, _), UnitLit(true))) => None + case (None, Fld(FldFlags(_, spec, _), Var(name))) => Some((spec, Expr.Ref(name))) + case (Some(Var(name)), Fld(FldFlags(_, spec, _), _)) => Some((spec, Expr.Ref(name))) + case _ => throw new MonomorphError( + s"only `Var` can be parameters but we meet ${showStructure(term)}" + ) + } + case _ => throw MonomorphError("expect the list of parameters to be a `Tup`") + + def toFuncArgs(term: Term): IterableOnce[Term] = term match + // The new parser generates `(undefined, )` when no arguments. + // Let's do this temporary fix. + case Tup((_, Fld(FldFlags(_, _, _), UnitLit(true))) :: Nil) => Iterable.empty + case Tup(fields) => fields.iterator.map(_._2.value) + case _ => Some(term) + + def term2Expr(term: Term): Expr = { + term match + case Var(name) => Expr.Ref(name) + case Lam(lhs, rhs) => + val params = toFuncParams(lhs).toList + Expr.Lambda(params, term2Expr(rhs)) + case App(App(Var("=>"), Bra(false, args: Tup)), body) => + val params = toFuncParams(args).toList + Expr.Lambda(params, term2Expr(body)) + case App(App(Var("."), self), App(Var(method), args: Tup)) => + Expr.Apply(Expr.Select(term2Expr(self), Expr.Ref(method)), List.from(toFuncArgs(args).map(term2Expr))) + case App(lhs, rhs) => + val callee = term2Expr(lhs) + val arguments = toFuncArgs(rhs).map(term2Expr).toList + Expr.Apply(callee, arguments) + case Tup(fields) => + Expr.Tuple(fields.map { + case (_, Fld(FldFlags(mut, spec, genGetter), value)) => term2Expr(value) + }) + case Rcd(fields) => + Expr.Record(fields.map { + case (name, Fld(FldFlags(mut, spec, genGetter), value)) => (Expr.Ref(name.name), term2Expr(value)) + }) + case Sel(receiver, fieldName) => + Expr.Select(term2Expr(receiver), Expr.Ref(fieldName.name)) + case Let(rec, Var(name), rhs, body) => + val exprRhs = term2Expr(rhs) + val exprBody = term2Expr(body) + Expr.LetIn(rec, Expr.Ref(name), exprRhs, exprBody) + case Blk(stmts) => Expr.Block(stmts.flatMap[Expr | Item.FuncDecl | Item.FuncDefn] { + case term: Term => Some(term2Expr(term)) + case tyDef: NuTypeDef => throw MonomorphError(s"Unimplemented term2Expr ${term}") + case funDef: NuFunDef => + val NuFunDef(_, nme, sn, targs, rhs) = funDef + val ret: Item.FuncDecl | Item.FuncDefn = rhs match + case Left(Lam(params, body)) => + Item.FuncDecl(Expr.Ref(nme.name), toFuncParams(params).toList, term2Expr(body)) + case Left(body: Term) => Item.FuncDecl(Expr.Ref(nme.name), Nil, term2Expr(body)) + case Right(tp) => Item.FuncDefn(Expr.Ref(nme.name), targs, PolyType(Nil, tp)) //TODO: Check correctness in Type -> Polytype conversion + Some(ret) + case mlscript.DataDefn(_) => throw MonomorphError("unsupported DataDefn") + case mlscript.DatatypeDefn(_, _) => throw MonomorphError("unsupported DatatypeDefn") + case mlscript.TypeDef(_, _, _, _, _, _, _, _) => throw MonomorphError("unsupported TypeDef") + case mlscript.Def(_, _, _, _) => throw MonomorphError("unsupported Def") + case mlscript.LetS(_, _, _) => throw MonomorphError("unsupported LetS") + case mlscript.Constructor(_, _) => throw MonomorphError("unsupported Constructor") + }) + case Bra(rcd, term) => term2Expr(term) + case Asc(term, ty) => Expr.As(term2Expr(term), ty) + case _: Bind => throw MonomorphError("cannot monomorphize `Bind`") + case _: Test => throw MonomorphError("cannot monomorphize `Test`") + case With(term, Rcd(fields)) => + Expr.With(term2Expr(term), Expr.Record(fields.map { + case (name, Fld(FldFlags(mut, spec, getGetter), value)) => (Expr.Ref(name.name), term2Expr(term)) + })) + case CaseOf(term, cases) => + def rec(bra: CaseBranches)(using buffer: ArrayBuffer[CaseBranch]): Unit = bra match + case Case(pat, body, rest) => + val newCase = pat match + case Var(name) => CaseBranch.Instance(Expr.Ref(name), Expr.Ref("_"), term2Expr(body)) + case DecLit(value) => CaseBranch.Constant(Expr.Literal(value), term2Expr(body)) + case IntLit(value) => CaseBranch.Constant(Expr.Literal(value), term2Expr(body)) + case StrLit(value) => CaseBranch.Constant(Expr.Literal(value), term2Expr(body)) + case UnitLit(undefinedOrNull) => CaseBranch.Constant(Expr.Literal(UnitValue.Undefined), term2Expr(body)) + buffer.addOne(newCase) + rec(rest) + case NoCases => () + case Wildcard(body) => + buffer.addOne(CaseBranch.Wildcard(term2Expr(body))) + val branchBuffer = ArrayBuffer[CaseBranch]() + rec(cases)(using branchBuffer) + Expr.Match(term2Expr(term), branchBuffer) + + case Subs(array, index) => + Expr.Subscript(term2Expr(array), term2Expr(index)) + case Assign(lhs, rhs) => + Expr.Assign(term2Expr(lhs), term2Expr(rhs)) + case New(None, body) => + throw MonomorphError(s"Unimplemented term2Expr ${term}") + case New(Some((constructor, args)), body) => + val typeName = constructor match + case AppliedType(TypeName(name), _) => name + case TypeName(name) => name + Expr.New(TypeName(typeName), toFuncArgs(args).map(term2Expr).toList) + // case Blk(unit) => Expr.Isolated(trans2Expr(TypingUnit(unit))) + case If(body, alternate) => body match + case IfThen(condition, consequent) => + Expr.IfThenElse( + term2Expr(condition), + term2Expr(consequent), + alternate.map(term2Expr) + ) + case term: IfElse => throw MonomorphError("unsupported IfElse") + case term: IfLet => throw MonomorphError("unsupported IfLet") + case term: IfOpApp => throw MonomorphError("unsupported IfOpApp") + case term: IfOpsApp => throw MonomorphError("unsupported IfOpsApp") + case term: IfBlock => throw MonomorphError("unsupported IfBlock") + case IntLit(value) => Expr.Literal(value) + case DecLit(value) => Expr.Literal(value) + case StrLit(value) => Expr.Literal(value) + case UnitLit(undefinedOrNull) => + Expr.Literal(if undefinedOrNull + then UnitValue.Undefined + else UnitValue.Null) + case _ => throw MonomorphError("unsupported term"+ term.toString) + } + + def func2Item(funDef: NuFunDef): Item.FuncDecl | Item.FuncDefn = + val NuFunDef(_, nme, sn, targs, rhs) = funDef + rhs match + case Left(Lam(params, body)) => + Item.FuncDecl(Expr.Ref(nme.name), toFuncParams(params).toList, term2Expr(body)) + case Left(body: Term) => Item.FuncDecl(Expr.Ref(nme.name), Nil, term2Expr(body)) + case Right(tp) => Item.FuncDefn(Expr.Ref(nme.name), targs, PolyType(Nil, tp)) //TODO: Check correctness in Type -> Polytype conversion + + def type2Item(tyDef: NuTypeDef): Item.TypeDecl = + val NuTypeDef(kind, className, tparams, params, _, _, parents, _, _, body) = tyDef + val isolation = Isolation(body.entities.flatMap { + // Question: Will there be pure terms in class body? + case term: Term => + Some(term2Expr(term)) + case subTypeDef: NuTypeDef => throw MonomorphError(s"Unimplemented func2Item ${tyDef}") + case subFunDef: NuFunDef => + Some(func2Item(subFunDef)) + case term => throw MonomorphError(term.toString) + }) + val typeDecl: Item.TypeDecl = Item.TypeDecl( + Expr.Ref(className.name), // name + kind, // kind + tparams.map(_._2), // typeParams + toFuncParams(params.getOrElse(Tup(Nil))).toList, // params + parents.map { + case Var(name) => (TypeName(name), Nil) + case App(Var(name), args) => (TypeName(name), term2Expr(args) match{ + case Expr.Tuple(fields) => fields + case _ => Nil + }) + case _ => throw MonomorphError("unsupported parent term") + }, // parents + isolation // body + ) + typeDecl + + private given Conversion[TypeDefKind, TypeDeclKind] with + import mlscript.{Als, Cls, Trt} + def apply(kind: TypeDefKind): TypeDeclKind = kind match + case Als => TypeDeclKind.Alias + case Cls => TypeDeclKind.Class + case Trt => TypeDeclKind.Trait + case _ => throw MonomorphError(s"Unsupported TypeDefKind conversion ${kind}") diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala b/compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala new file mode 100644 index 0000000000..fde9c93ede --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala @@ -0,0 +1,334 @@ +package mlscript.compiler.mono + +import mlscript.compiler.debug.{Debug, DummyDebug} +import mlscript.{TypingUnit, NuTypeDef, NuFunDef} +import mlscript.{AppliedType, TypeName} +import mlscript.{App, Asc, Assign, Bind, Blk, Bra, CaseOf, Lam, Let, Lit, + New, Rcd, Sel, Subs, Term, Test, Tup, With, Var, Fld, If} +import mlscript.{IfThen, IfElse, IfLet, IfOpApp, IfOpsApp, IfBlock} +import mlscript.{IntLit, DecLit, StrLit, UnitLit} +import scala.collection.immutable.{HashMap} +import scala.collection.mutable.{Map as MutMap, Set as MutSet} +import scala.collection.mutable.ListBuffer +import mlscript.Cls +import mlscript.CaseBranches +import mlscript.TypeDefKind +import mlscript.AppliedType.apply +import mlscript.compiler.mono.specializer.Builtin +import mlscript.compiler.mono.specializer.Context +import mlscript.compiler.* + +import mlscript.compiler.printer.ExprPrinter +import mlscript.compiler.mono.specializer.BoundedExpr +import mlscript.compiler.mono.specializer.{MonoValue, ObjectValue, UnknownValue, FunctionValue, VariableValue} + +class Monomorph(debug: Debug = DummyDebug) extends DataTypeInferer: + import Helpers._ + import Monomorph._ + + /** + * Specialized implementations of function declarations. + */ + private val funImpls = MutMap[String, (Item.FuncDecl, MutMap[String, Item.FuncDecl], List[BoundedExpr], VariableValue)]() + + private def getfunInfo(nm: String): String = + val info = funImpls.get(nm).get + s"$nm: (${info._3.mkString(" X ")}) -> ${info._4} @${funDependence.get(nm).get.mkString("{", ", ", "}")}" + + private val funDependence = MutMap[String, Set[String]]() + + val evalQueue = MutSet[String]() + val evalCnt = MutMap[String, Int]() + + /** + * Specialized implementations of each type declarations. + */ + private val tyImpls = MutMap[String, SpecializationMap[Item.TypeDecl]]() + private val allTypeImpls = MutMap[String, Item.TypeDecl]() + /** + * Add a prototype type declaration. + */ + private def addPrototypeTypeDecl(typeDecl: Item.TypeDecl) = + tyImpls.addOne(typeDecl.name.name, SpecializationMap(typeDecl)) + allTypeImpls.addOne(typeDecl.name.name, typeDecl) + /** + * An iterator going through all type declarations. + */ + private def allTypeDecls: IterableOnce[Item.TypeDecl] = + tyImpls.values.flatMap { _.iterator } + + /** + * A global store of monomorphized lambda classes. + */ + private val lamTyDefs = MutMap[String, Item.TypeDecl]() + /** + * A global store of anonymous classes. For example, `new { ... }`. + */ + private val anonymTyDefs = MutMap[String, Item.TypeDecl]() + + def findClassByName(name: String): Option[mlscript.compiler.Item.TypeDecl] = + allTypeImpls.get(name) + + val specializer = mono.specializer.Specializer(this)(using debug) + + private def addNewFunction(func: Item.FuncDecl): Unit = { + funImpls.addOne(func.name.name, (func, MutMap(), func.params.map(_ => BoundedExpr()), VariableValue.refresh())) + funDependence.addOne(func.name.name, Set()) + } + + private def getResult(exps: List[Expr]) = mlscript.compiler.ModuleUnit(exps.concat[Expr | Item](funImpls.map(x => x._2._1)) + .concat(allTypeImpls.values.map(x => x.copy(body = Isolation(Nil)))) + .concat(lamTyDefs.values) + .concat(anonymTyDefs.values) + .toList) + + /** + * This function defunctionalizes the top-level `TypingUnit` into a `Module`. + */ + def defunctionalize(tu: TypingUnit): ModuleUnit = + // debug.trace("MONO MODL", PrettyPrinter.show(tu)) { + val exps = tu.entities.zipWithIndex.flatMap[Expr] { + case (term: Term, i) => + val exp = term2Expr(term) + val funcName = s"main$$$$$i" + val asFunc: Item.FuncDecl = Item.FuncDecl(Expr.Ref(funcName), Nil, exp) + addNewFunction(asFunc) + evalQueue.addOne(funcName) + Some(Expr.Apply(Expr.Ref(funcName), Nil)) + case (tyDef: NuTypeDef, _) => + val ret = type2Item(tyDef) + addPrototypeTypeDecl(ret) + None + case (funDef: NuFunDef, _) => + val funcItem = func2Item(funDef) + funcItem match + case funcDecl: Item.FuncDecl => + addNewFunction(funcDecl) + case _ => () + None + case (other, _) => throw MonomorphError(s"Unknown Statement in TypingUnit: ${other}") + }; + debug.log(getResult(exps).getDebugOutput.toLines(using false).mkString("\n")) + while(!evalQueue.isEmpty){ + val crt = evalQueue.head + evalQueue.remove(crt) + updateFunction(crt) + } + funImpls.mapValuesInPlace{ + case (_, (Item.FuncDecl(nm, as, body), mp, la, lr)) => + (Item.FuncDecl(nm, as, specializer.defunctionalize(body)), mp, la, lr) + } + val ret = getResult(exps) + debug.log("") + debug.log("==============final function signatures==================") + funImpls.foreach( + (nm, info) => { + debug.log(s"$nm: (${info._3.mkString(" X ")}) -> ${info._4}") + } + ) + + ret + // }() + + private def updateFunction(crt: String): Unit = { + debug.log(s"evaluating $crt, rests: ${evalQueue}") + val cnt = evalCnt.get(crt).getOrElse(0) + if(cnt <= 10){ + evalCnt.update(crt, cnt+1) + debug.log("=" * 10 + s" updating $crt " + "=" * 10) + debug.log(getfunInfo(crt)) + updateFunc(crt) + debug.log(getfunInfo(crt)) + } + else{ + throw new MonomorphError("stack overflow!!!") + } + } + + /** + * This function monomorphizes the nested `TypingUnit` into a `Isolation`. + */ + private def trans2Expr(body: TypingUnit): Isolation = + debug.trace("MONO BODY", PrettyPrinter.show(body)) { + Isolation(body.entities.flatMap[Expr | Item.FuncDecl | Item.FuncDefn] { + case term: Term => + Some(term2Expr(term)) + case tyDef: NuTypeDef => + val ret = type2Item(tyDef) + addPrototypeTypeDecl(ret) + None + case funDef: NuFunDef => + Some(func2Item(funDef)) + case other => throw MonomorphError(s"Unknown Statement in TypingUnit: ${other}") + }) + }(identity) + + def getFuncRetVal(name: String, args: List[BoundedExpr])(using evalCtx: Context, callingStack: List[String]): BoundedExpr = { + debug.trace[BoundedExpr]("SPEC CALL", name + args.mkString(" with (", ", ", ")")) { + if(funImpls.contains(name)){ + val (funcdecl, mps, oldArgs, oldVs) = funImpls.get(name).get + val old = funDependence.get(name).get + funDependence.update(name, old ++ callingStack.headOption) + // debug.log(s"adding dependence ${callingStack.headOption}") + val nArgs = (oldArgs zip (args.map(_.unfoldVars))).map(_ ++ _).zip(funcdecl.params).map( + (x,y) => if(y._1) then x else x.literals2Prims + ) + + debug.log(s"comparing ${oldArgs.mkString("(", ", ", ")")} with ${nArgs.map(_.getDebugOutput).mkString("(", ", ", ")")}") + if(evalCnt.get(name).isEmpty || (oldArgs zip nArgs).find(x => x._1.compare(x._2)).isDefined){ + funImpls.update(name, (funcdecl, mps, nArgs, oldVs)) + if(!evalQueue.contains(name)){ + if(evalCnt.get(name).isEmpty){ + debug.log(s"first time encounter $name") + updateFunction(name) + } + else{ + debug.log(s"find finer args") + evalQueue.add(name) + } + } + } + BoundedExpr(funImpls.get(name).get._4) + } + else { + debug.log(s"calling unknown function $name(${args.mkString(",")})") + debug.log(funImpls.keySet.toString()) + BoundedExpr(UnknownValue()) + } + }(identity) + } + + private def updateFunc(name: String): Unit = { + val (funcdecl, mps, args, _) = funImpls.get(name).get + val ctx = (funcdecl.params.map(_._2.name) zip args).toMap + val nBody = specializer.evaluate(funcdecl.body)(using Context()++ctx, List(funcdecl.name.name)) + val nVs = nBody.expValue + val oldVs = VariableValue.get(funImpls.get(name).get._4) + debug.log(s"comparing ${oldVs} with ${nVs}") + if(oldVs.compare(nVs)){ + debug.log(s"adding these funcs to queue: ${funDependence.get(name).get}") + funDependence.get(name).get.foreach(x => if !evalQueue.contains(x) then evalQueue.add(x)) + } + funImpls.updateWith(name)(_.map(x => { + val nFuncDecl: Item.FuncDecl = x._1.copy(body = nBody) + VariableValue.update(x._4, nVs) + (nFuncDecl, x._2, x._3, x._4) + })) + } + + def findVar(name: String)(using evalCtx: Context, callingStack: List[String]): MonoValue = { + if(funImpls.contains(name)){ + val funcBody = funImpls.get(name).get + funDependence.update(name, funDependence.get(name).get ++ callingStack.headOption) + FunctionValue(name, funcBody._1.params.map(_._2.name), Nil) + } + else{ + UnknownValue() + } + } + + private def partitationArguments(name: String, params: List[Parameter], args: List[Expr]): (List[Expr], List[Expr]) = + if (args.length != params.length) { + debug.log("") + throw MonomorphError(s"$name expect ${params.length} arguments but ${args.length} were given") + } + val staticArguments = params.iterator.zip(args).flatMap({ + case ((true, _), value) => Some(value) + case _ => None + }).toList + val dynamicArguments = params.iterator.zip(args).flatMap({ + case ((false, _), value) => Some(value) + case _ => None + }).toList + (staticArguments, dynamicArguments) + + private def generateSignature(staticArguments: List[Expr])(using MonomorphContext): String = + staticArguments.iterator.map(infer(_, None)).mkString("__", "_", "") + + private def specializeClassCall(name: String, args: List[Expr])(using MonomorphContext): Option[Expr] = + debug.trace("SPEC CALL", "class " + name + args.mkString(" with (", ", ", ")")) { + ??? + }(_.fold(Debug.noPostTrace)(identity)) + + def createObjValue(tpName: String, args: List[BoundedExpr]): MonoValue = + debug.trace("SPEC NEW", s"$tpName($args)"){ + if(allTypeImpls.contains(tpName)){ + val tp = allTypeImpls.get(tpName).get + val ags = (tp.params.map(_._2.name) zip args) + val ret = ObjectValue(tpName, MutMap(ags: _*)) + val pars = tp.parents.map((supTp, prms) => { + val evArgs = prms.map(specializer.evaluate(_)(using Context() ++ (("this"->BoundedExpr(ret)) :: ags), List(tpName)).expValue) + BoundedExpr(createObjValue(supTp.base.name, evArgs)) + }) + val parObjs = pars.zipWithIndex.map((e, i) => s"sup$$$i" -> e) + debug.log(s"par objs: $parObjs") + ret.fields.addAll(parObjs) + ret + } + else throw MonomorphError(s"tpName ${tpName} not found in implementations ${allTypeImpls}") + }(identity) + + def getFieldVal(obj: ObjectValue, field: String): BoundedExpr = + debug.trace("SPEC SEL", s"$obj :: $field"){ + if(allTypeImpls.contains(obj.name)){ + val tpDef = allTypeImpls.get(obj.name).get + val func = tpDef.body.items.flatMap{ + case funcDecl@Item.FuncDecl(Expr.Ref(nm), prms, bd) if nm.equals(field) => + Some(funcDecl) + case _ => None + }.headOption + if(func.isDefined){ + debug.log("defined") + val Item.FuncDecl(nm, prms, bd) = func.get + val nFuncName = s"${nm.name}$$${obj.name}" + if(!funImpls.contains(nFuncName)){ + val nFunc: Item.FuncDecl = Item.FuncDecl(Expr.Ref(nFuncName), (false, Expr.Ref("this")) :: prms, bd) + addNewFunction(nFunc) + } + BoundedExpr(FunctionValue(nFuncName, prms.map(_._2.name), List("this" -> BoundedExpr(obj)))) + } + else if(obj.fields.contains(field)) + debug.log("contains") + obj.fields.get(field).get + else{ + debug.log("else") + obj.fields.flatMap(x => { + if (x._1.matches("sup\\$[0-9]+")) { + x._2.asValue match{ + case Some(o: ObjectValue) => + Some(getFieldVal(o, field)) + case _ => None + } + } + else None + }).headOption.getOrElse( + throw MonomorphError(s"Field ${field} not Found in"+obj.toString()) + ) + } + } + else { + throw MonomorphError(s"ObjectValue ${obj} not found in implementations ${allTypeImpls}") + } + }(identity) + +object Monomorph: + class SpecializationMap[T <: Item](val prototype: T): + private var basePrototype: Option[T] = None + private val implementations = MutMap[String, T]() + + inline def getOrInsert(signature: String, op: => T): T = + implementations.getOrElseUpdate(signature, op) + inline def size: Int = implementations.size + // signature + item + inline def +=(entry: (String, T)): T = + implementations.addOne(entry) + entry._2 + inline def base: Option[T] = basePrototype + inline def base_=(op: => T): Unit = + basePrototype match + case None => basePrototype = Some(op) + case Some(_) => () + inline def isEmpty: Boolean = implementations.isEmpty + inline def iterator: Iterator[T] = + if implementations.isEmpty then Iterator.empty else + basePrototype.iterator.concat(implementations.values) \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala new file mode 100644 index 0000000000..b3eef13425 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala @@ -0,0 +1,33 @@ +package mlscript.compiler.mono + +import mlscript.compiler.debug.DebugOutput +import scala.collection.immutable.SeqMap +import mlscript.compiler.debug.Printable +import mlscript.compiler.* + +class MonomorphContext(context: List[Map[String, DataType]]) extends Printable: + def +(entry: (String, DataType)): MonomorphContext = + MonomorphContext(context match { + case Nil => Nil + case head :: tail => (head + entry) :: tail + }) + + def :+(entry: (String, DataType)): MonomorphContext = + MonomorphContext((Map.empty + entry) :: context) + + def unary_+ : MonomorphContext = + MonomorphContext(Map.empty :: context) + + def get(key: String): Option[DataType] = + context.iterator.flatMap(_.get(key)).nextOption() + + def getDebugOutput: DebugOutput = + DebugOutput.Map(context.foldRight(SeqMap.empty[String, String]) { (entries, map) => + entries.foldLeft(map) { (map, entry) => + map + (entry._1 -> entry._2.toString) + } + }.toList) + + +object MonomorphContext: + def empty: MonomorphContext = MonomorphContext(Nil) \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala new file mode 100644 index 0000000000..e7ef0305e5 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala @@ -0,0 +1,3 @@ +package mlscript.compiler.mono + +class MonomorphError(message: String) extends Error(message) diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala new file mode 100644 index 0000000000..fc60c04dae --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala @@ -0,0 +1,226 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.{Expr, UnitValue} +import mlscript.compiler.debug.Printable +import mlscript.compiler.debug.DebugOutput +import scala.collection.mutable.Map as MutMap +import scala.collection.mutable.Set as MutSet +import mlscript.Var +import scala.collection.immutable +import mlscript.compiler.mono.MonomorphError + +abstract class MonoValue { + def toBoundedExpr = BoundedExpr(this) + def toStringSafe(using Set[Int]) = this.toString() +} +case class ObjectValue(name: String, fields: MutMap[String, BoundedExpr]) extends MonoValue{ + override def toString(): String = fields.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(s"$name@{", ", ", "}") + override def toStringSafe(using Set[Int]): String = fields.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(s"$name@{", ", ", "}") + def merge(other: ObjectValue)(using inStackExps: Set[Int]): ObjectValue = { + val allKeys = fields.keySet + val nFlds = allKeys.map(k => { + val s1 = fields.get(k).get + val s2 = other.fields.get(k).get + if(inStackExps.contains(s1.hashCode()) && inStackExps.contains(s2.hashCode())) + (k -> s1) + else (k -> (s1 ++ s2)) + }) + ObjectValue(name, MutMap(nFlds.toSeq: _*)) + } + override def equals(x: Any): Boolean = { + x match { + case ObjectValue(xName, _) => name.equals(xName) + case _ => false + } + } +} +case class FunctionValue(name: String, prm: List[String], ctx: List[(String, BoundedExpr)]) extends MonoValue{ + override def toString(): String = prm.mkString(s"$name(", ", ", ")") + ctx.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(" given {", ", ", "}") + override def toStringSafe(using Set[Int]): String = prm.mkString(s"$name(", ", ", ")") + ctx.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(" given {", ", ", "}") + override def equals(x: Any): Boolean = x match{ + case FunctionValue(xName, _, _) => name.equals(xName) + case _ => false + } +} +case class UnknownValue() extends MonoValue{ + val idValue = UnknownValue.refresh() + override def toString(): String = s"?$idValue?" +} +object UnknownValue{ + var unknownCnt: Int = 0 + def refresh() = { + unknownCnt += 1 + unknownCnt + } +} +case class VariableValue(vx: Int, version: Int) extends MonoValue{ + override def toStringSafe(using Set[Int]): String = s"*$vx*=${VariableValue.get(this).toStringSafe}" + override def toString(): String = toStringSafe(using Set()) + def refresh() = VariableValue(vx, version+1) +} +object VariableValue{ + var vxCnt = 0 + val vMap = MutMap[Int, BoundedExpr]() + def refresh(): VariableValue = { + vxCnt += 1 + val ret = VariableValue(vxCnt, 0) + vMap.addOne(vxCnt -> BoundedExpr(ret)) + ret + } + def get(v: VariableValue): BoundedExpr = vMap.get(v.vx).get + def update(v: VariableValue, s: BoundedExpr): Unit = { + vMap.update(v.vx, s) + } +} + +case class LiteralValue(i: BigInt | BigDecimal | Boolean | String | UnitValue) extends MonoValue{ + def asBoolean(): Option[Boolean] = i match{ + case x: Boolean => Some(x) + case _ => None + } + override def toString(): String = i.toString() +} +case class PrimitiveValue() extends MonoValue{ + override def toString(): String = "*LIT*" +} + +class BoundedExpr(private val values: Set[MonoValue]) extends Printable { + def this(singleVal: MonoValue) = this(Set(singleVal)) + def this() = this(Set()) + def getDebugOutput: DebugOutput = DebugOutput.Plain(toStringSafe) + def getObjNames() = values.flatMap{ + // case FunctionValue(name, body, prm, ctx) => Some(name) + case ObjectValue(name, _) => Some(name) + case _ => None + }.toSet + // override def hashCode(): Int = values.hashCode() + override def toString(): String = toStringSafe + var updateCnt: Int = 0 + def toStringSafe(using printed: Set[Int] = Set()): String = { + if(printed.contains(this.hashCode())) s"..." + else values.map(_.toStringSafe(using printed + this.hashCode())).mkString("[", " | ", s"]") + } + def asValue: Option[MonoValue] = { + val tmp = this.unfoldVars + if(tmp.values.size == 1) { + Some(tmp.values.head) + } + else None + } + def getValue: Set[MonoValue] = { + unfoldVars.values.toSet.filterNot(_.isInstanceOf[VariableValue]) + } + + private def splitSpecifiedObjects(vs: Set[MonoValue], nms: Set[String]): (Set[MonoValue], Map[String, ObjectValue]) = { + val ret = vs.map{ + case o@ObjectValue(name, fields) => + if nms.contains(name) then { + (None, Some(name -> o)) + } else { + (Some(o), None) + } + case x => (Some(x), None) + }.unzip + val ret1 = ret._1.flatten + val ret2 = ret._2.flatten.toMap + (ret1, ret2) + } + + def unfoldVars(using instackExps: Set[Int] = Set()): BoundedExpr = { + val vars = values.toList.map{ + case vx: VariableValue => (Some(vx), None) + case others => (None, Some(others)) + }.unzip + val varSets: List[BoundedExpr] = vars._1.flatten.map(x => { + val vSet = VariableValue.get(x) + if(!instackExps.contains(vSet.hashCode())){ + vSet.unfoldVars(using instackExps + vSet.hashCode()) + } + else BoundedExpr(x) + }) + varSets.foldLeft(BoundedExpr(vars._2.flatten.toSet))((x, y) => (x ++ y)(using instackExps + y.hashCode())) + } + + def literals2Prims: BoundedExpr = { + val hasPrim = values.find(x => x.isInstanceOf[PrimitiveValue] || x.isInstanceOf[LiteralValue]).isDefined + if(hasPrim) + BoundedExpr(values.filterNot(x => x.isInstanceOf[PrimitiveValue] || x.isInstanceOf[LiteralValue]) + PrimitiveValue()) + else this + } + + def ++(other: BoundedExpr)(using instackExps: Set[Int] = Set()): BoundedExpr = { + if(this == other) this + else { + // unfoldVars + // other.unfoldVars + val mergingValNms = getObjNames().intersect(other.getObjNames()) + val (restVals1, mergingVals1) = splitSpecifiedObjects(values.toSet, mergingValNms) + val (restVals2, mergingVals2) = splitSpecifiedObjects(other.values.toSet, mergingValNms) + // val map2 = other.values.flatMap(x => if(values.fin(x)) then None else Some(x)) + val ret = mergingValNms.map(nm => (mergingVals1.get(nm), mergingVals2.get(nm)) match + case (Some(x1: ObjectValue), Some(x2: ObjectValue)) => x1.merge(x2)(using instackExps ++ Set(this.hashCode(), other.hashCode())) + case _ => throw MonomorphError(s"Name ${nm} not found in BoundedExpr merging") + ) + // println(s"get ${BoundedExpr(restVals1 ++ restVals2 ++ ret)}") + var ret2 = restVals1 ++ restVals2 + if(ret2.count(x => (x.isInstanceOf[LiteralValue] || x.isInstanceOf[PrimitiveValue])) > 1){ + ret2 = ret2.filterNot(_.isInstanceOf[LiteralValue]) + PrimitiveValue() + } + val retVals = BoundedExpr(ret2 ++ ret) + retVals.updateCnt = this.updateCnt + if(this.compare(retVals)) retVals.updateCnt += 1 + retVals + } + } + + def size = values.size + // lazy val eleCnt: Int = countEles + def eleCnt(using instackExps: Set[Int] = Set()): Int = { + if(values.size == 0) { + 0 + } + else { + val seperated = values.map{ + case o: ObjectValue => (None, Some(o)) + case f: FunctionValue => (Some(1), None) + case _: LiteralValue => (Some(1), None) + case _: PrimitiveValue => (Some(100000), None) + case UnknownValue() => (Some(1), None) + case vx: VariableValue => (Some(VariableValue.get(vx).eleCnt(using instackExps + VariableValue.get(vx).hashCode())), None) + }.unzip + val (lits, objs) = (seperated._1.flatten, seperated._2.flatten) + val objn = objs.map{ + case ObjectValue(name, fields) => + fields.map(x => { + if(instackExps.contains(x._2.hashCode())) 1 + else x._2.eleCnt(using instackExps + x._2.hashCode()) + }).fold(0)(_ + _) + 1 + }.fold(0)(_ + _) + lits.fold(0)(_ + _) + objn + } + } + def compare(other: BoundedExpr)(using instackExps: Set[Int] = Set()): Boolean = { + if(instackExps.contains(this.hashCode()) && instackExps.contains(other.hashCode())) + false + else { + if(values.find(_.isInstanceOf[PrimitiveValue]).isEmpty && other.values.find(_.isInstanceOf[PrimitiveValue]).isDefined) + true + else if(this.size != other.size) + this.size < other.size + else{ + val nms1 = this.getObjNames() + val nms2 = other.getObjNames() + if(nms1.equals(nms2)){ + val (rests1, objs1) = splitSpecifiedObjects(this.values.toSet, nms1) + val (rests2, objs2) = splitSpecifiedObjects(other.values.toSet, nms1) + nms1.find(nm => { + val v1s = objs1.get(nm).get.fields + val v2s = objs2.get(nm).get.fields + v1s.keySet.find(k => v1s.get(k).get.compare(v2s.get(k).get)(using instackExps + this.hashCode() + other.hashCode())).isDefined + }).isDefined + } + else true + } + } + } +} \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala new file mode 100644 index 0000000000..a1a7b12c13 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala @@ -0,0 +1,95 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.Expr +import mlscript.compiler.mono.MonomorphError + +object Builtin: + val builtinRefs = Set(">", "-", "+", "*", "&&", "||", "==", "true", "false") + + private val builtinBinaryOperations = Map[String, (Expr, Expr) => Option[Expr]]( + (">", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs > rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs > rhs)) + case (_, _) => None + }), + ("-", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs - rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs - rhs)) + case (_, _) => None + }), + ("+", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs + rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs + rhs)) + case (_, _) => None + }), + ("*", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs * rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs * rhs)) + case (_, _) => None + }) + ) + + private val builtinBinaryOperationsValue = Map[String, (MonoValue, MonoValue) => Option[MonoValue]]( + (">", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs > rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs > rhs)) + case (_, _) => None + }), + ("-", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs - rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs - rhs)) + case (_, _) => None + }), + ("+", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs + rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs + rhs)) + case (_, _) => None + }), + ("*", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs * rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs * rhs)) + case (_, _) => None + }), + ("&&", { + case (LiteralValue(lhs: Boolean), LiteralValue(rhs: Boolean)) => + Some(LiteralValue(lhs && rhs)) + case (_, _) => None + }), + ("||", { + case (LiteralValue(lhs: Boolean), LiteralValue(rhs: Boolean)) => + Some(LiteralValue(lhs || rhs)) + case (_, _) => None + }), + ("==", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs == rhs)) + case (LiteralValue(lhs: Boolean), LiteralValue(rhs: Boolean)) => + Some(LiteralValue(lhs == rhs)) + case (_, _) => None + }) + ) + + def isBinaryOperator(name: String): Boolean = + builtinBinaryOperations.contains(name) + + def evalulateBinaryOperation(name: String, lhs: Expr, rhs: Expr): Option[Expr] = + builtinBinaryOperations(name)(lhs, rhs) + + def evaluateBinaryOpValue(name: String, lhs: MonoValue, rhs: MonoValue): Option[MonoValue] = + builtinBinaryOperationsValue(name)(lhs, rhs) diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala new file mode 100644 index 0000000000..bd1d8faecb --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala @@ -0,0 +1,21 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.Expr +import mlscript.compiler.debug.{DebugOutput, Printable} +import mlscript.compiler.mono.specializer.BoundedExpr + +class Context(private val entries: Map[String, BoundedExpr]) extends Printable: + def this() = this(Map("true" -> BoundedExpr(LiteralValue(true)), "false" -> BoundedExpr(LiteralValue(false)))) + inline def get(name: String): BoundedExpr = entries.get(name).getOrElse(BoundedExpr(UnknownValue())) + inline def +(entry: (String, BoundedExpr)): Context = Context(entries + entry) + inline def ++(other: Context): Context = Context(entries ++ other.entries) + inline def ++(other: IterableOnce[(String, BoundedExpr)]) = Context(entries ++ other) + inline def isEmpty: Boolean = entries.isEmpty + inline def contains(name: String): Boolean = entries.contains(name) + def getDebugOutput: DebugOutput = + DebugOutput.Map(entries.iterator.map { + (key, value) => (key, value.toString) + }.toList) +object Context{ + def toCtx(entries: IterableOnce[(String, BoundedExpr)]) = Context(Map.from(entries)) +} \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala new file mode 100644 index 0000000000..80a75fa1a3 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala @@ -0,0 +1,6 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.Expr + +object Predicates: + \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala new file mode 100644 index 0000000000..6a8adea774 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala @@ -0,0 +1,228 @@ +package mlscript.compiler.mono.specializer + +import scala.collection.mutable.ArrayBuffer +import scala.collection.mutable.Map as MutMap +import mlscript.compiler.debug.Debug +import mlscript.compiler.mono.MonomorphError +import mlscript.compiler.mono.Monomorph +import mlscript.compiler.UnitValue +import mlscript.TypeName +import mlscript.compiler.Item +import mlscript.compiler.CaseBranch +import mlscript.compiler.Expr + +class Specializer(monoer: Monomorph)(using debug: Debug){ + + def evaluate(rawExpr: Expr)(using evalCtx: Context, callingStack: List[String]): Expr = + // debug.trace[Expr]("EVAL ", rawExpr.toString()) { + rawExpr match{ + case Expr.Ref(name) => + rawExpr.expValue = + if evalCtx.contains(name) then evalCtx.get(name) else BoundedExpr(monoer.findVar(name)) + rawExpr + case Expr.Apply(Expr.Apply(opE@Expr.Ref(op), a1), a2) if Builtin.isBinaryOperator(op) => + if(a1.length == 1 && a2.length == 1) + { + val a1E = evaluate(a1.head) + val a2E = evaluate(a2.head) + val pairedAV = (a1E.expValue.asValue, a2E.expValue.asValue) match { + case (Some(i1: LiteralValue), Some(i2: LiteralValue)) => + Builtin.evaluateBinaryOpValue(op, i1, i2) match{ + case Some(value) => value + case None => PrimitiveValue() + } + case _ => PrimitiveValue() + } + val retExp = Expr.Apply(Expr.Apply(opE, List(a1E)), List(a2E)) + retExp.expValue = BoundedExpr(pairedAV) + retExp + } + else throw MonomorphError(s"Malformed Expr: ${rawExpr}") + + case other@Expr.Apply(callee, arguments) => + val calE = evaluate(callee) + val cal = calE.expValue + val nArgs = arguments.map(evaluate) + val args = nArgs.map(_.expValue) + val retV = cal.getValue.map{ + case FunctionValue(name, prm, ctxArg) => + val callResult = monoer.getFuncRetVal(name, ctxArg.unzip._2 ++ args) + // debug.log(s"call result: $callResult") + callResult + case o: ObjectValue => + val sel = monoer.getFieldVal(o, "apply") + sel.asValue match + case Some(FunctionValue(name, prm, ctx)) => + val callResult = monoer.getFuncRetVal(name, ctx.unzip._2 ++ args) + // debug.log(s"call result: $callResult") + callResult + case _ => BoundedExpr(UnknownValue()) + case _ => BoundedExpr(UnknownValue()) + }.fold(BoundedExpr())((x, y) => { + // debug.log(s"merging $x with $y") + val xy = x ++ y + // debug.log(s"result $xy") + xy + }) + val retExp = Expr.Apply(calE, nArgs) + retExp.expValue = retV + retExp + + case Expr.Select(receiver, field) => + val rec = evaluate(receiver) + val retV = rec.expValue.getValue.map{ + case ObjectValue(_, flds) if flds.contains(field.name) => + flds.get(field.name).get + case obj: ObjectValue => + monoer.getFieldVal(obj, field.name) + case _ => + BoundedExpr(UnknownValue()) + }.fold(BoundedExpr())(_ ++ _) + val retExp = Expr.Select(rec, field) + retExp.expValue = retV + retExp + + case Expr.LetIn(false, name, rhs, body) => + val nRhs = evaluate(rhs) + val nCtx = evalCtx + (name.name -> nRhs.expValue) + val nBody = evaluate(body)(using nCtx) + val retExp = Expr.LetIn(false, name, nRhs, nBody) + retExp.expValue = body.expValue + retExp + + case l@Expr.Literal(value) => + l.expValue = BoundedExpr(LiteralValue(value)) + l + + case Expr.New(apply, arguments) => + val nArgs = arguments.map(evaluate(_)) + val args = nArgs.map(_.expValue) + val retV = BoundedExpr(monoer.createObjValue(apply.name, args)) + val retExp = Expr.New(apply, nArgs) + retExp.expValue = retV + retExp + + case Expr.IfThenElse(condition, consequent, Some(alternate)) => + val nCond = evaluate(condition) + val nCons = evaluate(consequent) + val nAlter = evaluate(alternate) + val retV = nCond.expValue.asValue match { + case Some(x: LiteralValue) if x.asBoolean().isDefined => + if(x.asBoolean().get){ + nCons.expValue + } + else { + nAlter.expValue + } + case _ => + nCons.expValue ++ nAlter.expValue + } + val retExp = Expr.IfThenElse(nCond, nCons, Some(nAlter)) + retExp.expValue = retV + retExp + case Expr.IfThenElse(condition, consequent, None) => + val nCond = evaluate(condition) + val nCons = evaluate(consequent) + val retExp = Expr.IfThenElse(nCond, nCons, None) + retExp.expValue = BoundedExpr(LiteralValue(UnitValue.Undefined)) + retExp + + case self@Expr.Lambda(prm, body) => + throw MonomorphError(s"Unhandled case: ${rawExpr}") + + case Expr.Isolated(isolation) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + + case Expr.Tuple(fields) => + if(fields.length == 1){ + evaluate(fields.head) + } + else + throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Record(fields) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.LetIn(true, name, rhs, body) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Block(items) => + val exps = items.flatMap{ + case e: Expr => Some(evaluate(e)) + case _ => None + } + if(exps.length == 0){ + val retE = Expr.Literal(UnitValue.Undefined) + val retV = BoundedExpr(LiteralValue(UnitValue.Undefined)) + retE.expValue = retV + retE + } + else if(exps.length == 1){ + exps.head + } + else { + val retV = exps.reverse.head.expValue + val retE = Expr.Block(exps) + retE.expValue = retV + retE + } + + case Expr.As(value, toType) => + val retV = evaluate(value) + rawExpr.expValue = retV.expValue + rawExpr + case Expr.Assign(assignee, value) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.With(value, fields) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Subscript(receiver, index) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Match(scrutinee, branches) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + } + // }(_.expValue) + + def defunctionalize(rawExpr: Expr): Expr = { + val ret: Expr = rawExpr match { + case _: (Expr.Ref | Expr.Literal) => rawExpr + case Expr.Apply(sel@Expr.Select(receiver, field), args) => + val nRec = defunctionalize(receiver) + val nArgs = args.map(defunctionalize) + val branches = ArrayBuffer[CaseBranch]() + receiver.expValue.getValue.foreach{ + case o@ObjectValue(name, _) => + val selValue = monoer.getFieldVal(o, field.name) + val branchExp = selValue.asValue match{ + // foo.f is a member function + case Some(f: FunctionValue) => + Expr.Apply(Expr.Ref(f.name), Expr.Ref("obj") :: nArgs) + // foo.f is (many candidate) lambda(Object) + case _ if selValue.getValue.forall(_.isInstanceOf[ObjectValue]) => + // foo.f match ... + val scrut = Expr.Select(Expr.Ref("obj"), field) + val brchs = selValue.getValue.toList.map(_.asInstanceOf[ObjectValue]) + .map(o => { + val lambdaMemFunc = monoer.getFieldVal(o, "apply").asValue.get.asInstanceOf[FunctionValue] + val caseVarNm: Expr.Ref = Expr.Ref(s"obj$$${o.name}") + CaseBranch.Instance(Expr.Ref(o.name), caseVarNm, + Expr.Apply(Expr.Ref(lambdaMemFunc.name), caseVarNm :: nArgs)) + }) + Expr.Match(scrut, ArrayBuffer(brchs: _*)) + case _ => throw MonomorphError(s"Unhandled case: ${rawExpr}") + + } + branches.addOne(CaseBranch.Instance(Expr.Ref(name), Expr.Ref("obj"), branchExp)) + case _ => () + } + Expr.Match(nRec, branches) + case Expr.Apply(callee, arguments) => + if(callee.expValue.getValue.find(_.isInstanceOf[ObjectValue]).isDefined) + defunctionalize(Expr.Apply(Expr.Select(callee, Expr.Ref("apply")), arguments)) + else + Expr.Apply(defunctionalize(callee), arguments.map(defunctionalize)) + case Expr.New(typeName, args) => Expr.New(typeName, args.map(defunctionalize)) + case Expr.Tuple(fields) => Expr.Tuple(fields.map(defunctionalize)) + case Expr.LetIn(isRec, name, rhs, body) => Expr.LetIn(isRec, name, defunctionalize(rhs), defunctionalize(body)) + case Expr.IfThenElse(condition, consequent, alternate) => Expr.IfThenElse(defunctionalize(condition), defunctionalize(consequent), alternate.map(defunctionalize)) + case Expr.Block(items) => Expr.Block(items.map{ + case e: Expr => defunctionalize(e) + case other => other + }) + case Expr.Select(receiver, field) => Expr.Select(defunctionalize(receiver), field) + case Expr.As(value, toType) => Expr.As(defunctionalize(value), toType) + case _ => throw MonomorphError(s"Unhandled case: ${rawExpr}") + } + ret.expValue = rawExpr.expValue + ret + } +} diff --git a/compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala b/compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala new file mode 100644 index 0000000000..6026a9ea09 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala @@ -0,0 +1,73 @@ +package mlscript.compiler.printer + +import mlscript.compiler.{Expr, Isolation, Item, ModuleUnit, Parameter} + +class ExprPrinter: + private val printer = BlockPrinter() + + import printer.{endLine, enter, leave, print} + + private def show(module: ModuleUnit): Unit = module.items.foreach { + case expr: Expr => show(expr) + case item: Item => show(item) + } + + private def show(params: List[Parameter]): String = + params.iterator.map { + case (spec, Expr.Ref(name)) => (if spec then "#" else "") + name + }.mkString("(", ", ", ")") + + private def show(item: Item): Unit = item match + case Item.TypeDecl(Expr.Ref(name), kind, typeParams, params, parents, body) => + val typeParamsStr = if typeParams.isEmpty then "" + else typeParams.iterator.map(_.name).mkString("[", ", ", "]") + val reprParents = if parents.isEmpty then "" + else parents.iterator.map { case (parent, args) => + parent.show(true) + args.iterator.mkString("(", ", ", ")") + }.mkString(": ", ", ", "") + print(s"$kind $name$typeParamsStr${show(params)}$reprParents ") + show(body) + case Item.FuncDecl(Expr.Ref(name), params, body) => + print(s"fun $name${show(params)} =") + enter() + show(body) + leave() + case Item.FuncDefn(Expr.Ref(name), typeParams, polyType) => + val reprTypeParams = if typeParams.isEmpty then "" else + s"${typeParams.mkString("[", ", ", "]")} => " + print(s"fun $name: $reprTypeParams${polyType.show}") + + private def show(isolation: Isolation): Unit = + enter("{", "}") + isolation.items.foreach { + case expr: Expr => show(expr) + case item: Item => show(item) + } + leave() + + private def show(expr: Expr) = + print(expr.toString) + endLine() + + def toLines: List[String] = printer.toLines + + override def toString(): String = printer.toString + +object ExprPrinter: + def print(node: ModuleUnit | Item | Isolation | Expr): String = + val printer = ExprPrinter() + node match + case module: ModuleUnit => printer.show(module) + case item: Item => printer.show(item) + case isolation: Isolation => printer.show(isolation) + case expr: Expr => printer.show(expr) + printer.toString + + def printLines(node: ModuleUnit | Item | Isolation | Expr): List[String] = + val printer = ExprPrinter() + node match + case module: ModuleUnit => printer.show(module) + case item: Item => printer.show(item) + case isolation: Isolation => printer.show(isolation) + case expr: Expr => printer.show(expr) + printer.toLines diff --git a/compiler/shared/main/scala/mlscript/compiler/syntax.scala b/compiler/shared/main/scala/mlscript/compiler/syntax.scala new file mode 100644 index 0000000000..b7e205112e --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/syntax.scala @@ -0,0 +1,271 @@ +package mlscript.compiler + +import mlscript.compiler.debug.{DebugOutput, Printable} +import mlscript.compiler.printer.ExprPrinter +import scala.collection.mutable.ArrayBuffer +import mlscript.{Type, Union, Inter, Function, Record, Tuple, Recursive, AppliedType, + Neg, Rem, Bounds, WithExtension, Constrained, Top, Bot, Literal, + TypeName, TypeVar, PolyType, NamedType} +import scala.collection.immutable.HashMap +import mlscript.compiler.mono.specializer.BoundedExpr +import mlscript.compiler.mono.specializer.Builtin + +trait ASTNode: + var parent: ASTNode = null + def setNodeFields(): Unit + var expValue: BoundedExpr = BoundedExpr() + var freeVars: Set[String] = null + var isStatic: Boolean = false + +enum Expr extends Printable, ASTNode: + case Ref(name: String) + case Lambda(params: List[Parameter], body: Expr) + case Apply(callee: Expr, arguments: List[Expr]) + case Tuple(fields: List[Expr]) + case Record(fields: List[(Ref, Expr)]) + case Select(receiver: Expr, field: Ref) + case LetIn(isRec: Boolean, name: Ref, rhs: Expr, body: Expr) + case Block(items: List[Expr | Item.FuncDecl | Item.FuncDefn]) + case As(value: Expr, toType: Type) + case Assign(assignee: Expr, value: Expr) + case With(value: Expr, fields: Expr.Record) + case Subscript(receiver: Expr, index: Expr) + case Match(scrutinee: Expr, branches: ArrayBuffer[CaseBranch]) + case Literal(value: BigInt | BigDecimal | Boolean | String | UnitValue) + case New(typeName: TypeName, args: List[Expr]) + case IfThenElse(condition: Expr, consequent: Expr, alternate: Option[Expr]) + case Isolated(isolation: Isolation) + + val workaround = setNodeFields() + + def setNodeFields(): Unit = this match + case Expr.Ref(name) => + freeVars = if Builtin.builtinRefs.contains(name) then Set() else Set(name) + case Expr.Lambda(params, body) => + body.parent = this; freeVars = body.freeVars -- params.map(_._2.name) + case Expr.Apply(callee, arguments) => + callee.parent = this; arguments.foreach(x => x.parent = this); freeVars = callee.freeVars ++ arguments.flatMap(_.freeVars); isStatic = arguments.map(_.isStatic).fold(callee.isStatic)(_ && _) + case Expr.Tuple(fields) => + fields.foreach(x => x.parent = this); freeVars = fields.flatMap(_.freeVars).toSet; isStatic = fields.map(_.isStatic).fold(true)(_ && _) + case Expr.Record(fields) => + fields.foreach(x => x._2.parent = this); freeVars = fields.flatMap(_._2.freeVars).toSet -- fields.map(_._1.name); isStatic = fields.map(_._2.isStatic).fold(true)(_ && _) + case Expr.Select(receiver, field) => + receiver.parent = this; field.parent = this; freeVars = receiver.freeVars; isStatic = receiver.isStatic + case Expr.LetIn(isRec, name, rhs, body) => + rhs.parent = this; body.parent = this; freeVars = rhs.freeVars ++ body.freeVars - name.name; isStatic = rhs.isStatic && body.isStatic + case Expr.Block(items) => + val expItems = items.flatMap{ + case x: Expr => Some(x) + case _ => None + } + freeVars = expItems.flatMap(_.freeVars).toSet + expItems.foreach(x => {x.parent = this}) + isStatic = expItems.map(_.isStatic).fold(true)(_ && _) + case Expr.As(value, toType) => + value.parent = this; freeVars = value.freeVars; isStatic = value.isStatic + case Expr.Assign(assignee, value) => + assignee.parent = this; value.parent = this; freeVars = assignee.freeVars ++ value.freeVars; isStatic = true + case Expr.With(value, fields) => + value.parent = this; fields.parent = this; freeVars = value.freeVars ++ fields.freeVars; isStatic = value.isStatic && fields.isStatic + case Expr.Subscript(receiver, index) => + receiver.parent = this; index.parent = this; freeVars = receiver.freeVars ++ index.freeVars; isStatic = receiver.isStatic && index.isStatic + case Expr.Match(scrutinee, branches) => + scrutinee.parent = this + isStatic = scrutinee.isStatic + freeVars = scrutinee.freeVars ++ branches.flatMap{ + case CaseBranch.Instance(className, alias, body) => + isStatic &&= body.isStatic + body.freeVars - alias.name + case CaseBranch.Constant(literal, body) => + isStatic &&= body.isStatic + body.freeVars + case CaseBranch.Wildcard(body) => + isStatic &&= body.isStatic + body.freeVars + } + branches.foreach(x => x.body.parent = this) + case Expr.Literal(value) => + freeVars = Set() + isStatic = true + case Expr.New(typeName, args) => + args.foreach(x => x.parent = this) + isStatic = args.map(_.isStatic).fold(true)(_ && _) + freeVars = args.flatMap(_.freeVars).toSet + typeName.name + case Expr.IfThenElse(condition, consequent, alternate) => + condition.parent = this + consequent.parent = this + alternate.foreach(x => x.parent = this) + freeVars = condition.freeVars ++ consequent.freeVars ++ alternate.map(_.freeVars).getOrElse(Set()) + isStatic = alternate.map(_.isStatic && condition.isStatic && consequent.isStatic).getOrElse(true) + case Expr.Isolated(isolation) => + val exps = isolation.items.flatMap{ + case x: Expr => Some(x) + case _ => None + } + exps.foreach{x => x.parent = this} + freeVars = exps.flatMap(_.freeVars).toSet + isStatic = exps.map(_.isStatic).fold(true)(_ && _) + + def asBoolean(): Boolean = this match + case Literal(value: BigInt) => value != 0 + case Literal(value: BigDecimal) => value != 0 + case Literal(value: Boolean) => value + case Literal(value: String) => !value.isEmpty() + case Literal(_) => false + case _ => false + + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + + override def toString(): String = + // val header = if this.parent == null then this.freeVars.mkString("[", ", ", "]~") else "" + val body = this match { + case Ref(name) => name + case Lambda(params, body) => + val head = params.mkString("(", ", ", ")") + s"(fun $head -> $body)" + case Apply(Apply(Ref(op), lhs :: Nil), rhs :: Nil) + if !op.headOption.forall(_.isLetter) => + s"($lhs $op $rhs)" + case Apply(callee, arguments) => + callee.toString + arguments.mkString("(", ", ", ")") + case Tuple(fields) => + val inner = fields.mkString(", ") + "(" + (if fields.length == 1 then inner + ", " else inner) + ")" + case Record(fields) => + "{" + fields.iterator.map { (name, value) => s"$name = $value" } + "}" + case Select(receiver, field) => s"$receiver.$field" + case LetIn(isRec, name, rhs, body) => s"let $name = $rhs in $body" + case Block(items) => items.mkString(";") + case As(value, toType) => s"$value as $toType" + case Assign(assignee, value) => s"$assignee = $value" + case With(value, fields) => s"$value with $fields" + case Subscript(receiver, index) => s"$receiver[$index]" + case Match(scrutinee, branches) => + s"$scrutinee match " + branches.iterator.mkString("{", "; ", "}") + case Literal(value) => "#" + value.toString + case New(callee, args) => + s"new ${callee.name}" + args.mkString(" (", ", ", ") ") + case IfThenElse(condition, consequent, None) => + s"if $condition then $consequent" + case IfThenElse(condition, consequent, Some(alternate)) => + s"if $condition then $consequent else $alternate" + case Isolated(isolation) => s"{\n$isolation\n}" + } + // header + + body +end Expr + +// This corresponds to `mlscript.UnitLit`. +enum UnitValue: + case Null, Undefined + + override def toString(): String = + this match + case Null => "null" + case Undefined => "()" // `()` is shorter than `undefined` + +enum CaseBranch: + val body: Expr + + case Instance(className: Expr.Ref, alias: Expr.Ref, body: Expr) + case Constant(literal: Expr.Literal, body: Expr) + case Wildcard(body: Expr) + + override def toString(): String = + this match + case Instance(Expr.Ref(className), Expr.Ref(alias), body) => + s"case $alias: $className => $body" + case Constant(literal, body) => s"case $literal => $body" + case Wildcard(body) => s"_ => $body" + +enum TypeDeclKind: + case Alias, Class, Trait + + override def toString(): String = this match + case Alias => "alias" + case Class => "class" + case Trait => "trait" + + +/** + * Function parameters: `(specializable, name)`. + */ +type Parameter = (Boolean, Expr.Ref) + +enum Item extends Printable: + val name: Expr.Ref + + /** + * Type declarations: aliases, classes and traits. + */ + case TypeDecl(name: Expr.Ref, kind: TypeDeclKind, typeParams: List[TypeName], + params: List[Parameter], parents: List[(NamedType, List[Expr])], body: Isolation) + /** + * Function declaration (with implementation). + */ + case FuncDecl(name: Expr.Ref, params: List[Parameter], body: Expr) + /** + * Function definition (with definition) + */ + case FuncDefn(name: Expr.Ref, typeParams: List[TypeName], body: PolyType) + + override def toString(): String = this match + case TypeDecl(Expr.Ref(name), kind, typeParams, params, parents, body) => + val typeParamsStr = if typeParams.isEmpty then "" + else typeParams.iterator.map(_.name).mkString("[", ", ", "]") + val parentsStr = if parents.isEmpty then "" + else parents.mkString(" extends ", " with ", " ") + s"$kind $name$typeParamsStr$parentsStr { $body }" + case FuncDecl(Expr.Ref(name), params, body) => + val parameters = params.iterator.map { + case (spec, Expr.Ref(name)) => + (if spec then "#" else "") + name + }.mkString("(", ", ", ")") + s"fun $name$parameters = $body" + case FuncDefn(Expr.Ref(name), Nil, polyType) => + s"fun $name: $polyType" + case FuncDefn(Expr.Ref(name), typeParams, polyType) => + s"fun $name: ${typeParams.mkString("[", ", ", "]")} => $polyType" + + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + +object Item: + /** + * A shorthand constructor for classes without type parameters and parents. + */ + def classDecl(name: String, params: List[Parameter], body: Isolation): Item.TypeDecl = + Item.TypeDecl(Expr.Ref(name), TypeDeclKind.Class, Nil, params, Nil, body) + +/** + * An `Isolation` is like a `TypingUnit` but without nested classes. + */ +class Isolation(val items: List[Expr | Item.FuncDecl | Item.FuncDefn]) extends Printable: + private val namedItemMap = HashMap.from(items.iterator.flatMap { + case _: Expr => None: Option[(String, Item.FuncDecl | Item.FuncDefn)] + case item: Item.FuncDecl => Some((item.name.name, item)) + case item: Item.FuncDefn => Some((item.name.name, item)) + }) + + def get(name: String): Option[Item.FuncDecl | Item.FuncDefn] = + namedItemMap.get(name) + + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + + override def toString(): String = items.mkString("\n") + +object Isolation: + def empty = Isolation(Nil) + +/** + * A `Module` is like a `TypingUnit`. + * This name conflicts with `java.lang.Module`. + * TODO: Find a better name. + */ +class ModuleUnit(val items: List[Expr | Item]) extends Printable: + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + + override def toString(): String = items.mkString("\n") diff --git a/compiler/shared/test/diff/LambLift.mls b/compiler/shared/test/diff/LambLift.mls new file mode 100644 index 0000000000..5e5054efe5 --- /dev/null +++ b/compiler/shared/test/diff/LambLift.mls @@ -0,0 +1,87 @@ +:NewDefs + +:AllowRuntimeErrors +fun foo() = + let local(x) = + class Foo { + fun bar = x + foo() + } + (new Foo()).bar + local(1) +foo() +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Blk(...))), App(Var(foo), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Foo$1([x,]) {fun bar = () => +((this).x, foo$1(),)} +//│ let local$2 = (x,) => {('(' new Foo$1([x,]) {} ')').bar} +//│ fun foo$1 = () => {local$2(1,)} +//│ Code(List(foo$1())) +//│ } +//│ fun foo: () -> Int +//│ Int +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +fun foo(f) = + f(1) +foo(x => x+1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$2$1([]) {fun apply = (x,) => +(x, 1,)} +//│ fun foo$1 = (f,) => {f(1,)} +//│ Code(List(foo$1({new Lambda1$2$1([]) {}},))) +//│ } +//│ fun foo: forall 'a. (1 -> 'a) -> 'a +//│ Int +//│ res +//│ = 2 + +fun foo(x) = + let bar(f) = + f(x) + bar(y => y+x) +foo(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$3$1([x,]) {fun apply = (y,) => +(y, (this).x,)} +//│ let bar$2 = (f, x,) => {f(x,)} +//│ fun foo$1 = (x,) => {bar$2({new Lambda1$3$1([x,]) {}}, x,)} +//│ Code(List(foo$1(1,))) +//│ } +//│ fun foo: Int -> Int +//│ Int +//│ res +//│ = 2 + +fun foo(f) = + f(1) +class A(y: Int){ + fun bar(z) = y+z +} +fun app(a) = + foo(z => a.bar(z)) +app(new A(1)) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), NuTypeDef(class, A, (), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: Var(y), _: Var(z))))))), NuFunDef(None, app, None, [], Lam(Tup(_: Var(a)), Blk(...))), App(Var(app), Tup(_: New(Some((TypeName(A),[1,])), TypingUnit())))) +//│ Lifted: +//│ TypingUnit { +//│ class A$1([y: Int,]) {fun bar = (z,) => +((this).y, z,)} +//│ class Lambda1$3$2([a,]) {fun apply = (z,) => ((this).a).bar(z,)} +//│ fun foo$2 = (f,) => {f(1,)} +//│ fun app$1 = (a,) => {foo$2({new Lambda1$3$2([a,]) {}},)} +//│ Code(List(app$1(new A$1([1,]) {},))) +//│ } +//│ fun foo: forall 'a. (1 -> 'a) -> 'a +//│ class A(y: Int) { +//│ fun bar: Int -> Int +//│ } +//│ fun app: forall 'b. {bar: 1 -> 'b} -> 'b +//│ Int +//│ res +//│ = 2 diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index 454a20d26a..2b4ccc4f07 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -8,7 +8,7 @@ class CTX{ //│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |#=>| |A|)|#:| |(|A| |#=>| |A|)| |#=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| //│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A([]) {},) : (A -> A) -> A}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), ‹›))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit()))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {} @@ -29,8 +29,8 @@ class CTX(x, y){ //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: Var(B))), Asc(Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} +//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { //│ fun foo = (any: [CTX$1_A$2, CTX$1_B$3,],) => [(any)._2, (any)._1,] : [CTX$1_B$3, CTX$1_A$2] //│ } @@ -48,8 +48,8 @@ class CTX(x, y){ //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} +//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { //│ fun foo = (any: '{' {p1: CTX$1_A$2, p2: CTX$1_B$3} '}',) => [(any).p2, (any).p1,] : [CTX$1_B$3, CTX$1_A$2] //│ } @@ -67,8 +67,8 @@ class CTX(x, y){ //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A))))), Asc(Tup(_: Var(any), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3[T]([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} +//│ class CTX$1_B$3[T]([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { //│ fun foo = (any: [CTX$1_A$2, CTX$1_B$3‹CTX$1_A$2›,],) => [any, (any)._1,] : [[CTX$1_B$3[CTX$1_A$2], CTX$1_A$2], CTX$1_A$2] //│ } diff --git a/compiler/shared/test/diff/Lifter.mls b/compiler/shared/test/diff/Lifter.mls index 29d225c0fc..bf77d3a629 100644 --- a/compiler/shared/test/diff/Lifter.mls +++ b/compiler/shared/test/diff/Lifter.mls @@ -28,32 +28,32 @@ class A(x) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getB1| |#=| |B1|(|y|)|↵|#class| |C|(|z|)| |{|→|#fun| |inc|(||)| |#=| |x| |+| |1|↵|#fun| |getY| |#=| |y|↵|#fun| |getA| |#=| |A|(|z|)|↵|#fun| |getB|(|w|)| |#=| |B|(|w|)|↵|#fun| |getC| |#=| |#new| |C|(|inc|(||)|)|↵|#fun| |getSelf| |#=| |this|←|↵|}|←|↵|}|↵|#class| |B1|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getY| |#=| |y|↵|#fun| |getB| |#=| |#new| |B|(|y|)|↵|#fun| |getB1| |#=| |#new| |B1|(|y|)|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|(|x|)|↵|#fun| |getB2|(|y|)| |#=| |B1|(|y|)|↵|#fun| |getB3|(|z|)| |#=| |getB2|(|z|)|↵|#fun| |getA| |#=| |A|(|x|)|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1(y,); class C(z,) {fun inc = () => +(x, 1,); fun getY = y; fun getA = A(z,); fun getB = (w,) => B(w,); fun getC = new C([inc(),]) {}; fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = new B([y,]) {}; fun getB1 = new B1([y,]) {}}; fun getB = new B([x,]) {}; fun getB2 = (y,) => B1(y,); fun getB3 = (z,) => getB2(z,); fun getA = A(x,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), ‹›)), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), ‹›)), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), ‹›)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), ‹›)), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), TypingUnit())), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), TypingUnit())), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), TypingUnit())))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), TypingUnit())), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2_C$4([par$A$1_B$2, z,]) { -//│ fun inc = () => +((((this).par$A$1_B$2).par$A$1).x, 1,) -//│ fun getY = ((this).par$A$1_B$2).y -//│ fun getA = A$1((this).z,) +//│ class A$1_B$2_C$4([par$A$1_B$2, z, x,]) { +//│ fun inc = () => +((this).x, 1,) +//│ fun getY = () => ((this).par$A$1_B$2).y +//│ fun getA = () => A$1((this).z,) //│ fun getB = (w,) => A$1_B$2(((this).par$A$1_B$2).par$A$1, w,) -//│ fun getC = new A$1_B$2_C$4([(this).par$A$1_B$2, (this).inc(),]) {} -//│ fun getSelf = this +//│ fun getC = () => new A$1_B$2_C$4([(this).par$A$1_B$2, (this).inc(), (this).x,]) {} +//│ fun getSelf = () => this //│ } //│ class A$1_B$2([par$A$1, y,]) { -//│ fun getX = ((this).par$A$1).x -//│ fun getB1 = A$1_B1$3((this).par$A$1, (this).y,) +//│ fun getX = () => ((this).par$A$1).x +//│ fun getB1 = () => A$1_B1$3((this).par$A$1, (this).y,) //│ } //│ class A$1_B1$3([par$A$1, y,]) { -//│ fun getX = ((this).par$A$1).x -//│ fun getY = (this).y -//│ fun getB = new A$1_B$2([(this).par$A$1, (this).y,]) {} -//│ fun getB1 = new A$1_B1$3([(this).par$A$1, (this).y,]) {} +//│ fun getX = () => ((this).par$A$1).x +//│ fun getY = () => (this).y +//│ fun getB = () => new A$1_B$2([(this).par$A$1, (this).y,]) {} +//│ fun getB1 = () => new A$1_B1$3([(this).par$A$1, (this).y,]) {} //│ } //│ class A$1([x,]) { -//│ fun getB = new A$1_B$2([this, (this).x,]) {} +//│ fun getB = () => new A$1_B$2([this, (this).x,]) {} //│ fun getB2 = (y,) => A$1_B1$3(this, y,) //│ fun getB3 = (z,) => (this).getB2(z,) -//│ fun getA = A$1((this).x,) +//│ fun getA = () => A$1((this).x,) //│ } //│ } //│ @@ -71,8 +71,8 @@ class A(x) { //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, sum, None, [], App(Var(+), Tup(_: App(Var(+), Tup(_: Var(x), _: Var(y))), _: Var(z))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2_C$3([par$A$1_B$2, z,]) { -//│ fun sum = +(+((((this).par$A$1_B$2).par$A$1).x, ((this).par$A$1_B$2).y,), (this).z,) +//│ class A$1_B$2_C$3([par$A$1_B$2, z, x,]) { +//│ fun sum = () => +(+((this).x, ((this).par$A$1_B$2).y,), (this).z,) //│ } //│ class A$1_B$2([par$A$1, y,]) {} //│ class A$1([x,]) {} @@ -108,7 +108,7 @@ new C{ //│ |#class| |A|(|x|)| |{|→|#class| |B|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |11|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |2|↵|#fun| |bar| |#=| |12|←|↵|}|↵|#fun| |bar| |#=| |13|←|↵|}|↵|#class| |C|#:| |A|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |3|↵|#fun| |bar| |#=| |14|←|↵|}|↵|#fun| |bar| |#=| |15|←|↵|}|↵|#new| |C|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |4|↵|#fun| |bar| |#=| |16|←|↵|}|↵|#fun| |bar| |#=| |17|←|↵|}| //│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B([]) {fun foo = 2; fun bar = 12}; fun bar = 13}; class C: A {fun getB = new B([]) {fun foo = 3; fun bar = 14}; fun bar = 15}; new C([]) {fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹fun foo = 2; fun bar = 12›)), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹fun foo = 3; fun bar = 14›)), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), ‹fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(2)), NuFunDef(None, bar, None, [], IntLit(12))))), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(3)), NuFunDef(None, bar, None, [], IntLit(14))))), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(4)), NuFunDef(None, bar, None, [], IntLit(16))))), NuFunDef(None, bar, None, [], IntLit(17))))) //│ Lifted: //│ Lifting failed: java.util.NoSuchElementException: None.get //│ @@ -148,7 +148,7 @@ class A(x: Int): {a1: Int} & B & D(x){ //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| //│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C([]) {fun foo = (x: T,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), ‹fun foo = (x: T,) => x›)))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(x: Var(T)), Var(x)))))))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -171,7 +171,7 @@ class A(x: Int) extends {a1: Int}, B, D(x){ //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)| |#extends| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| //│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C([]) {fun foo = (x,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), ‹fun foo = (x,) => x›)))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x)))))))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -192,13 +192,13 @@ class Child(x): { age: T } & { name: String} { //│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| //│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner {fun foo = age}; fun bar = age; fun boo = new Inner([]) {}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), ‹›))))) +//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), TypingUnit()))))) //│ Lifted: //│ TypingUnit { -//│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = (this).age} +//│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = () => (this).age} //│ class Child$1[T,U]([x,]) { -//│ fun bar = age -//│ fun boo = new Child$1_Inner$2([this, age,]) {} +//│ fun bar = () => age +//│ fun boo = () => new Child$1_Inner$2([this, age,]) {} //│ } //│ } //│ @@ -215,11 +215,11 @@ new A(0) { //│ |#class| |A|(|x|#:| |Int|)| |{|→|#fun| |getA|#:| |Int| |#=| |0|↵|#fun| |getA1| |#=| |1|←|↵|}|↵|#new| |A|(|0|)| |{|→|#fun| |getA| |#=| |3|↵|#fun| |getA2| |#=| |2|←|↵|}| //│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; new A([0,]) {fun getA = 3; fun getA2 = 2}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), ‹fun getA = 3; fun getA2 = 2›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), TypingUnit(NuFunDef(None, getA, None, [], IntLit(3)), NuFunDef(None, getA2, None, [], IntLit(2))))) //│ Lifted: //│ TypingUnit { -//│ class A$1([x: Int,]) {fun getA = 0 : Int; fun getA1 = 1} -//│ class A$1$2([x: Int,]): A$1((this).x,) {fun getA = 3; fun getA2 = 2} +//│ class A$1([x: Int,]) {fun getA = () => 0 : Int; fun getA1 = () => 1} +//│ class A$1$2([x: Int,]): A$1((this).x,) {fun getA = () => 3; fun getA2 = () => 2} //│ Code(List({new A$1$2([0,]) {}})) //│ } //│ @@ -236,13 +236,13 @@ new A(1) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{| |}|←|↵|}|↵|#new| |A|(|1|)| |{|→|#fun| |getB| |#=| |#new| |B|(|2|)|{|→|#fun| |getB| |#=| |#new| |B|(|3|)|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {}}; new A([1,]) {fun getB = new B([2,]) {fun getB = new B([3,]) {}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), ‹fun getB = new B([2,]) {fun getB = new B([3,]) {}}›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[2,])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[3,])), TypingUnit())))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1, y,]) {} //│ class A$1([x,]) {} -//│ class A$1$3_B$2$4([par$A$1$3, y,]): A$1_B$2((this).par$A$1$3, (this).y,) {fun getB = new A$1_B$2([(this).par$A$1$3, 3,]) {}} -//│ class A$1$3([x,]): A$1((this).x,) {fun getB = {new A$1$3_B$2$4([this, 2,]) {}}} +//│ class A$1$3_B$2$4([par$A$1$3, y,]): A$1_B$2((this).par$A$1$3, (this).y,) {fun getB = () => new A$1_B$2([(this).par$A$1$3, 3,]) {}} +//│ class A$1$3([x,]): A$1((this).x,) {fun getB = () => {new A$1$3_B$2$4([this, 2,]) {}}} //│ Code(List({new A$1$3([1,]) {}})) //│ } //│ @@ -269,18 +269,18 @@ new B{ //│ |#class| |A| |{|→|#fun| |getA| |#=| |0|↵|#fun| |funcA| |#=| |10|←|↵|}|↵|#class| |B|#:| |A|{|→|#fun| |getA| |#=| |1|↵|#fun| |funcB| |#=| |11|←|↵|}|↵|#new| |A|↵|#new| |B|↵|#fun| |f|(|x|)| |#=| |#if| |x| |is| |A| |#then| |0| |#else| |1|↵|f|(|#new| |A|{|→|#fun| |getA| |#=| |2|←|↵|}|)|↵|#new| |B|{|→|#fun| |getA| |#=| |funcB|←|↵|}| //│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A([]) {}; new B([]) {}; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A([]) {fun getA = 2},); new B([]) {fun getA = funcB}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), ‹›), New(Some((TypeName(B),[])), ‹›), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), ‹fun getA = 2›))), New(Some((TypeName(B),[])), ‹fun getA = funcB›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), TypingUnit()), New(Some((TypeName(B),[])), TypingUnit()), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, getA, None, [], IntLit(2)))))), New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, getA, None, [], Var(funcB))))) //│ Lifted: //│ TypingUnit { -//│ class A$1([]) {fun getA = 0; fun funcA = 10} -//│ class B$2([]) {fun getA = 1; fun funcB = 11} -//│ class A$1$3([]): A$1() {fun getA = 2} -//│ class B$2$4([]): B$2() {fun getA = (this).funcB} -//│ fun f = (x,) => if (is(x, A$1(),)) then 0 else 1 +//│ class A$1([]) {fun getA = () => 0; fun funcA = () => 10} +//│ class B$2([]) {fun getA = () => 1; fun funcB = () => 11} +//│ class A$2$3([]): A$1() {fun getA = () => 2} +//│ class B$3$4([]): B$2() {fun getA = () => (this).funcB} +//│ fun f$1 = (x,) => if (is(x, A$1(),)) then 0 else 1 //│ Code(List(new A$1([]) {})) //│ Code(List(new B$2([]) {})) -//│ Code(List(f({new A$1$3([]) {}},))) -//│ Code(List({new B$2$4([]) {}})) +//│ Code(List(f$1({new A$2$3([]) {}},))) +//│ Code(List({new B$3$4([]) {}})) //│ } //│ @@ -313,11 +313,11 @@ class A{ //│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1,]) {fun funB = 1; fun foo = 100} -//│ class A$1_C$3([par$A$1,]) {fun funC = 2; fun foo = 1000} -//│ class A$1_D$4_E$5([par$A$1_D$4,]) {fun funE = 4; fun foo = 100000} -//│ class A$1_D$4_F$6([par$A$1_D$4,]) {fun funF = 5; fun foo = 1000000} -//│ class A$1_D$4([par$A$1,]) {fun funD = 3; fun foo = 10000} +//│ class A$1_B$2([par$A$1,]) {fun funB = () => 1; fun foo = () => 100} +//│ class A$1_C$3([par$A$1,]) {fun funC = () => 2; fun foo = () => 1000} +//│ class A$1_D$4_E$5([par$A$1_D$4,]) {fun funE = () => 4; fun foo = () => 100000} +//│ class A$1_D$4_F$6([par$A$1_D$4,]) {fun funF = () => 5; fun foo = () => 1000000} +//│ class A$1_D$4([par$A$1,]) {fun funD = () => 3; fun foo = () => 10000} //│ class A$1([]) {} //│ } //│ @@ -353,27 +353,27 @@ class A{ //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|↵|#fun| |getB| |#=| |#new| |B|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|↵|#fun| |getD| |#=| |#new| |D|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|↵|#fun| |getE| |#=| |#new| |E|{|→|#fun| |foo| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B([]) {}}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D([]) {}}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E([]) {fun foo = 0}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹›)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), ‹›)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), ‹fun foo = 0›))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit())))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), TypingUnit())))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1,]) {fun funB = 1; fun foo = 100} +//│ class A$1_B$2([par$A$1,]) {fun funB = () => 1; fun foo = () => 100} //│ class A$1_C$3([par$A$1,]) { -//│ fun funC = 2 -//│ fun foo = 1000 -//│ fun getB = new A$1_B$2([(this).par$A$1,]) {} +//│ fun funC = () => 2 +//│ fun foo = () => 1000 +//│ fun getB = () => new A$1_B$2([(this).par$A$1,]) {} //│ } //│ class A$1_D$4_E$5([par$A$1_D$4,]) { -//│ fun funE = 4 -//│ fun foo = 100000 -//│ fun getD = new A$1_D$4([((this).par$A$1_D$4).par$A$1,]) {} +//│ fun funE = () => 4 +//│ fun foo = () => 100000 +//│ fun getD = () => new A$1_D$4([((this).par$A$1_D$4).par$A$1,]) {} //│ } -//│ class A$1_D$4_F$6_E$1$7([par$A$1_D$4_F$6,]): A$1_D$4_E$5(((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = 0} +//│ class A$1_D$4_F$6_E$1$7([par$A$1_D$4_F$6,]): A$1_D$4_E$5(((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = () => 0} //│ class A$1_D$4_F$6([par$A$1_D$4,]) { -//│ fun funF = 5 -//│ fun foo = 1000000 -//│ fun getE = {new A$1_D$4_F$6_E$1$7([this,]) {}} +//│ fun funF = () => 5 +//│ fun foo = () => 1000000 +//│ fun getE = () => {new A$1_D$4_F$6_E$1$7([this,]) {}} //│ } -//│ class A$1_D$4([par$A$1,]) {fun funD = 3; fun foo = 10000} +//│ class A$1_D$4([par$A$1,]) {fun funD = () => 3; fun foo = () => 10000} //│ class A$1([]) {} //│ } //│ @@ -389,11 +389,11 @@ new A //│ |#class| |A|{|→|#class| |B|{|→|#fun| |foo| |#=| |1|←|↵|}|↵|#fun| |bar| |#=| |#new| |B|←|↵|}|↵|#new| |A| //│ Parsed: {class A {class B {fun foo = 1}; fun bar = new B([]) {}}; new A([]) {}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), ‹›)))), New(Some((TypeName(A),[])), ‹›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), TypingUnit())))), New(Some((TypeName(A),[])), TypingUnit())) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1,]) {fun foo = 1} -//│ class A$1([]) {fun bar = new A$1_B$2([this,]) {}} +//│ class A$1_B$2([par$A$1,]) {fun foo = () => 1} +//│ class A$1([]) {fun bar = () => new A$1_B$2([this,]) {}} //│ Code(List(new A$1([]) {})) //│ } //│ @@ -414,20 +414,20 @@ let x = new A{ //│ |#class| |A|(|x|)| |{|→|#fun| |foo| |#=| |0|↵|#fun| |bar| |#=| |x|←|↵|}|↵|#let| |x| |#=| |#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |newFun| |#=| |2|↵|#fun| |bar| |#=| |#new| |A|(|foo|)|{|→|#fun| |foo| |#=| |bar| |+| |1|↵|#fun| |bar2| |#=| |newFun| |+| |1|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A([]) {fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), ‹fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}›))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, newFun, None, [], IntLit(2)), NuFunDef(None, bar, None, [], New(Some((TypeName(A),[foo,])), TypingUnit(NuFunDef(None, foo, None, [], App(Var(+), Tup(_: Var(bar), _: IntLit(1)))), NuFunDef(None, bar2, None, [], App(Var(+), Tup(_: Var(newFun), _: IntLit(1))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1([x,]) {fun foo = 0; fun bar = (this).x} -//│ class A$1$2_A$2$3([par$A$1$2, x,]): A$1((this).x,) { -//│ fun foo = +((this).bar, 1,) -//│ fun bar2 = +(((this).par$A$1$2).newFun, 1,) +//│ class A$1([x,]) {fun foo = () => 0; fun bar = () => (this).x} +//│ class A$2$2_A$3$3([par$A$2$2, x,]): A$1((this).x,) { +//│ fun foo = () => +((this).bar, 1,) +//│ fun bar2 = () => +(((this).par$A$2$2).newFun, 1,) //│ } -//│ class A$1$2([x,]): A$1((this).x,) { -//│ fun foo = 1 -//│ fun newFun = 2 -//│ fun bar = {new A$1$2_A$2$3([this, (this).foo,]) {}} +//│ class A$2$2([x,]): A$1((this).x,) { +//│ fun foo = () => 1 +//│ fun newFun = () => 2 +//│ fun bar = () => {new A$2$2_A$3$3([this, (this).foo,]) {}} //│ } -//│ let x = {new A$1$2([]) {}} +//│ let x$1 = () => {new A$2$2([]) {}} //│ } //│ @@ -451,27 +451,30 @@ new A{ //│ |#class| |A| |{||}|↵|#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |#new| |A|{|→|#fun| |foo1| |#=| |foo|↵|#fun| |bar1| |#=| |#new| |A|{|→|#fun| |foo2| |#=| |foo|↵|#fun| |bar2| |#=| |#new| |A|{|→|#fun| |foo3| |#=| |foo|↵|#fun| |bar3| |#=| |#new| |A|{|→|#fun| |foo4| |#=| |foo|↵|#fun| |bar4| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A {}; new A([]) {fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), ‹fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo1, None, [], Var(foo)), NuFunDef(None, bar1, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo2, None, [], Var(foo)), NuFunDef(None, bar2, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo3, None, [], Var(foo)), NuFunDef(None, bar3, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo4, None, [], Var(foo)), NuFunDef(None, bar4, None, [], IntLit(0))))))))))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1([]) {} //│ class A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([par$A$1$2_A$2$3_A$3$4_A$4$5,]): A$1() { -//│ fun foo4 = (((((this).par$A$1$2_A$2$3_A$3$4_A$4$5).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar4 = 0 +//│ fun foo4 = () => (((((this).par$A$1$2_A$2$3_A$3$4_A$4$5).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo +//│ fun bar4 = () => 0 //│ } //│ class A$1$2_A$2$3_A$3$4_A$4$5([par$A$1$2_A$2$3_A$3$4,]): A$1() { -//│ fun foo3 = ((((this).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar3 = {new A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([this,]) {}} +//│ fun foo3 = () => ((((this).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo +//│ fun bar3 = () => {new A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([this,]) {}} //│ } //│ class A$1$2_A$2$3_A$3$4([par$A$1$2_A$2$3,]): A$1() { -//│ fun foo2 = (((this).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar2 = {new A$1$2_A$2$3_A$3$4_A$4$5([this,]) {}} +//│ fun foo2 = () => (((this).par$A$1$2_A$2$3).par$A$1$2).foo +//│ fun bar2 = () => {new A$1$2_A$2$3_A$3$4_A$4$5([this,]) {}} //│ } //│ class A$1$2_A$2$3([par$A$1$2,]): A$1() { -//│ fun foo1 = ((this).par$A$1$2).foo -//│ fun bar1 = {new A$1$2_A$2$3_A$3$4([this,]) {}} +//│ fun foo1 = () => ((this).par$A$1$2).foo +//│ fun bar1 = () => {new A$1$2_A$2$3_A$3$4([this,]) {}} +//│ } +//│ class A$1$2([]): A$1() { +//│ fun foo = () => 1 +//│ fun bar = () => {new A$1$2_A$2$3([this,]) {}} //│ } -//│ class A$1$2([]): A$1() {fun foo = 1; fun bar = {new A$1$2_A$2$3([this,]) {}}} //│ Code(List({new A$1$2([]) {}})) //│ } //│ diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index 2ca0c8b44b..67d569bd56 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -9,7 +9,7 @@ fun foo = //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) //│ Lifted: -//│ TypingUnit {fun foo = {print("ok",); print("ko",)}} +//│ TypingUnit {fun foo$1 = () => {print("ok",); print("ko",)}} //│ class A{ @@ -28,7 +28,7 @@ class A{ //│ fun foo = - fun local(x) = + let local(x) = class Foo { fun bar = x + 1 } @@ -38,14 +38,16 @@ fun foo = fun tmp = 1 print of local of 0 + local of 1 fun tmp = 2 -//│ |#fun| |foo| |#=|→|#fun| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| -//│ Parsed: {fun foo = {fun local = (x,) => {class Foo {fun bar = +(x, 1,)}; (Foo()).bar}; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); fun tmp = 1; print(local(+(0, local(1,),),),); fun tmp = 2}} +//│ |#fun| |foo| |#=|→|#let| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| +//│ Parsed: {fun foo = {let local = (x,) => {class Foo {fun bar = +(x, 1,)}; (Foo()).bar}; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); fun tmp = 1; print(local(+(0, local(1,),),),); fun tmp = 2}} //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1([x,]) {fun bar = +((this).x, 1,)} -//│ fun foo = {fun local = (x,) => {(Foo$1(x,)).bar}; fun tmp = 1; fun tmp = 2; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); print(local(+(0, local(1,),),),)} +//│ class Foo$1([x,]) {fun bar = () => +((this).x, 1,)} +//│ let local$3 = (x,) => {(Foo$1(x,)).bar} +//│ fun tmp$2 = () => 1 +//│ fun foo$1 = () => {print(+(local$3(0,), local$3(1,),),); print(+('(' local$3(0,) ')', local$3(1,),),); print(local$3(+(0, local$3(1,),),),)} //│ } //│ @@ -55,13 +57,13 @@ f(0) //│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |#=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| //│ Parsed: {class A(y,) {}; let f = (x,) => new A([0,]) {fun bar = +(x, y,)}; f(0,)} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), ‹fun bar = +(x, y,)›))), App(Var(f), Tup(_: IntLit(0)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), TypingUnit(NuFunDef(None, bar, None, [], App(Var(+), Tup(_: Var(x), _: Var(y)))))))), App(Var(f), Tup(_: IntLit(0)))) //│ Lifted: //│ TypingUnit { //│ class A$1([y,]) {} -//│ class A$1$2([y, x,]): A$1((this).y,) {fun bar = +((this).x, (this).y,)} -//│ let f = (x,) => {new A$1$2([0, x,]) {}} -//│ Code(List(f(0,))) +//│ class A$2$2([y, x,]): A$1((this).y,) {fun bar = () => +((this).x, (this).y,)} +//│ let f$1 = (x,) => {new A$2$2([0, x,]) {}} +//│ Code(List(f$1(0,))) //│ } //│ @@ -81,10 +83,14 @@ class A(x){ //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, w, None, [], Var(x)), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(y)), Blk(...)))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1, z, y,]) {fun bar = +(+(((this).par$A$1).x, (this).y,), (this).z,)} -//│ class A$1_B$1$3([par$A$1, z, y,]): A$1_B$2((this).par$A$1, (this).z, (this).y,) {fun bar = +(+(((this).par$A$1).w, (this).y,), (this).z,)} +//│ class A$1_B$2([par$A$1, z, y,]) { +//│ fun bar = () => +(+(((this).par$A$1).x, (this).y,), (this).z,) +//│ } +//│ class A$1_B$1$3([par$A$1, z, y,]): A$1_B$2((this).par$A$1, (this).z, (this).y,) { +//│ fun bar = () => +(+(((this).par$A$1).w, (this).y,), (this).z,) +//│ } //│ class A$1([x,]) { -//│ fun w = (this).x +//│ fun w = () => (this).x //│ fun foo = (y,) => {{new A$1_B$1$3([this, 0, y,]) {}}} //│ } //│ } @@ -109,15 +115,15 @@ fun f(x,y,z) = //│ Lifted: //│ TypingUnit { //│ class A$1([x, y,]) { -//│ fun foo = new B$2([(this).y, (this).x,]) {} -//│ fun bar1 = (this).x +//│ fun foo = () => new B$2([(this).y, (this).x,]) {} +//│ fun bar1 = () => (this).x //│ } //│ class B$2([y, x,]) { -//│ fun foo = new A$1([(this).x, (this).y,]) {} -//│ fun bar2 = (this).y +//│ fun foo = () => new A$1([(this).x, (this).y,]) {} +//│ fun bar2 = () => (this).y //│ } -//│ class C$3([x, y,]): A$1((this).x, (this).y,), B$2((this).y, (this).x,) {fun bar = +((this).bar1, (this).bar2,)} -//│ fun f = (x, y, z,) => {} +//│ class C$3([x, y,]): A$1((this).x, (this).y,), B$2((this).y, (this).x,) {fun bar = () => +((this).bar1, (this).bar2,)} +//│ fun f$1 = (x, y, z,) => {} //│ } //│ @@ -140,35 +146,51 @@ fun f(x,y,z) = //│ Lifted: //│ TypingUnit { //│ class C$1_A$2([par$C$1,]) { -//│ fun foo = new C$1_B$3([(this).par$C$1,]) {} -//│ fun bar1 = ((this).par$C$1).x +//│ fun foo = () => new C$1_B$3([(this).par$C$1,]) {} +//│ fun bar1 = () => ((this).par$C$1).x //│ } //│ class C$1_B$3([par$C$1,]) { -//│ fun foo = new C$1_A$2([(this).par$C$1,]) {} -//│ fun bar2 = ((this).par$C$1).y +//│ fun foo = () => new C$1_A$2([(this).par$C$1,]) {} +//│ fun bar2 = () => ((this).par$C$1).y //│ } //│ class C$1([x, y, z,]) { -//│ fun boo = +(+(('(' new C$1_A$2([this,]) {} ')').bar1, (C$1_B$3(this,)).bar2,), (this).z,) +//│ fun boo = () => +(+(('(' new C$1_A$2([this,]) {} ')').bar1, (C$1_B$3(this,)).bar2,), (this).z,) //│ } -//│ fun f = (x, y, z,) => {} +//│ fun f$1 = (x, y, z,) => {} //│ } //│ -fun f(x) = - let g(x) = x + 1 +fun f(y) = + let g(x) = x + y + 1 class Foo(x) { fun h = g(x) } - Foo(x).h -//│ |#fun| |f|(|x|)| |#=|→|#let| |g|(|x|)| |#=| |x| |+| |1|↵|#class| |Foo|(|x|)| |{|→|#fun| |h| |#=| |g|(|x|)|←|↵|}|↵|Foo|(|x|)|.h|←| -//│ Parsed: {fun f = (x,) => {let g = (x,) => +(x, 1,); class Foo(x,) {fun h = g(x,)}; (Foo(x,)).h}} +//│ |#fun| |f|(|y|)| |#=|→|#let| |g|(|x|)| |#=| |x| |+| |y| |+| |1|↵|#class| |Foo|(|x|)| |{|→|#fun| |h| |#=| |g|(|x|)|←|↵|}|←| +//│ Parsed: {fun f = (y,) => {let g = (x,) => +(+(x, y,), 1,); class Foo(x,) {fun h = g(x,)}}} //│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...)))) +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(y)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1([x, g,]) {fun h = (this).g((this).x,)} -//│ fun f = (x,) => {let g = (x,) => +(x, 1,); (Foo$1(x, g,)).h} +//│ class Foo$1([x, y,]) {fun h = () => g$2((this).x, y,)} +//│ let g$2 = (x, y,) => +(+(x, y,), 1,) +//│ fun f$1 = (y,) => {} //│ } +//│ + Foo(1).h +//│ | |Foo|(|1|)|.h| +//│ Parsed: {(Foo(1,)).h} +//│ Parsed: +//│ TypingUnit(Sel(App(Var(Foo), Tup(_: IntLit(1))), h)) +//│ Lifted: +//│ TypingUnit {Code(List((Foo(1,)).h))} +//│ + Foo(x).h +//│ | |Foo|(|x|)|.h| +//│ Parsed: {(Foo(x,)).h} +//│ Parsed: +//│ TypingUnit(Sel(App(Var(Foo), Tup(_: Var(x))), h)) +//│ Lifted: +//│ TypingUnit {Code(List((Foo(x,)).h))} //│ fun f(x) = @@ -185,8 +207,10 @@ fun f(x) = //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1([x, y, g,]) {fun bar = +((this).g((this).x,), (this).y,)} -//│ fun f = (x,) => {let g = (x,) => {let h = (x,) => +(x, 2,); (Foo$1(h(x,), x, g,)).bar}; (Foo$1(x, x, g,)).bar} +//│ class Foo$1([x, y,]) {fun bar = () => +(g$2((this).x,), (this).y,)} +//│ let h$3 = (x,) => +(x, 2,) +//│ let g$2 = (x,) => {(Foo$1(h$3(x,), x,)).bar} +//│ fun f$1 = (x,) => {(Foo$1(x, x,)).bar} //│ } //│ @@ -212,25 +236,26 @@ fun foo(x: T): string = //│ TypingUnit(NuFunDef(None, foo, None, [TypeName(T), TypeName(U)], Lam(Tup(x: Var(T)), Asc(Blk(...), TypeName(string))))) //│ Lifted: //│ TypingUnit { -//│ class A$1[T,U]([y,]): B‹T›, C(y: U,) {fun bar = this} -//│ fun foo[T, U] = (x: T,) => {"rua"} : string +//│ class A$1[T,U]([y,]): B‹T›, C(y: U,) {fun bar = () => this} +//│ fun foo$1[T, U] = (x: T,) => {"rua"} : string //│ } //│ class A{ class B{ - fun f: T => B => T = x => y => x + fun f = x => y => x fun g: T => B => T } } -//│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f|#:| |T| |#=>| |B| |#=>| |T| |#=| |x| |#=>| |y| |#=>| |x|↵|#fun| |g|#:| |T| |#=>| |B| |#=>| |T|←|↵|}|←|↵|}| -//│ Parsed: {class A‹T› {class B {fun f = (x,) => (y,) => x : T -> B -> T; fun g: T -> B -> T}}} +//│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f| |#=| |x| |#=>| |y| |#=>| |x|↵|#fun| |g|#:| |T| |#=>| |B| |#=>| |T|←|↵|}|←|↵|}| +//│ Parsed: {class A‹T› {class B {fun f = (x,) => (y,) => x; fun g: T -> B -> T}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, None, [], Asc(Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x))), Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T))))), NuFunDef(None, g, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) +//│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x)))), NuFunDef(None, g, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) //│ Lifted: //│ TypingUnit { +//│ class A$1_B$2_Lambda1$1$3([par$A$1_B$2, x,]) {fun apply = (y,) => (this).x} //│ class A$1_B$2[T]([par$A$1,]) { -//│ fun f = (x,) => (y,) => x : T -> A$1_B$2 -> T +//│ fun f = (x,) => {new A$1_B$2_Lambda1$1$3([this, x,]) {}} //│ fun g = T -> A$1_B$2 -> T //│ } //│ class A$1[T]([]) {} @@ -273,8 +298,9 @@ fun ctx(a,b) = //│ TypingUnit { //│ class Func$1[T,U]([]) {fun apply = T -> U} //│ class Lambda$2[T,U]([]) {} -//│ class Lambda$1$3([a,]): Lambda$2() {fun apply = (x,) => +((this).a, x,)} -//│ fun ctx = (a, b,) => {fun foo = (f: Func$1, x,) => {(f).apply(x,)}; foo({new Lambda$1$3([a,]) {}}, b,)} +//│ class Lambda$3$3([a,]): Lambda$2() {fun apply = (x,) => +((this).a, x,)} +//│ fun foo$2 = (f: Func$1, x,) => {(f).apply(x,)} +//│ fun ctx$1 = (a, b,) => {foo$2({new Lambda$3$3([a,]) {}}, b,)} //│ } //│ @@ -288,3 +314,19 @@ f(MyClass) //│ Lifted: //│ Lifting failed: mlscript.codegen.CodeGenError: Cannot find type T. Class values are not supported in lifter. //│ + +class A { + fun foo = + fun bar = foo() + bar() +} +//│ |#class| |A| |{|→|#fun| |foo| |#=| |→|#fun| |bar| |#=| |foo|(||)|↵|bar|(||)|←|←|↵|}| +//│ Parsed: {class A {fun foo = {fun bar = foo(); bar()}}} +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Blk(...))))) +//│ Lifted: +//│ TypingUnit { +//│ class A$1([]) {fun foo = () => {bar$1(this,)}} +//│ fun bar$1 = (this,) => (this).foo() +//│ } +//│ diff --git a/compiler/shared/test/diff/mono.mls b/compiler/shared/test/diff/mono.mls new file mode 100644 index 0000000000..5116e6600d --- /dev/null +++ b/compiler/shared/test/diff/mono.mls @@ -0,0 +1,1204 @@ + +:NewDefs + +:mono +fun f(x: Int) = if x then 42 else 1337 +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(x: Var(Int)), If(IfThen(Var(x), IntLit(42), Some(IntLit(1337)))))) +//│ Lifted: +//│ TypingUnit { +//│ fun f$1 = (x: Int,) => if (x) then 42 else 1337 +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ fun f$1(x) = +//│ if x then #42 else #1337 +//│ fun f: (x: Int) -> (1337 | 42) + +:mono +fun foo() = 42 +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), IntLit(42)))) +//│ Lifted: +//│ TypingUnit {fun foo$1 = () => 42} +//│ Mono: +//│ +//│ Defunc result: +//│ fun foo$1() = +//│ #42 +//│ fun foo: () -> 42 + +:mono +fun foo(x, #b) = if b then x else 1337 +let a = foo(42, true) +let b = foo(23, false) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x), _: Var(b)), If(IfThen(Var(b), Var(x), Some(IntLit(1337))))), NuFunDef(Some(false), a, None, [], App(Var(foo), Tup(_: IntLit(42), _: Var(true)))), NuFunDef(Some(false), b, None, [], App(Var(foo), Tup(_: IntLit(23), _: Var(false))))) +//│ Lifted: +//│ TypingUnit { +//│ fun foo$3 = (x, #b,) => if (b) then x else 1337 +//│ let a$1 = () => foo$3(42, true,) +//│ let b$2 = () => foo$3(23, false,) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ fun b$2() = +//│ foo$3(#23, false) +//│ fun foo$3(x, #b) = +//│ if b then x else #1337 +//│ fun a$1() = +//│ foo$3(#42, true) +//│ fun foo: forall 'a. ('a, Object) -> (1337 | 'a) +//│ let a: 1337 | 42 +//│ let b: 1337 | 23 +//│ a +//│ = 42 +//│ b +//│ = 1337 + +:mono +let x = 42 + 1337 +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), x, None, [], App(Var(+), Tup(_: IntLit(42), _: IntLit(1337))))) +//│ Lifted: +//│ TypingUnit {let x$1 = () => +(42, 1337,)} +//│ Mono: +//│ +//│ Defunc result: +//│ fun x$1() = +//│ +(#42, #1337) +//│ let x: Int +//│ x +//│ = 1379 + +//:mono +//:e // FIXME: Mutable Parameters +//class Bar(#x) +//fun foo(#b) = b +//let a = foo(new Bar(1)) +//let b = foo(new Bar(2)) + +//:mono +//:w // FIXME: Mutable Parameters +//class OneInt(#a){ +// fun inc() = a+1 +//} +//(new OneInt(1)).inc() + +//:mono +//:e // FIXME: Mutable Parameters +//class OneInt(#a){ +// fun add(x) = +// new OneInt(a+x.a) +//} +//(new OneInt(1)).add(new OneInt(2)) + +:mono +if true then 1 else 0 +if 1+1 > 1 then 1 - 1 else 1*1 +//│ Parsed: +//│ TypingUnit(If(IfThen(Var(true), IntLit(1), Some(IntLit(0))), If(IfThen(App(Var(>), Tup(_: App(Var(+), Tup(_: IntLit(1), _: IntLit(1))), _: IntLit(1))), App(Var(-), Tup(_: IntLit(1), _: IntLit(1))), Some(App(Var(*), Tup(_: IntLit(1), _: IntLit(1)))))) +//│ Lifted: +//│ TypingUnit { +//│ Code(List(if (true) then 1 else 0)) +//│ Code(List(if (>(+(1, 1,), 1,)) then -(1, 1,) else *(1, 1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$0() +//│ main$$1() +//│ fun main$$0() = +//│ if true then #1 else #0 +//│ fun main$$1() = +//│ if >(+(#1, #1), #1) then -(#1, #1) else *(#1, #1) +//│ Int +//│ res +//│ = 1 +//│ res +//│ = 0 + +:mono +if(b) then 1 else 2 +//│ Parsed: +//│ TypingUnit(If(IfThen(Bra(rcd = false, Var(b)), IntLit(1), Some(IntLit(2)))) +//│ Lifted: +//│ TypingUnit {Code(List(if ('(' b ')') then 1 else 2))} +//│ Mono: +//│ +//│ Defunc result: +//│ main$$0() +//│ fun main$$0() = +//│ if b then #1 else #2 +//│ 1 | 2 +//│ res +//│ = 2 + +:mono +((f, g) => f(g))(f => f, true) +//│ Parsed: +//│ TypingUnit(App(Bra(rcd = false, Lam(Tup(_: Var(f), _: Var(g)), App(Var(f), Tup(_: Var(g))))), Tup(_: Lam(Tup(_: Var(f)), Var(f)), _: Var(true)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda2$1$1([]) {fun apply = (f, g,) => f(g,)} +//│ class Lambda1$2$2([]) {fun apply = (f,) => f} +//│ Code(List('(' {new Lambda2$1$1([]) {}} ')'({new Lambda1$2$2([]) {}}, true,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$2() +//│ fun apply$Lambda2$1$1(this, f, g) = +//│ f match {case obj: Lambda1$2$2 => apply$Lambda1$2$2(obj, g)} +//│ fun main$$2() = +//│ new Lambda2$1$1 () match {case obj: Lambda2$1$1 => apply$Lambda2$1$1(obj, new Lambda1$2$2 () , true)} +//│ fun apply$Lambda1$2$2(this, f) = +//│ f +//│ class Lambda2$1$1() { +//│ } +//│ class Lambda1$2$2() { +//│ } +//│ true +//│ res +//│ = true + + +:mono +(b => if b then true else false) (true) +//│ Parsed: +//│ TypingUnit(App(Bra(rcd = false, Lam(Tup(_: Var(b)), If(IfThen(Var(b), Var(true), Some(Var(false))))), Tup(_: Var(true)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$1$1([]) {fun apply = (b,) => if (b) then true else false} +//│ Code(List('(' {new Lambda1$1$1([]) {}} ')'(true,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun apply$Lambda1$1$1(this, b) = +//│ if b then true else false +//│ fun main$$1() = +//│ new Lambda1$1$1 () match {case obj: Lambda1$1$1 => apply$Lambda1$1$1(obj, true)} +//│ class Lambda1$1$1() { +//│ } +//│ Bool +//│ res +//│ = true + +:mono +fun f(x) = + if(x > 0) then x+1 else x - 1 +f(2)+3 +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(+), Tup(_: App(Var(f), Tup(_: IntLit(2))), _: IntLit(3)))) +//│ Lifted: +//│ TypingUnit { +//│ fun f$1 = (x,) => {if ('(' >(x, 0,) ')') then +(x, 1,) else -(x, 1,)} +//│ Code(List(+(f$1(2,), 3,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun f$1(x) = +//│ if >(x, #0) then +(x, #1) else -(x, #1) +//│ fun main$$1() = +//│ +(f$1(#2), #3) +//│ fun f: Int -> Int +//│ Int +//│ res +//│ = 6 + +:mono +fun fac(n) = + if (n > 1) then fac(n - 1) * n else 1 +fac(2) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, fac, None, [], Lam(Tup(_: Var(n)), Blk(...))), App(Var(fac), Tup(_: IntLit(2)))) +//│ Lifted: +//│ TypingUnit { +//│ fun fac$1 = (n,) => {if ('(' >(n, 1,) ')') then *(fac$1(-(n, 1,),), n,) else 1} +//│ Code(List(fac$1(2,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun fac$1(n) = +//│ if >(n, #1) then *(fac$1(-(n, #1)), n) else #1 +//│ fun main$$1() = +//│ fac$1(#2) +//│ fun fac: Int -> Int +//│ Int +//│ res +//│ = 2 + +:mono +class List(val l: List | Nil | undefined, val hasTail: Bool) {} +class Nil(val l: List | Nil | undefined, val hasTail: Bool) {} +fun count(lst) = + if lst.hasTail then + let l = lst.l + if l is undefined then 1 else count(l)+1 + else 0 +count(new List(new List(new Nil(undefined, false), true), true)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, count, None, [], Lam(Tup(_: Var(lst)), Blk(...))), App(Var(count), Tup(_: New(Some((TypeName(List),[new List([new Nil([undefined, false,]) {}, true,]) {}, true,])), TypingUnit())))) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([val l: |(|(List, Nil,), undefined,), val hasTail: Bool,]) {} +//│ class Nil$2([val l: |(|(List, Nil,), undefined,), val hasTail: Bool,]) {} +//│ let l$2 = (lst,) => (lst).l +//│ fun count$1 = (lst,) => {if ((lst).hasTail) then {if (is(l, undefined,)) then 1 else +(count$1(l,), 1,)} else 0} +//│ Code(List(count$1(new List$1([new List$1([new Nil$2([undefined, false,]) {}, true,]) {}, true,]) {},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ fun l$2(lst) = +//│ lst.l +//│ fun count$1(lst) = +//│ if lst.hasTail then if is(l, #()) then #1 else +(count$1(l), #1) else #0 +//│ fun main$$4() = +//│ count$1(new List$1 (new List$1 (new Nil$2 (#(), false) , true) , true) ) +//│ class Nil$2(l, hasTail) { +//│ } +//│ class List$1(l, hasTail) { +//│ } +//│ class List(l: List | Nil | (), hasTail: Bool) +//│ class Nil(l: List | Nil | (), hasTail: Bool) +//│ fun count: forall 'a. 'a -> Int +//│ Int +//│ where +//│ 'a <: {hasTail: Object, l: Object & 'a & ~() | ()} +//│ res +//│ = 2 + +//:mono +//class Cons(e, tail){ +// fun gen() = new Cons(e, tail.gen()) +//} +//class Nil(){ +// fun gen() = new Cons(0, this) +//} +//fun generate(x) = +// if x > 0 then new Cons(x, generate(x+1)) else new Nil() +//generate(10).gen() + +:mono +class List(e: Int, tail: List | Nil) { + fun map: (Int -> Int) -> List + fun map(f)= new List(f(e), tail.map(f)) + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun map(f) = this + fun count() = 0 +} +fun add2(x) = x+2 +(new List(1, new List(2, new Nil()))).map(x => x+1).map(x => add2(x)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, map, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(Int))))),TypeName(Int)))))),TypeName(List)))), NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), New(Some((TypeName(List),[f(e,), (tail).map(f,),])), TypingUnit()))), NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), Var(this))), NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, add2, None, [], Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))), App(Sel(App(Sel(Bra(rcd = false, New(Some((TypeName(List),[1, new List([2, new Nil([]) {},]) {},])), TypingUnit())), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1)))))), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(add2), Tup(_: Var(x))))))) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([e: Int, tail: |(List, Nil,),]) { +//│ fun map = (Int -> Int) -> List$1 +//│ fun map = (f,) => new List$1([f((this).e,), ((this).tail).map(f,),]) {} +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun map = (f,) => this; fun count = () => 0} +//│ class Lambda1$2$3([]) {fun apply = (x,) => +(x, 1,)} +//│ class Lambda1$3$4([]) {fun apply = (x,) => add2$1(x,)} +//│ fun add2$1 = (x,) => +(x, 2,) +//│ Code(List((('(' new List$1([1, new List$1([2, new Nil$2([]) {},]) {},]) {} ')').map({new Lambda1$2$3([]) {}},)).map({new Lambda1$3$4([]) {}},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ fun map$List$1(this, f) = +//│ new List$1 (f match {case obj: Lambda1$2$3 => apply$Lambda1$2$3(obj, this.e); case obj: Lambda1$3$4 => apply$Lambda1$3$4(obj, this.e)}, this.tail match {case obj: List$1 => map$List$1(obj, f); case obj: Nil$2 => map$Nil$2(obj, f)}) +//│ fun add2$1(x) = +//│ +(x, #2) +//│ fun main$$5() = +//│ new List$1 (#1, new List$1 (#2, new Nil$2 () ) ) match {case obj: List$1 => map$List$1(obj, new Lambda1$2$3 () )} match {case obj: List$1 => map$List$1(obj, new Lambda1$3$4 () )} +//│ fun apply$Lambda1$3$4(this, x) = +//│ add2$1(x) +//│ fun map$Nil$2(this, f) = +//│ this +//│ fun apply$Lambda1$2$3(this, x) = +//│ +(x, #1) +//│ class Lambda1$3$4() { +//│ } +//│ class Nil$2() { +//│ } +//│ class List$1(e, tail) { +//│ } +//│ class Lambda1$2$3() { +//│ } +//│ class List(e: Int, tail: List | Nil) { +//│ fun count: () -> Int +//│ fun map: (Int -> Int) -> List +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ fun map: anything -> Nil +//│ } +//│ fun add2: Int -> Int +//│ List +//│ res +//│ = List {} + +:mono +:AllowRuntimeErrors +class List(e: Int, tail: List | Nil) { + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun count() = 0 +} +fun foo(x) = x.count() +fun generate(x) = + if x > 0 then new List(x, generate(x+1)) else new Nil() +foo(new List(1, new List(2, new Nil()))) +foo(generate(1)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), App(Sel(Var(x), count), Tup()))), NuFunDef(None, generate, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: New(Some((TypeName(List),[1, new List([2, new Nil([]) {},]) {},])), TypingUnit()))), App(Var(foo), Tup(_: App(Var(generate), Tup(_: IntLit(1)))))) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([e: Int, tail: |(List, Nil,),]) { +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun count = () => 0} +//│ fun foo$1 = (x,) => (x).count() +//│ fun generate$2 = (x,) => {if (>(x, 0,)) then new List$1([x, generate$2(+(x, 1,),),]) {} else new Nil$2([]) {}} +//│ Code(List(foo$1(new List$1([1, new List$1([2, new Nil$2([]) {},]) {},]) {},))) +//│ Code(List(foo$1(generate$2(1,),))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ main$$5() +//│ fun foo$1(x) = +//│ x match {case obj: Nil$2 => count$Nil$2(obj); case obj: List$1 => count$List$1(obj)} +//│ fun count$Nil$2(this) = +//│ #0 +//│ fun count$List$1(this) = +//│ +(#1, this.tail match {case obj: List$1 => count$List$1(obj); case obj: Nil$2 => count$Nil$2(obj)}) +//│ fun generate$2(x) = +//│ if >(x, #0) then new List$1 (x, generate$2(+(x, #1))) else new Nil$2 () +//│ fun main$$5() = +//│ foo$1(generate$2(#1)) +//│ fun main$$4() = +//│ foo$1(new List$1 (#1, new List$1 (#2, new Nil$2 () ) ) ) +//│ class Nil$2() { +//│ } +//│ class List$1(e, tail) { +//│ } +//│ class List(e: Int, tail: List | Nil) { +//│ fun count: () -> Int +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ } +//│ fun foo: forall 'a. {count: () -> 'a} -> 'a +//│ fun generate: Int -> (List | Nil) +//│ Int +//│ res +//│ = 2 +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:mono +fun foo(x) = + (f => f(x))(z => z+1) +foo(2) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: IntLit(2)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$2$1([x,]) {fun apply = (f,) => f((this).x,)} +//│ class Lambda1$3$2([]) {fun apply = (z,) => +(z, 1,)} +//│ fun foo$1 = (x,) => {'(' {new Lambda1$2$1([x,]) {}} ')'({new Lambda1$3$2([]) {}},)} +//│ Code(List(foo$1(2,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$3() +//│ fun apply$Lambda1$2$1(this, f) = +//│ f match {case obj: Lambda1$3$2 => apply$Lambda1$3$2(obj, this.x)} +//│ fun foo$1(x) = +//│ new Lambda1$2$1 (x) match {case obj: Lambda1$2$1 => apply$Lambda1$2$1(obj, new Lambda1$3$2 () )} +//│ fun main$$3() = +//│ foo$1(#2) +//│ fun apply$Lambda1$3$2(this, z) = +//│ +(z, #1) +//│ class Lambda1$2$1(x) { +//│ } +//│ class Lambda1$3$2() { +//│ } +//│ fun foo: Int -> Int +//│ Int +//│ res +//│ = 3 + +:mono +fun f(x) = + (y => f(x+y))(x+1) +f(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(f), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$2$1([x,]) {fun apply = (y,) => f$1(+((this).x, y,),)} +//│ fun f$1 = (x,) => {'(' {new Lambda1$2$1([x,]) {}} ')'(+(x, 1,),)} +//│ Code(List(f$1(1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$2() +//│ fun apply$Lambda1$2$1(this, y) = +//│ f$1(+(this.x, y)) +//│ fun f$1(x) = +//│ new Lambda1$2$1 (x) match {case obj: Lambda1$2$1 => apply$Lambda1$2$1(obj, +(x, #1))} +//│ fun main$$2() = +//│ f$1(#1) +//│ class Lambda1$2$1(x) { +//│ } +//│ fun f: Int -> nothing +//│ nothing +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + + +:mono +fun f(x) = f(x) +f(0) +f(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), App(Var(f), Tup(_: Var(x))))), App(Var(f), Tup(_: IntLit(0))), App(Var(f), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ fun f$1 = (x,) => f$1(x,) +//│ Code(List(f$1(0,))) +//│ Code(List(f$1(1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ main$$2() +//│ fun f$1(x) = +//│ f$1(x) +//│ fun main$$2() = +//│ f$1(#1) +//│ fun main$$1() = +//│ f$1(#0) +//│ fun f: anything -> nothing +//│ nothing +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:mono +class Cons(e: 'A, tail: Cons | Nil) { + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun count() = 0 +} +class Lambda(){ + fun apply(l) = + l.count() +} +class Lambda2(a: Int){ + fun apply(l) = + (new Cons(a, l)).count() +} +fun foo(x) = + x.apply(new Cons(1, new Nil())) + x.apply(new Nil()) +foo(new Lambda()) +foo(new Lambda2(2)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var('A), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuTypeDef(class, Lambda, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuTypeDef(class, Lambda2, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: New(Some((TypeName(Lambda),[])), TypingUnit()))), App(Var(foo), Tup(_: New(Some((TypeName(Lambda2),[2,])), TypingUnit())))) +//│ Lifted: +//│ TypingUnit { +//│ class Cons$1([e: 'A, tail: |(Cons, Nil,),]) { +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun count = () => 0} +//│ class Lambda$3([]) {fun apply = (l,) => {(l).count()}} +//│ class Lambda2$4([a: Int,]) { +//│ fun apply = (l,) => {('(' new Cons$1([(this).a, l,]) {} ')').count()} +//│ } +//│ fun foo$1 = (x,) => {+((x).apply(new Cons$1([1, new Nil$2([]) {},]) {},), (x).apply(new Nil$2([]) {},),)} +//│ Code(List(foo$1(new Lambda$3([]) {},))) +//│ Code(List(foo$1(new Lambda2$4([2,]) {},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ main$$6() +//│ fun count$Cons$1(this) = +//│ +(#1, this.tail match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)}) +//│ fun foo$1(x) = +//│ +(x match {case obj: Lambda2$4 => apply$Lambda2$4(obj, new Cons$1 (#1, new Nil$2 () ) ); case obj: Lambda$3 => apply$Lambda$3(obj, new Cons$1 (#1, new Nil$2 () ) )}, x match {case obj: Lambda2$4 => apply$Lambda2$4(obj, new Nil$2 () ); case obj: Lambda$3 => apply$Lambda$3(obj, new Nil$2 () )}) +//│ fun apply$Lambda$3(this, l) = +//│ l match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)} +//│ fun count$Nil$2(this) = +//│ #0 +//│ fun apply$Lambda2$4(this, l) = +//│ new Cons$1 (this.a, l) match {case obj: Cons$1 => count$Cons$1(obj)} +//│ fun main$$6() = +//│ foo$1(new Lambda2$4 (#2) ) +//│ fun main$$5() = +//│ foo$1(new Lambda$3 () ) +//│ class Nil$2() { +//│ } +//│ class Lambda2$4(a) { +//│ } +//│ class Cons$1(e, tail) { +//│ } +//│ class Lambda$3() { +//│ } +//│ class Cons(e: nothing, tail: Cons | Nil) { +//│ fun count: () -> Int +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ } +//│ class Lambda() { +//│ fun apply: forall 'a. {count: () -> 'a} -> 'a +//│ } +//│ class Lambda2(a: Int) { +//│ fun apply: (Cons | Nil) -> Int +//│ } +//│ fun foo: {apply: (Cons | Nil) -> Int} -> Int +//│ Int +//│ res +//│ = 1 +//│ res +//│ = 3 + +:mono +class Cons(e: Int, tail: Cons | Nil) { + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun count() = 0 +} +fun foo(x) = + x(new Cons(1, new Nil())) + x(new Nil()) +foo(l => l.count()) +foo(l => (new Cons(2, l)).count()) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Var(l), count), Tup())))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Bra(rcd = false, New(Some((TypeName(Cons),[2, l,])), TypingUnit())), count), Tup()))))) +//│ Lifted: +//│ TypingUnit { +//│ class Cons$1([e: Int, tail: |(Cons, Nil,),]) { +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun count = () => 0} +//│ class Lambda1$2$3([]) {fun apply = (l,) => (l).count()} +//│ class Lambda1$3$4([]) { +//│ fun apply = (l,) => ('(' new Cons$1([2, l,]) {} ')').count() +//│ } +//│ fun foo$1 = (x,) => {+(x(new Cons$1([1, new Nil$2([]) {},]) {},), x(new Nil$2([]) {},),)} +//│ Code(List(foo$1({new Lambda1$2$3([]) {}},))) +//│ Code(List(foo$1({new Lambda1$3$4([]) {}},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ main$$6() +//│ fun count$Cons$1(this) = +//│ +(#1, this.tail match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)}) +//│ fun foo$1(x) = +//│ +(x match {case obj: Lambda1$3$4 => apply$Lambda1$3$4(obj, new Cons$1 (#1, new Nil$2 () ) ); case obj: Lambda1$2$3 => apply$Lambda1$2$3(obj, new Cons$1 (#1, new Nil$2 () ) )}, x match {case obj: Lambda1$3$4 => apply$Lambda1$3$4(obj, new Nil$2 () ); case obj: Lambda1$2$3 => apply$Lambda1$2$3(obj, new Nil$2 () )}) +//│ fun count$Nil$2(this) = +//│ #0 +//│ fun main$$6() = +//│ foo$1(new Lambda1$3$4 () ) +//│ fun main$$5() = +//│ foo$1(new Lambda1$2$3 () ) +//│ fun apply$Lambda1$3$4(this, l) = +//│ new Cons$1 (#2, l) match {case obj: Cons$1 => count$Cons$1(obj)} +//│ fun apply$Lambda1$2$3(this, l) = +//│ l match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)} +//│ class Lambda1$3$4() { +//│ } +//│ class Nil$2() { +//│ } +//│ class Cons$1(e, tail) { +//│ } +//│ class Lambda1$2$3() { +//│ } +//│ class Cons(e: Int, tail: Cons | Nil) { +//│ fun count: () -> Int +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ } +//│ fun foo: ((Cons | Nil) -> Int) -> Int +//│ Int +//│ res +//│ = 1 +//│ res +//│ = 3 + +:mono +class Exp() { + virtual fun derive(x: Int): Exp + virtual fun derive(x: Int) = Exp() + virtual fun isEmpty(): Bool + virtual fun isEmpty() = false +} +class E() extends Exp { + fun derive(x) = + new E + fun isEmpty() = + false +} +class Ep() extends Exp { + fun derive(x) = + new E + fun isEmpty() = + true +} +class Ch(i: Int) extends Exp { + fun derive(x) = + if x == i then new Ep else new E + fun isEmpty() = + false +} +class A(e1: Exp, e2: Exp) extends Exp { + fun derive(x) = + new A(e1.derive(x), e2.derive(x)) + fun isEmpty() = + e1.isEmpty() || e2.isEmpty() +} +class C(e1: Exp, e2: Exp) extends Exp { + fun derive(x) = + if e1.isEmpty() then new A(new C(e1.derive(x), e2), e2.derive(x)) else new C(e1.derive(x), e2) + fun isEmpty() = + e1.isEmpty() && e2.isEmpty() +} +(new C(new Ch(1), new A(new Ch(2), new Ch(3)))).derive(0).isEmpty() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Exp, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, derive, None, [], PolyType(List(),Function(Tuple(List((Some(x),Field(None,TypeName(Int))))),TypeName(Exp)))), NuFunDef(None, derive, None, [], Lam(Tup(x: Var(Int)), App(Var(Exp), Tup()))), NuFunDef(None, isEmpty, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Bool)))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Var(false))))), NuTypeDef(class, E, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ep, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ch, (), Tup(i: Var(Int)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, A, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, C, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), App(Sel(App(Sel(Bra(rcd = false, New(Some((TypeName(C),[new Ch([1,]) {}, new A([new Ch([2,]) {}, new Ch([3,]) {},]) {},])), TypingUnit())), derive), Tup(_: IntLit(0))), isEmpty), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Exp$1([]) { +//│ fun derive = (x: Int) -> Exp$1 +//│ fun derive = (x: Int,) => Exp$1() +//│ fun isEmpty = () -> Bool +//│ fun isEmpty = () => false +//│ } +//│ class E$2([]): Exp$1() { +//│ fun derive = (x,) => {new E$2([]) {}} +//│ fun isEmpty = () => {false} +//│ } +//│ class Ep$3([]): Exp$1() { +//│ fun derive = (x,) => {new E$2([]) {}} +//│ fun isEmpty = () => {true} +//│ } +//│ class Ch$4([i: Int,]): Exp$1() { +//│ fun derive = (x,) => {if (==(x, (this).i,)) then new Ep$3([]) {} else new E$2([]) {}} +//│ fun isEmpty = () => {false} +//│ } +//│ class A$5([e1: Exp, e2: Exp,]): Exp$1() { +//│ fun derive = (x,) => {new A$5([((this).e1).derive(x,), ((this).e2).derive(x,),]) {}} +//│ fun isEmpty = () => {||(((this).e1).isEmpty(), ((this).e2).isEmpty(),)} +//│ } +//│ class C$6([e1: Exp, e2: Exp,]): Exp$1() { +//│ fun derive = (x,) => {if (((this).e1).isEmpty()) then new A$5([new C$6([((this).e1).derive(x,), (this).e2,]) {}, ((this).e2).derive(x,),]) {} else new C$6([((this).e1).derive(x,), (this).e2,]) {}} +//│ fun isEmpty = () => {&&(((this).e1).isEmpty(), ((this).e2).isEmpty(),)} +//│ } +//│ Code(List((('(' new C$6([new Ch$4([1,]) {}, new A$5([new Ch$4([2,]) {}, new Ch$4([3,]) {},]) {},]) {} ')').derive(0,)).isEmpty())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$6() +//│ fun isEmpty$E$2(this) = +//│ false +//│ fun isEmpty$A$5(this) = +//│ ||(this.e1 match {case obj: Ch$4 => isEmpty$Ch$4(obj)}, this.e2 match {case obj: Ch$4 => isEmpty$Ch$4(obj)}) +//│ fun isEmpty$Ch$4(this) = +//│ false +//│ fun derive$A$5(this, x) = +//│ new A$5 (this.e1 match {case obj: Ch$4 => derive$Ch$4(obj, x)}, this.e2 match {case obj: Ch$4 => derive$Ch$4(obj, x)}) +//│ fun isEmpty$C$6(this) = +//│ &&(this.e1 match {case obj: Ep$3 => isEmpty$Ep$3(obj); case obj: E$2 => isEmpty$E$2(obj)}, this.e2 match {case obj: A$5 => isEmpty$A$5(obj)}) +//│ fun derive$C$6(this, x) = +//│ if this.e1 match {case obj: Ch$4 => isEmpty$Ch$4(obj)} then new A$5 (new C$6 (this.e1 match {case obj: Ch$4 => derive$Ch$4(obj, x)}, this.e2) , this.e2 match {case obj: A$5 => derive$A$5(obj, x)}) else new C$6 (this.e1 match {case obj: Ch$4 => derive$Ch$4(obj, x)}, this.e2) +//│ fun main$$6() = +//│ new C$6 (new Ch$4 (#1) , new A$5 (new Ch$4 (#2) , new Ch$4 (#3) ) ) match {case obj: C$6 => derive$C$6(obj, #0)} match {case obj: C$6 => isEmpty$C$6(obj)} +//│ fun derive$Ch$4(this, x) = +//│ if ==(x, this.i) then new Ep$3 () else new E$2 () +//│ fun isEmpty$Ep$3(this) = +//│ true +//│ class A$5(e1, e2): Exp$1() { +//│ } +//│ class E$2(): Exp$1() { +//│ } +//│ class C$6(e1, e2): Exp$1() { +//│ } +//│ class Ch$4(i): Exp$1() { +//│ } +//│ class Ep$3(): Exp$1() { +//│ } +//│ class Exp$1() { +//│ } +//│ class Exp() { +//│ fun derive: (x: Int) -> Exp +//│ fun isEmpty: () -> Bool +//│ } +//│ class E() extends Exp { +//│ fun derive: anything -> E +//│ fun isEmpty: () -> false +//│ } +//│ class Ep() extends Exp { +//│ fun derive: anything -> E +//│ fun isEmpty: () -> true +//│ } +//│ class Ch(i: Int) extends Exp { +//│ fun derive: Num -> (E | Ep) +//│ fun isEmpty: () -> false +//│ } +//│ class A(e1: Exp, e2: Exp) extends Exp { +//│ fun derive: Int -> A +//│ fun isEmpty: () -> Bool +//│ } +//│ class C(e1: Exp, e2: Exp) extends Exp { +//│ fun derive: Int -> (A | C) +//│ fun isEmpty: () -> Bool +//│ } +//│ Bool +//│ res +//│ = false + + +:mono +val anyUnknown = false +class List(l: List | Nil, hasTail: Bool) {} +class Nil(hasTail: Bool) {} +fun gen() = + if anyUnknown then new List(gen(), true) else new Nil(false) +gen() +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), anyUnknown, None, [], Var(false)), NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: Var(List), _: Var(Nil))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, gen, None, [], Lam(Tup(), Blk(...))), App(Var(gen), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([l: |(List, Nil,), hasTail: Bool,]) {} +//│ class Nil$2([hasTail: Bool,]) {} +//│ let anyUnknown$2 = () => false +//│ fun gen$1 = () => {if (anyUnknown) then new List$1([gen$1(), true,]) {} else new Nil$2([false,]) {}} +//│ Code(List(gen$1())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ fun anyUnknown$2() = +//│ false +//│ fun gen$1() = +//│ if anyUnknown then new List$1 (gen$1(), true) else new Nil$2 (false) +//│ fun main$$4() = +//│ gen$1() +//│ class Nil$2(hasTail) { +//│ } +//│ class List$1(l, hasTail) { +//│ } +//│ val anyUnknown: false +//│ class List(l: List | Nil, hasTail: Bool) +//│ class Nil(hasTail: Bool) +//│ fun gen: () -> (List | Nil) +//│ List | Nil +//│ anyUnknown +//│ = false +//│ res +//│ = Nil {} + + + +:mono +class Foo(x: Int){ + fun bar(y) = x+y + fun boo(z) = bar(z)+x +} +(new Foo(1)).boo(2) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(y)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, boo, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: App(Var(bar), Tup(_: Var(z))), _: Var(x))))))), App(Sel(Bra(rcd = false, New(Some((TypeName(Foo),[1,])), TypingUnit())), boo), Tup(_: IntLit(2)))) +//│ Lifted: +//│ TypingUnit { +//│ class Foo$1([x: Int,]) { +//│ fun bar = (y,) => +((this).x, y,) +//│ fun boo = (z,) => +((this).bar(z,), (this).x,) +//│ } +//│ Code(List(('(' new Foo$1([1,]) {} ')').boo(2,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun boo$Foo$1(this, z) = +//│ +(this match {case obj: Foo$1 => bar$Foo$1(obj, z)}, this.x) +//│ fun bar$Foo$1(this, y) = +//│ +(this.x, y) +//│ fun main$$1() = +//│ new Foo$1 (#1) match {case obj: Foo$1 => boo$Foo$1(obj, #2)} +//│ class Foo$1(x) { +//│ } +//│ class Foo(x: Int) { +//│ fun bar: Int -> Int +//│ fun boo: Int -> Int +//│ } +//│ Int +//│ res +//│ = 4 + +:mono +class OneInt(a: Int){ + fun fac: () -> Int + fun fac = () -> + if(a > 0) then (new OneInt(a - 1)).fac() else 1 +} +(new OneInt(10)).fac() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, fac, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, fac, None, [], Lam(Tup(), Blk(...))))), App(Sel(Bra(rcd = false, New(Some((TypeName(OneInt),[10,])), TypingUnit())), fac), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class OneInt$1([a: Int,]) { +//│ fun fac = () -> Int +//│ fun fac = () => {if ('(' >((this).a, 0,) ')') then ('(' new OneInt$1([-((this).a, 1,),]) {} ')').fac() else 1} +//│ } +//│ Code(List(('(' new OneInt$1([10,]) {} ')').fac())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun fac$OneInt$1(this) = +//│ if >(this.a, #0) then new OneInt$1 (-(this.a, #1)) match {case obj: OneInt$1 => fac$OneInt$1(obj)} else #1 +//│ fun main$$1() = +//│ new OneInt$1 (#10) match {case obj: OneInt$1 => fac$OneInt$1(obj)} +//│ class OneInt$1(a) { +//│ } +//│ class OneInt(a: Int) { +//│ fun fac: () -> Int +//│ } +//│ Int +//│ res +//│ = 1 + +//:mono +//:e // FIXME: Mutable Parameters +//trait AnyFoo { +//} +//class FooPlus(#a): AnyFoo { +// fun bar(b) = a + b +//} +//class FooMinus(#a): AnyFoo { +// fun bar(b) = a - b +//} +//fun f(x) = x.bar(42) +//f(new FooPlus(1)) +//f(new FooMinus(2)) + +:mono +val any = -20 +fun f(x) = + if x > any then 0 + else g(x - 1) +fun g(x) = + if x > any then g(x - 1) + else f(x - 2) +g(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), any, None, [], IntLit(-20)), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, g, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(g), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ let any$3 = () => -20 +//│ fun f$1 = (x,) => {if (>(x, any,)) then 0 else g$2(-(x, 1,),)} +//│ fun g$2 = (x,) => {if (>(x, any,)) then g$2(-(x, 1,),) else f$1(-(x, 2,),)} +//│ Code(List(g$2(1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$3() +//│ fun any$3() = +//│ #-20 +//│ fun f$1(x) = +//│ if >(x, any) then #0 else g$2(-(x, #1)) +//│ fun g$2(x) = +//│ if >(x, any) then g$2(-(x, #1)) else f$1(-(x, #2)) +//│ fun main$$3() = +//│ g$2(#1) +//│ val any: -20 +//│ fun f: Int -> 0 +//│ fun g: Int -> 0 +//│ 0 +//│ any +//│ = -20 +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:mono +class OneInt(a: Int){ + fun get = () -> a +} +class OneBool(b: Bool){ + fun get = () -> b +} +(if b then new OneInt(1) else new OneBool(true)).get() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, OneBool, (), Tup(b: Var(Bool)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(b))))), App(Sel(Bra(rcd = false, If(IfThen(Var(b), New(Some((TypeName(OneInt),[1,])), TypingUnit()), Some(New(Some((TypeName(OneBool),[true,])), TypingUnit())))), get), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class OneInt$1([a: Int,]) {fun get = () => (this).a} +//│ class OneBool$2([b: Bool,]) {fun get = () => (this).b} +//│ Code(List(('(' if (b) then new OneInt$1([1,]) {} else new OneBool$2([true,]) {} ')').get())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$2() +//│ fun get$OneInt$1(this) = +//│ this.a +//│ fun get$OneBool$2(this) = +//│ this.b +//│ fun main$$2() = +//│ if b then new OneInt$1 (#1) else new OneBool$2 (true) match {case obj: OneInt$1 => get$OneInt$1(obj); case obj: OneBool$2 => get$OneBool$2(obj)} +//│ class OneInt$1(a) { +//│ } +//│ class OneBool$2(b) { +//│ } +//│ class OneInt(a: Int) { +//│ fun get: () -> Int +//│ } +//│ class OneBool(b: Bool) { +//│ fun get: () -> Bool +//│ } +//│ Int | false | true +//│ res +//│ = true + +:mono +class Bar(x: Int) { + fun foo(x) = x + fun FooMinus(y: Int) = x + y + fun car = foo(2) +} +class Car { + fun da(b: Bar) = b.foo(2) +} +fun baz(b: Bar) = b.foo(2) +let bar = Bar(42) +baz(bar) +(new Car()).da(Bar(1337)) +bar.car +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Bar, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x))), NuFunDef(None, FooMinus, None, [], Lam(Tup(y: Var(Int)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, car, None, [], App(Var(foo), Tup(_: IntLit(2)))))), NuTypeDef(class, Car, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, da, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))))), NuFunDef(None, baz, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))), NuFunDef(Some(false), bar, None, [], App(Var(Bar), Tup(_: IntLit(42)))), App(Var(baz), Tup(_: Var(bar))), App(Sel(Bra(rcd = false, New(Some((TypeName(Car),[])), TypingUnit())), da), Tup(_: App(Var(Bar), Tup(_: IntLit(1337))))), Sel(Var(bar), car)) +//│ Lifted: +//│ TypingUnit { +//│ class Bar$1([x: Int,]) { +//│ fun foo = (x,) => x +//│ fun FooMinus = (y: Int,) => +((this).x, y,) +//│ fun car = () => (this).foo(2,) +//│ } +//│ class Car$2([]) {fun da = (b: Bar$1,) => (b).foo(2,)} +//│ fun baz$2 = (b: Bar$1,) => (b).foo(2,) +//│ let bar$1 = () => Bar$1(42,) +//│ Code(List(baz$2(bar,))) +//│ Code(List(('(' new Car$2([]) {} ')').da(Bar$1(1337,),))) +//│ Code(List((bar).car)) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ main$$5() +//│ main$$6() +//│ fun bar$1() = +//│ Bar$1(#42) +//│ fun da$Car$2(this, b) = +//│ b match {} +//│ fun main$$6() = +//│ bar.car +//│ fun baz$2(b) = +//│ b match {} +//│ fun main$$5() = +//│ new Car$2 () match {case obj: Car$2 => da$Car$2(obj, Bar$1(#1337))} +//│ fun main$$4() = +//│ baz$2(bar) +//│ class Bar$1(x) { +//│ } +//│ class Car$2() { +//│ } +//│ class Bar(x: Int) { +//│ fun FooMinus: (y: Int) -> Int +//│ fun car: 2 +//│ fun foo: forall 'a. 'a -> 'a +//│ } +//│ class Car { +//│ constructor() +//│ fun da: (b: Bar) -> 2 +//│ } +//│ fun baz: (b: Bar) -> 2 +//│ let bar: Bar +//│ 2 +//│ bar +//│ = Bar {} +//│ res +//│ = 2 +//│ res +//│ = 2 +//│ res +//│ = 2 + +:mono +val c = 5 +class Sup(a: Int){ + virtual fun foo = () -> a +} +class Sub(b: Int) extends Sup(b+b){ +} +class Sub2(c: Int) extends Sub(c+c){ + fun foo = () -> a+c +} +(new Sub(10)).foo() +(new Sub2(c)).foo() +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), c, None, [], IntLit(5)), NuTypeDef(class, Sup, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, Sub, (), Tup(b: Var(Int)), (App(Var(Sup), Tup(_: App(Var(+), Tup(_: Var(b), _: Var(b)))))), None, None, TypingUnit()), NuTypeDef(class, Sub2, (), Tup(c: Var(Int)), (App(Var(Sub), Tup(_: App(Var(+), Tup(_: Var(c), _: Var(c)))))), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(a), _: Var(c))))))), App(Sel(Bra(rcd = false, New(Some((TypeName(Sub),[10,])), TypingUnit())), foo), Tup()), App(Sel(Bra(rcd = false, New(Some((TypeName(Sub2),[c,])), TypingUnit())), foo), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Sup$1([a: Int,]) {fun foo = () => (this).a} +//│ class Sub$2([b: Int,]): Sup$1(+((this).b, (this).b,),) {} +//│ class Sub2$3([c: Int,]): Sub$2(+((this).c, (this).c,),) {fun foo = () => +((this).a, (this).c,)} +//│ let c$1 = () => 5 +//│ Code(List(('(' new Sub$2([10,]) {} ')').foo())) +//│ Code(List(('(' new Sub2$3([c,]) {} ')').foo())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ main$$5() +//│ fun c$1() = +//│ #5 +//│ fun main$$5() = +//│ new Sub2$3 (c) match {case obj: Sub2$3 => foo$Sub2$3(obj)} +//│ fun main$$4() = +//│ new Sub$2 (#10) match {case obj: Sub$2 => foo$Sup$1(obj)} +//│ fun foo$Sup$1(this) = +//│ this.a +//│ fun foo$Sub2$3(this) = +//│ +(this.a, this.c) +//│ class Sub2$3(c): Sub$2(+(this.c, this.c)) { +//│ } +//│ class Sup$1(a) { +//│ } +//│ class Sub$2(b): Sup$1(+(this.b, this.b)) { +//│ } +//│ val c: 5 +//│ class Sup(a: Int) { +//│ fun foo: () -> Int +//│ } +//│ class Sub(b: Int) extends Sup { +//│ fun foo: () -> Int +//│ } +//│ class Sub2(c: Int) extends Sub, Sup { +//│ fun foo: () -> Int +//│ } +//│ Int +//│ c +//│ = 5 +//│ res +//│ = 20 +//│ res +//│ = 47 + +:mono +class Foo(f: Int -> Int){ + fun foo = () -> f(1) +} +class F1() extends Foo(x => x+1){} +class F2() extends Foo(x => x+2){} +(new F1()).foo() +(new F2()).foo() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(f: App(Var(->), Tup(_: Var(Int), _: Var(Int)))), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(f), Tup(_: IntLit(1))))))), NuTypeDef(class, F1, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))), None, None, TypingUnit()), NuTypeDef(class, F2, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))))), None, None, TypingUnit()), App(Sel(Bra(rcd = false, New(Some((TypeName(F1),[])), TypingUnit())), foo), Tup()), App(Sel(Bra(rcd = false, New(Some((TypeName(F2),[])), TypingUnit())), foo), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Foo$1([f: ->(Int, Int,),]) {fun foo = () => (this).f(1,)} +//│ class F1$2_Lambda1$1$4([par$F1$2,]) {fun apply = (x,) => +(x, 1,)} +//│ class F1$2([]): Foo$1({new F1$2_Lambda1$1$4([this,]) {}},) {} +//│ class F2$3_Lambda1$2$5([par$F2$3,]) {fun apply = (x,) => +(x, 2,)} +//│ class F2$3([]): Foo$1({new F2$3_Lambda1$2$5([this,]) {}},) {} +//│ Code(List(('(' new F1$2([]) {} ')').foo())) +//│ Code(List(('(' new F2$3([]) {} ')').foo())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ main$$6() +//│ fun apply$F2$3_Lambda1$2$5(this, x) = +//│ +(x, #2) +//│ fun foo$Foo$1(this) = +//│ this match {case obj: Foo$1 => obj.f match {case obj$F2$3_Lambda1$2$5: F2$3_Lambda1$2$5 => apply$F2$3_Lambda1$2$5(obj$F2$3_Lambda1$2$5, #1); case obj$F1$2_Lambda1$1$4: F1$2_Lambda1$1$4 => apply$F1$2_Lambda1$1$4(obj$F1$2_Lambda1$1$4, #1)}} +//│ fun main$$6() = +//│ new F2$3 () match {case obj: F2$3 => foo$Foo$1(obj)} +//│ fun main$$5() = +//│ new F1$2 () match {case obj: F1$2 => foo$Foo$1(obj)} +//│ fun apply$F1$2_Lambda1$1$4(this, x) = +//│ +(x, #1) +//│ class F1$2(): Foo$1(new F1$2_Lambda1$1$4 (this) ) { +//│ } +//│ class F2$3_Lambda1$2$5(par$F2$3) { +//│ } +//│ class F2$3(): Foo$1(new F2$3_Lambda1$2$5 (this) ) { +//│ } +//│ class Foo$1(f) { +//│ } +//│ class F1$2_Lambda1$1$4(par$F1$2) { +//│ } +//│ class Foo(f: Int -> Int) { +//│ fun foo: () -> Int +//│ } +//│ class F1() extends Foo { +//│ fun foo: () -> Int +//│ } +//│ class F2() extends Foo { +//│ fun foo: () -> Int +//│ } +//│ Int +//│ res +//│ = 2 +//│ res +//│ = 3 diff --git a/compiler/shared/test/scala/mlscript/compiler/Test.scala b/compiler/shared/test/scala/mlscript/compiler/Test.scala index df325ec59c..e0df0d8f00 100644 --- a/compiler/shared/test/scala/mlscript/compiler/Test.scala +++ b/compiler/shared/test/scala/mlscript/compiler/Test.scala @@ -1,10 +1,14 @@ -package mlscript -package compiler +package mlscript.compiler import mlscript.utils.shorthands.* import scala.util.control.NonFatal import scala.collection.mutable.StringBuilder import mlscript.codegen.Helpers.inspect as showStructure +import mlscript.{DiffTests, ModeType, TypingUnit} +import mlscript.compiler.debug.TreeDebug +import mlscript.compiler.mono.Monomorph +import mlscript.compiler.printer.ExprPrinter +import mlscript.compiler.mono.MonomorphError class DiffTestCompiler extends DiffTests { import DiffTestCompiler.* @@ -16,13 +20,28 @@ class DiffTestCompiler extends DiffTests { outputBuilder ++= "\nLifted:\n" var rstUnit = unit; try - rstUnit = ClassLifter().liftTypingUnit(unit) + rstUnit = ClassLifter(mode.fullExceptionStack).liftTypingUnit(unit) outputBuilder ++= PrettyPrinter.showTypingUnit(rstUnit) catch case NonFatal(err) => outputBuilder ++= "Lifting failed: " ++ err.toString() - if mode.fullExceptionStack then outputBuilder ++= - "\n" ++ err.getStackTrace().map(_.toString()).mkString("\n") + if mode.fullExceptionStack then + outputBuilder ++= "\n" ++ err.getStackTrace().map(_.toString()).mkString("\n") + if(mode.mono){ + outputBuilder ++= "\nMono:\n" + val treeDebug = new TreeDebug() + try{ + val monomorph = new Monomorph(treeDebug) + val monomorphized = monomorph.defunctionalize(rstUnit) + outputBuilder ++= "\nDefunc result: \n" + outputBuilder ++= ExprPrinter.print(monomorphized) + outputBuilder ++= "\n" + }catch{ + case error: MonomorphError => outputBuilder ++= (error.getMessage() :: error.getStackTrace().map(_.toString()).toList).mkString("\n") + // case error: StackOverflowError => outputBuilder ++= (error.getMessage() :: error.getStackTrace().take(40).map(_.toString()).toList).mkString("\n") + } + // outputBuilder ++= treeDebug.getLines.mkString("\n") + } outputBuilder.toString().linesIterator.toList override protected lazy val files = allFiles.filter { file => diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 96b4114479..2ffcbdcf9d 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -49,7 +49,7 @@ object Helpers { val elems = fs.map{case L(l) => s"...${inspect(l)}" case R(Fld(_, r)) => inspect(r)}.mkString(", ") s"Splc($elems)" case If(bod, els) => s"If(${inspect(bod)}, ${els.map(inspect)})" - case New(base, body) => s"New(${base}, ${body})" + case New(base, body) => s"New(${base}, ${inspect(body)})" case TyApp(base, targs) => s"TyApp(${inspect(base)}, ${targs})" case Def(rec, nme, rhs, isByname) => s"Def($rec, $nme, ${rhs.fold(inspect, "" + _)}, $isByname)" diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 686694824c..07b66ff054 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -39,6 +39,7 @@ abstract class ModeType { def expectCodeGenErrors: Bool def showRepl: Bool def allowEscape: Bool + def mono: Bool } class DiffTests @@ -163,13 +164,14 @@ class DiffTests expectCodeGenErrors: Bool = false, showRepl: Bool = false, allowEscape: Bool = false, + mono: Bool = false, // noProvs: Bool = false, ) extends ModeType { def isDebugging: Bool = dbg || dbgSimplif } val defaultMode = Mode() - var parseOnly = basePath.headOption.contains("parser") || basePath.headOption.contains("compiler") + var parseOnly = basePath.headOption.contains("parser") var allowTypeErrors = false var allowParseErrors = false var showRelativeLineNums = false @@ -260,6 +262,7 @@ class DiffTests case "re" => mode.copy(expectRuntimeErrors = true) case "r" | "showRepl" => mode.copy(showRepl = true) case "escape" => mode.copy(allowEscape = true) + case "mono" => {mode.copy(mono = true)} case "exit" => out.println(exitMarker) ls.dropWhile(_ =:= exitMarker).tails.foreach { From 74d13f2c429e4eee9b5a17493ad67e84e8a7a1ca Mon Sep 17 00:00:00 2001 From: HarrisL2 Date: Tue, 24 Oct 2023 02:03:53 +0800 Subject: [PATCH 481/498] Fix parenthesization for binary operators (#189) Co-authored-by: Lionel Parreaux --- .../src/main/scala/mlscript/JSBackend.scala | 6 ++ .../main/scala/mlscript/codegen/Codegen.scala | 5 ++ .../src/test/diff/codegen/NuParentheses.mls | 61 +++++++++++++++++++ shared/src/test/diff/nu/UnaryMinus.mls | 4 +- 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 shared/src/test/diff/codegen/NuParentheses.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 3ee699d065..9ea71bf8ef 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -277,6 +277,12 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { name -> translateTerm(value) }) :: Nil ) + // Only parenthesize binary operators + // Custom operators do not need special handling since they are desugared to plain methods + case Bra(false, trm) => trm match { + case App(Var(op), _) if JSBinary.operators.contains(op) => JSParenthesis(translateTerm(trm)) + case trm => translateTerm(trm) + } case Bra(_, trm) => translateTerm(trm) case Tup(terms) => JSArray(terms map { case (_, Fld(_, term)) => translateTerm(term) }) diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 0639db3b74..3efacdef7e 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -924,6 +924,11 @@ final case class JSComment(text: Str) extends JSStmt { def toSourceCode: SourceCode = SourceCode(s"// $text") } +final case class JSParenthesis(exp: JSExpr) extends JSExpr { + implicit def precedence: Int = 0 + def toSourceCode: SourceCode = exp.embed +} + object JSCodeHelpers { def id(name: Str): JSIdent = JSIdent(name) def lit(value: Int): JSLit = JSLit(value.toString()) diff --git a/shared/src/test/diff/codegen/NuParentheses.mls b/shared/src/test/diff/codegen/NuParentheses.mls new file mode 100644 index 0000000000..356a47a2fd --- /dev/null +++ b/shared/src/test/diff/codegen/NuParentheses.mls @@ -0,0 +1,61 @@ +:NewDefs + + +:js +16 / (2 / 2) +//│ Num +//│ // Prelude +//│ let res; +//│ class TypingUnit {} +//│ const typing_unit = new TypingUnit; +//│ // Query 1 +//│ res = 16 / (2 / 2); +//│ // End of generated code +//│ res +//│ = 16 + +:js +1 - (3 - 5) +//│ Int +//│ // Prelude +//│ class TypingUnit1 {} +//│ const typing_unit1 = new TypingUnit1; +//│ // Query 1 +//│ res = 1 - (3 - 5); +//│ // End of generated code +//│ res +//│ = 3 + + +fun (--) minusminus(a, b) = a - b +//│ fun (--) minusminus: (Int, Int) -> Int + +:js +1 -- (3 -- 5) +//│ Int +//│ // Prelude +//│ class TypingUnit3 {} +//│ const typing_unit3 = new TypingUnit3; +//│ // Query 1 +//│ res = minusminus(1, minusminus(3, 5)); +//│ // End of generated code +//│ res +//│ = 3 + + +fun (-+-) complex(a, b) = a - 2*b +//│ fun (-+-) complex: (Int, Int) -> Int + +:js +1 -+- (3 -+- 5) +//│ Int +//│ // Prelude +//│ class TypingUnit5 {} +//│ const typing_unit5 = new TypingUnit5; +//│ // Query 1 +//│ res = complex(1, complex(3, 5)); +//│ // End of generated code +//│ res +//│ = 15 + + diff --git a/shared/src/test/diff/nu/UnaryMinus.mls b/shared/src/test/diff/nu/UnaryMinus.mls index 389426bfe5..bb0341d0a3 100644 --- a/shared/src/test/diff/nu/UnaryMinus.mls +++ b/shared/src/test/diff/nu/UnaryMinus.mls @@ -28,7 +28,7 @@ 1 - (3 - 5) //│ Int //│ res -//│ = -7 +//│ = 3 3 - 1 //│ Int @@ -53,7 +53,7 @@ 1 - (1 - 1) //│ Int //│ res -//│ = -1 +//│ = 1 1 - 1 //│ Int From 1d3811c77559efb57c031f6cb8327e587e93c3cf Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 22 Nov 2023 23:08:22 +0800 Subject: [PATCH 482/498] Allow selecting tuple by integer indices (#192) * Modify lexer, parsers & typer to allow selecting tuple by indices * Do not enclose field names in quotes if they are integers * Do not use integer fields as name hints --- shared/src/main/scala/mlscript/MLParser.scala | 10 +- shared/src/main/scala/mlscript/NewLexer.scala | 21 +- .../src/main/scala/mlscript/NewParser.scala | 4 + shared/src/main/scala/mlscript/Parser.scala | 9 +- .../main/scala/mlscript/TypeSimplifier.scala | 14 +- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- .../main/scala/mlscript/TyperHelpers.scala | 9 +- .../main/scala/mlscript/codegen/Codegen.scala | 8 +- shared/src/main/scala/mlscript/helpers.scala | 8 + shared/src/test/diff/basics/Intersections.fun | 2 +- shared/src/test/diff/basics/Tuples.fun | 42 ++-- shared/src/test/diff/basics/Unions.fun | 28 +-- shared/src/test/diff/codegen/Terms.mls | 20 +- .../test/diff/ecoop23/PolymorphicVariants.mls | 20 +- shared/src/test/diff/fcp/PolyParams.mls | 8 +- shared/src/test/diff/fcp/Skolems2.mls | 6 +- .../mlf-examples/variations_ex_hashtbl.mls | 10 +- shared/src/test/diff/mlscript/DavidB.mls | 2 +- shared/src/test/diff/mlscript/LetPolym.mls | 63 +++--- shared/src/test/diff/mlscript/MLTuples.mls | 42 ++-- shared/src/test/diff/mlscript/Mut.mls | 168 ++++++++-------- shared/src/test/diff/mlscript/Mut2.mls | 40 ++-- .../diff/mlscript/PolyVariantCodeReuse.mls | 66 +++---- shared/src/test/diff/mlscript/SelfNeg.mls | 2 +- shared/src/test/diff/mlscript/SelfNegs.mls | 2 +- shared/src/test/diff/mlscript/This.mls | 14 +- .../test/diff/mlscript/TrickyExtrusion.mls | 52 ++--- shared/src/test/diff/mlscript/TupleArray.mls | 184 +++++++++--------- shared/src/test/diff/mlscript/TupleArray2.mls | 14 +- shared/src/test/diff/mlscript/Yicong.mls | 97 +++++---- shared/src/test/diff/nu/Ascription.mls | 17 +- shared/src/test/diff/nu/BasicMixins.mls | 6 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 2 +- shared/src/test/diff/nu/Interfaces.mls | 8 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 22 +-- shared/src/test/diff/nu/Tuples.mls | 118 +++++++++++ shared/src/test/diff/nu/WeirdUnions.mls | 4 +- 38 files changed, 637 insertions(+), 509 deletions(-) create mode 100644 shared/src/test/diff/nu/Tuples.mls diff --git a/shared/src/main/scala/mlscript/MLParser.scala b/shared/src/main/scala/mlscript/MLParser.scala index b9a0e8223a..1ccd068632 100644 --- a/shared/src/main/scala/mlscript/MLParser.scala +++ b/shared/src/main/scala/mlscript/MLParser.scala @@ -41,6 +41,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { def number[p: P]: P[Int] = P( CharIn("0-9").repX(1).!.map(_.toInt) ) def ident[p: P]: P[String] = P( (letter | "_") ~~ (letter | digit | "_" | "'").repX ).!.filter(!keywords(_)) + def index[p: P]: P[String] = P( "0" | CharIn("1-9") ~~ digit.repX ).!.map(_.toString) def termOrAssign[p: P]: P[Statement] = P( term ~ ("=" ~ term).? ).map { case (expr, N) => expr @@ -58,6 +59,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { | P(kw("undefined")).map(x => UnitLit(true)) | P(kw("null")).map(x => UnitLit(false))) def variable[p: P]: P[Var] = locate(ident.map(Var)) + def fieldName[p: P]: P[Var] = locate( (ident | index).map(Var) ) def parenCell[p: P]: P[Either[Term, (Term, Boolean)]] = (("..." | kw("mut")).!.? ~ term).map { case (Some("..."), t) => Left(t) @@ -83,7 +85,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { def subterm[p: P]: P[Term] = P( Index ~~ subtermNoSel ~ ( // Fields: - ("." ~/ (variable | locate(("(" ~/ ident ~ "." ~ ident ~ ")") + ("." ~/ (fieldName | locate(("(" ~/ ident ~ "." ~ ident ~ ")") .map {case (prt, id) => Var(s"${prt}.${id}")}))) .map {(t: Var) => Left(t)} | // Array subscripts: @@ -101,7 +103,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { } def record[p: P]: P[Rcd] = locate(P( - "{" ~/ (kw("mut").!.? ~ variable ~ "=" ~ term map L.apply).|(kw("mut").!.? ~ + "{" ~/ (kw("mut").!.? ~ fieldName ~ "=" ~ term map L.apply).|(kw("mut").!.? ~ variable map R.apply).rep(sep = ";" | ",") ~ "}" ).map { fs => Rcd(fs.map{ case L((mut, v, t)) => v -> Fld(FldFlags(mut.isDefined, false, false), t) @@ -253,7 +255,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { // Note: field removal types are not supposed to be explicitly used by programmers, // and they won't work in negative positions, // but parsing them is useful in tests (such as shared/src/test/diff/mlscript/Annoying.mls) - def tyNoFun[p: P]: P[Type] = P( (rcd | ctor | parTy) ~ ("\\" ~ variable).rep(0) ) map { + def tyNoFun[p: P]: P[Type] = P( (rcd | ctor | parTy) ~ ("\\" ~ fieldName).rep(0) ) map { case (ty, Nil) => ty case (ty, ids) => Rem(ty, ids.toList) } @@ -270,7 +272,7 @@ class MLParser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { )) def tyWild[p: P]: P[Bounds] = locate(P("?".! map (_ => Bounds(Bot, Top)))) def rcd[p: P]: P[Record] = - locate(P( "{" ~/ ( kw("mut").!.? ~ variable ~ ":" ~ ty).rep(sep = ";") ~ "}" ) + locate(P( "{" ~/ ( kw("mut").!.? ~ fieldName ~ ":" ~ ty).rep(sep = ";") ~ "}" ) .map(_.toList.map { case (None, v, t) => v -> Field(None, t) case (Some(_), v, t) => v -> Field(Some(t), t) diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 2bd9f0e614..f5ac326297 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -169,10 +169,23 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { lex(j, ind, next(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n)))) case _ if isOpChar(c) => val (n, j) = takeWhile(i)(isOpChar) - if (n === "." && j < length && isIdentFirstChar(bytes(j))) { - val (name, k) = takeWhile(j)(isIdentChar) - // go(k, SELECT(name)) - lex(k, ind, next(k, SELECT(name))) + if (n === "." && j < length) { + val nc = bytes(j) + if (isIdentFirstChar(nc)) { + val (name, k) = takeWhile(j)(isIdentChar) + // go(k, SELECT(name)) + lex(k, ind, next(k, SELECT(name))) + } + else if ( + // The first character is '0' and the next character is not a digit + (nc === '0' && !(j + 1 < length && isDigit(bytes(j + 1)))) || + ('0' < nc && nc <= '9') // The first character is a digit other than '0' + ) { + val (name, k) = takeWhile(j)(isDigit) + // go(k, SELECT(name)) + lex(k, ind, next(k, SELECT(name))) + } + else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) } // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 22be9ea17b..f0a38600aa 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -1173,6 +1173,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo consume consume S(Var(idStr).withLoc(S(l0))) + case (LITVAL(IntLit(i)), l0) :: (KEYWORD(":"), _) :: _ => // TODO: | ... + consume + consume + S(Var(i.toString).withLoc(S(l0))) case _ => N } // val e = expr(NoElsePrec) -> argMut.isDefined diff --git a/shared/src/main/scala/mlscript/Parser.scala b/shared/src/main/scala/mlscript/Parser.scala index ba61c790bf..3895efd95f 100644 --- a/shared/src/main/scala/mlscript/Parser.scala +++ b/shared/src/main/scala/mlscript/Parser.scala @@ -39,13 +39,18 @@ class Parser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { def NAME[p: P]: P[Var] = locate(ident.map(Var(_))) - def ident[p: P] = Lexer.identifier | "(" ~ operator.! ~ ")" + def ident[p: P]: P[String] = Lexer.identifier | "(" ~ operator.! ~ ")" def NUMBER[p: P]: P[Lit] = locate( P( Lexer.longinteger | Lexer.integer ).map(IntLit) | P( Lexer.floatnumber ).map(DecLit) ) def STRING[p: P]: P[StrLit] = locate(Lexer.stringliteral.map(StrLit(_))) + + def FIELD[p: P]: P[Var] = locate( + P( Lexer.identifier ).map(Var(_)) | + P( Lexer.decimalinteger ).map(n => Var(n.toString)) + ) def expr[p: P]: P[Term] = P( ite | basicExpr ).opaque("expression") @@ -174,7 +179,7 @@ class Parser(origin: Origin, indent: Int = 0, recordLocations: Bool = true) { case (as, ao) => (as ++ ao.toList).reduceLeft((f, a) => App(f, toParams(a))) } - def atomOrSelect[p: P]: P[Term] = P(atom ~ (Index ~~ "." ~ NAME ~~ Index).rep).map { + def atomOrSelect[p: P]: P[Term] = P(atom ~ (Index ~~ "." ~ FIELD ~~ Index).rep).map { case (lhs, sels) => sels.foldLeft(lhs) { case (acc, (i0,str,i1)) => Sel(lhs, str).withLoc(i0, i1, origin) } diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index f50c8285e5..f2a4b297bf 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -411,20 +411,10 @@ trait TypeSimplifier { self: Typer => val arity = fs.size val (componentFields, rcdFields) = rcd.fields .filterNot(traitPrefixes contains _._1.name.takeWhile(_ =/= '#')) - .partitionMap(f => - if (f._1.name.length > 1 && f._1.name.startsWith("_")) { - val namePostfix = f._1.name.tail - if (namePostfix.forall(_.isDigit)) { - val index = namePostfix.toInt - if (index <= arity && index > 0) L(index -> f._2) - else R(f) - } - else R(f) - } else R(f) - ) + .partitionMap(f => f._1.toIndexOption.filter((0 until arity).contains).map(_ -> f._2).toLeft(f)) val componentFieldsMap = componentFields.toMap val tupleComponents = fs.iterator.zipWithIndex.map { case ((nme, ty), i) => - nme -> (ty && componentFieldsMap.getOrElse(i + 1, TopType.toUpper(noProv))).update(go(_, pol.map(!_)), go(_, pol)) + nme -> (ty && componentFieldsMap.getOrElse(i, TopType.toUpper(noProv))).update(go(_, pol.map(!_)), go(_, pol)) }.toList S(TupleType(tupleComponents)(tt.prov)) -> rcdFields.mapValues(_.update(go(_, pol.map(!_)), go(_, pol))) case S(ct: ClassTag) => S(ct) -> nFields diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 0558bc35d0..3b11dfca25 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1101,7 +1101,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne // Returns a function expecting an additional argument of type `Class` before the method arguments def rcdSel(obj: Term, fieldName: Var) = { val o_ty = typeMonomorphicTerm(obj) - val res = freshVar(prov, N, Opt.when(!fieldName.name.startsWith("_"))(fieldName.name)) + val res = freshVar(prov, N, Opt.when(!fieldName.name.startsWith("_") && !fieldName.isIndex)(fieldName.name)) val obj_ty = mkProxy(o_ty, tp(obj.toCoveringLoc, "receiver")) val rcd_ty = RecordType.mk( fieldName -> res.toUpper(tp(fieldName.toLoc, "field selector")) :: Nil)(prov) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index fae7992dc3..121184b93a 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -269,7 +269,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => lazy val toArray: ArrayType = ArrayType(inner)(prov) // upcast to array override lazy val toRecord: RecordType = RecordType( - fields.zipWithIndex.map { case ((_, t), i) => (Var("_"+(i+1)), t) } + fields.zipWithIndex.map { case ((_, t), i) => (Var(i.toString), t) } // Note: In line with TypeScript, tuple field names are pure type system fictions, // with no runtime existence. Therefore, they should not be included in the record type // corresponding to this tuple type. diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index d73bfc9f7b..727b0001c7 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -604,14 +604,7 @@ abstract class TyperHelpers { Typer: Typer => case t @ RecordType(fs) => RecordType(fs.filter(nt => !names(nt._1)))(t.prov) case t @ TupleType(fs) => val relevantNames = names.filter(n => - n.name.startsWith("_") - && { - val t = n.name.tail - t.forall(_.isDigit) && { - val n = t.toInt - 1 <= n && n <= fs.length - } - }) + n.toIndexOption.exists((0 until fs.length).contains)) if (relevantNames.isEmpty) t else { val rcd = t.toRecord diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 3efacdef7e..9a785cfc10 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -605,9 +605,11 @@ class JSField(`object`: JSExpr, val property: JSIdent) extends JSMember(`object` ) ++ SourceCode( if (JSField.isValidFieldName(property.name)) { s".${property.name}" - } else { - s"[${JSLit.makeStringLiteral(property.name)}]" - } + } else + property.name.toIntOption match { + case S(index) => s"[$index]" + case N => s"[${JSLit.makeStringLiteral(property.name)}]" + } ) } diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index c6061ce28d..a6e2784f46 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -715,6 +715,14 @@ trait LitImpl { self: Lit => } trait VarImpl { self: Var => + /** Check if the variable name is an integer. */ + def isIndex: Bool = name.headOption match { + case S('0') => name.length === 1 + case S(_) => name.forall(_.isDigit) + case N => false + } + /** Get the integer if it's a valid index. */ + def toIndexOption: Opt[Int] = if (isIndex) name.toIntOption else N def isPatVar: Bool = (name.head.isLetter && name.head.isLower || name.head === '_' || name.head === '$') && name =/= "true" && name =/= "false" def toVar: Var = this diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index 95d264faf1..4bbdaa0f74 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -6,7 +6,7 @@ let foo = _ as (_: (Int => Int) & (Bool => Bool)) :ns let foo = _ as (_: (Int => Int) & (Bool => Bool)) -let foo = (_ as (_: (Int => Int) & (Bool => Bool)))._1 +let foo = (_ as (_: (Int => Int) & (Bool => Bool))).0 //│ foo: forall 'a. (_: 'a,) //│ where //│ 'a <: int -> int & bool -> bool diff --git a/shared/src/test/diff/basics/Tuples.fun b/shared/src/test/diff/basics/Tuples.fun index 0ae793a335..4df4ecdb82 100644 --- a/shared/src/test/diff/basics/Tuples.fun +++ b/shared/src/test/diff/basics/Tuples.fun @@ -15,40 +15,26 @@ let t = x: 1, y: 2, z: 3 //│ t: (1, y: 2, 3,) //│ t: (x: 1, y: 2, z: 3,) -(1, true, "hey")._2 -(1, true, "hey")._3 +(1, true, "hey").1 +(1, true, "hey").2 //│ res: true //│ res: "hey" :e -(1, true, "hey")._4 +(1, true, "hey").3 //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.24: (1, true, "hey")._4 -//│ ║ ^^^ -//│ ╟── tuple of type `{_1: 1, _2: true, _3: "hey"}` does not have field '_4' -//│ ║ l.24: (1, true, "hey")._4 +//│ ║ l.24: (1, true, "hey").3 +//│ ║ ^^ +//│ ╟── tuple of type `{0: 1, 1: true, 2: "hey"}` does not have field '3' +//│ ║ l.24: (1, true, "hey").3 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── but it flows into receiver with expected type `{_4: ?a}` -//│ ║ l.24: (1, true, "hey")._4 +//│ ╟── but it flows into receiver with expected type `{3: ?a}` +//│ ║ l.24: (1, true, "hey").3 //│ ╙── ^^^^^^^^^^^^^^^^ //│ res: error -:p -:e -(1, true, "hey").2 -//│ Parsed: '(' {[1, true, "hey",]} ')'(...0.2); -//│ Desugared: '(' {[1, true, "hey",]} ')'(...0.2) -//│ AST: App(Bra(rcd = false, Blk(...)), DecLit(0.2)) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.38: (1, true, "hey").2 -//│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── tuple of type `(1, true, "hey",)` is not a function -//│ ║ l.38: (1, true, "hey").2 -//│ ║ ^^^^^^^^^^^^^^ -//│ ╟── but it flows into applied expression with expected type `0.2 -> ?a` -//│ ║ l.38: (1, true, "hey").2 -//│ ╙── ^^^^^^^^^^^^^^^^ -//│ res: error +(1, true, "hey").1 +//│ res: true :w let not-tup = ( @@ -56,7 +42,7 @@ let not-tup = ( 2 ) //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.55: 1 +//│ ║ l.41: 1 //│ ╙── ^ //│ not-tup: 2 @@ -66,7 +52,7 @@ let tup = ( 2 ) //│ ╔══[WARNING] Previous field definitions are discarded by this returned expression. -//│ ║ l.66: 2 +//│ ║ l.52: 2 //│ ╙── ^ //│ tup: 2 @@ -76,7 +62,7 @@ let tup = 2, 3 //│ ╔══[WARNING] Previous field definitions are discarded by this returned expression. -//│ ║ l.77: 3 +//│ ║ l.63: 3 //│ ╙── ^ //│ tup: 3 diff --git a/shared/src/test/diff/basics/Unions.fun b/shared/src/test/diff/basics/Unions.fun index 88b43723b5..b693f8afa4 100644 --- a/shared/src/test/diff/basics/Unions.fun +++ b/shared/src/test/diff/basics/Unions.fun @@ -145,7 +145,7 @@ x => foo { v: x } // Notice that in MLscript, `(0, 0) | (1, 1)` is equivalent to `(0 | 1, 0 | 1)` -let bar(r: (0, 0) | (1, 1)) = if r._1 < 1 then r._1 else r._2 +let bar(r: (0, 0) | (1, 1)) = if r.0 < 1 then r.0 else r.1 //│ bar: (r: ('a & (0 | 1), 'a & (0 | 1),),) -> 'a bar(0, 1) @@ -221,25 +221,25 @@ x => bar(bar(x, 1), 0) //│ res: ('a & (0 | 1), 'a & (0 | 1),) -> (0 | 'a) -let baz(r: (0, 0) | _) = if r._1 < 1 then r._1 else r._2 -//│ baz: (r: {_1: number & 'a, _2: 'a},) -> 'a +let baz(r: (0, 0) | _) = if r.0 < 1 then r.0 else r.1 +//│ baz: (r: {0: number & 'a, 1: 'a},) -> 'a :e baz(0) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.228: baz(0) //│ ║ ^^^^^^ -//│ ╟── integer literal of type `0` does not have field '_2' +//│ ╟── integer literal of type `0` does not have field '1' //│ ║ l.228: baz(0) //│ ║ ^ -//│ ╟── but it flows into argument with expected type `{_2: ?a}` +//│ ╟── but it flows into argument with expected type `{1: ?a}` //│ ║ l.228: baz(0) //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.224: let baz(r: (0, 0) | _) = if r._1 < 1 then r._1 else r._2 -//│ ║ ^^^ +//│ ║ l.224: let baz(r: (0, 0) | _) = if r.0 < 1 then r.0 else r.1 +//│ ║ ^^ //│ ╟── from binding: -//│ ║ l.224: let baz(r: (0, 0) | _) = if r._1 < 1 then r._1 else r._2 +//│ ║ l.224: let baz(r: (0, 0) | _) = if r.0 < 1 then r.0 else r.1 //│ ╙── ^^^^^^^^^^^^^ //│ res: error @@ -260,7 +260,7 @@ x => baz(x, x) //│ res: (number & 'a, 'a,) -> 'a -let baz(r: (0, 0) | (1, _)) = if r._1 < 1 then r._1 else r._2 +let baz(r: (0, 0) | (1, _)) = if r.0 < 1 then r.0 else r.1 //│ baz: (r: ('a & (0 | 1), 'a,),) -> 'a :e @@ -269,17 +269,17 @@ baz(0, 1) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.267: baz(0) //│ ║ ^^^^^^ -//│ ╟── integer literal of type `0` does not have field '_2' +//│ ╟── integer literal of type `0` does not have field '1' //│ ║ l.267: baz(0) //│ ║ ^ -//│ ╟── but it flows into argument with expected type `{_2: ?a}` +//│ ╟── but it flows into argument with expected type `{1: ?a}` //│ ║ l.267: baz(0) //│ ║ ^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.263: let baz(r: (0, 0) | (1, _)) = if r._1 < 1 then r._1 else r._2 -//│ ║ ^^^ +//│ ║ l.263: let baz(r: (0, 0) | (1, _)) = if r.0 < 1 then r.0 else r.1 +//│ ║ ^^ //│ ╟── from binding: -//│ ║ l.263: let baz(r: (0, 0) | (1, _)) = if r._1 < 1 then r._1 else r._2 +//│ ║ l.263: let baz(r: (0, 0) | (1, _)) = if r.0 < 1 then r.0 else r.1 //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ res: error //│ res: 0 | 1 diff --git a/shared/src/test/diff/codegen/Terms.mls b/shared/src/test/diff/codegen/Terms.mls index 221227c531..1df094b5a1 100644 --- a/shared/src/test/diff/codegen/Terms.mls +++ b/shared/src/test/diff/codegen/Terms.mls @@ -413,12 +413,12 @@ t1 = (mut "hello", mut true) //│ = [ 'hello', true ] :js -t1._1 <- "bye" -t1._1 +t1.0 <- "bye" +t1.0 //│ // Query 1 -//│ res = (t1["_1"] = "bye", []); +//│ res = (t1[0] = "bye", []); //│ // Query 2 -//│ res = t1["_1"]; +//│ res = t1[0]; //│ // End of generated code //│ = [] //│ res: "hello" @@ -480,20 +480,20 @@ xpp a1 :js tu = (mut (), mut 2) -tu._1 <- (tu._2 <- 3) -tu._1 -tu._2 +tu.0 <- (tu.1 <- 3) +tu.0 +tu.1 //│ // Query 1 //│ globalThis.tu = [ //│ [], //│ 2 //│ ]; //│ // Query 2 -//│ res = (tu["_1"] = (tu["_2"] = 3, []), []); +//│ res = (tu[0] = (tu[1] = 3, []), []); //│ // Query 3 -//│ res = tu["_1"]; +//│ res = tu[0]; //│ // Query 4 -//│ res = tu["_2"]; +//│ res = tu[1]; //│ // End of generated code //│ tu: (mut 'a, mut 'b,) //│ where diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index 8496e8efea..dc46b03530 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -22,10 +22,10 @@ class Success[out A](result: A) fun list_assoc(s, l) = if l is Cons(h, t) then - if s === h._1 then Success(h._2) + if s === h.0 then Success(h.1) else list_assoc(s, t) Nil then NotFound() -//│ fun list_assoc: forall 'a 'A. (Eql['a], Cons[{_1: 'a, _2: 'A}] | Nil) -> (NotFound | Success['A]) +//│ fun list_assoc: forall 'a 'A. (Eql['a], Cons[{0: 'a, 1: 'A}] | Nil) -> (NotFound | Success['A]) // fun list_assoc(s: Str, l: Cons[{ _1: Str, _2: 'b }] | Nil): NotFound | Success['b] @@ -40,7 +40,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, Var) -> (Var | 'a) +//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, Var) -> (Var | 'a) //│ } class Abs[A](x: Str, t: A) @@ -80,7 +80,7 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, Abs['b] | App['c] | Var) -> 'a +//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, Abs['b] | App['c] | Var) -> 'a //│ } //│ where //│ 'b <: Abs['b] | App['c] | Var @@ -123,7 +123,7 @@ Test1.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("b", Var("b")), Var("c" //│ 'A0 :> 'a //│ 'A :> 'a //│ res -//│ = Var {} +//│ = Abs {} class Numb(n: Int) class Add[A](l: A, r: A) @@ -158,7 +158,7 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (Cons[{_1: anything, _2: Object & 'b}] | Nil, 'a & (Add['c] | Mul['c] | Numb | Var)) -> (Numb | Var | 'b | 'a | 'c) +//│ fun eval: forall 'a. (Cons[{0: anything, 1: Object & 'b}] | Nil, 'a & (Add['c] | Mul['c] | Numb | Var)) -> (Numb | Var | 'b | 'a | 'c) //│ } //│ where //│ 'c <: Add['c] | Mul['c] | Numb | Var @@ -176,7 +176,7 @@ Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Var("a")) Test2.eval(Cons(["a", Numb(1)], Nil), Var("a")) //│ Numb | Var //│ res -//│ = Var {} +//│ = Numb {} // * This expected error shows that Test2 does not handle Abs expression inputs :e @@ -205,7 +205,7 @@ Test2.eval(Cons(["a", Abs("d", Var("d"))], Nil), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, Abs['b] | App['c] | Object & 'd & ~#Abs & ~#App) -> 'e +//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, Abs['b] | App['c] | Object & 'd & ~#Abs & ~#App) -> 'e //│ } //│ where //│ 'a :> 'e @@ -233,12 +233,12 @@ Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("a", Var("a")), Add(Num //│ 'A0 :> 'a //│ 'A :> 'a //│ res -//│ = Var {} +//│ = Add {} // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: (Cons[{_1: anything, _2: 'a}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) +//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) //│ } //│ where //│ 'a :> 'c | 'b diff --git a/shared/src/test/diff/fcp/PolyParams.mls b/shared/src/test/diff/fcp/PolyParams.mls index 590dbdf290..7ac50b731d 100644 --- a/shared/src/test/diff/fcp/PolyParams.mls +++ b/shared/src/test/diff/fcp/PolyParams.mls @@ -10,12 +10,12 @@ fooid = foo id //│ fooid: (1, true,) //│ = [ 1, true ] -fooid._1 -fooid._2 +fooid.0 +fooid.1 //│ res: 1 -//│ = undefined +//│ = 1 //│ res: true -//│ = undefined +//│ = true def foo(f: (forall 'A. 'A -> 'A) -> (forall 'B. 'B -> 'B)) = id f id (f id) diff --git a/shared/src/test/diff/fcp/Skolems2.mls b/shared/src/test/diff/fcp/Skolems2.mls index 882d24e0ab..fa15cc0c10 100644 --- a/shared/src/test/diff/fcp/Skolems2.mls +++ b/shared/src/test/diff/fcp/Skolems2.mls @@ -198,7 +198,7 @@ f 42 //│ [Function (anonymous)] // * Note: parser parses this the same as `oops((f, 0)._1)` -def extrude f = oops((f, 0))._1 +def extrude f = oops((f, 0)).0 //│ extrude: (forall 'c. ('c -> 'c, 0,)) -> 'c0 -> 'c0 //│ = [Function: extrude1] @@ -209,8 +209,8 @@ def extrude f = oops((f, 0))._1 def oops (i: forall 'c. ('c -> 'c, 0)) = - let _ = (i._1 id) "hello" - in i._1 + let _ = (i.0 id) "hello" + in i.0 //│ oops: (forall 'c. ('c -> 'c, 0,)) -> 'c0 -> 'c0 //│ = [Function: oops1] diff --git a/shared/src/test/diff/mlf-examples/variations_ex_hashtbl.mls b/shared/src/test/diff/mlf-examples/variations_ex_hashtbl.mls index 8c19e48604..56ddbc3244 100644 --- a/shared/src/test/diff/mlf-examples/variations_ex_hashtbl.mls +++ b/shared/src/test/diff/mlf-examples/variations_ex_hashtbl.mls @@ -72,10 +72,10 @@ table = hashtbl_add table "one" (fun f -> fun x -> f x) rec def find table key = match_list table none (fun h -> fun t -> - if eq h._1 key then some h._2 + if eq h.0 key then some h.1 else find t key ) -//│ find: List[{_1: anything, _2: 'val}] -> anything -> (None | Some['val]) +//│ find: List[{0: anything, 1: 'val}] -> anything -> (None | Some['val]) def nfind table key = let opt = find table key in @@ -83,10 +83,10 @@ def nfind table key = { None -> fun f -> fun x -> x | Some -> opt.val } -//│ nfind: List[{_1: anything, _2: 'val}] -> anything -> (anything -> 'a -> 'a | 'val) +//│ nfind: List[{0: anything, 1: 'val}] -> anything -> (anything -> 'a -> 'a | 'val) -def nfind: List[{_1: anything; _2: 'val}] -> anything -> (anything -> 'a -> 'a | 'val) -//│ nfind: List[{_1: anything, _2: 'val}] -> anything -> ('val | anything -> 'a -> 'a) +def nfind: List[{0: anything; 1: 'val}] -> anything -> (anything -> 'a -> 'a | 'val) +//│ nfind: List[{0: anything, 1: 'val}] -> anything -> ('val | anything -> 'a -> 'a) // * Alternative // def nfind table key = diff --git a/shared/src/test/diff/mlscript/DavidB.mls b/shared/src/test/diff/mlscript/DavidB.mls index e6c3e3f8cc..8f001eb4b7 100644 --- a/shared/src/test/diff/mlscript/DavidB.mls +++ b/shared/src/test/diff/mlscript/DavidB.mls @@ -10,7 +10,7 @@ tuple2 = (4, 5) //│ = [ 4, 5 ] if true then tuple1 else tuple2 -//│ res: Array[1 | 2 | 3 | 4 | 5] & {_1: 1 | 4, _2: 2 | 5} +//│ res: Array[1 | 2 | 3 | 4 | 5] & {0: 1 | 4, 1: 2 | 5} //│ = [ 1, 2, 3 ] arr = tuple1 : Array[int] diff --git a/shared/src/test/diff/mlscript/LetPolym.mls b/shared/src/test/diff/mlscript/LetPolym.mls index 0a41c097cd..9da8acedd3 100644 --- a/shared/src/test/diff/mlscript/LetPolym.mls +++ b/shared/src/test/diff/mlscript/LetPolym.mls @@ -136,18 +136,15 @@ def test f = //│ test: ((1 | 2) -> int) -> (int -> int, int -> int,) //│ = [Function: test11] -:re // TODO f_g = test succ -f_g._1 42 -f_g._2 42 +f_g.0 42 +f_g.1 42 //│ f_g: (int -> int, int -> int,) //│ = [ [Function (anonymous)], [Function (anonymous)] ] //│ res: int -//│ Runtime error: -//│ TypeError: f_g._1 is not a function +//│ = 44 //│ res: int -//│ Runtime error: -//│ TypeError: f_g._2 is not a function +//│ = 45 def test f = @@ -159,10 +156,10 @@ def test f = :e test succ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.160: test succ +//│ ║ l.157: test succ //│ ║ ^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `int` -//│ ║ l.155: in (local add 1, local concat "ok") +//│ ║ l.152: in (local add 1, local concat "ok") //│ ╙── ^^^^ //│ res: error | (int -> int, string -> string,) //│ = [ [Function (anonymous)], [Function (anonymous)] ] @@ -201,16 +198,16 @@ fun f -> fun x -> :e res add "1" //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.202: res add "1" +//│ ║ l.199: res add "1" //│ ║ ^^^^^^^^^^^ //│ ╟── string literal of type `"1"` is not an instance of type `int` -//│ ║ l.202: res add "1" +//│ ║ l.199: res add "1" //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.196: let local = (fun y -> f y) x +//│ ║ l.193: let local = (fun y -> f y) x //│ ║ ^ //│ ╟── from reference: -//│ ║ l.196: let local = (fun y -> f y) x +//│ ║ l.193: let local = (fun y -> f y) x //│ ╙── ^ //│ res: error | () //│ = [] @@ -224,16 +221,16 @@ fun f -> fun x -> :e res add "1" //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.225: res add "1" +//│ ║ l.222: res add "1" //│ ║ ^^^^^^^^^^^ //│ ╟── string literal of type `"1"` is not an instance of type `int` -//│ ║ l.225: res add "1" +//│ ║ l.222: res add "1" //│ ║ ^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.219: let local = f ((fun y -> y) x) +//│ ║ l.216: let local = f ((fun y -> y) x) //│ ║ ^^^^^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.219: let local = f ((fun y -> y) x) +//│ ║ l.216: let local = f ((fun y -> y) x) //│ ╙── ^ //│ res: error | () //│ = [] @@ -254,17 +251,17 @@ fun f -> fun x -> let tmp = add x 1 in x )) (fun f -> f true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.253: (fun k -> k (fun x -> +//│ ║ l.250: (fun k -> k (fun x -> //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.254: let tmp = add x 1 in x +//│ ║ l.251: let tmp = add x 1 in x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.255: )) (fun f -> f true) +//│ ║ l.252: )) (fun f -> f true) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.255: )) (fun f -> f true) +//│ ║ l.252: )) (fun f -> f true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.254: let tmp = add x 1 in x +//│ ║ l.251: let tmp = add x 1 in x //│ ╙── ^ //│ res: error | true //│ = true @@ -276,21 +273,21 @@ fun f -> fun x -> ) in test ) (fun f -> f true) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.273: (fun k -> +//│ ║ l.270: (fun k -> //│ ║ ^^^^^^^^^ -//│ ║ l.274: let test = k (fun x -> +//│ ║ l.271: let test = k (fun x -> //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.275: let tmp = add x 1 in x +//│ ║ l.272: let tmp = add x 1 in x //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.276: ) in test +//│ ║ l.273: ) in test //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.277: ) (fun f -> f true) +//│ ║ l.274: ) (fun f -> f true) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.277: ) (fun f -> f true) +//│ ║ l.274: ) (fun f -> f true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.275: let tmp = add x 1 in x +//│ ║ l.272: let tmp = add x 1 in x //│ ╙── ^ //│ res: error | true //│ = true @@ -349,16 +346,16 @@ foo (fun x -> (x, x)) :e foo (fun x -> (0, x + 1)) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.350: foo (fun x -> (0, x + 1)) +//│ ║ l.347: foo (fun x -> (0, x + 1)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── type `'a` is not an instance of type `int` -//│ ║ l.339: def foo (f: forall 'a. 'a -> ('a, 'a)) = +//│ ║ l.336: def foo (f: forall 'a. 'a -> ('a, 'a)) = //│ ║ ^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.350: foo (fun x -> (0, x + 1)) +//│ ║ l.347: foo (fun x -> (0, x + 1)) //│ ║ ^ //│ ╟── Note: quantified type variable 'a is defined at: -//│ ║ l.339: def foo (f: forall 'a. 'a -> ('a, 'a)) = +//│ ║ l.336: def foo (f: forall 'a. 'a -> ('a, 'a)) = //│ ╙── ^^ //│ res: error | int //│ = 43 diff --git a/shared/src/test/diff/mlscript/MLTuples.mls b/shared/src/test/diff/mlscript/MLTuples.mls index 54809c2697..bc9debd5a3 100644 --- a/shared/src/test/diff/mlscript/MLTuples.mls +++ b/shared/src/test/diff/mlscript/MLTuples.mls @@ -27,7 +27,7 @@ Hey t //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.26: Hey t //│ ║ ^^^^^ -//│ ╟── tuple literal of type `{_1: 1, _2: 2, _3: 3}` does not have field 'x' +//│ ╟── tuple literal of type `{0: 1, 1: 2, 2: 3}` does not have field 'x' //│ ║ l.2: t = (1, 2, 3) //│ ║ ^^^^^^^^^ //│ ╟── but it flows into reference with expected type `{x: int}` @@ -158,13 +158,13 @@ if bool then (1,) else (2,) :ge if bool then (1,) else (2, 3) -//│ res: Array[1 | 2 | 3] & {_1: 1 | 2} +//│ res: Array[1 | 2 | 3] & {0: 1 | 2} //│ Code generation encountered an error: //│ type alias bool is not a valid expression :ge if bool then (1,) with { a = 1; b = 2 } else (2, 3) with { b = 3; c = 4 } -//│ res: Array[1 | 2 | 3] & {_1: 1 | 2, b: 2 | 3} +//│ res: Array[1 | 2 | 3] & {0: 1 | 2, b: 2 | 3} //│ Code generation encountered an error: //│ type alias bool is not a valid expression @@ -176,12 +176,12 @@ if bool then (1,) else fun x -> x -t._1 -t._2 +t.0 +t.1 //│ res: 1 -//│ = undefined +//│ = 1 //│ res: 2 -//│ = undefined +//│ = 2 t = (1, 2, 3) with {x = 1} @@ -193,32 +193,32 @@ t.x //│ res: 1 //│ = 1 -t._1 -t._2 +t.0 +t.1 //│ res: 1 -//│ = undefined +//│ = 1 //│ res: 2 -//│ = undefined +//│ = 2 -t = (1, 2, 3) with {_1 = "oops"} -//│ t: {_1: "oops", _2: 2, _3: 3} -//│ = [ 1, 2, 3, _1: 'oops' ] +t = (1, 2, 3) with {0 = "oops"} +//│ t: {0: "oops", 1: 2, 2: 3} +//│ = [ 'oops', 2, 3 ] // TODO (https://github.com/hkust-taco/mlscript/issues/69) :e -(t: ("oops",int,int,))._1 +(t: ("oops",int,int,)).0 //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.210: (t: ("oops",int,int,))._1 +//│ ║ l.210: (t: ("oops",int,int,)).0 //│ ║ ^ -//│ ╟── `with` extension of type `{_1: "oops", _2: 2, _3: 3}` is not a 3-element tuple -//│ ║ l.204: t = (1, 2, 3) with {_1 = "oops"} -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── `with` extension of type `{0: "oops", 1: 2, 2: 3}` is not a 3-element tuple +//│ ║ l.204: t = (1, 2, 3) with {0 = "oops"} +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `("oops", int, int,)` -//│ ║ l.210: (t: ("oops",int,int,))._1 +//│ ║ l.210: (t: ("oops",int,int,)).0 //│ ║ ^ //│ ╟── Note: constraint arises from tuple type: -//│ ║ l.210: (t: ("oops",int,int,))._1 +//│ ║ l.210: (t: ("oops",int,int,)).0 //│ ╙── ^^^^^^^^^^^^^^^^^ //│ res: "oops" //│ = 'oops' diff --git a/shared/src/test/diff/mlscript/Mut.mls b/shared/src/test/diff/mlscript/Mut.mls index 61793dcd1a..5abffdda48 100644 --- a/shared/src/test/diff/mlscript/Mut.mls +++ b/shared/src/test/diff/mlscript/Mut.mls @@ -97,18 +97,18 @@ immtpl = (1: int,) //│ = [ 1 ] immrcd.x -immtpl._1 +immtpl.0 immtpl[0] //│ res: int //│ = 1 //│ res: int -//│ = undefined +//│ = 1 //│ res: int | undefined //│ = 1 :e immrcd.x <- 0 -immtpl._1 <- 0 +immtpl.0 <- 0 immtpl[0] <- 0 //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.110: immrcd.x <- 0 @@ -121,14 +121,14 @@ immtpl[0] <- 0 //│ ╙── ^ //│ = [] //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.111: immtpl._1 <- 0 -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.111: immtpl.0 <- 0 +//│ ║ ^^^^^^^^^^^^^ //│ ╟── tuple field of type `int` is not mutable //│ ║ l.93: immtpl = (1: int,) //│ ║ ^ -//│ ╟── but it flows into assigned field with expected type `?a` -//│ ║ l.111: immtpl._1 <- 0 -//│ ╙── ^^ +//│ ╟── but it flows into assigned field with expected type `?0` +//│ ║ l.111: immtpl.0 <- 0 +//│ ╙── ^ //│ = [] //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.112: immtpl[0] <- 0 @@ -404,7 +404,7 @@ mt1 : (int, bool) //│ mt1 is not implemented def emt: (mut int) -emt._1 +emt.0 //│ emt: (mut int,) //│ = //│ res: int @@ -412,7 +412,7 @@ emt._1 //│ emt is not implemented k1 = (mut 233, "hello", mut true) -k1._1 <- k1._1 + 1 +k1.0 <- k1.0 + 1 //│ k1: (mut 'a, "hello", mut 'b,) //│ where //│ 'b :> true @@ -421,19 +421,19 @@ k1._1 <- k1._1 + 1 //│ = [] :e -k1._2 <- 233 +k1.1 <- 233 //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.424: k1._2 <- 233 -//│ ║ ^^^^^^^^^^^^ -//│ ╟── tuple literal of type `forall ?a ?b. (mut ?a, "hello", mut ?b,)` does not have field '_2' +//│ ║ l.424: k1.1 <- 233 +//│ ║ ^^^^^^^^^^^ +//│ ╟── tuple literal of type `forall ?a ?b. (mut ?a, "hello", mut ?b,)` does not have field '1' //│ ║ l.414: k1 = (mut 233, "hello", mut true) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `{mut _2: in ?c}` -//│ ║ l.424: k1._2 <- 233 +//│ ╟── but it flows into reference with expected type `{mut 1: in ?1}` +//│ ║ l.424: k1.1 <- 233 //│ ║ ^^ //│ ╟── Note: constraint arises from assigned selection: -//│ ║ l.424: k1._2 <- 233 -//│ ╙── ^^^^^ +//│ ║ l.424: k1.1 <- 233 +//│ ╙── ^^^^ //│ = [] mt1 = (mut 3, mut false) @@ -474,7 +474,7 @@ amf mt4 :e a1[0] <- 1 -mt1[0] <- mt2._1 +mt1[0] <- mt2.0 mt4[3] <- true //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.476: a1[0] <- 1 @@ -488,8 +488,8 @@ mt4[3] <- true //│ = //│ a1 is not implemented //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.477: mt1[0] <- mt2._1 -//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.477: mt1[0] <- mt2.0 +//│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type `int` is not an instance of `bool` //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^ @@ -497,22 +497,22 @@ mt4[3] <- true //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── from assigned array element: -//│ ║ l.477: mt1[0] <- mt2._1 +//│ ║ l.477: mt1[0] <- mt2.0 //│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.477: mt1[0] <- mt2._1 -//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.477: mt1[0] <- mt2.0 +//│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type `int` is not an instance of `bool` //│ ║ l.382: def mt2: (int, int) //│ ║ ^^^ //│ ╟── but it flows into field selection with expected type `bool` -//│ ║ l.477: mt1[0] <- mt2._1 -//│ ║ ^^^^^^ +//│ ║ l.477: mt1[0] <- mt2.0 +//│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── from assigned array element: -//│ ║ l.477: mt1[0] <- mt2._1 +//│ ║ l.477: mt1[0] <- mt2.0 //│ ╙── ^^^^^^ //│ = //│ mt2 is not implemented @@ -527,11 +527,11 @@ mt4[3] <- true //│ ╙── ^^^ //│ = [] -mt1._1 <- mt2._1 -mt1._1 <- mt1._1 * 2 -mt1._2 <- false +mt1.0 <- mt2.0 +mt1.0 <- mt1.0 * 2 +mt1.1 <- false mt3[0] <- let tmp = mt3[1] in case tmp of { undefined -> 0 | _ -> tmp } -mt3[1] <- mt1._1 +mt3[1] <- mt1.0 //│ = //│ mt2 is not implemented //│ = [] @@ -543,68 +543,68 @@ mt3[1] <- mt1._1 :e :ge -mt1._1 <- mt1._2 -mt1._2 <- 1 -mt1._1 <- (b1.t <- 4) -(mt1._1 <- b1.t) <- 4 +mt1.0 <- mt1.1 +mt1.1 <- 1 +mt1.0 <- (b1.t <- 4) +(mt1.0 <- b1.t) <- 4 b1.x <- 1 + 2 <- 4 //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.546: mt1._1 <- mt1._2 -//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.546: mt1.0 <- mt1.1 +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── type `bool` is not an instance of `int` //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── but it flows into field selection with expected type `int` -//│ ║ l.546: mt1._1 <- mt1._2 -//│ ║ ^^^^^^ +//│ ║ l.546: mt1.0 <- mt1.1 +//│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^ //│ ╟── from assigned selection: -//│ ║ l.546: mt1._1 <- mt1._2 -//│ ╙── ^^^^^^ +//│ ║ l.546: mt1.0 <- mt1.1 +//│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.547: mt1._2 <- 1 -//│ ║ ^^^^^^^^^^^ +//│ ║ l.547: mt1.1 <- 1 +//│ ║ ^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.547: mt1._2 <- 1 -//│ ║ ^ +//│ ║ l.547: mt1.1 <- 1 +//│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── from assigned selection: -//│ ║ l.547: mt1._2 <- 1 -//│ ╙── ^^^^^^ +//│ ║ l.547: mt1.1 <- 1 +//│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.548: mt1._1 <- (b1.t <- 4) -//│ ║ ^^^^^^^^^ +//│ ║ l.548: mt1.0 <- (b1.t <- 4) +//│ ║ ^^^^^^^^^ //│ ╟── type `B` does not have field 't' //│ ║ l.265: def b1 : B //│ ║ ^ //│ ╟── but it flows into reference with expected type `{mut t: in ?t}` -//│ ║ l.548: mt1._1 <- (b1.t <- 4) -//│ ║ ^^ +//│ ║ l.548: mt1.0 <- (b1.t <- 4) +//│ ║ ^^ //│ ╟── Note: constraint arises from assigned selection: -//│ ║ l.548: mt1._1 <- (b1.t <- 4) -//│ ╙── ^^^^ +//│ ║ l.548: mt1.0 <- (b1.t <- 4) +//│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.548: mt1._1 <- (b1.t <- 4) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.548: mt1.0 <- (b1.t <- 4) +//│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── assignment of type `unit` is not an instance of type `int` -//│ ║ l.548: mt1._1 <- (b1.t <- 4) -//│ ║ ^^^^^^^^^ +//│ ║ l.548: mt1.0 <- (b1.t <- 4) +//│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^ //│ ╟── from assigned selection: -//│ ║ l.548: mt1._1 <- (b1.t <- 4) -//│ ╙── ^^^^^^ +//│ ║ l.548: mt1.0 <- (b1.t <- 4) +//│ ╙── ^^^^^ //│ ╔══[ERROR] Illegal assignment -//│ ║ l.549: (mt1._1 <- b1.t) <- 4 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.549: (mt1.0 <- b1.t) <- 4 +//│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── cannot assign to assignment -//│ ║ l.549: (mt1._1 <- b1.t) <- 4 -//│ ╙── ^^^^^^^^^^^^^^^^ +//│ ║ l.549: (mt1.0 <- b1.t) <- 4 +//│ ╙── ^^^^^^^^^^^^^^^ //│ res: error //│ ╔══[ERROR] Illegal assignment //│ ║ l.550: b1.x <- 1 + 2 <- 4 @@ -613,19 +613,19 @@ b1.x <- 1 + 2 <- 4 //│ ║ l.550: b1.x <- 1 + 2 <- 4 //│ ╙── ^ //│ Code generation encountered an error: -//│ illegal assignemnt left-hand side: Bra(rcd = false, Assign(Sel(Var(mt1), _1), Sel(Var(b1), t))) +//│ illegal assignemnt left-hand side: Bra(rcd = false, Assign(Sel(Var(mt1), 0), Sel(Var(b1), t))) -def f : {mut _1 : int} -> int -> unit +def f : {mut 0 : int} -> int -> unit def g : (mut int, bool) -> int -> unit -//│ f: {mut _1: int} -> int -> unit +//│ f: {mut 0: int} -> int -> unit //│ = //│ g: (mut int, bool,) -> int -> unit //│ = -def f a n = a._1 <- n -//│ {mut _1: in 'a} -> 'a -> unit +def f a n = a.0 <- n +//│ {mut 0: in '0} -> '0 -> unit //│ <: f: -//│ {mut _1: int} -> int -> unit +//│ {mut 0: int} -> int -> unit //│ = [Function: f] f mt1 1 @@ -699,20 +699,20 @@ st2 = (mut 4,) //│ (mut int,) //│ = [ 4 ] -st2._1 <- 8 +st2.0 <- 8 //│ = [] :e -st1._1 <- 9 +st1.0 <- 9 //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.706: st1._1 <- 9 -//│ ║ ^^^^^^^^^^^ +//│ ║ l.706: st1.0 <- 9 +//│ ║ ^^^^^^^^^^ //│ ╟── tuple field of type `int` is not mutable //│ ║ l.682: def st1 : (int, ) //│ ║ ^^^ -//│ ╟── but it flows into assigned field with expected type `?a` -//│ ║ l.706: st1._1 <- 9 -//│ ╙── ^^ +//│ ╟── but it flows into assigned field with expected type `?0` +//│ ║ l.706: st1.0 <- 9 +//│ ╙── ^ //│ = [] def am1 : Array[(mut int)] @@ -724,7 +724,7 @@ def foreach : Array['a] -> ('a -> unit) -> Array['a] //│ = foreach am1 (fun x -> x[0] <- 1) -foreach am1 (fun y -> y._1 <- 2) +foreach am1 (fun y -> y.0 <- 2) //│ res: Array[(mut int,)] //│ = //│ foreach is not implemented @@ -734,7 +734,7 @@ foreach am1 (fun y -> y._1 <- 2) :e (1,2,3)[0] <- true -(1,2,3)._1 <- "hello" +(1,2,3).0 <- "hello" //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.736: (1,2,3)[0] <- true //│ ║ ^^^^^^^^^^^^^^^^^^ @@ -743,14 +743,14 @@ foreach am1 (fun y -> y._1 <- 2) //│ ╙── ^^^^^^^ //│ = [] //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.737: (1,2,3)._1 <- "hello" -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.737: (1,2,3).0 <- "hello" +//│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple field of type `1` is not mutable -//│ ║ l.737: (1,2,3)._1 <- "hello" +//│ ║ l.737: (1,2,3).0 <- "hello" //│ ║ ^ -//│ ╟── but it flows into assigned field with expected type `?a` -//│ ║ l.737: (1,2,3)._1 <- "hello" -//│ ╙── ^^ +//│ ╟── but it flows into assigned field with expected type `?0` +//│ ║ l.737: (1,2,3).0 <- "hello" +//│ ╙── ^ //│ = [] :e diff --git a/shared/src/test/diff/mlscript/Mut2.mls b/shared/src/test/diff/mlscript/Mut2.mls index 527b9bfd75..c4e23d206d 100644 --- a/shared/src/test/diff/mlscript/Mut2.mls +++ b/shared/src/test/diff/mlscript/Mut2.mls @@ -11,13 +11,13 @@ //│ 'a :> 1 | 2 //│ = [ 1, 2 ] -((fun t -> let tmp = t._1 <- 3 in t) ((mut 1, mut 2))): MutArray['a] +((fun t -> let tmp = t.0 <- 3 in t) ((mut 1, mut 2))): MutArray['a] //│ res: MutArray['a] //│ where //│ 'a :> 1 | 2 | 3 -//│ = [ 1, 2, _1: 3 ] +//│ = [ 3, 2 ] -((fun t -> let tmp = t._1 + 1 in t) ((mut 1, mut 2))): MutArray['a] +((fun t -> let tmp = t.0 + 1 in t) ((mut 1, mut 2))): MutArray['a] //│ res: MutArray[in 'a & 'b out 'b] //│ where //│ 'a <: int & 'b @@ -46,19 +46,19 @@ r = if true then t1 else t2 //│ t1 is not implemented :e -r._1 <- 1 +r.0 <- 1 //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.49: r._1 <- 1 -//│ ║ ^^^^^^^^^ +//│ ║ l.49: r.0 <- 1 +//│ ║ ^^^^^^^^ //│ ╟── integer literal of type `1` does not match type `3` -//│ ║ l.49: r._1 <- 1 -//│ ║ ^ +//│ ║ l.49: r.0 <- 1 +//│ ║ ^ //│ ╟── Note: constraint arises from literal type: //│ ║ l.37: def t2: (mut 3, mut 4) //│ ║ ^ //│ ╟── from assigned selection: -//│ ║ l.49: r._1 <- 1 -//│ ╙── ^^^^ +//│ ║ l.49: r.0 <- 1 +//│ ╙── ^^^ //│ = //│ r and t1 are not implemented @@ -75,26 +75,26 @@ r = if true then t1 else t2 //│ = //│ t1 is not implemented -r._1 <- if true then 2 else 3 +r.0 <- if true then 2 else 3 //│ = //│ r and t1 are not implemented :e -r._1 <- if true then 2 else 1 +r.0 <- if true then 2 else 1 //│ ╔══[ERROR] Type mismatch in assignment: -//│ ║ l.83: r._1 <- if true then 2 else 1 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.83: r.0 <- if true then 2 else 1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` does not match type `2 | 3 | 4` -//│ ║ l.83: r._1 <- if true then 2 else 1 -//│ ║ ^ +//│ ║ l.83: r.0 <- if true then 2 else 1 +//│ ║ ^ //│ ╟── but it flows into application with expected type `2 | 3 | 4` -//│ ║ l.83: r._1 <- if true then 2 else 1 -//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.83: r.0 <- if true then 2 else 1 +//│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from union type: //│ ║ l.67: def t2: (mut 2 | 3 | 4) //│ ║ ^^^^^^^^^ //│ ╟── from assigned selection: -//│ ║ l.83: r._1 <- if true then 2 else 1 -//│ ╙── ^^^^ +//│ ║ l.83: r.0 <- if true then 2 else 1 +//│ ╙── ^^^ //│ = //│ r and t1 are not implemented diff --git a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls index 10cbaa988e..851a7317bb 100644 --- a/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls +++ b/shared/src/test/diff/mlscript/PolyVariantCodeReuse.mls @@ -53,13 +53,13 @@ def eq: string -> string -> bool rec def list_assoc s l = case l of { | Cons -> - if eq l.head._1 s then Success l.head._2 + if eq l.head.0 s then Success l.head.1 else list_assoc s l.tail | Nil -> NotFound } //│ list_assoc: string -> 'a -> (NotFound | (Success with {result: 'result})) //│ where -//│ 'a <: (Cons[?] with {head: {_1: string, _2: 'result}, tail: 'a}) | Nil +//│ 'a <: (Cons[?] with {head: {0: string, 1: 'result}, tail: 'a}) | Nil //│ = //│ eq is not implemented @@ -86,7 +86,7 @@ def eval_var sub v = case v of { } //│ eval_var: (Cons[?] & 'a | Nil) -> (Var & 'result) -> 'result //│ where -//│ 'a <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'a | Nil} +//│ 'a <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'a | Nil} //│ = //│ list_assoc and eq are not implemented @@ -125,13 +125,13 @@ def eval_lambda eval_rec subst v = case v of { | Abs -> eval_rec (Cons (Tuple l1.name l2) Nil) l1.body | _ -> App { lhs = l1; rhs = l2 } } - | Abs -> let new_name = int_to_string ((gensym ())._2.a) in + | Abs -> let new_name = int_to_string ((gensym ()).1.a) in Abs { name = new_name; body = eval_rec (Cons (Tuple v.name (Var { name = new_name })) subst) v.body } } //│ eval_lambda: (((Cons[('a, Var | 'body,) | 'A] with {head: ('a, Var | 'body,), tail: Nil | 'tail}) | 'tail) -> 'lhs -> ('body & 'result & ((Abs[?] with {body: 'lhs, name: 'a}) | 'lhs0 & ~#Abs))) -> (List['A] & (Cons[?] & 'b | Nil) & 'tail) -> ((Abs[?] with {body: 'lhs, name: 'a}) | App[?] & {lhs: 'lhs, rhs: 'lhs} | Var & 'result) -> (Abs['body] | (App['lhs0 | 'body] with {lhs: 'lhs0, rhs: 'body}) | 'result) //│ where -//│ 'b <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'b | Nil} +//│ 'b <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'b | Nil} //│ = //│ eval_var, list_assoc and eq are not implemented @@ -139,7 +139,7 @@ rec def eval1 subst = eval_lambda eval1 subst //│ eval1: ('tail & (Cons[?] & List[?] & 'b | Nil & List[?])) -> 'c -> 'd //│ where //│ 'tail <: Cons[?] & 'b | Nil -//│ 'b <: {head: {_1: string, _2: 'result}, tail: 'tail} +//│ 'b <: {head: {0: string, 1: 'result}, tail: 'tail} //│ 'result :> 'd //│ <: Abs[?] & 'e & 'f | 'lhs & (Abs[?] & 'f & ~#Abs | App[?] & 'g | Var & 'h) //│ 'd :> 'result | 'i | App['a]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs} | Abs['d] @@ -213,7 +213,7 @@ rec def eval_expr eval_rec subst v = } //│ eval_expr: ('a -> 'rhs -> 'rhs0) -> ('a & (Cons[?] & 'b | Nil)) -> (Add[?] & {lhs: 'rhs, rhs: 'rhs} | Mul[?] & {lhs: 'rhs, rhs: 'rhs} | Numb & 'result | Var & 'result) -> (Add['rhs0] | Mul['rhs0] | Numb | 'result) //│ where -//│ 'b <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'b | Nil} +//│ 'b <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'b | Nil} //│ = //│ eval_var, list_assoc and eq are not implemented @@ -221,7 +221,7 @@ rec def eval2 subst = eval_expr eval2 subst //│ eval2: (Cons[?] & 'a | Nil) -> 'b -> (Numb | 'result) //│ where //│ 'b <: Add[?] & {lhs: 'b, rhs: 'b} | Mul[?] & {lhs: 'b, rhs: 'b} | Numb & 'result | Var & 'result -//│ 'a <: {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: Cons[?] & 'a | Nil} +//│ 'a <: {head: {0: string, 1: 'result & (Numb | ~#Numb)}, tail: Cons[?] & 'a | Nil} //│ 'result :> Mul[Numb | 'result] | Add[Numb | 'result] //│ = //│ eval_expr, eval_var, list_assoc and eq are not implemented @@ -261,8 +261,8 @@ def eval_lexpr eval_rec subst v = case v of { } //│ eval_lexpr: ((Cons[('a, Var | 'body,) | 'A]\head\tail & {head: ('a, Var | 'body,), tail: Nil | 'tail} | 'tail) -> 'lhs -> ('body & 'result & (Abs[?]\body\name & {body: 'lhs, name: 'a} | 'lhs0 & ~#Abs))) -> (List['A] & (Cons[?] & 'b | Nil) & (Cons[?] & 'c | Nil) & 'tail) -> (Abs[?]\body\name & {body: 'lhs, name: 'a} | Add[?] & {lhs: 'lhs, rhs: 'lhs} | App[?] & {lhs: 'lhs, rhs: 'lhs} | Mul[?] & {lhs: 'lhs, rhs: 'lhs} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | App['lhs0 | 'body]\lhs\rhs & {lhs: 'lhs0, rhs: 'body} | Mul['body] | Numb | 'result) //│ where -//│ 'c <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'c | Nil} -//│ 'b <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'b | Nil} +//│ 'c <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'c | Nil} +//│ 'b <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'b | Nil} //│ = //│ eval_lambda, eval_var, list_assoc and eq are not implemented @@ -270,9 +270,9 @@ rec def eval3 subst = eval_lexpr eval3 subst //│ eval3: ('tail & 'tail0 & (Cons[?] & List[?] & 'b & 'c | Nil & List[?])) -> 'd -> 'e //│ where //│ 'tail0 <: Cons[?] & 'c | Nil -//│ 'c <: {head: {_1: string, _2: 'result}, tail: 'tail0} +//│ 'c <: {head: {0: string, 1: 'result}, tail: 'tail0} //│ 'tail <: Cons[?] & 'b | Nil -//│ 'b <: {head: {_1: string, _2: 'result}, tail: 'tail} +//│ 'b <: {head: {0: string, 1: 'result}, tail: 'tail} //│ 'result :> Var | 'e | Numb //│ <: Abs[?] & 'f & 'g | 'lhs & (Lambda & 'f & ~#Abs | 'h & (Expr & ~#Numb | Numb)) //│ 'e :> Abs['e] | (App['a] with {lhs: 'lhs, rhs: 'rhs}) | 'result | 'i | 'j | (Add['e] with {lhs: 'e, rhs: 'e}) | (Mul['e] with {lhs: 'e, rhs: 'e}) @@ -405,12 +405,12 @@ def eval_lexpr' eval_rec subst v = case v of { } //│ eval_lexpr': ((Cons[('b, Var | 'body,) | 'A]\head\tail & {head: ('b, Var | 'body,), tail: Nil | 'tail} | 'tail) -> 'body0 -> ('body & 'result & (Abs[?]\body\name & {body: 'body0, name: 'b} | 'lhs & 'a & (Abs[?]\body\name & {body: 'body0, name: 'b} & ~#Abs | 'lhs & 'a & ~#Abs)))) -> (List['A] & (Cons[?] & 'c | Nil) & (Cons[?] & 'd | Nil) & (Cons[?] & 'e | Nil) & (Cons[?] & 'f | Nil) & (Cons[?] & 'g | Nil) & 'tail & (Cons[?] & 'h | Nil)) -> (Abs[?]\body\name & {body: 'body0, name: 'b} | Add[?] & {lhs: 'body0, rhs: 'body0} | App[?] & {lhs: 'body0, rhs: 'body0} | Mul[?] & {lhs: 'body0, rhs: 'body0} | Numb & 'result | Var & 'result) -> (Abs['body] | Add['body] | App['a | 'body]\lhs\rhs & {lhs: 'lhs, rhs: 'body} | Mul['body] | Numb | 'result) //│ where -//│ 'h <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'h | Nil} -//│ 'g <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'g | Nil} -//│ 'f <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'f | Nil} -//│ 'e <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'e | Nil} -//│ 'd <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'd | Nil} -//│ 'c <: {head: {_1: string, _2: 'result}, tail: Cons[?] & 'c | Nil} +//│ 'h <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'h | Nil} +//│ 'g <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'g | Nil} +//│ 'f <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'f | Nil} +//│ 'e <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'e | Nil} +//│ 'd <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'd | Nil} +//│ 'c <: {head: {0: string, 1: 'result}, tail: Cons[?] & 'c | Nil} //│ = //│ eval_var, list_assoc and eq are not implemented @@ -423,32 +423,32 @@ rec def eval4 subst = eval_lexpr' eval4 subst //│ eval4: ('tail & 'tail0 & 'tail1 & 'tail2 & 'tail3 & 'tail4 & (Cons[?] & List[?] & 'a & 'b & 'c & 'd & 'e & 'f | Nil & List[?])) -> 'g -> (App[nothing] | 'result | 'h) //│ where //│ 'tail4 <: Cons[?] & 'f | Nil -//│ 'f <: {head: {_1: string, _2: 'result0}, tail: 'tail4} +//│ 'f <: {head: {0: string, 1: 'result0}, tail: 'tail4} //│ 'tail3 <: Cons[?] & 'e | Nil -//│ 'e <: {head: {_1: string, _2: 'result0}, tail: 'tail3} +//│ 'e <: {head: {0: string, 1: 'result0}, tail: 'tail3} //│ 'tail2 <: Cons[?] & 'd | Nil -//│ 'd <: {head: {_1: string, _2: 'result & (Numb | ~#Numb)}, tail: 'tail2} +//│ 'd <: {head: {0: string, 1: 'result & (Numb | ~#Numb)}, tail: 'tail2} //│ 'tail1 <: Cons[?] & 'c | Nil //│ 'c <: { //│ head: { -//│ _1: string, -//│ _2: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) +//│ 0: string, +//│ 1: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) //│ }, //│ tail: 'tail1 //│ } //│ 'tail0 <: Cons[?] & 'b | Nil //│ 'b <: { //│ head: { -//│ _1: string, -//│ _2: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) +//│ 0: string, +//│ 1: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) //│ }, //│ tail: 'tail0 //│ } //│ 'tail <: Cons[?] & 'a | Nil //│ 'a <: { //│ head: { -//│ _1: string, -//│ _2: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) +//│ 0: string, +//│ 1: 'result & (Abs[?] & 'i & 'j | 'lhs & (Abs[?] & 'j & ~#Abs | Add[?] & 'k | App[?] & 'l | Mul[?] & 'm | Var & 'n | 'o & (Numb | Numb & ~#Numb))) //│ }, //│ tail: 'tail //│ } @@ -477,17 +477,17 @@ rec def eval4 subst = eval_lexpr' eval4 subst //│ eval4: ('tail & 'tail0 & 'tail1 & 'tail2 & 'tail3 & 'tail4 & (Cons[?] & List[?] & 'b & 'c & 'd & 'e & 'f & 'g | Nil & List[?])) -> 'h -> 'i //│ where //│ 'tail4 <: Cons[?] & 'd | Nil -//│ 'd <: {head: {_1: string, _2: 'result}, tail: 'tail4} +//│ 'd <: {head: {0: string, 1: 'result}, tail: 'tail4} //│ 'tail3 <: Cons[?] & 'c | Nil -//│ 'c <: {head: {_1: string, _2: 'result0}, tail: 'tail3} +//│ 'c <: {head: {0: string, 1: 'result0}, tail: 'tail3} //│ 'tail2 <: Cons[?] & 'b | Nil -//│ 'b <: {head: {_1: string, _2: 'result0}, tail: 'tail2} +//│ 'b <: {head: {0: string, 1: 'result0}, tail: 'tail2} //│ 'tail1 <: Cons[?] & 'g | Nil -//│ 'g <: {head: {_1: string, _2: 'result0}, tail: 'tail1} +//│ 'g <: {head: {0: string, 1: 'result0}, tail: 'tail1} //│ 'tail0 <: Cons[?] & 'f | Nil -//│ 'f <: {head: {_1: string, _2: 'result}, tail: 'tail0} +//│ 'f <: {head: {0: string, 1: 'result}, tail: 'tail0} //│ 'tail <: Cons[?] & 'e | Nil -//│ 'e <: {head: {_1: string, _2: 'result}, tail: 'tail} +//│ 'e <: {head: {0: string, 1: 'result}, tail: 'tail} //│ 'result :> Var | 'i | Numb //│ <: Abs[?] & 'j & 'k & 'l | 'lhs & 'lhs0 & (Add[?] & 'm | App[?] & 'n | Mul[?] & 'o | Var & 'p | 'q & (Numb | Numb & ~#Numb)) //│ 'i :> 'result0 | 'r | Abs['i] | App['a]\lhs\rhs & {lhs: 'lhs0, rhs: 'rhs} | 'result | 's | Add['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | Mul['i]\lhs\rhs & {lhs: 'i, rhs: 'i} | App['a0]\lhs\rhs & {lhs: 'lhs, rhs: 'rhs0} diff --git a/shared/src/test/diff/mlscript/SelfNeg.mls b/shared/src/test/diff/mlscript/SelfNeg.mls index f473c61024..50e34e43db 100644 --- a/shared/src/test/diff/mlscript/SelfNeg.mls +++ b/shared/src/test/diff/mlscript/SelfNeg.mls @@ -120,7 +120,7 @@ r //│ = //│ r and bar are not implemented -r._1 : nothing +r.0 : nothing //│ res: nothing //│ = //│ r and bar are not implemented diff --git a/shared/src/test/diff/mlscript/SelfNegs.mls b/shared/src/test/diff/mlscript/SelfNegs.mls index 9f4c14c02b..8446f2bbb4 100644 --- a/shared/src/test/diff/mlscript/SelfNegs.mls +++ b/shared/src/test/diff/mlscript/SelfNegs.mls @@ -6,7 +6,7 @@ def foo(f: (~'a) -> 'a, a: 'a) = //│ = [Function: foo] def foo(fa: ((~'a) -> 'a, 'a)) = - fa._1 fa._2 + fa.0 fa.1 //│ foo: ((~'a -> 'a, 'a,),) -> 'a //│ = [Function: foo1] diff --git a/shared/src/test/diff/mlscript/This.mls b/shared/src/test/diff/mlscript/This.mls index 18753a4bfc..bd2f7ed473 100644 --- a/shared/src/test/diff/mlscript/This.mls +++ b/shared/src/test/diff/mlscript/This.mls @@ -103,7 +103,7 @@ class Base2 class Derived2: Base2 method Foo3 = (this.Foo2,) class DerivedDerived2: Derived2 - method Foo2 = this.Foo3._1 + method Foo2 = this.Foo3.0 //│ Defined class Base2 //│ Declared Base2.Foo2: (Base2 & 'this) -> (Base2 & 'this) //│ Defined class Derived2 @@ -127,7 +127,7 @@ class NewBase //│ Defined NewBase.NewBar: (NewBase & 'this) -> (NewBase & 'this,) class NewDerived: NewBase - method NewQux = this.NewBar._1 + method NewQux = this.NewBar.0 //│ Defined class NewDerived //│ Defined NewDerived.NewQux: (NewDerived & 'this) -> (NewDerived & NewBase & 'this) @@ -155,13 +155,13 @@ NewDerivedDerived.NewQuz :e class NewDerivedDerivedDerived: NewDerivedDerived - method NewQux = this.NewBar._1 + method NewQux = this.NewBar.0 //│ ╔══[ERROR] Overriding method NewDerived.NewQux without explicit declaration is not allowed. -//│ ║ l.158: method NewQux = this.NewBar._1 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.158: method NewQux = this.NewBar.0 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Note: method definition inherited from -//│ ║ l.130: method NewQux = this.NewBar._1 -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.130: method NewQux = this.NewBar.0 +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^ //│ Defined class NewDerivedDerivedDerived //│ Defined NewDerivedDerivedDerived.NewQux: (NewDerivedDerivedDerived & 'this) -> (NewDerivedDerivedDerived & NewBase & 'this) diff --git a/shared/src/test/diff/mlscript/TrickyExtrusion.mls b/shared/src/test/diff/mlscript/TrickyExtrusion.mls index 143c35c924..e73b958417 100644 --- a/shared/src/test/diff/mlscript/TrickyExtrusion.mls +++ b/shared/src/test/diff/mlscript/TrickyExtrusion.mls @@ -53,44 +53,44 @@ test f = //│ = [Function: test2] :e // * Due to lack of precision -(test id)._1 + 1 +(test id).0 + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.56: (test id)._1 + 1 -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.56: (test id).0 + 1 +//│ ║ ^^^^^^^^^^^^^ //│ ╟── reference of type `true` is not an instance of type `int` //│ ║ l.4: True = true //│ ║ ^^^^ //│ ╟── but it flows into field selection with expected type `int` -//│ ║ l.56: (test id)._1 + 1 -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.56: (test id).0 + 1 +//│ ╙── ^^^^^^^^^^^ //│ res: error | int -//│ = NaN +//│ = 1 :e // * Due to lack of precision -not (test id)._2 +not (test id).1 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.70: not (test id)._2 -//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.70: not (test id).1 +//│ ║ ^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `0` is not an instance of type `bool` //│ ║ l.51: in (r 0, r True) //│ ║ ^ //│ ╟── but it flows into field selection with expected type `bool` -//│ ║ l.70: not (test id)._2 -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.70: not (test id).1 +//│ ╙── ^^^^^^^^^^^ //│ res: bool | error -//│ = true +//│ = false :e // * Legit -not (test id)._1 +not (test id).0 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.84: not (test id)._1 -//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.84: not (test id).0 +//│ ║ ^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `0` is not an instance of type `bool` //│ ║ l.51: in (r 0, r True) //│ ║ ^ //│ ╟── but it flows into field selection with expected type `bool` -//│ ║ l.84: not (test id)._1 -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.84: not (test id).0 +//│ ╙── ^^^^^^^^^^^ //│ res: bool | error //│ = true @@ -126,25 +126,25 @@ test // * We can tell the type is still precise enough because these work: -(test id)._1 + 1 +(test id).0 + 1 //│ res: int -//│ = NaN +//│ = 1 -not (test id)._2 +not (test id).1 //│ res: bool -//│ = true +//│ = false :e // * Legit -not (test id)._1 +not (test id).0 //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.138: not (test id)._1 -//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.138: not (test id).0 +//│ ║ ^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `0` is not an instance of type `bool` //│ ║ l.112: in (r 0, r True) //│ ║ ^ //│ ╟── but it flows into field selection with expected type `bool` -//│ ║ l.138: not (test id)._1 -//│ ╙── ^^^^^^^^^^^^ +//│ ║ l.138: not (test id).0 +//│ ╙── ^^^^^^^^^^^ //│ res: bool | error //│ = true diff --git a/shared/src/test/diff/mlscript/TupleArray.mls b/shared/src/test/diff/mlscript/TupleArray.mls index 800dd8fa5f..fa0b2dc4aa 100644 --- a/shared/src/test/diff/mlscript/TupleArray.mls +++ b/shared/src/test/diff/mlscript/TupleArray.mls @@ -49,43 +49,43 @@ r = {b = "a", c = 1} //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ = { b: 'a', c: 1 } -(1,2,3) with { _4 = "oops" } -//│ res: (1, 2, 3,) & {_4: "oops"} -//│ = [ 1, 2, 3, _4: 'oops' ] +(1,2,3) with { 3 = "oops" } +//│ res: (1, 2, 3,) & {3: "oops"} +//│ = [ 1, 2, 3, 'oops' ] -(1,2,3) with { _1 = "oops" } -//│ res: {_1: "oops", _2: 2, _3: 3} -//│ = [ 1, 2, 3, _1: 'oops' ] +(1,2,3) with { 0 = "oops" } +//│ res: {0: "oops", 1: 2, 2: 3} +//│ = [ 'oops', 2, 3 ] :e -(res: (int,int,int,))._1 +(res: (int,int,int,)).0 //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.61: (res: (int,int,int,))._1 +//│ ║ l.61: (res: (int,int,int,)).0 //│ ║ ^^^ -//│ ╟── `with` extension of type `{_1: "oops", _2: 2, _3: 3}` is not a 3-element tuple -//│ ║ l.56: (1,2,3) with { _1 = "oops" } -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── `with` extension of type `{0: "oops", 1: 2, 2: 3}` is not a 3-element tuple +//│ ║ l.56: (1,2,3) with { 0 = "oops" } +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `(int, int, int,)` -//│ ║ l.61: (res: (int,int,int,))._1 +//│ ║ l.61: (res: (int,int,int,)).0 //│ ║ ^^^ //│ ╟── Note: constraint arises from tuple type: -//│ ║ l.61: (res: (int,int,int,))._1 +//│ ║ l.61: (res: (int,int,int,)).0 //│ ╙── ^^^^^^^^^^^^^^ //│ res: int //│ = 'oops' -def r: int \ _1 -//│ r: int\_1 +def r: int \ 0 +//│ r: int\0 //│ = -def r: (1,2,3) \ _1 -//│ r: in (1, 2, 3,)\_1 out {_2: 2, _3: 3} +def r: (1,2,3) \ 0 +//│ r: in (1, 2, 3,)\0 out {1: 2, 2: 3} //│ = -// (1,2,3).toRecord \ _1 +// (1,2,3).toRecord \ 1 -def r: (1,2,3) \ _12345 -//│ r: in (1, 2, 3,)\_12345 out (1, 2, 3,) +def r: (1,2,3) \ 12345 +//│ r: in (1, 2, 3,)\12345 out (1, 2, 3,) //│ = def arr: Array[int] @@ -107,18 +107,18 @@ fr : Array[int] & {b: int} //│ fr and r are not implemented :e -arr._1 +arr.0 //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.110: arr._1 -//│ ║ ^^^^^^ -//│ ╟── type `Array[int]` does not have field '_1' +//│ ║ l.110: arr.0 +//│ ║ ^^^^^ +//│ ╟── type `Array[int]` does not have field '0' //│ ║ l.91: def arr: Array[int] //│ ║ ^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `{_1: ?a}` -//│ ║ l.110: arr._1 +//│ ╟── but it flows into reference with expected type `{0: ?a}` +//│ ║ l.110: arr.0 //│ ╙── ^^^ //│ res: error -//│ = undefined +//│ = 1 rr = arr with { x = 1 } //│ rr: Array[int] & {x: 1} @@ -138,13 +138,13 @@ t = (1, 2, 3) with {x = 1} //│ t: (1, 2, 3,) & {x: 1} //│ = [ 1, 2, 3, x: 1 ] -t._1 -t._2 +t.0 +t.1 t.x //│ res: 1 -//│ = undefined +//│ = 1 //│ res: 2 -//│ = undefined +//│ = 2 //│ res: 1 //│ = 1 @@ -211,14 +211,14 @@ def myval: A & { x: anything } // //│ myval: A with {x: string} -def tuuu: (1 | 2, true) & {_1: 2 | 3} +def tuuu: (1 | 2, true) & {0: 2 | 3} //│ tuuu: (2, true,) //│ = // tuuu: ((1 | 2) & (2 | 3), true,) // tuuu: (2, true,) // (S, T, U) -// Array[S | T | U] & { _1: S; _2: T; _3: U } +// Array[S | T | U] & { 1: S; 2: T; 3: U } def f(x: int, y: string) = x //│ f: (int, string,) -> int @@ -282,43 +282,43 @@ res: { x: int } //│ res: (1, 2, (true, false, ("hello", "world", "bye",),),) //│ = [ 1, 2, [ true, false, [ 'hello', 'world', 'bye' ] ] ] -k1 = (6, "hi", false) with {_5=5; _6=true} -k1._1 -k1._3 -//│ k1: (6, "hi", false,) & {_5: 5, _6: true} -//│ = [ 6, 'hi', false, _5: 5, _6: true ] +k1 = (6, "hi", false) with {4=5; 5=true} +k1.0 +k1.2 +//│ k1: (6, "hi", false,) & {4: 5, 5: true} +//│ = [ 6, 'hi', false, <1 empty item>, 5, true ] //│ res: 6 -//│ = undefined +//│ = 6 //│ res: false -//│ = undefined +//│ = false -(1,2,3) with {_2 = "hello"; _a = true; _4 = 4} -//│ res: {_1: 1, _2: "hello", _3: 3, _4: 4, _a: true} -//│ = [ 1, 2, 3, _2: 'hello', _a: true, _4: 4 ] +(1,2,3) with {1 = "hello"; _a = true; 3 = 4} +//│ res: {0: 1, 1: "hello", 2: 3, 3: 4, _a: true} +//│ = [ 1, 'hello', 3, 4, _a: true ] -(1,2,3) with {_1 = true; _0 = 233} -//│ res: {_0: 233, _1: true, _2: 2, _3: 3} -//│ = [ 1, 2, 3, _1: true, _0: 233 ] +(1,2,3) with {1 = true; 0 = 233} +//│ res: {0: 233, 1: true, 2: 3} +//│ = [ 233, true, 3 ] -(1, 2, true) with {_0 = "hello"} -//│ res: (1, 2, true,) & {_0: "hello"} -//│ = [ 1, 2, true, _0: 'hello' ] +(1, 2, true) with {0 = "hello"} +//│ res: {0: "hello", 1: 2, 2: true} +//│ = [ 'hello', 2, true ] ta1 = (5, 6, true, false, "hahaha") -ta2 = ta1 with {x = 123; _7 = "bye"; _1 = 0} -ta1._1 -ta2._2 -ta2._3 +ta2 = ta1 with {x = 123; 7 = "bye"; 0 = 0} +ta1.0 +ta2.1 +ta2.2 //│ ta1: (5, 6, true, false, "hahaha",) //│ = [ 5, 6, true, false, 'hahaha' ] -//│ ta2: {_1: 0, _2: 6, _3: true, _4: false, _5: "hahaha", _7: "bye", x: 123} -//│ = [ 5, 6, true, false, 'hahaha', x: 123, _7: 'bye', _1: 0 ] +//│ ta2: {0: 0, 1: 6, 2: true, 3: false, 4: "hahaha", 7: "bye", x: 123} +//│ = [ 0, 6, true, false, 'hahaha', <2 empty items>, 'bye', x: 123 ] //│ res: 5 -//│ = undefined +//│ = 5 //│ res: 6 -//│ = undefined +//│ = 6 //│ res: true -//│ = undefined +//│ = true def rep5: 'a -> Array['a] def rep5 x = (x,x,x,x,x) @@ -329,69 +329,69 @@ def rep5 x = (x,x,x,x,x) //│ 'a -> Array['a] //│ = [Function: rep5] -rep5 1 with {_1 = 10} -a2 = rep5 2 with {_2 = true; x = "haha"} -a2._2 +rep5 1 with {0 = 10} +a2 = rep5 2 with {1 = true; x = "haha"} +a2.1 a2.x -//│ res: Array[1] & {_1: 10} -//│ = [ 1, 1, 1, 1, 1, _1: 10 ] -//│ a2: Array[2] & {_2: true, x: "haha"} -//│ = [ 2, 2, 2, 2, 2, _2: true, x: 'haha' ] +//│ res: Array[1] & {0: 10} +//│ = [ 10, 1, 1, 1, 1 ] +//│ a2: Array[2] & {1: true, x: "haha"} +//│ = [ 2, true, 2, 2, 2, x: 'haha' ] //│ res: true //│ = true //│ res: "haha" //│ = 'haha' :e -a2._1 +a2.0 //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.346: a2._1 -//│ ║ ^^^^^ -//│ ╟── type `Array['a]` does not match type `{_1: ?a} | ~{_2: true, x: "haha"}` +//│ ║ l.346: a2.0 +//│ ║ ^^^^ +//│ ╟── type `Array['a]` does not match type `{0: ?a} | ~{1: true, x: "haha"}` //│ ║ l.323: def rep5: 'a -> Array['a] //│ ║ ^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `{_1: ?a} | ~{_2: true, x: "haha"}` -//│ ║ l.346: a2._1 +//│ ╟── but it flows into reference with expected type `{0: ?a} | ~{1: true, x: "haha"}` +//│ ║ l.346: a2.0 //│ ╙── ^^ //│ res: error -//│ = undefined +//│ = 2 (1,2,3,true) with {_a = 1; _b1 = false} //│ res: (1, 2, 3, true,) & {_a: 1, _b1: false} //│ = [ 1, 2, 3, true, _a: 1, _b1: false ] -ht1 = (1,2,false) with {_1 = 'a'; _2 = 'hello'; _3 = false} -ht1._1 -//│ ht1: {_1: "a", _2: "hello", _3: false} -//│ = [ 1, 2, false, _1: 'a', _2: 'hello', _3: false ] +ht1 = (1,2,false) with {0 = 'a'; 1 = 'hello'; 2 = false} +ht1.0 +//│ ht1: {0: "a", 1: "hello", 2: false} +//│ = [ 'a', 'hello', false ] //│ res: "a" //│ = 'a' -def hg1 t = (t._1, t._2) +def hg1 t = (t.0, t.1) hg1 ht1 hg1 ((5,5,5)) -(hg1 ht1)._2 -//│ hg1: {_1: 'a, _2: 'b} -> ('a, 'b,) +(hg1 ht1).1 +//│ hg1: {0: 'a, 1: 'b} -> ('a, 'b,) //│ = [Function: hg1] //│ res: ("a", "hello",) //│ = [ 'a', 'hello' ] //│ res: (5, 5,) -//│ = [ undefined, undefined ] +//│ = [ 5, 5 ] //│ res: "hello" -//│ = undefined +//│ = 'hello' def ta1: Array[int] | (int, bool) -def test: (string, 1) & { _1: "hello" } -def test2: (string, 1) & { _1: "hello"; _3: int } +def test: (string, 1) & { 0: "hello" } +def test2: (string, 1) & { 0: "hello"; 2: int } //│ ta1: Array[bool | int] //│ = //│ test: ("hello", 1,) //│ = -//│ test2: ("hello", 1,) & {_3: int} +//│ test2: ("hello", 1,) & {2: int} //│ = -test: { _1: 'a } -//│ res: {_1: "hello"} +test: { 0: 'a } +//│ res: {0: "hello"} //│ = //│ test is not implemented @@ -403,9 +403,9 @@ test: ('a, 1) //│ = //│ test is not implemented -// TODO in principe, we could narrow the refinement to ` & { _1: 1 }` here... -def test3: Array[1] & { _1: int } -//│ test3: Array[1] & {_1: int} +// TODO in principe, we could narrow the refinement to ` & { 1: 1 }` here... +def test3: Array[1] & { 0: int } +//│ test3: Array[1] & {0: int} //│ = def fta1: Array[int | bool] -> int @@ -420,7 +420,7 @@ fta1 r1 //│ res: int //│ = //│ fta1 is not implemented -//│ r1: Array[1 | 2 | 3] & {_1: 1, _2: 2} +//│ r1: Array[1 | 2 | 3] & {0: 1, 1: 2} //│ = [ 1, 2, 3 ] //│ res: int //│ = @@ -429,9 +429,9 @@ fta1 r1 :NoJS def p1: T | Array[bool] | (int, string) | (true, 3) def p2: T | (string, bool) | Array[int] | (2, 4) -def pf t = (t[1], t._1) +def pf t = (t[1], t.0) pf((1,2,3)) //│ p1: Array[bool | int | string] | T //│ p2: Array[bool | int | string] | T -//│ pf: (Array['a & ~undefined] & {_1: 'b}) -> (undefined | 'a, 'b,) +//│ pf: (Array['a & ~undefined] & {0: 'b}) -> (undefined | 'a, 'b,) //│ res: (1 | 2 | 3 | undefined, 1,) diff --git a/shared/src/test/diff/mlscript/TupleArray2.mls b/shared/src/test/diff/mlscript/TupleArray2.mls index c35eca01c3..7eee0690b0 100644 --- a/shared/src/test/diff/mlscript/TupleArray2.mls +++ b/shared/src/test/diff/mlscript/TupleArray2.mls @@ -154,7 +154,7 @@ f_2 = f_1 -def test: (string, 1) & { _1: "hello" } +def test: (string, 1) & { 0: "hello" } //│ test: ("hello", 1,) //│ = @@ -170,8 +170,8 @@ test = ("hi", 1) //│ ║ l.162: test = ("hi", 1) //│ ║ ^^^^ //│ ╟── Note: constraint arises from literal type: -//│ ║ l.157: def test: (string, 1) & { _1: "hello" } -//│ ╙── ^^^^^^^ +//│ ║ l.157: def test: (string, 1) & { 0: "hello" } +//│ ╙── ^^^^^^^ //│ = [ 'hi', 1 ] test = ("hello", 1) @@ -184,8 +184,8 @@ test = ("hello", 1) //│ res: string //│ = 'hello' -test: { _1: 'a } -//│ res: {_1: "hello"} +test: { 0: 'a } +//│ res: {0: "hello"} //│ = [ 'hello', 1 ] test: ('a, 1) @@ -200,7 +200,7 @@ class A: (1,2) :re -error: Array[1] & { _1: int } -//│ res: Array[1] & {_1: int} +error: Array[1] & { 0: int } +//│ res: Array[1] & {0: int} //│ Runtime error: //│ Error: an error was thrown diff --git a/shared/src/test/diff/mlscript/Yicong.mls b/shared/src/test/diff/mlscript/Yicong.mls index a1b4e2a760..8d21237181 100644 --- a/shared/src/test/diff/mlscript/Yicong.mls +++ b/shared/src/test/diff/mlscript/Yicong.mls @@ -141,18 +141,18 @@ t = if false then res else hhh g = if true then (6,6,6) else res gwx = g with {x=123} gwx.x with {y = gwx} -//│ res: Array["hello" | 1 | 2 | 3 | 4 | false | true] & {_1: 1 | true, _2: 2 | 4, _3: 3 | false} +//│ res: Array["hello" | 1 | 2 | 3 | 4 | false | true] & {0: 1 | true, 1: 2 | 4, 2: 3 | false} //│ = [ 1, 2, 3, 'hello' ] -//│ hhh: Array["bye" | 345 | 3 | 45 | false | true] & {_1: 45 | false, _2: 345 | 3} +//│ hhh: Array["bye" | 345 | 3 | 45 | false | true] & {0: 45 | false, 1: 345 | 3} //│ = [ false, 3 ] -//│ t: Array["bye" | "hello" | 1 | 2 | 345 | 3 | 45 | 4 | false | true] & {_1: 1 | 45 | false | true, _2: 2 | 345 | 3 | 4} +//│ t: Array["bye" | "hello" | 1 | 2 | 345 | 3 | 45 | 4 | false | true] & {0: 1 | 45 | false | true, 1: 2 | 345 | 3 | 4} //│ = [ false, 3 ] -//│ g: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {_1: 1 | 6 | true, _2: 2 | 4 | 6, _3: 3 | 6 | false} +//│ g: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {0: 1 | 6 | true, 1: 2 | 4 | 6, 2: 3 | 6 | false} //│ = [ 6, 6, 6 ] -//│ gwx: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {_1: 1 | 6 | true, _2: 2 | 4 | 6, _3: 3 | 6 | false, x: 123} +//│ gwx: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {0: 1 | 6 | true, 1: 2 | 4 | 6, 2: 3 | 6 | false, x: 123} //│ = [ 6, 6, 6, x: 123 ] //│ res: 123 & { -//│ y: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {_1: 1 | 6 | true, _2: 2 | 4 | 6, _3: 3 | 6 | false, x: 123} +//│ y: Array["hello" | 1 | 2 | 3 | 4 | 6 | false | true] & {0: 1 | 6 | true, 1: 2 | 4 | 6, 2: 3 | 6 | false, x: 123} //│ } //│ = [Number: 123] { y: [ 6, 6, 6, x: 123 ] } @@ -165,14 +165,14 @@ def g: (bool, string, int) -> int //│ = p1 = if true then (1, 2, 2) else (true, false) -//│ p1: Array[1 | 2 | false | true] & {_1: 1 | true, _2: 2 | false} +//│ p1: Array[1 | 2 | false | true] & {0: 1 | true, 1: 2 | false} //│ = [ 1, 2, 2 ] def q: Array[int] q = if true then (1,1) else (1,1,1) //│ q: Array[int] //│ = -//│ Array[1] & {_1: 1, _2: 1} +//│ Array[1] & {0: 1, 1: 1} //│ <: q: //│ Array[int] //│ = [ 1, 1 ] @@ -212,11 +212,11 @@ def h f = (f ((1,2,false)), f ((1,true))) //│ = [Function: h1] h (fun x -> x[0]) -h (fun x -> x._1) +h (fun x -> x.0) //│ res: (1 | 2 | false | undefined, 1 | true | undefined,) //│ = [ 1, 1 ] //│ res: (1, 1,) -//│ = [ undefined, undefined ] +//│ = [ 1, 1 ] q1 = (1,1,1,1) @@ -332,7 +332,7 @@ tk (two.snd) :e def a1: Array[int] a1 = (1,2,true,'hello') -a1._2 +a1.1 //│ a1: Array[int] //│ = //│ (1, 2, true, "hello",) @@ -349,16 +349,16 @@ a1._2 //│ ╙── ^^^ //│ = [ 1, 2, true, 'hello' ] //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.335: a1._2 -//│ ║ ^^^^^ -//│ ╟── type `Array[int]` does not have field '_2' +//│ ║ l.335: a1.1 +//│ ║ ^^^^ +//│ ╟── type `Array[int]` does not have field '1' //│ ║ l.333: def a1: Array[int] //│ ║ ^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `{_2: ?a}` -//│ ║ l.335: a1._2 +//│ ╟── but it flows into reference with expected type `{1: ?a}` +//│ ║ l.335: a1.1 //│ ╙── ^^ //│ res: error -//│ = undefined +//│ = 2 def getx p = p.x def a123: Array[int] @@ -678,32 +678,32 @@ ra: (Array['a], Array['a], Array['a]) as 'a //│ = //│ ra is not implemented -def tktup t = (t._2, t._3) +def tktup t = (t.1, t.2) tktup ((1,2,3,true)) -//│ tktup: {_2: 'a, _3: 'b} -> ('a, 'b,) +//│ tktup: {1: 'a, 2: 'b} -> ('a, 'b,) //│ = [Function: tktup] //│ res: (2, 3,) -//│ = [ undefined, undefined ] +//│ = [ 2, 3 ] :e tktup a123 //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.689: tktup a123 //│ ║ ^^^^^^^^^^ -//│ ╟── type `Array[int]` does not have field '_3' +//│ ╟── type `Array[int]` does not have field '2' //│ ║ l.364: def a123: Array[int] //│ ║ ^^^^^^^^^^ -//│ ╟── but it flows into reference with expected type `{_3: ?a}` +//│ ╟── but it flows into reference with expected type `{2: ?a}` //│ ║ l.689: tktup a123 //│ ║ ^^^^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.681: def tktup t = (t._2, t._3) -//│ ║ ^^^^ +//│ ║ l.681: def tktup t = (t.1, t.2) +//│ ║ ^^^ //│ ╟── from reference: -//│ ║ l.681: def tktup t = (t._2, t._3) -//│ ╙── ^ +//│ ║ l.681: def tktup t = (t.1, t.2) +//│ ╙── ^ //│ res: error | (nothing, nothing,) -//│ = [ undefined, undefined ] +//│ = [ 2, 3 ] def definedOr x els = case x of { @@ -860,24 +860,24 @@ mk1[2 ] //│ res: error | undefined //│ = undefined -def s1 a = (defined a[1] + defined a[2], a[(1,2)._2]) -def s2 a = (defined (defined a[1])[0])._2 + (defined a[2])._1 -def s3 a = defined a._1.t[0] + defined (defined a.x[1])[2] -(defined ((1, "hello"),(2, true, false),(3,3,4))[0])._1 +def s1 a = (defined a[1] + defined a[2], a[(1,2).1]) +def s2 a = (defined (defined a[1])[0]).1 + (defined a[2]).0 +def s3 a = defined a.0.t[0] + defined (defined a.x[1])[2] +(defined ((1, "hello"),(2, true, false),(3,3,4))[0]).0 //│ s1: Array[int & 'a] -> (int, undefined | 'a,) //│ = [Function: s1] -//│ s2: Array[Array[{_2: int} & ~undefined] & {_1: int}] -> int +//│ s2: Array[Array[{1: int} & ~undefined] & {0: int}] -> int //│ = [Function: s2] -//│ s3: {_1: {t: Array[int]}, x: Array[Array[int]]} -> int +//│ s3: {0: {t: Array[int]}, x: Array[Array[int]]} -> int //│ = [Function: s3] //│ res: 1 | 2 | 3 -//│ = undefined +//│ = 1 def ara: Array[(int, bool)] def arb: Array[Array[(int, int)]] -(defined ara[1])._1 -(defined (defined arb[0])[1])._2 -def s4 arr = (defined (defined (defined arr.x[0])._3[6])[7])._h.hello +(defined ara[1]).0 +(defined (defined arb[0])[1]).1 +def s4 arr = (defined (defined (defined arr.x[0]).2[6])[7])._h.hello //│ ara: Array[(int, bool,)] //│ = //│ arb: Array[Array[(int, int,)]] @@ -888,13 +888,13 @@ def s4 arr = (defined (defined (defined arr.x[0])._3[6])[7])._h.hello //│ res: int //│ = //│ arb is not implemented -//│ s4: {x: Array[{_3: Array[Array[{_h: {hello: 'hello}} & ~undefined]]} & ~undefined]} -> 'hello +//│ s4: {x: Array[{2: Array[Array[{_h: {hello: 'hello}} & ~undefined]]} & ~undefined]} -> 'hello //│ = [Function: s4] -def at1 xs = (defined xs[0])._1 +def at1 xs = (defined xs[0]).0 def dup a b = a * 2 + b -dup (defined ara[1])._1 (defined (defined arb[10])[8])._2 + 1 -//│ at1: Array[{_1: 'a} & ~undefined] -> 'a +dup (defined ara[1]).0 (defined (defined arb[10])[8]).1 + 1 +//│ at1: Array[{0: 'a} & ~undefined] -> 'a //│ = [Function: at1] //│ dup: int -> int -> int //│ = [Function: dup] @@ -903,16 +903,15 @@ dup (defined ara[1])._1 (defined (defined arb[10])[8])._2 + 1 //│ ara is not implemented :e -(1,2,3)._1[1] +(1,2,3).0[1] //│ ╔══[ERROR] Type mismatch in array access: -//│ ║ l.906: (1,2,3)._1[1] -//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.906: (1,2,3).0[1] +//│ ║ ^^^^^^^^^^^^ //│ ╟── integer literal of type `1` does not match type `Array[?a]` -//│ ║ l.906: (1,2,3)._1[1] +//│ ║ l.906: (1,2,3).0[1] //│ ║ ^ //│ ╟── but it flows into field selection with expected type `Array[?b]` -//│ ║ l.906: (1,2,3)._1[1] -//│ ╙── ^^^^^^^^^^ +//│ ║ l.906: (1,2,3).0[1] +//│ ╙── ^^^^^^^^^ //│ res: error | undefined -//│ Runtime error: -//│ TypeError: Cannot read properties of undefined (reading '1') +//│ = undefined diff --git a/shared/src/test/diff/nu/Ascription.mls b/shared/src/test/diff/nu/Ascription.mls index ff022d5c0c..0060edad14 100644 --- a/shared/src/test/diff/nu/Ascription.mls +++ b/shared/src/test/diff/nu/Ascription.mls @@ -31,8 +31,21 @@ foo(123 : Int) : Int //│ res //│ = 124 +:e +foo(123: Int): Int +//│ ╔══[ERROR] Cannot use named arguments as the function type has untyped arguments +//│ ║ l.35: foo(123: Int): Int +//│ ╙── ^^^^^^^^^^ +//│ Int +//│ Code generation encountered an error: +//│ unresolved symbol Int + +:e foo(123:Int):Int +//│ ╔══[ERROR] Cannot use named arguments as the function type has untyped arguments +//│ ║ l.44: foo(123:Int):Int +//│ ╙── ^^^^^^^^^ //│ Int -//│ res -//│ = 124 +//│ Code generation encountered an error: +//│ unresolved symbol Int diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 31de48af83..811f685d07 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -316,11 +316,9 @@ let wd = w(1) //│ wd //│ = [ [ [ 1 ] ] ] -// TODO implement _1 -wd._1._1._1 + 1 +wd.0.0.0 + 1 //│ Int //│ res -//│ Runtime error: -//│ TypeError: Cannot read properties of undefined (reading '_1') +//│ = 2 diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index a3e0aff6c7..93a890c05c 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -26,7 +26,7 @@ trait Product[A, B] extends Into[A] { //│ 'T := A class TwoInts(val pair: [Int, Int]) extends Product[Int, Int] { - fun Into = pair._1 + pair._2 + fun Into = pair.0 + pair.1 } //│ class TwoInts(pair: [Int, Int]) extends Into, Product { //│ fun Into: Int diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 34ab4936b8..1f97848ab4 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -843,7 +843,7 @@ class Bc12() extends Bc1(1), Bc2(true) //│ Code generation encountered an error: //│ unexpected parent symbol new class Bc2. -class Bc02() extends Bc1(1:Int) { +class Bc02() extends Bc1(1 : Int) { val foo = 2 } //│ class Bc02() extends Bc1 { @@ -961,10 +961,10 @@ fb(bp, false) //│ bp is not implemented class CP() extends BPar[Int] { - fun f(x) = [x._2, x._1] + fun f(x) = [x.1, x.0] } //│ class CP() extends BPar, Base { -//│ fun f: forall 'a 'b. {_1: 'a, _2: 'b} -> ['b, 'a] +//│ fun f: forall 'a 'b. {0: 'a, 1: 'b} -> ['b, 'a] //│ } let cp1 = CP() @@ -975,7 +975,7 @@ let cp1 = CP() fb(cp1, 2) //│ [Int, Int] //│ res -//│ = [ undefined, undefined ] +//│ = [ 2, 1 ] trait BInfer1 extends Base //│ trait BInfer1 extends Base { diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index c394d2af85..a9c1de4d73 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -38,16 +38,16 @@ fun list_assoc(s, l: List<'a>) = l.match( ifNil: () => NotFound, ifCons: (h, t) => - if eq(s, h._1) then Success(h._2) + if eq(s, h.0) then Success(h.1) else list_assoc(s, t) ) -//│ fun list_assoc: forall 'A. (Str, l: List[{_1: Str, _2: 'A}]) -> (NotFound | Success['A]) +//│ fun list_assoc: forall 'A. (Str, l: List[{0: Str, 1: 'A}]) -> (NotFound | Success['A]) -list_assoc : (Str, List<{ _1: Str, _2: 'b }>) => (NotFound | Success['b]) -//│ (Str, List[{_1: Str, _2: 'b}]) -> (NotFound | Success['b]) +list_assoc : (Str, List<{ 0: Str, 1: 'b }>) => (NotFound | Success['b]) +//│ (Str, List[{0: Str, 1: 'b}]) -> (NotFound | Success['b]) -fun list_assoc(s: Str, l: List<{ _1: Str, _2: 'b }>): NotFound | Success['b] -//│ fun list_assoc: forall 'b. (s: Str, l: List[{_1: Str, _2: 'b}]) -> (NotFound | Success['b]) +fun list_assoc(s: Str, l: List<{ 0: Str, 1: 'b }>): NotFound | Success['b] +//│ fun list_assoc: forall 'b. (s: Str, l: List[{0: Str, 1: 'b}]) -> (NotFound | Success['b]) class Var(s: Str) //│ class Var(s: Str) @@ -60,7 +60,7 @@ mixin EvalVar { Success(r) then r } //│ mixin EvalVar() { -//│ fun eval: (List[{_1: Str, _2: 'a}], Var) -> (Var | 'a) +//│ fun eval: (List[{0: Str, 1: 'a}], Var) -> (Var | 'a) //│ } class Abs(x: Str, t: A) @@ -103,7 +103,7 @@ mixin EvalLambda { module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: (List[{_1: Str, _2: 'a}], 'b) -> 'a +//│ fun eval: (List[{0: Str, 1: 'a}], 'b) -> 'a //│ } //│ where //│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Var @@ -162,7 +162,7 @@ mixin EvalExpr { module Test2 extends EvalVar, EvalExpr //│ module Test2 { -//│ fun eval: forall 'a. (List[{_1: Str, _2: Object & 'b}], 'a & (Add['c] | Mul['c] | Numb | Var)) -> (Numb | Var | 'b | 'a | 'c) +//│ fun eval: forall 'a. (List[{0: Str, 1: Object & 'b}], 'a & (Add['c] | Mul['c] | Numb | Var)) -> (Numb | Var | 'b | 'a | 'c) //│ } //│ where //│ 'c <: Add['c] | Mul['c] | Numb | Var @@ -181,7 +181,7 @@ Test2.eval(Cons(["a", Abs("d", Var("d"))], Nil()), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: (List[{_1: Str, _2: 'a}], 'b) -> 'c +//│ fun eval: (List[{0: Str, 1: 'a}], 'b) -> 'c //│ } //│ where //│ 'a :> 'c @@ -202,7 +202,7 @@ Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil()), App(Abs("a", Var("a")), Add(N module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: (List[{_1: Str, _2: 'a}], 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) +//│ fun eval: (List[{0: Str, 1: 'a}], 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) //│ } //│ where //│ 'a :> 'b | 'c diff --git a/shared/src/test/diff/nu/Tuples.mls b/shared/src/test/diff/nu/Tuples.mls new file mode 100644 index 0000000000..42b5343ac8 --- /dev/null +++ b/shared/src/test/diff/nu/Tuples.mls @@ -0,0 +1,118 @@ +:NewDefs + + +// Tuple literals use square brackets. +let t = [0, 1, 2] +//│ let t: [0, 1, 2] +//│ t +//│ = [ 0, 1, 2 ] + + +// Tuple indices are zero-based. +t.0 +t.1 +t.2 +//│ 2 +//│ res +//│ = 0 +//│ res +//│ = 1 +//│ res +//│ = 2 + + +// Tuple indices cannot be negative. +:e +t.-1 +//│ ╔══[ERROR] identifier not found: .- +//│ ║ l.26: t.-1 +//│ ╙── ^^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol .- + + +// Non-zero tuple indices cannot start with a zero. +:e +t.01 +//│ ╔══[ERROR] identifier not found: . +//│ ║ l.37: t.01 +//│ ╙── ^ +//│ error +//│ Code generation encountered an error: +//│ unresolved symbol . + + +// Out of bounds indices cause type errors. +:e +t.3 +//│ ╔══[ERROR] Type mismatch in field selection: +//│ ║ l.48: t.3 +//│ ║ ^^^ +//│ ╟── tuple literal of type `{0: 0, 1: 1, 2: 2}` does not have field '3' +//│ ║ l.5: let t = [0, 1, 2] +//│ ║ ^^^^^^^^^ +//│ ╟── but it flows into reference with expected type `{3: ?a}` +//│ ║ l.48: t.3 +//│ ╙── ^ +//│ error +//│ res +//│ = undefined + + +// Note that record fields can be integers with leading zeros. +{ 000000: "just zero" } +{ 042: "cuarenta y dos" } +//│ {42: "cuarenta y dos"} +//│ res +//│ = { '0': 'just zero' } +//│ res +//│ = { '42': 'cuarenta y dos' } + + +// Negative integer record fields are disallowed, which aligns with JavaScript. +:pe +:e +{ -1: "oh no" } +//│ ╔══[PARSE ERROR] Record field should have a name +//│ ╙── +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ╟── integer literal of type `-1` does not match type `"oh no"` +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.76: { -1: "oh no" } +//│ ╙── ^^^^^^^ +//│ {: "oh no"} +//│ res +//│ = { '': -1 } + + +// Note that leading zeros of integer record fields are ignored. +// And duplicate fields lead to errors. +:e +{ 0: "oh", 00: "no" } +//│ ╔══[ERROR] Multiple declarations of field name 0 in record literal +//│ ║ l.92: { 0: "oh", 00: "no" } +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── Declared at +//│ ║ l.92: { 0: "oh", 00: "no" } +//│ ║ ^ +//│ ╟── Declared at +//│ ║ l.92: { 0: "oh", 00: "no" } +//│ ╙── ^^ +//│ {0: "oh", 0: "no"} +//│ res +//│ = { '0': 'no' } + + +// Fields that are integers or start with an underscore should not be used as name hints. +fun f(x) = x._q +fun g(x) = x._1 +fun h(x) = x.1 +//│ fun f: forall 'a. {_q: 'a} -> 'a +//│ fun g: forall 'b. {_1: 'b} -> 'b +//│ fun h: forall 'c. {1: 'c} -> 'c + + +// Other fields should be used as name hints. +fun p(x) = x.y +//│ fun p: forall 'y. {y: 'y} -> 'y diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 0b4e81c386..03ab69c023 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -6,7 +6,7 @@ fun f: Str | [Str, Int] //│ fun f: Str | [Str, Int] fun f: [Str] | [Str, Int] -//│ fun f: Array[Int | Str] & {_1: Str} +//│ fun f: Array[Int | Str] & {0: Str} fun f: (Str | [Str, Int]) //│ fun f: Str | [Str, Int] @@ -33,7 +33,7 @@ fun f: Str | ((Str, Int)) // * This type merges the input tuples, resulting in the union seen above: fun f: (Str => Str) & ((Str, Int) => Str) -//│ fun f: (...Array[Int | Str] & {_1: Str}) -> Str +//│ fun f: (...Array[Int | Str] & {0: Str}) -> Str f("abc", "abc") //│ Str From 8894b740eadba1d5f597160fa0d4fa4de8fd802c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 22 Nov 2023 23:23:05 +0800 Subject: [PATCH 483/498] Update Scala and Wartremover versions --- build.sbt | 18 ++++---- .../scala/mlscript/compiler/Helpers.scala | 42 ++++++------------- js/src/main/scala/Main.scala | 2 +- project/plugins.sbt | 2 +- .../src/main/scala/mlscript/NewParser.scala | 5 +-- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- .../codegen/typescript/TsTypegen.scala | 6 +-- .../main/scala/mlscript/ucs/Desugarer.scala | 12 +++--- .../src/test/scala/mlscript/DiffTests.scala | 5 ++- 9 files changed, 37 insertions(+), 57 deletions(-) diff --git a/build.sbt b/build.sbt index 66cf668450..8f4ff503f5 100644 --- a/build.sbt +++ b/build.sbt @@ -2,10 +2,15 @@ import Wart._ enablePlugins(ScalaJSPlugin) -ThisBuild / scalaVersion := "2.13.9" +ThisBuild / scalaVersion := "2.13.12" ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / organization := "io.lptk" ThisBuild / organizationName := "LPTK" +ThisBuild / scalacOptions ++= Seq( + "-deprecation", + "-feature", + "-unchecked", +) lazy val root = project.in(file(".")) .aggregate(mlscriptJS, mlscriptJVM, ts2mlsTest, compilerJVM) @@ -18,9 +23,6 @@ lazy val mlscript = crossProject(JSPlatform, JVMPlatform).in(file(".")) .settings( name := "mlscript", scalacOptions ++= Seq( - "-deprecation", - "-feature", - "-unchecked", "-language:higherKinds", "-Ywarn-value-discard", "-Ypatmat-exhaust-depth:160", @@ -36,7 +38,8 @@ lazy val mlscript = crossProject(JSPlatform, JVMPlatform).in(file(".")) StringPlusAny, Any, ToString, JavaSerializable, Serializable, Product, ToString, LeakingSealed, Overloading, - Option2Iterable, IterableOps, ListAppend + Option2Iterable, IterableOps, ListAppend, SeqApply, + TripleQuestionMark, ), libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.12" % Test, libraryDependencies += "com.lihaoyi" %%% "sourcecode" % "0.3.0", @@ -60,10 +63,6 @@ lazy val mlscriptJS = mlscript.js lazy val ts2mls = crossProject(JSPlatform, JVMPlatform).in(file("ts2mls")) .settings( name := "ts2mls", - scalaVersion := "2.13.8", - scalacOptions ++= Seq( - "-deprecation" - ) ) .jvmSettings() .jsSettings( @@ -76,7 +75,6 @@ lazy val ts2mlsJVM = ts2mls.jvm lazy val ts2mlsTest = project.in(file("ts2mls")) .settings( - scalaVersion := "2.13.8", Test / test := ((ts2mlsJVM / Test / test) dependsOn (ts2mlsJS / Test / test)).value ) diff --git a/compiler/shared/main/scala/mlscript/compiler/Helpers.scala b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala index a49bd85bd3..5eb1a526dc 100644 --- a/compiler/shared/main/scala/mlscript/compiler/Helpers.scala +++ b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala @@ -1,25 +1,9 @@ -package mlscript.compiler +package mlscript +package compiler -import mlscript.{App, Asc, Assign, Bind, Blk, Bra, CaseOf, Lam, Let, Lit, - New, Rcd, Sel, Subs, Term, Test, Tup, With, Var, Fld, FldFlags, If, PolyType} -import mlscript.{IfBody, IfThen, IfElse, IfLet, IfOpApp, IfOpsApp, IfBlock} -import mlscript.UnitLit import mlscript.codegen.Helpers.inspect as showStructure -import mlscript.compiler.mono.MonomorphError -import mlscript.NuTypeDef -import mlscript.NuFunDef +import mlscript.compiler.mono.{Monomorph, MonomorphError} import scala.collection.mutable.ArrayBuffer -import mlscript.CaseBranches -import mlscript.Case -import mlscript.NoCases -import mlscript.Wildcard -import mlscript.DecLit -import mlscript.IntLit -import mlscript.StrLit -import mlscript.AppliedType -import mlscript.TypeName -import mlscript.TypeDefKind -import mlscript.compiler.mono.Monomorph object Helpers: /** @@ -54,10 +38,10 @@ object Helpers: val params = toFuncParams(args).toList Expr.Lambda(params, term2Expr(body)) case App(App(Var("."), self), App(Var(method), args: Tup)) => - Expr.Apply(Expr.Select(term2Expr(self), Expr.Ref(method)), List.from(toFuncArgs(args).map(term2Expr))) + Expr.Apply(Expr.Select(term2Expr(self), Expr.Ref(method)), List.from(toFuncArgs(args).iterator.map(term2Expr))) case App(lhs, rhs) => val callee = term2Expr(lhs) - val arguments = toFuncArgs(rhs).map(term2Expr).toList + val arguments = toFuncArgs(rhs).iterator.map(term2Expr).toList Expr.Apply(callee, arguments) case Tup(fields) => Expr.Tuple(fields.map { @@ -127,7 +111,7 @@ object Helpers: val typeName = constructor match case AppliedType(TypeName(name), _) => name case TypeName(name) => name - Expr.New(TypeName(typeName), toFuncArgs(args).map(term2Expr).toList) + Expr.New(TypeName(typeName), toFuncArgs(args).iterator.map(term2Expr).toList) // case Blk(unit) => Expr.Isolated(trans2Expr(TypingUnit(unit))) case If(body, alternate) => body match case IfThen(condition, consequent) => @@ -172,7 +156,12 @@ object Helpers: }) val typeDecl: Item.TypeDecl = Item.TypeDecl( Expr.Ref(className.name), // name - kind, // kind + kind match // kind + case Als => TypeDeclKind.Alias + case Cls => TypeDeclKind.Class + case Trt => TypeDeclKind.Trait + case _ => throw MonomorphError(s"Unsupported TypeDefKind conversion ${kind}") + , tparams.map(_._2), // typeParams toFuncParams(params.getOrElse(Tup(Nil))).toList, // params parents.map { @@ -187,10 +176,3 @@ object Helpers: ) typeDecl - private given Conversion[TypeDefKind, TypeDeclKind] with - import mlscript.{Als, Cls, Trt} - def apply(kind: TypeDefKind): TypeDeclKind = kind match - case Als => TypeDeclKind.Alias - case Cls => TypeDeclKind.Class - case Trt => TypeDeclKind.Trait - case _ => throw MonomorphError(s"Unsupported TypeDefKind conversion ${kind}") diff --git a/js/src/main/scala/Main.scala b/js/src/main/scala/Main.scala index deba214668..a67f8ce8a3 100644 --- a/js/src/main/scala/Main.scala +++ b/js/src/main/scala/Main.scala @@ -88,7 +88,7 @@ object Main { if (l =:= endLineNum) endLineCol else curLine.length + 1 val front = curLine.slice(0, c - 1) val middle = underline(curLine.slice(c - 1, lastCol - 1)) - val back = curLine.slice(lastCol - 1, curLine.size) + val back = curLine.slice(lastCol - 1, curLine.length) output(s"$prepre$pre\t$front$middle$back") c = 1 l += 1 diff --git a/project/plugins.sbt b/project/plugins.sbt index 66dc10c855..3d01a25463 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ -addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.0.6") +addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.1.5") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.11.0") addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.2.0") diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index f0a38600aa..5b56641d99 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -258,9 +258,8 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case class ModifierSet(mods: Map[Str, Loc]) { def handle(mod: Str): (Opt[Loc], ModifierSet) = mods.get(mod) -> copy(mods = mods - mod) - def done: Unit = mods.foreach { - case (mod, loc) => - err(msg"Unrecognized modifier `${mod}` in this position" -> S(loc) :: Nil) + def done: Unit = mods.foreachEntry { (mod, loc) => + err(msg"Unrecognized modifier `${mod}` in this position" -> S(loc) :: Nil) } } object ModifierSet { diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 033964e0a4..ceb2fd23c5 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -276,7 +276,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } }() } - members.foreach { + members.foreachEntry { case (_, m: NuParam) if m.isType => case (_, m) => Trav.applyMem(PolMap.pos)(m) } diff --git a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala index 80d45b759b..51a41cfa35 100644 --- a/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala +++ b/shared/src/main/scala/mlscript/codegen/typescript/TsTypegen.scala @@ -198,13 +198,13 @@ final class TsTypegenCodeBuilder { // add body fields classFieldsAndType - .map {case (fieldVar, fieldTypes) => + .map { case (fieldVar, fieldTypes) => val fieldTypesCode = toTypegenInheritedFields(fieldTypes) (SourceCode(fieldVar.name), fieldTypesCode) } - .foreach({ case (fieldVar, fieldType) => { + .foreachEntry { (fieldVar, fieldType) => { classDeclaration += SourceCode(" ") ++ fieldVar ++ SourceCode.colon ++ fieldType - }}) + }} // constructor needs all fields including super classes val allFieldsAndTypes = (classFieldsAndType ++ diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index d5156d86d8..6358f18928 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -371,12 +371,12 @@ class Desugarer extends TypeDefs { self: Typer => if (exhaustivenessMap.isEmpty) printlnUCS(" * ") else - exhaustivenessMap.foreach { case (symbol, patternMap) => + exhaustivenessMap.foreachEntry { (symbol, patternMap) => printlnUCS(s" * Patterns of $symbol") if (patternMap.isEmpty) printlnUCS(s" + ") else - patternMap.foreach { case (pattern, locations) => + patternMap.foreachEntry { (pattern, locations) => val first = pattern match { case Left(tupleArity) => s"()^$tupleArity" case Right(litOrCls) => litOrCls.toString() @@ -706,7 +706,7 @@ class Desugarer extends TypeDefs { self: Typer => printlnUCS("The match has a default branch. So, it is always safe.") case S(patternMap) => printlnUCS(s"The exhaustiveness map is") - exhaustivenessMap.foreach { case (key, matches) => + exhaustivenessMap.foreachEntry { (key, matches) => printlnUCS(s"- $key -> ${matches.keysIterator.mkString(", ")}") } printlnUCS(s"The scrutinee key is ${getScurtineeKey(scrutinee)}") @@ -714,7 +714,7 @@ class Desugarer extends TypeDefs { self: Typer => if (patternMap.isEmpty) printlnUCS("") else - patternMap.foreach { case (key, mutCase) => printlnUCS(s"- $key => $mutCase")} + patternMap.foreachEntry { (key, mutCase) => printlnUCS(s"- $key => $mutCase")} // Compute all classes that can be covered by this match. val coveredClassNames = Set.from[String](branches.iterator.flatMap { case MutCase.Literal(_, _) => Nil @@ -742,7 +742,7 @@ class Desugarer extends TypeDefs { self: Typer => case R(_) -> _ => true // Literals. Don't remove. } printlnUCS("Missing cases") - missingCases.foreach { case (key, m) => + missingCases.foreachEntry { (key, m) => printlnUCS(s"- $key -> ${m}") } if (!missingCases.isEmpty) { @@ -1030,7 +1030,7 @@ object Desugarer { if (graph.isEmpty) print(" + ") else - graph.foreach { case (source, targets) => + graph.foreachEntry { (source, targets) => print(s" + $source $arrow " + { if (targets.isEmpty) s"{}" else targets.mkString("{ ", ", ", " }") diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 07b66ff054..9d74c269bd 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -53,6 +53,7 @@ class DiffTests def postProcess(mode: ModeType, basePath: Ls[Str], testName: Str, unit: TypingUnit): Ls[Str] = Nil + @SuppressWarnings(Array("org.wartremover.warts.RedundantIsInstanceOf")) private val inParallel = isInstanceOf[ParallelTestExecution] import DiffTests._ @@ -1068,8 +1069,8 @@ class DiffTests val timeStr = (((endTime - beginTime) / 1000 / 100).toDouble / 10.0).toString val testColor = if (testFailed) Console.RED else Console.GREEN - val resStr = s"${" " * (35 - testStr.size)}${testColor}${ - " " * (6 - timeStr.size)}$timeStr ms${Console.RESET}" + val resStr = s"${" " * (35 - testStr.length)}${testColor}${ + " " * (6 - timeStr.length)}$timeStr ms${Console.RESET}" if (inParallel) println(s"${Console.CYAN}Processed${Console.RESET} $testStr$resStr") else println(resStr) From 8ab9346735ac1eba052505050e453f594937bf58 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 23 Nov 2023 00:54:58 +0800 Subject: [PATCH 484/498] Fix corner case parsing bug --- .../src/main/scala/mlscript/NewParser.scala | 2 +- shared/src/test/diff/nu/OpLam.mls | 53 +++++++++++++------ shared/src/test/diff/parser/IfThenElse.mls | 8 +-- shared/src/test/diff/parser/Ops.mls | 38 ++++++------- shared/src/test/diff/parser/Select.mls | 2 +- shared/src/test/diff/ucs/zipWith.mls | 10 +--- 6 files changed, 64 insertions(+), 49 deletions(-) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 5b56641d99..81484c69f4 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -995,7 +995,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo // val rhs = exprOrIf(1) rhs match { case R(rhs) => - val res = App(App(opv, acc), rhs) + val res = App(opv, PlainTup(acc, rhs)) cur match { case (NEWLINE, _) :: c => // TODO allow let bindings... consume diff --git a/shared/src/test/diff/nu/OpLam.mls b/shared/src/test/diff/nu/OpLam.mls index bcbddb6ae8..15b57dbca7 100644 --- a/shared/src/test/diff/nu/OpLam.mls +++ b/shared/src/test/diff/nu/OpLam.mls @@ -47,41 +47,64 @@ x => x + 2 >> succ //│ res //│ = [Function (anonymous)] -:e // FIXME parsing +:e x => x + 2 >> succ //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.51: x => x + 2 //│ ║ ^ //│ ║ l.52: >> succ -//│ ║ ^^^^ -//│ ╟── integer literal of type `2` is not a 2-element tuple +//│ ║ ^^^^^^^^^^ +//│ ╟── integer literal of type `2` is not a function //│ ║ l.51: x => x + 2 //│ ║ ^ -//│ ╟── Note: constraint arises from tuple literal: +//│ ╟── Note: constraint arises from application: +//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ ^^^^ +//│ ╟── from reference: //│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) -//│ ╙── ^^^^^^ +//│ ╙── ^ //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.51: x => x + 2 -//│ ║ ^ +//│ ║ ^^^^^ //│ ║ l.52: >> succ -//│ ║ ^^^^^^^^^^ -//│ ╟── reference of type `Int -> Int` is not a 1-element tuple +//│ ║ ^^^^^^^^^ +//│ ╟── function of type `?a -> ?b` is not an instance of type `Int` +//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── but it flows into operator application with expected type `Int` +//│ ║ l.51: x => x + 2 +//│ ║ ^ //│ ║ l.52: >> succ -//│ ╙── ^^^^ +//│ ╙── ^^^^^^^^^^ +//│ Int -> (Int | error) +//│ res +//│ = [Function: res] + +(x => x + 2) + >> succ //│ Int -> Int -//│ Code generation encountered an error: -//│ ill-formed application App(App(Var(>>), IntLit(2)), Var(succ)) +//│ res +//│ = [Function (anonymous)] + +:pe +>> succ +//│ ╔══[PARSE ERROR] Unexpected operator in expression position +//│ ║ l.91: >> succ +//│ ╙── ^^ +//│ Int -> Int +//│ res +//│ = [Function: succ] :e x => x.y => y //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.78: x => x.y => y -//│ ╙── ^^^ +//│ ║ l.101: x => x.y => y +//│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: y -//│ ║ l.78: x => x.y => y -//│ ╙── ^ +//│ ║ l.101: x => x.y => y +//│ ╙── ^ //│ anything -> error -> error //│ Code generation encountered an error: //│ term Sel(Var(x), y) is not a valid pattern diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 606640c2f0..e3de5bfaf8 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -465,7 +465,7 @@ if true then 0 + 1 //│ |#if| |true|→|#then| |0|→|+| |1|←|←| -//│ Parsed: {if (true) then +(...0)(...1)} +//│ Parsed: {if (true) then +(0, 1,)} if true then 0 @@ -478,7 +478,7 @@ if true else 0 + 1 //│ |#if| |true|→|#then| |0|↵|#else| |0|→|+| |1|←|←| -//│ Parsed: {if (true) then 0 else +(...0)(...1)} +//│ Parsed: {if (true) then 0 else +(0, 1,)} :pe if true @@ -504,12 +504,12 @@ if true if true then 0 + 1 //│ |#if| |true| |#then| |0|→|+| |1|←| -//│ Parsed: {if (true) then +(...0)(...1)} +//│ Parsed: {if (true) then +(0, 1,)} if true then 0 else 0 + 1 //│ |#if| |true| |#then| |0| |#else| |0|→|+| |1|←| -//│ Parsed: {if (true) then 0 else +(...0)(...1)} +//│ Parsed: {if (true) then 0 else +(0, 1,)} // TODO deal with meaningless whitespace: diff --git a/shared/src/test/diff/parser/Ops.mls b/shared/src/test/diff/parser/Ops.mls index 796d53e6fe..87c0576404 100644 --- a/shared/src/test/diff/parser/Ops.mls +++ b/shared/src/test/diff/parser/Ops.mls @@ -16,7 +16,7 @@ acc acc + 1 //│ |acc|→|+| |1|←| -//│ Parsed: {+(...acc)(...1)} +//│ Parsed: {+(acc, 1,)} acc + 1 @@ -32,26 +32,26 @@ acc //│ ║ ^ //│ ║ l.28: 1 //│ ╙── ^^ -//│ Parsed: {+(...acc)(...1)} +//│ Parsed: {+(acc, 1,)} acc + 1 //│ |acc|→|+|→|1|←|←| -//│ Parsed: {+(...acc)(...{1})} +//│ Parsed: {+(acc, {1},)} acc + 1 * 3 //│ |acc|→|+| |1|↵|*| |3|←| -//│ Parsed: {*(...(+(...acc)(...1)))(...3)} +//│ Parsed: {*(+(acc, 1,), 3,)} acc + 1 + 2 * 3 //│ |acc|→|+| |1|↵|+| |2|↵|*| |3|←| -//│ Parsed: {*(...(+(...(+(...acc)(...1)))(...2)))(...3)} +//│ Parsed: {*(+(+(acc, 1,), 2,), 3,)} acc + 1 + 2 * 3 //│ |acc| |+| |1| |+| |2| |*| |3| @@ -86,23 +86,23 @@ a +b c //│ |a|→|+|b|←|↵|c| -//│ Parsed: {+(...a)(...b); c} +//│ Parsed: {+(a, b,); c} a + b * 2 //│ |a| |+| |b|→|*| |2|←| -//│ Parsed: {+(a,)(*(...b)(...2),)} +//│ Parsed: {+(a,)(*(b, 2,),)} a(b) * 2 //│ |a|(|b|)|→|*| |2|←| -//│ Parsed: {*(...(a(b,)))(...2)} +//│ Parsed: {*(a(b,), 2,)} a of b * 2 //│ |a| |#of| |b|→|*| |2|←| -//│ Parsed: {a(*(...b)(...2),)} +//│ Parsed: {a(*(b, 2,),)} a then b * 2 @@ -119,26 +119,26 @@ a + b + 1 * 3 //│ |a| |+| |b|→|*| |2|↵|+| |1|↵|*| |3|←| -//│ Parsed: {+(a,)(*(...(+(...(*(...b)(...2)))(...1)))(...3),)} +//│ Parsed: {+(a,)(*(+(*(b, 2,), 1,), 3,),)} a + b * 2 + 1 //│ |a| |+| |b|→|*| |2|→|+| |1|←|←| -//│ Parsed: {+(a,)(*(...b)(...(+(...2)(...1))),)} +//│ Parsed: {+(a,)(*(b, +(2, 1,),),)} a + b * 2 - 1 //│ |a| |+| |b|→|*| |2|←|→|-| |1|←| -//│ Parsed: {-(...(+(a,)(*(...b)(...2),)))(...1)} +//│ Parsed: {-(+(a,)(*(b, 2,),), 1,)} a + b * 2 + 1 * 3 //│ |a| |+| |b|→|*| |2|→|+| |1|←|↵|*| |3|←| -//│ Parsed: {+(a,)(*(...(*(...b)(...(+(...2)(...1)))))(...3),)} +//│ Parsed: {+(a,)(*(*(b, +(2, 1,),), 3,),)} a + b @@ -152,7 +152,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.147: * 3 //│ ╙── ^ -//│ Parsed: {+(a,)({*(...b)(...2); 1; 3},)} +//│ Parsed: {+(a,)({*(b, 2,); 1; 3},)} a + b @@ -163,7 +163,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.160: + 1 //│ ╙── ^ -//│ Parsed: {*(...(+(a,)({*(...b)(...2); 1},)))(...3)} +//│ Parsed: {*(+(a,)({*(b, 2,); 1},), 3,)} a + b @@ -175,7 +175,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.171: + //│ ╙── ^ -//│ Parsed: {+(a,)({*(...b)(...2); {*(...1)(...3)}},)} +//│ Parsed: {+(a,)({*(b, 2,); {*(1, 3,)}},)} a + b @@ -184,7 +184,7 @@ a + 1 * 3 //│ |a| |+|→|b|→|*| |2|↵|+|→|1|→|*| |3|←|←|←|←| -//│ Parsed: {+(a,)({+(...(*(...b)(...2)))(...{*(...1)(...3)})},)} +//│ Parsed: {+(a,)({+(*(b, 2,), {*(1, 3,)},)},)} a + b @@ -195,7 +195,7 @@ a + //│ ╔══[PARSE ERROR] Unexpected operator in expression position //│ ║ l.192: + 1 //│ ╙── ^ -//│ Parsed: {+(a,)({*(...b)(...2); *(...1)(...3)},)} +//│ Parsed: {+(a,)({*(b, 2,); *(1, 3,)},)} a + b @@ -203,7 +203,7 @@ a + + 1 * 3 //│ |a| |+|→|b|→|*| |2|↵|+| |1|→|*| |3|←|←|←| -//│ Parsed: {+(a,)({+(...(*(...b)(...2)))(...(*(...1)(...3)))},)} +//│ Parsed: {+(a,)({+(*(b, 2,), *(1, 3,),)},)} a + diff --git a/shared/src/test/diff/parser/Select.mls b/shared/src/test/diff/parser/Select.mls index 76f786894c..96f5548ad9 100644 --- a/shared/src/test/diff/parser/Select.mls +++ b/shared/src/test/diff/parser/Select.mls @@ -228,7 +228,7 @@ a //│ ╔══[PARSE ERROR] Unexpected selector in operator block //│ ║ l.226: .b //│ ╙── ^^ -//│ Parsed: {*(...(+(...a)(...1)))(...2)} +//│ Parsed: {*(+(a, 1,), 2,)} 1 .+ 2 diff --git a/shared/src/test/diff/ucs/zipWith.mls b/shared/src/test/diff/ucs/zipWith.mls index bc15416c22..a92fef3877 100644 --- a/shared/src/test/diff/ucs/zipWith.mls +++ b/shared/src/test/diff/ucs/zipWith.mls @@ -73,20 +73,12 @@ fun zipWith_wrong(f, xs, ys) = //│ fun zipWith_wrong: (anything, anything, anything) -> () -// FIXME parsing fun zipWith_wrong(f, xs, ys) = if xs is Cons(x, xs) and ys is Cons(y, ys) and zipWith_wrong(f, xs, ys) is Some(tail) then Some(Cons(f(x, y), tail)) else None -//│ ╔══[ERROR] illegal pattern -//│ ║ l.78: if xs is Cons(x, xs) -//│ ║ ^^^^^^^^^^^ -//│ ║ l.79: and ys is Cons(y, ys) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ fun zipWith_wrong: (anything, anything, anything) -> error -//│ Code generation encountered an error: -//│ if expression was not desugared +//│ fun zipWith_wrong: forall 'a 'b 'A. (('a, 'b) -> 'A, Cons['a] | Object & ~#Cons, Cons['b] | Object & ~#Cons) -> (None | Some[Cons['A]]) fun zipWith_wrong(f, xs, ys) = From 2a3a104b12ab144b08d90e2fc51ed870a4a8e920 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 28 Nov 2023 10:32:16 +0800 Subject: [PATCH 485/498] Overhaul support for `new` operator Fixes #191 The current lifter implementation is buggy and its results changed strangely --- .../scala/mlscript/compiler/ClassLifter.scala | 16 +- compiler/shared/test/diff/LambLift.mls | 2 +- compiler/shared/test/diff/LiftType.mls | 6 +- compiler/shared/test/diff/Lifter.mls | 109 ++++------- compiler/shared/test/diff/LifterBlks.mls | 17 +- compiler/shared/test/diff/mono.mls | 24 +-- .../src/main/scala/mlscript/JSBackend.scala | 39 ++-- .../src/main/scala/mlscript/NewParser.scala | 82 +++++---- .../src/main/scala/mlscript/NuTypeDefs.scala | 26 +-- shared/src/main/scala/mlscript/Typer.scala | 78 ++++---- .../main/scala/mlscript/codegen/Helpers.scala | 2 + shared/src/main/scala/mlscript/helpers.scala | 6 + shared/src/main/scala/mlscript/syntax.scala | 3 + .../diff/codegen/AuxiliaryConstructors.mls | 69 ++++--- shared/src/test/diff/codegen/New.mls | 4 +- shared/src/test/diff/gadt/ThisMatching.mls | 14 +- shared/src/test/diff/nu/AbstractClasses.mls | 4 +- shared/src/test/diff/nu/AuxCtors.mls | 38 ++-- shared/src/test/diff/nu/BadBlocks.mls | 10 +- shared/src/test/diff/nu/BadTraits.mls | 16 ++ .../test/diff/nu/BasicClassInheritance.mls | 32 +++- shared/src/test/diff/nu/BasicMixins.mls | 2 +- shared/src/test/diff/nu/Eval.mls | 2 +- shared/src/test/diff/nu/FlatMonads.mls | 2 +- .../test/diff/nu/GenericClassInheritance.mls | 6 +- shared/src/test/diff/nu/Interfaces.mls | 125 +++++++------ shared/src/test/diff/nu/LocalLets.mls | 7 +- shared/src/test/diff/nu/ModuleParameters.mls | 8 +- shared/src/test/diff/nu/MutualRec.mls | 32 ++-- shared/src/test/diff/nu/New.mls | 8 +- shared/src/test/diff/nu/NewNew.mls | 148 +++++++++------ shared/src/test/diff/nu/NoThisCtor.mls | 2 +- shared/src/test/diff/nu/NuScratch.mls | 164 +++++++++++++++++ shared/src/test/diff/nu/Object.mls | 11 +- shared/src/test/diff/nu/Refinements.mls | 34 ++-- shared/src/test/diff/nu/SelfRec.mls | 2 +- shared/src/test/diff/nu/SimpleTraitImpl.mls | 4 +- shared/src/test/diff/nu/TODO_Classes.mls | 16 +- shared/src/test/diff/nu/TraitSignatures.mls | 2 +- .../test/diff/nu/TrickyGenericInheritance.mls | 65 +++---- shared/src/test/diff/nu/Uninstantiable.mls | 11 +- shared/src/test/diff/nu/i191.mls | 169 ++++++++++++++++++ shared/src/test/diff/parser/BasicSyntax.mls | 58 +++--- shared/src/test/diff/parser/New.mls | 51 ++---- .../src/test/scala/mlscript/DiffTests.scala | 4 +- 45 files changed, 965 insertions(+), 565 deletions(-) create mode 100644 shared/src/test/diff/nu/BadTraits.mls create mode 100644 shared/src/test/diff/nu/i191.mls diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index 5c0c8da40b..5124a31c56 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -304,7 +304,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { private def liftTerm(target: Term)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Term, LocalContext) = log(s"liftTermNew $target in $ctx, $cache, $globFuncs, $outer") - target match{ + target match { case v: Var => if(ctx.contains(v) || v.name.equals("this") || primiTypes.contains(v.name)) (v, emptyCtx) else if(cache.contains(TypeName(v.name))){ @@ -339,6 +339,18 @@ class ClassLifter(logDebugMsg: Boolean = false) { val ret = liftTerm(trm) val nTy = liftType(ty) (Asc(ret._1, nTy._1), ret._2 ++ nTy._2) + case NuNew(cls) => + liftTerm(App(NuNew(cls), Tup(Nil))) + case App(NuNew(cls), args) => + liftTerm(Rft(App(NuNew(cls), args), TypingUnit(Nil))) + case Rft(NuNew(cls), tu) => + liftTerm(Rft(App(NuNew(cls), Tup(Nil)), TypingUnit(Nil))) + case Rft(App(NuNew(cls), args), tu) => + (cls, args) match { + case (v: Var, args: Tup) => + liftTerm(New(Some((TypeName(v.name), args)), tu)) + case _ => ??? + } case App(v: Var, prm: Tup) if cache.contains(TypeName(v.name)) => val ret = liftConstr(TypeName(v.name), prm) (App(Var(ret._1.name), ret._2), ret._3) @@ -428,7 +440,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (bod2, ctx) = liftTerm(bod) val (sts2, ctx2) = liftEntities(sts) (Where(bod2, sts2), ctx2) - case _: Eqn | _: Super => throw MonomorphError(s"Unimplemented liftTerm: ${target}") // TODO + case _: Eqn | _: Super | _: Rft => throw MonomorphError(s"Unimplemented liftTerm: ${target}") // TODO case patmat: AdtMatchWith => lastWords(s"Cannot liftTermNew ${patmat}") } diff --git a/compiler/shared/test/diff/LambLift.mls b/compiler/shared/test/diff/LambLift.mls index 5e5054efe5..c42974bf49 100644 --- a/compiler/shared/test/diff/LambLift.mls +++ b/compiler/shared/test/diff/LambLift.mls @@ -68,7 +68,7 @@ fun app(a) = foo(z => a.bar(z)) app(new A(1)) //│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), NuTypeDef(class, A, (), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: Var(y), _: Var(z))))))), NuFunDef(None, app, None, [], Lam(Tup(_: Var(a)), Blk(...))), App(Var(app), Tup(_: New(Some((TypeName(A),[1,])), TypingUnit())))) +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), NuTypeDef(class, A, (), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: Var(y), _: Var(z))))))), NuFunDef(None, app, None, [], Lam(Tup(_: Var(a)), Blk(...))), App(Var(app), Tup(_: App(NuNew(Var(A)), Tup(_: IntLit(1)))))) //│ Lifted: //│ TypingUnit { //│ class A$1([y: Int,]) {fun bar = (z,) => +((this).y, z,)} diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index 2b4ccc4f07..773e24b1e9 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -6,9 +6,9 @@ class CTX{ fun foo(f: A => A): (A => A) => A = f(new A) } //│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |#=>| |A|)|#:| |(|A| |#=>| |A|)| |#=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| -//│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A([]) {},) : (A -> A) -> A}} +//│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A,) : (A -> A) -> A}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit()))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: NuNew(Var(A)))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {} @@ -84,7 +84,7 @@ class CTX{ (new CTX).bar } //│ |#class| |CTX|{|→|#fun| |ctx|(|x|,|y|)| |#=| |→|#class| |A|{| |#fun| |foo| |#=| |x| |}|↵|#fun| |bar|‹|T|›|(|any|#:| |T|)|#:| |A| |#=| |→|#let| |x| |#=| |#new| |T|↵|#new| |A|←|↵|(|#new| |CTX|)|.bar|‹|CTX|›|←|←|↵|}| -//│ Parsed: {class CTX {fun ctx = (x, y,) => {class A {fun foo = x}; fun bar = (any: T,) => {let x = new T([]) {}; new A([]) {}} : A; ('(' new CTX([]) {} ')').bar‹CTX›}}} +//│ Parsed: {class CTX {fun ctx = (x, y,) => {class A {fun foo = x}; fun bar = (any: T,) => {let x = new T; new A} : A; ('(' new CTX ')').bar‹CTX›}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, ctx, None, [], Lam(Tup(_: Var(x), _: Var(y)), Blk(...)))))) //│ Lifted: diff --git a/compiler/shared/test/diff/Lifter.mls b/compiler/shared/test/diff/Lifter.mls index bf77d3a629..fffb3d7252 100644 --- a/compiler/shared/test/diff/Lifter.mls +++ b/compiler/shared/test/diff/Lifter.mls @@ -26,9 +26,9 @@ class A(x) { fun getA = A(x) } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getB1| |#=| |B1|(|y|)|↵|#class| |C|(|z|)| |{|→|#fun| |inc|(||)| |#=| |x| |+| |1|↵|#fun| |getY| |#=| |y|↵|#fun| |getA| |#=| |A|(|z|)|↵|#fun| |getB|(|w|)| |#=| |B|(|w|)|↵|#fun| |getC| |#=| |#new| |C|(|inc|(||)|)|↵|#fun| |getSelf| |#=| |this|←|↵|}|←|↵|}|↵|#class| |B1|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getY| |#=| |y|↵|#fun| |getB| |#=| |#new| |B|(|y|)|↵|#fun| |getB1| |#=| |#new| |B1|(|y|)|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|(|x|)|↵|#fun| |getB2|(|y|)| |#=| |B1|(|y|)|↵|#fun| |getB3|(|z|)| |#=| |getB2|(|z|)|↵|#fun| |getA| |#=| |A|(|x|)|←|↵|}| -//│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1(y,); class C(z,) {fun inc = () => +(x, 1,); fun getY = y; fun getA = A(z,); fun getB = (w,) => B(w,); fun getC = new C([inc(),]) {}; fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = new B([y,]) {}; fun getB1 = new B1([y,]) {}}; fun getB = new B([x,]) {}; fun getB2 = (y,) => B1(y,); fun getB3 = (z,) => getB2(z,); fun getA = A(x,)}} +//│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1(y,); class C(z,) {fun inc = () => +(x, 1,); fun getY = y; fun getA = A(z,); fun getB = (w,) => B(w,); fun getC = (new C)(inc(),); fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = (new B)(y,); fun getB1 = (new B1)(y,)}; fun getB = (new B)(x,); fun getB2 = (y,) => B1(y,); fun getB3 = (z,) => getB2(z,); fun getA = A(x,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), TypingUnit())), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), TypingUnit())), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), TypingUnit())))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), TypingUnit())), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], App(NuNew(Var(C)), Tup(_: App(Var(inc), Tup())))), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], App(NuNew(Var(B)), Tup(_: Var(y)))), NuFunDef(None, getB1, None, [], App(NuNew(Var(B1)), Tup(_: Var(y)))))), NuFunDef(None, getB, None, [], App(NuNew(Var(B)), Tup(_: Var(x)))), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2_C$4([par$A$1_B$2, z, x,]) { @@ -106,11 +106,11 @@ new C{ fun bar = 17 } //│ |#class| |A|(|x|)| |{|→|#class| |B|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |11|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |2|↵|#fun| |bar| |#=| |12|←|↵|}|↵|#fun| |bar| |#=| |13|←|↵|}|↵|#class| |C|#:| |A|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |3|↵|#fun| |bar| |#=| |14|←|↵|}|↵|#fun| |bar| |#=| |15|←|↵|}|↵|#new| |C|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |4|↵|#fun| |bar| |#=| |16|←|↵|}|↵|#fun| |bar| |#=| |17|←|↵|}| -//│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B([]) {fun foo = 2; fun bar = 12}; fun bar = 13}; class C: A {fun getB = new B([]) {fun foo = 3; fun bar = 14}; fun bar = 15}; new C([]) {fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17}} +//│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B { ‹fun foo = 2; fun bar = 12› }; fun bar = 13}; class C: A {fun getB = new B { ‹fun foo = 3; fun bar = 14› }; fun bar = 15}; new C { ‹fun getB = new B { ‹fun foo = 4; fun bar = 16› }; fun bar = 17› }} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(2)), NuFunDef(None, bar, None, [], IntLit(12))))), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(3)), NuFunDef(None, bar, None, [], IntLit(14))))), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(4)), NuFunDef(None, bar, None, [], IntLit(16))))), NuFunDef(None, bar, None, [], IntLit(17))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], Rft(NuNew(Var(B)), ...)), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], Rft(NuNew(Var(B)), ...)), NuFunDef(None, bar, None, [], IntLit(15)))), Rft(NuNew(Var(C)), ...)) //│ Lifted: -//│ Lifting failed: java.util.NoSuchElementException: None.get +//│ Lifting failed: mlscript.codegen.CodeGenError: Cannot find type B. Class values are not supported in lifter. //│ @@ -140,22 +140,21 @@ class Parent(x) { class B {} class C {} class D(y: Int) {} -class A(x: Int): {a1: Int} & B & D(x){ +class A(x: Int): ({a1: Int} & B & D(x)) { fun getA() = new C{ fun foo(x: T) = x } } -//│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| -//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C([]) {fun foo = (x: T,) => x}}} +//│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |(|{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|)| |{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| +//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C { ‹fun foo = (x: T,) => x› }}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(x: Var(T)), Var(x)))))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), Rft(NuNew(Var(C)), ...)))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} //│ class C$2([]) {} //│ class D$3([y: Int,]) {} -//│ class A$4_C$1$5[T]([par$A$4,]): C$2() {fun foo = (x: T,) => x} -//│ class A$4[T,U]([x: Int,]) {fun getA = () => {new A$4_C$1$5([this,]) {}}} +//│ class A$4[T,U]([x: Int,]) {fun getA = () => new C$2([]) {}} //│ } //│ // │ TypingUnit(NuTypeDef(class, B, (TypeName(T)), Tup(), (), TypingUnit()), NuTypeDef(class, C, (), Tup(), (), TypingUnit()), NuTypeDef(class, A, (TypeName(T), TypeName(U)), Tup(x: Var(Int)), (App(App(Var(&), Tup(_: Bra(rcd = true, Rcd(Var(a1) = Var(Int)})))), Tup(_: TyApp(Var(B), List(TypeName(T)))))), TypingUnit(NuFunDef(None, getA, [], Lam(Tup(), New(Some((TypeName(C),)), TypingUnit(List(fun foo = x: T, => x)))))))) @@ -169,30 +168,29 @@ class A(x: Int) extends {a1: Int}, B, D(x){ } } //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)| |#extends| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| -//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C([]) {fun foo = (x,) => x}}} +//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C { ‹fun foo = (x,) => x› }}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x)))))))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), Rft(NuNew(Var(C)), ...)))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} //│ class C$2([]) {} //│ class D$3([y: Int,]) {} -//│ class A$4_C$1$5([par$A$4,]): C$2() {fun foo = (x,) => x} -//│ class A$4[T,U]([x: Int,]): '{' {a1: Int} '}', B$1()‹T›, D$3((this).x,) {fun getA = () => {new A$4_C$1$5([this,]) {}}} +//│ class A$4[T,U]([x: Int,]): '{' {a1: Int} '}', B$1()‹T›, D$3((this).x,) {fun getA = () => new C$2([]) {}} //│ } //│ -class Child(x): { age: T } & { name: String} { +class Child(x): ({ age: T } & { name: String}) { class Inner{ fun foo = age } fun bar = age fun boo = new Inner } -//│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| -//│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner {fun foo = age}; fun bar = age; fun boo = new Inner([]) {}}} +//│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |(|{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}|)| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| +//│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner {fun foo = age}; fun bar = age; fun boo = new Inner}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), TypingUnit()))))) +//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], NuNew(Var(Inner)))))) //│ Lifted: //│ TypingUnit { //│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = () => (this).age} @@ -213,9 +211,9 @@ new A(0) { fun getA2 = 2 } //│ |#class| |A|(|x|#:| |Int|)| |{|→|#fun| |getA|#:| |Int| |#=| |0|↵|#fun| |getA1| |#=| |1|←|↵|}|↵|#new| |A|(|0|)| |{|→|#fun| |getA| |#=| |3|↵|#fun| |getA2| |#=| |2|←|↵|}| -//│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; new A([0,]) {fun getA = 3; fun getA2 = 2}} +//│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; (new A)(0,) { ‹fun getA = 3; fun getA2 = 2› }} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), TypingUnit(NuFunDef(None, getA, None, [], IntLit(3)), NuFunDef(None, getA2, None, [], IntLit(2))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), Rft(App(NuNew(Var(A)), Tup(_: IntLit(0))), ...)) //│ Lifted: //│ TypingUnit { //│ class A$1([x: Int,]) {fun getA = () => 0 : Int; fun getA1 = () => 1} @@ -234,9 +232,9 @@ new A(1) { } } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{| |}|←|↵|}|↵|#new| |A|(|1|)| |{|→|#fun| |getB| |#=| |#new| |B|(|2|)|{|→|#fun| |getB| |#=| |#new| |B|(|3|)|←|↵|}|←|↵|}| -//│ Parsed: {class A(x,) {class B(y,) {}}; new A([1,]) {fun getB = new B([2,]) {fun getB = new B([3,]) {}}}} +//│ Parsed: {class A(x,) {class B(y,) {}}; (new A)(1,) { ‹fun getB = (new B)(2,) { ‹fun getB = (new B)(3,)› }› }} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[2,])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[3,])), TypingUnit())))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), Rft(App(NuNew(Var(A)), Tup(_: IntLit(1))), ...)) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1, y,]) {} @@ -267,20 +265,18 @@ new B{ fun getA = funcB } //│ |#class| |A| |{|→|#fun| |getA| |#=| |0|↵|#fun| |funcA| |#=| |10|←|↵|}|↵|#class| |B|#:| |A|{|→|#fun| |getA| |#=| |1|↵|#fun| |funcB| |#=| |11|←|↵|}|↵|#new| |A|↵|#new| |B|↵|#fun| |f|(|x|)| |#=| |#if| |x| |is| |A| |#then| |0| |#else| |1|↵|f|(|#new| |A|{|→|#fun| |getA| |#=| |2|←|↵|}|)|↵|#new| |B|{|→|#fun| |getA| |#=| |funcB|←|↵|}| -//│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A([]) {}; new B([]) {}; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A([]) {fun getA = 2},); new B([]) {fun getA = funcB}} +//│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A; new B; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A { ‹fun getA = 2› },); new B { ‹fun getA = funcB› }} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), TypingUnit()), New(Some((TypeName(B),[])), TypingUnit()), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, getA, None, [], IntLit(2)))))), New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, getA, None, [], Var(funcB))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), NuNew(Var(A)), NuNew(Var(B)), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: Rft(NuNew(Var(A)), ...))), Rft(NuNew(Var(B)), ...)) //│ Lifted: //│ TypingUnit { //│ class A$1([]) {fun getA = () => 0; fun funcA = () => 10} //│ class B$2([]) {fun getA = () => 1; fun funcB = () => 11} -//│ class A$2$3([]): A$1() {fun getA = () => 2} -//│ class B$3$4([]): B$2() {fun getA = () => (this).funcB} //│ fun f$1 = (x,) => if (is(x, A$1(),)) then 0 else 1 //│ Code(List(new A$1([]) {})) //│ Code(List(new B$2([]) {})) -//│ Code(List(f$1({new A$2$3([]) {}},))) -//│ Code(List({new B$3$4([]) {}})) +//│ Code(List(f$1(new A$1([]) {},))) +//│ Code(List(new B$2([]) {})) //│ } //│ @@ -351,9 +347,9 @@ class A{ } } //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|↵|#fun| |getB| |#=| |#new| |B|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|↵|#fun| |getD| |#=| |#new| |D|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|↵|#fun| |getE| |#=| |#new| |E|{|→|#fun| |foo| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B([]) {}}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D([]) {}}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E([]) {fun foo = 0}}}}} +//│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E { ‹fun foo = 0› }}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit())))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), TypingUnit())))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)))))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], NuNew(Var(B))))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], NuNew(Var(D))))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], Rft(NuNew(Var(E)), ...))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {fun funB = () => 1; fun foo = () => 100} @@ -367,11 +363,10 @@ class A{ //│ fun foo = () => 100000 //│ fun getD = () => new A$1_D$4([((this).par$A$1_D$4).par$A$1,]) {} //│ } -//│ class A$1_D$4_F$6_E$1$7([par$A$1_D$4_F$6,]): A$1_D$4_E$5(((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = () => 0} //│ class A$1_D$4_F$6([par$A$1_D$4,]) { //│ fun funF = () => 5 //│ fun foo = () => 1000000 -//│ fun getE = () => {new A$1_D$4_F$6_E$1$7([this,]) {}} +//│ fun getE = () => new A$1_D$4_E$5([(this).par$A$1_D$4,]) {} //│ } //│ class A$1_D$4([par$A$1,]) {fun funD = () => 3; fun foo = () => 10000} //│ class A$1([]) {} @@ -387,9 +382,9 @@ class A{ } new A //│ |#class| |A|{|→|#class| |B|{|→|#fun| |foo| |#=| |1|←|↵|}|↵|#fun| |bar| |#=| |#new| |B|←|↵|}|↵|#new| |A| -//│ Parsed: {class A {class B {fun foo = 1}; fun bar = new B([]) {}}; new A([]) {}} +//│ Parsed: {class A {class B {fun foo = 1}; fun bar = new B}; new A} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), TypingUnit())))), New(Some((TypeName(A),[])), TypingUnit())) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], NuNew(Var(B))))), NuNew(Var(A))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {fun foo = () => 1} @@ -412,22 +407,13 @@ let x = new A{ } } //│ |#class| |A|(|x|)| |{|→|#fun| |foo| |#=| |0|↵|#fun| |bar| |#=| |x|←|↵|}|↵|#let| |x| |#=| |#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |newFun| |#=| |2|↵|#fun| |bar| |#=| |#new| |A|(|foo|)|{|→|#fun| |foo| |#=| |bar| |+| |1|↵|#fun| |bar2| |#=| |newFun| |+| |1|←|↵|}|←|↵|}| -//│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A([]) {fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}}} +//│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A { ‹fun foo = 1; fun newFun = 2; fun bar = (new A)(foo,) { ‹fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)› }› }} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, newFun, None, [], IntLit(2)), NuFunDef(None, bar, None, [], New(Some((TypeName(A),[foo,])), TypingUnit(NuFunDef(None, foo, None, [], App(Var(+), Tup(_: Var(bar), _: IntLit(1)))), NuFunDef(None, bar2, None, [], App(Var(+), Tup(_: Var(newFun), _: IntLit(1))))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], Rft(NuNew(Var(A)), ...))) //│ Lifted: //│ TypingUnit { //│ class A$1([x,]) {fun foo = () => 0; fun bar = () => (this).x} -//│ class A$2$2_A$3$3([par$A$2$2, x,]): A$1((this).x,) { -//│ fun foo = () => +((this).bar, 1,) -//│ fun bar2 = () => +(((this).par$A$2$2).newFun, 1,) -//│ } -//│ class A$2$2([x,]): A$1((this).x,) { -//│ fun foo = () => 1 -//│ fun newFun = () => 2 -//│ fun bar = () => {new A$2$2_A$3$3([this, (this).foo,]) {}} -//│ } -//│ let x$1 = () => {new A$2$2([]) {}} +//│ let x$1 = () => new A$1([]) {} //│ } //│ @@ -449,33 +435,10 @@ new A{ } } //│ |#class| |A| |{||}|↵|#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |#new| |A|{|→|#fun| |foo1| |#=| |foo|↵|#fun| |bar1| |#=| |#new| |A|{|→|#fun| |foo2| |#=| |foo|↵|#fun| |bar2| |#=| |#new| |A|{|→|#fun| |foo3| |#=| |foo|↵|#fun| |bar3| |#=| |#new| |A|{|→|#fun| |foo4| |#=| |foo|↵|#fun| |bar4| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A {}; new A([]) {fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}}} +//│ Parsed: {class A {}; new A { ‹fun foo = 1; fun bar = new A { ‹fun foo1 = foo; fun bar1 = new A { ‹fun foo2 = foo; fun bar2 = new A { ‹fun foo3 = foo; fun bar3 = new A { ‹fun foo4 = foo; fun bar4 = 0› }› }› }› }› }} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo1, None, [], Var(foo)), NuFunDef(None, bar1, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo2, None, [], Var(foo)), NuFunDef(None, bar2, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo3, None, [], Var(foo)), NuFunDef(None, bar3, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo4, None, [], Var(foo)), NuFunDef(None, bar4, None, [], IntLit(0))))))))))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), Rft(NuNew(Var(A)), ...)) //│ Lifted: -//│ TypingUnit { -//│ class A$1([]) {} -//│ class A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([par$A$1$2_A$2$3_A$3$4_A$4$5,]): A$1() { -//│ fun foo4 = () => (((((this).par$A$1$2_A$2$3_A$3$4_A$4$5).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar4 = () => 0 -//│ } -//│ class A$1$2_A$2$3_A$3$4_A$4$5([par$A$1$2_A$2$3_A$3$4,]): A$1() { -//│ fun foo3 = () => ((((this).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar3 = () => {new A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([this,]) {}} -//│ } -//│ class A$1$2_A$2$3_A$3$4([par$A$1$2_A$2$3,]): A$1() { -//│ fun foo2 = () => (((this).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar2 = () => {new A$1$2_A$2$3_A$3$4_A$4$5([this,]) {}} -//│ } -//│ class A$1$2_A$2$3([par$A$1$2,]): A$1() { -//│ fun foo1 = () => ((this).par$A$1$2).foo -//│ fun bar1 = () => {new A$1$2_A$2$3_A$3$4([this,]) {}} -//│ } -//│ class A$1$2([]): A$1() { -//│ fun foo = () => 1 -//│ fun bar = () => {new A$1$2_A$2$3([this,]) {}} -//│ } -//│ Code(List({new A$1$2([]) {}})) -//│ } +//│ TypingUnit {class A$1([]) {}; Code(List(new A$1([]) {}))} //│ diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index 67d569bd56..414d4109b4 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -55,9 +55,9 @@ class A(y){} let f = x => new A(0){fun bar = x+y} f(0) //│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |#=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| -//│ Parsed: {class A(y,) {}; let f = (x,) => new A([0,]) {fun bar = +(x, y,)}; f(0,)} +//│ Parsed: {class A(y,) {}; let f = (x,) => (new A)(0,) { ‹fun bar = +(x, y,)› }; f(0,)} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), TypingUnit(NuFunDef(None, bar, None, [], App(Var(+), Tup(_: Var(x), _: Var(y)))))))), App(Var(f), Tup(_: IntLit(0)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), Rft(App(NuNew(Var(A)), Tup(_: IntLit(0))), ...))), App(Var(f), Tup(_: IntLit(0)))) //│ Lifted: //│ TypingUnit { //│ class A$1([y,]) {} @@ -78,7 +78,7 @@ class A(x){ } } //│ |#class| |A|(|x|)|{|→|#fun| |w| |#=| |x|↵|#fun| |foo|(|y|)| |#=| |→|#class| |B|(|z|)|{|→|#fun| |bar| |#=| |x|+|y|+|z|←|↵|}|↵|#new| |B|(|0|)|{|→|#fun| |bar| |#=| |w|+|y|+|z|←|↵|}|←|←|↵|}| -//│ Parsed: {class A(x,) {fun w = x; fun foo = (y,) => {class B(z,) {fun bar = +(+(x, y,), z,)}; new B([0,]) {fun bar = +(+(w, y,), z,)}}}} +//│ Parsed: {class A(x,) {fun w = x; fun foo = (y,) => {class B(z,) {fun bar = +(+(x, y,), z,)}; (new B)(0,) { ‹fun bar = +(+(w, y,), z,)› }}}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, w, None, [], Var(x)), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(y)), Blk(...)))))) //│ Lifted: @@ -109,7 +109,7 @@ fun f(x,y,z) = fun bar = bar1 + bar2 } //│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#class| |C| |#extends| |A|,| |B| |{|→|#fun| |bar| |#=| |bar1| |+| |bar2|←|↵|}|←| -//│ Parsed: {fun f = (x, y, z,) => {class A {fun foo = new B([]) {}; fun bar1 = x}; class B {fun foo = new A([]) {}; fun bar2 = y}; class C: A, B {fun bar = +(bar1, bar2,)}}} +//│ Parsed: {fun f = (x, y, z,) => {class A {fun foo = new B; fun bar1 = x}; class B {fun foo = new A; fun bar2 = y}; class C: A, B {fun bar = +(bar1, bar2,)}}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) //│ Lifted: @@ -140,7 +140,7 @@ fun f(x,y,z) = fun boo = (new A).bar1 + B().bar2 + z } //│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |C|{|→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#fun| |boo| |#=| |(|#new| |A|)|.bar1| |+| |B|(||)|.bar2| |+| |z|←|↵|}|←| -//│ Parsed: {fun f = (x, y, z,) => {class C {class A {fun foo = new B([]) {}; fun bar1 = x}; class B {fun foo = new A([]) {}; fun bar2 = y}; fun boo = +(+(('(' new A([]) {} ')').bar1, (B()).bar2,), z,)}}} +//│ Parsed: {fun f = (x, y, z,) => {class C {class A {fun foo = new B; fun bar1 = x}; class B {fun foo = new A; fun bar2 = y}; fun boo = +(+(('(' new A ')').bar1, (B()).bar2,), z,)}}} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) //│ Lifted: @@ -291,16 +291,15 @@ fun ctx(a,b) = fun apply(x) = a+x }, b) //│ |#class| |Func|‹|T|,| |U|›| |{|→|#fun| |apply|#:| |T| |#=>| |U|←|↵|}|↵|#class| |Lambda|‹|T|,| |U|›| |#:| |Func|‹|T|,| |U|›| |{||}|↵|#fun| |ctx|(|a|,|b|)| |#=|→|#fun| |foo|(|f|#:| |Func|,| |x|)| |#=| |→|f|.apply|(|x|)|←|↵|foo|(|#new| |Lambda|{|→|#fun| |apply|(|x|)| |#=| |a|+|x|←|↵|}|,| |b|)|←| -//│ Parsed: {class Func‹T, U› {fun apply: T -> U}; class Lambda‹T, U›: Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply(x,)}; foo(new Lambda([]) {fun apply = (x,) => +(a, x,)}, b,)}} +//│ Parsed: {class Func‹T, U› {fun apply: T -> U}; class Lambda‹T, U›: Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply(x,)}; foo(new Lambda { ‹fun apply = (x,) => +(a, x,)› }, b,)}} //│ Parsed: //│ TypingUnit(NuTypeDef(class, Func, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),TypeName(U)))))), NuTypeDef(class, Lambda, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit()), NuFunDef(None, ctx, None, [], Lam(Tup(_: Var(a), _: Var(b)), Blk(...)))) //│ Lifted: //│ TypingUnit { //│ class Func$1[T,U]([]) {fun apply = T -> U} //│ class Lambda$2[T,U]([]) {} -//│ class Lambda$3$3([a,]): Lambda$2() {fun apply = (x,) => +((this).a, x,)} //│ fun foo$2 = (f: Func$1, x,) => {(f).apply(x,)} -//│ fun ctx$1 = (a, b,) => {foo$2({new Lambda$3$3([a,]) {}}, b,)} +//│ fun ctx$1 = (a, b,) => {foo$2(new Lambda$2([]) {}, b,)} //│ } //│ @@ -308,7 +307,7 @@ fun f(T) = new T() f(MyClass) //│ |#fun| |f|(|T|)| |#=| |→|#new| |T|(||)|←|↵|f|(|MyClass|)| -//│ Parsed: {fun f = (T,) => {new T([]) {}}; f(MyClass,)} +//│ Parsed: {fun f = (T,) => {(new T)()}; f(MyClass,)} //│ Parsed: //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(T)), Blk(...))), App(Var(f), Tup(_: Var(MyClass)))) //│ Lifted: diff --git a/compiler/shared/test/diff/mono.mls b/compiler/shared/test/diff/mono.mls index 5116e6600d..780851b8a1 100644 --- a/compiler/shared/test/diff/mono.mls +++ b/compiler/shared/test/diff/mono.mls @@ -246,7 +246,7 @@ fun count(lst) = else 0 count(new List(new List(new Nil(undefined, false), true), true)) //│ Parsed: -//│ TypingUnit(NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, count, None, [], Lam(Tup(_: Var(lst)), Blk(...))), App(Var(count), Tup(_: New(Some((TypeName(List),[new List([new Nil([undefined, false,]) {}, true,]) {}, true,])), TypingUnit())))) +//│ TypingUnit(NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, count, None, [], Lam(Tup(_: Var(lst)), Blk(...))), App(Var(count), Tup(_: App(NuNew(Var(List)), Tup(_: App(NuNew(Var(List)), Tup(_: App(NuNew(Var(Nil)), Tup(_: UnitLit(true), _: Var(false))), _: Var(true))), _: Var(true)))))) //│ Lifted: //│ TypingUnit { //│ class List$1([val l: |(|(List, Nil,), undefined,), val hasTail: Bool,]) {} @@ -303,7 +303,7 @@ class Nil() { fun add2(x) = x+2 (new List(1, new List(2, new Nil()))).map(x => x+1).map(x => add2(x)) //│ Parsed: -//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, map, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(Int))))),TypeName(Int)))))),TypeName(List)))), NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), New(Some((TypeName(List),[f(e,), (tail).map(f,),])), TypingUnit()))), NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), Var(this))), NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, add2, None, [], Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))), App(Sel(App(Sel(Bra(rcd = false, New(Some((TypeName(List),[1, new List([2, new Nil([]) {},]) {},])), TypingUnit())), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1)))))), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(add2), Tup(_: Var(x))))))) +//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, map, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(Int))))),TypeName(Int)))))),TypeName(List)))), NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), App(NuNew(Var(List)), Tup(_: App(Var(f), Tup(_: Var(e))), _: App(Sel(Var(tail), map), Tup(_: Var(f))))))), NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), Var(this))), NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, add2, None, [], Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))), App(Sel(App(Sel(Bra(rcd = false, App(NuNew(Var(List)), Tup(_: IntLit(1), _: App(NuNew(Var(List)), Tup(_: IntLit(2), _: App(NuNew(Var(Nil)), Tup())))))), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1)))))), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(add2), Tup(_: Var(x))))))) //│ Lifted: //│ TypingUnit { //│ class List$1([e: Int, tail: |(List, Nil,),]) { @@ -370,7 +370,7 @@ fun generate(x) = foo(new List(1, new List(2, new Nil()))) foo(generate(1)) //│ Parsed: -//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), App(Sel(Var(x), count), Tup()))), NuFunDef(None, generate, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: New(Some((TypeName(List),[1, new List([2, new Nil([]) {},]) {},])), TypingUnit()))), App(Var(foo), Tup(_: App(Var(generate), Tup(_: IntLit(1)))))) +//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), App(Sel(Var(x), count), Tup()))), NuFunDef(None, generate, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: App(NuNew(Var(List)), Tup(_: IntLit(1), _: App(NuNew(Var(List)), Tup(_: IntLit(2), _: App(NuNew(Var(Nil)), Tup()))))))), App(Var(foo), Tup(_: App(Var(generate), Tup(_: IntLit(1)))))) //│ Lifted: //│ TypingUnit { //│ class List$1([e: Int, tail: |(List, Nil,),]) { @@ -537,7 +537,7 @@ fun foo(x) = foo(new Lambda()) foo(new Lambda2(2)) //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var('A), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuTypeDef(class, Lambda, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuTypeDef(class, Lambda2, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: New(Some((TypeName(Lambda),[])), TypingUnit()))), App(Var(foo), Tup(_: New(Some((TypeName(Lambda2),[2,])), TypingUnit())))) +//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var('A), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuTypeDef(class, Lambda, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuTypeDef(class, Lambda2, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: App(NuNew(Var(Lambda)), Tup()))), App(Var(foo), Tup(_: App(NuNew(Var(Lambda2)), Tup(_: IntLit(2)))))) //│ Lifted: //│ TypingUnit { //│ class Cons$1([e: 'A, tail: |(Cons, Nil,),]) { @@ -612,7 +612,7 @@ fun foo(x) = foo(l => l.count()) foo(l => (new Cons(2, l)).count()) //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Var(l), count), Tup())))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Bra(rcd = false, New(Some((TypeName(Cons),[2, l,])), TypingUnit())), count), Tup()))))) +//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Var(l), count), Tup())))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Bra(rcd = false, App(NuNew(Var(Cons)), Tup(_: IntLit(2), _: Var(l)))), count), Tup()))))) //│ Lifted: //│ TypingUnit { //│ class Cons$1([e: Int, tail: |(Cons, Nil,),]) { @@ -707,7 +707,7 @@ class C(e1: Exp, e2: Exp) extends Exp { } (new C(new Ch(1), new A(new Ch(2), new Ch(3)))).derive(0).isEmpty() //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Exp, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, derive, None, [], PolyType(List(),Function(Tuple(List((Some(x),Field(None,TypeName(Int))))),TypeName(Exp)))), NuFunDef(None, derive, None, [], Lam(Tup(x: Var(Int)), App(Var(Exp), Tup()))), NuFunDef(None, isEmpty, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Bool)))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Var(false))))), NuTypeDef(class, E, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ep, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ch, (), Tup(i: Var(Int)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, A, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, C, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), App(Sel(App(Sel(Bra(rcd = false, New(Some((TypeName(C),[new Ch([1,]) {}, new A([new Ch([2,]) {}, new Ch([3,]) {},]) {},])), TypingUnit())), derive), Tup(_: IntLit(0))), isEmpty), Tup())) +//│ TypingUnit(NuTypeDef(class, Exp, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, derive, None, [], PolyType(List(),Function(Tuple(List((Some(x),Field(None,TypeName(Int))))),TypeName(Exp)))), NuFunDef(None, derive, None, [], Lam(Tup(x: Var(Int)), App(Var(Exp), Tup()))), NuFunDef(None, isEmpty, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Bool)))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Var(false))))), NuTypeDef(class, E, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ep, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ch, (), Tup(i: Var(Int)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, A, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, C, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), App(Sel(App(Sel(Bra(rcd = false, App(NuNew(Var(C)), Tup(_: App(NuNew(Var(Ch)), Tup(_: IntLit(1))), _: App(NuNew(Var(A)), Tup(_: App(NuNew(Var(Ch)), Tup(_: IntLit(2))), _: App(NuNew(Var(Ch)), Tup(_: IntLit(3)))))))), derive), Tup(_: IntLit(0))), isEmpty), Tup())) //│ Lifted: //│ TypingUnit { //│ class Exp$1([]) { @@ -851,7 +851,7 @@ class Foo(x: Int){ } (new Foo(1)).boo(2) //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(y)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, boo, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: App(Var(bar), Tup(_: Var(z))), _: Var(x))))))), App(Sel(Bra(rcd = false, New(Some((TypeName(Foo),[1,])), TypingUnit())), boo), Tup(_: IntLit(2)))) +//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(y)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, boo, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: App(Var(bar), Tup(_: Var(z))), _: Var(x))))))), App(Sel(Bra(rcd = false, App(NuNew(Var(Foo)), Tup(_: IntLit(1)))), boo), Tup(_: IntLit(2)))) //│ Lifted: //│ TypingUnit { //│ class Foo$1([x: Int,]) { @@ -888,7 +888,7 @@ class OneInt(a: Int){ } (new OneInt(10)).fac() //│ Parsed: -//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, fac, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, fac, None, [], Lam(Tup(), Blk(...))))), App(Sel(Bra(rcd = false, New(Some((TypeName(OneInt),[10,])), TypingUnit())), fac), Tup())) +//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, fac, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, fac, None, [], Lam(Tup(), Blk(...))))), App(Sel(Bra(rcd = false, App(NuNew(Var(OneInt)), Tup(_: IntLit(10)))), fac), Tup())) //│ Lifted: //│ TypingUnit { //│ class OneInt$1([a: Int,]) { @@ -977,7 +977,7 @@ class OneBool(b: Bool){ } (if b then new OneInt(1) else new OneBool(true)).get() //│ Parsed: -//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, OneBool, (), Tup(b: Var(Bool)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(b))))), App(Sel(Bra(rcd = false, If(IfThen(Var(b), New(Some((TypeName(OneInt),[1,])), TypingUnit()), Some(New(Some((TypeName(OneBool),[true,])), TypingUnit())))), get), Tup())) +//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, OneBool, (), Tup(b: Var(Bool)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(b))))), App(Sel(Bra(rcd = false, If(IfThen(Var(b), App(NuNew(Var(OneInt)), Tup(_: IntLit(1))), Some(App(NuNew(Var(OneBool)), Tup(_: Var(true)))))), get), Tup())) //│ Lifted: //│ TypingUnit { //│ class OneInt$1([a: Int,]) {fun get = () => (this).a} @@ -1023,7 +1023,7 @@ baz(bar) (new Car()).da(Bar(1337)) bar.car //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Bar, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x))), NuFunDef(None, FooMinus, None, [], Lam(Tup(y: Var(Int)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, car, None, [], App(Var(foo), Tup(_: IntLit(2)))))), NuTypeDef(class, Car, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, da, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))))), NuFunDef(None, baz, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))), NuFunDef(Some(false), bar, None, [], App(Var(Bar), Tup(_: IntLit(42)))), App(Var(baz), Tup(_: Var(bar))), App(Sel(Bra(rcd = false, New(Some((TypeName(Car),[])), TypingUnit())), da), Tup(_: App(Var(Bar), Tup(_: IntLit(1337))))), Sel(Var(bar), car)) +//│ TypingUnit(NuTypeDef(class, Bar, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x))), NuFunDef(None, FooMinus, None, [], Lam(Tup(y: Var(Int)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, car, None, [], App(Var(foo), Tup(_: IntLit(2)))))), NuTypeDef(class, Car, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, da, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))))), NuFunDef(None, baz, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))), NuFunDef(Some(false), bar, None, [], App(Var(Bar), Tup(_: IntLit(42)))), App(Var(baz), Tup(_: Var(bar))), App(Sel(Bra(rcd = false, App(NuNew(Var(Car)), Tup())), da), Tup(_: App(Var(Bar), Tup(_: IntLit(1337))))), Sel(Var(bar), car)) //│ Lifted: //│ TypingUnit { //│ class Bar$1([x: Int,]) { @@ -1094,7 +1094,7 @@ class Sub2(c: Int) extends Sub(c+c){ (new Sub(10)).foo() (new Sub2(c)).foo() //│ Parsed: -//│ TypingUnit(NuFunDef(Some(false), c, None, [], IntLit(5)), NuTypeDef(class, Sup, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, Sub, (), Tup(b: Var(Int)), (App(Var(Sup), Tup(_: App(Var(+), Tup(_: Var(b), _: Var(b)))))), None, None, TypingUnit()), NuTypeDef(class, Sub2, (), Tup(c: Var(Int)), (App(Var(Sub), Tup(_: App(Var(+), Tup(_: Var(c), _: Var(c)))))), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(a), _: Var(c))))))), App(Sel(Bra(rcd = false, New(Some((TypeName(Sub),[10,])), TypingUnit())), foo), Tup()), App(Sel(Bra(rcd = false, New(Some((TypeName(Sub2),[c,])), TypingUnit())), foo), Tup())) +//│ TypingUnit(NuFunDef(Some(false), c, None, [], IntLit(5)), NuTypeDef(class, Sup, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, Sub, (), Tup(b: Var(Int)), (App(Var(Sup), Tup(_: App(Var(+), Tup(_: Var(b), _: Var(b)))))), None, None, TypingUnit()), NuTypeDef(class, Sub2, (), Tup(c: Var(Int)), (App(Var(Sub), Tup(_: App(Var(+), Tup(_: Var(c), _: Var(c)))))), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(a), _: Var(c))))))), App(Sel(Bra(rcd = false, App(NuNew(Var(Sub)), Tup(_: IntLit(10)))), foo), Tup()), App(Sel(Bra(rcd = false, App(NuNew(Var(Sub2)), Tup(_: Var(c)))), foo), Tup())) //│ Lifted: //│ TypingUnit { //│ class Sup$1([a: Int,]) {fun foo = () => (this).a} @@ -1152,7 +1152,7 @@ class F2() extends Foo(x => x+2){} (new F1()).foo() (new F2()).foo() //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(f: App(Var(->), Tup(_: Var(Int), _: Var(Int)))), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(f), Tup(_: IntLit(1))))))), NuTypeDef(class, F1, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))), None, None, TypingUnit()), NuTypeDef(class, F2, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))))), None, None, TypingUnit()), App(Sel(Bra(rcd = false, New(Some((TypeName(F1),[])), TypingUnit())), foo), Tup()), App(Sel(Bra(rcd = false, New(Some((TypeName(F2),[])), TypingUnit())), foo), Tup())) +//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(f: App(Var(->), Tup(_: Var(Int), _: Var(Int)))), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(f), Tup(_: IntLit(1))))))), NuTypeDef(class, F1, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))), None, None, TypingUnit()), NuTypeDef(class, F2, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))))), None, None, TypingUnit()), App(Sel(Bra(rcd = false, App(NuNew(Var(F1)), Tup())), foo), Tup()), App(Sel(Bra(rcd = false, App(NuNew(Var(F2)), Tup())), foo), Tup())) //│ Lifted: //│ TypingUnit { //│ class Foo$1([f: ->(Int, Int,),]) {fun foo = () => (this).f(1,)} diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 9ea71bf8ef..1d5a94e857 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -9,7 +9,9 @@ import scala.collection.mutable.{Set => MutSet} import scala.util.control.NonFatal import scala.util.chaining._ -class JSBackend(allowUnresolvedSymbols: Boolean) { +abstract class JSBackend(allowUnresolvedSymbols: Bool) { + def oldDefs: Bool + /** * The root scope of the program. */ @@ -66,7 +68,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { translatePattern(base) case Inst(bod) => translatePattern(bod) case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf | _: Subs | _: Assign - | If(_, _) | New(_, _) | _: Splc | _: Forall | _: Where | _: Super | _: Eqn | _: AdtMatchWith => + | If(_, _) | New(_, _) | NuNew(_) | _: Splc | _: Forall | _: Where | _: Super | _: Eqn | _: AdtMatchWith | _: Rft => throw CodeGenError(s"term ${inspect(t)} is not a valid pattern") } @@ -122,12 +124,13 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { if (sym.isByvalueRec.isEmpty && !sym.isLam) ident() else ident }) case S(sym: ClassSymbol) => - if (isCallee) + if (isCallee || !oldDefs) JSNew(JSIdent(sym.runtimeName)) else JSArrowFn(JSNamePattern("x") :: Nil, L(JSNew(JSIdent(sym.runtimeName))(JSIdent("x")))) case S(sym: TraitSymbol) => - JSIdent(sym.lexicalName)("build") + if (oldDefs) JSIdent(sym.lexicalName)("build") + else return Left(CodeGenError(s"trait used in term position")) case N => scope.getType(name) match { case S(sym: TypeAliasSymbol) => return Left(CodeGenError(s"type alias ${name} is not a valid expression")) @@ -160,7 +163,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { // Function invocation case App(trm, Tup(args)) => val callee = trm match { - case Var(nme) => scope.resolveValue(nme) match { + case Var(nme) if oldDefs => scope.resolveValue(nme) match { case S(sym: NuTypeSymbol) => translateNuTypeSymbol(sym, false) // ClassName(params) case _ => translateVar(nme, true) // Keep this case for the legacy test cases @@ -168,6 +171,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case _ => translateTerm(trm) } callee(args map { case (_, Fld(_, arg)) => translateTerm(arg) }: _*) + case App(trm, splice) => ??? // TODO represents `trm(...splice)` case _ => throw CodeGenError(s"ill-formed application ${inspect(term)}") } @@ -298,6 +302,15 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case Inst(bod) => translateTerm(bod) case iff: If => throw CodeGenError(s"if expression was not desugared") + case NuNew(cls) => + cls match { + case Var(className) => + translateVar(className, true) match { + case n: JSNew => n + case t => JSNew(t) + } + case _ => throw CodeGenError(s"Unsupported `new` class term: ${inspect(cls)}") + } case New(N, TypingUnit(Nil)) => JSRecord(Nil) case New(S(TypeName(className) -> Tup(args)), TypingUnit(Nil)) => val callee = translateVar(className, true) match { @@ -311,7 +324,7 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { case TyApp(base, _) => translateTerm(base) case Eqn(Var(name), _) => throw CodeGenError(s"assignment of $name is not supported outside a constructor") - case _: Bind | _: Test | If(_, _) | _: Splc | _: Where | _: AdtMatchWith => + case _: Bind | _: Test | If(_, _) | _: Splc | _: Where | _: AdtMatchWith | _: Rft => throw CodeGenError(s"cannot generate code for term ${inspect(term)}") } @@ -639,13 +652,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } protected def translateNewClassParameters(classBody: JSClassNewDecl) = { - val constructor = classBody match { - case dec: JSClassNewDecl => dec.fields.map(JSNamePattern(_)) - } - val params = classBody match { - case dec: JSClassNewDecl => dec.fields.map(JSIdent(_)) - } - + val constructor = classBody.ctorParams.map(JSNamePattern(_)) + val params = classBody.ctorParams.map(JSIdent(_)) (constructor, params) } @@ -1126,6 +1134,8 @@ class JSBackend(allowUnresolvedSymbols: Boolean) { } class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { + def oldDefs = false + // Name of the array that contains execution results val resultsName: Str = topLevelScope declareRuntimeSymbol "results" @@ -1256,7 +1266,8 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { if (newDefs) generateNewDef(pgrm) else generate(pgrm) } -class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { +abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { + private val lastResultSymbol = topLevelScope.declareValue("res", Some(false), false, N) private val resultIdent = JSIdent(lastResultSymbol.runtimeName) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 81484c69f4..a85ea1a831 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -124,11 +124,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo "+ -", // "* / %", "* %", + "", // Precedence of application ".", ).zipWithIndex.flatMap { case (cs, i) => cs.filterNot(_ === ' ').map(_ -> (i + 1)) }.toMap.withDefaultValue(Int.MaxValue) + private val AppPrec = prec('.') - 1 + final def opCharPrec(opChar: Char): Int = prec(opChar) final def opPrec(opStr: Str): (Int, Int) = opStr match { case "is" => (4, 4) @@ -240,12 +243,12 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo rec(toks, S(br.innerLoc), br.describe).concludeWith(_.typingUnit) case _ => typingUnit } - final def curlyTypingUnit(implicit fe: FoundErr): TypingUnit = yeetSpaces match { + final def curlyTypingUnit(implicit fe: FoundErr): Opt[TypingUnit] = yeetSpaces match { case (br @ BRACKETS(Curly, toks), l1) :: _ => consume - rec(toks, S(br.innerLoc), br.describe).concludeWith(_.typingUnitMaybeIndented).withLoc(S(l1)) + S(rec(toks, S(br.innerLoc), br.describe).concludeWith(_.typingUnitMaybeIndented).withLoc(S(l1))) case _ => - TypingUnit(Nil) + N } final def toParamsTy(t: Type): Tuple = t match { @@ -309,7 +312,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (br @ BRACKETS(Round, toks), loc) :: _ => consume val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) // TODO - val body = curlyTypingUnit + val body = curlyTypingUnit.getOrElse(TypingUnit(Nil)) Constructor(Tup(as).withLoc(S(loc)), Blk(body.entities).withLocOf(body)) case _ => err(msg"Expect parameter list for the constructor" -> S(l0) :: Nil) @@ -373,13 +376,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo expr(0) :: otherParents case _ => Nil } - val sig = yeetSpaces match { + val sigTrm = yeetSpaces match { case (KEYWORD("="), _) :: _ if kind is Als => consume - S(typ(0)) + S(expr(0)) case (KEYWORD(":"), _) :: _ if !(kind is Als) => consume - S(typ(0)) + S(expr(0)) case _ => N } val ps = yeetSpaces match { @@ -391,7 +394,18 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo expr(0) :: otherParents case _ => Nil } - val fullTu = curlyTypingUnit + val (sigTrm2, ps2, fullTu) = curlyTypingUnit.fold { + ps.lastOption match { + case S(Rft(bse, tu)) => (sigTrm, (bse :: ps.reverse.tail).reverse, tu) + case _ => + sigTrm match { + case S(Rft(bse, tu)) => (S(bse), ps, tu) + case _ => + (sigTrm, ps, TypingUnit(Nil)) + } + } + }(tu => (sigTrm, ps, tu)) + val sig = sigTrm2.map(mkType(_)) val (ctors, bodyStmts) = fullTu.entities.partitionMap { case c: Constructor => L(c) case t => R(t) @@ -403,7 +417,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo } val ctor = ctors.headOption val res = - NuTypeDef(kind, tn, tparams, params, ctor, sig, ps, N, N, tu)(isDecl, isAbs) + NuTypeDef(kind, tn, tparams, params, ctor, sig, ps2, N, N, tu)(isDecl, isAbs) R(res.withLoc(S(l0 ++ tn.getLoc ++ res.getLoc))) R(res.withLoc(S(l0 ++ res.getLoc))) @@ -548,7 +562,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo final def funParams(implicit et: ExpectThen, fe: FoundErr, l: Line): Ls[Tup] = wrap(()) { l => yeetSpaces match { case (KEYWORD("=" | ":"), _) :: _ => Nil - case Nil => Nil case (KEYWORD("of"), _) :: _ => consume Tup(args(false) // TODO @@ -563,6 +576,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo msg"Expected function parameter list; found ${tk.describe} instead" -> S(l0) :: Nil)) consume Nil + case Nil => Nil } } @@ -694,22 +708,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (KEYWORD("new"), l0) :: c => consume val body = expr(outer.prec('.')) - val head = body match { - case Var(clsNme) => - S(TypeName(clsNme).withLocOf(body) -> Tup(Nil)) - case App(Var(clsNme), Tup(N -> Fld(FldFlags(false, false, _), UnitLit(true)) :: Nil)) => - S(TypeName(clsNme).withLocOf(body) -> Tup(Nil)) - case App(Var(clsNme), arg) => - S(TypeName(clsNme).withLocOf(body) -> arg) - case UnitLit(true) => - N - case _ => - err(( - msg"Unexpected ${body.describe} after `new` keyword" -> body.toLoc :: Nil)) - N - } - val res = New(head, curlyTypingUnit).withLoc(S(head.foldLeft(l0)((l, h) => l ++ h._1.toLoc ++ h._2.toLoc))) - exprCont(res, prec, allowNewlines = false) + exprCont(NuNew(body).withLoc(S(l0 ++ body.toLoc)), prec, allowNewlines = false) case (KEYWORD("else"), l0) :: _ => consume val e = expr(0) @@ -878,7 +877,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (br @ BRACKETS(Indent, (IDENT(opStr, true), l0) :: toks), _) :: _ => consume rec(toks, S(br.innerLoc), br.describe).concludeWith(_.opBlock(acc, opStr, l0)) - case Nil => R(acc) case (KEYWORD("then"), _) :: _ if /* expectThen && */ prec === 0 => // case (KEYWORD("then"), _) :: _ if /* expectThen && */ prec <= 1 => consume @@ -892,6 +890,12 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (NEWLINE, _) :: _ if allowNewlines => consume exprCont(acc, 0, allowNewlines) + + case (br @ BRACKETS(Curly, toks), loc) :: _ if prec <= AppPrec => + consume + val tu = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.typingUnitMaybeIndented).withLoc(S(loc)) + exprCont(Rft(acc, tu), prec, allowNewlines) + case (COMMA | NEWLINE | KEYWORD("then" | "else" | "in" | ";;" | "=") | IDENT(_, true) | BRACKETS(Curly, _), _) :: _ => R(acc) @@ -955,19 +959,19 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo val idx = rec(toks, S(br.innerLoc), "subscript").concludeWith(_.expr(0)) val res = Subs(acc, idx.withLoc(S(loc))) exprCont(res, prec, allowNewlines)*/ + + case (br @ BRACKETS(Round, toks), loc) :: _ if prec <= AppPrec => + consume + val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) + val res = App(acc, Tup(as).withLoc(S(loc))) + exprCont(res, prec, allowNewlines) - case (br @ BRACKETS(Round, toks), loc) :: _ => - consume - val as = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.argsMaybeIndented()) - val res = App(acc, Tup(as).withLoc(S(loc))) - exprCont(res, prec, allowNewlines) - - case (KEYWORD("of"), _) :: _ => - consume - val as = argsMaybeIndented() - // val as = argsOrIf(Nil) // TODO - val res = App(acc, Tup(as)) - exprCont(res, prec, allowNewlines) + case (KEYWORD("of"), _) :: _ => + consume + val as = argsMaybeIndented() + // val as = argsOrIf(Nil) // TODO + val res = App(acc, Tup(as)) + exprCont(res, prec, allowNewlines) case c @ (h :: _) if (h._1 match { case KEYWORD(";;" | ":" | "of" | "where" | "extends") | BRACKETS(Round | Square, _) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index ceb2fd23c5..8eb2bdf2d6 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -475,18 +475,18 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => )(provTODO) else if ((td.kind is Cls) || (td.kind is Mod)) { if (td.kind is Mod) - err(msg"Parameterized modules are not supported", loco) - val psOpt: Opt[Params] = ( - if (usesNew) acParams.map(_.mapValues(_.toUpper(noProv))).orElse(params) - else params.orElse { - acParams.map { ps => - err(msg"Construction of unparameterized class ${td.nme.name} should use the `new` keyword", loco) - ps.mapValues(_.toUpper(noProv)) - } - } - ) - val ps = psOpt.getOrElse { - return err(msg"Class ${td.nme.name} cannot be instantiated as it exposes no such constructor", loco) + err(msg"Parameterized modules are not yet supported", loco) + println(s"params: $params $acParams") + if (!usesNew) + if (params.isEmpty) + if (acParams.isEmpty) + return err(msg"Class ${td.nme.name} cannot be instantiated as it exposes no constructor", loco) + else err(msg"Construction of unparameterized class ${td.nme.name} should use the `new` keyword", loco) + else if (acParams.isDefined) + err(msg"Construction of class with auxiliary constructor should use the `new` keyword", loco) + val ps: Params = acParams match { + case S(acParams) => acParams.mapValues(_.toUpper(noProv)) + case N => params.getOrElse(Nil) } PolymorphicType.mk(level, FunctionType( @@ -1768,7 +1768,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * We want to avoid forcing completion of types needlessly // * OTOH we need the type to be completed to use its aux ctor (whose param types are optional) // * TODO: avoid forcing when the aux ctor has type-annotated params - if (usesNew && (td.ctor.isDefined || !td.params.isDefined)) complete() match { + if (td.ctor.isDefined) complete() match { case cls: TypedNuCls => cls.typeSignature(usesNew, loco) case _: TypedNuDummy => errType diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3b11dfca25..1ba8909896 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1005,6 +1005,46 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne val body_ty = typeTerm(body)(newCtx, raise, vars, generalizeCurriedFunctions || doGenLambdas) FunctionType(param_ty, body_ty)(tp(term.toLoc, "function")) + case NuNew(cls) => typeMonomorphicTerm(App(NuNew(cls), Tup(Nil).withLoc(term.toLoc.map(_.right)))) + case app @ App(nw @ NuNew(cls), args) => + cls match { + case _: TyApp => // * TODO improve (hacky) + err(msg"Type arguments in `new` expressions are not yet supported", prov.loco) + case _ => + } + val cls_ty = typeType(cls.toTypeRaise) + def process(clsNme: Str) = { + println(clsNme, ctx.tyDefs2.get(clsNme)) + ctx.tyDefs2.get(clsNme) match { + case N => + err(msg"Type `${clsNme}` cannot be used in `new` expression", term.toLoc) + case S(lti) => + def checkNotAbstract(decl: NuDecl) = + if (decl.isAbstract) + err(msg"Class ${decl.name} is abstract and cannot be instantiated", term.toLoc) + lti match { + case dti: DelayedTypeInfo if !(dti.kind is Cls) => + err(msg"${dti.kind.str.capitalize} ${dti.name} cannot be used in `new` expression", + prov.loco) + case dti: DelayedTypeInfo => + checkNotAbstract(dti.decl) + dti.typeSignature(true, prov.loco) + } + } + } + val new_ty = cls_ty.unwrapProxies match { + case TypeRef(clsNme, targs) => + // FIXME don't disregard `targs` + process(clsNme.name) + case err @ ClassTag(ErrTypeId, _) => err + case ClassTag(Var(clsNme), _) => process(clsNme) + case _ => + // * Debug with: ${cls_ty.getClass.toString} + err(msg"Unexpected type `${cls_ty.expPos}` after `new` keyword" -> cls.toLoc :: Nil) + } + val res = freshVar(prov, N) + val argProv = tp(args.toLoc, "argument list") + con(new_ty, FunctionType(typeTerm(args).withProv(argProv), res)(noProv), res) case App(App(Var("is"), _), _) => // * Old-style operators val desug = If(IfThen(term, Var("true")), S(Var("false"))) term.desugaredTerm = S(desug) @@ -1349,42 +1389,6 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne } } ret_ty - case New(S((nmedTy, trm)), TypingUnit(Nil)) if !newDefs => - typeMonomorphicTerm(App(Var(nmedTy.base.name).withLocOf(nmedTy), trm)) - case nw @ New(S((nmedTy, trm: Tup)), TypingUnit(Nil)) if newDefs => - typeMonomorphicTerm(App(New(S((nmedTy, UnitLit(true))), TypingUnit(Nil)).withLocOf(nw), trm)) - case New(S((nmedTy, UnitLit(true))), TypingUnit(Nil)) if newDefs => - if (nmedTy.targs.nonEmpty) - err(msg"Type arguments in `new` expressions are not yet supported", prov.loco) - ctx.get(nmedTy.base.name).fold(err("identifier not found: " + nmedTy.base, term.toLoc): ST) { - case AbstractConstructor(absMths, traitWithMths) => die - case VarSymbol(ty, _) => - err(msg"Cannot use `new` on non-class variable of type ${ty.expPos}", term.toLoc) - case lti: LazyTypeInfo => - def checkNotAbstract(decl: NuDecl) = - if (decl.isAbstract) - err(msg"Class ${decl.name} is abstract and cannot be instantiated", term.toLoc) - lti match { - case ti: CompletedTypeInfo => - ti.member match { - case _: TypedNuFun | _: NuParam => - err(msg"${ti.member.kind.str.capitalize} ${ti.member.name - } cannot be used in `new` expression", prov.loco) - case ti: TypedNuCls => - checkNotAbstract(ti.decl) - ti.typeSignature(true, prov.loco) - case ti: TypedNuDecl => - err(msg"${ti.kind.str.capitalize} ${ti.name - } cannot be used in term position", prov.loco) - } - case dti: DelayedTypeInfo if !(dti.kind is Cls) => - err(msg"${dti.kind.str.capitalize} ${dti.name - } cannot be used in `new` expression", prov.loco) - case dti: DelayedTypeInfo => - checkNotAbstract(dti.decl) - dti.typeSignature(true, prov.loco) - } - } case New(base, args) => err(msg"Currently unsupported `new` syntax", term.toCoveringLoc) case TyApp(base, _) => err(msg"Type application syntax is not yet supported", term.toLoc) // TODO handle @@ -1418,6 +1422,8 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne res case Eqn(lhs, rhs) => err(msg"Unexpected equation in this position", term.toLoc) + case Rft(bse, tu) => + err(msg"Refinement terms are not yet supported", term.toLoc) } }(r => s"$lvl. : ${r}") diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 2ffcbdcf9d..5bade531b9 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -50,6 +50,7 @@ object Helpers { s"Splc($elems)" case If(bod, els) => s"If(${inspect(bod)}, ${els.map(inspect)})" case New(base, body) => s"New(${base}, ${inspect(body)})" + case NuNew(base) => s"NuNew(${inspect(base)})" case TyApp(base, targs) => s"TyApp(${inspect(base)}, ${targs})" case Def(rec, nme, rhs, isByname) => s"Def($rec, $nme, ${rhs.fold(inspect, "" + _)}, $isByname)" @@ -60,6 +61,7 @@ object Helpers { case Super() => "Super()" case AdtMatchWith(cond, arms) => s"match ${inspect(cond)} with ${arms.map(patmat => s"${inspect(patmat.pat)} -> ${inspect(patmat.rhs)}").mkString(" | ")}" + case Rft(bse, tu) => s"Rft(${inspect(bse)}, ...)" } def inspect(body: IfBody): Str = body match { diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index a6e2784f46..cb069e47c8 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -549,6 +549,8 @@ trait TermImpl extends StatementImpl { self: Term => case Assign(lhs, rhs) => "assignment" case Splc(fs) => "splice" case New(h, b) => "object instantiation" + case NuNew(_) => "new instance" + case Rft(_, _) => "refinement" case If(_, _) => "if-else block" case TyApp(_, _) => "type application" case Where(_, _) => s"constraint clause" @@ -603,6 +605,7 @@ trait TermImpl extends StatementImpl { self: Term => case Assign(lhs, rhs) => s" $lhs <- $rhs" |> bra case New(S((at, ar)), bod) => s"new ${at.showDbg2}($ar) ${bod.showDbg}" |> bra case New(N, bod) => s"new ${bod.showDbg}" |> bra + case NuNew(cls) => s"new ${cls.print(false)}" |> bra case If(body, els) => s"if $body" + els.fold("")(" else " + _) |> bra case TyApp(lhs, targs) => s"$lhs‹${targs.map(_.showDbg2).mkString(", ")}›" case Where(bod, wh) => s"${bod} where {${wh.mkString("; ")}}" @@ -612,6 +615,7 @@ trait TermImpl extends StatementImpl { self: Term => case Eqn(lhs, rhs) => s"${lhs} = ${rhs}" case AdtMatchWith(cond, arms) => s"match ${cond} with ${arms.map (patmat => s"${patmat.pat} -> ${patmat.rhs}").mkString (" | ") }" + case Rft(bse, tu) => s"${bse} { ${tu} }" }} def toTypeRaise(implicit raise: Raise): Type = toType match { @@ -983,6 +987,8 @@ trait StatementImpl extends Located { self: Statement => case d @ NuFunDef(_, v, v2, ts, rhs) => v :: v2.toList ::: ts ::: d.body :: Nil case TyApp(lhs, targs) => lhs :: targs case New(base, bod) => base.toList.flatMap(ab => ab._1 :: ab._2 :: Nil) ::: bod :: Nil + case NuNew(cls) => cls :: Nil + case Rft(bs, tu) => bs :: tu :: Nil case Where(bod, wh) => bod :: wh case Forall(ps, bod) => ps ::: bod :: Nil case Inst(bod) => bod :: Nil diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index f33023a395..e899ff5828 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -82,6 +82,7 @@ final case class Subs(arr: Term, idx: Term) extends Ter final case class Assign(lhs: Term, rhs: Term) extends Term final case class Splc(fields: Ls[Either[Term, Fld]]) extends Term final case class New(head: Opt[(NamedType, Term)], body: TypingUnit) extends Term // `new C(...)` or `new C(){...}` or `new{...}` +final case class NuNew(cls: Term) extends Term final case class If(body: IfBody, els: Opt[Term]) extends Term final case class TyApp(lhs: Term, targs: Ls[Type]) extends Term final case class Where(body: Term, where: Ls[Statement]) extends Term @@ -89,6 +90,7 @@ final case class Forall(params: Ls[TypeVar], body: Term) extends Ter final case class Inst(body: Term) extends Term final case class Super() extends Term final case class Eqn(lhs: Var, rhs: Term) extends Term // equations such as x = y, notably used in constructors; TODO: make lhs a Term +final case class Rft(base: Term, decls: TypingUnit) extends Term final case class AdtMatchWith(cond: Term, arms: Ls[AdtMatchPat]) extends Term final case class AdtMatchPat(pat: Term, rhs: Term) extends AdtMatchPatImpl @@ -156,6 +158,7 @@ final case class WithExtension(base: Type, rcd: Record) extends Type final case class Splice(fields: Ls[Either[Type, Field]]) extends Type final case class Constrained(base: TypeLike, tvBounds: Ls[TypeVar -> Bounds], where: Ls[Bounds]) extends Type // final case class FirstClassDefn(defn: NuTypeDef) extends Type // TODO +// final case class Refinement(base: Type, decls: TypingUnit) extends Type // TODO final case class Field(in: Opt[Type], out: Type) extends FieldImpl diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls index 97dda3a6e5..3fd393ed25 100644 --- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -79,21 +79,18 @@ abstract class C new C //│ ╔══[ERROR] Class C is abstract and cannot be instantiated //│ ║ l.79: new C -//│ ╙── ^^^^^ -//│ ╔══[ERROR] Class C cannot be instantiated as it exposes no such constructor -//│ ║ l.79: new C -//│ ╙── ^^^^^ -//│ error +//│ ╙── ^ +//│ C //│ res //│ = C {} :e C() //│ ╔══[ERROR] Class C is abstract and cannot be instantiated -//│ ║ l.91: C() +//│ ║ l.88: C() //│ ╙── ^ -//│ ╔══[ERROR] Class C cannot be instantiated as it exposes no such constructor -//│ ║ l.91: C() +//│ ╔══[ERROR] Class C cannot be instantiated as it exposes no constructor +//│ ║ l.88: C() //│ ╙── ^ //│ error //│ res @@ -135,10 +132,10 @@ class C { :e let c = new C() //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.136: let c = new C() +//│ ║ l.133: let c = new C() //│ ║ ^^^^^^^ -//│ ╟── argument of type `[]` does not match type `[x: Int]` -//│ ║ l.136: let c = new C() +//│ ╟── argument list of type `[]` does not match type `[x: Int]` +//│ ║ l.133: let c = new C() //│ ╙── ^^ //│ let c: C | error //│ c @@ -184,7 +181,7 @@ class D(val x: Int) { //│ return [x.#x]; //│ } //│ }; -//│ this.#D = ((x) => Object.freeze(new D(x))); +//│ this.#D = ((y) => Object.freeze(new D(y))); //│ this.#D.class = D; //│ this.#D.unapply = D.unapply; //│ } @@ -206,7 +203,7 @@ dd.x //│ res //│ = 42 -let dd = D(41) +let dd = new D(41) dd.x //│ let dd: D //│ Int @@ -223,7 +220,7 @@ class E { constructor(y: Int) } //│ ╔══[PARSE ERROR] A class may have at most one explicit constructor -//│ ║ l.221: class E { +//│ ║ l.218: class E { //│ ╙── ^^^^^ //│ class E { //│ constructor(x: Int) @@ -232,7 +229,7 @@ class E { :e constructor(x: Int) //│ ╔══[ERROR] Illegal position for this constructor statement. -//│ ║ l.233: constructor(x: Int) +//│ ║ l.230: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ //│ Code generation encountered an error: @@ -422,8 +419,8 @@ fun g(x: Int) = } fun ll = x + y } - L -//│ fun g: (x: Int) -> (y: Int) -> L + x => new L(x) +//│ fun g: (x: Int) -> Int -> L //│ // Prelude //│ class TypingUnit18 {} //│ const typing_unit18 = new TypingUnit18; @@ -447,11 +444,11 @@ fun g(x: Int) = //│ } //│ } //│ let ctor; -//│ ctor = ((y) => new L(y)); +//│ ctor = ((z) => new L(z)); //│ ctor.class = L; //│ return ctor; //│ })(); -//│ return L; +//│ return (x) => new L.class(x); //│ })()); //│ }; //│ // End of generated code @@ -460,7 +457,7 @@ fun g(x: Int) = let m = g(1) let n = m(2) n.ll -//│ let m: (y: Int) -> L +//│ let m: Int -> L //│ let n: L //│ Int //│ // Prelude @@ -474,7 +471,7 @@ n.ll //│ res = n.ll; //│ // End of generated code //│ m -//│ = [Function: ctor] { class: [class L] } +//│ = [Function (anonymous)] //│ n //│ = L {} //│ res @@ -504,7 +501,7 @@ fun h(z: Int) = } N //│ ╔══[ERROR] Construction of unparameterized class N should use the `new` keyword -//│ ║ l.505: N +//│ ║ l.502: N //│ ╙── ^ //│ fun h: (z: Int) -> (x: Int) -> N @@ -515,9 +512,9 @@ let hh = h(1) :e new hh(1) -//│ ╔══[ERROR] Value hh cannot be used in `new` expression -//│ ║ l.517: new hh(1) -//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] type identifier not found: hh +//│ ║ l.514: new hh(1) +//│ ╙── ^^ //│ error //│ res //│ = N {} @@ -532,10 +529,10 @@ mixin P { constructor(x: Int) } //│ ╔══[ERROR] Explicit module constructors are not supported -//│ ║ l.529: constructor(x: Int) +//│ ║ l.526: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Explicit mixin constructors are not supported -//│ ║ l.532: constructor(x: Int) +//│ ║ l.529: constructor(x: Int) //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ module O { //│ constructor(x: Int) @@ -551,28 +548,28 @@ class QQ(qq: Str) { } } //│ ╔══[ERROR] identifier not found: lol -//│ ║ l.549: lol +//│ ║ l.546: lol //│ ╙── ^^^ //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.549: lol +//│ ║ l.546: lol //│ ╙── ^^^ //│ ╔══[ERROR] Type mismatch in auxiliary class constructor: -//│ ║ l.548: constructor(foo: Int) { +//│ ║ l.545: constructor(foo: Int) { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.549: lol +//│ ║ l.546: lol //│ ║ ^^^^^^^ -//│ ║ l.550: qq = foo +//│ ║ l.547: qq = foo //│ ║ ^^^^^^^^^^^^ -//│ ║ l.551: } +//│ ║ l.548: } //│ ║ ^^^ //│ ╟── type `Int` is not an instance of `Str` -//│ ║ l.548: constructor(foo: Int) { +//│ ║ l.545: constructor(foo: Int) { //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `Str` -//│ ║ l.550: qq = foo +//│ ║ l.547: qq = foo //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.547: class QQ(qq: Str) { +//│ ║ l.544: class QQ(qq: Str) { //│ ╙── ^^^ //│ class QQ(qq: Str) { //│ constructor(foo: Int) diff --git a/shared/src/test/diff/codegen/New.mls b/shared/src/test/diff/codegen/New.mls index 1e8b0b88de..9909f20df2 100644 --- a/shared/src/test/diff/codegen/New.mls +++ b/shared/src/test/diff/codegen/New.mls @@ -13,7 +13,7 @@ new C //│ class TypingUnit1 {} //│ const typing_unit1 = new TypingUnit1; //│ // Query 1 -//│ res = new C(); +//│ res = new C; //│ // End of generated code //│ res //│ = C {} @@ -69,7 +69,7 @@ new C //│ class TypingUnit6 {} //│ const typing_unit6 = new TypingUnit6; //│ // Query 1 -//│ res = new C.class(); +//│ res = new C.class; //│ // End of generated code //│ res //│ = C {} diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index 9178a42293..8bbf2032e1 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -47,7 +47,7 @@ class Unfunny { fun test = this + 1 } //│ } -class Exp: Pair | Lit { +class Exp: (Pair | Lit) { fun test = if this is Lit then 0 Pair then 1 @@ -66,7 +66,7 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ } -class Exp: Pair | Lit { +class Exp: (Pair | Lit) { fun test = if this is Lit then 0 Pair(l, r) then 1 @@ -91,7 +91,7 @@ Pair(Lit(1), Lit(2)).test :e // TODO can we support this? -class Exp: Pair | Lit { +class Exp: (Pair | Lit) { fun test = if this is Lit then 0 Pair(l, r) then l.test + r.test @@ -113,7 +113,7 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ } -class Exp: Pair | Lit { +class Exp: (Pair | Lit) { fun test : Int fun test = if this is Lit then 0 @@ -134,7 +134,7 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp :e // TODO support – this requires implementing type member lookup without forced completion (we get constraints like Pair <: Pair#L) -class Exp[A]: Pair | Lit { +class Exp[A]: (Pair | Lit) { fun test = if this is Lit then 0 Pair then 1 @@ -142,8 +142,8 @@ class Exp[A]: Pair | Lit { class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.137: class Exp[A]: Pair | Lit { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.137: class Exp[A]: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.138: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.139: Lit then 0 diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index 6c78fa993e..ab09dd59b9 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -46,12 +46,12 @@ Foo(1) :e // TODO support new Foo(1) { fun f = id } -//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ╔══[ERROR] Refinement terms are not yet supported //│ ║ l.48: new Foo(1) { fun f = id } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: -//│ custom class body is not supported yet +//│ cannot generate code for term Rft(App(NuNew(Var(Foo)), Tup(_: IntLit(1))), ...) abstract class Bar extends Foo(1) diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index 583a7bf830..7f5e45f7f4 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -2,7 +2,7 @@ class C(val x: Int) { constructor(y: Int) { x = y } } -C(123).x +new C(123).x //│ class C(x: Int) { //│ constructor(y: Int) //│ } @@ -11,7 +11,7 @@ C(123).x //│ = 123 class C(val x: Int) { constructor(y) { x = y } } -C(123).x +new C(123).x //│ class C(x: Int) { //│ constructor(y: Int) //│ } @@ -20,7 +20,7 @@ C(123).x //│ = 123 class C(val x: Int) { constructor(y: Int) { log(y);; x = y;; log(x) } } -C(123).x +new C(123).x //│ class C(x: Int) { //│ constructor(y: Int) //│ } @@ -33,7 +33,7 @@ C(123).x :e class C(val x: Int) { constructor(y: Int) { x = y;; log(x);; x = y + 1;; log(x) } } -C(123).x +new C(123).x //│ ╔══[ERROR] Class parameter 'x' was already set //│ ║ l.35: class C(val x: Int) { constructor(y: Int) { x = y;; log(x);; x = y + 1;; log(x) } } //│ ╙── ^ @@ -127,20 +127,24 @@ class C(val x: Int, y: Int) { :e C(11) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.129: C(11) -//│ ║ ^^^^^ -//│ ╟── argument of type `[11]` does not match type `[x: Int, y: Int]` +//│ ╔══[ERROR] Construction of class with auxiliary constructor should use the `new` keyword //│ ║ l.129: C(11) -//│ ╙── ^^^^ -//│ C | error +//│ ╙── ^ +//│ C //│ res //│ = C {} //│ // Output //│ [ 11, 11 ] -C(1, 2) -//│ C +:e +new C(1, 2) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.140: new C(1, 2) +//│ ║ ^^^^^^^^^^^ +//│ ╟── tuple literal of type `[1, 2]` does not match type `[z: Int]` +//│ ║ l.140: new C(1, 2) +//│ ╙── ^^^^^^ +//│ C | error //│ res //│ = C {} //│ // Output @@ -156,10 +160,10 @@ new C(11) :e new C(1, 2) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.157: new C(1, 2) +//│ ║ l.161: new C(1, 2) //│ ║ ^^^^^^^^^^^ -//│ ╟── argument list of type `[1, 2]` does not match type `[z: Int]` -//│ ║ l.157: new C(1, 2) +//│ ╟── tuple literal of type `[1, 2]` does not match type `[z: Int]` +//│ ║ l.161: new C(1, 2) //│ ╙── ^^^^^^ //│ C | error //│ res @@ -171,10 +175,10 @@ new C(1, 2) :w class C { constructor(x: Int);; constructor(y: Int) } //│ ╔══[PARSE ERROR] A class may have at most one explicit constructor -//│ ║ l.172: class C { constructor(x: Int);; constructor(y: Int) } +//│ ║ l.176: class C { constructor(x: Int);; constructor(y: Int) } //│ ╙── ^^^^^ //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.172: class C { constructor(x: Int);; constructor(y: Int) } +//│ ║ l.176: class C { constructor(x: Int);; constructor(y: Int) } //│ ╙── ^^ //│ class C { //│ constructor(x: Int) diff --git a/shared/src/test/diff/nu/BadBlocks.mls b/shared/src/test/diff/nu/BadBlocks.mls index cc6e4cc868..eedcd08dfd 100644 --- a/shared/src/test/diff/nu/BadBlocks.mls +++ b/shared/src/test/diff/nu/BadBlocks.mls @@ -162,7 +162,10 @@ fun test = (new { //│ ╔══[PARSE ERROR] Unexpected '=' here //│ ║ l.159: val res = a + 1 //│ ╙── ^ -//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword +//│ ╔══[ERROR] type identifier not found: res +//│ ║ l.159: val res = a + 1 +//│ ╙── ^^^ +//│ ╔══[ERROR] Unexpected type `{res: error}` after `new` keyword //│ ║ l.158: fun test = (new { //│ ║ ^ //│ ║ l.159: val res = a + 1 @@ -171,8 +174,7 @@ fun test = (new { //│ ║ ^^^^^^^^^^^^^ //│ ║ l.161: }).res //│ ╙── ^ -//│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.158: fun test = (new { -//│ ╙── ^^^ //│ fun test: error +//│ Code generation encountered an error: +//│ Unsupported `new` class term: Bra(rcd = true, Rcd(Var(res) = Var(res))) diff --git a/shared/src/test/diff/nu/BadTraits.mls b/shared/src/test/diff/nu/BadTraits.mls new file mode 100644 index 0000000000..a0b718f8d4 --- /dev/null +++ b/shared/src/test/diff/nu/BadTraits.mls @@ -0,0 +1,16 @@ +:NewDefs + + +trait Foo +//│ trait Foo + +:e +Foo +//│ ╔══[ERROR] trait Foo cannot be used in term position +//│ ║ l.8: Foo +//│ ╙── ^^^ +//│ error +//│ Code generation encountered an error: +//│ trait used in term position + + diff --git a/shared/src/test/diff/nu/BasicClassInheritance.mls b/shared/src/test/diff/nu/BasicClassInheritance.mls index f9a0743f47..29907d3302 100644 --- a/shared/src/test/diff/nu/BasicClassInheritance.mls +++ b/shared/src/test/diff/nu/BasicClassInheritance.mls @@ -66,9 +66,18 @@ class E(val m: Int) extends A { //│ fun a2: 2 //│ } -// * FIXME codegen +:e E(1).m -//│ Int +//│ ╔══[ERROR] Construction of class with auxiliary constructor should use the `new` keyword +//│ ║ l.70: E(1).m +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.70: E(1).m +//│ ║ ^^^^ +//│ ╟── argument of type `[1]` does not match type `[a: Int, b: Int]` +//│ ║ l.70: E(1).m +//│ ╙── ^^^ +//│ Int | error //│ res //│ = NaN //│ // Output @@ -81,6 +90,13 @@ E(1).m //│ // Output //│ Here's m: 3 +new E(1, 2).m +//│ Int +//│ res +//│ = 3 +//│ // Output +//│ Here's m: 3 + if new E(1, 2) is E(x) then x //│ Int //│ res @@ -91,8 +107,8 @@ if new E(1, 2) is E(x) then x :e module F extends E //│ ╔══[ERROR] class E expects 2 parameter(s); got 0 -//│ ║ l.92: module F extends E -//│ ╙── ^ +//│ ║ l.108: module F extends E +//│ ╙── ^ //│ module F extends A, E { //│ fun a1: Int //│ fun a2: 2 @@ -101,7 +117,7 @@ module F extends E :e module F extends E(123) //│ ╔══[ERROR] class E expects 2 parameter(s); got 1 -//│ ║ l.102: module F extends E(123) +//│ ║ l.118: module F extends E(123) //│ ╙── ^^^^^ //│ module F extends A, E { //│ fun a1: Int @@ -146,13 +162,13 @@ class H extends E { } } //│ ╔══[ERROR] class E expects 2 parameter(s); got 0 -//│ ║ l.143: class H extends E { +//│ ║ l.159: class H extends E { //│ ╙── ^ //│ ╔══[ERROR] Illegal use of `super` -//│ ║ l.145: super(a, b) +//│ ║ l.161: super(a, b) //│ ╙── ^^^^^ //│ ╔══[ERROR] identifier not found: super -//│ ║ l.145: super(a, b) +//│ ║ l.161: super(a, b) //│ ╙── ^^^^^ //│ class H extends A, E { //│ constructor(a: Int, b: Int) diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 811f685d07..37dfd296a9 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -201,7 +201,7 @@ module Base1(base: Int, misc: string) extends Foo :e Base1.test -//│ ╔══[ERROR] Parameterized modules are not supported +//│ ╔══[ERROR] Parameterized modules are not yet supported //│ ║ l.203: Base1.test //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in field selection: diff --git a/shared/src/test/diff/nu/Eval.mls b/shared/src/test/diff/nu/Eval.mls index 2e0961e10d..4056777475 100644 --- a/shared/src/test/diff/nu/Eval.mls +++ b/shared/src/test/diff/nu/Eval.mls @@ -79,7 +79,7 @@ module None extends Option[nothing] //│ class Some[A](value: A) extends Option //│ module None extends Option -abstract class List[out A]: Cons[A] | Nil { virtual val length: Int } +abstract class List[out A]: (Cons[A] | Nil) { virtual val length: Int } class Cons[out A](val head: A, val tail: List[A]) extends List[A] { val length: Int val length = tail.length + 1 diff --git a/shared/src/test/diff/nu/FlatMonads.mls b/shared/src/test/diff/nu/FlatMonads.mls index 452bd802ad..2358f88b61 100644 --- a/shared/src/test/diff/nu/FlatMonads.mls +++ b/shared/src/test/diff/nu/FlatMonads.mls @@ -410,7 +410,7 @@ r.run :NoJS // * TODO We'll need to support functions extended with fields // * An interface that describes monadic functions with a field `run` -declare trait IO[A]: forall 'b: (A -> IO['b]) -> IO['b] { +declare trait IO[A]: (forall 'b: (A -> IO['b]) -> IO['b]) { fun run: A } declare fun pure: 'a -> IO['a] diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index dda26819b3..2b45a50288 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -85,17 +85,17 @@ class C1[A] extends C0[A] { val a = a } //│ val a: nothing //│ } -new C1 : C1[Int] +new C1() : C1[Int] //│ C1[Int] //│ res //│ = C1 {} -((new C1) : C1[Int]) : C0['X] +(new C1() : C1[Int]) : C0['X] //│ C0[Int] //│ res //│ = C1 {} -(new C1).a +new C1().a //│ nothing //│ res //│ = undefined diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 1f97848ab4..5b466012f5 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -535,14 +535,13 @@ let tt1 = Test //│ ║ l.533: let tt1 = Test //│ ╙── ^^^^ //│ let tt1: error -//│ tt1 -//│ Runtime error: -//│ TypeError: Cannot read properties of undefined (reading 'build') +//│ Code generation encountered an error: +//│ trait used in term position :e fun mt(x) = if x is Test then 1 else 0 //│ ╔══[ERROR] Cannot match on trait `Test` -//│ ║ l.543: fun mt(x) = if x is Test then 1 else 0 +//│ ║ l.542: fun mt(x) = if x is Test then 1 else 0 //│ ╙── ^^^^ //│ fun mt: anything -> error //│ Code generation encountered an error: @@ -608,40 +607,40 @@ z: WP g: ZL e: ZL & WP //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.606: fun fto(w: WP): EM = w +//│ ║ l.605: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── type `#WP` is not an instance of type `EM` -//│ ║ l.606: fun fto(w: WP): EM = w +//│ ║ l.605: fun fto(w: WP): EM = w //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#EM` -//│ ║ l.606: fun fto(w: WP): EM = w +//│ ║ l.605: fun fto(w: WP): EM = w //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.606: fun fto(w: WP): EM = w +//│ ║ l.605: fun fto(w: WP): EM = w //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.607: z: WP +//│ ║ l.606: z: WP //│ ║ ^ //│ ╟── type `#ZL` is not an instance of type `WP` -//│ ║ l.563: let z: ZL +//│ ║ l.562: let z: ZL //│ ║ ^^ //│ ╟── but it flows into reference with expected type `#WP` -//│ ║ l.607: z: WP +//│ ║ l.606: z: WP //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.607: z: WP +//│ ║ l.606: z: WP //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.608: g: ZL +//│ ║ l.607: g: ZL //│ ║ ^ //│ ╟── type `#Geo` is not an instance of type `ZL` -//│ ║ l.562: let g: Geo +//│ ║ l.561: let g: Geo //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `#ZL` -//│ ║ l.608: g: ZL +//│ ║ l.607: g: ZL //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.608: g: ZL +//│ ║ l.607: g: ZL //│ ╙── ^^ //│ fun fto: (w: WP) -> EM //│ WP & ZL @@ -697,29 +696,29 @@ class Eh2 extends Bs(true), Ele { fun ce(x) = x } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.696: fun foo(x) = x && false +//│ ║ l.695: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.696: fun foo(x) = x && false +//│ ║ l.695: fun foo(x) = x && false //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.696: fun foo(x) = x && false +//│ ║ l.695: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.696: fun foo(x) = x && false +//│ ║ l.695: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.659: virtual fun foo(x) = x + 1 +//│ ║ l.658: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.696: fun foo(x) = x && false +//│ ║ l.695: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.696: fun foo(x) = x && false +//│ ║ l.695: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.659: virtual fun foo(x) = x + 1 +//│ ║ l.658: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Eh2 extends Bs, Ele { //│ constructor() @@ -732,25 +731,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.731: class Eh extends Bs(1) +//│ ║ l.730: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `Bool` -//│ ║ l.731: class Eh extends Bs(1) +//│ ║ l.730: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.658: class Bs(val a: Bool) { +//│ ║ l.657: class Bs(val a: Bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.732: class Eh1 extends Bs +//│ ║ l.731: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.659: virtual fun foo(x) = x + 1 +//│ ║ l.658: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── function of type `?a -> (forall ?b. ?b)` is not an instance of type `Int` -//│ ║ l.659: virtual fun foo(x) = x + 1 +//│ ║ l.658: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^ //│ ╟── but it flows into definition of method foo with expected type `Int` -//│ ║ l.659: virtual fun foo(x) = x + 1 +//│ ║ l.658: virtual fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.5: fun foo: Int @@ -759,7 +758,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `Eh3` -//│ ║ l.733: class Eh3 extends Bs(false), Test +//│ ║ l.732: class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool @@ -837,7 +836,7 @@ abstract class Bc3 { :e class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] Cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.838: class Bc12() extends Bc1(1), Bc2(true) +//│ ║ l.837: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: @@ -858,14 +857,14 @@ Bc02().foo :e class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.859: class Bc31(baz: Bool) extends Bc3 +//│ ║ l.858: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.829: let baz : Int +//│ ║ l.828: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.829: let baz : Int +//│ ║ l.828: let baz : Int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: Bool) extends Bc3 @@ -900,7 +899,7 @@ trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.900: fun f = error +//│ ║ l.899: fun f = error //│ ╙── ^^^^^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -931,7 +930,7 @@ bp: Base[[Int, Bool]] :e bp: Base[[Int, Int]] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.932: bp: Base[[Int, Int]] +//│ ║ l.931: bp: Base[[Int, Int]] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -992,13 +991,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.993: class DerBad1 extends Base[Int, Int] +//│ ║ l.992: class DerBad1 extends Base[Int, Int] //│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared (or its declaration is inherited) but is not implemented in `DerBad1` -//│ ║ l.993: class DerBad1 extends Base[Int, Int] +//│ ║ l.992: class DerBad1 extends Base[Int, Int] //│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.881: trait Base[A] { fun f: A -> A } +//│ ║ l.880: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^^^^^ //│ class DerBad1 extends Base { //│ constructor() @@ -1010,28 +1009,28 @@ class DerBad1 extends Base[Int, Int] :e class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ constructor() @@ -1083,7 +1082,7 @@ trait Tb extends Ta[Int] { virtual val p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1083: virtual val p = false +//│ ║ l.1082: virtual val p = false //│ ╙── ^^^^^^^^^^^^^ //│ trait Tb extends Ta { //│ val g: 'T @@ -1118,14 +1117,14 @@ trait Oz { :e class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1119: class Fischl(age: Bool) extends Oz +//│ ║ l.1118: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1112: let age: Int +//│ ║ l.1111: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1112: let age: Int +//│ ║ l.1111: let age: Int //│ ╙── ^^^^^^^^ //│ class Fischl(age: Bool) extends Oz @@ -1145,29 +1144,29 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1145: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1145: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1145: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1145: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1136: virtual fun foo(x) = x + 1 +//│ ║ l.1135: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1145: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1145: fun foo(x) = x && true +//│ ║ l.1144: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1136: virtual fun foo(x) = x + 1 +//│ ║ l.1135: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { //│ constructor() @@ -1186,11 +1185,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1187: class Ohhh(x: Bool) extends Ha +//│ ║ l.1186: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1177: class Ha { virtual val x: Int = 1 } +//│ ║ l.1176: class Ha { virtual val x: Int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: Bool) extends Ha diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index 51f2653edb..211987ae06 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -24,9 +24,12 @@ class E(x: Int) :e // TODO support (currently parsed as a function definition named E) let E(x) = new E(1) -//│ ╔══[ERROR] Value E cannot be used in `new` expression +//│ ╔══[ERROR] value E cannot be used as a type //│ ║ l.26: let E(x) = new E(1) -//│ ╙── ^^^^^^^^ +//│ ╙── ^ +//│ ╔══[ERROR] type identifier not found: E +//│ ║ l.26: let E(x) = new E(1) +//│ ╙── ^ //│ let E: anything -> error //│ E //│ = [Function: E1] diff --git a/shared/src/test/diff/nu/ModuleParameters.mls b/shared/src/test/diff/nu/ModuleParameters.mls index b7301e33d5..f0922ad6a6 100644 --- a/shared/src/test/diff/nu/ModuleParameters.mls +++ b/shared/src/test/diff/nu/ModuleParameters.mls @@ -12,7 +12,7 @@ module A(x: Int) { fun y = x } :e A -//│ ╔══[ERROR] Parameterized modules are not supported +//│ ╔══[ERROR] Parameterized modules are not yet supported //│ ║ l.14: A //│ ╙── ^ //│ (x: Int) -> A @@ -21,7 +21,7 @@ A :e A(123) -//│ ╔══[ERROR] Parameterized modules are not supported +//│ ╔══[ERROR] Parameterized modules are not yet supported //│ ║ l.23: A(123) //│ ╙── ^ //│ A @@ -31,7 +31,7 @@ A(123) :e A.x -//│ ╔══[ERROR] Parameterized modules are not supported +//│ ╔══[ERROR] Parameterized modules are not yet supported //│ ║ l.33: A.x //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in field selection: @@ -46,7 +46,7 @@ A.x :e A.y -//│ ╔══[ERROR] Parameterized modules are not supported +//│ ╔══[ERROR] Parameterized modules are not yet supported //│ ║ l.48: A.y //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in field selection: diff --git a/shared/src/test/diff/nu/MutualRec.mls b/shared/src/test/diff/nu/MutualRec.mls index 8f4d21c958..4d4b406614 100644 --- a/shared/src/test/diff/nu/MutualRec.mls +++ b/shared/src/test/diff/nu/MutualRec.mls @@ -188,10 +188,10 @@ class Test1_1 { class Test1_2 { fun b = Test1_1().a } -//│ ╔══[ERROR] Class Test1_2 cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class Test1_2 cannot be instantiated as it exposes no constructor //│ ║ l.186: fun a = Test1_2().b //│ ╙── ^^^^^^^ -//│ ╔══[ERROR] Class Test1_1 cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class Test1_1 cannot be instantiated as it exposes no constructor //│ ║ l.189: fun b = Test1_1().a //│ ╙── ^^^^^^^ //│ class Test1_1 { @@ -227,13 +227,9 @@ class Test1_1 { class Test1_2 { fun b = (new Test1_1).a } -//│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.224: class Test1_1 { -//│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.225: fun a = (new Test1_2).b -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.226: } -//│ ╙── ^ +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.228: fun b = (new Test1_1).a +//│ ╙── ^^ //│ class Test1_1 { //│ constructor() //│ fun a: error @@ -243,6 +239,22 @@ class Test1_2 { //│ fun b: error //│ } +class Test1_1 { + fun a: Int + fun a = (new Test1_2).b +} +class Test1_2 { + fun b = (new Test1_1).a +} +//│ class Test1_1 { +//│ constructor() +//│ fun a: Int +//│ } +//│ class Test1_2 { +//│ constructor() +//│ fun b: Int +//│ } + :e module Test2_1 { @@ -257,7 +269,7 @@ module Test2_2 { fun e = Test2_1.n } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.256: fun c = Test2_1.a +//│ ║ l.268: fun c = Test2_1.a //│ ╙── ^^ //│ module Test2_1 { //│ fun a: 123 | error diff --git a/shared/src/test/diff/nu/New.mls b/shared/src/test/diff/nu/New.mls index df4bd0f2f4..a145d88fec 100644 --- a/shared/src/test/diff/nu/New.mls +++ b/shared/src/test/diff/nu/New.mls @@ -10,9 +10,7 @@ let f = Foo(1) //│ f: Foo & {x: 1} //│ = Foo { x: 1 } -let f = new Foo(1) -//│ f: Foo & {x: 1} -//│ = Foo { x: 1 } +// let f = new Foo(1) if f is Foo then 1 else 0 //│ res: 0 | 1 @@ -45,8 +43,6 @@ class PoInt(x, y) //│ PoInt: ('x, 'y,) -> (PoInt & {x: 'x, y: 'y}) //│ = [Function: PoInt1] -let origin = new PoInt(0, 0) -//│ origin: PoInt & {x: 0, y: 0} -//│ = PoInt { x: 0, y: 0 } +// let origin = new PoInt(0, 0) diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index 1350b5e9bc..0550fedd84 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -28,69 +28,117 @@ if f is Foo(a) then a else 0 class PoInt[A](x: A, y: A) //│ class PoInt[A](x: A, y: A) +new PoInt(1, 2) +//│ PoInt[1 | 2] +//│ res +//│ = PoInt {} + +:e +new PoInt +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.37: new PoInt +//│ ║ ^^^^^ +//│ ╟── argument list of type `[]` does not match type `[x: ?A, y: ?A]` +//│ ║ l.37: new PoInt +//│ ╙── ^ +//│ PoInt[nothing] | error +//│ res +//│ = PoInt {} + +:e +new PoInt['_] +//│ ╔══[ERROR] Type arguments in `new` expressions are not yet supported +//│ ║ l.49: new PoInt['_] +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.49: new PoInt['_] +//│ ║ ^^^^^^^^^ +//│ ╟── argument list of type `[]` does not match type `[x: ?A, y: ?A]` +//│ ║ l.49: new PoInt['_] +//│ ╙── ^ +//│ PoInt[nothing] | error +//│ Code generation encountered an error: +//│ Unsupported `new` class term: TyApp(Var(PoInt), List('_)) + +:e +new PoInt[Str](0, 0) +//│ ╔══[ERROR] Type arguments in `new` expressions are not yet supported +//│ ║ l.64: new PoInt[Str](0, 0) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ PoInt[0] +//│ Code generation encountered an error: +//│ Unsupported `new` class term: TyApp(Var(PoInt), List(TypeName(Str))) + +type T = PoInt[Str] +//│ type T = PoInt[Str] + +:e +new T(0, 0) +//│ ╔══[ERROR] Type alias T cannot be used in `new` expression +//│ ║ l.76: new T(0, 0) +//│ ╙── ^^^^^^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ type alias T is not a valid expression + let origin = new PoInt(0, 0) //│ let origin: PoInt[0] //│ origin //│ = PoInt {} -// TODO +:e // TODO support let origin = PoInt[Int](0, 0) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.37: let origin = PoInt[Int](0, 0) +//│ ║ l.90: let origin = PoInt[Int](0, 0) //│ ╙── ^^^^^^^^^^ //│ let origin: PoInt[0] //│ origin //│ = PoInt {} -// TODO +:e // TODO support let origin = new PoInt[Int](0, 0) -//│ ╔══[PARSE ERROR] Unexpected application after `new` keyword -//│ ║ l.46: let origin = new PoInt[Int](0, 0) -//│ ╙── ^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.46: let origin = new PoInt[Int](0, 0) -//│ ╙── ^^^ -//│ let origin: error -//│ origin -//│ = {} +//│ ╔══[ERROR] Type arguments in `new` expressions are not yet supported +//│ ║ l.99: let origin = new PoInt[Int](0, 0) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ let origin: PoInt[0] +//│ Code generation encountered an error: +//│ Unsupported `new` class term: TyApp(Var(PoInt), List(TypeName(Int))) -// TODO +:e // TODO support new {} -//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword -//│ ║ l.59: new {} -//│ ╙── ^^ -//│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.59: new {} -//│ ╙── ^^^ +//│ ╔══[ERROR] Unexpected type `anything` after `new` keyword +//│ ║ l.109: new {} +//│ ╙── ^^ //│ error -//│ res -//│ = {} +//│ Code generation encountered an error: +//│ Unsupported `new` class term: Bra(rcd = true, Rcd()) -// TODO +:pe +:e new //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.71: new -//│ ╙── ^ -//│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.71: new -//│ ╙── ^^^ +//│ ║ l.119: new +//│ ╙── ^ +//│ ╔══[ERROR] Unexpected type `()` after `new` keyword +//│ ║ l.119: new +//│ ╙── ^ //│ error -//│ res -//│ = {} +//│ Code generation encountered an error: +//│ Unsupported `new` class term: UnitLit(true) -// TODO +:e // support? new x: 0 -//│ ╔══[PARSE ERROR] Unexpected type ascription after `new` keyword -//│ ║ l.84: x: 0 -//│ ╙── ^ -//│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.83: new -//│ ╙── ^^^ +//│ ╔══[ERROR] Not a recognized type +//│ ║ l.132: x: 0 +//│ ╙── ^ +//│ ╔══[ERROR] Unexpected type `nothing` after `new` keyword +//│ ║ l.132: x: 0 +//│ ╙── ^ //│ error -//│ res -//│ = {} +//│ Code generation encountered an error: +//│ Unsupported `new` class term: Blk(...) @@ -100,9 +148,9 @@ fun f(x) = {x} :e new f(1) -//│ ╔══[ERROR] Value f cannot be used in `new` expression -//│ ║ l.102: new f(1) -//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] type identifier not found: f +//│ ║ l.150: new f(1) +//│ ╙── ^ //│ error //│ res //│ = { x: 1 } @@ -113,10 +161,9 @@ module Oops :e new Oops -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.115: new Oops -//│ ║ ^^^^^^^^ -//│ ╙── applied expression of type `Oops` is not a function +//│ ╔══[ERROR] Module Oops cannot be used in `new` expression +//│ ║ l.163: new Oops +//│ ╙── ^^^^ //│ error //│ res //│ = Oops {} @@ -125,13 +172,12 @@ new Oops :e new Oops2 trait Oops2 -//│ ╔══[ERROR] Trait Oops2 cannot be used in term position -//│ ║ l.126: new Oops2 -//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Trait Oops2 cannot be used in `new` expression +//│ ║ l.173: new Oops2 +//│ ╙── ^^^^^ //│ trait Oops2 //│ error -//│ res -//│ Runtime error: -//│ TypeError: Cannot read properties of undefined (reading 'build') +//│ Code generation encountered an error: +//│ trait used in term position diff --git a/shared/src/test/diff/nu/NoThisCtor.mls b/shared/src/test/diff/nu/NoThisCtor.mls index 0493ba15e1..4ed1d59bcf 100644 --- a/shared/src/test/diff/nu/NoThisCtor.mls +++ b/shared/src/test/diff/nu/NoThisCtor.mls @@ -143,7 +143,7 @@ class Bar2() extends Bar() { // it accesses this in an unusual way! :e -abstract class Foo: Int -> Int { +abstract class Foo: (Int -> Int) { val x = f fun f = this(0) } diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index 539c23787c..e4098b8a4a 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,3 +1,167 @@ :NewDefs +// ;; +// : +// new A.B + + + +module Foo { val a = 1 } +//│ module Foo { +//│ val a: 1 +//│ } + +Foo.a +//│ 1 +//│ res +//│ = 1 + + + +:e +123 { 4 } +//│ ╔══[ERROR] Refinement terms are not yet supported +//│ ║ l.23: 123 { 4 } +//│ ╙── ^^^^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ cannot generate code for term Rft(IntLit(123), ...) + + +class A +//│ class A { +//│ constructor() +//│ } + +:e +new A { } +//│ ╔══[ERROR] Refinement terms are not yet supported +//│ ║ l.38: new A { } +//│ ╙── ^^^^^^^^^ +//│ error +//│ Code generation encountered an error: +//│ cannot generate code for term Rft(NuNew(Var(A)), ...) + + + + +:w +class Foo { constructor(x: Int){};; val y = 2 } +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.50: class Foo { constructor(x: Int){};; val y = 2 } +//│ ╙── ^^ +//│ class Foo { +//│ constructor(x: Int) +//│ val y: 2 +//│ } + +:pe +:e +class Foo { constructor(x: Int){}; val y = 2 } +//│ ╔══[PARSE ERROR] Unexpected operator in expression position +//│ ║ l.61: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╙── ^ +//│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position +//│ ║ l.61: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╙── ^^^ +//│ ╔══[ERROR] Unexpected equation in this position +//│ ║ l.61: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╙── ^^^^^ +//│ class Foo { +//│ constructor(x: Int) +//│ } +//│ Syntax error: +//│ Private field '#y' must be declared in an enclosing class + +class Foo { + constructor(x: Int){} + val y = 2 +} +//│ class Foo { +//│ constructor(x: Int) +//│ val y: 2 +//│ } + +:e +Foo +//│ ╔══[ERROR] Construction of unparameterized class Foo should use the `new` keyword +//│ ║ l.87: Foo +//│ ╙── ^^^ +//│ (x: Int) -> Foo +//│ res +//│ = [class Foo] + +// :d +:e +new Foo +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.97: new Foo +//│ ║ ^^^ +//│ ╟── argument list of type `[]` does not match type `[x: Int]` +//│ ║ l.97: new Foo +//│ ╙── ^ +//│ Foo | error +//│ res +//│ = Foo {} + +:e +let f = new Foo +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.109: let f = new Foo +//│ ║ ^^^ +//│ ╟── argument list of type `[]` does not match type `[x: Int]` +//│ ║ l.109: let f = new Foo +//│ ╙── ^ +//│ let f: Foo | error +//│ f +//│ = Foo {} + +:e +f(1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.121: f(1) +//│ ║ ^^^^ +//│ ╟── application of type `Foo` is not a function +//│ ║ l.109: let f = new Foo +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `1 -> ?a` +//│ ║ l.121: f(1) +//│ ╙── ^ +//│ error +//│ res +//│ Runtime error: +//│ TypeError: f is not a function + + +new Foo(2) +//│ Foo +//│ res +//│ = Foo {} + +// new Foo("2") + +:e +new Foo() +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.145: new Foo() +//│ ║ ^^^^^^^^^ +//│ ╟── argument list of type `[]` does not match type `[x: Int]` +//│ ║ l.145: new Foo() +//│ ╙── ^^ +//│ Foo | error +//│ res +//│ = Foo {} + + +// :dp +new Foo(1).y +//│ 2 +//│ res +//│ = 2 + + + + + + diff --git a/shared/src/test/diff/nu/Object.mls b/shared/src/test/diff/nu/Object.mls index b8df29c71d..1f8ab3df0b 100644 --- a/shared/src/test/diff/nu/Object.mls +++ b/shared/src/test/diff/nu/Object.mls @@ -91,7 +91,7 @@ Object //│ ╔══[ERROR] Class Object is abstract and cannot be instantiated //│ ║ l.90: Object //│ ╙── ^^^^^^ -//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no constructor //│ ║ l.90: Object //│ ╙── ^^^^^^ //│ error @@ -103,7 +103,7 @@ Object() //│ ╔══[ERROR] Class Object is abstract and cannot be instantiated //│ ║ l.102: Object() //│ ╙── ^^^^^^ -//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no constructor //│ ║ l.102: Object() //│ ╙── ^^^^^^ //│ error @@ -114,11 +114,8 @@ Object() new Object //│ ╔══[ERROR] Class Object is abstract and cannot be instantiated //│ ║ l.114: new Object -//│ ╙── ^^^^^^^^^^ -//│ ╔══[ERROR] Class Object cannot be instantiated as it exposes no such constructor -//│ ║ l.114: new Object -//│ ╙── ^^^^^^^^^^ -//│ error +//│ ╙── ^^^^^^ +//│ Object //│ Code generation encountered an error: //│ unresolved symbol Object diff --git a/shared/src/test/diff/nu/Refinements.mls b/shared/src/test/diff/nu/Refinements.mls index 5db034cb6b..3aa89616d7 100644 --- a/shared/src/test/diff/nu/Refinements.mls +++ b/shared/src/test/diff/nu/Refinements.mls @@ -76,18 +76,14 @@ r with { x: 1 } //│ = { x: 1 } -:pe // TODO support :e // TODO support let r = new {} -//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword -//│ ║ l.81: let r = new {} +//│ ╔══[ERROR] Unexpected type `anything` after `new` keyword +//│ ║ l.80: let r = new {} //│ ╙── ^^ -//│ ╔══[ERROR] Currently unsupported `new` syntax -//│ ║ l.81: let r = new {} -//│ ╙── ^^^ //│ let r: error -//│ r -//│ = {} +//│ Code generation encountered an error: +//│ Unsupported `new` class term: Bra(rcd = true, Rcd()) r : Object //│ Object @@ -108,16 +104,16 @@ let r = { x: 0 } :e r : Object //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.109: r : Object +//│ ║ l.105: r : Object //│ ║ ^ //│ ╟── record literal of type `{x: 0}` is not an instance of type `Object` -//│ ║ l.103: let r = { x: 0 } -//│ ║ ^ +//│ ║ l.99: let r = { x: 0 } +//│ ║ ^ //│ ╟── but it flows into reference with expected type `Object` -//│ ║ l.109: r : Object +//│ ║ l.105: r : Object //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.109: r : Object +//│ ║ l.105: r : Object //│ ╙── ^^^^^^ //│ Object //│ res @@ -142,16 +138,16 @@ o : {} :e o : Object //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.143: o : Object +//│ ║ l.139: o : Object //│ ║ ^ //│ ╟── type `anything` is not an instance of type `Object` -//│ ║ l.136: fun o : {} +//│ ║ l.132: fun o : {} //│ ║ ^^ //│ ╟── but it flows into reference with expected type `Object` -//│ ║ l.143: o : Object +//│ ║ l.139: o : Object //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.143: o : Object +//│ ║ l.139: o : Object //│ ╙── ^^^^^^ //│ Object @@ -173,10 +169,10 @@ o : Object :e let d = D & { f: 0 } //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.174: let d = D & { f: 0 } +//│ ║ l.170: let d = D & { f: 0 } //│ ╙── ^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.174: let d = D & { f: 0 } +//│ ║ l.170: let d = D & { f: 0 } //│ ╙── ^ //│ let d: error diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 9b4fa8bb81..7f9a6fd6b9 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -126,7 +126,7 @@ Foo3(1).foo class Foo4 { fun test = [Foo4.test] } -//│ ╔══[ERROR] Class Foo4 cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class Foo4 cannot be instantiated as it exposes no constructor //│ ║ l.127: fun test = [Foo4.test] //│ ╙── ^^^^ //│ class Foo4 { diff --git a/shared/src/test/diff/nu/SimpleTraitImpl.mls b/shared/src/test/diff/nu/SimpleTraitImpl.mls index 2792480218..ff7a366dc8 100644 --- a/shared/src/test/diff/nu/SimpleTraitImpl.mls +++ b/shared/src/test/diff/nu/SimpleTraitImpl.mls @@ -359,7 +359,7 @@ class C2 extends T3[Int] //│ ╔══[ERROR] Method implementations in traits are not yet supported //│ ║ l.356: val r = C2().x //│ ╙── ^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no constructor //│ ║ l.356: val r = C2().x //│ ╙── ^^ //│ trait T3[A] { @@ -383,7 +383,7 @@ class C3 extends T3[Int] //│ val r: error //│ } -(new C3) : T3['X] +new C3 : T3['X] //│ T3[Int] diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index 1ebff6886b..bc37f00a70 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -15,9 +15,9 @@ class D(x: Int) :e fun foo(c) = new c -//│ ╔══[ERROR] Cannot use `new` on non-class variable of type ?a +//│ ╔══[ERROR] type identifier not found: c //│ ║ l.17: fun foo(c) = new c -//│ ╙── ^^^^^ +//│ ╙── ^ //│ fun foo: anything -> error :re @@ -39,9 +39,9 @@ foo(C) :e fun bar(c) = new c(123) -//│ ╔══[ERROR] Cannot use `new` on non-class variable of type ?a +//│ ╔══[ERROR] type identifier not found: c //│ ║ l.41: fun bar(c) = new c(123) -//│ ╙── ^^^^^^^^^^ +//│ ╙── ^ //│ fun bar: anything -> error :re @@ -73,14 +73,14 @@ class C //│ constructor() //│ } -:e // TODO +:e // TODO support new C { val x = 1 } -//│ ╔══[ERROR] Currently unsupported `new` syntax +//│ ╔══[ERROR] Refinement terms are not yet supported //│ ║ l.77: new C { val x = 1 } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: -//│ custom class body is not supported yet +//│ cannot generate code for term Rft(NuNew(Var(C)), ...) @@ -196,7 +196,7 @@ test(0).x // IntLit then x.n // in Scala, compiler sees x.n : Int = x.T <: T // BoolLit then x.b -abstract class Expr[A]: IntLit | BoolLit {} +abstract class Expr[A]: (IntLit | BoolLit) {} class IntLit() extends Expr[Int] class BoolLit() extends Expr[Bool] //│ abstract class Expr[A]: BoolLit | IntLit diff --git a/shared/src/test/diff/nu/TraitSignatures.mls b/shared/src/test/diff/nu/TraitSignatures.mls index 394cb400e1..f02ba4efa6 100644 --- a/shared/src/test/diff/nu/TraitSignatures.mls +++ b/shared/src/test/diff/nu/TraitSignatures.mls @@ -4,7 +4,7 @@ // * Interfaces that are "callable" are important to support for TS/JS interop -declare trait Foo: (x: Num) => Num { +declare trait Foo: ((x: Num) => Num) { val y: Str } //│ declare trait Foo: (x: Num) -> Num { diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index b63734cda5..0ab5a2970f 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -87,6 +87,7 @@ c1.f // * The more tricky case: +// * TODO better error (cf. "exposes no constructor") :e trait T2[A] { fun f: A -> A @@ -96,10 +97,10 @@ class C2 extends T2['FigureItOut] { fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.93: val r = C2().f(false) +//│ ║ l.94: val r = C2().f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no such constructor -//│ ║ l.93: val r = C2().f(false) +//│ ╔══[ERROR] Class C2 cannot be instantiated as it exposes no constructor +//│ ║ l.94: val r = C2().f(false) //│ ╙── ^^ //│ trait T2[A] { //│ fun f: A -> A @@ -120,10 +121,10 @@ class C3 extends T3['FigureItOut] { fun f(x: Int) = x } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.117: val r = (C3() : T3['X]).f(false) +//│ ║ l.118: val r = (C3() : T3['X]).f(false) //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Class C3 cannot be instantiated as it exposes no such constructor -//│ ║ l.117: val r = (C3() : T3['X]).f(false) +//│ ╔══[ERROR] Class C3 cannot be instantiated as it exposes no constructor +//│ ║ l.118: val r = (C3() : T3['X]).f(false) //│ ╙── ^^ //│ trait T3[A] { //│ fun f: A -> A @@ -138,7 +139,7 @@ class C3 extends T3['FigureItOut] { :e // FIXME C3() : T3['X] //│ ╔══[ERROR] Construction of unparameterized class C3 should use the `new` keyword -//│ ║ l.139: C3() : T3['X] +//│ ║ l.140: C3() : T3['X] //│ ╙── ^^ //│ T3[Int] //│ res @@ -153,14 +154,14 @@ abstract class IO[A] { } class Bind[A](underlying: IO[A]) extends IO[Int] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.151: abstract class IO[A] { +//│ ║ l.152: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.152: fun test = Bind(this) : IO[Int] +//│ ║ l.153: fun test = Bind(this) : IO[Int] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.153: } +//│ ║ l.154: } //│ ╙── ^ //│ ╔══[ERROR] Type `Bind[?A]` does not contain member `IO#A` -//│ ║ l.151: abstract class IO[A] { +//│ ║ l.152: abstract class IO[A] { //│ ╙── ^ //│ abstract class IO[A] { //│ fun test: IO[Int] @@ -177,27 +178,27 @@ class Map[A, B](underlying: IO[A], f: A -> B) extends IO[B] { fun run: B = error } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.171: abstract class IO[A] { +//│ ║ l.172: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.172: fun map[B]: (A -> B) -> IO[B] // * Removing this works... +//│ ║ l.173: fun map[B]: (A -> B) -> IO[B] // * Removing this works... //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.173: fun map(f) = Map(this, f) +//│ ║ l.174: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.174: fun run: A +//│ ║ l.175: fun run: A //│ ║ ^^^^^^^^^^^^ -//│ ║ l.175: } +//│ ║ l.176: } //│ ╙── ^ //│ ╔══[ERROR] Type `Map[?A, ?B]` does not contain member `IO#A` -//│ ║ l.171: abstract class IO[A] { +//│ ║ l.172: abstract class IO[A] { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method map: -//│ ║ l.173: fun map(f) = Map(this, f) +//│ ║ l.174: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Map[?A, ?B]` does not have field 'IO#A' -//│ ║ l.173: fun map(f) = Map(this, f) +//│ ║ l.174: fun map(f) = Map(this, f) //│ ║ ^^^^^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.172: fun map[B]: (A -> B) -> IO[B] // * Removing this works... +//│ ║ l.173: fun map[B]: (A -> B) -> IO[B] // * Removing this works... //│ ╙── ^^^^^ //│ abstract class IO[A] { //│ fun map: forall 'B. (A -> 'B) -> IO['B] @@ -217,27 +218,27 @@ class Bind[A, B](underlying: IO[A], f: A -> IO[B]) extends IO[B] { fun run = f(underlying.run).run } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.211: abstract class IO[A] { +//│ ║ l.212: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.212: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error +//│ ║ l.213: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.213: fun bind(f) = Bind(this, f) +//│ ║ l.214: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.214: fun run: A +//│ ║ l.215: fun run: A //│ ║ ^^^^^^^^^^^^ -//│ ║ l.215: } +//│ ║ l.216: } //│ ╙── ^ //│ ╔══[ERROR] Type `Bind[?A, ?B]` does not contain member `IO#A` -//│ ║ l.211: abstract class IO[A] { +//│ ║ l.212: abstract class IO[A] { //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method bind: -//│ ║ l.213: fun bind(f) = Bind(this, f) +//│ ║ l.214: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Bind[?A, ?B]` does not have field 'IO#A' -//│ ║ l.213: fun bind(f) = Bind(this, f) +//│ ║ l.214: fun bind(f) = Bind(this, f) //│ ║ ^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from applied type reference: -//│ ║ l.212: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error +//│ ║ l.213: fun bind[B]: (A -> IO[B]) -> IO[B] // * FIXME: causes cycle error //│ ╙── ^^^^^ //│ abstract class IO[A] { //│ fun bind: forall 'B. (A -> IO['B]) -> IO['B] @@ -253,11 +254,11 @@ abstract class IO[A] { class Bind[B]() extends IO[B] } //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.252: abstract class IO[A] { +//│ ║ l.253: abstract class IO[A] { //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.253: class Bind[B]() extends IO[B] +//│ ║ l.254: class Bind[B]() extends IO[B] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.254: } +//│ ║ l.255: } //│ ╙── ^ //│ abstract class IO[A] { //│ class Bind[B]() extends IO diff --git a/shared/src/test/diff/nu/Uninstantiable.mls b/shared/src/test/diff/nu/Uninstantiable.mls index 0ea6cfac1d..04e5f34318 100644 --- a/shared/src/test/diff/nu/Uninstantiable.mls +++ b/shared/src/test/diff/nu/Uninstantiable.mls @@ -6,7 +6,7 @@ Int //│ ╔══[ERROR] Class Int is abstract and cannot be instantiated //│ ║ l.5: Int //│ ╙── ^^^ -//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no constructor //│ ║ l.5: Int //│ ╙── ^^^ //│ error @@ -18,7 +18,7 @@ Int() //│ ╔══[ERROR] Class Int is abstract and cannot be instantiated //│ ║ l.17: Int() //│ ╙── ^^^ -//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no such constructor +//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no constructor //│ ║ l.17: Int() //│ ╙── ^^^ //│ error @@ -29,11 +29,8 @@ Int() new Int //│ ╔══[ERROR] Class Int is abstract and cannot be instantiated //│ ║ l.29: new Int -//│ ╙── ^^^^^^^ -//│ ╔══[ERROR] Class Int cannot be instantiated as it exposes no such constructor -//│ ║ l.29: new Int -//│ ╙── ^^^^^^^ -//│ error +//│ ╙── ^^^ +//│ Int //│ Code generation encountered an error: //│ unresolved symbol Int diff --git a/shared/src/test/diff/nu/i191.mls b/shared/src/test/diff/nu/i191.mls new file mode 100644 index 0000000000..2601152466 --- /dev/null +++ b/shared/src/test/diff/nu/i191.mls @@ -0,0 +1,169 @@ +:NewDefs + + +class demo() { constructor(param1: Int) } +val invalidConstruction = new demo(1) +//│ class demo() { +//│ constructor(param1: Int) +//│ } +//│ val invalidConstruction: demo +//│ invalidConstruction +//│ = demo {} + +:e +class demo() { constructor(param1: Int) } +val invalidConstruction = demo() +//│ ╔══[ERROR] Construction of class with auxiliary constructor should use the `new` keyword +//│ ║ l.15: val invalidConstruction = demo() +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.15: val invalidConstruction = demo() +//│ ║ ^^^^^^ +//│ ╟── argument of type `[]` does not match type `[param1: Int]` +//│ ║ l.15: val invalidConstruction = demo() +//│ ╙── ^^ +//│ class demo() { +//│ constructor(param1: Int) +//│ } +//│ val invalidConstruction: demo | error +//│ invalidConstruction +//│ = demo {} + +:e +val invalidConstruction = demo(1) +//│ ╔══[ERROR] Construction of class with auxiliary constructor should use the `new` keyword +//│ ║ l.33: val invalidConstruction = demo(1) +//│ ╙── ^^^^ +//│ val invalidConstruction: demo +//│ invalidConstruction +//│ = demo {} + +:e +val invalidConstruction = new demo +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.42: val invalidConstruction = new demo +//│ ║ ^^^^ +//│ ╟── argument list of type `[]` does not match type `[param1: Int]` +//│ ║ l.42: val invalidConstruction = new demo +//│ ╙── ^ +//│ val invalidConstruction: demo | error +//│ invalidConstruction +//│ = demo {} + +:e +class demo { constructor(param1: Int) } +val invalidConstruction = demo() +//│ ╔══[ERROR] Construction of unparameterized class demo should use the `new` keyword +//│ ║ l.55: val invalidConstruction = demo() +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.55: val invalidConstruction = demo() +//│ ║ ^^^^^^ +//│ ╟── argument of type `[]` does not match type `[param1: Int]` +//│ ║ l.55: val invalidConstruction = demo() +//│ ╙── ^^ +//│ class demo { +//│ constructor(param1: Int) +//│ } +//│ val invalidConstruction: demo | error +//│ invalidConstruction +//│ Runtime error: +//│ TypeError: Class constructor demo cannot be invoked without 'new' + +:e +val invalidConstruction = demo +//│ ╔══[ERROR] Construction of unparameterized class demo should use the `new` keyword +//│ ║ l.74: val invalidConstruction = demo +//│ ╙── ^^^^ +//│ val invalidConstruction: (param1: Int) -> demo +//│ invalidConstruction +//│ = [class demo] + +:e +val invalidConstruction = new demo +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.83: val invalidConstruction = new demo +//│ ║ ^^^^ +//│ ╟── argument list of type `[]` does not match type `[param1: Int]` +//│ ║ l.83: val invalidConstruction = new demo +//│ ╙── ^ +//│ val invalidConstruction: demo | error +//│ invalidConstruction +//│ = demo {} + +val invalidConstruction = new demo(1) +//│ val invalidConstruction: demo +//│ invalidConstruction +//│ = demo {} + +:e +val invalidConstruction = demo() +//│ ╔══[ERROR] Construction of unparameterized class demo should use the `new` keyword +//│ ║ l.100: val invalidConstruction = demo() +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.100: val invalidConstruction = demo() +//│ ║ ^^^^^^ +//│ ╟── argument of type `[]` does not match type `[param1: Int]` +//│ ║ l.100: val invalidConstruction = demo() +//│ ╙── ^^ +//│ val invalidConstruction: demo | error +//│ invalidConstruction +//│ Runtime error: +//│ TypeError: Class constructor demo cannot be invoked without 'new' + + +class demo(x: Int) { + constructor(param1: Int, param2: Int) { + log(param1) + log(param2) + x = param1*param2 + } +} +//│ class demo(x: Int) { +//│ constructor(param1: Int, param2: Int) +//│ } + +val validConstruction = new demo(5, 10) +//│ val validConstruction: demo +//│ validConstruction +//│ = demo {} +//│ // Output +//│ 5 +//│ 10 + +:e +val invalidConstruction = demo(5) +//│ ╔══[ERROR] Construction of class with auxiliary constructor should use the `new` keyword +//│ ║ l.136: val invalidConstruction = demo(5) +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.136: val invalidConstruction = demo(5) +//│ ║ ^^^^^^^ +//│ ╟── argument of type `[5]` does not match type `[param1: Int, param2: Int]` +//│ ║ l.136: val invalidConstruction = demo(5) +//│ ╙── ^^^ +//│ val invalidConstruction: demo | error +//│ invalidConstruction +//│ = demo {} +//│ // Output +//│ 5 +//│ undefined + +:e +val invalidConstruction = new demo(5) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.154: val invalidConstruction = new demo(5) +//│ ║ ^^^^^^^^^^^ +//│ ╟── argument list of type `[5]` does not match type `[param1: Int, param2: Int]` +//│ ║ l.154: val invalidConstruction = new demo(5) +//│ ╙── ^^^ +//│ val invalidConstruction: demo | error +//│ invalidConstruction +//│ = demo {} +//│ // Output +//│ 5 +//│ undefined + + + diff --git a/shared/src/test/diff/parser/BasicSyntax.mls b/shared/src/test/diff/parser/BasicSyntax.mls index 3b2d1c4660..5c4c9b09d7 100644 --- a/shared/src/test/diff/parser/BasicSyntax.mls +++ b/shared/src/test/diff/parser/BasicSyntax.mls @@ -319,33 +319,27 @@ f[1, 2, 3] f{} //│ |f|{||}| -//│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.320: f{} -//│ ╙── ^^ -//│ Parsed: {f} +//│ Parsed: {f { ‹› }} f{1} //│ |f|{|1|}| -//│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.327: f{1} -//│ ╙── ^^^ -//│ Parsed: {f} +//│ Parsed: {f { ‹1› }} f{1, 2, 3} //│ |f|{|1|,| |2|,| |3|}| -//│ ╔══[PARSE ERROR] Expected end of input; found curly brace section instead -//│ ║ l.334: f{1, 2, 3} -//│ ╙── ^^^^^^^^^ -//│ Parsed: {f} +//│ ╔══[PARSE ERROR] Unexpected comma here +//│ ║ l.328: f{1, 2, 3} +//│ ╙── ^ +//│ Parsed: {f { ‹1› }} f 1,, 2 //│ |f| |1|,|,| |2| //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.342: f 1,, 2 +//│ ║ l.336: f 1,, 2 //│ ╙── ^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.342: f 1,, 2 +//│ ║ l.336: f 1,, 2 //│ ╙── ^^^^^^^ //│ Parsed: {f(1, 2,)} @@ -357,10 +351,10 @@ f of x f g x //│ |f| |g| |x| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.357: f g x +//│ ║ l.351: f g x //│ ╙── ^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.357: f g x +//│ ║ l.351: f g x //│ ╙── ^^^^^ //│ Parsed: {f(g(x,),)} @@ -371,7 +365,7 @@ f of g of x f of of g //│ |f| |#of| |#of| |g| //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position -//│ ║ l.371: f of of g +//│ ║ l.365: f of of g //│ ╙── ^^ //│ Parsed: {f(g,)} @@ -379,52 +373,52 @@ f of of g f x: 1 //│ |f| |x|#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.379: f x: 1 +//│ ║ l.373: f x: 1 //│ ╙── ^^^^^^ //│ Parsed: {f(x: 1,)} f x: 1, //│ |f| |x|#:| |1|,| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.386: f x: 1, +//│ ║ l.380: f x: 1, //│ ╙── ^^^^^^ //│ Parsed: {f(x: 1,)} f x : 1 //│ |f| |x| |#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.393: f x : 1 +//│ ║ l.387: f x : 1 //│ ╙── ^^^ //│ Parsed: {f(x : 1,)} f x: 1, y: 2 //│ |f| |x|#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.400: f x: 1, y: 2 +//│ ║ l.394: f x: 1, y: 2 //│ ╙── ^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: 2,)} f x : 1, y: 2 //│ |f| |x| |#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.407: f x : 1, y: 2 +//│ ║ l.401: f x : 1, y: 2 //│ ╙── ^^^^^^^^^^^^^ //│ Parsed: {f(x : 1, y: 2,)} f x: 1, y: 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.414: f x: 1, y: 2, z: 3 +//│ ║ l.408: f x: 1, y: 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: 2, z: 3,)} f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.421: f x: 1, y: g 2, z: 3 +//│ ║ l.415: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.421: f x: 1, y: g 2, z: 3 +//│ ║ l.415: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: g(2, z: 3,),)} @@ -439,10 +433,10 @@ f(x: 1, y: g(2), z: 3) f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.439: f x: 1, y: g 2, z: 3 +//│ ║ l.433: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.439: f x: 1, y: g 2, z: 3 +//│ ║ l.433: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: g(2, z: 3,),)} @@ -453,13 +447,13 @@ f of x: 1, y: g of 2, z: 3 f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ |f| |x|#:| |1| |+| |1|,| |y|#:| |2| |2|,| |z|#:| |3| |+| |2| |4| |-| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.453: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.447: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.453: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.447: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.453: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.447: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: +(1,)(1,), y: 2(2, z: +(3,)(2(-(4,)(1,),),),),)} @@ -471,10 +465,10 @@ x.y .y //│ |.y| //│ ╔══[PARSE ERROR] Unexpected selector in expression position -//│ ║ l.471: .y +//│ ║ l.465: .y //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.471: .y +//│ ║ l.465: .y //│ ╙── ^ //│ Parsed: {undefined} diff --git a/shared/src/test/diff/parser/New.mls b/shared/src/test/diff/parser/New.mls index 3bdc464a75..2ce52058de 100644 --- a/shared/src/test/diff/parser/New.mls +++ b/shared/src/test/diff/parser/New.mls @@ -6,7 +6,7 @@ new //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here //│ ║ l.4: new //│ ╙── ^ -//│ Parsed: {new {}} +//│ Parsed: {new undefined} :pe (new) @@ -14,82 +14,65 @@ new //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.12: (new) //│ ╙── ^ -//│ Parsed: {'(' new {} ')'} +//│ Parsed: {'(' new undefined ')'} -:pe new {} //│ |#new| |{||}| -//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword -//│ ║ l.20: new {} -//│ ╙── ^^ -//│ Parsed: {new {}} +//│ Parsed: {new '{' {} '}'} new A //│ |#new| |A| -//│ Parsed: {new A([]) {}} +//│ Parsed: {new A} new A() //│ |#new| |A|(||)| -//│ Parsed: {new A([]) {}} +//│ Parsed: {(new A)()} new A(1, 2, 3) //│ |#new| |A|(|1|,| |2|,| |3|)| -//│ Parsed: {new A([1, 2, 3,]) {}} +//│ Parsed: {(new A)(1, 2, 3,)} new A of 1, 2, 3 //│ |#new| |A| |#of| |1|,| |2|,| |3| -//│ Parsed: {new A([1, 2, 3,]) {}} +//│ Parsed: {new A(1, 2, 3,)} new A { fun x = 1 } //│ |#new| |A| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A([]) {fun x = 1}} +//│ Parsed: {new A { ‹fun x = 1› }} new A() { fun x = 1 } //│ |#new| |A|(||)| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A([]) {fun x = 1}} +//│ Parsed: {(new A)() { ‹fun x = 1› }} new A(1, 2, 3) { fun x = 1 } //│ |#new| |A|(|1|,| |2|,| |3|)| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A([1, 2, 3,]) {fun x = 1}} +//│ Parsed: {(new A)(1, 2, 3,) { ‹fun x = 1› }} new A of 1, 2, 3 { fun x = 1 } //│ |#new| |A| |#of| |1|,| |2|,| |3| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A([1, 2, 3,]) {fun x = 1}} +//│ Parsed: {new A(1, 2, 3 { ‹fun x = 1› },)} :pe new new //│ |#new| |#new| //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.61: new new +//│ ║ l.57: new new //│ ╙── ^ -//│ ╔══[PARSE ERROR] Unexpected object instantiation after `new` keyword -//│ ║ l.61: new new -//│ ╙── ^^^ -//│ Parsed: {new {}} +//│ Parsed: {new new undefined} -:pe new new {} //│ |#new| |#new| |{||}| -//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword -//│ ║ l.72: new new {} -//│ ╙── ^^ -//│ ╔══[PARSE ERROR] Unexpected object instantiation after `new` keyword -//│ ║ l.72: new new {} -//│ ╙── ^^^ -//│ Parsed: {new {}} +//│ Parsed: {new new '{' {} '}'} :pe new {new} //│ |#new| |{|#new|}| //│ ╔══[PARSE ERROR] Unexpected end of curly brace section; an expression was expected here -//│ ║ l.83: new {new} +//│ ║ l.69: new {new} //│ ╙── ^ //│ ╔══[PARSE ERROR] Record field should have a name -//│ ║ l.83: new {new} +//│ ║ l.69: new {new} //│ ╙── ^^^ -//│ ╔══[PARSE ERROR] Unexpected record after `new` keyword -//│ ║ l.83: new {new} -//│ ╙── ^^^^^ -//│ Parsed: {new {}} +//│ Parsed: {new '{' {: new undefined} '}'} diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 9d74c269bd..2edc36dfce 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -195,7 +195,9 @@ class DiffTests var newParser = basePath.headOption.contains("parser") || basePath.headOption.contains("compiler") - val backend = new JSTestBackend() + val backend = new JSTestBackend { + def oldDefs = !newDefs + } val host = ReplHost() val codeGenTestHelpers = new CodeGenTestHelpers(file, output) From b8db6a1b2ac6ea2519e29e3483a94739dc7e6ea0 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 28 Nov 2023 17:57:59 +0800 Subject: [PATCH 486/498] Clean up some tests + add some doc --- .../src/main/scala/mlscript/JSBackend.scala | 5 +- shared/src/test/diff/nu/AuxCtors.mls | 37 ++++ shared/src/test/diff/nu/NewNew.mls | 178 +++++++++++++++--- shared/src/test/diff/nu/NuScratch.mls | 164 ---------------- 4 files changed, 192 insertions(+), 192 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 1d5a94e857..7057e76993 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -303,14 +303,17 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { case iff: If => throw CodeGenError(s"if expression was not desugared") case NuNew(cls) => + // * The following logic handles the case when `new C(123)` needs to be translated to `new C.class(123)` cls match { case Var(className) => - translateVar(className, true) match { + translateVar(className, isCallee = true) match { case n: JSNew => n case t => JSNew(t) } case _ => throw CodeGenError(s"Unsupported `new` class term: ${inspect(cls)}") } + // * Would not be quite correct: + // JSNew(translateTerm(cls)) case New(N, TypingUnit(Nil)) => JSRecord(Nil) case New(S(TypeName(className) -> Tup(args)), TypingUnit(Nil)) => val callee = translateVar(className, true) match { diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index 7f5e45f7f4..3f753f4fa8 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -185,4 +185,41 @@ class C { constructor(x: Int);; constructor(y: Int) } //│ } +:w // * FIXME +class Foo { constructor(x: Int){};; val y = 2 } +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.189: class Foo { constructor(x: Int){};; val y = 2 } +//│ ╙── ^^ +//│ class Foo { +//│ constructor(x: Int) +//│ val y: 2 +//│ } + +:pe +:e +class Foo { constructor(x: Int){}; val y = 2 } +//│ ╔══[PARSE ERROR] Unexpected operator in expression position +//│ ║ l.200: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╙── ^ +//│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position +//│ ║ l.200: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╙── ^^^ +//│ ╔══[ERROR] Unexpected equation in this position +//│ ║ l.200: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╙── ^^^^^ +//│ class Foo { +//│ constructor(x: Int) +//│ } +//│ Syntax error: +//│ Private field '#y' must be declared in an enclosing class + +class Foo { + constructor(x: Int){} + val y = 2 +} +//│ class Foo { +//│ constructor(x: Int) +//│ val y: 2 +//│ } + diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index 0550fedd84..c135ca38a9 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -1,7 +1,7 @@ :NewDefs -class Foo(x: Int) +class Foo(val x: Int) //│ class Foo(x: Int) let f = Foo(1) @@ -9,11 +9,26 @@ let f = Foo(1) //│ f //│ = Foo {} +f.x +//│ Int +//│ res +//│ = 1 + let f = new Foo(1) //│ let f: Foo //│ f //│ = Foo {} +f.x +//│ Int +//│ res +//│ = 1 + +new Foo(1).x +//│ Int +//│ res +//│ = 1 + if f is Foo then 1 else 0 //│ 0 | 1 //│ res @@ -24,6 +39,100 @@ if f is Foo(a) then a else 0 //│ res //│ = 1 +let f = Foo +//│ let f: (x: Int) -> Foo +//│ f +//│ = [Function (anonymous)] { +//│ class: [class Foo], +//│ unapply: [Function: unapply] +//│ } + +f(1) +//│ Foo +//│ res +//│ = Foo {} + + +class Foo { + constructor(x: Int){} + val y = 2 +} +//│ class Foo { +//│ constructor(x: Int) +//│ val y: 2 +//│ } + +new Foo(1).y +//│ 2 +//│ res +//│ = 2 + +:e +let f = Foo(1) +//│ ╔══[ERROR] Construction of unparameterized class Foo should use the `new` keyword +//│ ║ l.71: let f = Foo(1) +//│ ╙── ^^^ +//│ let f: Foo +//│ f +//│ Runtime error: +//│ TypeError: Class constructor Foo cannot be invoked without 'new' + +:e +let f = new Foo +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.81: let f = new Foo +//│ ║ ^^^ +//│ ╟── argument list of type `[]` does not match type `[x: Int]` +//│ ║ l.81: let f = new Foo +//│ ╙── ^ +//│ let f: Foo | error +//│ f +//│ = Foo {} + +:e +f(1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.93: f(1) +//│ ║ ^^^^ +//│ ╟── application of type `Foo` is not a function +//│ ║ l.81: let f = new Foo +//│ ║ ^^^ +//│ ╟── but it flows into reference with expected type `1 -> ?a` +//│ ║ l.93: f(1) +//│ ╙── ^ +//│ error +//│ res +//│ Runtime error: +//│ TypeError: f4 is not a function + +:e +new Foo("2") +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.109: new Foo("2") +//│ ║ ^^^^^^^^^^^^ +//│ ╟── string literal of type `"2"` is not an instance of type `Int` +//│ ║ l.109: new Foo("2") +//│ ║ ^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.57: constructor(x: Int){} +//│ ╙── ^^^ +//│ Foo | error +//│ res +//│ = Foo {} + +:e +new Foo() +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.124: new Foo() +//│ ║ ^^^^^^^^^ +//│ ╟── argument list of type `[]` does not match type `[x: Int]` +//│ ║ l.124: new Foo() +//│ ╙── ^^ +//│ Foo | error +//│ res +//│ = Foo {} + + class PoInt[A](x: A, y: A) //│ class PoInt[A](x: A, y: A) @@ -36,11 +145,11 @@ new PoInt(1, 2) :e new PoInt //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.37: new PoInt -//│ ║ ^^^^^ +//│ ║ l.146: new PoInt +//│ ║ ^^^^^ //│ ╟── argument list of type `[]` does not match type `[x: ?A, y: ?A]` -//│ ║ l.37: new PoInt -//│ ╙── ^ +//│ ║ l.146: new PoInt +//│ ╙── ^ //│ PoInt[nothing] | error //│ res //│ = PoInt {} @@ -48,14 +157,14 @@ new PoInt :e new PoInt['_] //│ ╔══[ERROR] Type arguments in `new` expressions are not yet supported -//│ ║ l.49: new PoInt['_] -//│ ╙── ^^^^^^^^^ +//│ ║ l.158: new PoInt['_] +//│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.49: new PoInt['_] -//│ ║ ^^^^^^^^^ +//│ ║ l.158: new PoInt['_] +//│ ║ ^^^^^^^^^ //│ ╟── argument list of type `[]` does not match type `[x: ?A, y: ?A]` -//│ ║ l.49: new PoInt['_] -//│ ╙── ^ +//│ ║ l.158: new PoInt['_] +//│ ╙── ^ //│ PoInt[nothing] | error //│ Code generation encountered an error: //│ Unsupported `new` class term: TyApp(Var(PoInt), List('_)) @@ -63,8 +172,8 @@ new PoInt['_] :e new PoInt[Str](0, 0) //│ ╔══[ERROR] Type arguments in `new` expressions are not yet supported -//│ ║ l.64: new PoInt[Str](0, 0) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.173: new PoInt[Str](0, 0) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ PoInt[0] //│ Code generation encountered an error: //│ Unsupported `new` class term: TyApp(Var(PoInt), List(TypeName(Str))) @@ -75,8 +184,8 @@ type T = PoInt[Str] :e new T(0, 0) //│ ╔══[ERROR] Type alias T cannot be used in `new` expression -//│ ║ l.76: new T(0, 0) -//│ ╙── ^^^^^^^^^^^ +//│ ║ l.185: new T(0, 0) +//│ ╙── ^^^^^^^^^^^ //│ error //│ Code generation encountered an error: //│ type alias T is not a valid expression @@ -89,8 +198,8 @@ let origin = new PoInt(0, 0) :e // TODO support let origin = PoInt[Int](0, 0) //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.90: let origin = PoInt[Int](0, 0) -//│ ╙── ^^^^^^^^^^ +//│ ║ l.199: let origin = PoInt[Int](0, 0) +//│ ╙── ^^^^^^^^^^ //│ let origin: PoInt[0] //│ origin //│ = PoInt {} @@ -98,8 +207,8 @@ let origin = PoInt[Int](0, 0) :e // TODO support let origin = new PoInt[Int](0, 0) //│ ╔══[ERROR] Type arguments in `new` expressions are not yet supported -//│ ║ l.99: let origin = new PoInt[Int](0, 0) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.208: let origin = new PoInt[Int](0, 0) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ let origin: PoInt[0] //│ Code generation encountered an error: //│ Unsupported `new` class term: TyApp(Var(PoInt), List(TypeName(Int))) @@ -108,7 +217,7 @@ let origin = new PoInt[Int](0, 0) :e // TODO support new {} //│ ╔══[ERROR] Unexpected type `anything` after `new` keyword -//│ ║ l.109: new {} +//│ ║ l.218: new {} //│ ╙── ^^ //│ error //│ Code generation encountered an error: @@ -118,10 +227,10 @@ new {} :e new //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.119: new +//│ ║ l.228: new //│ ╙── ^ //│ ╔══[ERROR] Unexpected type `()` after `new` keyword -//│ ║ l.119: new +//│ ║ l.228: new //│ ╙── ^ //│ error //│ Code generation encountered an error: @@ -131,10 +240,10 @@ new new x: 0 //│ ╔══[ERROR] Not a recognized type -//│ ║ l.132: x: 0 +//│ ║ l.241: x: 0 //│ ╙── ^ //│ ╔══[ERROR] Unexpected type `nothing` after `new` keyword -//│ ║ l.132: x: 0 +//│ ║ l.241: x: 0 //│ ╙── ^ //│ error //│ Code generation encountered an error: @@ -149,7 +258,7 @@ fun f(x) = {x} :e new f(1) //│ ╔══[ERROR] type identifier not found: f -//│ ║ l.150: new f(1) +//│ ║ l.259: new f(1) //│ ╙── ^ //│ error //│ res @@ -162,7 +271,7 @@ module Oops :e new Oops //│ ╔══[ERROR] Module Oops cannot be used in `new` expression -//│ ║ l.163: new Oops +//│ ║ l.272: new Oops //│ ╙── ^^^^ //│ error //│ res @@ -173,7 +282,7 @@ new Oops new Oops2 trait Oops2 //│ ╔══[ERROR] Trait Oops2 cannot be used in `new` expression -//│ ║ l.173: new Oops2 +//│ ║ l.282: new Oops2 //│ ╙── ^^^^^ //│ trait Oops2 //│ error @@ -181,3 +290,18 @@ trait Oops2 //│ trait used in term position + +module A { class B } +//│ module A { +//│ class B { +//│ constructor() +//│ } +//│ } + +:ge // TODO support +new A.B +//│ B +//│ Code generation encountered an error: +//│ Unsupported `new` class term: Sel(Var(A), B) + + diff --git a/shared/src/test/diff/nu/NuScratch.mls b/shared/src/test/diff/nu/NuScratch.mls index e4098b8a4a..539c23787c 100644 --- a/shared/src/test/diff/nu/NuScratch.mls +++ b/shared/src/test/diff/nu/NuScratch.mls @@ -1,167 +1,3 @@ :NewDefs -// ;; -// : -// new A.B - - - -module Foo { val a = 1 } -//│ module Foo { -//│ val a: 1 -//│ } - -Foo.a -//│ 1 -//│ res -//│ = 1 - - - -:e -123 { 4 } -//│ ╔══[ERROR] Refinement terms are not yet supported -//│ ║ l.23: 123 { 4 } -//│ ╙── ^^^^^^^^^ -//│ error -//│ Code generation encountered an error: -//│ cannot generate code for term Rft(IntLit(123), ...) - - -class A -//│ class A { -//│ constructor() -//│ } - -:e -new A { } -//│ ╔══[ERROR] Refinement terms are not yet supported -//│ ║ l.38: new A { } -//│ ╙── ^^^^^^^^^ -//│ error -//│ Code generation encountered an error: -//│ cannot generate code for term Rft(NuNew(Var(A)), ...) - - - - -:w -class Foo { constructor(x: Int){};; val y = 2 } -//│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.50: class Foo { constructor(x: Int){};; val y = 2 } -//│ ╙── ^^ -//│ class Foo { -//│ constructor(x: Int) -//│ val y: 2 -//│ } - -:pe -:e -class Foo { constructor(x: Int){}; val y = 2 } -//│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.61: class Foo { constructor(x: Int){}; val y = 2 } -//│ ╙── ^ -//│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.61: class Foo { constructor(x: Int){}; val y = 2 } -//│ ╙── ^^^ -//│ ╔══[ERROR] Unexpected equation in this position -//│ ║ l.61: class Foo { constructor(x: Int){}; val y = 2 } -//│ ╙── ^^^^^ -//│ class Foo { -//│ constructor(x: Int) -//│ } -//│ Syntax error: -//│ Private field '#y' must be declared in an enclosing class - -class Foo { - constructor(x: Int){} - val y = 2 -} -//│ class Foo { -//│ constructor(x: Int) -//│ val y: 2 -//│ } - -:e -Foo -//│ ╔══[ERROR] Construction of unparameterized class Foo should use the `new` keyword -//│ ║ l.87: Foo -//│ ╙── ^^^ -//│ (x: Int) -> Foo -//│ res -//│ = [class Foo] - -// :d -:e -new Foo -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.97: new Foo -//│ ║ ^^^ -//│ ╟── argument list of type `[]` does not match type `[x: Int]` -//│ ║ l.97: new Foo -//│ ╙── ^ -//│ Foo | error -//│ res -//│ = Foo {} - -:e -let f = new Foo -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.109: let f = new Foo -//│ ║ ^^^ -//│ ╟── argument list of type `[]` does not match type `[x: Int]` -//│ ║ l.109: let f = new Foo -//│ ╙── ^ -//│ let f: Foo | error -//│ f -//│ = Foo {} - -:e -f(1) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.121: f(1) -//│ ║ ^^^^ -//│ ╟── application of type `Foo` is not a function -//│ ║ l.109: let f = new Foo -//│ ║ ^^^ -//│ ╟── but it flows into reference with expected type `1 -> ?a` -//│ ║ l.121: f(1) -//│ ╙── ^ -//│ error -//│ res -//│ Runtime error: -//│ TypeError: f is not a function - - -new Foo(2) -//│ Foo -//│ res -//│ = Foo {} - -// new Foo("2") - -:e -new Foo() -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.145: new Foo() -//│ ║ ^^^^^^^^^ -//│ ╟── argument list of type `[]` does not match type `[x: Int]` -//│ ║ l.145: new Foo() -//│ ╙── ^^ -//│ Foo | error -//│ res -//│ = Foo {} - - -// :dp -new Foo(1).y -//│ 2 -//│ res -//│ = 2 - - - - - - From 4909975cf1d8f1a8e145f04b89f75266f882a821 Mon Sep 17 00:00:00 2001 From: Fa1sePRoMiSe Date: Thu, 30 Nov 2023 20:27:14 +0800 Subject: [PATCH 487/498] Fix codegen error for global functions (#186) --- .../src/main/scala/mlscript/JSBackend.scala | 20 +++--- .../diff/codegen/AuxiliaryConstructors.mls | 8 +-- .../src/test/diff/codegen/ConstructorStmt.mls | 10 +-- shared/src/test/diff/codegen/Modules.mls | 63 +++++++++++++++++-- shared/src/test/diff/codegen/Nested.mls | 36 +++++------ shared/src/test/diff/codegen/New.mls | 4 +- shared/src/test/diff/codegen/NewMatching.mls | 2 +- shared/src/test/diff/codegen/NuReplHost.mls | 4 +- shared/src/test/diff/codegen/SymbolicOps.mls | 10 +-- shared/src/test/diff/mlscript/Sequence.mls | 2 +- shared/src/test/diff/nu/FlatIndentFuns.mls | 4 +- shared/src/test/diff/nu/FlatMonads_repro.mls | 2 +- shared/src/test/diff/nu/HeungTung.mls | 2 +- shared/src/test/diff/nu/LamPatterns.mls | 4 +- shared/src/test/diff/nu/LetRec.mls | 13 ++-- shared/src/test/diff/nu/LocalLets.mls | 2 +- shared/src/test/diff/nu/MIscPoly.mls | 2 +- shared/src/test/diff/nu/Misc.mls | 14 ++--- shared/src/test/diff/nu/NamedArgs.mls | 10 +-- shared/src/test/diff/nu/NestedRecords.mls | 2 +- shared/src/test/diff/nu/NewNew.mls | 2 +- shared/src/test/diff/nu/Refinements.mls | 32 +++++----- shared/src/test/diff/nu/Res.mls | 2 +- shared/src/test/diff/nu/Vals.mls | 9 +-- 24 files changed, 156 insertions(+), 103 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 7057e76993..9c8b3d34fd 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -1401,6 +1401,16 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case _ => die } + otherStmts.foreach { + case fd @ NuFunDef(isLetRec, Var(nme), symNme, _, L(body)) => + val isByname = isLetRec.isEmpty + val isByvalueRecIn = if (isByname) None else Some(true) + val bodyIsLam = body match { case _: Lam => true case _ => false } + val symb = symNme.map(_.name) + scope.declareValue(nme, isByvalueRecIn, bodyIsLam, symb) + case _ => () + } + // don't pass `otherStmts` to the top-level module, because we need to execute them one by one later val topModule = topLevelScope.declareTopModule("TypingUnit", Nil, typeDefs, true) val moduleIns = topLevelScope.declareValue("typing_unit", Some(false), false, N) @@ -1416,16 +1426,6 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { (zeroWidthSpace + JSIdent("e") + zeroWidthSpace).log() :: Nil ) - otherStmts.foreach { - case fd @ NuFunDef(isLetRec, Var(nme), symNme, _, L(body)) if isLetRec.getOrElse(true) => - val isByname = isLetRec.isEmpty - val isByvalueRecIn = if (isByname) None else Some(true) - val bodyIsLam = body match { case _: Lam => true case _ => false } - val symb = symNme.map(_.name) - scope.declareValue(nme, isByvalueRecIn, bodyIsLam, symb) - case _ => () - } - // TODO Improve: (Lionel) I find this logic very strange! What's going on here? // Why are we declaring some things above AND below? // Why does the fact that a binding is recursive affect its declaration in the OUTER scope? diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls index 3fd393ed25..5c729795cb 100644 --- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -464,11 +464,11 @@ n.ll //│ class TypingUnit19 {} //│ const typing_unit19 = new TypingUnit19; //│ // Query 1 -//│ globalThis.m = g(1); +//│ globalThis.m1 = g(1); //│ // Query 2 -//│ globalThis.n = m(2); +//│ globalThis.n1 = m1(2); //│ // Query 3 -//│ res = n.ll; +//│ res = n1.ll; //│ // End of generated code //│ m //│ = [Function (anonymous)] @@ -487,7 +487,7 @@ let mm = new M() //│ class TypingUnit21 {} //│ const typing_unit21 = new TypingUnit21; //│ // Query 1 -//│ globalThis.mm = new M.class(); +//│ globalThis.mm1 = new M.class(); //│ // End of generated code //│ mm //│ = M {} diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index a61301347e..4f769b8f32 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -105,7 +105,7 @@ let aa = A(42) //│ class TypingUnit5 {} //│ const typing_unit5 = new TypingUnit5; //│ // Query 1 -//│ globalThis.aa = A(42); +//│ globalThis.aa1 = A(42); //│ // End of generated code //│ aa //│ = A {} @@ -119,7 +119,7 @@ aa //│ class TypingUnit6 {} //│ const typing_unit6 = new TypingUnit6; //│ // Query 1 -//│ res = aa; +//│ res = aa1; //│ // End of generated code //│ res //│ = A {} @@ -131,7 +131,7 @@ let ab = A(0) //│ class TypingUnit7 {} //│ const typing_unit7 = new TypingUnit7; //│ // Query 1 -//│ globalThis.ab = A(0); +//│ globalThis.ab1 = A(0); //│ // End of generated code //│ ab //│ = A {} @@ -408,9 +408,9 @@ www.add(42) //│ class TypingUnit15 {} //│ const typing_unit15 = new TypingUnit15; //│ // Query 1 -//│ globalThis.www = W(); +//│ globalThis.www1 = W(); //│ // Query 2 -//│ res = www.add(42); +//│ res = www1.add(42); //│ // End of generated code //│ www //│ = W {} diff --git a/shared/src/test/diff/codegen/Modules.mls b/shared/src/test/diff/codegen/Modules.mls index 884d2a7927..82d6fa856c 100644 --- a/shared/src/test/diff/codegen/Modules.mls +++ b/shared/src/test/diff/codegen/Modules.mls @@ -9,7 +9,6 @@ module test { // hello //│ } -:ge // * FIXME :js fun y = 1 module Foo { @@ -19,10 +18,36 @@ module Foo { //│ module Foo { //│ fun x: 1 //│ } -//│ Code generation encountered an error: -//│ unresolved symbol y +//│ // Prelude +//│ class TypingUnit1 { +//│ #Foo; +//│ constructor() { +//│ } +//│ get Foo() { +//│ const qualifier = this; +//│ if (this.#Foo === undefined) { +//│ class Foo { +//│ constructor() { +//│ } +//│ get x() { +//│ return y(); +//│ } +//│ } +//│ this.#Foo = new Foo(); +//│ this.#Foo.class = Foo; +//│ } +//│ return this.#Foo; +//│ } +//│ } +//│ const typing_unit1 = new TypingUnit1; +//│ globalThis.Foo = typing_unit1.Foo; +//│ // Query 1 +//│ globalThis.y = function y() { +//│ return 1; +//│ }; +//│ // End of generated code + -:ge // * FIXME :js module Foo { fun x = y @@ -32,7 +57,33 @@ fun y = 1 //│ fun x: 1 //│ } //│ fun y: 1 -//│ Code generation encountered an error: -//│ unresolved symbol y +//│ // Prelude +//│ class TypingUnit2 { +//│ #Foo; +//│ constructor() { +//│ } +//│ get Foo() { +//│ const qualifier = this; +//│ if (this.#Foo === undefined) { +//│ class Foo { +//│ constructor() { +//│ } +//│ get x() { +//│ return y1(); +//│ } +//│ } +//│ this.#Foo = new Foo(); +//│ this.#Foo.class = Foo; +//│ } +//│ return this.#Foo; +//│ } +//│ } +//│ const typing_unit2 = new TypingUnit2; +//│ globalThis.Foo = typing_unit2.Foo; +//│ // Query 1 +//│ globalThis.y1 = function y1() { +//│ return 1; +//│ }; +//│ // End of generated code diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 10843c74aa..227d0c7a2d 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -78,9 +78,9 @@ bb.b //│ class TypingUnit1 {} //│ const typing_unit1 = new TypingUnit1; //│ // Query 1 -//│ globalThis.bb = A.B(A.a); +//│ globalThis.bb1 = A.B(A.a); //│ // Query 2 -//│ res = bb.b; +//│ res = bb1.b; //│ // End of generated code //│ bb //│ = B {} @@ -241,9 +241,9 @@ ee.x //│ class TypingUnit5 {} //│ const typing_unit5 = new TypingUnit5; //│ // Query 1 -//│ globalThis.ee = D.createE(42); +//│ globalThis.ee1 = D.createE(42); //│ // Query 2 -//│ res = ee.x; +//│ res = ee1.x; //│ // End of generated code //│ ee //│ = E {} @@ -361,13 +361,13 @@ gg.sum //│ class TypingUnit7 {} //│ const typing_unit7 = new TypingUnit7; //│ // Query 1 -//│ globalThis.es = E(1); +//│ globalThis.es1 = E(1); //│ // Query 2 -//│ globalThis.fff = es.F(2); +//│ globalThis.fff1 = es1.F(2); //│ // Query 3 -//│ globalThis.gg = fff.G(3); +//│ globalThis.gg1 = fff1.G(3); //│ // Query 4 -//│ res = gg.sum; +//│ res = gg1.sum; //│ // End of generated code //│ es //│ = E {} @@ -559,11 +559,11 @@ i.x //│ class TypingUnit10 {} //│ const typing_unit10 = new TypingUnit10; //│ // Query 1 -//│ globalThis.jj = G.H.J(42); +//│ globalThis.jj1 = G.H.J(42); //│ // Query 2 -//│ globalThis.i = jj.ii(2); +//│ globalThis.i1 = jj1.ii(2); //│ // Query 3 -//│ res = i.x; +//│ res = i1.x; //│ // End of generated code //│ jj //│ = J {} @@ -666,9 +666,9 @@ j.i.x //│ class TypingUnit12 {} //│ const typing_unit12 = new TypingUnit12; //│ // Query 1 -//│ globalThis.j = H.J(42); +//│ globalThis.j1 = H.J(42); //│ // Query 2 -//│ res = j.i.x; +//│ res = j1.i.x; //│ // End of generated code //│ j //│ = J {} @@ -757,11 +757,11 @@ ij.incY //│ const typing_unit13 = new TypingUnit13; //│ globalThis.I = typing_unit13.I; //│ // Query 1 -//│ globalThis.i1 = I(1); +//│ globalThis.i3 = I(1); //│ // Query 2 -//│ globalThis.ij = i1.J(0); +//│ globalThis.ij1 = i3.J(0); //│ // Query 3 -//│ res = ij.incY; +//│ res = ij1.incY; //│ // End of generated code //│ i //│ = I {} @@ -890,9 +890,9 @@ let n = J.N(2) //│ class TypingUnit15 {} //│ const typing_unit15 = new TypingUnit15; //│ // Query 1 -//│ globalThis.m = J.M(); +//│ globalThis.m1 = J.M(); //│ // Query 2 -//│ globalThis.n = J.N(2); +//│ globalThis.n1 = J.N(2); //│ // End of generated code //│ m //│ = M {} diff --git a/shared/src/test/diff/codegen/New.mls b/shared/src/test/diff/codegen/New.mls index 9909f20df2..8636a83c8b 100644 --- a/shared/src/test/diff/codegen/New.mls +++ b/shared/src/test/diff/codegen/New.mls @@ -46,7 +46,7 @@ let c = C //│ class TypingUnit3 {} //│ const typing_unit3 = new TypingUnit3; //│ // Query 1 -//│ globalThis.c = C; +//│ globalThis.c1 = C; //│ // End of generated code //│ c //│ = [class C] @@ -93,7 +93,7 @@ let c = C //│ class TypingUnit8 {} //│ const typing_unit8 = new TypingUnit8; //│ // Query 1 -//│ globalThis.c1 = C; +//│ globalThis.c3 = C; //│ // End of generated code //│ c //│ = [Function (anonymous)] { diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index 50d2dbc1da..acdef0ef4a 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -136,7 +136,7 @@ fun foo(s) = //│ // Query 1 //│ globalThis.foo = function foo(s) { //│ return ((() => { -//│ return s instanceof Some.class ? (([t]) => ((b) => b + t.x)(s2.value))(Some.unapply(s)) : 0; +//│ return s instanceof Some.class ? (([t]) => ((b) => b + t.x)(s21.value))(Some.unapply(s)) : 0; //│ })()); //│ }; //│ // End of generated code diff --git a/shared/src/test/diff/codegen/NuReplHost.mls b/shared/src/test/diff/codegen/NuReplHost.mls index d4805d1c82..c5aaf4563f 100644 --- a/shared/src/test/diff/codegen/NuReplHost.mls +++ b/shared/src/test/diff/codegen/NuReplHost.mls @@ -33,7 +33,7 @@ let r = foo(1) //│ └─┬ Query 2/2 //│ ├── Prelude: //│ ├── Code: -//│ ├── globalThis.r = foo(1); +//│ ├── globalThis.r1 = foo(1); //│ └── Reply: [runtime error] Error: an error was thrown //│ r //│ Runtime error: @@ -44,7 +44,7 @@ r //│ nothing //│ res //│ Runtime error: -//│ ReferenceError: r is not defined +//│ ReferenceError: r1 is not defined diff --git a/shared/src/test/diff/codegen/SymbolicOps.mls b/shared/src/test/diff/codegen/SymbolicOps.mls index 9dd61cb78a..37e42ce6a0 100644 --- a/shared/src/test/diff/codegen/SymbolicOps.mls +++ b/shared/src/test/diff/codegen/SymbolicOps.mls @@ -14,7 +14,7 @@ let r = succ >> succ //│ class TypingUnit1 {} //│ const typing_unit1 = new TypingUnit1; //│ // Query 1 -//│ globalThis.r = compose(succ, succ); +//│ globalThis.r1 = compose(succ, succ); //│ // End of generated code //│ r //│ = [Function (anonymous)] @@ -65,7 +65,7 @@ let f = (>>) //│ class TypingUnit7 {} //│ const typing_unit7 = new TypingUnit7; //│ // Query 1 -//│ globalThis.f = compose; +//│ globalThis.f1 = compose; //│ // End of generated code //│ f //│ = [Function: compose] @@ -315,7 +315,7 @@ fun (:-D) dd(a, b) = a + b val (->) f(x, y) = [x, y] //│ val (->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] //│ f -//│ = [Function: f1] +//│ = [Function: f3] 12 -> 34 //│ [12, 34] @@ -326,7 +326,7 @@ val (->) f(x, y) = [x, y] let (->) _ = f //│ let (->) _: forall 'a 'b. ('a, 'b) -> ['a, 'b] //│ _ -//│ = [Function: f1] +//│ = [Function: f3] :js 12 -> 34 @@ -335,7 +335,7 @@ let (->) _ = f //│ class TypingUnit42 {} //│ const typing_unit42 = new TypingUnit42; //│ // Query 1 -//│ res = _(12, 34); +//│ res = _1(12, 34); //│ // End of generated code //│ res //│ = [ 12, 34 ] diff --git a/shared/src/test/diff/mlscript/Sequence.mls b/shared/src/test/diff/mlscript/Sequence.mls index 919c7251b1..6c52dff4ca 100644 --- a/shared/src/test/diff/mlscript/Sequence.mls +++ b/shared/src/test/diff/mlscript/Sequence.mls @@ -4,7 +4,7 @@ let test(x) = log(x); x + 1 //│ let test: Int -> Int //│ test -//│ = [Function: test] +//│ = [Function: test1] test(log("here we go"); 123) //│ Int diff --git a/shared/src/test/diff/nu/FlatIndentFuns.mls b/shared/src/test/diff/nu/FlatIndentFuns.mls index 3a58afdd03..77ace9e704 100644 --- a/shared/src/test/diff/nu/FlatIndentFuns.mls +++ b/shared/src/test/diff/nu/FlatIndentFuns.mls @@ -20,7 +20,7 @@ y => x + y //│ let r: Int -> Int -> Int //│ r -//│ = [Function: r] +//│ = [Function: r1] r(1)(2) //│ Int @@ -59,6 +59,6 @@ x + y //│ ╙── //│ let r: Int -> Int -> Int //│ r -//│ = [Function: r1] +//│ = [Function: r3] diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls index 938516f499..1fe5bef9a8 100644 --- a/shared/src/test/diff/nu/FlatMonads_repro.mls +++ b/shared/src/test/diff/nu/FlatMonads_repro.mls @@ -48,7 +48,7 @@ let ri(f) = Bind(Pure(42), f) //│ where //│ 'CC :> 42 //│ ri -//│ = [Function: ri] +//│ = [Function: ri1] ri(Pure) //│ Bind['CC, 'AA] diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 091301565c..264a541703 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -202,7 +202,7 @@ type Res = M(T) let f = x => [x, x] //│ let f: forall 'a. 'a -> ['a, 'a] //│ f -//│ = [Function: f2] +//│ = [Function: f3] [f(1), f(true)] //│ [[1, 1], [true, true]] diff --git a/shared/src/test/diff/nu/LamPatterns.mls b/shared/src/test/diff/nu/LamPatterns.mls index 58aa85eb8e..cb78cf3498 100644 --- a/shared/src/test/diff/nu/LamPatterns.mls +++ b/shared/src/test/diff/nu/LamPatterns.mls @@ -24,12 +24,12 @@ let f = Some => 0 //│ class TypingUnit2 {} //│ const typing_unit2 = new TypingUnit2; //│ // Query 1 -//│ globalThis.f = function f(Some) { +//│ globalThis.f1 = function f1(Some) { //│ return 0; //│ }; //│ // End of generated code //│ f -//│ = [Function: f] +//│ = [Function: f1] // :e // TODO f(Some) diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index c5e80d7775..74f8a3f58c 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -147,7 +147,7 @@ let rec f = let foo = foo //│ let foo: nothing //│ Code generation encountered an error: -//│ unresolved symbol foo +//│ unguarded recursive use of by-value binding foo // FIXME should work @@ -165,15 +165,14 @@ let foo = foo + 1 // FIXME let foo = foo.x //│ let foo: nothing -//│ foo -//│ = undefined +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding foo // :e // FIXME -:re +:ge foo()() //│ nothing -//│ res -//│ Runtime error: -//│ TypeError: foo2 is not a function +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding foo diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index 211987ae06..15717f5ded 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -32,6 +32,6 @@ let E(x) = new E(1) //│ ╙── ^ //│ let E: anything -> error //│ E -//│ = [Function: E1] +//│ = [Function: E2] diff --git a/shared/src/test/diff/nu/MIscPoly.mls b/shared/src/test/diff/nu/MIscPoly.mls index 3d9c94a5af..34235988a1 100644 --- a/shared/src/test/diff/nu/MIscPoly.mls +++ b/shared/src/test/diff/nu/MIscPoly.mls @@ -69,7 +69,7 @@ r() //│ nothing //│ res //│ Runtime error: -//│ TypeError: r is not a function +//│ TypeError: r1 is not a function diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index 821a12d2c7..a0aa87e20c 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -65,7 +65,7 @@ f of [1, 2] let f = (x, y) => x + y //│ let f: (Int, Int) -> Int //│ f -//│ = [Function: f4] +//│ = [Function: f5] f(1, 2) //│ Int @@ -96,7 +96,7 @@ let f = ((x, y)) => x + y //│ ╙── ^^^^^^ //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f5] +//│ = [Function: f7] :e f(1, 2) @@ -132,7 +132,7 @@ f[1, 2] //│ ╙── ^^^^^^^ //│ ([Int, Int]) -> Int //│ res -//│ = [Function: f5] +//│ = [Function: f7] :pe @@ -142,14 +142,14 @@ let f = (((x, y))) => x + y //│ ╙── ^^^^^^ //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f6] +//│ = [Function: f9] // * TODO maybe parse as type lambda? let f = [x, y] => x + y //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f7] +//│ = [Function: f11] :e f(1, 2) @@ -173,7 +173,7 @@ f([1, 2]) let f = ([x, y]) => x + y //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f8] +//│ = [Function: f13] f([1, 2]) //│ Int @@ -197,7 +197,7 @@ f(1, 2) let f = [[[x, y]]] => x + y //│ let f: ([[[Int, Int]]]) -> Int //│ f -//│ = [Function: f9] +//│ = [Function: f15] :e f([[1, 2]]) diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index 8c4d4606f1..c846ee548b 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -116,9 +116,9 @@ test(0, y: 200) //│ class TypingUnit13 {} //│ const typing_unit13 = new TypingUnit13; //│ // Query 1 -//│ globalThis.tmp = 2; +//│ globalThis.tmp1 = 2; //│ // Query 2 -//│ res = test1(0, tmp); +//│ res = test1(0, tmp1); //│ // Query 3 //│ res = test1(0, 200); //│ // End of generated code @@ -171,11 +171,11 @@ fff(y: 2, z: y_1 + 1, x: z_1 - 2) //│ class TypingUnit17 {} //│ const typing_unit17 = new TypingUnit17; //│ // Query 1 -//│ globalThis["y_1"] = 2; +//│ globalThis["y_11"] = 2; //│ // Query 2 -//│ globalThis["z_1"] = 3; +//│ globalThis["z_11"] = 3; //│ // Query 3 -//│ res = ((z_2) => ((x_1) => fff(x_1, 2, z_2))(z_1 - 2))(y_1 + 1); +//│ res = ((z_2) => ((x_1) => fff(x_1, 2, z_2))(z_11 - 2))(y_11 + 1); //│ // End of generated code //│ y_1 //│ = 2 diff --git a/shared/src/test/diff/nu/NestedRecords.mls b/shared/src/test/diff/nu/NestedRecords.mls index ebe7bbcbd6..ca216f4788 100644 --- a/shared/src/test/diff/nu/NestedRecords.mls +++ b/shared/src/test/diff/nu/NestedRecords.mls @@ -4,7 +4,7 @@ let f(x) = [x, x] //│ let f: forall 'a. 'a -> ['a, 'a] //│ f -//│ = [Function: f] +//│ = [Function: f1] let a = { u: f(f(f(1))), v: f(f(f(1))) } //│ let a: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]} diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index c135ca38a9..8ab334a692 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -103,7 +103,7 @@ f(1) //│ error //│ res //│ Runtime error: -//│ TypeError: f4 is not a function +//│ TypeError: f9 is not a function :e new Foo("2") diff --git a/shared/src/test/diff/nu/Refinements.mls b/shared/src/test/diff/nu/Refinements.mls index 3aa89616d7..2311c3c10c 100644 --- a/shared/src/test/diff/nu/Refinements.mls +++ b/shared/src/test/diff/nu/Refinements.mls @@ -85,15 +85,17 @@ let r = new {} //│ Code generation encountered an error: //│ Unsupported `new` class term: Bra(rcd = true, Rcd()) +:ge r : Object //│ Object -//│ res -//│ = {} +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding r +:ge r with { x: 1 } //│ error & {x: 1} -//│ res -//│ = { x: 1 } +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding r let r = { x: 0 } @@ -104,16 +106,16 @@ let r = { x: 0 } :e r : Object //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.105: r : Object +//│ ║ l.107: r : Object //│ ║ ^ //│ ╟── record literal of type `{x: 0}` is not an instance of type `Object` -//│ ║ l.99: let r = { x: 0 } -//│ ║ ^ +//│ ║ l.101: let r = { x: 0 } +//│ ║ ^ //│ ╟── but it flows into reference with expected type `Object` -//│ ║ l.105: r : Object +//│ ║ l.107: r : Object //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.105: r : Object +//│ ║ l.107: r : Object //│ ╙── ^^^^^^ //│ Object //│ res @@ -138,16 +140,16 @@ o : {} :e o : Object //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.139: o : Object +//│ ║ l.141: o : Object //│ ║ ^ //│ ╟── type `anything` is not an instance of type `Object` -//│ ║ l.132: fun o : {} +//│ ║ l.134: fun o : {} //│ ║ ^^ //│ ╟── but it flows into reference with expected type `Object` -//│ ║ l.139: o : Object +//│ ║ l.141: o : Object //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.139: o : Object +//│ ║ l.141: o : Object //│ ╙── ^^^^^^ //│ Object @@ -169,10 +171,10 @@ o : Object :e let d = D & { f: 0 } //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.170: let d = D & { f: 0 } +//│ ║ l.172: let d = D & { f: 0 } //│ ╙── ^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.170: let d = D & { f: 0 } +//│ ║ l.172: let d = D & { f: 0 } //│ ╙── ^ //│ let d: error diff --git a/shared/src/test/diff/nu/Res.mls b/shared/src/test/diff/nu/Res.mls index 0f7f660b69..e8936ec349 100644 --- a/shared/src/test/diff/nu/Res.mls +++ b/shared/src/test/diff/nu/Res.mls @@ -19,7 +19,7 @@ res(1) let res = x => x + 2 //│ let res: Int -> Int //│ res -//│ = [Function: res1] +//│ = [Function: res2] res(1) //│ Int diff --git a/shared/src/test/diff/nu/Vals.mls b/shared/src/test/diff/nu/Vals.mls index 5a5a62a811..e90080f1b9 100644 --- a/shared/src/test/diff/nu/Vals.mls +++ b/shared/src/test/diff/nu/Vals.mls @@ -18,20 +18,21 @@ val d = 1 //│ val c: Int //│ val d: 1 //│ Code generation encountered an error: -//│ unresolved symbol d +//│ unguarded recursive use of by-value binding d // :e // FIXME should not type check +:ge val a = a //│ val a: nothing -//│ a -//│ = 1 +//│ Code generation encountered an error: +//│ unguarded recursive use of by-value binding a val f(x) = x //│ val f: forall 'a. 'a -> 'a //│ f -//│ = [Function: f] +//│ = [Function: f1] f(123) //│ 123 From b11b9cb0918e5dacaba2d02f1419b5f31df09270 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Sat, 2 Dec 2023 14:07:21 +0800 Subject: [PATCH 488/498] Add a potentially buggy test case --- shared/src/test/diff/nu/OptionFilter.mls | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 shared/src/test/diff/nu/OptionFilter.mls diff --git a/shared/src/test/diff/nu/OptionFilter.mls b/shared/src/test/diff/nu/OptionFilter.mls new file mode 100644 index 0000000000..afe5f8c64c --- /dev/null +++ b/shared/src/test/diff/nu/OptionFilter.mls @@ -0,0 +1,27 @@ +:NewDefs + +// FIXME: this looks like a bug about mutually-referential definitions +abstract class Option[out T]: (Some[T] | None) { + virtual fun filter: (p: T -> Bool) -> Option[T] +} +class Some[out T](val value: T) extends Option[T] { + fun filter(p) = if p of value then Some(value) else None +} +module None extends Option[nothing] { + fun filter(_) = None +} +//│ ╔══[ERROR] Type `#Some & {Some#T <: ?T}` does not contain member `Option#T` +//│ ║ l.4: abstract class Option[out T]: (Some[T] | None) { +//│ ╙── ^ +//│ ╔══[ERROR] Type `#None` does not contain member `Option#T` +//│ ║ l.4: abstract class Option[out T]: (Some[T] | None) { +//│ ╙── ^ +//│ abstract class Option[T]: None | Some[T] { +//│ fun filter: (p: T -> Bool) -> Option[T] +//│ } +//│ class Some[T](value: T) extends Option { +//│ fun filter: (T -> Object) -> (None | Some[T]) +//│ } +//│ module None extends Option { +//│ fun filter: anything -> None +//│ } From 231d9ec5106db29f45b4be86cae514d55ce07995 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 6 Dec 2023 12:48:40 +0800 Subject: [PATCH 489/498] Update SBT version --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 22af2628c4..e8a1e246e8 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.7.1 +sbt.version=1.9.7 From f121cd035f50b95a6d0dfd507c534a35017da41b Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Mon, 1 Jan 2024 22:57:34 +0800 Subject: [PATCH 490/498] Support integer literals of different radices and decimal numeric literals (#199) * Support hex, octal, and binary integers * Support seperators in integer literals * Support decimal numbers --- shared/src/main/scala/mlscript/NewLexer.scala | 104 ++++++++++++- shared/src/test/diff/nu/DecLit.mls | 139 ++++++++++++++++++ shared/src/test/diff/nu/IntLit.mls | 139 ++++++++++++++++++ 3 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 shared/src/test/diff/nu/DecLit.mls create mode 100644 shared/src/test/diff/nu/IntLit.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index f5ac326297..4985c2fcea 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -23,6 +23,12 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { c.isLetter || c === '_' || c === '\'' def isIdentChar(c: Char): Bool = isIdentFirstChar(c) || isDigit(c) || c === '\'' + def isHexDigit(c: Char): Bool = + isDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') + def isOctDigit(c: Char): Bool = + c >= '0' && c <= '7' + def isBinDigit(c: Char): Bool = + c === '0' || c === '1' def isDigit(c: Char): Bool = c >= '0' && c <= '9' @@ -59,15 +65,109 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { if (i < length && pred(bytes(i))) takeWhile(i + 1, bytes(i) :: cur)(pred) else (cur.reverseIterator.mkString, i) + final def num(i: Int): (Lit, Int) = { + def test(i: Int, p: Char => Bool): Bool = i < length && p(bytes(i)) + def zero: IntLit = IntLit(BigInt(0)) + /** Take a sequence of digits interleaved with underscores. */ + def takeDigits(i: Int, pred: Char => Bool): (Opt[Str], Int) = { + @tailrec def rec(i: Int, acc: Ls[Char], firstSep: Bool, lastSep: Bool): (Str, Bool, Bool, Int) = + if (i < length) { + val c = bytes(i) + if (pred(c)) rec(i + 1, c :: acc, firstSep, false) + else if (c === '_') rec(i + 1, acc, acc.isEmpty, true) + else (acc.reverseIterator.mkString, firstSep, lastSep, i) + } + else (acc.reverseIterator.mkString, firstSep, lastSep, i) + val (str, firstSep, lastSep, j) = rec(i, Nil, false, false) + if (firstSep) + raise(WarningReport( + msg"Leading separator is not allowed" -> S(loc(i - 1, i)) :: Nil, + newDefs = true, source = Lexing)) + if (lastSep) + raise(WarningReport( + msg"Trailing separator is not allowed" -> S(loc(j - 1, j)) :: Nil, + newDefs = true, source = Lexing)) + (if (str.isEmpty) N else S(str), j) + } + /** Take an integer and coverts to `BigInt`. Also checks if it is empty. */ + def integer(i: Int, radix: Int, desc: Str, pred: Char => Bool): (IntLit, Int) = { + takeDigits(i, pred) match { + case (N, j) => + raise(ErrorReport(msg"Expect at least one $desc digit" -> S(loc(i, i + 2)) :: Nil, + newDefs = true, source = Lexing)) + (zero, j) + case (S(str), j) => (IntLit(BigInt(str, radix)), j) + } + } + def isDecimalStart(ch: Char) = ch === '.' || ch === 'e' || ch === 'E' + /** Take a fraction part with an optional exponent part. Call at periods. */ + def decimal(i: Int, integral: Str): (DecLit, Int) = { + val (fraction, j) = if (test(i, _ === '.')) { + takeDigits(i + 1, isDigit) match { + case (N, j) => + raise(ErrorReport(msg"Expect at least one digit after the decimal point" -> S(loc(i + 1, i + 2)) :: Nil, + newDefs = true, source = Lexing)) + ("", j) + case (S(digits), j) => ("." + digits, j) + } + } else ("", i) + val (exponent, k) = if (test(j, ch => ch === 'e' || ch === 'E')) { + val (sign, k) = if (test(j + 1, ch => ch === '+' || ch === '-')) { + (bytes(j + 1), j + 2) + } else { + ('+', j + 1) + } + takeDigits(k, isDigit) match { + case (N, l) => + raise(ErrorReport(msg"Expect at least one digit after the exponent sign" -> S(loc(l - 1, l)) :: Nil, + newDefs = true, source = Lexing)) + ("", l) + case (S(digits), l) => ("E" + sign + digits, l) + } + } else { + ("", j) + } + (DecLit(BigDecimal(integral + fraction + exponent)), k) + } + if (i < length) { + bytes(i) match { + case '0' if i + 1 < length => bytes(i + 1) match { + case 'x' => integer(i + 2, 16, "hexadecimal", isHexDigit) + case 'o' => integer(i + 2, 8, "octal", isOctDigit) + case 'b' => integer(i + 2, 2, "binary", isBinDigit) + case '.' | 'E' | 'e' => decimal(i + 1, "0") + case _ => integer(i, 10, "decimal", isDigit) + } + case '0' => (zero, i + 1) + case _ => takeDigits(i, isDigit) match { + case (N, j) => + raise(ErrorReport(msg"Expect a numeric literal" -> S(loc(i, i + 1)) :: Nil, + newDefs = true, source = Lexing)) + (zero, i) + case (S(integral), j) => + if (j < length && isDecimalStart(bytes(j))) decimal(j, integral) + else (IntLit(BigInt(integral)), j) + } + } + } else { + raise(ErrorReport(msg"Expect a numeric literal instead of end of input" -> S(loc(i, i + 1)) :: Nil, + newDefs = true, source = Lexing)) + (zero, i) + } + } + @tailrec final def str(i: Int, escapeMode: Bool, cur: Ls[Char] = Nil): (Str, Int) = if (escapeMode) if (i < length) bytes(i) match { + case '\\' => str(i + 1, false, '\\' :: cur) case '"' => str(i + 1, false, '"' :: cur) case 'n' => str(i + 1, false, '\n' :: cur) case 't' => str(i + 1, false, '\t' :: cur) case 'r' => str(i + 1, false, '\r' :: cur) + case 'b' => str(i + 1, false, '\b' :: cur) + case 'f' => str(i + 1, false, '\f' :: cur) case ch => raise(WarningReport(msg"Found invalid escape character" -> S(loc(i, i + 1)) :: Nil, newDefs = true, source = Lexing)) @@ -190,9 +290,9 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) case _ if isDigit(c) => - val (str, j) = takeWhile(i)(isDigit) + val (lit, j) = num(i) // go(j, LITVAL(IntLit(BigInt(str)))) - lex(j, ind, next(j, LITVAL(IntLit(BigInt(str))))) + lex(j, ind, next(j, LITVAL(lit))) case _ => pe(msg"unexpected character '${escapeChar(c)}'") // go(i + 1, ERROR) diff --git a/shared/src/test/diff/nu/DecLit.mls b/shared/src/test/diff/nu/DecLit.mls new file mode 100644 index 0000000000..1714d7b7d3 --- /dev/null +++ b/shared/src/test/diff/nu/DecLit.mls @@ -0,0 +1,139 @@ +:NewDefs + +// Real Numbers +// ============ + +[0.5, 1.0, 3.14159] +//│ [0.5, 1.0, 3.14159] +//│ res +//│ = [ 0.5, 1, 3.14159 ] + +[1e100, 1E100, 1e+100, 1E+100, 1E-11, 1e-10, 1E-2, 1e-2] +//│ [1E+100, 1E+100, 1E+100, 1E+100, 1E-11, 1E-10, 0.01, 0.01] +//│ res +//│ = [ +//│ 1e+100, 1e+100, +//│ 1e+100, 1e+100, +//│ 1e-11, 1e-10, +//│ 0.01, 0.01 +//│ ] + +[3.14e-10, 3.14E-10, 3.14e+10, 3.14E+10] +//│ [3.14E-10, 3.14E-10, 3.14E+10, 3.14E+10] +//│ res +//│ = [ 3.14e-10, 3.14e-10, 31400000000, 31400000000 ] + +[0.5e-10, 0.5E-10, 0.5e+10, 0.5E+10] +//│ [5E-11, 5E-11, 5E+9, 5E+9] +//│ res +//│ = [ 5e-11, 5e-11, 5000000000, 5000000000 ] + +// Separators in integral, fractional, and exponent parts. +[12_34_56.0, 12_34_56.78_90] +[1_2.3_4e-1_0, 1_2.3_4e+1_0, 1_2.3_4e1_0] +[1_2.3_4E-1_0, 1_2.3_4E+1_0, 1_2.3_4E1_0] +//│ [1.234E-9, 1.234E+11, 1.234E+11] +//│ res +//│ = [ 123456, 123456.789 ] +//│ res +//│ = [ 1.234e-9, 123400000000, 123400000000 ] +//│ res +//│ = [ 1.234e-9, 123400000000, 123400000000 ] + +// Conflict with tuple index selection. +:pe +.1 +//│ ╔══[PARSE ERROR] Unexpected selector in expression position +//│ ║ l.45: .1 +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.45: .1 +//│ ╙── ^ +//│ () +//│ res +//│ = undefined + +// Corner cases. +:pe +0.E10 +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the decimal point +//│ ║ l.58: 0.E10 +//│ ╙── ^ +//│ 0E+10 +//│ res +//│ = 0 + +:pe +0.0E +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the exponent sign +//│ ║ l.67: 0.0E +//│ ╙── ^ +//│ 0.0 +//│ res +//│ = 0 + +:pe +0.0E+ +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the exponent sign +//│ ║ l.76: 0.0E+ +//│ ╙── ^ +//│ 0.0 +//│ res +//│ = 0 + +:pe +0E +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the exponent sign +//│ ║ l.85: 0E +//│ ╙── ^ +//│ 0 +//│ res +//│ = 0 + +:pe +0E+ +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the exponent sign +//│ ║ l.94: 0E+ +//│ ╙── ^ +//│ 0 +//│ res +//│ = 0 + +:pe +1234E +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the exponent sign +//│ ║ l.103: 1234E +//│ ╙── ^ +//│ 1234 +//│ res +//│ = 1234 + +:pe +4378. +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the decimal point +//│ ║ l.112: 4378. +//│ ╙── ^ +//│ 4378 +//│ res +//│ = 4378 + +:pe +5. +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the decimal point +//│ ║ l.121: 5. +//│ ╙── ^ +//│ 5 +//│ res +//│ = 5 + +:pe +789.E +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the decimal point +//│ ║ l.130: 789.E +//│ ╙── ^ +//│ ╔══[LEXICAL ERROR] Expect at least one digit after the exponent sign +//│ ║ l.130: 789.E +//│ ╙── ^ +//│ 789 +//│ res +//│ = 789 diff --git a/shared/src/test/diff/nu/IntLit.mls b/shared/src/test/diff/nu/IntLit.mls new file mode 100644 index 0000000000..b140609aaf --- /dev/null +++ b/shared/src/test/diff/nu/IntLit.mls @@ -0,0 +1,139 @@ +:NewDefs + +// Decimal literals. +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +[-0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10] +//│ [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10] +//│ res +//│ = [ +//│ 0, 1, 2, 3, 4, +//│ 5, 6, 7, 8, 9, +//│ 10 +//│ ] +//│ res +//│ = [ +//│ 0, -1, -2, -3, -4, +//│ -5, -6, -7, -8, -9, +//│ -10 +//│ ] + +// Hexadecimal literals. +[0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A] +[-0x00, -0x01, -0x02, -0x03, -0x04, -0x05, -0x06, -0x07, -0x08, -0x09, -0x0A] +//│ [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10] +//│ res +//│ = [ +//│ 0, 1, 2, 3, 4, +//│ 5, 6, 7, 8, 9, +//│ 10 +//│ ] +//│ res +//│ = [ +//│ 0, -1, -2, -3, -4, +//│ -5, -6, -7, -8, -9, +//│ -10 +//│ ] + +// Octal literals. +[0o00, 0o01, 0o02, 0o03, 0o04, 0o05, 0o06, 0o07, 0o10, 0o11, 0o12] +[-0o00, -0o01, -0o02, -0o03, -0o04, -0o05, -0o06, -0o07, -0o10, -0o11, -0o12] +//│ [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10] +//│ res +//│ = [ +//│ 0, 1, 2, 3, 4, +//│ 5, 6, 7, 8, 9, +//│ 10 +//│ ] +//│ res +//│ = [ +//│ 0, -1, -2, -3, -4, +//│ -5, -6, -7, -8, -9, +//│ -10 +//│ ] + +// Binary literals. +[0b0000, 0b0001, 0b0010, 0b0011, 0b0100, 0b0101, 0b0110, 0b0111, 0b1000, 0b1001, 0b1010] +[-0b0, -0b1, -0b10, -0b11, -0b100, -0b101, -0b110, -0b111, -0b1000, -0b1001, -0b1010] +//│ [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10] +//│ res +//│ = [ +//│ 0, 1, 2, 3, 4, +//│ 5, 6, 7, 8, 9, +//│ 10 +//│ ] +//│ res +//│ = [ +//│ 0, -1, -2, -3, -4, +//│ -5, -6, -7, -8, -9, +//│ -10 +//│ ] + +:pe +0b +//│ ╔══[LEXICAL ERROR] Expect at least one binary digit +//│ ║ l.72: 0b +//│ ╙── ^^ +//│ 0 +//│ res +//│ = 0 + +:pe +0x +//│ ╔══[LEXICAL ERROR] Expect at least one hexadecimal digit +//│ ║ l.81: 0x +//│ ╙── ^^ +//│ 0 +//│ res +//│ = 0 + +:pe +0o +//│ ╔══[LEXICAL ERROR] Expect at least one octal digit +//│ ║ l.90: 0o +//│ ╙── ^^ +//│ 0 +//│ res +//│ = 0 + +// Underscores as separators in numeric literals. +1_000_000 +0xDEAD_CAFE +0b0010_0100_0011_0100 +//│ 9268 +//│ res +//│ = 1000000 +//│ res +//│ = 3735931646 +//│ res +//│ = 9268 + +// Trailing underscores are not allowed. +:w +0b00000000010_ +0xCAFE_____ +//│ ╔══[WARNING] Trailing separator is not allowed +//│ ║ l.112: 0b00000000010_ +//│ ╙── ^ +//│ ╔══[WARNING] Trailing separator is not allowed +//│ ║ l.113: 0xCAFE_____ +//│ ╙── ^ +//│ 51966 +//│ res +//│ = 2 +//│ res +//│ = 51966 + +// Extra leading zeros are discarded. +0123 +023456 +00 +0 +//│ 0 +//│ res +//│ = 123 +//│ res +//│ = 23456 +//│ res +//│ = 0 +//│ res +//│ = 0 From 0049da9600f44bc837caa1ed37942943f1c66964 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Tue, 2 Jan 2024 13:18:37 +0800 Subject: [PATCH 491/498] Fix name duplication in code generation for new definition typing (#197) --- .../src/main/scala/mlscript/JSBackend.scala | 2 +- .../main/scala/mlscript/codegen/Scope.scala | 30 +++- .../main/scala/mlscript/codegen/Symbol.scala | 28 ++- .../diff/codegen/AuxiliaryConstructors.mls | 8 +- .../src/test/diff/codegen/ConstructorStmt.mls | 10 +- shared/src/test/diff/codegen/Nested.mls | 36 ++-- shared/src/test/diff/codegen/New.mls | 4 +- shared/src/test/diff/codegen/NewMatching.mls | 2 +- shared/src/test/diff/codegen/NewMutualRef.mls | 166 ++++++++++++++++++ shared/src/test/diff/codegen/NuReplHost.mls | 4 +- shared/src/test/diff/codegen/SymbolicOps.mls | 10 +- shared/src/test/diff/mlscript/Sequence.mls | 2 +- shared/src/test/diff/nu/ArrayProg.mls | 2 +- shared/src/test/diff/nu/CtorSubtraction.mls | 4 +- shared/src/test/diff/nu/FlatIndentFuns.mls | 4 +- shared/src/test/diff/nu/FlatMonads_repro.mls | 2 +- shared/src/test/diff/nu/HeungTung.mls | 2 +- shared/src/test/diff/nu/LamPatterns.mls | 4 +- shared/src/test/diff/nu/LocalLets.mls | 2 +- shared/src/test/diff/nu/MIscPoly.mls | 2 +- shared/src/test/diff/nu/Misc.mls | 14 +- shared/src/test/diff/nu/NamedArgs.mls | 10 +- shared/src/test/diff/nu/NestedRecords.mls | 2 +- shared/src/test/diff/nu/NewNew.mls | 2 +- shared/src/test/diff/nu/Res.mls | 2 +- shared/src/test/diff/nu/Vals.mls | 2 +- 26 files changed, 279 insertions(+), 77 deletions(-) create mode 100644 shared/src/test/diff/codegen/NewMutualRef.mls diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index 9c8b3d34fd..ddca1a2799 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -1407,7 +1407,7 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { val isByvalueRecIn = if (isByname) None else Some(true) val bodyIsLam = body match { case _: Lam => true case _ => false } val symb = symNme.map(_.name) - scope.declareValue(nme, isByvalueRecIn, bodyIsLam, symb) + scope.declareValue(nme, isByvalueRecIn, bodyIsLam, symb, true) case _ => () } diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala index 80afdc3111..68c442ca87 100644 --- a/shared/src/main/scala/mlscript/codegen/Scope.scala +++ b/shared/src/main/scala/mlscript/codegen/Scope.scala @@ -313,18 +313,26 @@ class Scope(val name: Str, enclosing: Opt[Scope]) { symbol } - def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean, symbolicName: Opt[Str]): ValueSymbol = { + def declareValue( + lexicalName: Str, + isByvalueRec: Option[Boolean], + isLam: Boolean, + symbolicName: Opt[Str], + /** Workaround for the first pass traversal with new definition typing. */ + forNewDefsDryRun: Bool = false + ): ValueSymbol = { val runtimeName = lexicalValueSymbols.get(lexicalName) match { // If we are implementing a stub symbol and the stub symbol did not shadow any other // symbols, it is safe to reuse its `runtimeName`. - case S(sym: StubValueSymbol) if !sym.shadowing => sym.runtimeName - case S(sym: BuiltinSymbol) if !sym.accessed => sym.runtimeName - case _ => allocateRuntimeName(lexicalName) + case S(sym: StubValueSymbol) if !sym.shadowing => sym.runtimeName + case S(sym: ValueSymbol) if sym.forNewDefsDryRun => sym.runtimeName + case S(sym: BuiltinSymbol) if !sym.accessed => sym.runtimeName + case _ => allocateRuntimeName(lexicalName) } - val symbol = ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam) + val symbol = ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam, forNewDefsDryRun) register(symbol) symbolicName.foreach { symbolicName => - register(ValueSymbol(symbolicName, runtimeName, isByvalueRec, isLam)) + register(ValueSymbol(symbolicName, runtimeName, isByvalueRec, isLam, forNewDefsDryRun)) } symbol } @@ -350,10 +358,16 @@ class Scope(val name: Str, enclosing: Opt[Scope]) { allowEscape: Bool ): StubValueSymbol = { val symbol = lexicalValueSymbols.get(lexicalName) match { + // If the existing symbol is a value symbol, but the value symbol is + // declared in the dry-run of new definition typing, we can reuse the + // runtime name. + case S(valueSymbol: ValueSymbol) if valueSymbol.forNewDefsDryRun => + StubValueSymbol(lexicalName, valueSymbol.runtimeName, false, previous) // If a stub with the same name has been defined, use the name. - case S(value) => StubValueSymbol(lexicalName, value.runtimeName, true, previous) + case S(symbol) => StubValueSymbol(lexicalName, symbol.runtimeName, true, previous) // Otherwise, we will allocate a new name. - case N => StubValueSymbol(lexicalName, allocateRuntimeName(lexicalName), false, previous) + case N => + StubValueSymbol(lexicalName, allocateRuntimeName(lexicalName), false, previous) } register(symbol) symbolicName.foreach { symbolicName => diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala index 2d844d2f70..adc8d1bac9 100644 --- a/shared/src/main/scala/mlscript/codegen/Symbol.scala +++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala @@ -45,13 +45,35 @@ sealed trait NuTypeSymbol { sym: TypeSymbol => def isNested: Bool = qualifier.isDefined // is nested in another class/mixin/module } -sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol { +sealed class ValueSymbol( + val lexicalName: Str, + val runtimeName: Str, + val isByvalueRec: Option[Boolean], + val isLam: Boolean, + /** + * Workaround for the first pass traversal with new definition typing. + * "Dry run" here means that we haven't generated the code for the symbol + * yet in the new-definition-typing mode, so the symbol is just defined + * for the sake of code generation of classes/mixins/modules. + * + * This field should be deprecated after the `PreTyper` is done. See [PR + * #197](https://github.com/hkust-taco/mlscript/pull/197) for more details. + */ + val forNewDefsDryRun: Boolean +) extends RuntimeSymbol { override def toString: Str = s"value $lexicalName" } object ValueSymbol { - def apply(lexicalName: Str, runtimeName: Str, isByvalueRec: Option[Boolean], isLam: Boolean): ValueSymbol = - new ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam) + def apply( + lexicalName: Str, + runtimeName: Str, + isByvalueRec: Option[Boolean], + isLam: Boolean, + /** Workaround for the first pass traversal with new definition typing. */ + forNewDefsDryRun: Boolean = false + ): ValueSymbol = + new ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam, forNewDefsDryRun) } sealed case class TypeAliasSymbol( diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls index 5c729795cb..3fd393ed25 100644 --- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -464,11 +464,11 @@ n.ll //│ class TypingUnit19 {} //│ const typing_unit19 = new TypingUnit19; //│ // Query 1 -//│ globalThis.m1 = g(1); +//│ globalThis.m = g(1); //│ // Query 2 -//│ globalThis.n1 = m1(2); +//│ globalThis.n = m(2); //│ // Query 3 -//│ res = n1.ll; +//│ res = n.ll; //│ // End of generated code //│ m //│ = [Function (anonymous)] @@ -487,7 +487,7 @@ let mm = new M() //│ class TypingUnit21 {} //│ const typing_unit21 = new TypingUnit21; //│ // Query 1 -//│ globalThis.mm1 = new M.class(); +//│ globalThis.mm = new M.class(); //│ // End of generated code //│ mm //│ = M {} diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index 4f769b8f32..a61301347e 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -105,7 +105,7 @@ let aa = A(42) //│ class TypingUnit5 {} //│ const typing_unit5 = new TypingUnit5; //│ // Query 1 -//│ globalThis.aa1 = A(42); +//│ globalThis.aa = A(42); //│ // End of generated code //│ aa //│ = A {} @@ -119,7 +119,7 @@ aa //│ class TypingUnit6 {} //│ const typing_unit6 = new TypingUnit6; //│ // Query 1 -//│ res = aa1; +//│ res = aa; //│ // End of generated code //│ res //│ = A {} @@ -131,7 +131,7 @@ let ab = A(0) //│ class TypingUnit7 {} //│ const typing_unit7 = new TypingUnit7; //│ // Query 1 -//│ globalThis.ab1 = A(0); +//│ globalThis.ab = A(0); //│ // End of generated code //│ ab //│ = A {} @@ -408,9 +408,9 @@ www.add(42) //│ class TypingUnit15 {} //│ const typing_unit15 = new TypingUnit15; //│ // Query 1 -//│ globalThis.www1 = W(); +//│ globalThis.www = W(); //│ // Query 2 -//│ res = www1.add(42); +//│ res = www.add(42); //│ // End of generated code //│ www //│ = W {} diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls index 227d0c7a2d..10843c74aa 100644 --- a/shared/src/test/diff/codegen/Nested.mls +++ b/shared/src/test/diff/codegen/Nested.mls @@ -78,9 +78,9 @@ bb.b //│ class TypingUnit1 {} //│ const typing_unit1 = new TypingUnit1; //│ // Query 1 -//│ globalThis.bb1 = A.B(A.a); +//│ globalThis.bb = A.B(A.a); //│ // Query 2 -//│ res = bb1.b; +//│ res = bb.b; //│ // End of generated code //│ bb //│ = B {} @@ -241,9 +241,9 @@ ee.x //│ class TypingUnit5 {} //│ const typing_unit5 = new TypingUnit5; //│ // Query 1 -//│ globalThis.ee1 = D.createE(42); +//│ globalThis.ee = D.createE(42); //│ // Query 2 -//│ res = ee1.x; +//│ res = ee.x; //│ // End of generated code //│ ee //│ = E {} @@ -361,13 +361,13 @@ gg.sum //│ class TypingUnit7 {} //│ const typing_unit7 = new TypingUnit7; //│ // Query 1 -//│ globalThis.es1 = E(1); +//│ globalThis.es = E(1); //│ // Query 2 -//│ globalThis.fff1 = es1.F(2); +//│ globalThis.fff = es.F(2); //│ // Query 3 -//│ globalThis.gg1 = fff1.G(3); +//│ globalThis.gg = fff.G(3); //│ // Query 4 -//│ res = gg1.sum; +//│ res = gg.sum; //│ // End of generated code //│ es //│ = E {} @@ -559,11 +559,11 @@ i.x //│ class TypingUnit10 {} //│ const typing_unit10 = new TypingUnit10; //│ // Query 1 -//│ globalThis.jj1 = G.H.J(42); +//│ globalThis.jj = G.H.J(42); //│ // Query 2 -//│ globalThis.i1 = jj1.ii(2); +//│ globalThis.i = jj.ii(2); //│ // Query 3 -//│ res = i1.x; +//│ res = i.x; //│ // End of generated code //│ jj //│ = J {} @@ -666,9 +666,9 @@ j.i.x //│ class TypingUnit12 {} //│ const typing_unit12 = new TypingUnit12; //│ // Query 1 -//│ globalThis.j1 = H.J(42); +//│ globalThis.j = H.J(42); //│ // Query 2 -//│ res = j1.i.x; +//│ res = j.i.x; //│ // End of generated code //│ j //│ = J {} @@ -757,11 +757,11 @@ ij.incY //│ const typing_unit13 = new TypingUnit13; //│ globalThis.I = typing_unit13.I; //│ // Query 1 -//│ globalThis.i3 = I(1); +//│ globalThis.i1 = I(1); //│ // Query 2 -//│ globalThis.ij1 = i3.J(0); +//│ globalThis.ij = i1.J(0); //│ // Query 3 -//│ res = ij1.incY; +//│ res = ij.incY; //│ // End of generated code //│ i //│ = I {} @@ -890,9 +890,9 @@ let n = J.N(2) //│ class TypingUnit15 {} //│ const typing_unit15 = new TypingUnit15; //│ // Query 1 -//│ globalThis.m1 = J.M(); +//│ globalThis.m = J.M(); //│ // Query 2 -//│ globalThis.n1 = J.N(2); +//│ globalThis.n = J.N(2); //│ // End of generated code //│ m //│ = M {} diff --git a/shared/src/test/diff/codegen/New.mls b/shared/src/test/diff/codegen/New.mls index 8636a83c8b..9909f20df2 100644 --- a/shared/src/test/diff/codegen/New.mls +++ b/shared/src/test/diff/codegen/New.mls @@ -46,7 +46,7 @@ let c = C //│ class TypingUnit3 {} //│ const typing_unit3 = new TypingUnit3; //│ // Query 1 -//│ globalThis.c1 = C; +//│ globalThis.c = C; //│ // End of generated code //│ c //│ = [class C] @@ -93,7 +93,7 @@ let c = C //│ class TypingUnit8 {} //│ const typing_unit8 = new TypingUnit8; //│ // Query 1 -//│ globalThis.c3 = C; +//│ globalThis.c1 = C; //│ // End of generated code //│ c //│ = [Function (anonymous)] { diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index acdef0ef4a..50d2dbc1da 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -136,7 +136,7 @@ fun foo(s) = //│ // Query 1 //│ globalThis.foo = function foo(s) { //│ return ((() => { -//│ return s instanceof Some.class ? (([t]) => ((b) => b + t.x)(s21.value))(Some.unapply(s)) : 0; +//│ return s instanceof Some.class ? (([t]) => ((b) => b + t.x)(s2.value))(Some.unapply(s)) : 0; //│ })()); //│ }; //│ // End of generated code diff --git a/shared/src/test/diff/codegen/NewMutualRef.mls b/shared/src/test/diff/codegen/NewMutualRef.mls new file mode 100644 index 0000000000..49b50da288 --- /dev/null +++ b/shared/src/test/diff/codegen/NewMutualRef.mls @@ -0,0 +1,166 @@ +:NewDefs + +:js +fun foo: Int -> Int +fun foo = x => x + 1 // <- This will be added as a value symbol before translating `Bar`. +class Bar { + fun calc(x) = foo(x) +} +//│ fun foo: Int -> Int +//│ class Bar { +//│ constructor() +//│ fun calc: Int -> Int +//│ } +//│ fun foo: Int -> Int +//│ // Prelude +//│ let res; +//│ class TypingUnit { +//│ #Bar; +//│ constructor() { +//│ } +//│ get Bar() { +//│ const qualifier = this; +//│ if (this.#Bar === undefined) { +//│ class Bar { +//│ constructor() { +//│ } +//│ calc(x) { +//│ return foo(x); +//│ } +//│ }; +//│ this.#Bar = Bar; +//│ } +//│ return this.#Bar; +//│ } +//│ } +//│ const typing_unit = new TypingUnit; +//│ globalThis.Bar = typing_unit.Bar; +//│ // Query 1 is empty +//│ // Query 2 +//│ globalThis.foo = function foo(x) { +//│ return x + 1; +//│ }; +//│ // End of generated code + +// Note: This test case looks trivial but it was like: +// +// ``` +// :re +// (new Bar()).calc(0) +// //│ Int +// //│ res +// //│ Runtime error: +// //│ ReferenceError: foo is not defined +// ``` +// +// My fix is a little bit hacky. The root of the problem is: when generating +// code within a class, we need all top-level bindings to be accessible. This +// part of implementation of new-definition-typing chose to declare all term +// `NuFunDef` as `ValueSymbol` in advance, but this can lead to the fact that +// the same symbol is declared multiple times, thus wasting some runtime names. +// Consequently, the code that references these wasted runtime names are invalid. +// +// Actually, I have a better solution, but it requires adjusting the order of +// translation, and I don't have much time to spend on this at the moment. So, +// my current fix is rather hacky. But I will complete this part after `PreTyper` +// is finished, when I replacing the old Scope with the new Scope. +// +// Luyu Cheng on 2023/12/30 +(new Bar()).calc(0) +//│ Int +//│ res +//│ = 1 + +:js +fun foo: Int -> Int +fun foo = x => x + 1 +class Bar { fun calc(x) = foo(x) } +//│ fun foo: Int -> Int +//│ class Bar { +//│ constructor() +//│ fun calc: Int -> Int +//│ } +//│ fun foo: Int -> Int +//│ // Prelude +//│ class TypingUnit2 { +//│ #Bar; +//│ constructor() { +//│ } +//│ get Bar() { +//│ const qualifier = this; +//│ if (this.#Bar === undefined) { +//│ class Bar { +//│ constructor() { +//│ } +//│ calc(x) { +//│ return foo1(x); +//│ } +//│ }; +//│ this.#Bar = Bar; +//│ } +//│ return this.#Bar; +//│ } +//│ } +//│ const typing_unit2 = new TypingUnit2; +//│ globalThis.Bar = typing_unit2.Bar; +//│ // Query 1 is empty +//│ // Query 2 +//│ globalThis.foo1 = function foo1(x) { +//│ return x + 1; +//│ }; +//│ // End of generated code + +foo(0) +new Bar().calc(0) +//│ Int +//│ res +//│ = 1 +//│ res +//│ = 1 + +:js +class Bar { fun calc(x) = foo } +fun foo: Int +fun foo = 123 +//│ class Bar { +//│ constructor() +//│ fun calc: anything -> Int +//│ } +//│ fun foo: 123 +//│ fun foo: Int +//│ // Prelude +//│ class TypingUnit4 { +//│ #Bar; +//│ constructor() { +//│ } +//│ get Bar() { +//│ const qualifier = this; +//│ if (this.#Bar === undefined) { +//│ class Bar { +//│ constructor() { +//│ } +//│ calc(x) { +//│ return foo2(); +//│ } +//│ }; +//│ this.#Bar = Bar; +//│ } +//│ return this.#Bar; +//│ } +//│ } +//│ const typing_unit4 = new TypingUnit4; +//│ globalThis.Bar = typing_unit4.Bar; +//│ // Query 1 is empty +//│ // Query 2 +//│ globalThis.foo2 = function foo2() { +//│ return 123; +//│ }; +//│ // End of generated code + +foo +new Bar().calc(0) +//│ Int +//│ res +//│ = 123 +//│ res +//│ = 123 diff --git a/shared/src/test/diff/codegen/NuReplHost.mls b/shared/src/test/diff/codegen/NuReplHost.mls index c5aaf4563f..d4805d1c82 100644 --- a/shared/src/test/diff/codegen/NuReplHost.mls +++ b/shared/src/test/diff/codegen/NuReplHost.mls @@ -33,7 +33,7 @@ let r = foo(1) //│ └─┬ Query 2/2 //│ ├── Prelude: //│ ├── Code: -//│ ├── globalThis.r1 = foo(1); +//│ ├── globalThis.r = foo(1); //│ └── Reply: [runtime error] Error: an error was thrown //│ r //│ Runtime error: @@ -44,7 +44,7 @@ r //│ nothing //│ res //│ Runtime error: -//│ ReferenceError: r1 is not defined +//│ ReferenceError: r is not defined diff --git a/shared/src/test/diff/codegen/SymbolicOps.mls b/shared/src/test/diff/codegen/SymbolicOps.mls index 37e42ce6a0..9dd61cb78a 100644 --- a/shared/src/test/diff/codegen/SymbolicOps.mls +++ b/shared/src/test/diff/codegen/SymbolicOps.mls @@ -14,7 +14,7 @@ let r = succ >> succ //│ class TypingUnit1 {} //│ const typing_unit1 = new TypingUnit1; //│ // Query 1 -//│ globalThis.r1 = compose(succ, succ); +//│ globalThis.r = compose(succ, succ); //│ // End of generated code //│ r //│ = [Function (anonymous)] @@ -65,7 +65,7 @@ let f = (>>) //│ class TypingUnit7 {} //│ const typing_unit7 = new TypingUnit7; //│ // Query 1 -//│ globalThis.f1 = compose; +//│ globalThis.f = compose; //│ // End of generated code //│ f //│ = [Function: compose] @@ -315,7 +315,7 @@ fun (:-D) dd(a, b) = a + b val (->) f(x, y) = [x, y] //│ val (->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b] //│ f -//│ = [Function: f3] +//│ = [Function: f1] 12 -> 34 //│ [12, 34] @@ -326,7 +326,7 @@ val (->) f(x, y) = [x, y] let (->) _ = f //│ let (->) _: forall 'a 'b. ('a, 'b) -> ['a, 'b] //│ _ -//│ = [Function: f3] +//│ = [Function: f1] :js 12 -> 34 @@ -335,7 +335,7 @@ let (->) _ = f //│ class TypingUnit42 {} //│ const typing_unit42 = new TypingUnit42; //│ // Query 1 -//│ res = _1(12, 34); +//│ res = _(12, 34); //│ // End of generated code //│ res //│ = [ 12, 34 ] diff --git a/shared/src/test/diff/mlscript/Sequence.mls b/shared/src/test/diff/mlscript/Sequence.mls index 6c52dff4ca..919c7251b1 100644 --- a/shared/src/test/diff/mlscript/Sequence.mls +++ b/shared/src/test/diff/mlscript/Sequence.mls @@ -4,7 +4,7 @@ let test(x) = log(x); x + 1 //│ let test: Int -> Int //│ test -//│ = [Function: test1] +//│ = [Function: test] test(log("here we go"); 123) //│ Int diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index b33cb35fab..857ee4e3ac 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -40,7 +40,7 @@ fun zip(xs, ys) = mapi of xs, (x, i) => zip //│ forall 'a 'b. (Array['a], Array[Object & 'b & ~()]) -> Array[['a, 'b]] //│ res -//│ = [Function: zip1] +//│ = [Function: zip] diff --git a/shared/src/test/diff/nu/CtorSubtraction.mls b/shared/src/test/diff/nu/CtorSubtraction.mls index 38d37eaaac..9a58ce6842 100644 --- a/shared/src/test/diff/nu/CtorSubtraction.mls +++ b/shared/src/test/diff/nu/CtorSubtraction.mls @@ -16,12 +16,12 @@ fun x = case x : Int -> Int //│ Int -> Int //│ res -//│ = [Function: x1] +//│ = [Function: x] x : Cls -> nothing //│ Cls -> nothing //│ res -//│ = [Function: x1] +//│ = [Function: x] fun x: (Int | Str | Cls) \ Cls diff --git a/shared/src/test/diff/nu/FlatIndentFuns.mls b/shared/src/test/diff/nu/FlatIndentFuns.mls index 77ace9e704..3a58afdd03 100644 --- a/shared/src/test/diff/nu/FlatIndentFuns.mls +++ b/shared/src/test/diff/nu/FlatIndentFuns.mls @@ -20,7 +20,7 @@ y => x + y //│ let r: Int -> Int -> Int //│ r -//│ = [Function: r1] +//│ = [Function: r] r(1)(2) //│ Int @@ -59,6 +59,6 @@ x + y //│ ╙── //│ let r: Int -> Int -> Int //│ r -//│ = [Function: r3] +//│ = [Function: r1] diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls index 1fe5bef9a8..938516f499 100644 --- a/shared/src/test/diff/nu/FlatMonads_repro.mls +++ b/shared/src/test/diff/nu/FlatMonads_repro.mls @@ -48,7 +48,7 @@ let ri(f) = Bind(Pure(42), f) //│ where //│ 'CC :> 42 //│ ri -//│ = [Function: ri1] +//│ = [Function: ri] ri(Pure) //│ Bind['CC, 'AA] diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 264a541703..51f4efad8b 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -202,7 +202,7 @@ type Res = M(T) let f = x => [x, x] //│ let f: forall 'a. 'a -> ['a, 'a] //│ f -//│ = [Function: f3] +//│ = [Function: f1] [f(1), f(true)] //│ [[1, 1], [true, true]] diff --git a/shared/src/test/diff/nu/LamPatterns.mls b/shared/src/test/diff/nu/LamPatterns.mls index cb78cf3498..58aa85eb8e 100644 --- a/shared/src/test/diff/nu/LamPatterns.mls +++ b/shared/src/test/diff/nu/LamPatterns.mls @@ -24,12 +24,12 @@ let f = Some => 0 //│ class TypingUnit2 {} //│ const typing_unit2 = new TypingUnit2; //│ // Query 1 -//│ globalThis.f1 = function f1(Some) { +//│ globalThis.f = function f(Some) { //│ return 0; //│ }; //│ // End of generated code //│ f -//│ = [Function: f1] +//│ = [Function: f] // :e // TODO f(Some) diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls index 15717f5ded..211987ae06 100644 --- a/shared/src/test/diff/nu/LocalLets.mls +++ b/shared/src/test/diff/nu/LocalLets.mls @@ -32,6 +32,6 @@ let E(x) = new E(1) //│ ╙── ^ //│ let E: anything -> error //│ E -//│ = [Function: E2] +//│ = [Function: E1] diff --git a/shared/src/test/diff/nu/MIscPoly.mls b/shared/src/test/diff/nu/MIscPoly.mls index 34235988a1..3d9c94a5af 100644 --- a/shared/src/test/diff/nu/MIscPoly.mls +++ b/shared/src/test/diff/nu/MIscPoly.mls @@ -69,7 +69,7 @@ r() //│ nothing //│ res //│ Runtime error: -//│ TypeError: r1 is not a function +//│ TypeError: r is not a function diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index a0aa87e20c..821a12d2c7 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -65,7 +65,7 @@ f of [1, 2] let f = (x, y) => x + y //│ let f: (Int, Int) -> Int //│ f -//│ = [Function: f5] +//│ = [Function: f4] f(1, 2) //│ Int @@ -96,7 +96,7 @@ let f = ((x, y)) => x + y //│ ╙── ^^^^^^ //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f7] +//│ = [Function: f5] :e f(1, 2) @@ -132,7 +132,7 @@ f[1, 2] //│ ╙── ^^^^^^^ //│ ([Int, Int]) -> Int //│ res -//│ = [Function: f7] +//│ = [Function: f5] :pe @@ -142,14 +142,14 @@ let f = (((x, y))) => x + y //│ ╙── ^^^^^^ //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f9] +//│ = [Function: f6] // * TODO maybe parse as type lambda? let f = [x, y] => x + y //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f11] +//│ = [Function: f7] :e f(1, 2) @@ -173,7 +173,7 @@ f([1, 2]) let f = ([x, y]) => x + y //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f13] +//│ = [Function: f8] f([1, 2]) //│ Int @@ -197,7 +197,7 @@ f(1, 2) let f = [[[x, y]]] => x + y //│ let f: ([[[Int, Int]]]) -> Int //│ f -//│ = [Function: f15] +//│ = [Function: f9] :e f([[1, 2]]) diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls index c846ee548b..8c4d4606f1 100644 --- a/shared/src/test/diff/nu/NamedArgs.mls +++ b/shared/src/test/diff/nu/NamedArgs.mls @@ -116,9 +116,9 @@ test(0, y: 200) //│ class TypingUnit13 {} //│ const typing_unit13 = new TypingUnit13; //│ // Query 1 -//│ globalThis.tmp1 = 2; +//│ globalThis.tmp = 2; //│ // Query 2 -//│ res = test1(0, tmp1); +//│ res = test1(0, tmp); //│ // Query 3 //│ res = test1(0, 200); //│ // End of generated code @@ -171,11 +171,11 @@ fff(y: 2, z: y_1 + 1, x: z_1 - 2) //│ class TypingUnit17 {} //│ const typing_unit17 = new TypingUnit17; //│ // Query 1 -//│ globalThis["y_11"] = 2; +//│ globalThis["y_1"] = 2; //│ // Query 2 -//│ globalThis["z_11"] = 3; +//│ globalThis["z_1"] = 3; //│ // Query 3 -//│ res = ((z_2) => ((x_1) => fff(x_1, 2, z_2))(z_11 - 2))(y_11 + 1); +//│ res = ((z_2) => ((x_1) => fff(x_1, 2, z_2))(z_1 - 2))(y_1 + 1); //│ // End of generated code //│ y_1 //│ = 2 diff --git a/shared/src/test/diff/nu/NestedRecords.mls b/shared/src/test/diff/nu/NestedRecords.mls index ca216f4788..ebe7bbcbd6 100644 --- a/shared/src/test/diff/nu/NestedRecords.mls +++ b/shared/src/test/diff/nu/NestedRecords.mls @@ -4,7 +4,7 @@ let f(x) = [x, x] //│ let f: forall 'a. 'a -> ['a, 'a] //│ f -//│ = [Function: f1] +//│ = [Function: f] let a = { u: f(f(f(1))), v: f(f(f(1))) } //│ let a: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]} diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index 8ab334a692..c135ca38a9 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -103,7 +103,7 @@ f(1) //│ error //│ res //│ Runtime error: -//│ TypeError: f9 is not a function +//│ TypeError: f4 is not a function :e new Foo("2") diff --git a/shared/src/test/diff/nu/Res.mls b/shared/src/test/diff/nu/Res.mls index e8936ec349..0f7f660b69 100644 --- a/shared/src/test/diff/nu/Res.mls +++ b/shared/src/test/diff/nu/Res.mls @@ -19,7 +19,7 @@ res(1) let res = x => x + 2 //│ let res: Int -> Int //│ res -//│ = [Function: res2] +//│ = [Function: res1] res(1) //│ Int diff --git a/shared/src/test/diff/nu/Vals.mls b/shared/src/test/diff/nu/Vals.mls index e90080f1b9..413b7a8498 100644 --- a/shared/src/test/diff/nu/Vals.mls +++ b/shared/src/test/diff/nu/Vals.mls @@ -32,7 +32,7 @@ val a = a val f(x) = x //│ val f: forall 'a. 'a -> 'a //│ f -//│ = [Function: f1] +//│ = [Function: f] f(123) //│ 123 From 29e38d157dcb1d0de21a6cce1b8f5dfdd322f45d Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Tue, 2 Jan 2024 16:36:24 +0800 Subject: [PATCH 492/498] Remove inspection function for syntax tree nodes (#200) --- .../scala/mlscript/compiler/ClassLifter.scala | 3 +- .../scala/mlscript/compiler/Helpers.scala | 3 +- .../mlscript/compiler/PrettyPrinter.scala | 12 +- compiler/shared/test/diff/LambLift.mls | 12 +- compiler/shared/test/diff/LiftType.mls | 15 +- compiler/shared/test/diff/Lifter.mls | 63 +++----- compiler/shared/test/diff/LifterBlks.mls | 60 +++---- compiler/shared/test/diff/mono.mls | 81 ++++------ .../test/scala/mlscript/compiler/Test.scala | 3 - .../src/main/scala/mlscript/JSBackend.scala | 13 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 +- shared/src/main/scala/mlscript/Typer.scala | 2 +- .../main/scala/mlscript/TyperDatatypes.scala | 2 +- .../main/scala/mlscript/codegen/Helpers.scala | 100 ------------ shared/src/main/scala/mlscript/helpers.scala | 146 ++++++++++-------- shared/src/main/scala/mlscript/syntax.scala | 2 +- .../main/scala/mlscript/ucs/Desugarer.scala | 6 +- .../main/scala/mlscript/ucs/MutCaseOf.scala | 18 +-- .../main/scala/mlscript/ucs/Scrutinee.scala | 2 +- shared/src/test/diff/basics/Blocks.fun | 10 +- shared/src/test/diff/basics/Data.fun | 4 +- shared/src/test/diff/basics/Datatypes.fun | 14 +- shared/src/test/diff/basics/Either.fun | 4 +- shared/src/test/diff/basics/Flow.fun | 4 +- shared/src/test/diff/basics/Operators.fun | 16 +- shared/src/test/diff/basics/Slashes.fun | 2 +- shared/src/test/diff/mlscript/Basics.mls | 2 +- .../src/test/diff/mlscript/ByNameByValue.mls | 4 +- shared/src/test/diff/mlscript/MultiArgs.mls | 8 +- shared/src/test/diff/mlscript/Mut.mls | 2 +- shared/src/test/diff/mlscript/Ops.mls | 10 +- shared/src/test/diff/mlscript/Weird.mls | 4 +- shared/src/test/diff/nu/AbstractClasses.mls | 2 +- shared/src/test/diff/nu/BadBlocks.mls | 2 +- shared/src/test/diff/nu/LamPatterns.mls | 2 +- shared/src/test/diff/nu/LetRec.mls | 2 +- shared/src/test/diff/nu/NewNew.mls | 12 +- shared/src/test/diff/nu/OpLam.mls | 2 +- shared/src/test/diff/nu/OverrideShorthand.mls | 4 +- shared/src/test/diff/nu/Refinements.mls | 2 +- shared/src/test/diff/nu/RightAssocOps.mls | 6 +- shared/src/test/diff/nu/TODO_Classes.mls | 2 +- shared/src/test/diff/parser/BasicSyntax.mls | 6 +- shared/src/test/diff/parser/New.mls | 8 +- shared/src/test/diff/ucs/LeadingAnd.mls | 4 +- shared/src/test/diff/ucs/SplitOps.mls | 4 +- .../src/test/scala/mlscript/DiffTests.scala | 18 +-- 47 files changed, 270 insertions(+), 435 deletions(-) delete mode 100644 shared/src/main/scala/mlscript/codegen/Helpers.scala diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index 5124a31c56..559bc59578 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -7,7 +7,6 @@ import scala.collection.mutable.StringBuilder as StringBuilder import scala.collection.mutable.Map as MutMap import scala.collection.mutable.Set as MutSet import scala.collection.mutable.ArrayBuffer as ArrayBuffer -import mlscript.codegen.Helpers.inspect as showStructure import mlscript.codegen.CodeGenError import mlscript.compiler.mono.MonomorphError @@ -748,7 +747,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { def liftTypingUnit(rawUnit: TypingUnit): TypingUnit = { log("=========================\n") - log(s"lifting: \n${showStructure(rawUnit)}\n") + log(s"lifting: \n$rawUnit\n") retSeq = Nil globalFunctions.clear() val re = liftEntities(rawUnit.entities)(using emptyCtx, Map(), Map(), None) diff --git a/compiler/shared/main/scala/mlscript/compiler/Helpers.scala b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala index 5eb1a526dc..41515a772f 100644 --- a/compiler/shared/main/scala/mlscript/compiler/Helpers.scala +++ b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala @@ -1,7 +1,6 @@ package mlscript package compiler -import mlscript.codegen.Helpers.inspect as showStructure import mlscript.compiler.mono.{Monomorph, MonomorphError} import scala.collection.mutable.ArrayBuffer @@ -16,7 +15,7 @@ object Helpers: case (None, Fld(FldFlags(_, spec, _), Var(name))) => Some((spec, Expr.Ref(name))) case (Some(Var(name)), Fld(FldFlags(_, spec, _), _)) => Some((spec, Expr.Ref(name))) case _ => throw new MonomorphError( - s"only `Var` can be parameters but we meet ${showStructure(term)}" + s"only `Var` can be parameters but we meet $term" ) } case _ => throw MonomorphError("expect the list of parameters to be a `Tup`") diff --git a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala index 106748f96f..14e91ccf48 100644 --- a/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/PrettyPrinter.scala @@ -5,7 +5,7 @@ import mlscript.compiler.debug.DebugOutput // For pretty printing terms in debug output. object PrettyPrinter: - def show(term: Term): DebugOutput = DebugOutput.Code(term.toString.linesIterator.toList) + def show(term: Term): DebugOutput = DebugOutput.Code(term.showDbg.linesIterator.toList) def show(unit: TypingUnit): DebugOutput = DebugOutput.Code(showTypingUnit(unit, 0).linesIterator.toList) def show(funDef: NuFunDef): DebugOutput = DebugOutput.Code(showFunDef(funDef).linesIterator.toList) def show(tyDef: NuTypeDef): DebugOutput = DebugOutput.Code(showTypeDef(tyDef, 0).linesIterator.toList) @@ -16,7 +16,7 @@ object PrettyPrinter: case term: Term => show(term) case tyDef: NuTypeDef => showTypeDef(tyDef) case funDef: NuFunDef => showFunDef(funDef) - case others => others.toString() + case others => others.showDbg }.mkString("{", "; ", "}") if (singleLine.length < 60) singleLine @@ -26,7 +26,7 @@ object PrettyPrinter: case term: Term => show(term) case tyDef: NuTypeDef => showTypeDef(tyDef) case funDef: NuFunDef => showFunDef(funDef) - case others => others.toString() + case others => others.showDbg }.map(indentStr + " " + _).mkString("{\n", "\n", s"\n$indentStr}") def showFunDef(funDef: NuFunDef): String = @@ -40,15 +40,15 @@ object PrettyPrinter: then "" else funDef.tparams.map(_.name).mkString("[", ", ", "]")) + " = " - + funDef.rhs.fold(_.toString, _.show(newDefs = true)) + + funDef.rhs.fold(_.showDbg, _.show(newDefs = true)) def showTypeDef(tyDef: NuTypeDef, indent: Int = 0): String = s"${tyDef.kind.str} ${tyDef.nme.name}" + (if tyDef.tparams.isEmpty then "" else tyDef.tparams.map(_._2.name).mkString("[", ",", "]")) - + tyDef.params.fold("")(params => s"($params)") + + tyDef.params.fold("")(params => s"(${params.showDbg})") + (if tyDef.parents.isEmpty then "" - else ": " + tyDef.parents.map(_.toString).mkString(", ")) + else ": " + tyDef.parents.map(_.showDbg).mkString(", ")) + showTypingUnit(tyDef.body, indent + 1) diff --git a/compiler/shared/test/diff/LambLift.mls b/compiler/shared/test/diff/LambLift.mls index c42974bf49..81fecb52dd 100644 --- a/compiler/shared/test/diff/LambLift.mls +++ b/compiler/shared/test/diff/LambLift.mls @@ -9,8 +9,7 @@ fun foo() = (new Foo()).bar local(1) foo() -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Blk(...))), App(Var(foo), Tup())) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1([x,]) {fun bar = () => +((this).x, foo$1(),)} @@ -27,8 +26,7 @@ foo() fun foo(f) = f(1) foo(x => x+1) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class Lambda1$2$1([]) {fun apply = (x,) => +(x, 1,)} @@ -45,8 +43,7 @@ fun foo(x) = f(x) bar(y => y+x) foo(1) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: IntLit(1)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Lambda1$3$1([x,]) {fun apply = (y,) => +(y, (this).x,)} @@ -67,8 +64,7 @@ class A(y: Int){ fun app(a) = foo(z => a.bar(z)) app(new A(1)) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), NuTypeDef(class, A, (), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: Var(y), _: Var(z))))))), NuFunDef(None, app, None, [], Lam(Tup(_: Var(a)), Blk(...))), App(Var(app), Tup(_: App(NuNew(Var(A)), Tup(_: IntLit(1)))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1([y: Int,]) {fun bar = (z,) => +((this).y, z,)} diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index 773e24b1e9..e8a5206b51 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -7,8 +7,7 @@ class CTX{ } //│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |#=>| |A|)|#:| |(|A| |#=>| |A|)| |#=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| //│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A,) : (A -> A) -> A}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: NuNew(Var(A)))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {} @@ -25,8 +24,7 @@ class CTX(x, y){ } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |[|A|,| |B|]|)|#:| |[|B|,| |A|]| |#=| |[|any|._2|,| |any|._1|]|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: [A, B,],) => [(any)._2, (any)._1,] : [B, A]}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: Var(B))), Asc(Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} @@ -44,8 +42,7 @@ class CTX(x, y){ } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|#:| |A| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |{|p1|#:| |A|,| |p2|#:| |B|}|)|#:| |[|B|,| |A|]| |#=| |[|any|.p2|,| |any|.p1|]|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B: A {fun foo = y}; fun foo = (any: '{' {p1: A, p2: B} '}',) => [(any).p2, (any).p1,] : [B, A]}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} @@ -63,8 +60,7 @@ class CTX(x, y){ } //│ |#class| |CTX|(|x|,| |y|)|{|→|#class| |A|{| |#fun| |foo| |#=| |x|}|↵|#class| |B|‹|T|›| |{| |#fun| |foo| |#=| |y|}|↵|#fun| |foo|(|any|#:| |[|A|,| |B|‹|A|›|]|)|#:| |[|[|B|‹|A|›|,| |A|]|,| |A|]| |#=| |[|any|,| |any|._1|]|←|↵|}| //│ Parsed: {class CTX(x, y,) {class A {fun foo = x}; class B‹T› {fun foo = y}; fun foo = (any: [A, B‹A›,],) => [any, (any)._1,] : [[B[A], A], A]}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A))))), Asc(Tup(_: Var(any), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} @@ -85,8 +81,7 @@ class CTX{ } //│ |#class| |CTX|{|→|#fun| |ctx|(|x|,|y|)| |#=| |→|#class| |A|{| |#fun| |foo| |#=| |x| |}|↵|#fun| |bar|‹|T|›|(|any|#:| |T|)|#:| |A| |#=| |→|#let| |x| |#=| |#new| |T|↵|#new| |A|←|↵|(|#new| |CTX|)|.bar|‹|CTX|›|←|←|↵|}| //│ Parsed: {class CTX {fun ctx = (x, y,) => {class A {fun foo = x}; fun bar = (any: T,) => {let x = new T; new A} : A; ('(' new CTX ')').bar‹CTX›}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, ctx, None, [], Lam(Tup(_: Var(x), _: Var(y)), Blk(...)))))) +//│ //│ Lifted: //│ Lifting failed: mlscript.codegen.CodeGenError: Cannot find type T. Class values are not supported in lifter. //│ diff --git a/compiler/shared/test/diff/Lifter.mls b/compiler/shared/test/diff/Lifter.mls index fffb3d7252..c0c0f3a681 100644 --- a/compiler/shared/test/diff/Lifter.mls +++ b/compiler/shared/test/diff/Lifter.mls @@ -27,8 +27,7 @@ class A(x) { } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getB1| |#=| |B1|(|y|)|↵|#class| |C|(|z|)| |{|→|#fun| |inc|(||)| |#=| |x| |+| |1|↵|#fun| |getY| |#=| |y|↵|#fun| |getA| |#=| |A|(|z|)|↵|#fun| |getB|(|w|)| |#=| |B|(|w|)|↵|#fun| |getC| |#=| |#new| |C|(|inc|(||)|)|↵|#fun| |getSelf| |#=| |this|←|↵|}|←|↵|}|↵|#class| |B1|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getY| |#=| |y|↵|#fun| |getB| |#=| |#new| |B|(|y|)|↵|#fun| |getB1| |#=| |#new| |B1|(|y|)|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|(|x|)|↵|#fun| |getB2|(|y|)| |#=| |B1|(|y|)|↵|#fun| |getB3|(|z|)| |#=| |getB2|(|z|)|↵|#fun| |getA| |#=| |A|(|x|)|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1(y,); class C(z,) {fun inc = () => +(x, 1,); fun getY = y; fun getA = A(z,); fun getB = (w,) => B(w,); fun getC = (new C)(inc(),); fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = (new B)(y,); fun getB1 = (new B1)(y,)}; fun getB = (new B)(x,); fun getB2 = (y,) => B1(y,); fun getB3 = (z,) => getB2(z,); fun getA = A(x,)}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], App(NuNew(Var(C)), Tup(_: App(Var(inc), Tup())))), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], App(NuNew(Var(B)), Tup(_: Var(y)))), NuFunDef(None, getB1, None, [], App(NuNew(Var(B1)), Tup(_: Var(y)))))), NuFunDef(None, getB, None, [], App(NuNew(Var(B)), Tup(_: Var(x)))), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2_C$4([par$A$1_B$2, z, x,]) { @@ -67,8 +66,7 @@ class A(x) { } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#class| |C|(|z|)| |{|→|#fun| |sum| |#=| |x| |+| |y| |+| |z|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {class C(z,) {fun sum = +(+(x, y,), z,)}}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, sum, None, [], App(Var(+), Tup(_: App(Var(+), Tup(_: Var(x), _: Var(y))), _: Var(z))))))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2_C$3([par$A$1_B$2, z, x,]) { @@ -106,9 +104,8 @@ new C{ fun bar = 17 } //│ |#class| |A|(|x|)| |{|→|#class| |B|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |11|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |2|↵|#fun| |bar| |#=| |12|←|↵|}|↵|#fun| |bar| |#=| |13|←|↵|}|↵|#class| |C|#:| |A|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |3|↵|#fun| |bar| |#=| |14|←|↵|}|↵|#fun| |bar| |#=| |15|←|↵|}|↵|#new| |C|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |4|↵|#fun| |bar| |#=| |16|←|↵|}|↵|#fun| |bar| |#=| |17|←|↵|}| -//│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B { ‹fun foo = 2; fun bar = 12› }; fun bar = 13}; class C: A {fun getB = new B { ‹fun foo = 3; fun bar = 14› }; fun bar = 15}; new C { ‹fun getB = new B { ‹fun foo = 4; fun bar = 16› }; fun bar = 17› }} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], Rft(NuNew(Var(B)), ...)), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], Rft(NuNew(Var(B)), ...)), NuFunDef(None, bar, None, [], IntLit(15)))), Rft(NuNew(Var(C)), ...)) +//│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B {fun foo = 2; fun bar = 12}; fun bar = 13}; class C: A {fun getB = new B {fun foo = 3; fun bar = 14}; fun bar = 15}; new C {fun getB = new B {fun foo = 4; fun bar = 16}; fun bar = 17}} +//│ //│ Lifted: //│ Lifting failed: mlscript.codegen.CodeGenError: Cannot find type B. Class values are not supported in lifter. //│ @@ -124,8 +121,7 @@ class Parent(x) { } //│ |#class| |Parent|‹|T|,| |U|,| |V|›|(|x|)| |{| |→|#fun| |foo|(|x|#:| |Int|)|#:| |T| |#=| |x|+|1|↵|#class| |Inner|‹|W|›|(|y|#:| |Int|)|{|→|#fun| |bar|(|z|#:| |U|)| |#=| |foo|(|y|)|↵|#fun| |boo|(|z|#:| |W|)| |#=| |z|←|↵|}|←|↵|}| //│ Parsed: {class Parent‹T, U, V›(x,) {fun foo = (x: Int,) => +(x, 1,) : T; class Inner‹W›(y: Int,) {fun bar = (z: U,) => foo(y,); fun boo = (z: W,) => z}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Parent, ((None,TypeName(T)), (None,TypeName(U)), (None,TypeName(V))), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(x: Var(Int)), Asc(App(Var(+), Tup(_: Var(x), _: IntLit(1))), TypeName(T)))), NuTypeDef(class, Inner, ((None,TypeName(W))), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(z: Var(U)), App(Var(foo), Tup(_: Var(y))))), NuFunDef(None, boo, None, [], Lam(Tup(z: Var(W)), Var(z)))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class Parent$1_Inner$2[W,U]([par$Parent$1, y: Int,]) { @@ -146,9 +142,8 @@ class A(x: Int): ({a1: Int} & B & D(x)) { } } //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |(|{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|)| |{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| -//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C { ‹fun foo = (x: T,) => x› }}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), Rft(NuNew(Var(C)), ...)))))) +//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C {fun foo = (x: T,) => x}}} +//│ //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -168,9 +163,8 @@ class A(x: Int) extends {a1: Int}, B, D(x){ } } //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)| |#extends| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| -//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C { ‹fun foo = (x,) => x› }}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), Rft(NuNew(Var(C)), ...)))))) +//│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C {fun foo = (x,) => x}}} +//│ //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -189,8 +183,7 @@ class Child(x): ({ age: T } & { name: String}) { } //│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |(|{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}|)| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| //│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner {fun foo = age}; fun bar = age; fun boo = new Inner}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], NuNew(Var(Inner)))))) +//│ //│ Lifted: //│ TypingUnit { //│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = () => (this).age} @@ -211,9 +204,8 @@ new A(0) { fun getA2 = 2 } //│ |#class| |A|(|x|#:| |Int|)| |{|→|#fun| |getA|#:| |Int| |#=| |0|↵|#fun| |getA1| |#=| |1|←|↵|}|↵|#new| |A|(|0|)| |{|→|#fun| |getA| |#=| |3|↵|#fun| |getA2| |#=| |2|←|↵|}| -//│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; (new A)(0,) { ‹fun getA = 3; fun getA2 = 2› }} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), Rft(App(NuNew(Var(A)), Tup(_: IntLit(0))), ...)) +//│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; (new A)(0,) {fun getA = 3; fun getA2 = 2}} +//│ //│ Lifted: //│ TypingUnit { //│ class A$1([x: Int,]) {fun getA = () => 0 : Int; fun getA1 = () => 1} @@ -232,9 +224,8 @@ new A(1) { } } //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{| |}|←|↵|}|↵|#new| |A|(|1|)| |{|→|#fun| |getB| |#=| |#new| |B|(|2|)|{|→|#fun| |getB| |#=| |#new| |B|(|3|)|←|↵|}|←|↵|}| -//│ Parsed: {class A(x,) {class B(y,) {}}; (new A)(1,) { ‹fun getB = (new B)(2,) { ‹fun getB = (new B)(3,)› }› }} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), Rft(App(NuNew(Var(A)), Tup(_: IntLit(1))), ...)) +//│ Parsed: {class A(x,) {class B(y,) {}}; (new A)(1,) {fun getB = (new B)(2,) {fun getB = (new B)(3,)}}} +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1, y,]) {} @@ -265,9 +256,8 @@ new B{ fun getA = funcB } //│ |#class| |A| |{|→|#fun| |getA| |#=| |0|↵|#fun| |funcA| |#=| |10|←|↵|}|↵|#class| |B|#:| |A|{|→|#fun| |getA| |#=| |1|↵|#fun| |funcB| |#=| |11|←|↵|}|↵|#new| |A|↵|#new| |B|↵|#fun| |f|(|x|)| |#=| |#if| |x| |is| |A| |#then| |0| |#else| |1|↵|f|(|#new| |A|{|→|#fun| |getA| |#=| |2|←|↵|}|)|↵|#new| |B|{|→|#fun| |getA| |#=| |funcB|←|↵|}| -//│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A; new B; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A { ‹fun getA = 2› },); new B { ‹fun getA = funcB› }} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), NuNew(Var(A)), NuNew(Var(B)), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: Rft(NuNew(Var(A)), ...))), Rft(NuNew(Var(B)), ...)) +//│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A; new B; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A {fun getA = 2},); new B {fun getA = funcB}} +//│ //│ Lifted: //│ TypingUnit { //│ class A$1([]) {fun getA = () => 0; fun funcA = () => 10} @@ -305,8 +295,7 @@ class A{ } //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000}; class F: E {fun funF = 5; fun foo = 1000000}}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000))))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {fun funB = () => 1; fun foo = () => 100} @@ -347,9 +336,8 @@ class A{ } } //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|↵|#fun| |getB| |#=| |#new| |B|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|↵|#fun| |getD| |#=| |#new| |D|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|↵|#fun| |getE| |#=| |#new| |E|{|→|#fun| |foo| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E { ‹fun foo = 0› }}}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], NuNew(Var(B))))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], NuNew(Var(D))))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], Rft(NuNew(Var(E)), ...))))))))) +//│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E {fun foo = 0}}}}} +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {fun funB = () => 1; fun foo = () => 100} @@ -383,8 +371,7 @@ class A{ new A //│ |#class| |A|{|→|#class| |B|{|→|#fun| |foo| |#=| |1|←|↵|}|↵|#fun| |bar| |#=| |#new| |B|←|↵|}|↵|#new| |A| //│ Parsed: {class A {class B {fun foo = 1}; fun bar = new B}; new A} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], NuNew(Var(B))))), NuNew(Var(A))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {fun foo = () => 1} @@ -407,9 +394,8 @@ let x = new A{ } } //│ |#class| |A|(|x|)| |{|→|#fun| |foo| |#=| |0|↵|#fun| |bar| |#=| |x|←|↵|}|↵|#let| |x| |#=| |#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |newFun| |#=| |2|↵|#fun| |bar| |#=| |#new| |A|(|foo|)|{|→|#fun| |foo| |#=| |bar| |+| |1|↵|#fun| |bar2| |#=| |newFun| |+| |1|←|↵|}|←|↵|}| -//│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A { ‹fun foo = 1; fun newFun = 2; fun bar = (new A)(foo,) { ‹fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)› }› }} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], Rft(NuNew(Var(A)), ...))) +//│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A {fun foo = 1; fun newFun = 2; fun bar = (new A)(foo,) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}}} +//│ //│ Lifted: //│ TypingUnit { //│ class A$1([x,]) {fun foo = () => 0; fun bar = () => (this).x} @@ -435,9 +421,8 @@ new A{ } } //│ |#class| |A| |{||}|↵|#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |#new| |A|{|→|#fun| |foo1| |#=| |foo|↵|#fun| |bar1| |#=| |#new| |A|{|→|#fun| |foo2| |#=| |foo|↵|#fun| |bar2| |#=| |#new| |A|{|→|#fun| |foo3| |#=| |foo|↵|#fun| |bar3| |#=| |#new| |A|{|→|#fun| |foo4| |#=| |foo|↵|#fun| |bar4| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}|←|↵|}| -//│ Parsed: {class A {}; new A { ‹fun foo = 1; fun bar = new A { ‹fun foo1 = foo; fun bar1 = new A { ‹fun foo2 = foo; fun bar2 = new A { ‹fun foo3 = foo; fun bar3 = new A { ‹fun foo4 = foo; fun bar4 = 0› }› }› }› }› }} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), Rft(NuNew(Var(A)), ...)) +//│ Parsed: {class A {}; new A {fun foo = 1; fun bar = new A {fun foo1 = foo; fun bar1 = new A {fun foo2 = foo; fun bar2 = new A {fun foo3 = foo; fun bar3 = new A {fun foo4 = foo; fun bar4 = 0}}}}}} +//│ //│ Lifted: //│ TypingUnit {class A$1([]) {}; Code(List(new A$1([]) {}))} //│ diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index 414d4109b4..61ac5eedfc 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -6,8 +6,7 @@ fun foo = print("ko") //│ |#fun| |foo| |#=|→|print|(|"ok"|)|↵|print|(|"ko"|)|←| //│ Parsed: {fun foo = {print("ok",); print("ko",)}} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) +//│ //│ Lifted: //│ TypingUnit {fun foo$1 = () => {print("ok",); print("ko",)}} //│ @@ -18,8 +17,7 @@ class A{ } //│ |#class| |A|{|→|#class| |B| |{||}|↵|#fun| |foo|(|x|#:| |B|)| |#=| |(|x| |#:| |B|)|←|↵|}| //│ Parsed: {class A {class B {}; fun foo = (x: B,) => '(' x : B ')'}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(x: Var(B)), Bra(rcd = false, Asc(Var(x), TypeName(B)))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1,]) {} @@ -40,8 +38,7 @@ fun foo = fun tmp = 2 //│ |#fun| |foo| |#=|→|#let| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| //│ Parsed: {fun foo = {let local = (x,) => {class Foo {fun bar = +(x, 1,)}; (Foo()).bar}; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); fun tmp = 1; print(local(+(0, local(1,),),),); fun tmp = 2}} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1([x,]) {fun bar = () => +((this).x, 1,)} @@ -55,9 +52,8 @@ class A(y){} let f = x => new A(0){fun bar = x+y} f(0) //│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |#=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| -//│ Parsed: {class A(y,) {}; let f = (x,) => (new A)(0,) { ‹fun bar = +(x, y,)› }; f(0,)} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), Rft(App(NuNew(Var(A)), Tup(_: IntLit(0))), ...))), App(Var(f), Tup(_: IntLit(0)))) +//│ Parsed: {class A(y,) {}; let f = (x,) => (new A)(0,) {fun bar = +(x, y,)}; f(0,)} +//│ //│ Lifted: //│ TypingUnit { //│ class A$1([y,]) {} @@ -78,9 +74,8 @@ class A(x){ } } //│ |#class| |A|(|x|)|{|→|#fun| |w| |#=| |x|↵|#fun| |foo|(|y|)| |#=| |→|#class| |B|(|z|)|{|→|#fun| |bar| |#=| |x|+|y|+|z|←|↵|}|↵|#new| |B|(|0|)|{|→|#fun| |bar| |#=| |w|+|y|+|z|←|↵|}|←|←|↵|}| -//│ Parsed: {class A(x,) {fun w = x; fun foo = (y,) => {class B(z,) {fun bar = +(+(x, y,), z,)}; (new B)(0,) { ‹fun bar = +(+(w, y,), z,)› }}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, w, None, [], Var(x)), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(y)), Blk(...)))))) +//│ Parsed: {class A(x,) {fun w = x; fun foo = (y,) => {class B(z,) {fun bar = +(+(x, y,), z,)}; (new B)(0,) {fun bar = +(+(w, y,), z,)}}}} +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1, z, y,]) { @@ -110,8 +105,7 @@ fun f(x,y,z) = } //│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#class| |C| |#extends| |A|,| |B| |{|→|#fun| |bar| |#=| |bar1| |+| |bar2|←|↵|}|←| //│ Parsed: {fun f = (x, y, z,) => {class A {fun foo = new B; fun bar1 = x}; class B {fun foo = new A; fun bar2 = y}; class C: A, B {fun bar = +(bar1, bar2,)}}} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1([x, y,]) { @@ -141,8 +135,7 @@ fun f(x,y,z) = } //│ |#fun| |f|(|x|,|y|,|z|)| |#=| |→|#class| |C|{|→|#class| |A|{|→|#fun| |foo| |#=| |#new| |B|↵|#fun| |bar1| |#=| |x|←|↵|}|↵|#class| |B|{|→|#fun| |foo| |#=| |#new| |A|↵|#fun| |bar2| |#=| |y|←|↵|}|↵|#fun| |boo| |#=| |(|#new| |A|)|.bar1| |+| |B|(||)|.bar2| |+| |z|←|↵|}|←| //│ Parsed: {fun f = (x, y, z,) => {class C {class A {fun foo = new B; fun bar1 = x}; class B {fun foo = new A; fun bar2 = y}; fun boo = +(+(('(' new A ')').bar1, (B()).bar2,), z,)}}} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x), _: Var(y), _: Var(z)), Blk(...)))) +//│ //│ Lifted: //│ TypingUnit { //│ class C$1_A$2([par$C$1,]) { @@ -167,8 +160,7 @@ fun f(y) = } //│ |#fun| |f|(|y|)| |#=|→|#let| |g|(|x|)| |#=| |x| |+| |y| |+| |1|↵|#class| |Foo|(|x|)| |{|→|#fun| |h| |#=| |g|(|x|)|←|↵|}|←| //│ Parsed: {fun f = (y,) => {let g = (x,) => +(+(x, y,), 1,); class Foo(x,) {fun h = g(x,)}}} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(y)), Blk(...)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1([x, y,]) {fun h = () => g$2((this).x, y,)} @@ -179,16 +171,14 @@ fun f(y) = Foo(1).h //│ | |Foo|(|1|)|.h| //│ Parsed: {(Foo(1,)).h} -//│ Parsed: -//│ TypingUnit(Sel(App(Var(Foo), Tup(_: IntLit(1))), h)) +//│ //│ Lifted: //│ TypingUnit {Code(List((Foo(1,)).h))} //│ Foo(x).h //│ | |Foo|(|x|)|.h| //│ Parsed: {(Foo(x,)).h} -//│ Parsed: -//│ TypingUnit(Sel(App(Var(Foo), Tup(_: Var(x))), h)) +//│ //│ Lifted: //│ TypingUnit {Code(List((Foo(x,)).h))} //│ @@ -203,8 +193,7 @@ fun f(x) = Foo(x, x).bar //│ |#fun| |f|(|x|)| |#=|→|#let| |g|(|x|)| |#=| |→|#let| |h|(|x|)| |#=| |x| |+| |2|↵|Foo|(|h|(|x|)|,| |x|)|.bar|←|↵|#class| |Foo|(|x|,| |y|)| |{|→|#fun| |bar| |#=| |g|(|x|)|+|y|←|↵|}|↵|Foo|(|x|,| |x|)|.bar|←| //│ Parsed: {fun f = (x,) => {let g = (x,) => {let h = (x,) => +(x, 2,); (Foo(h(x,), x,)).bar}; class Foo(x, y,) {fun bar = +(g(x,), y,)}; (Foo(x, x,)).bar}} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1([x, y,]) {fun bar = () => +(g$2((this).x,), (this).y,)} @@ -217,8 +206,7 @@ fun f(x) = class Foo(x, y) extends Bar(y, x), Baz(x + y) //│ |#class| |Foo|(|x|,| |y|)| |#extends| |Bar|(|y|,| |x|)|,| |Baz|(|x| |+| |y|)| //│ Parsed: {class Foo(x, y,): Bar(y, x,), Baz(+(x, y,),) {}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(_: Var(x), _: Var(y)), (App(Var(Bar), Tup(_: Var(y), _: Var(x))), App(Var(Baz), Tup(_: App(Var(+), Tup(_: Var(x), _: Var(y)))))), None, None, TypingUnit())) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1([x, y,]): Bar((this).y, (this).x,), Baz(+((this).x, (this).y,),) {} @@ -232,8 +220,7 @@ fun foo(x: T): string = "rua" //│ |#fun| |foo|‹|T|,| |U|›|(|x|#:| |T|)|#:| |string| |#=| |→|#class| |A|(|y|)| |#extends| |B|‹|T|›|,| |C|(|y|#:| |U|)| |{|→|#fun| |bar| |#=| |this|←|↵|}|↵|"rua"|←| //│ Parsed: {fun foo = (x: T,) => {class A(y,): B‹T›, C(y: U,) {fun bar = this}; "rua"} : string} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [TypeName(T), TypeName(U)], Lam(Tup(x: Var(T)), Asc(Blk(...), TypeName(string))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1[T,U]([y,]): B‹T›, C(y: U,) {fun bar = () => this} @@ -249,8 +236,7 @@ class A{ } //│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f| |#=| |x| |#=>| |y| |#=>| |x|↵|#fun| |g|#:| |T| |#=>| |B| |#=>| |T|←|↵|}|←|↵|}| //│ Parsed: {class A‹T› {class B {fun f = (x,) => (y,) => x; fun g: T -> B -> T}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x)))), NuFunDef(None, g, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1_B$2_Lambda1$1$3([par$A$1_B$2, x,]) {fun apply = (y,) => (this).x} @@ -269,8 +255,7 @@ class Foo{ } //│ |#class| |Foo|‹|T|›|{|→|#class| |RectangleBox|#:| |Box|‹|T|›| |&| |{| |breadth|#:| |T| |}|↵|#class| |StackedRectangleBoxes|‹|N|›| |#:| |RectangleBox|‹|T|›| |&| |{| |size|#:| |N| |}|↵|#class| |Bar|#:| |{|any|#:| |RectangleBox| |#=>| |StackedRectangleBoxes|}|←|↵|}| //│ Parsed: {class Foo‹T› {class RectangleBox: Box[T] & {breadth: T} {}; class StackedRectangleBoxes‹N›: RectangleBox[T] & {size: N} {}; class Bar: {any: RectangleBox -> StackedRectangleBoxes} {}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, RectangleBox, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, StackedRectangleBoxes, ((None,TypeName(N))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, Bar, (), Tup(), (), None, None, TypingUnit())))) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1_RectangleBox$2([par$Foo$1,]) {} @@ -291,9 +276,8 @@ fun ctx(a,b) = fun apply(x) = a+x }, b) //│ |#class| |Func|‹|T|,| |U|›| |{|→|#fun| |apply|#:| |T| |#=>| |U|←|↵|}|↵|#class| |Lambda|‹|T|,| |U|›| |#:| |Func|‹|T|,| |U|›| |{||}|↵|#fun| |ctx|(|a|,|b|)| |#=|→|#fun| |foo|(|f|#:| |Func|,| |x|)| |#=| |→|f|.apply|(|x|)|←|↵|foo|(|#new| |Lambda|{|→|#fun| |apply|(|x|)| |#=| |a|+|x|←|↵|}|,| |b|)|←| -//│ Parsed: {class Func‹T, U› {fun apply: T -> U}; class Lambda‹T, U›: Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply(x,)}; foo(new Lambda { ‹fun apply = (x,) => +(a, x,)› }, b,)}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Func, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),TypeName(U)))))), NuTypeDef(class, Lambda, ((None,TypeName(T)), (None,TypeName(U))), Tup(), (), None, None, TypingUnit()), NuFunDef(None, ctx, None, [], Lam(Tup(_: Var(a), _: Var(b)), Blk(...)))) +//│ Parsed: {class Func‹T, U› {fun apply: T -> U}; class Lambda‹T, U›: Func[T, U] {}; fun ctx = (a, b,) => {fun foo = (f: Func, x,) => {(f).apply(x,)}; foo(new Lambda {fun apply = (x,) => +(a, x,)}, b,)}} +//│ //│ Lifted: //│ TypingUnit { //│ class Func$1[T,U]([]) {fun apply = T -> U} @@ -308,8 +292,7 @@ fun f(T) = f(MyClass) //│ |#fun| |f|(|T|)| |#=| |→|#new| |T|(||)|←|↵|f|(|MyClass|)| //│ Parsed: {fun f = (T,) => {(new T)()}; f(MyClass,)} -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(T)), Blk(...))), App(Var(f), Tup(_: Var(MyClass)))) +//│ //│ Lifted: //│ Lifting failed: mlscript.codegen.CodeGenError: Cannot find type T. Class values are not supported in lifter. //│ @@ -321,8 +304,7 @@ class A { } //│ |#class| |A| |{|→|#fun| |foo| |#=| |→|#fun| |bar| |#=| |foo|(||)|↵|bar|(||)|←|←|↵|}| //│ Parsed: {class A {fun foo = {fun bar = foo(); bar()}}} -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Blk(...))))) +//│ //│ Lifted: //│ TypingUnit { //│ class A$1([]) {fun foo = () => {bar$1(this,)}} diff --git a/compiler/shared/test/diff/mono.mls b/compiler/shared/test/diff/mono.mls index 780851b8a1..a261d75d03 100644 --- a/compiler/shared/test/diff/mono.mls +++ b/compiler/shared/test/diff/mono.mls @@ -3,8 +3,7 @@ :mono fun f(x: Int) = if x then 42 else 1337 -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(x: Var(Int)), If(IfThen(Var(x), IntLit(42), Some(IntLit(1337)))))) +//│ //│ Lifted: //│ TypingUnit { //│ fun f$1 = (x: Int,) => if (x) then 42 else 1337 @@ -18,8 +17,7 @@ fun f(x: Int) = if x then 42 else 1337 :mono fun foo() = 42 -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), IntLit(42)))) +//│ //│ Lifted: //│ TypingUnit {fun foo$1 = () => 42} //│ Mono: @@ -33,8 +31,7 @@ fun foo() = 42 fun foo(x, #b) = if b then x else 1337 let a = foo(42, true) let b = foo(23, false) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x), _: Var(b)), If(IfThen(Var(b), Var(x), Some(IntLit(1337))))), NuFunDef(Some(false), a, None, [], App(Var(foo), Tup(_: IntLit(42), _: Var(true)))), NuFunDef(Some(false), b, None, [], App(Var(foo), Tup(_: IntLit(23), _: Var(false))))) +//│ //│ Lifted: //│ TypingUnit { //│ fun foo$3 = (x, #b,) => if (b) then x else 1337 @@ -60,8 +57,7 @@ let b = foo(23, false) :mono let x = 42 + 1337 -//│ Parsed: -//│ TypingUnit(NuFunDef(Some(false), x, None, [], App(Var(+), Tup(_: IntLit(42), _: IntLit(1337))))) +//│ //│ Lifted: //│ TypingUnit {let x$1 = () => +(42, 1337,)} //│ Mono: @@ -98,8 +94,7 @@ let x = 42 + 1337 :mono if true then 1 else 0 if 1+1 > 1 then 1 - 1 else 1*1 -//│ Parsed: -//│ TypingUnit(If(IfThen(Var(true), IntLit(1), Some(IntLit(0))), If(IfThen(App(Var(>), Tup(_: App(Var(+), Tup(_: IntLit(1), _: IntLit(1))), _: IntLit(1))), App(Var(-), Tup(_: IntLit(1), _: IntLit(1))), Some(App(Var(*), Tup(_: IntLit(1), _: IntLit(1)))))) +//│ //│ Lifted: //│ TypingUnit { //│ Code(List(if (true) then 1 else 0)) @@ -122,8 +117,7 @@ if 1+1 > 1 then 1 - 1 else 1*1 :mono if(b) then 1 else 2 -//│ Parsed: -//│ TypingUnit(If(IfThen(Bra(rcd = false, Var(b)), IntLit(1), Some(IntLit(2)))) +//│ //│ Lifted: //│ TypingUnit {Code(List(if ('(' b ')') then 1 else 2))} //│ Mono: @@ -138,8 +132,7 @@ if(b) then 1 else 2 :mono ((f, g) => f(g))(f => f, true) -//│ Parsed: -//│ TypingUnit(App(Bra(rcd = false, Lam(Tup(_: Var(f), _: Var(g)), App(Var(f), Tup(_: Var(g))))), Tup(_: Lam(Tup(_: Var(f)), Var(f)), _: Var(true)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Lambda2$1$1([]) {fun apply = (f, g,) => f(g,)} @@ -167,8 +160,7 @@ if(b) then 1 else 2 :mono (b => if b then true else false) (true) -//│ Parsed: -//│ TypingUnit(App(Bra(rcd = false, Lam(Tup(_: Var(b)), If(IfThen(Var(b), Var(true), Some(Var(false))))), Tup(_: Var(true)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Lambda1$1$1([]) {fun apply = (b,) => if (b) then true else false} @@ -192,8 +184,7 @@ if(b) then 1 else 2 fun f(x) = if(x > 0) then x+1 else x - 1 f(2)+3 -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(+), Tup(_: App(Var(f), Tup(_: IntLit(2))), _: IntLit(3)))) +//│ //│ Lifted: //│ TypingUnit { //│ fun f$1 = (x,) => {if ('(' >(x, 0,) ')') then +(x, 1,) else -(x, 1,)} @@ -216,8 +207,7 @@ f(2)+3 fun fac(n) = if (n > 1) then fac(n - 1) * n else 1 fac(2) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, fac, None, [], Lam(Tup(_: Var(n)), Blk(...))), App(Var(fac), Tup(_: IntLit(2)))) +//│ //│ Lifted: //│ TypingUnit { //│ fun fac$1 = (n,) => {if ('(' >(n, 1,) ')') then *(fac$1(-(n, 1,),), n,) else 1} @@ -245,8 +235,7 @@ fun count(lst) = if l is undefined then 1 else count(l)+1 else 0 count(new List(new List(new Nil(undefined, false), true), true)) -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, count, None, [], Lam(Tup(_: Var(lst)), Blk(...))), App(Var(count), Tup(_: App(NuNew(Var(List)), Tup(_: App(NuNew(Var(List)), Tup(_: App(NuNew(Var(Nil)), Tup(_: UnitLit(true), _: Var(false))), _: Var(true))), _: Var(true)))))) +//│ //│ Lifted: //│ TypingUnit { //│ class List$1([val l: |(|(List, Nil,), undefined,), val hasTail: Bool,]) {} @@ -302,8 +291,7 @@ class Nil() { } fun add2(x) = x+2 (new List(1, new List(2, new Nil()))).map(x => x+1).map(x => add2(x)) -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, map, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(Int))))),TypeName(Int)))))),TypeName(List)))), NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), App(NuNew(Var(List)), Tup(_: App(Var(f), Tup(_: Var(e))), _: App(Sel(Var(tail), map), Tup(_: Var(f))))))), NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), Var(this))), NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, add2, None, [], Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))), App(Sel(App(Sel(Bra(rcd = false, App(NuNew(Var(List)), Tup(_: IntLit(1), _: App(NuNew(Var(List)), Tup(_: IntLit(2), _: App(NuNew(Var(Nil)), Tup())))))), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1)))))), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(add2), Tup(_: Var(x))))))) +//│ //│ Lifted: //│ TypingUnit { //│ class List$1([e: Int, tail: |(List, Nil,),]) { @@ -369,8 +357,7 @@ fun generate(x) = if x > 0 then new List(x, generate(x+1)) else new Nil() foo(new List(1, new List(2, new Nil()))) foo(generate(1)) -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), App(Sel(Var(x), count), Tup()))), NuFunDef(None, generate, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: App(NuNew(Var(List)), Tup(_: IntLit(1), _: App(NuNew(Var(List)), Tup(_: IntLit(2), _: App(NuNew(Var(Nil)), Tup()))))))), App(Var(foo), Tup(_: App(Var(generate), Tup(_: IntLit(1)))))) +//│ //│ Lifted: //│ TypingUnit { //│ class List$1([e: Int, tail: |(List, Nil,),]) { @@ -423,8 +410,7 @@ foo(generate(1)) fun foo(x) = (f => f(x))(z => z+1) foo(2) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: IntLit(2)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Lambda1$2$1([x,]) {fun apply = (f,) => f((this).x,)} @@ -457,8 +443,7 @@ foo(2) fun f(x) = (y => f(x+y))(x+1) f(1) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(f), Tup(_: IntLit(1)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Lambda1$2$1([x,]) {fun apply = (y,) => f$1(+((this).x, y,),)} @@ -488,8 +473,7 @@ f(1) fun f(x) = f(x) f(0) f(1) -//│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), App(Var(f), Tup(_: Var(x))))), App(Var(f), Tup(_: IntLit(0))), App(Var(f), Tup(_: IntLit(1)))) +//│ //│ Lifted: //│ TypingUnit { //│ fun f$1 = (x,) => f$1(x,) @@ -536,8 +520,7 @@ fun foo(x) = x.apply(new Cons(1, new Nil())) + x.apply(new Nil()) foo(new Lambda()) foo(new Lambda2(2)) -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var('A), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuTypeDef(class, Lambda, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuTypeDef(class, Lambda2, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: App(NuNew(Var(Lambda)), Tup()))), App(Var(foo), Tup(_: App(NuNew(Var(Lambda2)), Tup(_: IntLit(2)))))) +//│ //│ Lifted: //│ TypingUnit { //│ class Cons$1([e: 'A, tail: |(Cons, Nil,),]) { @@ -611,8 +594,7 @@ fun foo(x) = x(new Cons(1, new Nil())) + x(new Nil()) foo(l => l.count()) foo(l => (new Cons(2, l)).count()) -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Var(l), count), Tup())))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Bra(rcd = false, App(NuNew(Var(Cons)), Tup(_: IntLit(2), _: Var(l)))), count), Tup()))))) +//│ //│ Lifted: //│ TypingUnit { //│ class Cons$1([e: Int, tail: |(Cons, Nil,),]) { @@ -706,8 +688,7 @@ class C(e1: Exp, e2: Exp) extends Exp { e1.isEmpty() && e2.isEmpty() } (new C(new Ch(1), new A(new Ch(2), new Ch(3)))).derive(0).isEmpty() -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Exp, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, derive, None, [], PolyType(List(),Function(Tuple(List((Some(x),Field(None,TypeName(Int))))),TypeName(Exp)))), NuFunDef(None, derive, None, [], Lam(Tup(x: Var(Int)), App(Var(Exp), Tup()))), NuFunDef(None, isEmpty, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Bool)))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Var(false))))), NuTypeDef(class, E, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ep, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ch, (), Tup(i: Var(Int)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, A, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, C, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), App(Sel(App(Sel(Bra(rcd = false, App(NuNew(Var(C)), Tup(_: App(NuNew(Var(Ch)), Tup(_: IntLit(1))), _: App(NuNew(Var(A)), Tup(_: App(NuNew(Var(Ch)), Tup(_: IntLit(2))), _: App(NuNew(Var(Ch)), Tup(_: IntLit(3)))))))), derive), Tup(_: IntLit(0))), isEmpty), Tup())) +//│ //│ Lifted: //│ TypingUnit { //│ class Exp$1([]) { @@ -808,8 +789,7 @@ class Nil(hasTail: Bool) {} fun gen() = if anyUnknown then new List(gen(), true) else new Nil(false) gen() -//│ Parsed: -//│ TypingUnit(NuFunDef(Some(false), anyUnknown, None, [], Var(false)), NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: Var(List), _: Var(Nil))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, gen, None, [], Lam(Tup(), Blk(...))), App(Var(gen), Tup())) +//│ //│ Lifted: //│ TypingUnit { //│ class List$1([l: |(List, Nil,), hasTail: Bool,]) {} @@ -850,8 +830,7 @@ class Foo(x: Int){ fun boo(z) = bar(z)+x } (new Foo(1)).boo(2) -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(y)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, boo, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: App(Var(bar), Tup(_: Var(z))), _: Var(x))))))), App(Sel(Bra(rcd = false, App(NuNew(Var(Foo)), Tup(_: IntLit(1)))), boo), Tup(_: IntLit(2)))) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1([x: Int,]) { @@ -887,8 +866,7 @@ class OneInt(a: Int){ if(a > 0) then (new OneInt(a - 1)).fac() else 1 } (new OneInt(10)).fac() -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, fac, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, fac, None, [], Lam(Tup(), Blk(...))))), App(Sel(Bra(rcd = false, App(NuNew(Var(OneInt)), Tup(_: IntLit(10)))), fac), Tup())) +//│ //│ Lifted: //│ TypingUnit { //│ class OneInt$1([a: Int,]) { @@ -937,8 +915,7 @@ fun g(x) = if x > any then g(x - 1) else f(x - 2) g(1) -//│ Parsed: -//│ TypingUnit(NuFunDef(Some(false), any, None, [], IntLit(-20)), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, g, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(g), Tup(_: IntLit(1)))) +//│ //│ Lifted: //│ TypingUnit { //│ let any$3 = () => -20 @@ -976,8 +953,7 @@ class OneBool(b: Bool){ fun get = () -> b } (if b then new OneInt(1) else new OneBool(true)).get() -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, OneBool, (), Tup(b: Var(Bool)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(b))))), App(Sel(Bra(rcd = false, If(IfThen(Var(b), App(NuNew(Var(OneInt)), Tup(_: IntLit(1))), Some(App(NuNew(Var(OneBool)), Tup(_: Var(true)))))), get), Tup())) +//│ //│ Lifted: //│ TypingUnit { //│ class OneInt$1([a: Int,]) {fun get = () => (this).a} @@ -1022,8 +998,7 @@ let bar = Bar(42) baz(bar) (new Car()).da(Bar(1337)) bar.car -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Bar, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x))), NuFunDef(None, FooMinus, None, [], Lam(Tup(y: Var(Int)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, car, None, [], App(Var(foo), Tup(_: IntLit(2)))))), NuTypeDef(class, Car, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, da, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))))), NuFunDef(None, baz, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))), NuFunDef(Some(false), bar, None, [], App(Var(Bar), Tup(_: IntLit(42)))), App(Var(baz), Tup(_: Var(bar))), App(Sel(Bra(rcd = false, App(NuNew(Var(Car)), Tup())), da), Tup(_: App(Var(Bar), Tup(_: IntLit(1337))))), Sel(Var(bar), car)) +//│ //│ Lifted: //│ TypingUnit { //│ class Bar$1([x: Int,]) { @@ -1093,8 +1068,7 @@ class Sub2(c: Int) extends Sub(c+c){ } (new Sub(10)).foo() (new Sub2(c)).foo() -//│ Parsed: -//│ TypingUnit(NuFunDef(Some(false), c, None, [], IntLit(5)), NuTypeDef(class, Sup, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, Sub, (), Tup(b: Var(Int)), (App(Var(Sup), Tup(_: App(Var(+), Tup(_: Var(b), _: Var(b)))))), None, None, TypingUnit()), NuTypeDef(class, Sub2, (), Tup(c: Var(Int)), (App(Var(Sub), Tup(_: App(Var(+), Tup(_: Var(c), _: Var(c)))))), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(a), _: Var(c))))))), App(Sel(Bra(rcd = false, App(NuNew(Var(Sub)), Tup(_: IntLit(10)))), foo), Tup()), App(Sel(Bra(rcd = false, App(NuNew(Var(Sub2)), Tup(_: Var(c)))), foo), Tup())) +//│ //│ Lifted: //│ TypingUnit { //│ class Sup$1([a: Int,]) {fun foo = () => (this).a} @@ -1151,8 +1125,7 @@ class F1() extends Foo(x => x+1){} class F2() extends Foo(x => x+2){} (new F1()).foo() (new F2()).foo() -//│ Parsed: -//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(f: App(Var(->), Tup(_: Var(Int), _: Var(Int)))), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(f), Tup(_: IntLit(1))))))), NuTypeDef(class, F1, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))), None, None, TypingUnit()), NuTypeDef(class, F2, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))))), None, None, TypingUnit()), App(Sel(Bra(rcd = false, App(NuNew(Var(F1)), Tup())), foo), Tup()), App(Sel(Bra(rcd = false, App(NuNew(Var(F2)), Tup())), foo), Tup())) +//│ //│ Lifted: //│ TypingUnit { //│ class Foo$1([f: ->(Int, Int,),]) {fun foo = () => (this).f(1,)} diff --git a/compiler/shared/test/scala/mlscript/compiler/Test.scala b/compiler/shared/test/scala/mlscript/compiler/Test.scala index e0df0d8f00..7f4c816981 100644 --- a/compiler/shared/test/scala/mlscript/compiler/Test.scala +++ b/compiler/shared/test/scala/mlscript/compiler/Test.scala @@ -3,7 +3,6 @@ package mlscript.compiler import mlscript.utils.shorthands.* import scala.util.control.NonFatal import scala.collection.mutable.StringBuilder -import mlscript.codegen.Helpers.inspect as showStructure import mlscript.{DiffTests, ModeType, TypingUnit} import mlscript.compiler.debug.TreeDebug import mlscript.compiler.mono.Monomorph @@ -14,8 +13,6 @@ class DiffTestCompiler extends DiffTests { import DiffTestCompiler.* override def postProcess(mode: ModeType, basePath: List[Str], testName: Str, unit: TypingUnit): List[Str] = val outputBuilder = StringBuilder() - outputBuilder ++= "Parsed:\n" - outputBuilder ++= showStructure(unit) outputBuilder ++= "\nLifted:\n" var rstUnit = unit; diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index ddca1a2799..af39640d95 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -1,7 +1,6 @@ package mlscript import mlscript.utils._, shorthands._, algorithms._ -import mlscript.codegen.Helpers._ import mlscript.codegen._ import scala.collection.mutable.{ListBuffer, HashMap, HashSet} import mlscript.{JSField, JSLit} @@ -69,7 +68,7 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { case Inst(bod) => translatePattern(bod) case _: Lam | _: App | _: Sel | _: Let | _: Blk | _: Bind | _: Test | _: With | _: CaseOf | _: Subs | _: Assign | If(_, _) | New(_, _) | NuNew(_) | _: Splc | _: Forall | _: Where | _: Super | _: Eqn | _: AdtMatchWith | _: Rft => - throw CodeGenError(s"term ${inspect(t)} is not a valid pattern") + throw CodeGenError(s"term $t is not a valid pattern") } private def translateParams(t: Term)(implicit scope: Scope): Ls[JSPattern] = t match { @@ -172,7 +171,7 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { } callee(args map { case (_, Fld(_, arg)) => translateTerm(arg) }: _*) case App(trm, splice) => ??? // TODO represents `trm(...splice)` - case _ => throw CodeGenError(s"ill-formed application ${inspect(term)}") + case _ => throw CodeGenError(s"ill-formed application $term") } /** @@ -297,7 +296,7 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { case _: Subs | _: Sel | _: Var => JSCommaExpr(JSAssignExpr(translateTerm(lhs), translateTerm(value)) :: JSArray(Nil) :: Nil) case _ => - throw CodeGenError(s"illegal assignemnt left-hand side: ${inspect(lhs)}") + throw CodeGenError(s"illegal assignemnt left-hand side: $lhs") } case Inst(bod) => translateTerm(bod) case iff: If => @@ -310,7 +309,7 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { case n: JSNew => n case t => JSNew(t) } - case _ => throw CodeGenError(s"Unsupported `new` class term: ${inspect(cls)}") + case _ => throw CodeGenError(s"Unsupported `new` class term: $cls") } // * Would not be quite correct: // JSNew(translateTerm(cls)) @@ -328,7 +327,7 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { case Eqn(Var(name), _) => throw CodeGenError(s"assignment of $name is not supported outside a constructor") case _: Bind | _: Test | If(_, _) | _: Splc | _: Where | _: AdtMatchWith | _: Rft => - throw CodeGenError(s"cannot generate code for term ${inspect(term)}") + throw CodeGenError(s"cannot generate code for term $term") } private def translateCaseBranch(scrut: JSExpr, branch: CaseBranches)(implicit @@ -369,7 +368,7 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { } } case lit: Lit => - JSBinary("===", scrut, JSLit(lit.idStr)) + JSBinary("===", scrut, translateTerm(lit)) }, _, _ diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8eb2bdf2d6..8d97dc0006 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -560,7 +560,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case fd @ NuFunDef(_, nme, snme, tparams, R(rhs)) => funSigs.updateWith(nme.name) { case S(s) => - err(s"A type signature for '$nme' was already given", fd.toLoc) + err(s"A type signature for '${nme.name}' was already given", fd.toLoc) S(s) case N => S(fd) } diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 1ba8909896..3a3e5d15d4 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -1380,7 +1380,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne // () // and others case pat => - lastWords(s"Cannot handle pattern ${pat}") + lastWords(s"Cannot handle pattern ${pat.showDbg}") } handlePat(pat, cond_ty) diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 121184b93a..5fc80392a6 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -240,7 +240,7 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => RecordType(fields.filterNot(f => shadowing(f._1)) ++ fs)(prov) } def sorted: RecordType = RecordType(fields.sortBy(_._1))(prov) - override def toString = s"{${fields.map(f => s"${f._1}: ${f._2}").mkString(", ")}}" + override def toString = s"{${fields.map(f => s"${f._1.name}: ${f._2}").mkString(", ")}}" } object RecordType { def empty: RecordType = RecordType(Nil)(noProv) diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala deleted file mode 100644 index 5bade531b9..0000000000 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ /dev/null @@ -1,100 +0,0 @@ -package mlscript.codegen - -import mlscript._, mlscript.utils.shorthands._ -import scala.collection.immutable.{Map, Set} - -object Helpers { - /** - * Show how a term is actually structured. - */ - def inspect(t: Terms): Str = t match { - case Var(name) => s"Var($name)" - case Lam(lhs, rhs) => s"Lam(${inspect(lhs)}, ${inspect(rhs)})" - case App(lhs, rhs) => s"App(${inspect(lhs)}, ${inspect(rhs)})" - case Tup(fields) => - val entries = fields map { - case (S(name), Fld(_, value)) => s"$name: ${inspect(value)}" - case (N, Fld(_, value)) => s"_: ${inspect(value)}" - } - s"Tup(${entries mkString ", "})" - case Rcd(fields) => - val entries = fields.iterator - .map { case k -> Fld(_, v) => s"${inspect(k)} = ${inspect(v)}" } - .mkString(", ") - s"Rcd($entries)" - case Sel(receiver, fieldName) => s"Sel(${inspect(receiver)}, $fieldName)" - case Let(isRec, name, rhs, body) => s"Let($isRec, $name, ${inspect(rhs)}, ${inspect(body)})" - case Blk(stmts) => s"Blk(...)" - case Bra(rcd, trm) => s"Bra(rcd = $rcd, ${inspect(trm)})" - case Asc(trm, ty) => s"Asc(${inspect(trm)}, $ty)" - case Bind(lhs, rhs) => s"Bind(${inspect(lhs)}, ${inspect(rhs)})" - case Test(trm, ty) => s"Test(${inspect(trm)}, ${inspect(ty)})" - case With(trm, fields) => - s"With(${inspect(trm)}, ${inspect(fields)})" - case CaseOf(trm, cases) => - def inspectCaseBranches(br: CaseBranches): Str = br match { - case Case(clsNme, body, rest) => - s"Case($clsNme, ${inspect(body)}, ${inspectCaseBranches(rest)})" - case Wildcard(body) => s"Wildcard(${inspect(body)})" - case NoCases => "NoCases" - } - s"CaseOf(${inspect(trm)}, ${inspectCaseBranches(cases)}" - case IntLit(value) => s"IntLit($value)" - case DecLit(value) => s"DecLit($value)" - case StrLit(value) => s"StrLit($value)" - case UnitLit(value) => s"UnitLit($value)" - case Subs(arr, idx) => s"Subs(${inspect(arr)}, ${inspect(idx)})" - case Assign(f, v) => s"Assign(${inspect(f)}, ${inspect(v)})" - case Splc(fs) => - val elems = fs.map{case L(l) => s"...${inspect(l)}" case R(Fld(_, r)) => inspect(r)}.mkString(", ") - s"Splc($elems)" - case If(bod, els) => s"If(${inspect(bod)}, ${els.map(inspect)})" - case New(base, body) => s"New(${base}, ${inspect(body)})" - case NuNew(base) => s"NuNew(${inspect(base)})" - case TyApp(base, targs) => s"TyApp(${inspect(base)}, ${targs})" - case Def(rec, nme, rhs, isByname) => - s"Def($rec, $nme, ${rhs.fold(inspect, "" + _)}, $isByname)" - case Where(bod, sts) => s"Where(${inspect(bod)}, ...)" - case Forall(ps, bod) => s"Forall($ps, ${inspect(bod)})" - case Inst(bod) => s"Inst(${inspect(bod)})" - case Eqn(lhs, rhs) => s"Eqn(${inspect(lhs)}, ${inspect(rhs)})" - case Super() => "Super()" - case AdtMatchWith(cond, arms) => - s"match ${inspect(cond)} with ${arms.map(patmat => s"${inspect(patmat.pat)} -> ${inspect(patmat.rhs)}").mkString(" | ")}" - case Rft(bse, tu) => s"Rft(${inspect(bse)}, ...)" - } - - def inspect(body: IfBody): Str = body match { - case IfElse(expr) => s"IfElse(${inspect(expr)}" - case IfThen(expr, rhs) => s"IfThen(${inspect(expr)}, ${inspect(rhs)}" - case IfBlock(lines) => s"IfBlock(${ - lines.iterator.map { - case L(body) => inspect(body) - case R(NuFunDef(S(isRec), nme, _, _, L(rhs))) => - s"Let($isRec, ${nme.name}, ${inspect(rhs)})" - case R(_) => ??? - }.mkString(";") - })" - case IfOpsApp(lhs, opsRhss) => s"IfOpsApp(${inspect(lhs)}, ${ - opsRhss.iterator.map { case (op, body) => - s"$op -> ${inspect(body)}" - } - }".mkString("; ") - case IfLet(isRec, name, rhs, body) => ??? - case IfOpApp(lhs, op, rhs) => - s"IfOpApp(${inspect(lhs)}, ${inspect(op)}, ${inspect(rhs)}" - } - def inspect(t: TypingUnit): Str = t.entities.iterator - .map { - case term: Term => inspect(term) - case NuFunDef(lt, nme, symNme, targs, L(term)) => - s"NuFunDef(${lt}, ${nme.name}, $symNme, ${targs.mkString("[", ", ", "]")}, ${inspect(term)})" - case NuFunDef(lt, nme, symNme, targs, R(ty)) => - s"NuFunDef(${lt}, ${nme.name}, $symNme, ${targs.mkString("[", ", ", "]")}, $ty)" - case NuTypeDef(kind, nme, tparams, params, ctor, sig, parents, sup, ths, body) => - s"NuTypeDef(${kind.str}, ${nme.name}, ${tparams.mkString("(", ", ", ")")}, ${ - inspect(params.getOrElse(Tup(Nil)))}, ${parents.map(inspect).mkString("(", ", ", ")")}, $sup, $ths, ${inspect(body)})" - case others => others.toString() - } - .mkString("TypingUnit(", ", ", ")") -} diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index cb069e47c8..b6154bd409 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -101,7 +101,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case AppliedType(n, args) => s"${n.name}${args.map(_.showIn(ctx, 0)).mkString(ctx.<, ", ", ctx.>)}" case Selection(b, n) => b.showIn(ctx, 100) + "." + n.name - case Rem(b, ns) => s"${b.showIn(ctx, 90)}${ns.map("\\"+_).mkString}" + case Rem(b, ns) => s"${b.showIn(ctx, 90)}${ns.map("\\"+_.name).mkString}" case Literal(IntLit(n)) => n.toString case Literal(DecLit(n)) => n.toString case Literal(StrLit(s)) => "\"" + s + "\"" @@ -173,7 +173,7 @@ trait TypeLikeImpl extends Located { self: TypeLike => case _ => "" }}${sig.fold("")(": " + _.showIn(bodyCtx, 0))}${parents match { case Nil => "" - case ps => " extends " + ps.mkString(", ") // TODO pp parent terms... + case ps => " extends " + ps.iterator.map(_.print(false)).mkString(", ") // TODO pp parent terms... }}${if (body.entities.isEmpty && sup.isEmpty && ths.isEmpty) "" else " {\n" + sup.fold("")(s"${bodyCtx.indStr}super: " + _.showIn(bodyCtx, 0) + "\n") + ths.fold("")(s"${bodyCtx.indStr}this: " + _.showIn(bodyCtx, 0) + "\n") + @@ -386,7 +386,8 @@ trait PgrmImpl { self: Pgrm => } diags.toList -> res } - override def toString = tops.map("" + _ + ";").mkString(" ") + + def showDbg: Str = tops.iterator.map("" + _.showDbg + ";").mkString(" ") } object OpApp { @@ -401,18 +402,16 @@ object OpApp { trait DeclImpl extends Located { self: Decl => val body: Located def showBody: Str = this match { - case Def(_, _, rhs, isByname) => rhs.fold(_.toString, _.showDbg2) + case d: Def => d.rhs.fold(_.showDbg, _.showDbg2) case td: TypeDef => td.body.showDbg2 } def describe: Str = this match { case _: Def => "definition" case _: TypeDef => "type declaration" } - def showDbg: Str = showHead + (this match { - case TypeDef(Als, _, _, _, _, _, _, _) => " = "; case _ => ": " }) + showBody def showHead: Str = this match { - case Def(true, n, b, isByname) => s"rec def $n" - case Def(false, n, b, isByname) => s"def $n" + case Def(true, n, b, isByname) => s"rec def ${n.showDbg}" + case Def(false, n, b, isByname) => s"def ${n.showDbg}" case TypeDef(k, n, tps, b, _, _, pos, _) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_.name).mkString("[", ", ", "]")}${ if (pos.isEmpty) "" else pos.mkString("(", ", ", ")") @@ -434,27 +433,22 @@ trait NuDeclImpl extends Located { self: NuDecl => } def name: Str = nameVar.name def showBody: Str = this match { - case NuFunDef(_, _, _, _, rhs) => rhs.fold(_.toString, _.showDbg2) + case fd: NuFunDef => fd.rhs.fold(_.print(false), _.showDbg2) case td: NuTypeDef => td.body.showDbg } def describe: Str = this match { case _: NuFunDef => "definition" case _: NuTypeDef => "type declaration" } - def showDbg: Str = showHead + (this match { - case NuFunDef(_, _, _, _, L(_)) => " = " - case NuFunDef(_, _, _, _, R(_)) => ": " - case _: NuTypeDef => " " - }) + showBody def showHead: Str = this match { - case NuFunDef(N, n, snme, _, b) => s"fun${snme.fold("")(" ("+_+")")} $n" - case NuFunDef(S(false), n, snme, _, b) => s"let${snme.fold("")(" "+_+")")} $n" - case NuFunDef(S(true), n, snme, _, b) => s"let rec${snme.fold("")(" "+_+")")} $n" + case NuFunDef(N, n, snme, _, b) => s"fun${snme.fold("")(" ("+_.name+")")} ${n.name}" + case NuFunDef(S(false), n, snme, _, b) => s"let${snme.fold("")(" "+_.name+")")} ${n.name}" + case NuFunDef(S(true), n, snme, _, b) => s"let rec${snme.fold("")(" "+_.name+")")} ${n.name}" case NuTypeDef(k, n, tps, sps, ctor, sig, parents, sup, ths, bod) => s"${k.str} ${n.name}${if (tps.isEmpty) "" else tps.map(_._2.name).mkString("‹", ", ", "›")}${ sps.fold("")("(" + _.showElems + ")") }${sig.fold("")(": " + _.showDbg2)}${ - if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.mkString(", ")}" + if (parents.isEmpty) "" else if (k === Als) " = " else ": "}${parents.iterator.map(_.showDbg).mkString(", ")}" } lazy val genUnapply: Opt[NuFunDef] = this match { case td: NuTypeDef if td.kind is Cls => td.params.map { tup => @@ -472,13 +466,13 @@ trait NuDeclImpl extends Located { self: NuDecl => } trait TypingUnitImpl extends Located { self: TypingUnit => - def showDbg: Str = entities.map { - case t: Term => t.toString + def showDbg: Str = entities.iterator.map { + case t: Term => t.print(false) case d: NuDecl => d.showDbg - case c: Constructor => c.toString + case c: Constructor => c.showDbg case e => lastWords(s"Unexpected typing unit entity: $e") }.mkString("{", "; ", "}") - override def toString: String = s"‹${entities.mkString("; ")}›" + lazy val children: List[Located] = entities } @@ -495,6 +489,15 @@ trait TypeNameImpl extends Ordered[TypeName] { self: TypeName => lazy val toVar: Var = Var(name).withLocOf(this) } +trait FldFlagsImpl extends Located { self: FldFlags => + def children: Ls[Located] = Nil + override def toString(): String = { + val FldFlags(m, s, g) = this + val res = (if (m) "m" else "") + (if (s) "s" else "") + (if (g) "g" else "") + if (res.isEmpty) "_" else res + } +} + trait FldImpl extends Located { self: Fld => def children: Ls[Located] = self.value :: Nil def describe: Str = @@ -561,31 +564,31 @@ trait TermImpl extends StatementImpl { self: Term => case AdtMatchWith(cond, arms) => "ADT pattern matching" } } - - override def toString: Str = print(false) + + override def showDbg: Str = print(false) def print(brackets: Bool): Str = { def bra(str: Str): Str = if (brackets) s"($str)" else str this match { - case Bra(true, trm) => s"'{' $trm '}'" - case Bra(false, trm) => s"'(' $trm ')'" - case Blk(stmts) => stmts.mkString("{", "; ", "}") + case Bra(true, trm) => s"'{' ${trm.showDbg} '}'" + case Bra(false, trm) => s"'(' ${trm.showDbg} ')'" + case Blk(stmts) => stmts.iterator.map(_.showDbg).mkString("{", "; ", "}") case IntLit(value) => value.toString case DecLit(value) => value.toString case StrLit(value) => '"'.toString + value + '"' case UnitLit(value) => if (value) "undefined" else "null" case v @ Var(name) => name + v.uid.fold("")("::"+_.toString) - case Asc(trm, ty) => s"$trm : ${ty.showDbg2}" |> bra - case Lam(pat: Tup, rhs) => s"(${pat.showElems}) => $rhs" |> bra - case Lam(pat, rhs) => s"(...$pat) => $rhs" |> bra + case Asc(trm, ty) => s"${trm.showDbg} : ${ty.showDbg2}" |> bra + case Lam(pat: Tup, rhs) => s"(${pat.showElems}) => ${rhs.showDbg}" |> bra + case Lam(pat, rhs) => s"(...${pat.showDbg}) => ${rhs.showDbg}" |> bra case App(lhs, rhs: Tup) => s"${lhs.print(!lhs.isInstanceOf[App])}(${rhs.showElems})" |> bra case App(lhs, rhs) => s"${lhs.print(!lhs.isInstanceOf[App])}(...${rhs.print(true)})" |> bra case Rcd(fields) => fields.iterator.map(nv => - (if (nv._2.flags.mut) "mut " else "") + nv._1.name + ": " + nv._2.value).mkString("{", ", ", "}") - case Sel(receiver, fieldName) => "(" + receiver.toString + ")." + fieldName - case Let(isRec, name, rhs, body) => - s"let${if (isRec) " rec" else ""} $name = $rhs in $body" |> bra + (if (nv._2.flags.mut) "mut " else "") + nv._1.name + ": " + nv._2.value.showDbg).mkString("{", ", ", "}") + case Sel(receiver, fieldName) => "(" + receiver.showDbg + ")." + fieldName.showDbg + case Let(isRec, Var(name), rhs, body) => + s"let${if (isRec) " rec" else ""} $name = ${rhs.showDbg} in ${body.showDbg}" |> bra case tup: Tup => "[" + tup.showElems + "]" case Splc(fields) => fields.map{ case L(l) => s"...$l" @@ -596,26 +599,26 @@ trait TermImpl extends StatementImpl { self: Term => + r ) }.mkString("(", ", ", ")") - case Bind(l, r) => s"$l as $r" |> bra - case Test(l, r) => s"$l is $r" |> bra - case With(t, fs) => s"$t with $fs" |> bra + case Bind(l, r) => s"${l.showDbg} as ${r.showDbg}" |> bra + case Test(l, r) => s"${l.showDbg} is ${r.showDbg}" |> bra + case With(t, fs) => s"${t.showDbg} with ${fs.showDbg}" |> bra case CaseOf(s, c) => - s"case $s of { ${c.print(true)} }" |> bra - case Subs(a, i) => s"($a)[$i]" - case Assign(lhs, rhs) => s" $lhs <- $rhs" |> bra - case New(S((at, ar)), bod) => s"new ${at.showDbg2}($ar) ${bod.showDbg}" |> bra + s"case ${s.showDbg} of { ${c.print(true)} }" |> bra + case Subs(a, i) => s"(${a.showDbg})[${i.showDbg}]" + case Assign(lhs, rhs) => s" ${lhs.showDbg} <- ${rhs.showDbg}" |> bra + case New(S((at, ar)), bod) => s"new ${at.showDbg2}(${ar.showDbg}) ${bod.showDbg}" |> bra case New(N, bod) => s"new ${bod.showDbg}" |> bra - case NuNew(cls) => s"new ${cls.print(false)}" |> bra - case If(body, els) => s"if $body" + els.fold("")(" else " + _) |> bra - case TyApp(lhs, targs) => s"$lhs‹${targs.map(_.showDbg2).mkString(", ")}›" - case Where(bod, wh) => s"${bod} where {${wh.mkString("; ")}}" - case Forall(ps, bod) => s"forall ${ps.mkString(", ")}. ${bod}" + case NuNew(cls) => s"new ${cls.showDbg}" |> bra + case If(body, els) => s"if ${body.showDbg}" + els.fold("")(" else " + _.showDbg) |> bra + case TyApp(lhs, targs) => s"${lhs.showDbg}‹${targs.iterator.map(_.showDbg2).mkString(", ")}›" + case Where(bod, wh) => s"${bod.showDbg} where {${wh.iterator.map(_.showDbg).mkString("; ")}}" + case Forall(ps, bod) => s"forall ${ps.mkString(", ")}. ${bod.showDbg}" case Inst(bod) => s"${bod.print(true)}!" case Super() => "super" - case Eqn(lhs, rhs) => s"${lhs} = ${rhs}" + case Eqn(lhs, rhs) => s"${lhs.showDbg} = ${rhs.showDbg}" case AdtMatchWith(cond, arms) => - s"match ${cond} with ${arms.map (patmat => s"${patmat.pat} -> ${patmat.rhs}").mkString (" | ") }" - case Rft(bse, tu) => s"${bse} { ${tu} }" + s"match ${cond.showDbg} with ${arms.map (patmat => s"${patmat.pat.showDbg} -> ${patmat.rhs.showDbg}").mkString (" | ") }" + case Rft(bse, tu) => s"${bse.showDbg} ${tu.showDbg}" }} def toTypeRaise(implicit raise: Raise): Type = toType match { @@ -739,7 +742,7 @@ trait TupImpl { self: Tup => (if (t.flags.mut) "mut " else "") + (if (t.flags.genGetter) "val " else "") + (if (t.flags.spec) "#" else "") - + n.fold("")(_.name + ": ") + t.value + "," + + n.fold("")(_.name + ": ") + t.value.print(false) + "," )}.mkString(" ") } @@ -747,7 +750,7 @@ trait SimpleTermImpl extends Ordered[SimpleTerm] { self: SimpleTerm => def compare(that: SimpleTerm): Int = this.idStr compare that.idStr val idStr: Str = this match { case Var(name) => name - case lit: Lit => lit.toString + case lit: Lit => lit.showDbg } } @@ -817,6 +820,8 @@ trait Located { trait DesugaredStatementImpl extends Located { self: DesugaredStatement => def describe: Str + + def showDbg: Str } trait StatementImpl extends Located { self: Statement => @@ -836,7 +841,7 @@ trait StatementImpl extends Located { self: Statement => case v @ Var(nme) => R(TypeName(nme).withLocOf(v)) case t => import Message._ - L(ErrorReport(msg"illegal datatype type parameter shape: ${t.toString}" -> t.toLoc :: Nil, newDefs=false)) + L(ErrorReport(msg"illegal datatype type parameter shape: ${t.showDbg}" -> t.toLoc :: Nil, newDefs=false)) } val (diags2, cs) = desugarCases(bod, targs) val dataDefs = cs.collect{case td: TypeDef => td} @@ -1000,15 +1005,20 @@ trait StatementImpl extends Located { self: Statement => case AdtMatchWith(cond, _) => cond :: Nil // FIXME discards branches... } - - override def toString: Str = this match { - case LetS(isRec, name, rhs) => s"let${if (isRec) " rec" else ""} $name = $rhs" - case DatatypeDefn(head, body) => s"data type $head of $body" - case DataDefn(head) => s"data $head" - case Constructor(params, bod) => s"constructor(${params.showElems}) $bod" - case _: Term => super.toString - case d: Decl => d.showDbg - case d: NuDecl => d.showDbg + def showDbg: Str = this match { + case LetS(isRec, name, rhs) => s"let${if (isRec) " rec" else ""} ${name.showDbg} = ${rhs.showDbg}" + case DatatypeDefn(head, body) => s"data type ${head.showDbg} of ${body.showDbg}" + case DataDefn(head) => s"data ${head.showDbg}" + case Constructor(params, body) => s"constructor(${params.showElems}) ${body.showDbg}" + case t: Term => t.print(false) + case d: Decl => d.showHead + (d match { + case n: TypeDef if n.kind is Als => " = " + case _ => ": " + }) + d.showBody + case n: NuDecl => n.showHead + (n match { + case n: NuFunDef => if (n.rhs.isLeft) " = " else ": " + case _: NuTypeDef => " " + }) + n.showBody } } @@ -1058,13 +1068,13 @@ trait IfBodyImpl extends Located { self: IfBody => case IfOpsApp(t, ops) => t :: ops.flatMap(x => x._1 :: x._2 :: Nil) } - override def toString: String = this match { - case IfThen(lhs, rhs) => s"($lhs) then $rhs" - case IfElse(trm) => s"else $trm" - case IfBlock(ts) => s"‹${ts.map(_.fold(identity, identity)).mkString("; ")}›" - case IfOpApp(lhs, op, ib) => s"$lhs $op $ib" - case IfOpsApp(lhs, ops) => s"$lhs ‹${ops.iterator.map{case(v, r) => s"· $v $r"}.mkString("; ")}›" - case IfLet(isRec, v, r, b) => s"${if (isRec) "rec " else ""}let $v = $r in $b" + def showDbg: String = this match { + case IfThen(lhs, rhs) => s"(${lhs.showDbg}) then ${rhs.showDbg}" + case IfElse(trm) => s"else ${trm.showDbg}" + case IfBlock(ts) => s"‹${ts.iterator.map(_.fold(_.showDbg, _.showDbg)).mkString("; ")}›" + case IfOpApp(lhs, op, ib) => s"${lhs.showDbg} ${op.showDbg} ${ib.showDbg}" + case IfOpsApp(lhs, ops) => s"${lhs.showDbg} ‹${ops.iterator.map{case(v, r) => s"· ${v.showDbg} ${r.showDbg}"}.mkString("; ")}›" + case IfLet(isRec, v, r, b) => s"${if (isRec) "rec " else ""}let ${v.showDbg} = ${r.showDbg} in ${b.showDbg}" } } diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index e899ff5828..d3d3b05c4d 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -104,7 +104,7 @@ final case class IfOpsApp(lhs: Term, opsRhss: Ls[Var -> IfBody]) extends IfBody final case class IfBlock(lines: Ls[IfBody \/ Statement]) extends IfBody // final case class IfApp(fun: Term, opsRhss: Ls[Var -> IfBody]) extends IfBody -final case class FldFlags(mut: Bool, spec: Bool, genGetter: Bool) +final case class FldFlags(mut: Bool, spec: Bool, genGetter: Bool) extends FldFlagsImpl final case class Fld(flags: FldFlags, value: Term) extends FldImpl object FldFlags { val empty: FldFlags = FldFlags(false, false, false) } diff --git a/shared/src/main/scala/mlscript/ucs/Desugarer.scala b/shared/src/main/scala/mlscript/ucs/Desugarer.scala index 6358f18928..6e49e61efc 100644 --- a/shared/src/main/scala/mlscript/ucs/Desugarer.scala +++ b/shared/src/main/scala/mlscript/ucs/Desugarer.scala @@ -379,7 +379,7 @@ class Desugarer extends TypeDefs { self: Typer => patternMap.foreachEntry { (pattern, locations) => val first = pattern match { case Left(tupleArity) => s"()^$tupleArity" - case Right(litOrCls) => litOrCls.toString() + case Right(litOrCls) => litOrCls.showDbg } val second = locations.mkString("[", ", ", "]") printlnUCS(s" + $first -> $second") @@ -689,7 +689,7 @@ class Desugarer extends TypeDefs { self: Typer => parentOpt match { case S(IfThenElse(test, whenTrue, whenFalse)) => if (whenFalse === t) - throw new DesugaringException(msg"The case when this is false is not handled: ${test.toString}", test.toLoc) + throw new DesugaringException(msg"The case when this is false is not handled: ${test.showDbg}", test.toLoc) else lastWords("`MissingCase` are not supposed to be the true branch of `IfThenElse`") case S(Match(_, _, _)) => @@ -755,7 +755,7 @@ class Desugarer extends TypeDefs { self: Typer => missingCases.iterator.zipWithIndex.flatMap { case ((pattern, locations), index) => val patternName = pattern match { case L(tupleArity) => s"$tupleArity-ary tuple" - case R(litOrCls) => litOrCls.toString() + case R(litOrCls) => litOrCls.showDbg } val progress = s"[Missing Case ${index + 1}/$numMissingCases]" (msg"$progress `$patternName`" -> N) :: diff --git a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala index 199d5619a8..8472e8b319 100644 --- a/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala +++ b/shared/src/main/scala/mlscript/ucs/MutCaseOf.scala @@ -62,7 +62,7 @@ sealed abstract class MutCaseOf extends WithBindings { object MutCaseOf { def showScrutinee(scrutinee: Scrutinee): Str = - s"«${scrutinee.term}»" + (scrutinee.local match { + s"«${scrutinee.term.showDbg}»" + (scrutinee.local match { case N => "" case S(Var(alias)) => s" as $alias" }) @@ -72,15 +72,15 @@ object MutCaseOf { def rec(t: MutCaseOf, indent: Int): Unit = { val baseIndent = " " * indent lazy val bindingLines = t.getBindings.iterator.map { - case LetBinding(_, recursive, name, term) => + case LetBinding(_, recursive, Var(name), term) => // Show bindings - s"[binding $name = $term]" + s"[binding $name = ${term.showDbg}]" }.toList t match { case IfThenElse(condition, whenTrue, whenFalse) => // Output the `whenTrue` with the prefix "if". bindingLines.foreach { lines += baseIndent + _ } - lines += baseIndent + s"if «$condition»" + lines += baseIndent + s"if «${condition.showDbg}»" rec(whenTrue, indent + 1) // Output the `whenFalse` case with the prefix "else". lines += s"${baseIndent}else" @@ -90,13 +90,13 @@ object MutCaseOf { lines += baseIndent + showScrutinee(scrutinee) + " match" branches.foreach { case MutCase.Literal(literal, consequent) => - lines += s"$baseIndent case $literal =>" + lines += s"$baseIndent case ${literal.showDbg} =>" rec(consequent, indent + 1) case MutCase.Constructor(Var(className) -> fields, consequent) => lines += s"$baseIndent case $className =>" fields.foreach { case (field, Var(alias)) => // Show pattern bindings. - lines += s"$baseIndent [pattern $alias = ${scrutinee.reference}.$field]" + lines += s"$baseIndent [pattern $alias = ${scrutinee.reference.showDbg}.$field]" } rec(consequent, indent + 2) } @@ -106,7 +106,7 @@ object MutCaseOf { } case Consequent(term) => bindingLines.foreach { lines += baseIndent + _ } - lines += s"$baseIndent«$term»" + lines += s"$baseIndent«${term.showDbg}»" case MissingCase => bindingLines.foreach { lines += baseIndent + _ } lines += s"$baseIndent" @@ -210,7 +210,7 @@ object MutCaseOf { // A short-hand for pattern matchings with only true and false branches. final case class IfThenElse(condition: Term, var whenTrue: MutCaseOf, var whenFalse: MutCaseOf) extends MutCaseOf { def describe: Str = - s"IfThenElse($condition, whenTrue = ${whenTrue.kind}, whenFalse = ${whenFalse.kind})" + s"IfThenElse(${condition.showDbg}, whenTrue = ${whenTrue.kind}, whenFalse = ${whenFalse.kind})" def duplicate(): MutCaseOf = IfThenElse(condition, whenTrue.duplicate(), whenFalse.duplicate()) @@ -469,7 +469,7 @@ object MutCaseOf { } } final case class Consequent(term: Term) extends MutCaseOf { - def describe: Str = s"Consequent($term)" + def describe: Str = s"Consequent(${term.showDbg})" override def fill(subTree: MutCaseOf): Unit = () diff --git a/shared/src/main/scala/mlscript/ucs/Scrutinee.scala b/shared/src/main/scala/mlscript/ucs/Scrutinee.scala index a0ce56d3e0..899c5629ac 100644 --- a/shared/src/main/scala/mlscript/ucs/Scrutinee.scala +++ b/shared/src/main/scala/mlscript/ucs/Scrutinee.scala @@ -26,5 +26,5 @@ final case class Scrutinee(var local: Opt[Var], term: Term)(val matchRootLoc: Op (local match { case N => "" case S(Var(alias)) => s"$alias @ " - }) + s"$term" + }) + s"${term.showDbg}" } diff --git a/shared/src/test/diff/basics/Blocks.fun b/shared/src/test/diff/basics/Blocks.fun index 65d88924eb..059b5e80de 100644 --- a/shared/src/test/diff/basics/Blocks.fun +++ b/shared/src/test/diff/basics/Blocks.fun @@ -44,7 +44,7 @@ discard / foo 1 //│ Parsed: discard(...(foo(...{1}))); //│ Desugared: discard(...(foo(...{1}))) -//│ AST: App(Var(discard), App(Var(foo), Blk(...))) +//│ AST: App(Var(discard),App(Var(foo),Blk(List(IntLit(1))))) :e discard foo @@ -81,7 +81,7 @@ id id id //│ Parsed: id(...id)(...{id}); //│ Desugared: id(...id)(...{id}) -//│ AST: App(App(Var(id), Var(id)), Blk(...)) +//│ AST: App(App(Var(id),Var(id)),Blk(List(Var(id)))) //│ res: 'a -> 'a :p @@ -91,7 +91,7 @@ id id id id id id //│ Parsed: id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)})})}); //│ Desugared: id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)(...{id(...id)(...id)})})}) -//│ AST: App(App(App(Var(id), Var(id)), Var(id)), Blk(...)) +//│ AST: App(App(App(Var(id),Var(id)),Var(id)),Blk(List(App(App(App(Var(id),Var(id)),Var(id)),Blk(List(App(App(App(Var(id),Var(id)),Var(id)),Blk(List(App(App(Var(id),Var(id)),Var(id))))))))))) //│ res: 'a -> 'a :p @@ -100,7 +100,7 @@ id id / id id //│ Parsed: id(...id)(...{id(...id)(...{id(...id)})}); //│ Desugared: id(...id)(...{id(...id)(...{id(...id)})}) -//│ AST: App(App(Var(id), Var(id)), Blk(...)) +//│ AST: App(App(Var(id),Var(id)),Blk(List(App(App(Var(id),Var(id)),Blk(List(App(Var(id),Var(id)))))))) //│ res: 'a -> 'a :p @@ -109,7 +109,7 @@ id id id id //│ Parsed: id(...id)(...{id(...id)})(...{id(...id)}); //│ Desugared: id(...id)(...{id(...id)})(...{id(...id)}) -//│ AST: App(App(App(Var(id), Var(id)), Blk(...)), Blk(...)) +//│ AST: App(App(App(Var(id),Var(id)),Blk(List(App(Var(id),Var(id))))),Blk(List(App(Var(id),Var(id))))) //│ res: 'a -> 'a let foo = diff --git a/shared/src/test/diff/basics/Data.fun b/shared/src/test/diff/basics/Data.fun index f155732eec..551c3b1c0c 100644 --- a/shared/src/test/diff/basics/Data.fun +++ b/shared/src/test/diff/basics/Data.fun @@ -4,7 +4,7 @@ data Test a b //│ Parsed: data Test(...a)(...b); //│ Desugared: class Test[a, b]: {a: a, b: b} //│ Desugared: def Test: forall a b. (...a) -> (...b) -> Test[a, b] -//│ AST: Def(false, Test, PolyType(List(Left(TypeName(a)), Left(TypeName(b))),Function(TypeName(a),Function(TypeName(b),AppliedType(TypeName(Test),List(TypeName(a), TypeName(b)))))), true) +//│ AST: Def(false,Var(Test),Right(PolyType(List(Left(TypeName(a)), Left(TypeName(b))),Function(TypeName(a),Function(TypeName(b),AppliedType(TypeName(Test),List(TypeName(a), TypeName(b))))))),true) //│ Defined class Test[+a, +b] //│ Test: 'a -> 'b -> Test['a, 'b] @@ -13,7 +13,7 @@ data Person(name: string, age: int) //│ Parsed: data Person(...'(' {[name: string, age: int,]} ')'); //│ Desugared: class Person: {age: int, name: string} //│ Desugared: def Person: (name: string, age: int) -> Person[] -//│ AST: Def(false, Person, PolyType(List(),Function(Tuple(List((Some(name),Field(None,TypeName(string))), (Some(age),Field(None,TypeName(int))))),AppliedType(TypeName(Person),List()))), true) +//│ AST: Def(false,Var(Person),Right(PolyType(List(),Function(Tuple(List((Some(Var(name)),Field(None,TypeName(string))), (Some(Var(age)),Field(None,TypeName(int))))),AppliedType(TypeName(Person),List())))),true) //│ Defined class Person //│ Person: (name: string, age: int,) -> Person diff --git a/shared/src/test/diff/basics/Datatypes.fun b/shared/src/test/diff/basics/Datatypes.fun index 2b2b0e7379..02cad3d2c6 100644 --- a/shared/src/test/diff/basics/Datatypes.fun +++ b/shared/src/test/diff/basics/Datatypes.fun @@ -6,9 +6,9 @@ data type Boolean of Tru, Fals //│ Desugared: class Tru: {} //│ Desugared: class Fals: {} //│ Desugared: def Tru: Tru[] -//│ AST: Def(false, Tru, PolyType(List(),AppliedType(TypeName(Tru),List())), true) +//│ AST: Def(false,Var(Tru),Right(PolyType(List(),AppliedType(TypeName(Tru),List()))),true) //│ Desugared: def Fals: Fals[] -//│ AST: Def(false, Fals, PolyType(List(),AppliedType(TypeName(Fals),List())), true) +//│ AST: Def(false,Var(Fals),Right(PolyType(List(),AppliedType(TypeName(Fals),List()))),true) //│ Defined type alias Boolean //│ Defined class Tru //│ Defined class Fals @@ -29,7 +29,7 @@ data type Bool2 of True2 & False2 //│ Desugared: type alias Bool2 = &[True2, False2] //│ Desugared: class &[True2, False2]: {False2 <: False2, True2 <: True2} //│ Desugared: def &: forall True2 False2. (...True2) -> (...False2) -> &[True2, False2] -//│ AST: Def(false, &, PolyType(List(Left(TypeName(True2)), Left(TypeName(False2))),Function(TypeName(True2),Function(TypeName(False2),AppliedType(TypeName(&),List(TypeName(True2), TypeName(False2)))))), true) +//│ AST: Def(false,Var(&),Right(PolyType(List(Left(TypeName(True2)), Left(TypeName(False2))),Function(TypeName(True2),Function(TypeName(False2),AppliedType(TypeName(&),List(TypeName(True2), TypeName(False2))))))),true) //│ ╔══[ERROR] type identifier not found: True2 //│ ║ l.27: data type Bool2 of True2 & False2 //│ ╙── ^^^^^ @@ -122,9 +122,9 @@ data type List a of //│ Desugared: class Nil[a]: {} //│ Desugared: class Cons[a]: {head: a, tail: anything} //│ Desugared: def Nil: forall a. Nil[a] -//│ AST: Def(false, Nil, PolyType(List(Left(TypeName(a))),AppliedType(TypeName(Nil),List(TypeName(a)))), true) +//│ AST: Def(false,Var(Nil),Right(PolyType(List(Left(TypeName(a))),AppliedType(TypeName(Nil),List(TypeName(a))))),true) //│ Desugared: def Cons: forall a. (head: a) -> (tail: anything) -> Cons[a] -//│ AST: Def(false, Cons, PolyType(List(Left(TypeName(a))),Function(Tuple(List((Some(head),Field(None,TypeName(a))))),Function(Tuple(List((Some(tail),Field(None,Top)))),AppliedType(TypeName(Cons),List(TypeName(a)))))), true) +//│ AST: Def(false,Var(Cons),Right(PolyType(List(Left(TypeName(a))),Function(Tuple(List((Some(Var(head)),Field(None,TypeName(a))))),Function(Tuple(List((Some(Var(tail)),Field(None,Top)))),AppliedType(TypeName(Cons),List(TypeName(a))))))),true) //│ Defined type alias List[+a] //│ Defined class Nil[±a] //│ Defined class Cons[+a] @@ -144,7 +144,7 @@ data type Ls of LsA a //│ Desugared: type alias Ls = LsA[a] //│ Desugared: class LsA[a]: {a: a} //│ Desugared: def LsA: forall a. (...a) -> LsA[a] -//│ AST: Def(false, LsA, PolyType(List(Left(TypeName(a))),Function(TypeName(a),AppliedType(TypeName(LsA),List(TypeName(a))))), true) +//│ AST: Def(false,Var(LsA),Right(PolyType(List(Left(TypeName(a))),Function(TypeName(a),AppliedType(TypeName(LsA),List(TypeName(a)))))),true) //│ ╔══[ERROR] type identifier not found: a //│ ║ l.142: data type Ls of LsA a //│ ╙── ^ @@ -159,7 +159,7 @@ data type Ls2 of LsA2 `a //│ Desugared: type alias Ls2 = LsA2[] //│ Desugared: class LsA2: {`a: 'a} //│ Desugared: def LsA2: (...'a) -> LsA2[] -//│ AST: Def(false, LsA2, PolyType(List(),Function(a,AppliedType(TypeName(LsA2),List()))), true) +//│ AST: Def(false,Var(LsA2),Right(PolyType(List(),Function(a,AppliedType(TypeName(LsA2),List())))),true) //│ ╔══[ERROR] cannot inherit from a polymorphic type //│ ║ l.157: data type Ls2 of LsA2 `a //│ ╙── ^^^^^^^ diff --git a/shared/src/test/diff/basics/Either.fun b/shared/src/test/diff/basics/Either.fun index 7ea04bae6f..a9a49120a7 100644 --- a/shared/src/test/diff/basics/Either.fun +++ b/shared/src/test/diff/basics/Either.fun @@ -9,9 +9,9 @@ data type Either l r of //│ Desugared: class Left[l, r]: {l: l} //│ Desugared: class Right[l, r]: {r: r} //│ Desugared: def Left: forall l r. (...l) -> Left[l, r] -//│ AST: Def(false, Left, PolyType(List(Left(TypeName(l)), Left(TypeName(r))),Function(TypeName(l),AppliedType(TypeName(Left),List(TypeName(l), TypeName(r))))), true) +//│ AST: Def(false,Var(Left),Right(PolyType(List(Left(TypeName(l)), Left(TypeName(r))),Function(TypeName(l),AppliedType(TypeName(Left),List(TypeName(l), TypeName(r)))))),true) //│ Desugared: def Right: forall l r. (...r) -> Right[l, r] -//│ AST: Def(false, Right, PolyType(List(Left(TypeName(l)), Left(TypeName(r))),Function(TypeName(r),AppliedType(TypeName(Right),List(TypeName(l), TypeName(r))))), true) +//│ AST: Def(false,Var(Right),Right(PolyType(List(Left(TypeName(l)), Left(TypeName(r))),Function(TypeName(r),AppliedType(TypeName(Right),List(TypeName(l), TypeName(r)))))),true) //│ Defined type alias Either[+l, +r] //│ Defined class Left[+l, ±r] //│ Defined class Right[±l, +r] diff --git a/shared/src/test/diff/basics/Flow.fun b/shared/src/test/diff/basics/Flow.fun index 5005f8a42c..8c363a2cb7 100644 --- a/shared/src/test/diff/basics/Flow.fun +++ b/shared/src/test/diff/basics/Flow.fun @@ -6,9 +6,9 @@ data R x //│ Desugared: class L[x]: {x: x} //│ Desugared: class R[x]: {x: x} //│ Desugared: def L: forall x. (...x) -> L[x] -//│ AST: Def(false, L, PolyType(List(Left(TypeName(x))),Function(TypeName(x),AppliedType(TypeName(L),List(TypeName(x))))), true) +//│ AST: Def(false,Var(L),Right(PolyType(List(Left(TypeName(x))),Function(TypeName(x),AppliedType(TypeName(L),List(TypeName(x)))))),true) //│ Desugared: def R: forall x. (...x) -> R[x] -//│ AST: Def(false, R, PolyType(List(Left(TypeName(x))),Function(TypeName(x),AppliedType(TypeName(R),List(TypeName(x))))), true) +//│ AST: Def(false,Var(R),Right(PolyType(List(Left(TypeName(x))),Function(TypeName(x),AppliedType(TypeName(R),List(TypeName(x)))))),true) //│ Defined class L[+x] //│ Defined class R[+x] //│ L: 'a -> L['a] diff --git a/shared/src/test/diff/basics/Operators.fun b/shared/src/test/diff/basics/Operators.fun index bbf5eff5cc..895e9dd48f 100644 --- a/shared/src/test/diff/basics/Operators.fun +++ b/shared/src/test/diff/basics/Operators.fun @@ -16,7 +16,7 @@ a + b //│ Parsed: +(...a)(...{b}); //│ Desugared: +(...a)(...{b}) -//│ AST: App(App(Var(+), Var(a)), Blk(...)) +//│ AST: App(App(Var(+),Var(a)),Blk(List(Var(b)))) //│ res: int :pe @@ -31,7 +31,7 @@ succ a + c //│ Parsed: +(...(succ(...a)))(...{+(...b)(...{c})}); //│ Desugared: +(...(succ(...a)))(...{+(...b)(...{c})}) -//│ AST: App(App(Var(+), App(Var(succ), Var(a))), Blk(...)) +//│ AST: App(App(Var(+),App(Var(succ),Var(a))),Blk(List(App(App(Var(+),Var(b)),Blk(List(Var(c))))))) //│ res: int :p @@ -40,7 +40,7 @@ succ / a + c //│ Parsed: succ(...(+(...a)(...{+(...b)(...{c})}))); //│ Desugared: succ(...(+(...a)(...{+(...b)(...{c})}))) -//│ AST: App(Var(succ), App(App(Var(+), Var(a)), Blk(...))) +//│ AST: App(Var(succ),App(App(Var(+),Var(a)),Blk(List(App(App(Var(+),Var(b)),Blk(List(Var(c)))))))) //│ res: int :p @@ -55,11 +55,11 @@ a + d //│ Parsed: +(...a)(...b); +(...(+(...a)(...b)))(...c); +(...(+(...(+(...a)(...b)))(...c)))(...d); //│ Desugared: +(...a)(...b) -//│ AST: App(App(Var(+), Var(a)), Var(b)) +//│ AST: App(App(Var(+),Var(a)),Var(b)) //│ Desugared: +(...(+(...a)(...b)))(...c) -//│ AST: App(App(Var(+), App(App(Var(+), Var(a)), Var(b))), Var(c)) +//│ AST: App(App(Var(+),App(App(Var(+),Var(a)),Var(b))),Var(c)) //│ Desugared: +(...(+(...(+(...a)(...b)))(...c)))(...d) -//│ AST: App(App(Var(+), App(App(Var(+), App(App(Var(+), Var(a)), Var(b))), Var(c))), Var(d)) +//│ AST: App(App(Var(+),App(App(Var(+),App(App(Var(+),Var(a)),Var(b))),Var(c))),Var(d)) //│ res: int //│ res: int //│ res: int @@ -74,7 +74,7 @@ a + d //│ Parsed: +(...(+(...(+(...a)(...b)))(...(+(...(+(...c)(...1)))(...(+(...2)(...3)))))))(...d); //│ Desugared: +(...(+(...(+(...a)(...b)))(...(+(...(+(...c)(...1)))(...(+(...2)(...3)))))))(...d) -//│ AST: App(App(Var(+), App(App(Var(+), App(App(Var(+), Var(a)), Var(b))), App(App(Var(+), App(App(Var(+), Var(c)), IntLit(1))), App(App(Var(+), IntLit(2)), IntLit(3))))), Var(d)) +//│ AST: App(App(Var(+),App(App(Var(+),App(App(Var(+),Var(a)),Var(b))),App(App(Var(+),App(App(Var(+),Var(c)),IntLit(1))),App(App(Var(+),IntLit(2)),IntLit(3))))),Var(d)) //│ res: int :pe @@ -112,7 +112,7 @@ succ + c //│ Parsed: +(...(succ(...{+(...a)(...b)})))(...c); //│ Desugared: +(...(succ(...{+(...a)(...b)})))(...c) -//│ AST: App(App(Var(+), App(Var(succ), Blk(...))), Var(c)) +//│ AST: App(App(Var(+),App(Var(succ),Blk(List(App(App(Var(+),Var(a)),Var(b)))))),Var(c)) //│ res: int // Maybe allow this as it lets us nicely align the operands? diff --git a/shared/src/test/diff/basics/Slashes.fun b/shared/src/test/diff/basics/Slashes.fun index ef7aef7047..d4c3316097 100644 --- a/shared/src/test/diff/basics/Slashes.fun +++ b/shared/src/test/diff/basics/Slashes.fun @@ -23,7 +23,7 @@ x => succ / succ / x + 1 foo / x => succ / succ / x //│ Parsed: foo(...((...x) => succ(...(succ(...x))))); //│ Desugared: foo(...((...x) => succ(...(succ(...x))))) -//│ AST: App(Var(foo), Lam(Var(x), App(Var(succ), App(Var(succ), Var(x))))) +//│ AST: App(Var(foo),Lam(Var(x),App(Var(succ),App(Var(succ),Var(x))))) //│ res: int :e diff --git a/shared/src/test/diff/mlscript/Basics.mls b/shared/src/test/diff/mlscript/Basics.mls index 2af98bf088..7ecdfea0f7 100644 --- a/shared/src/test/diff/mlscript/Basics.mls +++ b/shared/src/test/diff/mlscript/Basics.mls @@ -96,7 +96,7 @@ def f (x y z) = add x y //│ ╙── ^^^^^ //│ f: error -> int //│ Code generation encountered an error: -//│ term App(App(Var(x), Tup(_: Var(y))), Tup(_: Var(z))) is not a valid pattern +//│ term App(App(Var(x),Tup(List((None,Fld(_,Var(y)))))),Tup(List((None,Fld(_,Var(z)))))) is not a valid pattern f 1 //│ res: int diff --git a/shared/src/test/diff/mlscript/ByNameByValue.mls b/shared/src/test/diff/mlscript/ByNameByValue.mls index 3e87640778..a9b9b9b18c 100644 --- a/shared/src/test/diff/mlscript/ByNameByValue.mls +++ b/shared/src/test/diff/mlscript/ByNameByValue.mls @@ -16,7 +16,7 @@ def incr x = x.a <- x.a + 1 def gensym = let n = { mut a = 0 } in fun () -> (incr n, n) //│ Parsed: def gensym: let n = {mut a: 0} in () => [incr(n,), n,]; //│ Desugared: def gensym: let n = {mut a: 0} in () => [incr(n,), n,] -//│ AST: Def(false, gensym, Let(false, n, Rcd(Var(a) = IntLit(0)), Lam(Tup(), Tup(_: App(Var(incr), Tup(_: Var(n))), _: Var(n)))), true) +//│ AST: Def(false,Var(gensym),Left(Let(false,Var(n),Rcd(List((Var(a),Fld(m,IntLit(0))))),Lam(Tup(List()),Tup(List((None,Fld(_,App(Var(incr),Tup(List((None,Fld(_,Var(n)))))))), (None,Fld(_,Var(n)))))))),true) //│ // Query 1 //│ globalThis.gensym = function gensym() { //│ return (((n) => () => [ @@ -35,7 +35,7 @@ def gensym = let n = { mut a = 0 } in fun () -> (incr n, n) gensym1 = let n = { mut a = 0 } in fun () -> (incr n, n) //│ Parsed: let gensym1 = let n = {mut a: 0} in () => [incr(n,), n,]; //│ Desugared: def gensym1: let n = {mut a: 0} in () => [incr(n,), n,] -//│ AST: Def(false, gensym1, Let(false, n, Rcd(Var(a) = IntLit(0)), Lam(Tup(), Tup(_: App(Var(incr), Tup(_: Var(n))), _: Var(n)))), false) +//│ AST: Def(false,Var(gensym1),Left(Let(false,Var(n),Rcd(List((Var(a),Fld(m,IntLit(0))))),Lam(Tup(List()),Tup(List((None,Fld(_,App(Var(incr),Tup(List((None,Fld(_,Var(n)))))))), (None,Fld(_,Var(n)))))))),false) //│ // Query 1 //│ globalThis.gensym1 = ((n) => () => [ //│ incr(n), diff --git a/shared/src/test/diff/mlscript/MultiArgs.mls b/shared/src/test/diff/mlscript/MultiArgs.mls index 62e7a8090d..9f04e7f150 100644 --- a/shared/src/test/diff/mlscript/MultiArgs.mls +++ b/shared/src/test/diff/mlscript/MultiArgs.mls @@ -75,9 +75,9 @@ f = fun (x, y) -> add x y f(1, 2) //│ Parsed: let f = (x, y,) => add(x,)(y,); f(1, 2,); //│ Desugared: def f: (x, y,) => add(x,)(y,) -//│ AST: Def(false, f, Lam(Tup(_: Var(x), _: Var(y)), App(App(Var(add), Tup(_: Var(x))), Tup(_: Var(y)))), false) +//│ AST: Def(false,Var(f),Left(Lam(Tup(List((None,Fld(_,Var(x))), (None,Fld(_,Var(y))))),App(App(Var(add),Tup(List((None,Fld(_,Var(x)))))),Tup(List((None,Fld(_,Var(y)))))))),false) //│ Desugared: f(1, 2,) -//│ AST: App(Var(f), Tup(_: IntLit(1), _: IntLit(2))) +//│ AST: App(Var(f),Tup(List((None,Fld(_,IntLit(1))), (None,Fld(_,IntLit(2)))))) //│ f: (int, int,) -> int //│ = [Function: f] //│ res: int @@ -119,9 +119,9 @@ f = fun ((x, y)) -> add x y f((1, 2)) //│ Parsed: let f = ('(' [x, y,] ')',) => add(x,)(y,); f('(' [1, 2,] ')',); //│ Desugared: def f: ('(' [x, y,] ')',) => add(x,)(y,) -//│ AST: Def(false, f, Lam(Tup(_: Bra(rcd = false, Tup(_: Var(x), _: Var(y)))), App(App(Var(add), Tup(_: Var(x))), Tup(_: Var(y)))), false) +//│ AST: Def(false,Var(f),Left(Lam(Tup(List((None,Fld(_,Bra(false,Tup(List((None,Fld(_,Var(x))), (None,Fld(_,Var(y)))))))))),App(App(Var(add),Tup(List((None,Fld(_,Var(x)))))),Tup(List((None,Fld(_,Var(y)))))))),false) //│ Desugared: f('(' [1, 2,] ')',) -//│ AST: App(Var(f), Tup(_: Bra(rcd = false, Tup(_: IntLit(1), _: IntLit(2))))) +//│ AST: App(Var(f),Tup(List((None,Fld(_,Bra(false,Tup(List((None,Fld(_,IntLit(1))), (None,Fld(_,IntLit(2))))))))))) //│ f: ((int, int,),) -> int //│ = [Function: f1] //│ res: int diff --git a/shared/src/test/diff/mlscript/Mut.mls b/shared/src/test/diff/mlscript/Mut.mls index 5abffdda48..7cbd3ed19a 100644 --- a/shared/src/test/diff/mlscript/Mut.mls +++ b/shared/src/test/diff/mlscript/Mut.mls @@ -613,7 +613,7 @@ b1.x <- 1 + 2 <- 4 //│ ║ l.550: b1.x <- 1 + 2 <- 4 //│ ╙── ^ //│ Code generation encountered an error: -//│ illegal assignemnt left-hand side: Bra(rcd = false, Assign(Sel(Var(mt1), 0), Sel(Var(b1), t))) +//│ illegal assignemnt left-hand side: Bra(false,Assign(Sel(Var(mt1),Var(0)),Sel(Var(b1),Var(t)))) def f : {mut 0 : int} -> int -> unit def g : (mut int, bool) -> int -> unit diff --git a/shared/src/test/diff/mlscript/Ops.mls b/shared/src/test/diff/mlscript/Ops.mls index 837b2c09e6..fb99294cfb 100644 --- a/shared/src/test/diff/mlscript/Ops.mls +++ b/shared/src/test/diff/mlscript/Ops.mls @@ -3,7 +3,7 @@ 2 + 2 //│ Parsed: +(2,)(2,); //│ Desugared: +(2,)(2,) -//│ AST: App(App(Var(+), Tup(_: IntLit(2))), Tup(_: IntLit(2))) +//│ AST: App(App(Var(+),Tup(List((None,Fld(_,IntLit(2)))))),Tup(List((None,Fld(_,IntLit(2)))))) //│ res: int //│ = 4 @@ -11,7 +11,7 @@ 1 + 2 * 2 + 3 //│ Parsed: +(+(1,)(*(2,)(2,),),)(3,); //│ Desugared: +(+(1,)(*(2,)(2,),),)(3,) -//│ AST: App(App(Var(+), Tup(_: App(App(Var(+), Tup(_: IntLit(1))), Tup(_: App(App(Var(*), Tup(_: IntLit(2))), Tup(_: IntLit(2))))))), Tup(_: IntLit(3))) +//│ AST: App(App(Var(+),Tup(List((None,Fld(_,App(App(Var(+),Tup(List((None,Fld(_,IntLit(1)))))),Tup(List((None,Fld(_,App(App(Var(*),Tup(List((None,Fld(_,IntLit(2)))))),Tup(List((None,Fld(_,IntLit(2)))))))))))))))),Tup(List((None,Fld(_,IntLit(3)))))) //│ res: int //│ = 8 @@ -20,7 +20,7 @@ 1 + 2 / 2 + 3 //│ Parsed: +(+(1,)(/(2,)(2,),),)(3,); //│ Desugared: +(+(1,)(/(2,)(2,),),)(3,) -//│ AST: App(App(Var(+), Tup(_: App(App(Var(+), Tup(_: IntLit(1))), Tup(_: App(App(Var(/), Tup(_: IntLit(2))), Tup(_: IntLit(2))))))), Tup(_: IntLit(3))) +//│ AST: App(App(Var(+),Tup(List((None,Fld(_,App(App(Var(+),Tup(List((None,Fld(_,IntLit(1)))))),Tup(List((None,Fld(_,App(App(Var(/),Tup(List((None,Fld(_,IntLit(2)))))),Tup(List((None,Fld(_,IntLit(2)))))))))))))))),Tup(List((None,Fld(_,IntLit(3)))))) //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.20: 1 + 2 / 2 + 3 //│ ║ ^^^^^^^^^ @@ -36,7 +36,7 @@ 1 |> 2 || 3 //│ Parsed: ||(|>(1,)(2,),)(3,); //│ Desugared: ||(|>(1,)(2,),)(3,) -//│ AST: App(App(Var(||), Tup(_: App(App(Var(|>), Tup(_: IntLit(1))), Tup(_: IntLit(2))))), Tup(_: IntLit(3))) +//│ AST: App(App(Var(||),Tup(List((None,Fld(_,App(App(Var(|>),Tup(List((None,Fld(_,IntLit(1)))))),Tup(List((None,Fld(_,IntLit(2))))))))))),Tup(List((None,Fld(_,IntLit(3)))))) //│ ╔══[ERROR] identifier not found: |> //│ ║ l.36: 1 |> 2 || 3 //│ ╙── ^^ @@ -54,7 +54,7 @@ true || false && true || false //│ Parsed: ||(||(true,)(&&(false,)(true,),),)(false,); //│ Desugared: ||(||(true,)(&&(false,)(true,),),)(false,) -//│ AST: App(App(Var(||), Tup(_: App(App(Var(||), Tup(_: Var(true))), Tup(_: App(App(Var(&&), Tup(_: Var(false))), Tup(_: Var(true))))))), Tup(_: Var(false))) +//│ AST: App(App(Var(||),Tup(List((None,Fld(_,App(App(Var(||),Tup(List((None,Fld(_,Var(true)))))),Tup(List((None,Fld(_,App(App(Var(&&),Tup(List((None,Fld(_,Var(false)))))),Tup(List((None,Fld(_,Var(true)))))))))))))))),Tup(List((None,Fld(_,Var(false)))))) //│ res: bool //│ = true diff --git a/shared/src/test/diff/mlscript/Weird.mls b/shared/src/test/diff/mlscript/Weird.mls index 9aa518f720..2b658ed4e3 100644 --- a/shared/src/test/diff/mlscript/Weird.mls +++ b/shared/src/test/diff/mlscript/Weird.mls @@ -41,9 +41,9 @@ class C def n: C{} //│ Parsed: rec def n: C; {}; //│ Desugared: rec def n: C -//│ AST: Def(true, n, PolyType(List(),TypeName(C)), true) +//│ AST: Def(true,Var(n),Right(PolyType(List(),TypeName(C))),true) //│ Desugared: {} -//│ AST: Rcd() +//│ AST: Rcd(List()) //│ n: C //│ = //│ res: anything diff --git a/shared/src/test/diff/nu/AbstractClasses.mls b/shared/src/test/diff/nu/AbstractClasses.mls index ab09dd59b9..540f361d71 100644 --- a/shared/src/test/diff/nu/AbstractClasses.mls +++ b/shared/src/test/diff/nu/AbstractClasses.mls @@ -51,7 +51,7 @@ new Foo(1) { fun f = id } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: -//│ cannot generate code for term Rft(App(NuNew(Var(Foo)), Tup(_: IntLit(1))), ...) +//│ cannot generate code for term Rft(App(NuNew(Var(Foo)),Tup(List((None,Fld(_,IntLit(1)))))),TypingUnit(List(NuFunDef(None,Var(f),None,List(),Left(Var(id)))))) abstract class Bar extends Foo(1) diff --git a/shared/src/test/diff/nu/BadBlocks.mls b/shared/src/test/diff/nu/BadBlocks.mls index eedcd08dfd..b76b35c08c 100644 --- a/shared/src/test/diff/nu/BadBlocks.mls +++ b/shared/src/test/diff/nu/BadBlocks.mls @@ -176,5 +176,5 @@ fun test = (new { //│ ╙── ^ //│ fun test: error //│ Code generation encountered an error: -//│ Unsupported `new` class term: Bra(rcd = true, Rcd(Var(res) = Var(res))) +//│ Unsupported `new` class term: Bra(true,Rcd(List((Var(res),Fld(g,Var(res)))))) diff --git a/shared/src/test/diff/nu/LamPatterns.mls b/shared/src/test/diff/nu/LamPatterns.mls index 58aa85eb8e..557784389d 100644 --- a/shared/src/test/diff/nu/LamPatterns.mls +++ b/shared/src/test/diff/nu/LamPatterns.mls @@ -14,7 +14,7 @@ Some(x) => x //│ ╙── ^ //│ error -> error //│ Code generation encountered an error: -//│ term App(Var(Some), Tup(_: Var(x))) is not a valid pattern +//│ term App(Var(Some),Tup(List((None,Fld(_,Var(x)))))) is not a valid pattern :js // FIXME type diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index 74f8a3f58c..f990934e26 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -129,7 +129,7 @@ let rec lol = () => lol :p let rec f = 1 //│ |#let| |#rec| |f| |#=| |1| -//│ AST: TypingUnit(NuFunDef(Some(true), f, None, [], IntLit(1))) +//│ AST: TypingUnit(List(NuFunDef(Some(true),Var(f),None,List(),Left(IntLit(1))))) //│ Parsed: let rec f = 1; //│ let rec f: 1 //│ f diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index c135ca38a9..e62b8f9a95 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -167,7 +167,7 @@ new PoInt['_] //│ ╙── ^ //│ PoInt[nothing] | error //│ Code generation encountered an error: -//│ Unsupported `new` class term: TyApp(Var(PoInt), List('_)) +//│ Unsupported `new` class term: TyApp(Var(PoInt),List('_)) :e new PoInt[Str](0, 0) @@ -176,7 +176,7 @@ new PoInt[Str](0, 0) //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ PoInt[0] //│ Code generation encountered an error: -//│ Unsupported `new` class term: TyApp(Var(PoInt), List(TypeName(Str))) +//│ Unsupported `new` class term: TyApp(Var(PoInt),List(TypeName(Str))) type T = PoInt[Str] //│ type T = PoInt[Str] @@ -211,7 +211,7 @@ let origin = new PoInt[Int](0, 0) //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ let origin: PoInt[0] //│ Code generation encountered an error: -//│ Unsupported `new` class term: TyApp(Var(PoInt), List(TypeName(Int))) +//│ Unsupported `new` class term: TyApp(Var(PoInt),List(TypeName(Int))) :e // TODO support @@ -221,7 +221,7 @@ new {} //│ ╙── ^^ //│ error //│ Code generation encountered an error: -//│ Unsupported `new` class term: Bra(rcd = true, Rcd()) +//│ Unsupported `new` class term: Bra(true,Rcd(List())) :pe :e @@ -247,7 +247,7 @@ new //│ ╙── ^ //│ error //│ Code generation encountered an error: -//│ Unsupported `new` class term: Blk(...) +//│ Unsupported `new` class term: Blk(List(Asc(Var(x),Literal(IntLit(0))))) @@ -302,6 +302,6 @@ module A { class B } new A.B //│ B //│ Code generation encountered an error: -//│ Unsupported `new` class term: Sel(Var(A), B) +//│ Unsupported `new` class term: Sel(Var(A),Var(B)) diff --git a/shared/src/test/diff/nu/OpLam.mls b/shared/src/test/diff/nu/OpLam.mls index 15b57dbca7..b7eb786b51 100644 --- a/shared/src/test/diff/nu/OpLam.mls +++ b/shared/src/test/diff/nu/OpLam.mls @@ -107,6 +107,6 @@ x => x.y => y //│ ╙── ^ //│ anything -> error -> error //│ Code generation encountered an error: -//│ term Sel(Var(x), y) is not a valid pattern +//│ term Sel(Var(x),Var(y)) is not a valid pattern diff --git a/shared/src/test/diff/nu/OverrideShorthand.mls b/shared/src/test/diff/nu/OverrideShorthand.mls index 25db2319d8..2bd823530c 100644 --- a/shared/src/test/diff/nu/OverrideShorthand.mls +++ b/shared/src/test/diff/nu/OverrideShorthand.mls @@ -10,7 +10,7 @@ class Pair(lhs: Int, rhs: Int) :e fun f(override Pair(x, y)) = x + y //│ |#fun| |f|(|#override| |Pair|(|x|,| |y|)|)| |#=| |x| |+| |y| -//│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(_$0)), If(IfOpApp(Var(_$0), Var(is), IfThen(App(Var(Pair), Tup(_: Var(x), _: Var(y))), App(Var(+), Tup(_: Var(x), _: Var(y))), Some(App(Sel(Super(), f), Tup(_: Var(_$0)))))))) +//│ AST: TypingUnit(List(NuFunDef(None,Var(f),None,List(),Left(Lam(Tup(List((None,Fld(_,Var(_$0))))),If(IfOpApp(Var(_$0),Var(is),IfThen(App(Var(Pair),Tup(List((None,Fld(_,Var(x))), (None,Fld(_,Var(y)))))),App(Var(+),Tup(List((None,Fld(_,Var(x))), (None,Fld(_,Var(y)))))))),Some(App(Sel(Super(),Var(f)),Tup(List((None,Fld(_,Var(_$0))))))))))))) //│ Parsed: fun f = (_$0,) => if _$0 is (Pair(x, y,)) then +(x, y,) else (super).f(_$0,); //│ ╔══[ERROR] identifier not found: super //│ ║ l.11: fun f(override Pair(x, y)) = x + y @@ -46,7 +46,7 @@ fun f(override Pair(x, y), z) = x + y //│ ╙── ^ //│ fun f: (error, anything) -> Int //│ Code generation encountered an error: -//│ term App(Var(Pair), Tup(_: Var(x), _: Var(y))) is not a valid pattern +//│ term App(Var(Pair),Tup(List((None,Fld(_,Var(x))), (None,Fld(_,Var(y)))))) is not a valid pattern // TODO diff --git a/shared/src/test/diff/nu/Refinements.mls b/shared/src/test/diff/nu/Refinements.mls index 2311c3c10c..62a2a6790a 100644 --- a/shared/src/test/diff/nu/Refinements.mls +++ b/shared/src/test/diff/nu/Refinements.mls @@ -83,7 +83,7 @@ let r = new {} //│ ╙── ^^ //│ let r: error //│ Code generation encountered an error: -//│ Unsupported `new` class term: Bra(rcd = true, Rcd()) +//│ Unsupported `new` class term: Bra(true,Rcd(List())) :ge r : Object diff --git a/shared/src/test/diff/nu/RightAssocOps.mls b/shared/src/test/diff/nu/RightAssocOps.mls index 15a34aaad7..b692e7fb06 100644 --- a/shared/src/test/diff/nu/RightAssocOps.mls +++ b/shared/src/test/diff/nu/RightAssocOps.mls @@ -30,7 +30,7 @@ fun (++) conc(xs, ys) = [xs, ys] :p 1 +: "a" ++ "b" :+ 2 //│ |1| |+:| |"a"| |++| |"b"| |:+| |2| -//│ AST: TypingUnit(App(Var(+:), Tup(_: IntLit(1), _: App(Var(:+), Tup(_: App(Var(++), Tup(_: StrLit(a), _: StrLit(b))), _: IntLit(2)))))) +//│ AST: TypingUnit(List(App(Var(+:),Tup(List((None,Fld(_,IntLit(1))), (None,Fld(_,App(Var(:+),Tup(List((None,Fld(_,App(Var(++),Tup(List((None,Fld(_,StrLit(a))), (None,Fld(_,StrLit(b)))))))), (None,Fld(_,IntLit(2))))))))))))) //│ Parsed: +:(1, :+(++("a", "b",), 2,),); //│ [[Int], [["a", "b"], [Int]]] //│ res @@ -39,7 +39,7 @@ fun (++) conc(xs, ys) = [xs, ys] :p 1 +: "a" :+ 2 ++ "b" //│ |1| |+:| |"a"| |:+| |2| |++| |"b"| -//│ AST: TypingUnit(App(Var(+:), Tup(_: IntLit(1), _: App(Var(++), Tup(_: App(Var(:+), Tup(_: StrLit(a), _: IntLit(2))), _: StrLit(b)))))) +//│ AST: TypingUnit(List(App(Var(+:),Tup(List((None,Fld(_,IntLit(1))), (None,Fld(_,App(Var(++),Tup(List((None,Fld(_,App(Var(:+),Tup(List((None,Fld(_,StrLit(a))), (None,Fld(_,IntLit(2)))))))), (None,Fld(_,StrLit(b))))))))))))) //│ Parsed: +:(1, ++(:+("a", 2,), "b",),); //│ [[Int], [["a", [Int]], "b"]] //│ res @@ -49,7 +49,7 @@ fun (++) conc(xs, ys) = [xs, ys] :e 1 +: "a" ++ 2 +: "b" //│ |1| |+:| |"a"| |++| |2| |+:| |"b"| -//│ AST: TypingUnit(App(Var(+:), Tup(_: IntLit(1), _: App(Var(+:), Tup(_: App(Var(++), Tup(_: StrLit(a), _: IntLit(2))), _: StrLit(b)))))) +//│ AST: TypingUnit(List(App(Var(+:),Tup(List((None,Fld(_,IntLit(1))), (None,Fld(_,App(Var(+:),Tup(List((None,Fld(_,App(Var(++),Tup(List((None,Fld(_,StrLit(a))), (None,Fld(_,IntLit(2)))))))), (None,Fld(_,StrLit(b))))))))))))) //│ Parsed: +:(1, +:(++("a", 2,), "b",),); //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.50: 1 +: "a" ++ 2 +: "b" diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index bc37f00a70..dec21bdd11 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -80,7 +80,7 @@ new C { val x = 1 } //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ error //│ Code generation encountered an error: -//│ cannot generate code for term Rft(NuNew(Var(C)), ...) +//│ cannot generate code for term Rft(NuNew(Var(C)),TypingUnit(List(NuFunDef(Some(false),Var(x),None,List(),Left(IntLit(1)))))) diff --git a/shared/src/test/diff/parser/BasicSyntax.mls b/shared/src/test/diff/parser/BasicSyntax.mls index 5c4c9b09d7..f525ad0160 100644 --- a/shared/src/test/diff/parser/BasicSyntax.mls +++ b/shared/src/test/diff/parser/BasicSyntax.mls @@ -319,18 +319,18 @@ f[1, 2, 3] f{} //│ |f|{||}| -//│ Parsed: {f { ‹› }} +//│ Parsed: {f {}} f{1} //│ |f|{|1|}| -//│ Parsed: {f { ‹1› }} +//│ Parsed: {f {1}} f{1, 2, 3} //│ |f|{|1|,| |2|,| |3|}| //│ ╔══[PARSE ERROR] Unexpected comma here //│ ║ l.328: f{1, 2, 3} //│ ╙── ^ -//│ Parsed: {f { ‹1› }} +//│ Parsed: {f {1}} f 1,, 2 diff --git a/shared/src/test/diff/parser/New.mls b/shared/src/test/diff/parser/New.mls index 2ce52058de..f10a90908c 100644 --- a/shared/src/test/diff/parser/New.mls +++ b/shared/src/test/diff/parser/New.mls @@ -38,19 +38,19 @@ new A of 1, 2, 3 new A { fun x = 1 } //│ |#new| |A| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A { ‹fun x = 1› }} +//│ Parsed: {new A {fun x = 1}} new A() { fun x = 1 } //│ |#new| |A|(||)| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {(new A)() { ‹fun x = 1› }} +//│ Parsed: {(new A)() {fun x = 1}} new A(1, 2, 3) { fun x = 1 } //│ |#new| |A|(|1|,| |2|,| |3|)| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {(new A)(1, 2, 3,) { ‹fun x = 1› }} +//│ Parsed: {(new A)(1, 2, 3,) {fun x = 1}} new A of 1, 2, 3 { fun x = 1 } //│ |#new| |A| |#of| |1|,| |2|,| |3| |{| |#fun| |x| |#=| |1| |}| -//│ Parsed: {new A(1, 2, 3 { ‹fun x = 1› },)} +//│ Parsed: {new A(1, 2, 3 {fun x = 1},)} :pe diff --git a/shared/src/test/diff/ucs/LeadingAnd.mls b/shared/src/test/diff/ucs/LeadingAnd.mls index faa751e461..2303e4ebbe 100644 --- a/shared/src/test/diff/ucs/LeadingAnd.mls +++ b/shared/src/test/diff/ucs/LeadingAnd.mls @@ -23,7 +23,7 @@ fun f(a, b) = if a is Some(av) and b is Some(bv) then av + bv //│ |#fun| |f|(|a|,| |b|)| |#=| |#if| |a| |is| |Some|(|av|)|→|and| |b| |is| |Some|(|bv|)|↵|#then| |av| |+| |bv|←| -//│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(a), _: Var(b)), If(IfOpApp(Var(a), Var(is), I; f; O; p; s; A; p; p; (; A; p; p; (; V; a; r; (; S; o; m; e; ); ,; ; T; u; p; (; _; :; ; V; a; r; (; a; v; ); ); ); ,; ; <; i; t; e; r; a; t; o; r; >, None)))) +//│ AST: TypingUnit(List(NuFunDef(None,Var(f),None,List(),Left(Lam(Tup(List((None,Fld(_,Var(a))), (None,Fld(_,Var(b))))),If(IfOpApp(Var(a),Var(is),IfOpsApp(App(Var(Some),Tup(List((None,Fld(_,Var(av)))))),List((Var(and),IfThen(App(Var(is),Tup(List((None,Fld(_,Var(b))), (None,Fld(_,App(Var(Some),Tup(List((None,Fld(_,Var(bv))))))))))),App(Var(+),Tup(List((None,Fld(_,Var(av))), (None,Fld(_,Var(bv))))))))))),None)))))) //│ Parsed: fun f = (a, b,) => if a is Some(av,) ‹· and (is(b, Some(bv,),)) then +(av, bv,)›; //│ fun f: (Some[Int], Some[Int]) -> Int @@ -34,7 +34,7 @@ fun f(a, b) = if a is and b is Some(bv) then av + bv //│ |#fun| |f|(|a|,| |b|)| |#=| |#if| |a| |is|→|Some|(|av|)|→|and| |b| |is| |Some|(|bv|)|↵|#then| |av| |+| |bv|←|←| -//│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(a), _: Var(b)), If(IfOpApp(Var(a), Var(is), IfBlock(I; f; O; p; s; A; p; p; (; A; p; p; (; V; a; r; (; S; o; m; e; ); ,; ; T; u; p; (; _; :; ; V; a; r; (; a; v; ); ); ); ,; ; <; i; t; e; r; a; t; o; r; >), None)))) +//│ AST: TypingUnit(List(NuFunDef(None,Var(f),None,List(),Left(Lam(Tup(List((None,Fld(_,Var(a))), (None,Fld(_,Var(b))))),If(IfOpApp(Var(a),Var(is),IfBlock(List(Left(IfOpsApp(App(Var(Some),Tup(List((None,Fld(_,Var(av)))))),List((Var(and),IfThen(App(Var(is),Tup(List((None,Fld(_,Var(b))), (None,Fld(_,App(Var(Some),Tup(List((None,Fld(_,Var(bv))))))))))),App(Var(+),Tup(List((None,Fld(_,Var(av))), (None,Fld(_,Var(bv)))))))))))))),None)))))) //│ Parsed: fun f = (a, b,) => if a is ‹Some(av,) ‹· and (is(b, Some(bv,),)) then +(av, bv,)››; //│ ╔══[ERROR] Illegal pattern `and` //│ ║ l.34: and b is Some(bv) diff --git a/shared/src/test/diff/ucs/SplitOps.mls b/shared/src/test/diff/ucs/SplitOps.mls index 03ee227f54..c966e4b0a1 100644 --- a/shared/src/test/diff/ucs/SplitOps.mls +++ b/shared/src/test/diff/ucs/SplitOps.mls @@ -93,10 +93,10 @@ fun f(a, b, c) = if a == 0 and b is B() and c is C() then 0 //│ |#fun| |f|(|a|,| |b|,| |c|)| |#=|→|#if| |a|→|==| |0| |and| |b| |is| |B|(||)| |and| |c| |is| |C|(||)| |#then| |0|←|←| -//│ AST: TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(a), _: Var(b), _: Var(c)), Blk(...)))) +//│ AST: TypingUnit(List(NuFunDef(None,Var(f),None,List(),Left(Lam(Tup(List((None,Fld(_,Var(a))), (None,Fld(_,Var(b))), (None,Fld(_,Var(c))))),Blk(List(If(IfOpsApp(Var(a),List((Var(==),IfThen(App(App(Var(and),Tup(List((None,Fld(_,App(App(Var(and),Tup(List((None,Fld(_,IntLit(0)))))),Tup(List((None,Fld(_,App(App(Var(is),Tup(List((None,Fld(_,Var(b)))))),Tup(List((None,Fld(_,App(Var(B),Tup(List()))))))))))))))))),Tup(List((None,Fld(_,App(App(Var(is),Tup(List((None,Fld(_,Var(c)))))),Tup(List((None,Fld(_,App(Var(C),Tup(List())))))))))))),IntLit(0))))),None)))))))) //│ Parsed: fun f = (a, b, c,) => {if a ‹· == (and(and(0,)(is(b,)(B(),),),)(is(c,)(C(),),)) then 0›}; //│ Desugared: rec def f: (a, b, c,) => {if a ‹· == (and(and(0,)(is(b,)(B(),),),)(is(c,)(C(),),)) then 0›} -//│ AST: Def(true, f, Lam(Tup(_: Var(a), _: Var(b), _: Var(c)), Blk(...)), true) +//│ AST: Def(true,Var(f),Left(Lam(Tup(List((None,Fld(_,Var(a))), (None,Fld(_,Var(b))), (None,Fld(_,Var(c))))),Blk(List(If(IfOpsApp(Var(a),List((Var(==),IfThen(App(App(Var(and),Tup(List((None,Fld(_,App(App(Var(and),Tup(List((None,Fld(_,IntLit(0)))))),Tup(List((None,Fld(_,App(App(Var(is),Tup(List((None,Fld(_,Var(b)))))),Tup(List((None,Fld(_,App(Var(B),Tup(List()))))))))))))))))),Tup(List((None,Fld(_,App(App(Var(is),Tup(List((None,Fld(_,Var(c)))))),Tup(List((None,Fld(_,App(Var(C),Tup(List())))))))))))),IntLit(0))))),None))))),true) //│ ╔══[ERROR] The case when this is false is not handled: ==(a,)(0,) //│ ║ l.93: if a //│ ║ ^ diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 2edc36dfce..b5772437fd 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -427,10 +427,10 @@ class DiffTests val res = p.parseAll(p.typingUnit) if (parseOnly) - output("Parsed: " + res.showDbg) + output(s"Parsed: ${res.showDbg}") if (mode.showParse) - output("AST: " + mlscript.codegen.Helpers.inspect(res)) + output(s"AST: $res") postProcess(mode, basePath, testName, res).foreach(output) @@ -459,7 +459,7 @@ class DiffTests case Success(p, index) => if (mode.expectParseErrors && !newParser) failures += blockLineNum - if (mode.showParse || mode.dbgParsing) output("Parsed: " + p) + if (mode.showParse || mode.dbgParsing) output("Parsed: " + p.showDbg) // if (mode.isDebugging) typer.resetState() if (mode.stats) typer.resetStats() typer.dbg = mode.dbg @@ -619,10 +619,10 @@ class DiffTests report(diags) if (mode.showParse) { - typeDefs.foreach(td => output("Desugared: " + td)) + typeDefs.foreach(td => output("Desugared: " + td.showDbg)) stmts.foreach { s => - output("Desugared: " + s) - output("AST: " + mlscript.codegen.Helpers.inspect(s)) + output("Desugared: " + s.showDbg) + output(s"AST: $s") } } @@ -769,7 +769,7 @@ class DiffTests declared += nme.name -> ty_sch val exp = getType(ty_sch, N) if (mode.generateTsDeclarations) tsTypegenCodeBuilder.addTypeGenTermDefinition(exp, Some(nme.name)) - S(nme.name -> (s"$nme: ${exp.show(newDefs)}" :: Nil)) + S(nme.name -> (s"${nme.name}: ${exp.show(newDefs)}" :: Nil)) // statement is defined and has a body/definition case d @ Def(isrec, nme, L(rhs), isByname) => @@ -784,7 +784,7 @@ class DiffTests case N => ctx += nme.name -> typer.VarSymbol(ty_sch, nme) if (mode.generateTsDeclarations) tsTypegenCodeBuilder.addTypeGenTermDefinition(exp, Some(nme.name)) - s"$nme: ${exp.show(newDefs)}" :: Nil + s"${nme.name}: ${exp.show(newDefs)}" :: Nil // statement has a body and a declared type // both are used to compute a subsumption (What is this??) @@ -796,7 +796,7 @@ class DiffTests typer.subsume(ty_sch, sign)(ctx, raiseToBuffer, typer.TypeProvenance(d.toLoc, "def definition")) if (mode.generateTsDeclarations) tsTypegenCodeBuilder.addTypeGenTermDefinition(exp, Some(nme.name)) typeBeforeDiags = true - exp.show(newDefs) :: s" <: $nme:" :: sign_exp.show(newDefs) :: Nil + exp.show(newDefs) :: s" <: ${nme.name}:" :: sign_exp.show(newDefs) :: Nil })) case desug: DesugaredStatement => typer.dbg = mode.dbg From 1a7463e281142416ba166e4ca90d22868eed01e6 Mon Sep 17 00:00:00 2001 From: Luyu Cheng Date: Wed, 3 Jan 2024 00:12:56 +0800 Subject: [PATCH 493/498] Fix code generation for local functions declared by `let rec` (#198) --- .../src/main/scala/mlscript/JSBackend.scala | 47 ++++++++++--------- shared/src/test/diff/nu/LetRec.mls | 18 +++---- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala index af39640d95..0351fae58f 100644 --- a/shared/src/main/scala/mlscript/JSBackend.scala +++ b/shared/src/main/scala/mlscript/JSBackend.scala @@ -10,6 +10,15 @@ import scala.util.chaining._ abstract class JSBackend(allowUnresolvedSymbols: Bool) { def oldDefs: Bool + + protected implicit class TermOps(term: Term) { + def isLam: Bool = term match { + case _: Lam => true + case Bra(false, inner) => inner.isLam + case Asc(inner, _) => inner.isLam + case _ => false + } + } /** * The root scope of the program. @@ -237,7 +246,8 @@ abstract class JSBackend(allowUnresolvedSymbols: Bool) { case (t: Term, index) => JSExprStmt(translateTerm(t)(blkScope)) case (NuFunDef(isLetRec, Var(nme), symNme, _, L(rhs)), _) => val symb = symNme.map(_.name) - val pat = blkScope.declareValue(nme, isLetRec, isLetRec.isEmpty, symb) + val isLocalFunction = isLetRec.isEmpty || rhs.isLam + val pat = blkScope.declareValue(nme, isLetRec, isLocalFunction, symb) JSLetDecl(Ls(pat.runtimeName -> S(translateTerm(rhs)(blkScope)))) case (nt: NuTypeDef, _) => translateLocalNewType(nt)(blkScope) // TODO: find out if we need to support this. @@ -1166,18 +1176,17 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { // ``` .concat(otherStmts.flatMap { case Def(recursive, Var(name), L(body), isByname) => - val isLam = body.isInstanceOf[Lam] val (originalExpr, sym) = if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) - val sym = topLevelScope.declareValue(name, isByvalueRecIn, isLam, N) + val sym = topLevelScope.declareValue(name, isByvalueRecIn, body.isLam, N) val translated = translateTerm(body)(topLevelScope) topLevelScope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - (translated, topLevelScope.declareValue(name, isByvalueRecOut, isLam, N)) + (translated, topLevelScope.declareValue(name, isByvalueRecOut, body.isLam, N)) } else { val translatedBody = translateTerm(body)(topLevelScope) val isByvalueRec = if (isByname) None else Some(false) - (translatedBody, topLevelScope.declareValue(name, isByvalueRec, isLam, N)) + (translatedBody, topLevelScope.declareValue(name, isByvalueRec, body.isLam, N)) } val translatedBody = if (sym.isByvalueRec.isEmpty && !sym.isLam) JSArrowFn(Nil, L(originalExpr)) else originalExpr topLevelScope.tempVars `with` JSConstDecl(sym.runtimeName, translatedBody) :: @@ -1227,22 +1236,21 @@ class JSWebBackend extends JSBackend(allowUnresolvedSymbols = true) { case NuFunDef(isLetRec, nme @ Var(name), symNme, tys, rhs @ L(body)) => val recursive = isLetRec.getOrElse(true) val isByname = isLetRec.isEmpty - val bodyIsLam = body match { case _: Lam => true case _ => false } val symb = symNme.map(_.name) val (originalExpr, sym) = (if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) // TODO Improve: (Lionel) what?! - val sym = topLevelScope.declareValue(name, isByvalueRecIn, bodyIsLam, N) + val sym = topLevelScope.declareValue(name, isByvalueRecIn, body.isLam, N) val translated = translateTerm(body)(topLevelScope) topLevelScope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - (translated, topLevelScope.declareValue(name, isByvalueRecOut, bodyIsLam, symb)) + (translated, topLevelScope.declareValue(name, isByvalueRecOut, body.isLam, symb)) } else { val translated = translateTerm(body)(topLevelScope) val isByvalueRec = if (isByname) None else Some(false) - (translated, topLevelScope.declareValue(name, isByvalueRec, bodyIsLam, symb)) + (translated, topLevelScope.declareValue(name, isByvalueRec, body.isLam, symb)) }) val translatedBody = if (sym.isByvalueRec.isEmpty && !sym.isLam) JSArrowFn(Nil, L(originalExpr)) else originalExpr resultNames += sym.runtimeName @@ -1320,15 +1328,14 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { // Generate statements. val queries = otherStmts.map { case Def(recursive, Var(name), L(body), isByname) => - val bodyIsLam = body match { case _: Lam => true case _ => false } (if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) - val sym = scope.declareValue(name, isByvalueRecIn, bodyIsLam, N) + val sym = scope.declareValue(name, isByvalueRecIn, body.isLam, N) try { val translated = translateTerm(body) scope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - R((translated, scope.declareValue(name, isByvalueRecOut, bodyIsLam, N))) + R((translated, scope.declareValue(name, isByvalueRecOut, body.isLam, N))) } catch { case e: UnimplementedError => scope.stubize(sym, e.symbol) @@ -1336,7 +1343,7 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case NonFatal(e) => scope.unregisterSymbol(sym) val isByvalueRecOut = if (isByname) None else Some(false) - scope.declareValue(name, isByvalueRecOut, bodyIsLam, N) + scope.declareValue(name, isByvalueRecOut, body.isLam, N) throw e } } else { @@ -1346,7 +1353,7 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { L(e.getMessage()) }) map { val isByvalueRec = if (isByname) None else Some(false) - expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam, N)) + expr => (expr, scope.declareValue(name, isByvalueRec, body.isLam, N)) } }) match { case R((originalExpr, sym)) => @@ -1404,9 +1411,8 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case fd @ NuFunDef(isLetRec, Var(nme), symNme, _, L(body)) => val isByname = isLetRec.isEmpty val isByvalueRecIn = if (isByname) None else Some(true) - val bodyIsLam = body match { case _: Lam => true case _ => false } val symb = symNme.map(_.name) - scope.declareValue(nme, isByvalueRecIn, bodyIsLam, symb, true) + scope.declareValue(nme, isByvalueRecIn, body.isLam, symb, true) case _ => () } @@ -1434,26 +1440,25 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { case NuFunDef(isLetRec, nme @ Var(name), symNme, tys, rhs @ L(body)) => val recursive = isLetRec.getOrElse(true) val isByname = isLetRec.isEmpty - val bodyIsLam = body match { case _: Lam => true case _ => false } val symb = symNme.map(_.name) (if (recursive) { val isByvalueRecIn = if (isByname) None else Some(true) val sym = scope.resolveValue(name) match { case Some(s: ValueSymbol) => s - case _ => scope.declareValue(name, isByvalueRecIn, bodyIsLam, symb) + case _ => scope.declareValue(name, isByvalueRecIn, body.isLam, symb) } val isByvalueRecOut = if (isByname) None else Some(false) try { val translated = translateTerm(body) // TODO Improve: (Lionel) Why are the bodies translated in the SAME scope?! scope.unregisterSymbol(sym) // TODO Improve: (Lionel) ??? - R((translated, scope.declareValue(name, isByvalueRecOut, bodyIsLam, symb))) + R((translated, scope.declareValue(name, isByvalueRecOut, body.isLam, symb))) } catch { case e: UnimplementedError => scope.stubize(sym, e.symbol) L(e.getMessage()) case NonFatal(e) => scope.unregisterSymbol(sym) // TODO Improve: (Lionel) You should only try/catch around the part that may actually fail, and if `unregisterSymbol` should always be called, that should be done in `finally`... but the very logic of calling `unregisterSymbol` is very fishy, to say the least - scope.declareValue(name, isByvalueRecOut, bodyIsLam, symb) + scope.declareValue(name, isByvalueRecOut, body.isLam, symb) throw e } } else { @@ -1463,7 +1468,7 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) { L(e.getMessage()) }) map { val isByvalueRec = if (isByname) None else Some(false) - expr => (expr, scope.declareValue(name, isByvalueRec, bodyIsLam, symb)) + expr => (expr, scope.declareValue(name, isByvalueRec, body.isLam, symb)) } }) match { case R((originalExpr, sym)) => diff --git a/shared/src/test/diff/nu/LetRec.mls b/shared/src/test/diff/nu/LetRec.mls index f990934e26..1ff16fa41a 100644 --- a/shared/src/test/diff/nu/LetRec.mls +++ b/shared/src/test/diff/nu/LetRec.mls @@ -95,29 +95,29 @@ fun test = //│ Code generation encountered an error: //│ unguarded recursive use of by-value binding f -:ge // TODO this one should actually be accepted by codegen! fun test = let rec f() = f() //│ fun test: () -//│ Code generation encountered an error: -//│ unguarded recursive use of by-value binding f -:ge // TODO this one should actually be accepted by codegen! fun test = let rec lol = () => lol //│ fun test: () -//│ Code generation encountered an error: -//│ unguarded recursive use of by-value binding lol -:ge // TODO this one should actually be accepted by codegen! fun test = let rec lol() = lol lol //│ fun test: forall 'lol. 'lol //│ where //│ 'lol :> () -> 'lol -//│ Code generation encountered an error: -//│ unguarded recursive use of by-value binding lol + +fun testWithAsc = + let rec aux: Int -> Int = x => if x <= 0 then 1 else x * aux(x - 1) + aux(10) +testWithAsc +//│ fun testWithAsc: Int +//│ Int +//│ res +//│ = 3628800 let rec lol = () => lol //│ let rec lol: forall 'lol. 'lol From e3622416acb3b4d6cdad1571e6263e97f4834a69 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 4 Jan 2024 10:05:22 +0800 Subject: [PATCH 494/498] Update NodeTest --- shared/src/test/scala/mlscript/NodeTest.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/test/scala/mlscript/NodeTest.scala b/shared/src/test/scala/mlscript/NodeTest.scala index 1d23160af2..f10b7d895e 100644 --- a/shared/src/test/scala/mlscript/NodeTest.scala +++ b/shared/src/test/scala/mlscript/NodeTest.scala @@ -17,6 +17,7 @@ class NodeTests extends org.scalatest.funsuite.AnyFunSuite { || v.startsWith("v18") || v.startsWith("v19") || v.startsWith("v20") + || v.startsWith("v21") ) } From a68e1de75a2d61ca8caeb1d092db3b6832d46486 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 11 Jan 2024 09:20:26 +0800 Subject: [PATCH 495/498] Introduce comma operator and use `,`/`;` instead of `;`/`;;` (#204) --- shared/src/main/scala/mlscript/NewLexer.scala | 9 +- .../src/main/scala/mlscript/NewParser.scala | 183 ++++---- .../src/main/scala/mlscript/NuTypeDefs.scala | 4 +- shared/src/main/scala/mlscript/Token.scala | 2 + shared/src/main/scala/mlscript/Typer.scala | 9 +- .../main/scala/mlscript/codegen/Codegen.scala | 9 +- shared/src/main/scala/mlscript/helpers.scala | 2 +- shared/src/main/scala/mlscript/syntax.scala | 2 +- shared/src/test/diff/basics/Datatypes.fun | 4 +- .../src/test/diff/codegen/ConstructorStmt.mls | 10 +- shared/src/test/diff/codegen/ValLet.mls | 18 +- shared/src/test/diff/fcp-lit/QML.mls | 2 +- shared/src/test/diff/mlscript/MutArray.mls | 12 +- shared/src/test/diff/mlscript/Sequence.mls | 43 +- shared/src/test/diff/nu/Ascription.mls | 4 +- shared/src/test/diff/nu/AuxCtors.mls | 50 +-- shared/src/test/diff/nu/BadClasses.mls | 4 +- shared/src/test/diff/nu/BasicClasses.mls | 4 +- shared/src/test/diff/nu/CaseExpr.mls | 31 +- shared/src/test/diff/nu/CommaOperator.mls | 424 ++++++++++++++++++ shared/src/test/diff/nu/DiamondInherit.mls | 4 +- shared/src/test/diff/nu/Eval.mls | 58 +-- shared/src/test/diff/nu/FilterMap.mls | 4 +- shared/src/test/diff/nu/FlatMonads_repro.mls | 4 +- shared/src/test/diff/nu/FunPatterns.mls | 18 +- shared/src/test/diff/nu/GenericClasses.mls | 2 +- .../src/test/diff/nu/ImplicitMethodPolym.mls | 35 +- .../diff/nu/InferredInheritanceTypeArgs.mls | 2 +- shared/src/test/diff/nu/Misc.mls | 79 ++-- shared/src/test/diff/nu/Mixin42.mls | 2 +- shared/src/test/diff/nu/Mut.mls | 60 ++- shared/src/test/diff/nu/NewNew.mls | 16 +- .../test/diff/nu/NuPolymorphicTypeAliases.mls | 4 +- shared/src/test/diff/nu/Object.mls | 6 +- shared/src/test/diff/nu/OpLam.mls | 48 +- shared/src/test/diff/nu/ParamPassing.mls | 8 +- shared/src/test/diff/nu/Parens.mls | 36 +- shared/src/test/diff/nu/TODO_Classes.mls | 6 +- .../src/test/diff/nu/ThisRefinedClasses.mls | 22 +- shared/src/test/diff/nu/TypeVariables.mls | 16 +- shared/src/test/diff/nu/Unit.mls | 145 +++--- shared/src/test/diff/nu/WeirdUnions.mls | 14 +- shared/src/test/diff/parser/Arrays.mls | 22 +- shared/src/test/diff/parser/BasicSyntax.mls | 75 ++-- shared/src/test/diff/parser/Blocks.mls | 44 +- shared/src/test/diff/parser/Classes.mls | 22 +- shared/src/test/diff/parser/FatArrows.mls | 57 +++ shared/src/test/diff/parser/IfThenElse.mls | 23 +- shared/src/test/diff/parser/Lets.mls | 49 +- shared/src/test/diff/parser/Misc.mls | 18 +- shared/src/test/diff/parser/NamedArrays.mls | 73 +-- shared/src/test/diff/parser/Select.mls | 16 +- shared/src/test/diff/parser/Where.mls | 8 +- shared/src/test/diff/tapl/Untyped.mls | 2 +- shared/src/test/diff/ucs/InterleavedLet.mls | 4 +- .../src/test/scala/mlscript/DiffTests.scala | 30 +- shared/src/test/scala/mlscript/ReplHost.scala | 6 +- 57 files changed, 1200 insertions(+), 664 deletions(-) create mode 100644 shared/src/test/diff/nu/CommaOperator.mls create mode 100644 shared/src/test/diff/parser/FatArrows.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 4985c2fcea..6457fb5804 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -17,7 +17,7 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { private val isOpChar = Set( '!', '#', '%', '&', '*', '+', '-', '/', ':', '<', '=', '>', '?', '@', '\\', '^', '|', '~' , '.', // ',', - ';' + // ';' ) def isIdentFirstChar(c: Char): Bool = c.isLetter || c === '_' || c === '\'' @@ -45,7 +45,8 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { "=>", "=", ":", - ";;", + ";", + // ",", "#", // ".", // "<", @@ -209,6 +210,9 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { val j = i + 1 // go(j, COMMA) lex(j, ind, next(j, COMMA)) + case ';' => + val j = i + 1 + lex(j, ind, next(j, SEMI)) case '"' => val j = i + 1 val (chars, k) = str(j, false) @@ -441,6 +445,7 @@ object NewLexer { def printToken(tl: TokLoc): Str = tl match { case (SPACE, _) => " " case (COMMA, _) => "," + case (SEMI, _) => ";" case (NEWLINE, _) => "↵" case (INDENT, _) => "→" case (DEINDENT, _) => "←" diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index a85ea1a831..af6f34d577 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -16,6 +16,66 @@ object NewParser { final def expectThen(implicit ptr: ExpectThen): Bool = ptr === true final def foundErr(implicit ptr: FoundErr): Bool = ptr === true + type TokLoc = (Stroken, Loc) + + type LTL = Ls[TokLoc] + + private val MinPrec = 0 + private val NoElsePrec = MinPrec + 1 + + private val prec: Map[Char,Int] = + List( + "", // 0 is the virtual precedence of 'else' + "", + "", + "", + "", + "", + // ^ for keywords + // ";", + ",", + "=", + "@", + ":", + "|", + "/ \\", + "^", + "&", + // "= !", + "!", + "< >", + "+ -", + // "* / %", + "* %", + "", // Precedence of application + ".", + ).zipWithIndex.flatMap { + case (cs, i) => cs.filterNot(_ === ' ').map(_ -> (i + 1)) + }.toMap.withDefaultValue(Int.MaxValue) + + private val AppPrec = prec('.') - 1 + + final def opCharPrec(opChar: Char): Int = prec(opChar) + final def opPrec(opStr: Str): (Int, Int) = opStr match { + case "is" => (4, 4) + case "and" => (3, 3) + case "or" => (2, 2) + case "=>" => + // * The lambda operator is special: + // * it should associate very strongly on the left and very loosely on the right + // * so that we can write things like `f() |> x => x is 0` ie `(f()) |> (x => (x is 0))` + val eqPrec = prec('.') // * We pick the tightest precedence + (eqPrec, 1) + // * Note: we used to do this instead which broke the example above on both sides: + // val eqPrec = prec('=') + // (eqPrec, eqPrec - 1) + case _ if opStr.exists(_.isLetter) => + (5, 5) + case _ => + val r = opStr.last + (prec(opStr.head), prec(r) - (if (r === '@' || r === '/' || r === ',' || r === ':') 1 else 0)) + } + } import NewParser._ @@ -91,67 +151,6 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo printDbg(s"Concluded with $res") res } - final def nil: Unit = () - - type TokLoc = (Stroken, Loc) - - type LTL = Ls[TokLoc] - - private val MinPrec = 0 - private val NoElsePrec = MinPrec + 1 - - private val prec: Map[Char,Int] = - List( - "", // 0 is the virtual precedence of 'else' - "", - "", - "", - "", - "", - // ^ for keywords - ",", - ";", - "=", - "@", - ":", - "|", - "/ \\", - "^", - "&", - // "= !", - "!", - "< >", - "+ -", - // "* / %", - "* %", - "", // Precedence of application - ".", - ).zipWithIndex.flatMap { - case (cs, i) => cs.filterNot(_ === ' ').map(_ -> (i + 1)) - }.toMap.withDefaultValue(Int.MaxValue) - - private val AppPrec = prec('.') - 1 - - final def opCharPrec(opChar: Char): Int = prec(opChar) - final def opPrec(opStr: Str): (Int, Int) = opStr match { - case "is" => (4, 4) - case "and" => (3, 3) - case "or" => (2, 2) - case "=>" => - // * The lambda operator is special: - // * it should associate veyr strongly on the left and very loosely on the right - // * so that we can write things like `f() |> x => x is 0` ie `(f()) |> (x => (x is 0))` - val eqPrec = prec('.') // * We pick the tightest precedence - (eqPrec, 1) - // * Note: we used to do this instead which broke the example above on both sides: - // val eqPrec = prec('=') - // (eqPrec, eqPrec - 1) - case _ if opStr.exists(_.isLetter) => - (5, 5) - case _ => - val r = opStr.last - (prec(opStr.head), prec(r) - (if (r === '@' || r === '/' || r === ',' || r === ':') 1 else 0)) - } // def pe(msg: Message, l: Loc, rest: (Message, Opt[Loc])*): Unit = // err((msg -> S(l) :: rest.toList)) // TODO parse err @@ -373,7 +372,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo def otherParents: Ls[Term] = yeetSpaces match { case (COMMA, _) :: _ => consume - expr(0) :: otherParents + expr(prec(',')) :: otherParents // we don't want to parse parent lists as including comma expressions case _ => Nil } val sigTrm = yeetSpaces match { @@ -391,7 +390,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo // expr(0) :: otherParents case (KEYWORD("extends"), _) :: _ => consume - expr(0) :: otherParents + expr(prec(',')) :: otherParents // we don't want to parse parent lists as including comma expressions case _ => Nil } val (sigTrm2, ps2, fullTu) = curlyTypingUnit.fold { @@ -509,9 +508,17 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo val body = expr(0) val newBody = transformBody.fold(body)(_(body)) val annotatedBody = asc.fold(newBody)(ty => Asc(newBody, ty)) - R(NuFunDef( - isLetRec, v, opStr, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))) - )(isDecl, isVirtual, N, N, genField).withLoc(S(l0 ++ annotatedBody.toLoc))) + yeetSpaces match { + case (KEYWORD("in"), l1) :: _ if kwStr === "let" => + consume + if (tparams.nonEmpty) err(msg"Unsupported type parameters on 'let' binding" -> S(l1) :: Nil) + val rest = expr(0) + R(Let(isLetRec.getOrElse(die), v, body, rest).withLoc(S(l0 ++ annotatedBody.toLoc))) + case _ => + R(NuFunDef( + isLetRec, v, opStr, tparams, L(ps.foldRight(annotatedBody)((i, acc) => Lam(i, acc))) + )(isDecl, isVirtual, N, N, genField).withLoc(S(l0 ++ annotatedBody.toLoc))) + } case c => asc match { case S(ty) => @@ -547,7 +554,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case _ => t } yeetSpaces match { - case (KEYWORD(";;"), _) :: _ => consume; finalTerm :: block + case (SEMI, _) :: _ => consume; finalTerm :: block case (NEWLINE, _) :: _ => consume; finalTerm :: block case _ => finalTerm :: Nil } @@ -640,11 +647,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo })) case (Round, (N, Fld(FldFlags(false, false, _), elt)) :: Nil) => Bra(false, elt) - case (Round, fs) => + case (Round, _) => yeetSpaces match { case (KEYWORD("=>"), l1) :: _ => consume - val e = expr(0) + val e = expr(NewParser.opPrec("=>")._2) Lam(Tup(res), e) case (IDENT("->", true), l1) :: _ => consume @@ -655,9 +662,13 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case Nil => UnitLit(true) case _ => - err(( - msg"Expected '=>' or '->' after this parameter section" -> S(loc) :: Nil)) - Tup(fs) + res.map { + case N -> Fld(FldFlags.empty, t) => t + case no -> Fld(_, t) => + err((msg"Illegal position for field specification" -> Loc(no.toList :+ t) :: Nil)) + t + }.reduceRight((t, acc) => + App(Var(",").withLoc(Loc(t :: acc :: Nil)), PlainTup(t, acc))) } } case _ => @@ -692,7 +703,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo consume val bs = bindings(Nil) val body = yeetSpaces match { - case (KEYWORD("in" | ";;"), _) :: _ => + case (KEYWORD("in") | SEMI, _) :: _ => consume exprOrIf(0) case (NEWLINE, _) :: _ => @@ -707,7 +718,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo } case (KEYWORD("new"), l0) :: c => consume - val body = expr(outer.prec('.')) + val body = expr(NewParser.prec('.')) exprCont(NuNew(body).withLoc(S(l0 ++ body.toLoc)), prec, allowNewlines = false) case (KEYWORD("else"), l0) :: _ => consume @@ -761,7 +772,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo // S(thn, S(nested.concludeWith(_.expr(0)))) S(nested.concludeWith(_.expr(0))) case _ => - nested.concludeWith(_.nil) + nested.concludeWith(_ => ()) // S(thn, N) N } @@ -782,7 +793,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case Nil => err(msg"Unexpected end of $description; an expression was expected here" -> lastLoc :: Nil) R(errExpr) - case ((KEYWORD(";;") /* | NEWLINE */ /* | BRACKETS(Curly, _) */, l0) :: _) => + case ((SEMI /* | NEWLINE */ /* | BRACKETS(Curly, _) */, l0) :: _) => R(UnitLit(true).withLoc(S(l0))) // R(errExpr) // TODO case (IDENT("-", true), l0) :: _ /*if opPrec("-")._1 > prec*/ => // Unary minus @@ -809,6 +820,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo final def exprCont(acc: Term, prec: Int, allowNewlines: Bool)(implicit et: ExpectThen, fe: FoundErr, l: Line): IfBody \/ Term = wrap(prec, s"`$acc`", allowNewlines) { l => cur match { + case (COMMA, l0) :: _ if prec === 0 => + consume + yeetSpaces match { + case (NEWLINE, _) :: _ => consume + case _ => + } + val rhs = expr(prec) // TODO support exprOrIf for comma operators + R(App(Var(",").withLoc(S(l0)), PlainTup(acc, rhs))) case (KEYWORD(opStr @ "=>"), l0) :: (NEWLINE, l1) :: _ if opPrec(opStr)._1 > prec => consume val rhs = Blk(typingUnit.entities) @@ -844,14 +863,12 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo err(msg"record literal expected here; found ${rhs.describe}" -> rhs.toLoc :: Nil) acc } - case ";" => - Blk(acc :: rhs :: Nil) case _ => if (newDefs) App(v, PlainTup(acc, rhs)) else App(App(v, PlainTup(acc)), PlainTup(rhs)) }, prec, allowNewlines) } - case (KEYWORD(":"), l0) :: _ if prec <= outer.prec(':') => + case (KEYWORD(":"), l0) :: _ if prec <= NewParser.prec(':') => consume R(Asc(acc, typ(0))) case (KEYWORD("where"), l0) :: _ if prec <= 1 => @@ -896,7 +913,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo val tu = rec(toks, S(br.innerLoc), br.describe).concludeWith(_.typingUnitMaybeIndented).withLoc(S(loc)) exprCont(Rft(acc, tu), prec, allowNewlines) - case (COMMA | NEWLINE | KEYWORD("then" | "else" | "in" | ";;" | "=") + case (COMMA | SEMI | NEWLINE | KEYWORD("then" | "else" | "in" | "=") | IDENT(_, true) | BRACKETS(Curly, _), _) :: _ => R(acc) case (KEYWORD("of"), _) :: _ if prec <= 1 => @@ -974,9 +991,9 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo exprCont(res, prec, allowNewlines) case c @ (h :: _) if (h._1 match { - case KEYWORD(";;" | ":" | "of" | "where" | "extends") | BRACKETS(Round | Square, _) + case KEYWORD(":" | "of" | "where" | "extends") | SEMI | BRACKETS(Round | Square, _) | BRACKETS(Indent, ( - KEYWORD(";;" | "of") + KEYWORD("of") | SEMI | BRACKETS(Round | Square, _) | SELECT(_) , _) :: _) @@ -1224,7 +1241,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (SPACE, _) :: _ => consume bindings(acc) - case (NEWLINE | IDENT(_, true) | KEYWORD(";;"), _) :: _ => // TODO: | ... + case (NEWLINE | IDENT(_, true) | SEMI, _) :: _ => // TODO: | ... acc.reverse case (IDENT(id, false), l0) :: _ => consume diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 8d97dc0006..9349566a55 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -667,8 +667,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case _ => constrain(mkProxy(ty, TypeProvenance(t.toCoveringLoc, "expression in statement position")), UnitType)( raise = err => raise(WarningReport( // Demote constraint errors from this to warnings - msg"Expression in statement position should have type `unit`." -> N :: - msg"Use the `discard` function to discard non-unit values, making the intent clearer." -> N :: + msg"Expression in statement position should have type `()`." -> N :: + msg"Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer." -> N :: err.allMsgs, newDefs)), prov = TypeProvenance(t.toLoc, t.describe), ctx) } diff --git a/shared/src/main/scala/mlscript/Token.scala b/shared/src/main/scala/mlscript/Token.scala index d90bd6f207..041055cac1 100644 --- a/shared/src/main/scala/mlscript/Token.scala +++ b/shared/src/main/scala/mlscript/Token.scala @@ -8,6 +8,7 @@ sealed abstract class Token { def describe: Str = this match { case SPACE => "space" case COMMA => "comma" + case SEMI => "semicolon" case NEWLINE => "newline" case INDENT => "indentation" case DEINDENT => "deindentation" @@ -31,6 +32,7 @@ sealed trait Stroken extends Token case object SPACE extends Token with Stroken case object COMMA extends Token with Stroken +case object SEMI extends Token with Stroken case object NEWLINE extends Token with Stroken // TODO rm case object INDENT extends Token case object DEINDENT extends Token diff --git a/shared/src/main/scala/mlscript/Typer.scala b/shared/src/main/scala/mlscript/Typer.scala index 3a3e5d15d4..f45478abea 100644 --- a/shared/src/main/scala/mlscript/Typer.scala +++ b/shared/src/main/scala/mlscript/Typer.scala @@ -283,6 +283,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne if (funkyTuples) ty else TupleType((N, ty.toUpper(ty.prov) ) :: Nil)(noProv) def pair(ty1: ST, ty2: ST): ST = TupleType(N -> ty1.toUpper(ty1.prov) :: N -> ty2.toUpper(ty2.prov) :: Nil)(noProv) + private val sharedVar = freshVar(noProv, N)(1) val builtinBindings: Bindings = { val tv = freshVar(noProv, N)(1) import FunctionType.{ apply => fun } @@ -338,6 +339,10 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne PolymorphicType(MinLevel, fun(singleTup(v), fun(singleTup(v), BoolType)(noProv))(noProv)) }, "error" -> BotType, + "," -> { + val v = sharedVar + PolymorphicType(MinLevel, fun(TupleType(N -> TopType.toUpper(provTODO) :: N -> v.toUpper(provTODO) :: Nil)(noProv), v)(noProv)) + }, "+" -> intBinOpTy, "-" -> intBinOpTy, "*" -> intBinOpTy, @@ -349,7 +354,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne ">=" -> numberBinPred, "==" -> numberBinPred, "===" -> { - val v = freshVar(noProv, N)(1) + val v = sharedVar val eq = TypeRef(TypeName("Eql"), v :: Nil)(noProv) PolymorphicType(MinLevel, fun(pair(eq, v), BoolType)(noProv)) }, @@ -719,7 +724,7 @@ class Typer(var dbg: Boolean, var verbose: Bool, var explainErrors: Bool, val ne } // TODO also prevent rebinding of "not" - val reservedVarNames: Set[Str] = Set("|", "&", "~", ",", "neg", "and", "or", "is") + val reservedVarNames: Set[Str] = Set("|", "&", "~", "neg", "and", "or", "is") object ValidVar { def unapply(v: Var)(implicit raise: Raise): S[Str] = S { diff --git a/shared/src/main/scala/mlscript/codegen/Codegen.scala b/shared/src/main/scala/mlscript/codegen/Codegen.scala index 9a785cfc10..f398407c6d 100644 --- a/shared/src/main/scala/mlscript/codegen/Codegen.scala +++ b/shared/src/main/scala/mlscript/codegen/Codegen.scala @@ -374,7 +374,7 @@ object JSExpr { def arguments(exprs: Ls[JSExpr]): SourceCode = exprs.zipWithIndex .foldLeft(SourceCode.empty) { case (x, (y, i)) => - x ++ y.toSourceCode ++ (if (i === exprs.length - 1) SourceCode.empty + x ++ y.embed(parentPrecedence = JSCommaExpr.outerPrecedence) ++ (if (i === exprs.length - 1) SourceCode.empty else SourceCode(", ")) } .parenthesized @@ -411,7 +411,7 @@ final case class JSArrowFn(params: Ls[JSPattern], body: JSExpr \/ Ls[JSStmt]) ex case pattern => pattern.toSourceCode }) ++ (if (i === params.length - 1) SourceCode.empty else SourceCode(", ")) } - .parenthesized ++ SourceCode(" => ") ++ (body match { + .parenthesized ++ SourceCode.fatArrow ++ (body match { // TODO: Figure out how `=>` competes with other operators. case L(expr: JSRecord) => expr.toSourceCode.parenthesized case L(expr) => expr.embed @@ -444,7 +444,7 @@ final case class JSImmEvalFn( case None => (SourceCode(s"${JSExpr.params(params)} => ") ++ (body match { case Left(expr: JSRecord) => expr.toSourceCode.parenthesized - case Left(expr) => expr.toSourceCode + case Left(expr) => expr.embed(parentPrecedence = 2) case Right(stmts) => stmts.foldLeft(SourceCode.empty) { _ + _.toSourceCode }.block })).parenthesized ++ JSExpr.arguments(arguments) @@ -534,7 +534,8 @@ object JSBinary { "&&" -> 5, // infixl 4 "||" -> 4, - "??" -> 4 + "??" -> 4, + "," -> 1, ) val operators: Set[Str] = opPrecMap.keySet diff --git a/shared/src/main/scala/mlscript/helpers.scala b/shared/src/main/scala/mlscript/helpers.scala index b6154bd409..3e664b3e65 100644 --- a/shared/src/main/scala/mlscript/helpers.scala +++ b/shared/src/main/scala/mlscript/helpers.scala @@ -629,7 +629,7 @@ trait TermImpl extends StatementImpl { self: Term => try R(toType_!.withLocOf(this)) catch { case e: NotAType => import Message._ - L(ErrorReport(msg"Not a recognized type" -> e.trm.toLoc::Nil, newDefs=true)) } + L(ErrorReport(msg"Not a recognized type" -> e.trm.toLoc::Nil, newDefs=true, source=Diagnostic.Parsing)) } protected def toType_! : Type = (this match { case Var(name) if name.startsWith("`") => TypeVar(R(name.tail), N) case Var(name) if name.startsWith("'") => TypeVar(R(name), N) diff --git a/shared/src/main/scala/mlscript/syntax.scala b/shared/src/main/scala/mlscript/syntax.scala index d3d3b05c4d..35ac9f316f 100644 --- a/shared/src/main/scala/mlscript/syntax.scala +++ b/shared/src/main/scala/mlscript/syntax.scala @@ -104,7 +104,7 @@ final case class IfOpsApp(lhs: Term, opsRhss: Ls[Var -> IfBody]) extends IfBody final case class IfBlock(lines: Ls[IfBody \/ Statement]) extends IfBody // final case class IfApp(fun: Term, opsRhss: Ls[Var -> IfBody]) extends IfBody -final case class FldFlags(mut: Bool, spec: Bool, genGetter: Bool) extends FldFlagsImpl +final case class FldFlags(mut: Bool, spec: Bool, genGetter: Bool) extends FldFlagsImpl // TODO make it a Located and use in diagnostics final case class Fld(flags: FldFlags, value: Term) extends FldImpl object FldFlags { val empty: FldFlags = FldFlags(false, false, false) } diff --git a/shared/src/test/diff/basics/Datatypes.fun b/shared/src/test/diff/basics/Datatypes.fun index 02cad3d2c6..a2950ace06 100644 --- a/shared/src/test/diff/basics/Datatypes.fun +++ b/shared/src/test/diff/basics/Datatypes.fun @@ -109,13 +109,13 @@ Tru : Boolean // data type List of Nil { T: Nothing }, Cons head tail { T: head | tail.T } :p +:pe :w -:e data type List a of Nil Cons (head: a) (tail: List a) //│ Parsed: data type List(...a) of {Nil; Cons(...'(' {[head: a,]} ')')(...'(' {[tail: List(...a),]} ')')}; -//│ ╔══[ERROR] Not a recognized type +//│ ╔══[PARSE ERROR] Not a recognized type //│ ║ l.116: Cons (head: a) (tail: List a) //│ ╙── ^^^^^^ //│ Desugared: type alias List[a] = Nil[a] | Cons[a] diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls index a61301347e..fa0100cef9 100644 --- a/shared/src/test/diff/codegen/ConstructorStmt.mls +++ b/shared/src/test/diff/codegen/ConstructorStmt.mls @@ -147,8 +147,8 @@ class Foo { //│ ╔══[ERROR] Type `#Foo` does not contain member `x` //│ ║ l.145: this: { x: Int } //│ ╙── ^ -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in type ascription: //│ ║ l.145: this: { x: Int } //│ ║ ^^^^ @@ -191,8 +191,8 @@ class Bar { //│ ╔══[ERROR] Type `#Bar` does not contain member `x` //│ ║ l.186: super: { x: Int } //│ ╙── ^ -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in type ascription: //│ ║ l.186: super: { x: Int } //│ ║ ^^^^^ @@ -304,7 +304,7 @@ log([baz.x, baz.y]) class Q() { let q = 42 fun qq = - let f = (x: Int) => {q: x + q};; f(1) + let f = (x: Int) => {q: x + q}; f(1) } //│ class Q() { //│ let q: 42 diff --git a/shared/src/test/diff/codegen/ValLet.mls b/shared/src/test/diff/codegen/ValLet.mls index 1d12ae033c..6cdfebc4cb 100644 --- a/shared/src/test/diff/codegen/ValLet.mls +++ b/shared/src/test/diff/codegen/ValLet.mls @@ -225,26 +225,22 @@ fun f(val x: Int) = x + 1 //│ fun f: (x: Int) -> Int :pe -:e (val x: 1) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.229: (val x: 1) -//│ ╙── ^^^^^^^^^^ -//│ ╔══[ERROR] Cannot use `val` in this position -//│ ║ l.229: (val x: 1) +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.228: (val x: 1) //│ ╙── ^^^^ -//│ [x: 1] +//│ 1 //│ res -//│ = [ 1 ] +//│ = 1 :pe :e (val x: 1) => //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.242: (val x: 1) => +//│ ║ l.238: (val x: 1) => //│ ╙── ^ //│ ╔══[ERROR] Cannot use `val` in this position -//│ ║ l.242: (val x: 1) => +//│ ║ l.238: (val x: 1) => //│ ╙── ^^^^ //│ (x: 1) -> () //│ res @@ -253,7 +249,7 @@ fun f(val x: Int) = x + 1 :e (val x: 1) => () //│ ╔══[ERROR] Cannot use `val` in this position -//│ ║ l.254: (val x: 1) => () +//│ ║ l.250: (val x: 1) => () //│ ╙── ^^^^ //│ (x: 1) -> () //│ res diff --git a/shared/src/test/diff/fcp-lit/QML.mls b/shared/src/test/diff/fcp-lit/QML.mls index d70e9ee16f..df27d94faf 100644 --- a/shared/src/test/diff/fcp-lit/QML.mls +++ b/shared/src/test/diff/fcp-lit/QML.mls @@ -105,7 +105,7 @@ def open p t = p t // Altered from // let f = {exists 'a. 'a * ('a -> 'a) * ('a -> int)} (0, (fun x -> x + 1) , (fun x -> x)); -// open {exists 'a. a * ('a -> 'a) * ('a -> int)} g = f in (snd (snd g)) (fst g);; +// open {exists 'a. a * ('a -> 'a) * ('a -> int)} g = f in (snd (snd g)) (fst g); let f = pack ((0, (fun x -> x + 1, fun x -> x),),) in open f (fun x -> (snd (snd x)) (fst x)) //│ res: 0 diff --git a/shared/src/test/diff/mlscript/MutArray.mls b/shared/src/test/diff/mlscript/MutArray.mls index cafc4adbdd..d60246591f 100644 --- a/shared/src/test/diff/mlscript/MutArray.mls +++ b/shared/src/test/diff/mlscript/MutArray.mls @@ -70,10 +70,8 @@ update0 0 ((mut 1,)) update1 0 ((mut 1,)) //│ = [] -:re // FIXME update2 0 ((mut 1,)) -//│ Runtime error: -//│ TypeError: ((intermediate value) , []) is not a function +//│ = [] @@ -97,16 +95,16 @@ foo = emptyArray :e def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.98: def bar x = (mut x,) : MutArray[int] & MutArray[string] +//│ ║ l.96: def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ║ ^^^^^^^^ //│ ╟── type `string` is not an instance of `int` -//│ ║ l.98: def bar x = (mut x,) : MutArray[int] & MutArray[string] +//│ ║ l.96: def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.98: def bar x = (mut x,) : MutArray[int] & MutArray[string] +//│ ║ l.96: def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ║ ^^^ //│ ╟── from mutable tuple field: -//│ ║ l.98: def bar x = (mut x,) : MutArray[int] & MutArray[string] +//│ ║ l.96: def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ╙── ^ //│ bar: nothing -> MutArray[in int | string out nothing] //│ = [Function: bar] diff --git a/shared/src/test/diff/mlscript/Sequence.mls b/shared/src/test/diff/mlscript/Sequence.mls index 919c7251b1..42743cc59c 100644 --- a/shared/src/test/diff/mlscript/Sequence.mls +++ b/shared/src/test/diff/mlscript/Sequence.mls @@ -1,12 +1,51 @@ :NewDefs +:e let test(x) = log(x); x + 1 +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.5: let test(x) = log(x); x + 1 +//│ ╙── ^ +//│ let test: anything -> () +//│ Int +//│ Code generation encountered an error: +//│ unresolved symbol x + +let test(x) = log(x), x + 1 //│ let test: Int -> Int //│ test -//│ = [Function: test] +//│ = [Function: test1] + +test(1) +//│ Int +//│ res +//│ = 2 +//│ // Output +//│ 1 +:pe +:e test(log("here we go"); 123) +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.28: test(log("here we go"); 123) +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.28: test(log("here we go"); 123) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── application of type `()` is not an instance of type `Int` +//│ ║ l.28: test(log("here we go"); 123) +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.14: let test(x) = log(x), x + 1 +//│ ╙── ^ +//│ Int | error +//│ res +//│ = NaN +//│ // Output +//│ here we go +//│ undefined + +test((log("here we go"), 123)) //│ Int //│ res //│ = 124 @@ -15,7 +54,7 @@ test(log("here we go"); 123) //│ 123 -let a = 1;; let b = a + 1 +let a = 1; let b = a + 1 //│ let a: 1 //│ let b: Int //│ a diff --git a/shared/src/test/diff/nu/Ascription.mls b/shared/src/test/diff/nu/Ascription.mls index 0060edad14..7bc04929e6 100644 --- a/shared/src/test/diff/nu/Ascription.mls +++ b/shared/src/test/diff/nu/Ascription.mls @@ -11,9 +11,9 @@ //│ = 1 // TODO? -:e +:pe 1 : Int : Int -//│ ╔══[ERROR] Not a recognized type +//│ ╔══[PARSE ERROR] Not a recognized type //│ ║ l.15: 1 : Int : Int //│ ╙── ^^^ //│ anything diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index 3f753f4fa8..64f53ed219 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -19,7 +19,7 @@ new C(123).x //│ res //│ = 123 -class C(val x: Int) { constructor(y: Int) { log(y);; x = y;; log(x) } } +class C(val x: Int) { constructor(y: Int) { log(y); x = y; log(x) } } new C(123).x //│ class C(x: Int) { //│ constructor(y: Int) @@ -32,11 +32,11 @@ new C(123).x //│ 123 :e -class C(val x: Int) { constructor(y: Int) { x = y;; log(x);; x = y + 1;; log(x) } } +class C(val x: Int) { constructor(y: Int) { x = y; log(x); x = y + 1; log(x) } } new C(123).x //│ ╔══[ERROR] Class parameter 'x' was already set -//│ ║ l.35: class C(val x: Int) { constructor(y: Int) { x = y;; log(x);; x = y + 1;; log(x) } } -//│ ╙── ^ +//│ ║ l.35: class C(val x: Int) { constructor(y: Int) { x = y; log(x); x = y + 1; log(x) } } +//│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) //│ } @@ -48,9 +48,9 @@ new C(123).x //│ 124 :e -class C(val x: Int) { constructor(y: Int) { log(x);; x = y } } +class C(val x: Int) { constructor(y: Int) { log(x); x = y } } //│ ╔══[ERROR] identifier not found: x -//│ ║ l.51: class C(val x: Int) { constructor(y: Int) { log(x);; x = y } } +//│ ║ l.51: class C(val x: Int) { constructor(y: Int) { log(x); x = y } } //│ ╙── ^ //│ class C(x: Int) { //│ constructor(y: Int) @@ -118,7 +118,7 @@ class C(val x: Int) { constructor(2 + 2) { x = 0 } } class C(val x: Int, y: Int) { - constructor(z: Int) { x = z;; y = z } + constructor(z: Int) { x = z; y = z } log([x, y]) } //│ class C(x: Int, y: Int) { @@ -173,45 +173,43 @@ new C(1, 2) :pe :w -class C { constructor(x: Int);; constructor(y: Int) } +class C { constructor(x: Int); constructor(y: Int) } //│ ╔══[PARSE ERROR] A class may have at most one explicit constructor -//│ ║ l.176: class C { constructor(x: Int);; constructor(y: Int) } +//│ ║ l.176: class C { constructor(x: Int); constructor(y: Int) } //│ ╙── ^^^^^ //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.176: class C { constructor(x: Int);; constructor(y: Int) } -//│ ╙── ^^ +//│ ║ l.176: class C { constructor(x: Int); constructor(y: Int) } +//│ ╙── ^ //│ class C { //│ constructor(x: Int) //│ } :w // * FIXME -class Foo { constructor(x: Int){};; val y = 2 } +class Foo { constructor(x: Int){}; val y = 2 } //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.189: class Foo { constructor(x: Int){};; val y = 2 } -//│ ╙── ^^ +//│ ║ l.189: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╙── ^ //│ class Foo { //│ constructor(x: Int) //│ val y: 2 //│ } -:pe -:e +:w class Foo { constructor(x: Int){}; val y = 2 } -//│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.200: class Foo { constructor(x: Int){}; val y = 2 } +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.199: class Foo { constructor(x: Int){}; val y = 2 } //│ ╙── ^ -//│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.200: class Foo { constructor(x: Int){}; val y = 2 } -//│ ╙── ^^^ -//│ ╔══[ERROR] Unexpected equation in this position -//│ ║ l.200: class Foo { constructor(x: Int){}; val y = 2 } -//│ ╙── ^^^^^ //│ class Foo { //│ constructor(x: Int) +//│ val y: 2 +//│ } + +class Foo { constructor(x: Int){} val y = 2 } +//│ class Foo { +//│ constructor(x: Int) +//│ val y: 2 //│ } -//│ Syntax error: -//│ Private field '#y' must be declared in an enclosing class class Foo { constructor(x: Int){} diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 2fc62489c2..01a818e328 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -105,8 +105,8 @@ class Foo[A] { 42: A } //│ ╟── Note: constraint arises from type parameter: //│ ║ l.100: class Foo[A] { 42: A } //│ ╙── ^ -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in type ascription: //│ ║ l.100: class Foo[A] { 42: A } //│ ║ ^^ diff --git a/shared/src/test/diff/nu/BasicClasses.mls b/shared/src/test/diff/nu/BasicClasses.mls index 0fc43083b4..a24dc50fff 100644 --- a/shared/src/test/diff/nu/BasicClasses.mls +++ b/shared/src/test/diff/nu/BasicClasses.mls @@ -217,8 +217,8 @@ class Annots(base: 0 | 1) { a: Int fun a = base } -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in type ascription: //│ ║ l.217: a: Int //│ ║ ^ diff --git a/shared/src/test/diff/nu/CaseExpr.mls b/shared/src/test/diff/nu/CaseExpr.mls index 59407e65c9..c6ebf859ed 100644 --- a/shared/src/test/diff/nu/CaseExpr.mls +++ b/shared/src/test/diff/nu/CaseExpr.mls @@ -8,10 +8,10 @@ case 0 then true :pe // TODO support case 0 then true, 1 then false -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead +//│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead //│ ║ l.10: case 0 then true, 1 then false -//│ ╙── ^ -//│ 0 -> true +//│ ╙── ^^^^^^^^^^^^ +//│ 0 -> () //│ res //│ = [Function: res] @@ -128,33 +128,30 @@ case then 1 else 0 :pe :e case x, y then x + y -//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'case'; found reference instead +//│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead +//│ ║ l.130: case x, y then x + y +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'case'; found operator application instead //│ ║ l.130: case x, y then x + y -//│ ║ ^ +//│ ║ ^^^^^^^^^^^^^^^ //│ ╟── Note: 'case' expression starts here: //│ ║ l.130: case x, y then x + y //│ ╙── ^^^^ -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.130: case x, y then x + y -//│ ╙── ^ //│ ╔══[ERROR] identifier not found: x //│ ║ l.130: case x, y then x + y //│ ╙── ^ -//│ anything -> error +//│ anything -> () //│ Code generation encountered an error: //│ unresolved symbol x -:pe :e case (x, y) then x + y -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.149: case (x, y) then x + y -//│ ╙── ^^^^^^ -//│ ╔══[ERROR] type identifier not found: Tuple#2 -//│ ╙── -//│ nothing -> error +//│ ╔══[ERROR] Illegal pattern `,` +//│ ║ l.148: case (x, y) then x + y +//│ ╙── ^^^^ +//│ anything -> error //│ Code generation encountered an error: -//│ unknown match case: Tuple#2 +//│ if expression was not desugared :e // * FIXME[UCS] case [x, y] then x + y diff --git a/shared/src/test/diff/nu/CommaOperator.mls b/shared/src/test/diff/nu/CommaOperator.mls new file mode 100644 index 0000000000..6d7e46db0b --- /dev/null +++ b/shared/src/test/diff/nu/CommaOperator.mls @@ -0,0 +1,424 @@ +:NewDefs + + +1; 2 +//│ 2 +//│ res +//│ = 1 +//│ res +//│ = 2 + +// :dp +:js +1, 2 +//│ 2 +//│ // Prelude +//│ class TypingUnit1 {} +//│ const typing_unit1 = new TypingUnit1; +//│ // Query 1 +//│ res = (1 , 2); +//│ // End of generated code +//│ res +//│ = 2 + +(1, 2) +//│ 2 +//│ res +//│ = 2 + +(1, 2, 3) +//│ 3 +//│ res +//│ = 3 + +1, () +//│ () +//│ res +//│ = undefined + +log(1), 2 +//│ 2 +//│ res +//│ = 2 +//│ // Output +//│ 1 + + +(), +1 +//│ 1 +//│ res +//│ = 1 + +:pe +(), +1, +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.55: 1, +//│ ╙── ^ +//│ () +//│ res +//│ = undefined + +(), + 1 +//│ 1 +//│ res +//│ = 1 + +(), + log("ok") + 1 +//│ 1 +//│ res +//│ = 1 +//│ // Output +//│ ok + +:w +(), + 2 + 2 + 1 +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. +//│ ╟── Type mismatch in operator application: +//│ ║ l.80: 2 + 2 +//│ ║ ^^^^^ +//│ ╙── operator application of type `Int` does not match type `()` +//│ 1 +//│ res +//│ = 1 + +(), + 2 + 2, () + 1 +//│ 1 +//│ res +//│ = 1 + + + +let a = 1, 2 +//│ let a: 2 +//│ a +//│ = 2 + +let a = 1; 2 +//│ let a: 1 +//│ 2 +//│ a +//│ = 1 +//│ res +//│ = 2 + +:pe // TODO support; make `;` have even less precedence than `,` +(1;2) +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.115: (1;2) +//│ ╙── ^ +//│ 1 +//│ res +//│ = 1 + +:pe +(1,2;3) +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.124: (1,2;3) +//│ ╙── ^ +//│ 2 +//│ res +//│ = 2 + +(log(1), 2) +//│ 2 +//│ res +//│ = 2 +//│ // Output +//│ 1 + + + +fun foo(x) = x +//│ fun foo: forall 'a. 'a -> 'a + +:pe +foo(1;2) +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.145: foo(1;2) +//│ ╙── ^ +//│ 1 +//│ res +//│ = 1 + +foo(let x = 1; x + 1) +//│ Int +//│ res +//│ = 2 + +:js +foo(let x = log(0), 1; log(x), x + 1) +//│ Int +//│ // Prelude +//│ class TypingUnit20 {} +//│ const typing_unit20 = new TypingUnit20; +//│ // Query 1 +//│ res = foo(((x) => (log(x) , x + 1))((log(0) , 1))); +//│ // End of generated code +//│ res +//│ = 2 +//│ // Output +//│ 0 +//│ 1 + + +:js +foo((1, 2)) +//│ 2 +//│ // Prelude +//│ class TypingUnit21 {} +//│ const typing_unit21 = new TypingUnit21; +//│ // Query 1 +//│ res = foo((1 , 2)); +//│ // End of generated code +//│ res +//│ = 2 + +foo(let x = 1; x + 1) +//│ Int +//│ res +//│ = 2 + +foo(let x = 1 in x + 1) +//│ Int +//│ res +//│ = 2 + +foo((log(1), 2)) +//│ 2 +//│ res +//│ = 2 +//│ // Output +//│ 1 + +foo(1), 2 +//│ 2 +//│ res +//│ = 2 + + +:ge // FIXME +let rec x() = x() in x +//│ nothing +//│ Code generation encountered an error: +//│ recursive non-function definition x is not supported + + +:pe +let x[T] = 1 in x +//│ ╔══[PARSE ERROR] Expected function parameter list; found square bracket section instead +//│ ║ l.217: let x[T] = 1 in x +//│ ╙── ^^^ +//│ 1 +//│ res +//│ = 1 + + +let x = 2 in log(x), x + 1 +//│ Int +//│ res +//│ = 3 +//│ // Output +//│ 2 + +let x = 2; log(x), x + 1 +//│ let x: 2 +//│ Int +//│ x +//│ = 2 +//│ res +//│ = 3 +//│ // Output +//│ 2 + + + +fun foo(x, y) = [x, y] +//│ fun foo: forall 'a 'b. ('a, 'b) -> ['a, 'b] + +foo(1,2) +//│ [1, 2] +//│ res +//│ = [ 1, 2 ] + +foo(log(1),2) +//│ [(), 2] +//│ res +//│ = [ undefined, 2 ] +//│ // Output +//│ 1 + +foo( + log(1), + 2 +) +//│ [(), 2] +//│ res +//│ = [ undefined, 2 ] +//│ // Output +//│ 1 + +foo( + log(1), + 2, +) +//│ [(), 2] +//│ res +//│ = [ undefined, 2 ] +//│ // Output +//│ 1 + +:pe +:e +foo(log(1);2) +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.282: foo(log(1);2) +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.282: foo(log(1);2) +//│ ║ ^^^^^^^^^^^^^ +//│ ╟── argument of type `[?a]` does not match type `[?b, ?c]` +//│ ║ l.282: foo(log(1);2) +//│ ║ ^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.245: fun foo(x, y) = [x, y] +//│ ╙── ^^^^^^ +//│ error | [nothing, nothing] +//│ res +//│ = [ undefined, undefined ] +//│ // Output +//│ 1 + +:e +foo((log(1),2)) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.302: foo((log(1),2)) +//│ ║ ^^^^^^^^^^^^^^^ +//│ ╟── argument of type `[?a]` does not match type `[?b, ?c]` +//│ ║ l.302: foo((log(1),2)) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.245: fun foo(x, y) = [x, y] +//│ ╙── ^^^^^^ +//│ error | [nothing, nothing] +//│ res +//│ = [ 2, undefined ] +//│ // Output +//│ 1 + +foo((let x = log(0), 1; log(x), x + 1), 2) +//│ [Int, 2] +//│ res +//│ = [ 2, 2 ] +//│ // Output +//│ 0 +//│ 1 + +:e +foo(let x = log(0), 1; log(x), x + 1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.327: foo(let x = log(0), 1; log(x), x + 1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── argument of type `[?a]` does not match type `[?b, ?c]` +//│ ║ l.327: foo(let x = log(0), 1; log(x), x + 1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.245: fun foo(x, y) = [x, y] +//│ ╙── ^^^^^^ +//│ error | [nothing, nothing] +//│ res +//│ = [ 2, undefined ] +//│ // Output +//│ 0 +//│ 1 + +:e +foo(let x = log(0), 1 in log(x), x + 1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.345: foo(let x = log(0), 1 in log(x), x + 1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── argument of type `[?a]` does not match type `[?b, ?c]` +//│ ║ l.345: foo(let x = log(0), 1 in log(x), x + 1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.245: fun foo(x, y) = [x, y] +//│ ╙── ^^^^^^ +//│ error | [nothing, nothing] +//│ res +//│ = [ 2, undefined ] +//│ // Output +//│ 0 +//│ 1 + +:e +foo(let x = log(0), 1; log(x), 1 + 1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.363: foo(let x = log(0), 1; log(x), 1 + 1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── argument of type `[?a]` does not match type `[?b, ?c]` +//│ ║ l.363: foo(let x = log(0), 1; log(x), 1 + 1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.245: fun foo(x, y) = [x, y] +//│ ╙── ^^^^^^ +//│ error | [nothing, nothing] +//│ res +//│ = [ 2, undefined ] +//│ // Output +//│ 0 +//│ 1 + +:e +foo(if true then 1 else 2, 3) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.381: foo(if true then 1 else 2, 3) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── argument of type `[1 | ?a]` does not match type `[?b, ?c]` +//│ ║ l.381: foo(if true then 1 else 2, 3) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.245: fun foo(x, y) = [x, y] +//│ ╙── ^^^^^^ +//│ error | [nothing, nothing] +//│ res +//│ = [ 1, undefined ] + +foo((if true then 1 else 2), 3) +//│ [1 | 2, 3] +//│ res +//│ = [ 1, 3 ] + +:e +foo(if true then log("ok"), 1 else log("nok"), 2, 3) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.401: foo(if true then log("ok"), 1 else log("nok"), 2, 3) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── argument of type `[?a | ?b]` does not match type `[?c, ?d]` +//│ ║ l.401: foo(if true then log("ok"), 1 else log("nok"), 2, 3) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── Note: constraint arises from tuple literal: +//│ ║ l.245: fun foo(x, y) = [x, y] +//│ ╙── ^^^^^^ +//│ error | [nothing, nothing] +//│ res +//│ = [ 1, undefined ] +//│ // Output +//│ ok + +foo((if true then log("ok"), 1 else log("nok"), 2), 3) +//│ [1 | 2, 3] +//│ res +//│ = [ 1, 3 ] +//│ // Output +//│ ok + + diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index b65d6e0b18..e06a6def2a 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -33,7 +33,7 @@ Bar : Foo['X] //│ = 123 -trait Foo[A] { fun foo: A;; fun bar: A -> A } +trait Foo[A] { fun foo: A; fun bar: A -> A } //│ trait Foo[A] { //│ fun bar: A -> A //│ fun foo: A @@ -131,7 +131,7 @@ module Bar extends T1, Foo[Int | Str] { //│ } -trait Base[A] { fun foo: A;; fun bar: A -> A } +trait Base[A] { fun foo: A; fun bar: A -> A } trait Derived1[A] extends Base[A] trait Derived2 extends Base[[Int | Str, Int | Str]] //│ trait Base[A] { diff --git a/shared/src/test/diff/nu/Eval.mls b/shared/src/test/diff/nu/Eval.mls index 4056777475..7f803f8e20 100644 --- a/shared/src/test/diff/nu/Eval.mls +++ b/shared/src/test/diff/nu/Eval.mls @@ -22,27 +22,40 @@ declare class throw(arg: anything): nothing //│ declare class throw(arg: anything): nothing :w // * Due to current limitations of self types -:re -throw(1); 0 -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +fun raise(err) = + throw(err) + error +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in application: -//│ ║ l.26: throw(1); 0 -//│ ║ ^^^^^^^^ +//│ ║ l.26: throw(err) +//│ ║ ^^^^^^^^^^ //│ ╙── application of type `throw` does not match type `()` +//│ fun raise: anything -> nothing + +:re +raise(1); 0 //│ 0 //│ res //│ Runtime error: //│ 1 +//│ res +//│ = 0 -:w -fun test = throw(1); 0 -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. -//│ ╟── Type mismatch in application: -//│ ║ l.39: fun test = throw(1); 0 -//│ ║ ^^^^^^^^ -//│ ╙── application of type `throw` does not match type `()` +fun test = raise(1); 0 +//│ fun test: nothing +//│ 0 +//│ res +//│ = 0 + +:re +test +//│ nothing +//│ res +//│ Runtime error: +//│ 1 + +fun test = raise(1), 0 //│ fun test: 0 :re @@ -52,16 +65,9 @@ test //│ Runtime error: //│ 1 -:w fun test = - throw(1) + raise(1) error -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. -//│ ╟── Type mismatch in application: -//│ ║ l.57: throw(1) -//│ ║ ^^^^^^^^ -//│ ╙── application of type `throw` does not match type `()` //│ fun test: nothing :re @@ -187,10 +193,10 @@ type Value = Lam | Lit | Rcd[Value] fun err(msg) = throw(concat("Evaluation error: " ++ msg)) error -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in application: -//│ ║ l.188: throw(concat("Evaluation error: " ++ msg)) +//│ ║ l.194: throw(concat("Evaluation error: " ++ msg)) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╙── application of type `throw` does not match type `()` //│ fun err: Str -> nothing @@ -219,7 +225,7 @@ fun eval(t, env) = if t is //│ where //│ 'c :> 'a //│ <: Object & ~#Rcd | Rcd['c] -//│ 'a :> 'c | Rcd[Lam | Lit[nothing] | 'a] | Lam | Lit[nothing] +//│ 'a :> 'c | Lam | Lit[nothing] | Rcd[Lam | Lit[nothing] | 'a] //│ 'b <: App | Lam | Lit[anything] | Rcd['b] | Sel | Var eval : (Term, List[{key: Str, value: Value}]) -> Value diff --git a/shared/src/test/diff/nu/FilterMap.mls b/shared/src/test/diff/nu/FilterMap.mls index 2ac040cbad..421fe34c4a 100644 --- a/shared/src/test/diff/nu/FilterMap.mls +++ b/shared/src/test/diff/nu/FilterMap.mls @@ -68,8 +68,8 @@ mkString of list //│ res //│ = '1, 2, 3, 4, 5, 6, 7' -mkString of filtermap(x => if x % 2 == 0 then Tru else Fals, list) -mkString of filtermap(x => if x % 2 == 0 then Fals else Tru, list) +mkString of filtermap(x => (if x % 2 == 0 then Tru else Fals), list) +mkString of filtermap(x => (if x % 2 == 0 then Fals else Tru), list) mkString of filtermap(x => (if x % 2 == 0 then Fals x % 3 == 0 then Pair(Tru, x / 3) diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls index 938516f499..4ae73f6e72 100644 --- a/shared/src/test/diff/nu/FlatMonads_repro.mls +++ b/shared/src/test/diff/nu/FlatMonads_repro.mls @@ -174,7 +174,7 @@ fun loop = -val x: Bind['A, 'B] where undefined : 'A;; 'A : 'B +val x: Bind['A, 'B] where undefined : 'A; 'A : 'B //│ val x: forall 'A 'B. Bind['A, 'B] //│ where //│ 'A :> () @@ -189,7 +189,7 @@ x.run //│ = //│ x is not implemented -val x: Bind['A, 'B] where 'A : undefined;; 'A : 'B +val x: Bind['A, 'B] where 'A : undefined; 'A : 'B //│ val x: forall 'A 'B. Bind['A, 'B] //│ where //│ 'A <: () & 'B diff --git a/shared/src/test/diff/nu/FunPatterns.mls b/shared/src/test/diff/nu/FunPatterns.mls index dc160060f6..229b978983 100644 --- a/shared/src/test/diff/nu/FunPatterns.mls +++ b/shared/src/test/diff/nu/FunPatterns.mls @@ -13,12 +13,18 @@ fun f3([[x, y,],],) = x + y //│ fun f2: ([Int, Int]) -> Int //│ fun f3: ([[Int, Int]]) -> Int -:pe +:e fun f3([(x, y,),],) = x + y -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[ERROR] Unsupported pattern shape: //│ ║ l.17: fun f3([(x, y,),],) = x + y //│ ╙── ^^^^^^^ -//│ fun f3: ([[Int, Int]]) -> Int +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.17: fun f3([(x, y,),],) = x + y +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.17: fun f3([(x, y,),],) = x + y +//│ ╙── ^ +//│ fun f3: ([error]) -> Int class Pair(lhs: Int, rhs: Int) @@ -27,13 +33,13 @@ class Pair(lhs: Int, rhs: Int) :e // * TODO fun f(Pair(x, y)) = x + y //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.28: fun f(Pair(x, y)) = x + y +//│ ║ l.34: fun f(Pair(x, y)) = x + y //│ ╙── ^^^^^^^^^^ //│ ╔══[ERROR] identifier not found: x -//│ ║ l.28: fun f(Pair(x, y)) = x + y +//│ ║ l.34: fun f(Pair(x, y)) = x + y //│ ╙── ^ //│ ╔══[ERROR] identifier not found: y -//│ ║ l.28: fun f(Pair(x, y)) = x + y +//│ ║ l.34: fun f(Pair(x, y)) = x + y //│ ╙── ^ //│ fun f: error -> Int diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 4d71d0c012..685403f650 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -426,7 +426,7 @@ M: Cls['a] //│ = M { class: [class M extends Cls] } -class Cls[A](val x: A) { fun g: A -> Int;; fun g(x) = 42 } +class Cls[A](val x: A) { fun g: A -> Int; fun g(x) = 42 } //│ class Cls[A](x: A) { //│ fun g: A -> Int //│ } diff --git a/shared/src/test/diff/nu/ImplicitMethodPolym.mls b/shared/src/test/diff/nu/ImplicitMethodPolym.mls index 94642a1a7f..600628d3ca 100644 --- a/shared/src/test/diff/nu/ImplicitMethodPolym.mls +++ b/shared/src/test/diff/nu/ImplicitMethodPolym.mls @@ -145,9 +145,6 @@ module M extends C { module M extends C { fun g = (this.id2(true), this.id2(0)) } -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.146: fun g = (this.id2(true), this.id2(0)) -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.146: fun g = (this.id2(true), this.id2(0)) //│ ╙── ^^^^ @@ -156,7 +153,7 @@ module M extends C { //│ ╙── ^^^^ //│ module M extends C { //│ fun f: [error, error] -//│ fun g: [error, error] +//│ fun g: error //│ fun id1: forall 'a. 'a -> 'a //│ fun id2: forall 'b. 'b -> 'b //│ } @@ -177,9 +174,9 @@ M.f //│ = [ true, 0 ] M.g -//│ [error, error] +//│ error //│ res -//│ = [ true, 0 ] +//│ = 0 :e @@ -187,11 +184,11 @@ module M extends C { fun id1 = succ } //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.187: fun id1 = succ +//│ ║ l.184: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╙── variable of type `?a` is not an instance of type `Int` //│ ╔══[ERROR] Type mismatch in definition of method id1: -//│ ║ l.187: fun id1 = succ +//│ ║ l.184: fun id1 = succ //│ ║ ^^^^^^^^^^ //│ ╟── expression of type `Int` does not match type `?a` //│ ╟── Note: constraint arises from reference: @@ -217,15 +214,15 @@ M.id1 // FIXME? parsing/semantics of this, currently treated as a named tuple... (M: C) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.219: (M: C) -//│ ╙── ^^^^^^ +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.216: (M: C) +//│ ╙── ^^^^ //│ ╔══[ERROR] Construction of unparameterized class C should use the `new` keyword -//│ ║ l.219: (M: C) +//│ ║ l.216: (M: C) //│ ╙── ^ -//│ [M: () -> C] +//│ () -> C //│ res -//│ = [ [class C] ] +//│ = [class C] @@ -241,19 +238,19 @@ module M { fun oops(x) = m := x } //│ ╔══[PARSE ERROR] Unexpected 'mut' keyword in expression position -//│ ║ l.240: mut val m = None +//│ ║ l.237: mut val m = None //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected 'val' keyword in expression position -//│ ║ l.240: mut val m = None +//│ ║ l.237: mut val m = None //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: := -//│ ║ l.241: fun oops(x) = m := x +//│ ║ l.238: fun oops(x) = m := x //│ ╙── ^^ //│ ╔══[ERROR] identifier not found: m -//│ ║ l.241: fun oops(x) = m := x +//│ ║ l.238: fun oops(x) = m := x //│ ╙── ^ //│ ╔══[ERROR] Unexpected equation in this position -//│ ║ l.240: mut val m = None +//│ ║ l.237: mut val m = None //│ ╙── ^^^^^^^^ //│ module M { //│ fun oops: anything -> error diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 9bbf4abec9..57814459d9 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -184,7 +184,7 @@ trait Foo[type A] { fun foo(x: A): A } //│ } -trait Foo[A] { fun a: A;; fun foo(x: A): A } +trait Foo[A] { fun a: A; fun foo(x: A): A } //│ trait Foo[A] { //│ fun a: A //│ fun foo: (x: A) -> A diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls index 821a12d2c7..afe642af90 100644 --- a/shared/src/test/diff/nu/Misc.mls +++ b/shared/src/test/diff/nu/Misc.mls @@ -89,75 +89,88 @@ f([1, 2]) -:pe +:e let f = ((x, y)) => x + y -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[ERROR] Unsupported pattern shape: //│ ║ l.93: let f = ((x, y)) => x + y //│ ╙── ^^^^^^ -//│ let f: ([Int, Int]) -> Int -//│ f -//│ = [Function: f5] +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.93: let f = ((x, y)) => x + y +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.93: let f = ((x, y)) => x + y +//│ ╙── ^ +//│ let f: error -> Int +//│ Code generation encountered an error: +//│ term App(Var(,),Tup(List((None,Fld(_,Var(x))), (None,Fld(_,Var(y)))))) is not a valid pattern :e f(1, 2) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.102: f(1, 2) +//│ ║ l.108: f(1, 2) //│ ║ ^^^^^^^ -//│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` -//│ ║ l.102: f(1, 2) +//│ ╟── argument list of type `[1, 2]` does not match type `[error]` +//│ ║ l.108: f(1, 2) //│ ╙── ^^^^^^ //│ Int | error //│ res //│ Runtime error: -//│ TypeError: number 1 is not iterable (cannot read property Symbol(Symbol.iterator)) +//│ ReferenceError: f5 is not defined -:pe +:re f((1, 2)) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.115: f((1, 2)) -//│ ╙── ^^^^^^ //│ Int //│ res -//│ = 3 +//│ Runtime error: +//│ ReferenceError: f5 is not defined +:re f([1, 2]) //│ Int //│ res -//│ = 3 +//│ Runtime error: +//│ ReferenceError: f5 is not defined :e f[1, 2] //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.129: f[1, 2] +//│ ║ l.135: f[1, 2] //│ ╙── ^^^^^^^ -//│ ([Int, Int]) -> Int +//│ error -> Int //│ res -//│ = [Function: f5] +//│ Runtime error: +//│ ReferenceError: f5 is not defined -:pe +:e let f = (((x, y))) => x + y -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.139: let f = (((x, y))) => x + y +//│ ╔══[ERROR] Unsupported pattern shape: +//│ ║ l.146: let f = (((x, y))) => x + y //│ ╙── ^^^^^^ -//│ let f: ([Int, Int]) -> Int -//│ f -//│ = [Function: f6] +//│ ╔══[ERROR] identifier not found: x +//│ ║ l.146: let f = (((x, y))) => x + y +//│ ╙── ^ +//│ ╔══[ERROR] identifier not found: y +//│ ║ l.146: let f = (((x, y))) => x + y +//│ ╙── ^ +//│ let f: error -> Int +//│ Code generation encountered an error: +//│ term App(Var(,),Tup(List((None,Fld(_,Var(x))), (None,Fld(_,Var(y)))))) is not a valid pattern // * TODO maybe parse as type lambda? let f = [x, y] => x + y //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f7] +//│ = [Function: f5] :e f(1, 2) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.155: f(1, 2) +//│ ║ l.168: f(1, 2) //│ ║ ^^^^^^^ //│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` -//│ ║ l.155: f(1, 2) +//│ ║ l.168: f(1, 2) //│ ╙── ^^^^^^ //│ Int | error //│ res @@ -173,7 +186,7 @@ f([1, 2]) let f = ([x, y]) => x + y //│ let f: ([Int, Int]) -> Int //│ f -//│ = [Function: f8] +//│ = [Function: f6] f([1, 2]) //│ Int @@ -183,10 +196,10 @@ f([1, 2]) :e f(1, 2) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.184: f(1, 2) +//│ ║ l.197: f(1, 2) //│ ║ ^^^^^^^ //│ ╟── argument list of type `[1, 2]` does not match type `[[?a, ?b]]` -//│ ║ l.184: f(1, 2) +//│ ║ l.197: f(1, 2) //│ ╙── ^^^^^^ //│ Int | error //│ res @@ -197,15 +210,15 @@ f(1, 2) let f = [[[x, y]]] => x + y //│ let f: ([[[Int, Int]]]) -> Int //│ f -//│ = [Function: f9] +//│ = [Function: f7] :e f([[1, 2]]) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.203: f([[1, 2]]) +//│ ║ l.216: f([[1, 2]]) //│ ║ ^^^^^^^^^^^ //│ ╟── tuple literal of type `[1, 2]` does not match type `[[?a, ?b]]` -//│ ║ l.203: f([[1, 2]]) +//│ ║ l.216: f([[1, 2]]) //│ ╙── ^^^^^^ //│ Int | error //│ res diff --git a/shared/src/test/diff/nu/Mixin42.mls b/shared/src/test/diff/nu/Mixin42.mls index e5d214bb92..4bede9b036 100644 --- a/shared/src/test/diff/nu/Mixin42.mls +++ b/shared/src/test/diff/nu/Mixin42.mls @@ -83,7 +83,7 @@ C2.test //│ = 42 -class C1() extends M1, M2 { val factor: Int;; val factor = 2 } +class C1() extends M1, M2 { val factor: Int; val factor = 2 } C1().test //│ class C1() { //│ val factor: Int diff --git a/shared/src/test/diff/nu/Mut.mls b/shared/src/test/diff/nu/Mut.mls index fdb3fe11ef..c62fdea40c 100644 --- a/shared/src/test/diff/nu/Mut.mls +++ b/shared/src/test/diff/nu/Mut.mls @@ -83,65 +83,57 @@ v1.x <- 1 :pe let v2: (mut Int) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.85: let v2: (mut Int) -//│ ╙── ^^^^^^^^^ -//│ let v2: [mut Int] +//│ ╙── ^^^ +//│ let v2: Int //│ v2 //│ = :pe let v2 = (mut 1) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.94: let v2 = (mut 1) -//│ ╙── ^^^^^^^ -//│ let v2: [mut 'a] -//│ where -//│ 'a :> 1 +//│ ╙── ^ +//│ let v2: 1 //│ v2 -//│ = [ 1 ] +//│ = 1 :pe let v2: (mut x: Int) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.105: let v2: (mut x: Int) -//│ ╙── ^^^^^^^^^^^^ -//│ let v2: [mut x: Int] +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.103: let v2: (mut x: Int) +//│ ╙── ^^^^^^ +//│ let v2: Int //│ v2 //│ = :pe let v2 = (mut 1) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.114: let v2 = (mut 1) -//│ ╙── ^^^^^^^ -//│ let v2: [mut 'a] -//│ where -//│ 'a :> 1 +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.112: let v2 = (mut 1) +//│ ╙── ^ +//│ let v2: 1 //│ v2 -//│ = [ 1 ] +//│ = 1 :pe let v2 = (mut x: 1) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.125: let v2 = (mut x: 1) -//│ ╙── ^^^^^^^^^^ -//│ let v2: [mut x: 'x] -//│ where -//│ 'x :> 1 +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.121: let v2 = (mut x: 1) +//│ ╙── ^^^^ +//│ let v2: 1 //│ v2 -//│ = [ 1 ] +//│ = 1 :pe let v2 = (mut y: 1) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.136: let v2 = (mut y: 1) -//│ ╙── ^^^^^^^^^^ -//│ let v2: [mut y: 'y] -//│ where -//│ 'y :> 1 +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.130: let v2 = (mut y: 1) +//│ ╙── ^^^^ +//│ let v2: 1 //│ v2 -//│ = [ 1 ] +//│ = 1 let v2: [mut Int] diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index e62b8f9a95..9cdaf57304 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -236,14 +236,16 @@ new //│ Code generation encountered an error: //│ Unsupported `new` class term: UnitLit(true) -:e // support? +// Support? +:pe +:e new x: 0 -//│ ╔══[ERROR] Not a recognized type -//│ ║ l.241: x: 0 +//│ ╔══[PARSE ERROR] Not a recognized type +//│ ║ l.243: x: 0 //│ ╙── ^ //│ ╔══[ERROR] Unexpected type `nothing` after `new` keyword -//│ ║ l.241: x: 0 +//│ ║ l.243: x: 0 //│ ╙── ^ //│ error //│ Code generation encountered an error: @@ -258,7 +260,7 @@ fun f(x) = {x} :e new f(1) //│ ╔══[ERROR] type identifier not found: f -//│ ║ l.259: new f(1) +//│ ║ l.261: new f(1) //│ ╙── ^ //│ error //│ res @@ -271,7 +273,7 @@ module Oops :e new Oops //│ ╔══[ERROR] Module Oops cannot be used in `new` expression -//│ ║ l.272: new Oops +//│ ║ l.274: new Oops //│ ╙── ^^^^ //│ error //│ res @@ -282,7 +284,7 @@ new Oops new Oops2 trait Oops2 //│ ╔══[ERROR] Trait Oops2 cannot be used in `new` expression -//│ ║ l.282: new Oops2 +//│ ║ l.284: new Oops2 //│ ╙── ^^^^^ //│ trait Oops2 //│ error diff --git a/shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls b/shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls index 649faaad34..999389e9c8 100644 --- a/shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls +++ b/shared/src/test/diff/nu/NuPolymorphicTypeAliases.mls @@ -21,10 +21,10 @@ module A { //│ type F[A] = forall 'a. (A, 'a) -> [A, 'a] //│ } -:e // TODO +:pe // TODO fun f[B] = ((x: B, y) => [x, y]) : A.F[B] -//│ ╔══[ERROR] Not a recognized type +//│ ╔══[PARSE ERROR] Not a recognized type //│ ║ l.26: ((x: B, y) => [x, y]) : A.F[B] //│ ╙── ^^^^^^ //│ fun f: anything diff --git a/shared/src/test/diff/nu/Object.mls b/shared/src/test/diff/nu/Object.mls index 1f8ab3df0b..9e93dec27b 100644 --- a/shared/src/test/diff/nu/Object.mls +++ b/shared/src/test/diff/nu/Object.mls @@ -79,10 +79,10 @@ fun foo = forall 'a; (x: 'a) => if x is A then true else false //│ ╔══[PARSE ERROR] Expected `:` after `forall` section //│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false //│ ╙── ^ -//│ ╔══[PARSE ERROR] Expected end of input; found operator instead -//│ ║ l.78: fun foo = forall 'a; (x: 'a) => if x is A then true else false -//│ ╙── ^ //│ fun foo: () +//│ (x: Object) -> Bool +//│ res +//│ = [Function: res] diff --git a/shared/src/test/diff/nu/OpLam.mls b/shared/src/test/diff/nu/OpLam.mls index b7eb786b51..bedc2cd423 100644 --- a/shared/src/test/diff/nu/OpLam.mls +++ b/shared/src/test/diff/nu/OpLam.mls @@ -7,17 +7,23 @@ x => x is 42 //│ = [Function: res] +:pe fun (|>;) foo(a, b) = [a, b] -//│ fun (|>;) foo: forall 'a 'b. ('a, 'b) -> ['a, 'b] +//│ ╔══[PARSE ERROR] Unexpected semicolon after symbolic name +//│ ║ l.11: fun (|>;) foo(a, b) = [a, b] +//│ ╙── ^ +//│ fun (|>) foo: forall 'a 'b. ('a, 'b) -> ['a, 'b] 42 |>; x => x -//│ [42, forall 'a. 'a -> 'a] +//│ forall 'a. 'a -> 'a +//│ res +//│ = [ 42, undefined ] //│ res -//│ = [ 42, [Function (anonymous)] ] +//│ = [Function: res] fun (>>) compose(f, g) = x => g(f(x)) -//│ fun (>>) compose: forall 'a 'b 'c. ('a -> 'b, 'b -> 'c) -> 'a -> 'c +//│ fun (>>) compose: forall 'a 'b 'c. ('c -> 'a, 'a -> 'b) -> 'c -> 'b succ >> x => x + 2 //│ Int -> Int @@ -27,16 +33,16 @@ succ >> x => x + 2 :e x => x + 2 >> succ //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.28: x => x + 2 >> succ +//│ ║ l.34: x => x + 2 >> succ //│ ║ ^^^^^^^^^^^^^ //│ ╟── operator application of type `Int` is not a function -//│ ║ l.28: x => x + 2 >> succ +//│ ║ l.34: x => x + 2 >> succ //│ ║ ^^^^^ //│ ╟── Note: constraint arises from application: -//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ l.25: fun (>>) compose(f, g) = x => g(f(x)) //│ ║ ^^^^ //│ ╟── from reference: -//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ l.25: fun (>>) compose(f, g) = x => g(f(x)) //│ ╙── ^ //│ Int -> (error | anything -> Int) //│ res @@ -51,31 +57,31 @@ x => x + 2 >> succ x => x + 2 >> succ //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.51: x => x + 2 +//│ ║ l.57: x => x + 2 //│ ║ ^ -//│ ║ l.52: >> succ +//│ ║ l.58: >> succ //│ ║ ^^^^^^^^^^ //│ ╟── integer literal of type `2` is not a function -//│ ║ l.51: x => x + 2 +//│ ║ l.57: x => x + 2 //│ ║ ^ //│ ╟── Note: constraint arises from application: -//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ l.25: fun (>>) compose(f, g) = x => g(f(x)) //│ ║ ^^^^ //│ ╟── from reference: -//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ l.25: fun (>>) compose(f, g) = x => g(f(x)) //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.51: x => x + 2 +//│ ║ l.57: x => x + 2 //│ ║ ^^^^^ -//│ ║ l.52: >> succ +//│ ║ l.58: >> succ //│ ║ ^^^^^^^^^ //│ ╟── function of type `?a -> ?b` is not an instance of type `Int` -//│ ║ l.19: fun (>>) compose(f, g) = x => g(f(x)) +//│ ║ l.25: fun (>>) compose(f, g) = x => g(f(x)) //│ ║ ^^^^^^^^^^^^ //│ ╟── but it flows into operator application with expected type `Int` -//│ ║ l.51: x => x + 2 +//│ ║ l.57: x => x + 2 //│ ║ ^ -//│ ║ l.52: >> succ +//│ ║ l.58: >> succ //│ ╙── ^^^^^^^^^^ //│ Int -> (Int | error) //│ res @@ -90,7 +96,7 @@ x => x + 2 :pe >> succ //│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.91: >> succ +//│ ║ l.97: >> succ //│ ╙── ^^ //│ Int -> Int //│ res @@ -100,10 +106,10 @@ x => x + 2 :e x => x.y => y //│ ╔══[ERROR] Unsupported pattern shape: -//│ ║ l.101: x => x.y => y +//│ ║ l.107: x => x.y => y //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: y -//│ ║ l.101: x => x.y => y +//│ ║ l.107: x => x.y => y //│ ╙── ^ //│ anything -> error -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 4eacce0f29..0fc6a4af9c 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -192,7 +192,7 @@ B.x -abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } +abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } //│ abstract class Foo[A](x: A) { //│ fun i: A -> A //│ fun y: A @@ -226,14 +226,14 @@ module Bazz extends Foo(0) { //│ ║ l.223: val x: 2 //│ ║ ^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } +//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } //│ ╙── ^ //│ ╔══[ERROR] Member `i` is declared (or its declaration is inherited) but is not implemented in `Bazz` //│ ║ l.222: module Bazz extends Foo(0) { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } -//│ ╙── ^^^^^^^^^^^^^ +//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x; fun i: A -> A } +//│ ╙── ^^^^^^^^^^^^^ //│ module Bazz extends Foo { //│ fun i: 'A -> 'A //│ val x: 2 diff --git a/shared/src/test/diff/nu/Parens.mls b/shared/src/test/diff/nu/Parens.mls index e0b7691159..16f554ee2f 100644 --- a/shared/src/test/diff/nu/Parens.mls +++ b/shared/src/test/diff/nu/Parens.mls @@ -28,23 +28,15 @@ //│ res //│ = 1 -:pe (1, 2) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.32: (1, 2) -//│ ╙── ^^^^^^ -//│ [1, 2] +//│ 2 //│ res -//│ = [ 1, 2 ] +//│ = 2 -:pe (1, 2,) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.41: (1, 2,) -//│ ╙── ^^^^^^^ -//│ [1, 2] +//│ 2 //│ res -//│ = [ 1, 2 ] +//│ = 2 let x: () @@ -55,10 +47,10 @@ let x: () :pe let x: (,) //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.56: let x: (,) +//│ ║ l.48: let x: (,) //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.56: let x: (,) +//│ ║ l.48: let x: (,) //│ ╙── ^ //│ let x: () //│ x @@ -74,20 +66,20 @@ let x: (1,) //│ x //│ = -:pe +:e let x: (1, 2) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.78: let x: (1, 2) +//│ ╔══[ERROR] type identifier not found: , +//│ ║ l.70: let x: (1, 2) //│ ╙── ^^^^^^ -//│ let x: [1, 2] +//│ let x: error //│ x //│ = -:pe +:e let x: (1, 2,) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.87: let x: (1, 2,) +//│ ╔══[ERROR] type identifier not found: , +//│ ║ l.79: let x: (1, 2,) //│ ╙── ^^^^^^^ -//│ let x: [1, 2] +//│ let x: error //│ x //│ = diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index dec21bdd11..64cf384572 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -110,7 +110,7 @@ let y: c.A = c.x // *** GADTs *** // -class Cls[A] { fun x: A = x;; fun g: A -> Int;; fun g = g } +class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ class Cls[A] { //│ constructor() //│ fun g: A -> Int @@ -130,7 +130,7 @@ fun test(a: Object) = if a is //│ ║ l.124: else error //│ ║ ^^^^^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.113: class Cls[A] { fun x: A = x;; fun g: A -> Int;; fun g = g } +//│ ║ l.113: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> (error | ??A) @@ -146,7 +146,7 @@ fun test(a: Object) = if a is //│ ║ l.140: else 0 //│ ║ ^^^^^^^^ //│ ╟── type variable `A` leaks out of its scope -//│ ║ l.113: class Cls[A] { fun x: A = x;; fun g: A -> Int;; fun g = g } +//│ ║ l.113: class Cls[A] { fun x: A = x; fun g: A -> Int; fun g = g } //│ ╙── ^ //│ fun test: (a: Object) -> Int diff --git a/shared/src/test/diff/nu/ThisRefinedClasses.mls b/shared/src/test/diff/nu/ThisRefinedClasses.mls index dea56120c3..dd4245f923 100644 --- a/shared/src/test/diff/nu/ThisRefinedClasses.mls +++ b/shared/src/test/diff/nu/ThisRefinedClasses.mls @@ -47,8 +47,8 @@ class Foo { //│ ╔══[ERROR] Type `#Foo` does not contain member `x` //│ ║ l.44: this: { x: 'a } //│ ╙── ^ -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in type ascription: //│ ║ l.44: this: { x: 'a } //│ ║ ^^^^ @@ -65,23 +65,23 @@ class Foo { // TODO // * All on one line: -class Test { this: { x: Int};; fun test = this.x } +class Test { this: { x: Int}; fun test = this.x } //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } -//│ ╙── ^^ +//│ ║ l.68: class Test { this: { x: Int}; fun test = this.x } +//│ ╙── ^^ //│ ╔══[ERROR] Type `#Test` does not contain member `x` -//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } +//│ ║ l.68: class Test { this: { x: Int}; fun test = this.x } //│ ╙── ^ -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in type ascription: -//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } +//│ ║ l.68: class Test { this: { x: Int}; fun test = this.x } //│ ║ ^^^^ //│ ╟── type `{x: Int}` does not match type `()` -//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } +//│ ║ l.68: class Test { this: { x: Int}; fun test = this.x } //│ ║ ^^^^^^^^^ //│ ╟── but it flows into expression in statement position with expected type `()` -//│ ║ l.68: class Test { this: { x: Int};; fun test = this.x } +//│ ║ l.68: class Test { this: { x: Int}; fun test = this.x } //│ ╙── ^^^^ //│ class Test { //│ constructor() diff --git a/shared/src/test/diff/nu/TypeVariables.mls b/shared/src/test/diff/nu/TypeVariables.mls index 47ba5aa8b4..327b6ca005 100644 --- a/shared/src/test/diff/nu/TypeVariables.mls +++ b/shared/src/test/diff/nu/TypeVariables.mls @@ -17,7 +17,21 @@ fun x: forall 'a: 'a -> 'a = succ //│ ╙── ^^ //│ fun x: forall 'a. 'a -> 'a -fun x: [Int -> Int,] = [id : forall 'a: 'a -> 'a,] +fun x: [Int -> Int] = [id : forall 'a: 'a -> 'a] +//│ fun x: [Int -> Int] + +:pe +:e +fun x: [Int -> Int] = [id : forall 'a: 'a -> 'a,] +//│ ╔══[PARSE ERROR] Unexpected end of square bracket section; an expression was expected here +//│ ║ l.25: fun x: [Int -> Int] = [id : forall 'a: 'a -> 'a,] +//│ ╙── ^ +//│ ╔══[ERROR] type identifier not found: , +//│ ║ l.25: fun x: [Int -> Int] = [id : forall 'a: 'a -> 'a,] +//│ ╙── ^^^^^^^^^ +//│ fun x: [Int -> Int] + +fun x: [Int -> Int,] = [id : forall 'a: 'a -> 'a] //│ fun x: [Int -> Int] diff --git a/shared/src/test/diff/nu/Unit.mls b/shared/src/test/diff/nu/Unit.mls index 9c8b6a46eb..5ff8b979f7 100644 --- a/shared/src/test/diff/nu/Unit.mls +++ b/shared/src/test/diff/nu/Unit.mls @@ -76,14 +76,10 @@ fun x = 1 //│ res //│ = 1 -:pe (1,2) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.80: (1,2) -//│ ╙── ^^^^^ -//│ [1, 2] +//│ 2 //│ res -//│ = [ 1, 2 ] +//│ = 2 (let x = 1) //│ () @@ -93,7 +89,7 @@ fun x = 1 :pe (let x = 1 in) //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.94: (let x = 1 in) +//│ ║ l.90: (let x = 1 in) //│ ╙── ^ //│ () //│ res @@ -108,23 +104,31 @@ fun x = 1 :pe (log(1);) -//│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.110: (log(1);) -//│ ╙── ^ +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.106: (log(1);) +//│ ╙── ^ //│ () //│ res //│ = undefined //│ // Output //│ 1 +:pe // support? (log(1); 2) -//│ 2 +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.117: (log(1); 2) +//│ ╙── ^ +//│ () //│ res -//│ = 2 +//│ = undefined //│ // Output //│ 1 +:pe // support? (log(1); ()) +//│ ╔══[PARSE ERROR] Unexpected semicolon here +//│ ║ l.128: (log(1); ()) +//│ ╙── ^ //│ () //│ res //│ = undefined @@ -140,14 +144,10 @@ fun x = 1 -:pe (1, 2) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.144: (1, 2) -//│ ╙── ^^^^^^ -//│ [1, 2] +//│ 2 //│ res -//│ = [ 1, 2 ] +//│ = 2 x => x @@ -172,12 +172,8 @@ x => x //│ = [Function: res] -:pe 1 => (2, 3) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.176: 1 => (2, 3) -//│ ╙── ^^^^^^ -//│ 1 -> [2, 3] +//│ 1 -> 3 //│ res //│ = [Function: res] @@ -195,75 +191,74 @@ f of 1, 2 //│ res //│ = 3 -:pe :e f of (1, 2) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.200: f of (1, 2) -//│ ╙── ^^^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.200: f of (1, 2) +//│ ║ l.195: f of (1, 2) //│ ║ ^^^^^^^^^^^ -//│ ╟── argument of type `[[1, 2]]` does not match type `[?a, ?b]` -//│ ║ l.200: f of (1, 2) +//│ ╟── argument of type `[?a]` does not match type `[?b, ?c]` +//│ ║ l.195: f of (1, 2) //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.185: fun f(x, y) = x + y +//│ ║ l.181: fun f(x, y) = x + y //│ ╙── ^^^^^^ //│ Int | error //│ res -//│ = '1,2undefined' +//│ = NaN -:w 0; 0 -//│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.220: 0; 0 -//│ ╙── ^ //│ 0 //│ res //│ = 0 +//│ res +//│ = 0 + +:w +fun f = + 0; 0 +//│ ╔══[WARNING] Pure expression does nothing in statement position. +//│ ║ l.220: 0; 0 +//│ ╙── ^ +//│ fun f: 0 :w -succ(0); 0 -//│ ╔══[WARNING] Expression in statement position should have type `unit`. -//│ ╟── Use the `discard` function to discard non-unit values, making the intent clearer. +fun f = + succ(0); 0 +//│ ╔══[WARNING] Expression in statement position should have type `()`. +//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. //│ ╟── Type mismatch in application: -//│ ║ l.229: succ(0); 0 -//│ ║ ^^^^^^^ +//│ ║ l.228: succ(0); 0 +//│ ║ ^^^^^^^ //│ ╙── application of type `Int` does not match type `()` -//│ 0 -//│ res -//│ = 0 +//│ fun f: 0 -discard(succ(0)); 0 -//│ 0 -//│ res -//│ = 0 +fun f = + discard(succ(0)); 0 +//│ fun f: 0 -discard of succ(0);; 0 -//│ 0 -//│ res -//│ = undefined -//│ res -//│ = 0 +fun f = + discard of succ(0); 0 +//│ fun f: 0 -let _ = succ(0);; 0 -//│ let _: Int -//│ 0 -//│ _ -//│ = 1 -//│ res -//│ = 0 +fun f = + let _ = succ(0); 0 +//│ fun f: 0 + +fun f = + succ(0), 0 +//│ fun f: 0 x => x; () -//│ () -> () +//│ () //│ res //│ = [Function: res] +//│ res +//│ = undefined -x => x;; () +x => x; () //│ () //│ res //│ = [Function: res] @@ -272,14 +267,14 @@ x => x;; () :w fun f = - x => x;; () + x => x; () //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.275: x => x;; () +//│ ║ l.270: x => x; () //│ ╙── ^^^^^^ //│ fun f: () fun f = - discard of x => x;; () + discard of x => x; () //│ fun f: () :w @@ -287,7 +282,7 @@ fun f = x => x () //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.287: x => x +//│ ║ l.282: x => x //│ ╙── ^^^^^^ //│ fun f: () @@ -297,7 +292,7 @@ module Test { 123 } //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.297: 123 +//│ ║ l.292: 123 //│ ╙── ^^^ //│ module Test @@ -307,10 +302,10 @@ module Test { 456 } //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.306: 123 +//│ ║ l.301: 123 //│ ╙── ^^^ //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.307: 456 +//│ ║ l.302: 456 //│ ╙── ^^^ //│ module Test @@ -319,7 +314,7 @@ module Test { x => x } //│ ╔══[WARNING] Pure expression does nothing in statement position. -//│ ║ l.319: x => x +//│ ║ l.314: x => x //│ ╙── ^^^^^^ //│ module Test @@ -330,15 +325,15 @@ fun foo = let tmp = 0 foo + 1 //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.331: foo + 1 +//│ ║ l.326: foo + 1 //│ ║ ^^^^^^^ //│ ╟── definition of method foo of type `()` is not an instance of type `Int` -//│ ║ l.329: fun foo = +//│ ║ l.324: fun foo = //│ ║ ^^^^^ -//│ ║ l.330: let tmp = 0 +//│ ║ l.325: let tmp = 0 //│ ║ ^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `Int` -//│ ║ l.331: foo + 1 +//│ ║ l.326: foo + 1 //│ ╙── ^^^ //│ fun foo: () //│ Int | error diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 03ab69c023..89326b7576 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -11,23 +11,23 @@ fun f: [Str] | [Str, Int] fun f: (Str | [Str, Int]) //│ fun f: Str | [Str, Int] -:pe +:e fun f: Str | (Str, Int) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[ERROR] type identifier not found: , //│ ║ l.15: fun f: Str | (Str, Int) //│ ╙── ^^^^^^^^^^ -//│ fun f: Str | [Str, Int] +//│ fun f: Str | error fun f: Str | ([Str, Int]) //│ fun f: Str | [Str, Int] -:pe +:e fun f: Str | ((Str, Int)) -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[ERROR] type identifier not found: , //│ ║ l.26: fun f: Str | ((Str, Int)) -//│ ╙── ^^^^^^^^^^ -//│ fun f: Str | [Str, Int] +//│ ╙── ^^^^^^^^^^^^ +//│ fun f: Str | error diff --git a/shared/src/test/diff/parser/Arrays.mls b/shared/src/test/diff/parser/Arrays.mls index 56248ffb8a..24bf9bfe9d 100644 --- a/shared/src/test/diff/parser/Arrays.mls +++ b/shared/src/test/diff/parser/Arrays.mls @@ -31,10 +31,7 @@ (1, 2, 3) //│ |(|1|,| |2|,| |3|)| -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.32: (1, 2, 3) -//│ ╙── ^^^^^^^^^ -//│ Parsed: {[1, 2, 3,]} +//│ Parsed: {,(1, ,(2, 3,),)} 1 @@ -43,17 +40,14 @@ 1, //│ |1|,| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.44: 1, -//│ ╙── ^ -//│ Parsed: {1} +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.41: 1, +//│ ╙── ^ +//│ Parsed: {,(1, undefined,)} 1, 2, 3 //│ |1|,| |2|,| |3| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.51: 1, 2, 3 -//│ ╙── ^ -//│ Parsed: {1} +//│ Parsed: {,(1, ,(2, 3,),)} f of 1, 2, 3 //│ |f| |#of| |1|,| |2|,| |3| @@ -86,9 +80,9 @@ let arr = ] //│ |#let| |arr| |#=|↵|[|↵|]| //│ ╔══[PARSE ERROR] Unexpected newline in expression position -//│ ║ l.84: let arr = +//│ ║ l.78: let arr = //│ ║ ^ -//│ ║ l.85: [ +//│ ║ l.79: [ //│ ╙── //│ Parsed: {let arr = []} diff --git a/shared/src/test/diff/parser/BasicSyntax.mls b/shared/src/test/diff/parser/BasicSyntax.mls index f525ad0160..df6b16a603 100644 --- a/shared/src/test/diff/parser/BasicSyntax.mls +++ b/shared/src/test/diff/parser/BasicSyntax.mls @@ -180,10 +180,7 @@ foo foo of (1, 2, 3) //│ |foo|→|#of| |(|1|,| |2|,| |3|)|←| -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section -//│ ║ l.181: of (1, 2, 3) -//│ ╙── ^^^^^^^^^ -//│ Parsed: {foo([1, 2, 3,],)} +//│ Parsed: {foo(,(1, ,(2, 3,),),)} foo of @@ -229,28 +226,28 @@ foo (1 //│ ╔══[PARSE ERROR] Unmatched opening parenthesis -//│ ║ l.230: (1 +//│ ║ l.227: (1 //│ ╙── ^ //│ |1| //│ Parsed: {1} (1)) //│ ╔══[PARSE ERROR] Unexpected closing parenthesis -//│ ║ l.237: (1)) +//│ ║ l.234: (1)) //│ ╙── ^ //│ |(|1|)| //│ Parsed: {'(' 1 ')'} ( //│ ╔══[PARSE ERROR] Unmatched opening parenthesis -//│ ║ l.244: ( +//│ ║ l.241: ( //│ ╙── ^ //│ || //│ Parsed: {} ) //│ ╔══[PARSE ERROR] Unexpected closing parenthesis -//│ ║ l.251: ) +//│ ║ l.248: ) //│ ╙── ^ //│ || //│ Parsed: {} @@ -258,17 +255,17 @@ foo 1+ //│ |1|+| //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.258: 1+ +//│ ║ l.255: 1+ //│ ╙── ^ //│ Parsed: {+(1,)(undefined,)} * //│ |*| //│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.265: * +//│ ║ l.262: * //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.265: * +//│ ║ l.262: * //│ ╙── ^ //│ Parsed: {undefined} @@ -276,7 +273,7 @@ foo f 1 //│ |f| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.276: f 1 +//│ ║ l.273: f 1 //│ ╙── ^^^ //│ Parsed: {f(1,)} @@ -292,7 +289,7 @@ f (1) f 1, 2, 3 //│ |f| |1|,| |2|,| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.292: f 1, 2, 3 +//│ ║ l.289: f 1, 2, 3 //│ ╙── ^^^^^^^^^ //│ Parsed: {f(1, 2, 3,)} @@ -327,19 +324,16 @@ f{1} f{1, 2, 3} //│ |f|{|1|,| |2|,| |3|}| -//│ ╔══[PARSE ERROR] Unexpected comma here -//│ ║ l.328: f{1, 2, 3} -//│ ╙── ^ -//│ Parsed: {f {1}} +//│ Parsed: {f {,(1, ,(2, 3,),)}} f 1,, 2 //│ |f| |1|,|,| |2| //│ ╔══[PARSE ERROR] Unexpected comma in expression position -//│ ║ l.336: f 1,, 2 +//│ ║ l.330: f 1,, 2 //│ ╙── ^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.336: f 1,, 2 +//│ ║ l.330: f 1,, 2 //│ ╙── ^^^^^^^ //│ Parsed: {f(1, 2,)} @@ -351,10 +345,10 @@ f of x f g x //│ |f| |g| |x| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.351: f g x +//│ ║ l.345: f g x //│ ╙── ^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.351: f g x +//│ ║ l.345: f g x //│ ╙── ^^^^^ //│ Parsed: {f(g(x,),)} @@ -365,7 +359,7 @@ f of g of x f of of g //│ |f| |#of| |#of| |g| //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position -//│ ║ l.365: f of of g +//│ ║ l.359: f of of g //│ ╙── ^^ //│ Parsed: {f(g,)} @@ -373,52 +367,55 @@ f of of g f x: 1 //│ |f| |x|#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.373: f x: 1 +//│ ║ l.367: f x: 1 //│ ╙── ^^^^^^ //│ Parsed: {f(x: 1,)} f x: 1, //│ |f| |x|#:| |1|,| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.380: f x: 1, +//│ ║ l.374: f x: 1, //│ ╙── ^^^^^^ //│ Parsed: {f(x: 1,)} f x : 1 //│ |f| |x| |#:| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.387: f x : 1 +//│ ║ l.381: f x : 1 //│ ╙── ^^^ //│ Parsed: {f(x : 1,)} f x: 1, y: 2 //│ |f| |x|#:| |1|,| |y|#:| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.394: f x: 1, y: 2 +//│ ║ l.388: f x: 1, y: 2 //│ ╙── ^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: 2,)} f x : 1, y: 2 //│ |f| |x| |#:| |1|,| |y|#:| |2| +//│ ╔══[PARSE ERROR] Not a recognized type +//│ ║ l.395: f x : 1, y: 2 +//│ ╙── ^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.401: f x : 1, y: 2 -//│ ╙── ^^^^^^^^^^^^^ -//│ Parsed: {f(x : 1, y: 2,)} +//│ ║ l.395: f x : 1, y: 2 +//│ ╙── ^^^ +//│ Parsed: {f(x : anything,)} f x: 1, y: 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.408: f x: 1, y: 2, z: 3 +//│ ║ l.405: f x: 1, y: 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: 2, z: 3,)} f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.415: f x: 1, y: g 2, z: 3 +//│ ║ l.412: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.415: f x: 1, y: g 2, z: 3 +//│ ║ l.412: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: g(2, z: 3,),)} @@ -433,10 +430,10 @@ f(x: 1, y: g(2), z: 3) f x: 1, y: g 2, z: 3 //│ |f| |x|#:| |1|,| |y|#:| |g| |2|,| |z|#:| |3| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.433: f x: 1, y: g 2, z: 3 +//│ ║ l.430: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.433: f x: 1, y: g 2, z: 3 +//│ ║ l.430: f x: 1, y: g 2, z: 3 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: 1, y: g(2, z: 3,),)} @@ -447,13 +444,13 @@ f of x: 1, y: g of 2, z: 3 f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ |f| |x|#:| |1| |+| |1|,| |y|#:| |2| |2|,| |z|#:| |3| |+| |2| |4| |-| |1| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.447: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.444: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.447: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.444: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.447: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 +//│ ║ l.444: f x: 1 + 1, y: 2 2, z: 3 + 2 4 - 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ Parsed: {f(x: +(1,)(1,), y: 2(2, z: +(3,)(2(-(4,)(1,),),),),)} @@ -465,10 +462,10 @@ x.y .y //│ |.y| //│ ╔══[PARSE ERROR] Unexpected selector in expression position -//│ ║ l.465: .y +//│ ║ l.462: .y //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.465: .y +//│ ║ l.462: .y //│ ╙── ^ //│ Parsed: {undefined} diff --git a/shared/src/test/diff/parser/Blocks.mls b/shared/src/test/diff/parser/Blocks.mls index 1f1dd0ef69..f1cb7d0f4b 100644 --- a/shared/src/test/diff/parser/Blocks.mls +++ b/shared/src/test/diff/parser/Blocks.mls @@ -9,38 +9,32 @@ b a, b //│ |a|,|↵|b| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.9: a, -//│ ╙── ^ -//│ Parsed: {a} +//│ Parsed: {,(a, b,)} a, b, //│ |a|,|↵|b|,| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.17: a, -//│ ╙── ^ -//│ Parsed: {a} +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.15: b, +//│ ╙── ^ +//│ Parsed: {,(a, ,(b, undefined,),)} a, b, c //│ |a|,|↵|b|,|↵|c| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.25: a, -//│ ╙── ^ -//│ Parsed: {a} +//│ Parsed: {,(a, ,(b, c,),)} foo a b //│ |foo|→|a|↵|b|←| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.34: foo +//│ ║ l.28: foo //│ ║ ^^^ -//│ ║ l.35: a +//│ ║ l.29: a //│ ║ ^^^ -//│ ║ l.36: b +//│ ║ l.30: b //│ ╙── ^^^ //│ Parsed: {foo({a; b},)} @@ -71,9 +65,9 @@ foo( ) //│ |foo|(|→|a|←|→|b|←|↵|)| //│ ╔══[PARSE ERROR] Unexpected indented block here -//│ ║ l.70: b +//│ ║ l.64: b //│ ║ ^^^ -//│ ║ l.71: ) +//│ ║ l.65: ) //│ ╙── ^ //│ Parsed: {foo(a,)} @@ -84,10 +78,10 @@ foo of b //│ |foo| |#of|→|a|↵|#fun| |f| |#=| |1|↵|b|←| //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position -//│ ║ l.83: fun f = 1 +//│ ║ l.77: fun f = 1 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' here -//│ ║ l.83: fun f = 1 +//│ ║ l.77: fun f = 1 //│ ╙── ^ //│ Parsed: {foo({a; f},)} @@ -118,11 +112,11 @@ foo of c //│ |foo| |#of|→|a|↵|boo|→|x|↵|y|←|↵|c|←| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.115: boo +//│ ║ l.109: boo //│ ║ ^^^ -//│ ║ l.116: x +//│ ║ l.110: x //│ ║ ^^^^^ -//│ ║ l.117: y +//│ ║ l.111: y //│ ╙── ^^^^^ //│ Parsed: {foo({a; boo({x; y},); c},)} @@ -167,7 +161,7 @@ fun foo = log(1); log(a) //│ |log|(|1|)|;| |log|(|a|)| -//│ Parsed: {{log(1,); log(a,)}} +//│ Parsed: {log(1,); log(a,)} constructor(){ a = 1 @@ -178,13 +172,13 @@ constructor(){ a = 1; log(a) //│ |a| |#=| |1|;| |log|(|a|)| -//│ Parsed: {a = {1; log(a,)}} +//│ Parsed: {a = 1; log(a,)} :pe f(a) = 1 //│ |f|(|a|)| |#=| |1| //│ ╔══[PARSE ERROR] Expected end of input; found '=' instead -//│ ║ l.184: f(a) = 1 +//│ ║ l.178: f(a) = 1 //│ ╙── ^ //│ Parsed: {f(a,)} diff --git a/shared/src/test/diff/parser/Classes.mls b/shared/src/test/diff/parser/Classes.mls index dddfdd359c..b618b46647 100644 --- a/shared/src/test/diff/parser/Classes.mls +++ b/shared/src/test/diff/parser/Classes.mls @@ -30,13 +30,9 @@ class Foo extends Bar, Baz //│ |#class| |Foo| |#extends| |Bar|,| |Baz| //│ Parsed: {class Foo: Bar, Baz {}} -:pe class Foo: Bar, Baz //│ |#class| |Foo|#:| |Bar|,| |Baz| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.34: class Foo: Bar, Baz -//│ ╙── ^ -//│ Parsed: {class Foo: Bar {}} +//│ Parsed: {class Foo: ,[Bar, Baz] {}} class Foo: Bar { fun f = 0 } //│ |#class| |Foo|#:| |Bar| |{| |#fun| |f| |#=| |0| |}| @@ -49,10 +45,10 @@ class Foo extends Bar, Baz { fun f = 0 } :pe class Foo: Bar, Baz { fun f = 0 } //│ |#class| |Foo|#:| |Bar|,| |Baz| |{| |#fun| |f| |#=| |0| |}| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.50: class Foo: Bar, Baz { fun f = 0 } -//│ ╙── ^ -//│ Parsed: {class Foo: Bar {}} +//│ ╔══[PARSE ERROR] Not a recognized type +//│ ║ l.46: class Foo: Bar, Baz { fun f = 0 } +//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ Parsed: {class Foo: anything {}} // * Pretty confusing... better reject this: :pe @@ -62,15 +58,15 @@ class Foo: Bar { fun f = 0 } //│ |#class| |Foo|#:| |Bar| |{| |#fun| |f| |#=| |0|→|#fun| |bar| |#=| |1|←|↵|}| //│ ╔══[PARSE ERROR] Unexpected 'fun' keyword in expression position -//│ ║ l.61: fun bar = 1 +//│ ║ l.57: fun bar = 1 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' here -//│ ║ l.61: fun bar = 1 +//│ ║ l.57: fun bar = 1 //│ ╙── ^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.60: class Foo: Bar { fun f = 0 +//│ ║ l.56: class Foo: Bar { fun f = 0 //│ ║ ^ -//│ ║ l.61: fun bar = 1 +//│ ║ l.57: fun bar = 1 //│ ╙── ^^^^^^^^^ //│ Parsed: {class Foo: Bar {fun f = 0(bar,)}} diff --git a/shared/src/test/diff/parser/FatArrows.mls b/shared/src/test/diff/parser/FatArrows.mls new file mode 100644 index 0000000000..6f0a9c4093 --- /dev/null +++ b/shared/src/test/diff/parser/FatArrows.mls @@ -0,0 +1,57 @@ +:AllowParseErrors + + +fun f: (x: Int) => Int +//│ |#fun| |f|#:| |(|x|#:| |Int|)| |#=>| |Int| +//│ Parsed: {fun f: (x: Int) -> Int} + +fun f: (x: Int => Int, y: Int) => Int +//│ |#fun| |f|#:| |(|x|#:| |Int| |#=>| |Int|,| |y|#:| |Int|)| |#=>| |Int| +//│ Parsed: {fun f: (x: Int -> Int, y: Int) -> Int} + +fun f: (x: Int, y: Int => Int) => Int +//│ |#fun| |f|#:| |(|x|#:| |Int|,| |y|#:| |Int| |#=>| |Int|)| |#=>| |Int| +//│ Parsed: {fun f: (x: Int, y: Int -> Int) -> Int} + +fun f: (x: Int, y: (Int, Int) => Int) => Int +//│ |#fun| |f|#:| |(|x|#:| |Int|,| |y|#:| |(|Int|,| |Int|)| |#=>| |Int|)| |#=>| |Int| +//│ Parsed: {fun f: (x: Int, y: (Int, Int) -> Int) -> Int} + +fun f: (x: Int) +//│ |#fun| |f|#:| |(|x|#:| |Int|)| +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.20: fun f: (x: Int) +//│ ╙── ^^^^^^ +//│ Parsed: {fun f: Int} + +fun f: (x: Int, y: Int) +//│ |#fun| |f|#:| |(|x|#:| |Int|,| |y|#:| |Int|)| +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.27: fun f: (x: Int, y: Int) +//│ ╙── ^^^^^^ +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.27: fun f: (x: Int, y: Int) +//│ ╙── ^^^^^^ +//│ Parsed: {fun f: ,[Int, Int]} + +fun match: forall 'res: (() -> Int, ifCons: Int) => Int +//│ |#fun| |match|#:| |#forall| |'res|#:| |(|(||)| |->| |Int|,| |ifCons|#:| |Int|)| |#=>| |Int| +//│ Parsed: {fun match: forall 'res. (() -> Int, ifCons: Int) -> Int} + +fun match: forall 'res: (() => Int, ifCons: Int) => Int +//│ |#fun| |match|#:| |#forall| |'res|#:| |(|(||)| |#=>| |Int|,| |ifCons|#:| |Int|)| |#=>| |Int| +//│ Parsed: {fun match: forall 'res. (() -> Int, ifCons: Int) -> Int} + +fun match: forall 'res: (() => Int, Int) => Int +//│ |#fun| |match|#:| |#forall| |'res|#:| |(|(||)| |#=>| |Int|,| |Int|)| |#=>| |Int| +//│ Parsed: {fun match: forall 'res. (() -> Int, Int) -> Int} + +f(x => x, a) +//│ |f|(|x| |#=>| |x|,| |a|)| +//│ Parsed: {f((x,) => x, a,)} + +f(x => x, y: a) +//│ |f|(|x| |#=>| |x|,| |y|#:| |a|)| +//│ Parsed: {f((x,) => x, y: a,)} + + diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index e3de5bfaf8..81d6c602ef 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -547,31 +547,24 @@ if true //│ ╙── ^ //│ Parsed: {'(' if (true) then undefined ')'} -:pe if true then; //│ |#if| |true| |#then|;| -//│ ╔══[PARSE ERROR] Unexpected operator in expression position -//│ ║ l.551: if true then; -//│ ╙── ^ -//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here -//│ ║ l.551: if true then; -//│ ╙── ^ //│ Parsed: {if (true) then undefined} -if true then;; -//│ |#if| |true| |#then|#;;| +if true then; +//│ |#if| |true| |#then|;| //│ Parsed: {if (true) then undefined} :pe -if true then;; else;; -//│ |#if| |true| |#then|#;;| |#else|#;;| +if true then; else; +//│ |#if| |true| |#then|;| |#else|;| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.566: if true then;; else;; -//│ ╙── ^^^^^^ +//│ ║ l.559: if true then; else; +//│ ╙── ^^^^^ //│ Parsed: {if (true) then undefined; undefined} -if true then () else;; -//│ |#if| |true| |#then| |(||)| |#else|#;;| +if true then () else; +//│ |#if| |true| |#then| |(||)| |#else|;| //│ Parsed: {if (true) then undefined else undefined} diff --git a/shared/src/test/diff/parser/Lets.mls b/shared/src/test/diff/parser/Lets.mls index 61d18990f1..599d93f1cf 100644 --- a/shared/src/test/diff/parser/Lets.mls +++ b/shared/src/test/diff/parser/Lets.mls @@ -7,56 +7,53 @@ let x = 1 let x = 1, y = 2 //│ |#let| |x| |#=| |1|,| |y| |#=| |2| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead +//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead //│ ║ l.8: let x = 1, y = 2 -//│ ╙── ^ -//│ Parsed: {let x = 1} +//│ ╙── ^ +//│ Parsed: {let x = ,(1, y,)} let x = 1, y = 2 x + y //│ |#let| |x| |#=| |1|,| |y| |#=| |2|↵|x| |+| |y| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead +//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead //│ ║ l.15: let x = 1, y = 2 -//│ ╙── ^ -//│ Parsed: {let x = 1} +//│ ╙── ^ +//│ Parsed: {let x = ,(1, y,)} let x = 1 in x + 1 //│ |#let| |x| |#=| |1| |#in| |x| |+| |1| -//│ ╔══[PARSE ERROR] Expected end of input; found 'in' keyword instead -//│ ║ l.23: let x = 1 in x + 1 -//│ ╙── ^^ -//│ Parsed: {let x = 1} +//│ Parsed: {let x = 1 in +(x,)(1,)} let x = 1, y = 2 in x + y //│ |#let| |x| |#=| |1|,| |y| |#=| |2| |#in| |x| |+| |y| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.30: let x = 1, y = 2 in x + y -//│ ╙── ^ -//│ Parsed: {let x = 1} +//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead +//│ ║ l.27: let x = 1, y = 2 in x + y +//│ ╙── ^ +//│ Parsed: {let x = ,(1, y,)} let in 123 //│ |#let| |#in| |123| //│ ╔══[PARSE ERROR] Expected a function name; found 'in' keyword instead -//│ ║ l.37: let in 123 +//│ ║ l.34: let in 123 //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected function parameter list; found literal instead -//│ ║ l.37: let in 123 +//│ ║ l.34: let in 123 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Expected ':' or '=' followed by a function body or signature; found end of input instead -//│ ║ l.37: let in 123 +//│ ║ l.34: let in 123 //│ ╙── ^ //│ Parsed: {let = undefined} let x = 1; x + 1 //│ |#let| |x| |#=| |1|;| |x| |+| |1| -//│ Parsed: {let x = {1; +(x,)(1,)}} +//│ Parsed: {let x = 1; +(x,)(1,)} let x = 1, y = 2; x + y //│ |#let| |x| |#=| |1|,| |y| |#=| |2|;| |x| |+| |y| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.54: let x = 1, y = 2; x + y -//│ ╙── ^ -//│ Parsed: {let x = 1} +//│ ╔══[PARSE ERROR] Expected end of input; found '=' instead +//│ ║ l.51: let x = 1, y = 2; x + y +//│ ╙── ^ +//│ Parsed: {let x = ,(1, y,)} @@ -64,16 +61,16 @@ let x = 1, y = 2; x + y let in person be the default in following meetings //│ |#let| |#in| |person| |be| |the| |default| |#in| |following| |meetings| //│ ╔══[PARSE ERROR] Expected a function name; found 'in' keyword instead -//│ ║ l.64: let in person be the default in following meetings +//│ ║ l.61: let in person be the default in following meetings //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected function parameter list; found identifier instead -//│ ║ l.64: let in person be the default in following meetings +//│ ║ l.61: let in person be the default in following meetings //│ ╙── ^^^^^^ //│ ╔══[PARSE ERROR] Expected ':' or '=' followed by a function body or signature; found identifier instead -//│ ║ l.64: let in person be the default in following meetings +//│ ║ l.61: let in person be the default in following meetings //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected end of input; found identifier instead -//│ ║ l.64: let in person be the default in following meetings +//│ ║ l.61: let in person be the default in following meetings //│ ╙── ^^^ //│ Parsed: {let = undefined} diff --git a/shared/src/test/diff/parser/Misc.mls b/shared/src/test/diff/parser/Misc.mls index 0e20bd8aa4..b60f4e2d48 100644 --- a/shared/src/test/diff/parser/Misc.mls +++ b/shared/src/test/diff/parser/Misc.mls @@ -35,16 +35,16 @@ foo of //│ ╟── Note: 'if' expression starts here: //│ ║ l.10: discard of if f of x is //│ ╙── ^^ -//│ ╔══[PARSE ERROR] Unexpected comma here +//│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here //│ ║ l.15: None then 0, -//│ ╙── ^ +//│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause //│ ║ l.13: if g of y is //│ ║ ^^^^ //│ ║ l.14: Some(v) then v + 1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.15: None then 0, -//│ ╙── ^^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead //│ ║ l.13: if g of y is //│ ║ ^^^^^^^^^ @@ -67,16 +67,16 @@ foo of //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.60: Some v then v + 1 //│ ╙── ^^^^^^ -//│ ╔══[PARSE ERROR] Unexpected comma here +//│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here //│ ║ l.61: None then 0, -//│ ╙── ^ +//│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause //│ ║ l.59: if f of x is //│ ║ ^^^^ //│ ║ l.60: Some v then v + 1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.61: None then 0, -//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application followed by newline instead //│ ║ l.59: if f of x is //│ ║ ^^^^^^^^^ @@ -98,16 +98,16 @@ foo of //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword //│ ║ l.63: Some v then v + 1 //│ ╙── ^^^^^^ -//│ ╔══[PARSE ERROR] Unexpected comma here +//│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here //│ ║ l.64: None then 0, -//│ ╙── ^ +//│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause //│ ║ l.62: if g of y is //│ ║ ^^^^ //│ ║ l.63: Some v then v + 1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ║ l.64: None then 0, -//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ ╙── ^^^^^^^^^^^^^^^^^^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application followed by newline instead //│ ║ l.62: if g of y is //│ ║ ^^^^^^^^^ diff --git a/shared/src/test/diff/parser/NamedArrays.mls b/shared/src/test/diff/parser/NamedArrays.mls index 6151c63dbb..7b8ff3a159 100644 --- a/shared/src/test/diff/parser/NamedArrays.mls +++ b/shared/src/test/diff/parser/NamedArrays.mls @@ -59,48 +59,54 @@ (x: 1) //│ |(|x|#:| |1|)| -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.60: (x: 1) -//│ ╙── ^^^^^^ -//│ Parsed: {[x: 1,]} +//│ ╙── ^^^^ +//│ Parsed: {1} (x:) //│ |(|x|#:|)| //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here //│ ║ l.67: (x:) //│ ╙── ^ -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.67: (x:) -//│ ╙── ^^^^ -//│ Parsed: {[x: undefined,]} +//│ ╙── ^^ +//│ Parsed: {undefined} (x: 1,) //│ |(|x|#:| |1|,|)| -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.77: (x: 1,) -//│ ╙── ^^^^^^^ -//│ Parsed: {[x: 1,]} +//│ ╙── ^^^^ +//│ Parsed: {1} (x: 1, 2, 3) //│ |(|x|#:| |1|,| |2|,| |3|)| -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.84: (x: 1, 2, 3) -//│ ╙── ^^^^^^^^^^^^ -//│ Parsed: {[x: 1, 2, 3,]} +//│ ╙── ^^^^ +//│ Parsed: {,(1, ,(2, 3,),)} (1, y: 2, 3) //│ |(|1|,| |y|#:| |2|,| |3|)| -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.91: (1, y: 2, 3) -//│ ╙── ^^^^^^^^^^^^ -//│ Parsed: {[1, y: 2, 3,]} +//│ ╙── ^^^^ +//│ Parsed: {,(1, ,(2, 3,),)} (x: 1, y: 2, z: 3) //│ |(|x|#:| |1|,| |y|#:| |2|,| |z|#:| |3|)| -//│ ╔══[PARSE ERROR] Expected '=>' or '->' after this parameter section +//│ ╔══[PARSE ERROR] Illegal position for field specification //│ ║ l.98: (x: 1, y: 2, z: 3) -//│ ╙── ^^^^^^^^^^^^^^^^^^ -//│ Parsed: {[x: 1, y: 2, z: 3,]} +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.98: (x: 1, y: 2, z: 3) +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Illegal position for field specification +//│ ║ l.98: (x: 1, y: 2, z: 3) +//│ ╙── ^^^^ +//│ Parsed: {,(1, ,(2, 3,),)} 1 @@ -113,24 +119,21 @@ x: 1 1, //│ |1|,| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.114: 1, -//│ ╙── ^ -//│ Parsed: {1} +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.120: 1, +//│ ╙── ^ +//│ Parsed: {,(1, undefined,)} x: 1, //│ |x|#:| |1|,| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.121: x: 1, -//│ ╙── ^ -//│ Parsed: {x : 1} +//│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here +//│ ║ l.127: x: 1, +//│ ╙── ^ +//│ Parsed: {x : ,[1, ()]} 1, 2, 3 //│ |1|,| |2|,| |3| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.128: 1, 2, 3 -//│ ╙── ^ -//│ Parsed: {1} +//│ Parsed: {,(1, ,(2, 3,),)} f of 1, 2, 3 //│ |f| |#of| |1|,| |2|,| |3| @@ -162,10 +165,10 @@ f of z: 3 //│ |f| |#of|→|x|#:| |1|↵|y|#:| |2|↵|z|#:| |3|←| //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.160: x: 1 +//│ ║ l.163: x: 1 //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.161: y: 2 +//│ ║ l.164: y: 2 //│ ╙── ^ //│ Parsed: {f(z: {1; 2; 3},)} @@ -175,7 +178,7 @@ f of z: 3 //│ |f| |#of|→|x|#:| |1|↵|2|↵|z|#:| |3|←| //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.173: x: 1 +//│ ║ l.176: x: 1 //│ ╙── ^ //│ Parsed: {f(z: {1; 2; 3},)} @@ -185,10 +188,10 @@ f of 3 //│ |f| |#of|→|x|#:| |1|↵|y|#:| |2|↵|3|←| //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.183: x: 1 +//│ ║ l.186: x: 1 //│ ╙── ^ //│ ╔══[PARSE ERROR] Unexpected named argument name here -//│ ║ l.184: y: 2 +//│ ║ l.187: y: 2 //│ ╙── ^ //│ Parsed: {f({1; 2; 3},)} diff --git a/shared/src/test/diff/parser/Select.mls b/shared/src/test/diff/parser/Select.mls index 96f5548ad9..58a23c1c4a 100644 --- a/shared/src/test/diff/parser/Select.mls +++ b/shared/src/test/diff/parser/Select.mls @@ -88,13 +88,9 @@ x //│ |(|.|)| //│ Parsed: {.} -:pe a, b //│ |a|,| |b| -//│ ╔══[PARSE ERROR] Expected end of input; found comma instead -//│ ║ l.92: a, b -//│ ╙── ^ -//│ Parsed: {a} +//│ Parsed: {,(a, b,)} a .b .c @@ -136,10 +132,10 @@ a + .c //│ |a| |+|→|b|↵|.c|←| //│ ╔══[PARSE ERROR] Unexpected selector in expression position -//│ ║ l.136: .c +//│ ║ l.132: .c //│ ╙── ^^ //│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here -//│ ║ l.136: .c +//│ ║ l.132: .c //│ ╙── ^ //│ Parsed: {+(a,)({b; undefined},)} @@ -187,7 +183,7 @@ a of c //│ |a|→|.b| |+|→|1|↵|#of| |c|←|←| //│ ╔══[PARSE ERROR] Unexpected 'of' keyword in expression position -//│ ║ l.187: of c +//│ ║ l.183: of c //│ ╙── ^^ //│ Parsed: {+((a).b,)({1; c},)} @@ -226,7 +222,7 @@ a .b //│ |a|→|+|1|↵|*|2|↵|.b|←| //│ ╔══[PARSE ERROR] Unexpected selector in operator block -//│ ║ l.226: .b +//│ ║ l.222: .b //│ ╙── ^^ //│ Parsed: {*(+(a, 1,), 2,)} @@ -251,7 +247,7 @@ a 1 .+a 2 //│ |1| |.+|a| |2| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.251: 1 .+a 2 +//│ ║ l.247: 1 .+a 2 //│ ╙── ^^^ //│ Parsed: {.+(1,)(a(2,),)} diff --git a/shared/src/test/diff/parser/Where.mls b/shared/src/test/diff/parser/Where.mls index 43ff785a10..0bc3cf7667 100644 --- a/shared/src/test/diff/parser/Where.mls +++ b/shared/src/test/diff/parser/Where.mls @@ -17,18 +17,18 @@ fun foo: 'a => 'a => 'a where 'a : int //│ where //│ 'a <: int)} -:e +:pe fun foo: 'a + 'a + 'a where 'a : int //│ |#fun| |foo|#:| |'a| |+| |'a| |+| |'a| |#where| |'a| |#:| |int| -//│ ╔══[ERROR] Not a recognized type +//│ ╔══[PARSE ERROR] Not a recognized type //│ ║ l.21: fun foo: 'a + 'a + 'a where 'a : int //│ ╙── ^^^^^^^ //│ Parsed: {fun foo: anything} -:e +:pe fun foo: 'a -> 'a -> 'a where 'a : int //│ |#fun| |foo|#:| |'a| |->| |'a| |->| |'a| |#where| |'a| |#:| |int| -//│ ╔══[ERROR] Not a recognized type +//│ ╔══[PARSE ERROR] Not a recognized type //│ ║ l.29: fun foo: 'a -> 'a -> 'a where 'a : int //│ ╙── ^^^^^^^^^^^^^^ //│ Parsed: {fun foo: anything} diff --git a/shared/src/test/diff/tapl/Untyped.mls b/shared/src/test/diff/tapl/Untyped.mls index 65d6ead649..c8eb62a22f 100644 --- a/shared/src/test/diff/tapl/Untyped.mls +++ b/shared/src/test/diff/tapl/Untyped.mls @@ -272,7 +272,7 @@ fun hasFree(t, n) = //│ = [Function: hasFree] fun showHasFree(t, n) = - concat4(showTerm(t), if hasFree(t, n) then " has " else " DOES NOT have ", "free variable ", n) + concat4(showTerm(t), (if hasFree(t, n) then " has " else " DOES NOT have "), "free variable ", n) //│ showHasFree: (Abs & 'a & 'b | App & 'c & 'd | Var, string,) -> string //│ where //│ 'b <: {lhs: anything, rhs: Abs & 'b | App & 'd | Var | ~Abs & ~App & ~Var} diff --git a/shared/src/test/diff/ucs/InterleavedLet.mls b/shared/src/test/diff/ucs/InterleavedLet.mls index cb69a5eebc..77b2d6ba51 100644 --- a/shared/src/test/diff/ucs/InterleavedLet.mls +++ b/shared/src/test/diff/ucs/InterleavedLet.mls @@ -262,7 +262,7 @@ fun mapPartition(f, xs) = //│ 'a <: {head: 'head, tail: Cons & 'a | Nil} //│ = [Function: mapPartition] -mapPartition(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) +mapPartition(x => (if x % 2 == 0 then Left(x) else Right(x)), zeroToThree) //│ res: Pair & { //│ fst: forall 'a 'b. Nil | 'b | 'a, //│ snd: Nil | Cons & {head: 0 | 1 | 2 | 3, tail: Nil} @@ -299,7 +299,7 @@ fun mapPartition2(f, xs) = //│ 'a <: {head: 'head, tail: Cons & 'a | Nil} //│ = [Function: mapPartition2] -mapPartition2(x => if x % 2 == 0 then Left(x) else Right(x), zeroToThree) +mapPartition2(x => (if x % 2 == 0 then Left(x) else Right(x)), zeroToThree) //│ res: Pair & { //│ fst: forall 'a. Cons & { //│ head: 0, diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index b5772437fd..9906ed260b 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -394,13 +394,13 @@ class DiffTests if (!mode.fixme) { if (!allowTypeErrors && !mode.expectTypeErrors && diag.isInstanceOf[ErrorReport] && diag.source =:= Diagnostic.Typing) - failures += globalLineNum + { output("TEST CASE FAILURE: There was an unexpected type error"); failures += globalLineNum } if (!allowParseErrors && !mode.expectParseErrors && diag.isInstanceOf[ErrorReport] && (diag.source =:= Diagnostic.Lexing || diag.source =:= Diagnostic.Parsing)) - failures += globalLineNum + { output("TEST CASE FAILURE: There was an unexpected parse error"); failures += globalLineNum } if (!allowTypeErrors && !allowParseErrors && !mode.expectWarnings && diag.isInstanceOf[WarningReport]) - failures += globalLineNum + { output("TEST CASE FAILURE: There was an unexpected warning"); failures += globalLineNum } } () @@ -409,6 +409,8 @@ class DiffTests val raise: Raise = d => report(d :: Nil) + val legacyParser = file.ext =:= "fun" + // try to parse block of text into mlscript ast val ans = try { if (newParser) { @@ -441,7 +443,7 @@ class DiffTests } else parse(processedBlockStr, p => - if (file.ext =:= "fun") new Parser(Origin(testName, globalStartLineNum, fph)).pgrm(p) + if (legacyParser) new Parser(Origin(testName, globalStartLineNum, fph)).pgrm(p) else new MLParser(Origin(testName, globalStartLineNum, fph)).pgrm(p), verboseFailures = true ) @@ -451,14 +453,14 @@ class DiffTests val (lineNum, lineStr, col) = fph.getLineColAt(index) val globalLineNum = (allLines.size - lines.size) + lineNum if (!mode.expectParseErrors && !mode.fixme) - failures += globalLineNum + { output("TEST CASE FAILURE: There was an unexpected parse error"); failures += globalLineNum } output("/!\\ Parse error: " + extra.trace().msg + s" at l.$globalLineNum:$col: $lineStr") // successfully parsed block into a valid syntactically valid program case Success(p, index) => - if (mode.expectParseErrors && !newParser) - failures += blockLineNum + if (mode.expectParseErrors && !newParser && !legacyParser) + { output("TEST CASE FAILURE: There was an unexpected parse success"); failures += blockLineNum } if (mode.showParse || mode.dbgParsing) output("Parsed: " + p.showDbg) // if (mode.isDebugging) typer.resetState() if (mode.stats) typer.resetStats() @@ -938,10 +940,10 @@ class DiffTests if (!mode.expectTypeErrors && !mode.fixme) { // We don't expect code generation errors and it is. if (!mode.expectCodeGenErrors && isSyntaxError) - failures += blockLineNum + { output("TEST CASE FAILURE: There was an unexpected codegen error"); failures += blockLineNum } // We don't expect runtime errors and it's a runtime error. if (!mode.expectRuntimeErrors && !allowRuntimeErrors && !isSyntaxError) - failures += blockLineNum + { output("TEST CASE FAILURE: There was an unexpected runtime error"); failures += blockLineNum } } if (isSyntaxError) { // If there is syntax error in the generated code, @@ -1032,15 +1034,15 @@ class DiffTests } if (mode.expectParseErrors && totalParseErrors =:= 0) - failures += blockLineNum + { output("TEST CASE FAILURE: There was an unexpected lack of parse error"); failures += blockLineNum } if (mode.expectTypeErrors && totalTypeErrors =:= 0) - failures += blockLineNum + { output("TEST CASE FAILURE: There was an unexpected lack of type error"); failures += blockLineNum } if (mode.expectWarnings && totalWarnings =:= 0) - failures += blockLineNum + { output("TEST CASE FAILURE: There was an unexpected lack of warning"); failures += blockLineNum } if (mode.expectCodeGenErrors && totalCodeGenErrors =:= 0) - failures += blockLineNum + { output("TEST CASE FAILURE: There was an unexpected lack of codegen error"); failures += blockLineNum } if (mode.expectRuntimeErrors && totalRuntimeErrors =:= 0) - failures += blockLineNum + { output("TEST CASE FAILURE: There was an unexpected lack of runtime error"); failures += blockLineNum } } catch { case oh_noes: ThreadDeath => throw oh_noes case err: Throwable => diff --git a/shared/src/test/scala/mlscript/ReplHost.scala b/shared/src/test/scala/mlscript/ReplHost.scala index c13b421f61..2113ac7eb0 100644 --- a/shared/src/test/scala/mlscript/ReplHost.scala +++ b/shared/src/test/scala/mlscript/ReplHost.scala @@ -1,6 +1,6 @@ package mlscript -import mlscript.utils.shorthands._ +import mlscript.utils._, shorthands._ /** * A helper class to manipulate an interactive Node.js process. @@ -31,7 +31,9 @@ final case class ReplHost() { private def collectUntilPrompt(): ReplHost.Reply = { val buffer = new StringBuilder() while (!buffer.endsWith("\n> ")) { - buffer.append(stdout.read().toChar) + val c = stdout.read() + if (c === -1) lastWords(s"ReplHost could not read more from NodeJS stdout.") + buffer.append(c.toChar) } // Remove the trailing `"\n> "` buffer.delete(buffer.length - 3, buffer.length) From cc2773d3d8fbcd79c999fc27f9096891d82783f7 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 11 Jan 2024 23:03:23 +0800 Subject: [PATCH 496/498] Fix/virtual type arg params (#205) --- .../src/main/scala/mlscript/NuTypeDefs.scala | 25 +++- shared/src/test/diff/gadt/ThisMatching.mls | 125 ++++++++++++++---- shared/src/test/diff/nu/OptionFilter.mls | 59 ++++++++- shared/src/test/diff/nu/SelfRec.mls | 8 +- 4 files changed, 180 insertions(+), 37 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 9349566a55..a580394ecd 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -172,6 +172,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def isImplemented: Bool = true def isPublic = true // TODO + // TODO dedup with the one in TypedNuCls lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO), isPublic = true)(level) @@ -357,7 +358,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => lazy val virtualMembers: Map[Str, NuMember] = members ++ tparams.map { case (nme @ TypeName(name), tv, _) => td.nme.name+"#"+name -> NuParam(nme, FieldType(S(tv), tv)(provTODO), isPublic = false)(level) - } + } def freshenAbove(lim: Int, rigidify: Bool) (implicit ctx: Ctx, freshened: MutMap[TV,ST]) @@ -748,11 +749,16 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => * the map of members is for the inherited virtual type argument members. */ type TypedParentSpec = (TypedNuTypeDef, Ls[NuParam], Map[Str, NuMember], Opt[Loc]) + private var typingParents = false lazy val typedParents: Ls[TypedParentSpec] = ctx.nest.nextLevel { implicit ctx => ctx ++= paramSymbols - parentSpecs.flatMap { + if (typingParents === true) { + err(msg"Unhandled cyclic parent specification", decl.toLoc) + Nil + } else + try {typingParents = true; parentSpecs}.flatMap { case (p, v @ Var(parNme), lti, parTargs, parArgs) => trace(s"${lvl}. Typing parent spec $p") { val info = lti.complete() @@ -890,7 +896,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => } }() - } + } finally { typingParents = false } } @@ -1045,15 +1051,22 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case td: NuTypeDef => (td.params.getOrElse(Tup(Nil)).fields.iterator.flatMap(_._1) ++ td.body.entities.iterator.collect { case fd: NuFunDef => fd.nme - }).toSet ++ inheritedFields + }).toSet ++ inheritedFields ++ tparams.map { + case (nme @ TypeName(name), tv, _) => + Var(td.nme.name+"#"+name).withLocOf(nme) + } case _: NuFunDef => Set.empty } - lazy val typedFields: Map[Var, FieldType] = {println(("privateFields"),privateParams) + lazy val typedFields: Map[Var, FieldType] = { (typedParams.getOrElse(Nil).toMap // -- privateFields -- inheritedFields /* parameters can be overridden by inherited fields/methods */ - ) ++ typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) + ) ++ typedSignatures.iterator.map(fd_ty => fd_ty._1.nme -> fd_ty._2.toUpper(noProv)) ++ + typedParents.flatMap(_._3).flatMap { + case (k, p: NuParam) => Var(k) -> p.ty :: Nil + case _ => Nil + } } lazy val mutRecTV: TV = freshVar( TypeProvenance(decl.toLoc, decl.describe, S(decl.name), decl.isInstanceOf[NuTypeDef]), diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index 8bbf2032e1..e5d94d6926 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -66,26 +66,84 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ } -class Exp: (Pair | Lit) { +class Exp: (() | Lit) { fun test = if this is Lit then 0 - Pair(l, r) then 1 + () then 1 } class Lit(n: Int) extends Exp -class Pair(lhs: Exp, rhs: Exp) extends Exp -//│ class Exp: Lit | Pair { +//│ class Exp: Lit | () { //│ constructor() //│ fun test: 0 | 1 //│ } //│ class Lit(n: Int) extends Exp { //│ fun test: 0 | 1 //│ } -//│ class Pair(lhs: Exp, rhs: Exp) extends Exp { + +// * TODO fix this by requiring a type annotation on `test` and delaying its body's type checking until all the involed classes are completed +// * Currently we try to complete Exp ->{type checking defn body} complete test ->{type checking pattern} find Wrap's typed fields ->{get Wrap's typed parents} complete Exp +:e +class Exp: (() | Wrap) { + fun test = if this is + Wrap(a) then 0 + () then 1 +} +class Wrap(n: Exp) extends Exp +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.86: class Exp: (() | Wrap) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.87: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.88: Wrap(a) then 0 +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.89: () then 1 +//│ ║ ^^^^^^^^^^^^^ +//│ ║ l.90: } +//│ ╙── ^ +//│ class Exp: Wrap | () { +//│ constructor() //│ fun test: 0 | 1 //│ } +//│ class Wrap(n: Exp) extends Exp +// * TODO (same as above) +:e +class Exp: (Pair | Lit) { + fun test: Int + fun test = if this is + Lit then 0 + Pair(l, r) then 1 +} +class Lit(n: Int) extends Exp +class Pair(lhs: Exp, rhs: Exp) extends Exp +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.111: class Exp: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.112: fun test: Int +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.113: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.114: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.115: Pair(l, r) then 1 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.116: } +//│ ╙── ^ +//│ class Exp: Lit | Pair { +//│ constructor() +//│ fun test: Int +//│ } +//│ class Lit(n: Int) extends Exp { +//│ fun test: Int +//│ } +//│ class Pair(lhs: Exp, rhs: Exp) extends Exp + +:e // TODO Pair(Lit(1), Lit(2)).test -//│ 0 | 1 +//│ ╔══[ERROR] Type `Pair` does not contain member `test` +//│ ║ l.142: Pair(Lit(1), Lit(2)).test +//│ ╙── ^^^^^ +//│ error //│ res //│ = 1 @@ -98,9 +156,20 @@ class Exp: (Pair | Lit) { } class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.152: class Exp: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.153: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.154: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.155: Pair(l, r) then l.test + r.test +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.156: } +//│ ╙── ^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.97: Pair(l, r) then l.test + r.test -//│ ╙── ^^^^^ +//│ ║ l.155: Pair(l, r) then l.test + r.test +//│ ╙── ^^^^^ //│ class Exp: Lit | Pair { //│ constructor() //│ fun test: Int | error @@ -108,11 +177,10 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Lit(n: Int) extends Exp { //│ fun test: Int | error //│ } -//│ class Pair(lhs: Exp, rhs: Exp) extends Exp { -//│ fun test: Int | error -//│ } +//│ class Pair(lhs: Exp, rhs: Exp) extends Exp +:e // TODO class Exp: (Pair | Lit) { fun test : Int fun test = if this is @@ -121,6 +189,19 @@ class Exp: (Pair | Lit) { } class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp +//│ ╔══[ERROR] Unhandled cyclic definition +//│ ║ l.184: class Exp: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.185: fun test : Int +//│ ║ ^^^^^^^^^^^^^^^^ +//│ ║ l.186: fun test = if this is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.187: Lit then 0 +//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.188: Pair(l, r) then l.test + r.test +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.189: } +//│ ╙── ^ //│ class Exp: Lit | Pair { //│ constructor() //│ fun test: Int @@ -128,9 +209,7 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ class Lit(n: Int) extends Exp { //│ fun test: Int //│ } -//│ class Pair(lhs: Exp, rhs: Exp) extends Exp { -//│ fun test: Int -//│ } +//│ class Pair(lhs: Exp, rhs: Exp) extends Exp :e // TODO support – this requires implementing type member lookup without forced completion (we get constraints like Pair <: Pair#L) @@ -142,25 +221,25 @@ class Exp[A]: (Pair | Lit) { class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.137: class Exp[A]: (Pair | Lit) { +//│ ║ l.216: class Exp[A]: (Pair | Lit) { //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.138: fun test = if this is +//│ ║ l.217: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.139: Lit then 0 +//│ ║ l.218: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.140: Pair then 1 +//│ ║ l.219: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.141: } +//│ ║ l.220: } //│ ╙── ^ //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.138: fun test = if this is +//│ ║ l.217: fun test = if this is //│ ║ ^^^^^^^ -//│ ║ l.139: Lit then 0 +//│ ║ l.218: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.140: Pair then 1 +//│ ║ l.219: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.143: class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] +//│ ║ l.222: class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╙── ^ //│ class Exp[A]: Lit | Pair[anything, anything] { //│ constructor() diff --git a/shared/src/test/diff/nu/OptionFilter.mls b/shared/src/test/diff/nu/OptionFilter.mls index afe5f8c64c..530722135f 100644 --- a/shared/src/test/diff/nu/OptionFilter.mls +++ b/shared/src/test/diff/nu/OptionFilter.mls @@ -1,6 +1,24 @@ :NewDefs -// FIXME: this looks like a bug about mutually-referential definitions + +// * Minimization of code that used to cause a problem: + +abstract class Option[T]: (None | ()) { + virtual fun filter: Option[T] +} +module None extends Option[nothing] { + fun filter = None +} +//│ abstract class Option[T]: None | () { +//│ fun filter: Option[T] +//│ } +//│ module None extends Option { +//│ fun filter: None +//│ } + + +// * Original code: + abstract class Option[out T]: (Some[T] | None) { virtual fun filter: (p: T -> Bool) -> Option[T] } @@ -10,12 +28,6 @@ class Some[out T](val value: T) extends Option[T] { module None extends Option[nothing] { fun filter(_) = None } -//│ ╔══[ERROR] Type `#Some & {Some#T <: ?T}` does not contain member `Option#T` -//│ ║ l.4: abstract class Option[out T]: (Some[T] | None) { -//│ ╙── ^ -//│ ╔══[ERROR] Type `#None` does not contain member `Option#T` -//│ ║ l.4: abstract class Option[out T]: (Some[T] | None) { -//│ ╙── ^ //│ abstract class Option[T]: None | Some[T] { //│ fun filter: (p: T -> Bool) -> Option[T] //│ } @@ -25,3 +37,36 @@ module None extends Option[nothing] { //│ module None extends Option { //│ fun filter: anything -> None //│ } + + + +abstract class Boxful[T] { + virtual fun clone(): Boxful[T] +} +class MetalBox[T](value: T) extends Boxful[T] { + fun clone(): Boxful[T] = MetalBox(value) +} +//│ abstract class Boxful[T] { +//│ fun clone: () -> Boxful[T] +//│ } +//│ class MetalBox[T](value: T) extends Boxful { +//│ fun clone: () -> Boxful[T] +//│ } + + +fun makeMetalBox(value: 'A): Boxful['A] = MetalBox(value) +abstract class Boxful[T] { + virtual fun clone(): Boxful[T] +} +class MetalBox[T](value: T) extends Boxful[T] { + fun clone(): Boxful[T] = makeMetalBox(value) +} +//│ fun makeMetalBox: forall 'T. (value: 'T) -> Boxful['T] +//│ abstract class Boxful[T] { +//│ fun clone: () -> Boxful[T] +//│ } +//│ class MetalBox[T](value: T) extends Boxful { +//│ fun clone: () -> Boxful[T] +//│ } + + diff --git a/shared/src/test/diff/nu/SelfRec.mls b/shared/src/test/diff/nu/SelfRec.mls index 7f9a6fd6b9..3a68af47cf 100644 --- a/shared/src/test/diff/nu/SelfRec.mls +++ b/shared/src/test/diff/nu/SelfRec.mls @@ -229,6 +229,9 @@ class Foo8[A](x: A) { :e // * FIXME this is caused by the self-annotation... abstract class List(val length: Int): Cons class Cons(tail: List) extends List(tail.length + 1) +//│ ╔══[ERROR] Unhandled cyclic parent specification +//│ ║ l.231: class Cons(tail: List) extends List(tail.length + 1) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation //│ ║ l.231: class Cons(tail: List) extends List(tail.length + 1) //│ ╙── ^^^^^^^ @@ -241,8 +244,11 @@ class Cons(tail: List) extends List(tail.length + 1) abstract class List[out A](val length: Int): Cons[A] | Nil class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) module Nil extends List[nothing](0) +//│ ╔══[ERROR] Unhandled cyclic parent specification +//│ ║ l.245: class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.242: class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) +//│ ║ l.245: class Cons[out A](val head: A, val tail: List[A]) extends List[A](tail.length + 1) //│ ╙── ^^^^^^^ //│ abstract class List[A](length: Int): Cons[A] | Nil //│ class Cons[A](head: A, tail: List[A]) extends List From 0e5e01b4f6c077dfae65e89ea8b55b562baf60b2 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 11 Jan 2024 23:25:12 +0800 Subject: [PATCH 497/498] Allow somewhat flat if-then-else expressions --- .../src/main/scala/mlscript/NewParser.scala | 44 ++++-- shared/src/test/diff/nu/FlatIfThenElse.mls | 126 ++++++++++++++++++ shared/src/test/diff/nu/FunnyIndet.mls | 72 ++++++++++ shared/src/test/diff/parser/IfThenElse.mls | 61 ++++----- 4 files changed, 258 insertions(+), 45 deletions(-) create mode 100644 shared/src/test/diff/nu/FlatIfThenElse.mls create mode 100644 shared/src/test/diff/nu/FunnyIndet.mls diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index af6f34d577..ace8141eb8 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -587,15 +587,28 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo } } + private def unexpectedThenElse(loc: Opt[Loc]) = { + err(msg"Expected an expression; found a 'then'/'else' clause instead" -> loc :: Nil) + errExpr + } + final def expr(prec: Int, allowSpace: Bool = true)(implicit fe: FoundErr, l: Line): Term = wrap(prec,allowSpace) { l => exprOrIf(prec, allowSpace)(et = false, fe = fe, l = implicitly) match { case R(e) => e - case L(e) => - err(msg"Expected an expression; found a 'then'/'else' clause instead" -> e.toLoc :: Nil) - errExpr + case L(e) => unexpectedThenElse(e.toLoc) } } + def exprOrBlockContinuation(implicit et: ExpectThen, fe: FoundErr, l: Line): Term = + yeetSpaces match { + case (NEWLINE, l0) :: _ => + consume + val stmts = block + val es = stmts.map { case L(t) => unexpectedThenElse(t.toLoc); case R(e) => e } + Blk(es) + case _ => expr(0) + } + private def warnDbg(msg: Any, loco: Opt[Loc] = curLoc): Unit = raise(WarningReport(msg"[${cur.headOption.map(_._1).mkString}] ${""+msg}" -> loco :: Nil, newDefs = true)) @@ -722,8 +735,14 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo exprCont(NuNew(body).withLoc(S(l0 ++ body.toLoc)), prec, allowNewlines = false) case (KEYWORD("else"), l0) :: _ => consume - val e = expr(0) - L(IfElse(e).withLoc(S(l0 ++ e.toLoc))) + yeetSpaces match { + case (NEWLINE, l0) :: _ => + consume + ??? // TODO + case _ => + val e = expr(0) + L(IfElse(e).withLoc(S(l0 ++ e.toLoc))) + } case (KEYWORD("case"), l0) :: _ => consume exprOrIf(0)(et = true, fe = fe, l = implicitly) match { @@ -744,7 +763,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo val els = yeetSpaces match { case (KEYWORD("else"), _) :: _ => consume - S(expr(0)) + S(exprOrBlockContinuation) case (NEWLINE, _) :: (KEYWORD("else"), _) :: _ => consume consume @@ -847,7 +866,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (IDENT(opStr, true), l0) :: _ if /* isInfix(opStr) && */ opPrec(opStr)._1 > prec => consume val v = Var(opStr).withLoc(S(l0)) - // printDbg(s">>> $opStr ${opPrec(opStr)}") + yeetSpaces match { + case (NEWLINE, l0) :: _ => consume + case _ => + } exprOrIf(opPrec(opStr)._2) match { case L(rhs) => L(IfOpApp(acc, v, rhs)) @@ -897,13 +919,11 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (KEYWORD("then"), _) :: _ if /* expectThen && */ prec === 0 => // case (KEYWORD("then"), _) :: _ if /* expectThen && */ prec <= 1 => consume - val e = expr(0) - L(IfThen(acc, e)) + L(IfThen(acc, exprOrBlockContinuation)) case (NEWLINE, _) :: (KEYWORD("then"), _) :: _ if /* expectThen && */ prec === 0 => consume consume - val e = expr(0) - L(IfThen(acc, e)) + L(IfThen(acc, exprOrBlockContinuation)) case (NEWLINE, _) :: _ if allowNewlines => consume exprCont(acc, 0, allowNewlines) @@ -989,7 +1009,7 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo // val as = argsOrIf(Nil) // TODO val res = App(acc, Tup(as)) exprCont(res, prec, allowNewlines) - + case c @ (h :: _) if (h._1 match { case KEYWORD(":" | "of" | "where" | "extends") | SEMI | BRACKETS(Round | Square, _) | BRACKETS(Indent, ( diff --git a/shared/src/test/diff/nu/FlatIfThenElse.mls b/shared/src/test/diff/nu/FlatIfThenElse.mls new file mode 100644 index 0000000000..03a92984ec --- /dev/null +++ b/shared/src/test/diff/nu/FlatIfThenElse.mls @@ -0,0 +1,126 @@ +:NewDefs + + +type Option[out A] = Some[A] | None +class Some[out A](val value: A) +module None +//│ type Option[A] = None | Some[A] +//│ class Some[A](value: A) +//│ module None + + +fun test(x: Option[Int]) = + if x is None then [0, 0] else + log(x.value) + // ... + // do other things on the happy path + // ... + [x.value - 1, x.value + 1] +//│ fun test: (x: Option[Int]) -> [Int, Int] + +test(Some(10)) +//│ [Int, Int] +//│ res +//│ = [ 9, 11 ] +//│ // Output +//│ 10 + + +fun test(x: Option[Int]) = + if x is + None then [0, 0] + Some(value) then + log(value) + [value - 1, value + 1] +//│ fun test: (x: Option[Int]) -> [Int, Int] + +fun test(x: Option[Int]) = + if x is + None then [0, 0] + Some(value) + then + log(value) + [value - 1, value + 1] +//│ fun test: (x: Option[Int]) -> [Int, Int] + +fun test(x: Option[Int]) = + if x is + None then [0, 0] + Some(value) + then + log(value) + [value - 1, value + 1] +//│ fun test: (x: Option[Int]) -> [Int, Int] + +fun test(x: Option[Int]) = + if x is + None then [0, 0] + Some(value) then + log(value) + [value - 1, value + 1] +//│ fun test: (x: Option[Int]) -> [Int, Int] + +:pe // TODO support +fun test(x: Option[Int]) = + if x is + None then [0, 0] + Some(value) then [value - 1, value + 1] +//│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead +//│ ║ l.65: if x is +//│ ║ ^^^^ +//│ ║ l.66: None then [0, 0] +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.67: Some(value) then [value - 1, value + 1] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ fun test: (x: Option[Int]) -> () + +:pe // TODO support +fun test(x: Option[Int]) = + if x is + None then [0, 0] + Some(value) then + log(value) + [value - 1, value + 1] +//│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead +//│ ║ l.79: if x is +//│ ║ ^^^^ +//│ ║ l.80: None then [0, 0] +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.81: Some(value) then +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ║ l.82: log(value) +//│ ║ ^^^^^^^^^^^^ +//│ ║ l.83: [value - 1, value + 1] +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ fun test: (x: Option[Int]) -> () + +// Q: Support? +:pe +:e +fun test(x: Option[Int]) = + if x is + None then [0, 0] + Some(value) + then + log(value) + [value - 1, value + 1] +//│ ╔══[PARSE ERROR] Unexpected 'then' keyword in expression position +//│ ║ l.104: then +//│ ╙── ^^^^ +//│ ╔══[ERROR] Illegal interleaved statement App(Var(Some),Tup(List((None,Fld(_,Var(value)))))) +//│ ║ l.103: Some(value) +//│ ╙── ^^^^^^^^^^^ +//│ ╔══[ERROR] identifier not found: value +//│ ║ l.105: log(value) +//│ ╙── ^^^^^ +//│ ╔══[ERROR] identifier not found: value +//│ ║ l.106: [value - 1, value + 1] +//│ ╙── ^^^^^ +//│ ╔══[ERROR] identifier not found: value +//│ ║ l.106: [value - 1, value + 1] +//│ ╙── ^^^^^ +//│ fun test: (x: Option[Int]) -> [Int, Int] +//│ Code generation encountered an error: +//│ if expression was not desugared + + diff --git a/shared/src/test/diff/nu/FunnyIndet.mls b/shared/src/test/diff/nu/FunnyIndet.mls new file mode 100644 index 0000000000..3cd12c5189 --- /dev/null +++ b/shared/src/test/diff/nu/FunnyIndet.mls @@ -0,0 +1,72 @@ +:NewDefs + + +2 + + 2 * + 3 +//│ Int +//│ res +//│ = 8 + +2 - + 3 - + 4 +//│ Int +//│ res +//│ = 3 + +2 + + 2 +//│ Int +//│ res +//│ = 4 + +2 + +2 +//│ Int +//│ res +//│ = 4 + + +:e // TODO support +2 is + 2 +//│ ╔══[ERROR] illegal pattern +//│ ║ l.33: 2 +//│ ╙── ^ +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + +if 2 is 2 then true +//│ true +//│ res +//│ = true + +2 is +2 +//│ Bool +//│ res +//│ = true + + +if 2 is +2 then true +//│ true +//│ res +//│ = true + +:pe // TODO support +if 2 is +2 then true +1 then false +//│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause +//│ ║ l.62: 1 then false +//│ ╙── ^^^^^^^^^^^^ +//│ () +//│ res +//│ = true +//│ res +//│ = undefined + + diff --git a/shared/src/test/diff/parser/IfThenElse.mls b/shared/src/test/diff/parser/IfThenElse.mls index 81d6c602ef..7255013bc7 100644 --- a/shared/src/test/diff/parser/IfThenElse.mls +++ b/shared/src/test/diff/parser/IfThenElse.mls @@ -232,30 +232,25 @@ if lol then else //│ |#if| |lol|↵|#then|↵|#else| -//│ ╔══[PARSE ERROR] Unexpected newline in expression position -//│ ║ l.232: then -//│ ║ ^ -//│ ║ l.233: else -//│ ╙── //│ ╔══[PARSE ERROR] Unexpected end of input; an expression was expected here //│ ║ l.233: else //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead //│ ║ l.233: else //│ ╙── ^^^^ -//│ Parsed: {if (lol) then undefined} +//│ Parsed: {if (lol) then {undefined}} :pe if lol else 2 //│ |#if| |lol| |#else| |2| //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found reference followed by 'else' keyword instead -//│ ║ l.249: if lol else 2 +//│ ║ l.244: if lol else 2 //│ ║ ^^^^^^^^ //│ ╟── Note: 'if' expression starts here: -//│ ║ l.249: if lol else 2 +//│ ║ l.244: if lol else 2 //│ ╙── ^^ //│ ╔══[PARSE ERROR] Expected end of input; found 'else' keyword instead -//│ ║ l.249: if lol else 2 +//│ ║ l.244: if lol else 2 //│ ╙── ^^^^ //│ Parsed: {if (lol) then undefined} @@ -270,7 +265,7 @@ x = y = 1 //│ |x| |#=|→|#if| |true| |#then|←|↵|y| |#=| |1| //│ ╔══[PARSE ERROR] Unexpected end of indented block; an expression was expected here -//│ ║ l.269: if true then +//│ ║ l.264: if true then //│ ╙── ^ //│ Parsed: {x = {if (true) then undefined}; y = 1} @@ -287,7 +282,7 @@ if a == 2 and b then "" //│ |2| |and| |b| |#then| |""| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.287: 2 and b then "" +//│ ║ l.282: 2 and b then "" //│ ╙── ^^^^^^^^^^^^^^^ //│ Parsed: {undefined} @@ -318,7 +313,7 @@ if else 1 //│ |#else| |1| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.318: else 1 +//│ ║ l.313: else 1 //│ ╙── ^^^^^^ //│ Parsed: {undefined} @@ -326,7 +321,7 @@ else 1 1 else 2 //│ |1| |#else| |2| //│ ╔══[PARSE ERROR] Expected end of input; found 'else' keyword instead -//│ ║ l.326: 1 else 2 +//│ ║ l.321: 1 else 2 //│ ╙── ^^^^ //│ Parsed: {1} @@ -371,7 +366,7 @@ if a is Left x then x //│ |#if| |a| |is|→|Left| |x| |#then| |x|←| //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.371: Left x then x +//│ ║ l.366: Left x then x //│ ╙── ^^^^^^ //│ Parsed: {if a is ‹(Left(x,)) then x›} @@ -382,9 +377,9 @@ if a is then y //│ |#if| |a| |is|→|Left|(|x|)| |#then| |x|↵|#let| |y| |#=| |a| |+| |1|↵|#then| |y|←| //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.381: let y = a + 1 +//│ ║ l.376: let y = a + 1 //│ ║ ^^^^^ -//│ ║ l.382: then y +//│ ║ l.377: then y //│ ╙── ^^^^^^^^ //│ Parsed: {if a is ‹(Left(x,)) then x; let y = undefined›} @@ -397,19 +392,19 @@ if a is if let Some(x) = v then 123 //│ |#if| |#let| |Some|(|x|)| |#=| |v| |#then| |123| //│ ╔══[PARSE ERROR] Expected '='; found parenthesis section instead -//│ ║ l.397: if let Some(x) = v then 123 +//│ ║ l.392: if let Some(x) = v then 123 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' in expression position -//│ ║ l.397: if let Some(x) = v then 123 +//│ ║ l.392: if let Some(x) = v then 123 //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.397: if let Some(x) = v then 123 +//│ ║ l.392: if let Some(x) = v then 123 //│ ╙── ^^^^^^^^^^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found let binding instead -//│ ║ l.397: if let Some(x) = v then 123 +//│ ║ l.392: if let Some(x) = v then 123 //│ ║ ^ //│ ╟── Note: 'if' expression starts here: -//│ ║ l.397: if let Some(x) = v then 123 +//│ ║ l.392: if let Some(x) = v then 123 //│ ╙── ^^ //│ Parsed: {if (let Some = undefined in undefined) then undefined} @@ -418,19 +413,19 @@ if let Some(x) = v then 123 if let Some(x) = v and cond then 123 //│ |#if| |#let| |Some|(|x|)| |#=| |v| |and| |cond| |#then| |123| //│ ╔══[PARSE ERROR] Expected '='; found parenthesis section instead -//│ ║ l.418: if let Some(x) = v and cond then 123 +//│ ║ l.413: if let Some(x) = v and cond then 123 //│ ╙── ^^^ //│ ╔══[PARSE ERROR] Unexpected '=' in expression position -//│ ║ l.418: if let Some(x) = v and cond then 123 +//│ ║ l.413: if let Some(x) = v and cond then 123 //│ ╙── ^ //│ ╔══[PARSE ERROR] Expected an expression; found a 'then'/'else' clause instead -//│ ║ l.418: if let Some(x) = v and cond then 123 +//│ ║ l.413: if let Some(x) = v and cond then 123 //│ ╙── ^^^^^^^^^^^^^^^^^^^ //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found let binding instead -//│ ║ l.418: if let Some(x) = v and cond then 123 +//│ ║ l.413: if let Some(x) = v and cond then 123 //│ ║ ^ //│ ╟── Note: 'if' expression starts here: -//│ ║ l.418: if let Some(x) = v and cond then 123 +//│ ║ l.413: if let Some(x) = v and cond then 123 //│ ╙── ^^ //│ Parsed: {if (let Some = undefined in undefined) then undefined} @@ -457,7 +452,7 @@ if true + 1 //│ |#if| |true|→|#then| |0|↵|+| |1|←| //│ ╔══[PARSE ERROR] Unexpected operator here -//│ ║ l.457: + 1 +//│ ║ l.452: + 1 //│ ╙── ^ //│ Parsed: {if (true) then 0} @@ -486,7 +481,7 @@ if true + 1 //│ |#if| |true|→|#then| |0|←|→|+| |1|←| //│ ╔══[PARSE ERROR] Expected end of input; found indented block instead -//│ ║ l.486: + 1 +//│ ║ l.481: + 1 //│ ╙── ^^ //│ Parsed: {if (true) then 0} @@ -497,7 +492,7 @@ if true + 1 //│ |#if| |true|→|#then| |0|↵|#else| |0|←|→|+| |1|←| //│ ╔══[PARSE ERROR] Expected end of input; found indented block instead -//│ ║ l.497: + 1 +//│ ║ l.492: + 1 //│ ╙── ^^ //│ Parsed: {if (true) then 0 else 0} @@ -532,10 +527,10 @@ if true (if true) //│ |(|#if| |true|)| //│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found reference instead -//│ ║ l.532: (if true) +//│ ║ l.527: (if true) //│ ║ ^^^^ //│ ╟── Note: 'if' expression starts here: -//│ ║ l.532: (if true) +//│ ║ l.527: (if true) //│ ╙── ^^ //│ Parsed: {'(' if (true) then undefined ')'} @@ -543,7 +538,7 @@ if true (if true then) //│ |(|#if| |true| |#then|)| //│ ╔══[PARSE ERROR] Unexpected end of parenthesis section; an expression was expected here -//│ ║ l.543: (if true then) +//│ ║ l.538: (if true then) //│ ╙── ^ //│ Parsed: {'(' if (true) then undefined ')'} @@ -559,7 +554,7 @@ if true then; if true then; else; //│ |#if| |true| |#then|;| |#else|;| //│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause -//│ ║ l.559: if true then; else; +//│ ║ l.554: if true then; else; //│ ╙── ^^^^^ //│ Parsed: {if (true) then undefined; undefined} From 05752ff3bf5f3d482d47e9dc0140a2b5b813a249 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 12 Jan 2024 16:22:39 +0800 Subject: [PATCH 498/498] Improve self-type handling (#206) * Fix self-type-blindness * Make ctor signatures produce typerefs * Add explicit variance annotations (variance analysis needs to be overhauled) * Warn when annotating concrete classes * Handle transitively-inherited self-types properly * Fix generic modules (somewhat) * Fix transitively-inherited trait signatures * Fix SOF in type simplifier due to cyclic self-types --- .../scala/mlscript/ConstraintSolver.scala | 3 +- .../src/main/scala/mlscript/NuTypeDefs.scala | 82 ++++---- shared/src/main/scala/mlscript/TypeDefs.scala | 4 +- .../main/scala/mlscript/TypeSimplifier.scala | 4 +- .../main/scala/mlscript/TyperHelpers.scala | 19 +- .../diff/codegen/AuxiliaryConstructors.mls | 2 +- shared/src/test/diff/codegen/Mixin.mls | 6 +- shared/src/test/diff/codegen/NewMatching.mls | 2 +- shared/src/test/diff/codegen/NuClasses.mls | 2 +- .../test/diff/contys/ExplicitConstraints.mls | 10 +- .../test/diff/ecoop23/ExpressionProblem.mls | 26 ++- .../test/diff/ecoop23/PolymorphicVariants.mls | 80 +++----- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 2 +- .../test/diff/ecoop23/SimpleRegionDSL_raw.mls | 10 +- .../src/test/diff/fcp/NestedDataTypesGADT.mls | 2 +- .../src/test/diff/fcp/QML_exist_Classes.mls | 6 +- shared/src/test/diff/fcp/Vec.mls | 2 +- shared/src/test/diff/gadt/Exp1.mls | 17 +- shared/src/test/diff/gadt/Exp2.mls | 72 +++++-- shared/src/test/diff/gadt/ThisMatching.mls | 120 ++++++----- shared/src/test/diff/mlscript/BadInherit2.mls | 16 +- .../src/test/diff/mlscript/BadInherit2Co.mls | 4 +- shared/src/test/diff/mlscript/Mut.mls | 6 +- shared/src/test/diff/mlscript/MutArray.mls | 2 +- shared/src/test/diff/mlscript/ProvFlows.mls | 24 ++- shared/src/test/diff/mlscript/References.mls | 10 +- shared/src/test/diff/mlscript/Trans.mls | 4 +- shared/src/test/diff/mlscript/TypeClasses.mls | 10 +- shared/src/test/diff/mlscript/TypeRanges.mls | 32 +-- shared/src/test/diff/mlscript/Yuheng.mls | 2 +- shared/src/test/diff/nu/AuxCtors.mls | 2 +- shared/src/test/diff/nu/BadClassInherit.mls | 47 +++-- .../src/test/diff/nu/BadClassSignatures.mls | 187 ++++++++++++++++++ shared/src/test/diff/nu/BadClasses.mls | 2 +- shared/src/test/diff/nu/BasicMixins.mls | 43 ++-- shared/src/test/diff/nu/ClassSignatures.mls | 186 +++++++++++------ shared/src/test/diff/nu/DiamondInherit.mls | 17 +- shared/src/test/diff/nu/EqlClasses.mls | 6 +- shared/src/test/diff/nu/Eval.mls | 89 ++++++--- shared/src/test/diff/nu/EvalNegNeg.mls | 6 +- shared/src/test/diff/nu/ExplicitVariance.mls | 4 +- .../test/diff/nu/ExpressionProblem_repro.mls | 24 ++- .../test/diff/nu/ExpressionProblem_small.mls | 14 +- shared/src/test/diff/nu/GADTMono.mls | 2 +- .../test/diff/nu/GenericClassInheritance.mls | 39 +++- shared/src/test/diff/nu/GenericClasses.mls | 10 +- shared/src/test/diff/nu/GenericMixins.mls | 2 +- shared/src/test/diff/nu/GenericModules.mls | 149 +++++++------- shared/src/test/diff/nu/HeungTung.mls | 12 +- shared/src/test/diff/nu/Huawei1.mls | 12 +- .../diff/nu/InferredInheritanceTypeArgs.mls | 4 +- shared/src/test/diff/nu/InterfaceGeneric.mls | 4 +- shared/src/test/diff/nu/InterfaceMono.mls | 4 +- shared/src/test/diff/nu/Interfaces.mls | 140 ++++++++----- shared/src/test/diff/nu/Jonathan.mls | 4 +- .../src/test/diff/nu/MemberIntersections.mls | 2 +- shared/src/test/diff/nu/Metaprog.mls | 2 +- shared/src/test/diff/nu/MethodSignatures.mls | 2 +- shared/src/test/diff/nu/MissingTypeArg.mls | 10 +- shared/src/test/diff/nu/NewNew.mls | 2 +- shared/src/test/diff/nu/Numbers.mls | 2 +- shared/src/test/diff/nu/ParamImplementing.mls | 2 +- .../test/diff/nu/PolymorphicVariants_Alt.mls | 8 +- .../test/diff/nu/RawUnionTraitSignatures.mls | 99 +++++++++- shared/src/test/diff/nu/Refinements.mls | 30 +-- shared/src/test/diff/nu/TODO_Classes.mls | 10 +- shared/src/test/diff/nu/TraitSignatures.mls | 140 ++++++++++++- .../test/diff/nu/TrickyGenericInheritance.mls | 2 +- shared/src/test/diff/nu/repro0.mls | 4 +- shared/src/test/diff/nu/repro_EvalNegNeg.mls | 19 +- shared/src/test/diff/tapl/NuSimplyTyped.mls | 4 +- shared/src/test/diff/tapl/NuUntyped.mls | 4 +- shared/src/test/diff/ucs/Hygiene.mls | 6 +- shared/src/test/diff/ucs/JSON.mls | 12 +- shared/src/test/diff/ucs/NestedBranches.mls | 109 +++++----- shared/src/test/diff/ucs/NestedOpSplits.mls | 2 +- shared/src/test/diff/ucs/Tree.mls | 14 +- 77 files changed, 1362 insertions(+), 713 deletions(-) create mode 100644 shared/src/test/diff/nu/BadClassSignatures.mls diff --git a/shared/src/main/scala/mlscript/ConstraintSolver.scala b/shared/src/main/scala/mlscript/ConstraintSolver.scala index e509a48579..9e223b3e09 100644 --- a/shared/src/main/scala/mlscript/ConstraintSolver.scala +++ b/shared/src/main/scala/mlscript/ConstraintSolver.scala @@ -950,7 +950,8 @@ class ConstraintSolver extends NormalForms { self: Typer => } } } else { - (tr1.mkClsTag, tr2.mkClsTag) match { + if (tr1.mayHaveTransitiveSelfType) rec(tr1.expand, tr2.expand, true) + else (tr1.mkClsTag, tr2.mkClsTag) match { case (S(tag1), S(tag2)) if !(tag1 <:< tag2) => reportError() case _ => diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index a580394ecd..08e82484d1 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -471,9 +471,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => (implicit raise: Raise) : ST = if ((td.kind is Mod) && params.isEmpty) - ClassTag(Var(td.nme.name), - ihtags + TN("Object") - )(provTODO) + if (tparams.isEmpty) + TypeRef(td.nme, Nil)(provTODO) + else PolymorphicType.mk(level, + TypeRef(td.nme, tparams.map(_._2))(provTODO)) else if ((td.kind is Cls) || (td.kind is Mod)) { if (td.kind is Mod) err(msg"Parameterized modules are not yet supported", loco) @@ -492,17 +493,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => PolymorphicType.mk(level, FunctionType( TupleType(ps.mapKeys(some))(provTODO), - ClassTag(Var(td.nme.name), - ihtags + TN("Object") - )(provTODO) & RecordType.mk( - // * ^ Note: we used to include the self type here (& selfTy), - // * but it doesn't seem to be needed – if the class has a constructor, - // * then surely it satisfies the self type (once we check it). - tparams.map { case (tn, tv, vi) => - // TODO also use computed variance info when available! - Var(td.nme.name + "#" + tn.name).withLocOf(tn) -> - FieldType.mk(vi.getOrElse(VarianceInfo.in), tv, tv)(provTODO) } - )(provTODO) + TypeRef(td.nme, tparams.map(_._2))(provTODO) )(provTODO) ) } else errType // FIXME @@ -1346,7 +1337,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"Explicit ${td.kind.str} constructors are not supported", td.ctor.fold[Opt[Loc]](N)(c => c.toLoc)) - // * To type signatures correctly, we need to deal with type unbound variables 'X, + // * To type signatures correctly, we need to deal with unbound type variables 'X, // * which should be treated as unknowns (extruded skolems). // * Allowing such type variables is important for the typing of signatures such as // * `: Foo | Bar` where `Foo` and `Bar` take type parameters, @@ -1375,7 +1366,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // * Note that there should be only one, and in particular it should not be recursive, // * since the variable is never shared outside this scope. res.lowerBounds match { - case lb :: Nil => TypeBounds.mk(TopType, lb) + // case lb :: Nil => TypeBounds.mk(TopType, lb) + case lb :: Nil => lb case _ => die } } @@ -1393,25 +1385,26 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) ctx += "this" -> VarSymbol(thisTV, Var("this")) - val sig_ty = td.sig.fold(TopType: ST)(typeTypeSignature) - - def inherit(parents: Ls[TypedParentSpec], tags: ST, members: Ls[NuMember], tparamMembs: Map[Str, NuMember]) - : (ST, Ls[NuMember], Map[Str, NuMember]) = + def inherit(parents: Ls[TypedParentSpec], tags: ST, members: Ls[NuMember], + tparamMembs: Map[Str, NuMember], sig_ty: ST) + : (ST, Ls[NuMember], Map[Str, NuMember], ST) = parents match { case (trt: TypedNuTrt, argMembs, tpms, loc) :: ps => assert(argMembs.isEmpty, argMembs) inherit(ps, tags & trt.sign, membersInter(members, trt.members.values.toList), - tparamMembs ++ tpms // with type members of parent class + tparamMembs ++ tpms, // with type members of parent class + sig_ty & trt.sign, ) case (_, _, _, loc) :: ps => err(msg"A trait can only inherit from other traits", loc) - inherit(ps, tags, members, tparamMembs) - case Nil => (tags, members, tparamMembs) + inherit(ps, tags, members, tparamMembs, sig_ty) + case Nil => (tags, members, tparamMembs, sig_ty) } - val (tags, trtMembers, tparamMembs) = - inherit(typedParents, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty) + val (tags, trtMembers, tparamMembs, sig_ty) = + inherit(typedParents, trtNameToNomTag(td)(noProv, ctx), Nil, Map.empty, + td.sig.fold(TopType: ST)(typeTypeSignature)) td.body.entities.foreach { case fd @ NuFunDef(_, _, _, _, L(_)) => @@ -1465,6 +1458,14 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => err(msg"${td.kind.str.capitalize} parameters are not supported", typedParams.fold(td.nme.toLoc)(tp => Loc(tp.iterator.map(_._1)))) + if (!td.isAbstract && !td.isDecl) td.sig match { + case S(sig) => warn( + msg"Self-type annotations have no effects on non-abstract ${td.kind.str} definitions" -> sig.toLoc + :: msg"Did you mean to use `extends` and inherit from a parent class?" -> N + :: Nil) + case N => + } + ctx ++= paramSymbols ctx ++= typedSignatures.map(nt => nt._1.name -> VarSymbol(nt._2, nt._1.nme)) @@ -1489,7 +1490,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => baseClsNme: Opt[Str], baseClsMembers: Ls[NuMember], traitMembers: Ls[NuMember], - tparamMembers: Map[Str, NuMember] + tparamMembers: Map[Str, NuMember], + selfSig: ST, ) def inherit(parents: Ls[TypedParentSpec], pack: Pack): Pack = parents match { @@ -1535,7 +1537,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => inherit(ps, pack.copy( traitMembers = membersInter(pack.traitMembers, trt.members.valuesIterator.filterNot(_.isValueParam).toList), - tparamMembers = pack.tparamMembers ++ tpms + tparamMembers = pack.tparamMembers ++ tpms, + selfSig = pack.selfSig & trt.sign )) case cls: TypedNuCls => @@ -1552,6 +1555,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => println(s"argMembs $argMembs") + println(s"selfSig ${cls.sign}") + inherit(ps, pack.copy( baseClsNme = S(parNme), // baseClsMembers = argMembs ++ cls.members.valuesIterator.filterNot(_.isValueParam), @@ -1559,7 +1564,8 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => // baseClsMembers = cls.members.valuesIterator.filter(_.isValueParam) ++ argMembs ++ cls.members.valuesIterator.filterNot(_.isValueParam), // baseClsMembers = baseParamMems ::: argMembs ::: otherBaseMems, baseClsMembers = argMembs ++ cls.members.valuesIterator, - tparamMembers = pack.tparamMembers ++ tpms + tparamMembers = pack.tparamMembers ++ tpms, + selfSig = pack.selfSig & cls.sign )) case als: TypedNuAls => // Should be rejected in `typedParents` @@ -1573,16 +1579,20 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => RecordType(typedParams.getOrElse(Nil))(ttp(td.params.getOrElse(Tup(Nil)), isType = true)) )(provTODO) & clsNameToNomTag(td)(provTODO, ctx) & - RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) & - sig_ty + RecordType(tparamFields)(TypeProvenance(Loc(td.tparams.map(_._2)), "type parameters", isType = true)) trace(s"${lvl}. Finalizing inheritance with $thisType <: $finalType") { assert(finalType.level === lvl) - constrain(thisType, finalType) + constrain(thisType & sig_ty, finalType) + + }() + + if (!td.isAbstract) trace(s"Checking self signature...") { + constrain(thisType, pack.selfSig) }() // println(s"${lvl}. Finalized inheritance with $superType ~> $thisType") - pack.copy(superType = thisType) + pack.copy(superType = thisType, selfSig = pack.selfSig & sig_ty) } // * We start from an empty super type. @@ -1592,8 +1602,10 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => val paramMems = typedParams.getOrElse(Nil).map(f => NuParam(f._1, f._2, isPublic = !privateParams.contains(f._1))(lvl)) - val Pack(thisType, mxnMembers, _, baseClsMembers, traitMembers, tparamMembers) = - inherit(typedParents, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty)) + val Pack(thisType, mxnMembers, _, baseClsMembers, traitMembers, tparamMembers, selfSig) = + inherit(typedParents, Pack(baseType, tparamMems ++ paramMems, N, Nil, Nil, Map.empty, sig_ty)) + + // println(s"Final self-type: ${selfSig}") ctx += "this" -> VarSymbol(thisTV, Var("this")) ctx += "super" -> VarSymbol(thisType, Var("super")) @@ -1728,7 +1740,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => typedParams.isEmpty && (td.kind is Cls) && !td.isAbstract)(Nil)), allMembers, TopType, - sig_ty, + if (td.isAbstract) selfSig else sig_ty, inheritedTags, tparamMembers ).tap(_.variances) // * Force variance computation diff --git a/shared/src/main/scala/mlscript/TypeDefs.scala b/shared/src/main/scala/mlscript/TypeDefs.scala index 16f827b742..a33177486b 100644 --- a/shared/src/main/scala/mlscript/TypeDefs.scala +++ b/shared/src/main/scala/mlscript/TypeDefs.scala @@ -158,7 +158,7 @@ class TypeDefs extends NuTypeDefs { Typer: Typer => { ty match { case tr @ TypeRef(td, targs) => - fieldsOf(tr.expandWith(paramTags), paramTags) + fieldsOf(tr.expandWith(paramTags, selfTy = false), paramTags) case ComposedType(false, l, r) => mergeMap(fieldsOf(l, paramTags), fieldsOf(r, paramTags))(_ && _) case RecordType(fs) => fs.toMap @@ -384,7 +384,7 @@ class TypeDefs extends NuTypeDefs { Typer: Typer => } def checkRegular(ty: SimpleType)(implicit reached: Map[Str, Ls[SimpleType]]): Bool = ty match { case tr @ TypeRef(defn, targs) => reached.get(defn.name) match { - case None => checkRegular(tr.expandWith(false))(reached + (defn.name -> targs)) + case None => checkRegular(tr.expandWith(false, selfTy = false))(reached + (defn.name -> targs)) case Some(tys) => // Note: this check *has* to be relatively syntactic because // the termination of constraint solving relies on recursive type occurrences diff --git a/shared/src/main/scala/mlscript/TypeSimplifier.scala b/shared/src/main/scala/mlscript/TypeSimplifier.scala index f2a4b297bf..6f821ceda6 100644 --- a/shared/src/main/scala/mlscript/TypeSimplifier.scala +++ b/shared/src/main/scala/mlscript/TypeSimplifier.scala @@ -287,7 +287,7 @@ trait TypeSimplifier { self: Typer => })(noProv) println(s"typeRef ${typeRef}") - val clsFields = fieldsOf(typeRef.expandWith(paramTags = true), paramTags = true) + val clsFields = fieldsOf(typeRef.expandWith(paramTags = true, selfTy = false), paramTags = true) println(s"clsFields ${clsFields.mkString(", ")}") val cleanPrefixes = ps.map(_.name.capitalize) + clsNme ++ traitPrefixes @@ -373,7 +373,7 @@ trait TypeSimplifier { self: Typer => })(noProv) println(s"typeRef ${typeRef}") - val clsFields = fieldsOf(typeRef.expandWith(paramTags = true), paramTags = true) + val clsFields = fieldsOf(typeRef.expandWith(paramTags = true, selfTy = false), paramTags = true) println(s"clsFields ${clsFields.mkString(", ")}") val cleanPrefixes = ps.map(_.name.capitalize) + clsNme ++ traitPrefixes diff --git a/shared/src/main/scala/mlscript/TyperHelpers.scala b/shared/src/main/scala/mlscript/TyperHelpers.scala index 727b0001c7..07b14736a8 100644 --- a/shared/src/main/scala/mlscript/TyperHelpers.scala +++ b/shared/src/main/scala/mlscript/TyperHelpers.scala @@ -1080,13 +1080,13 @@ abstract class TyperHelpers { Typer: Typer => } case N => } - expandWith(paramTags = true) + expandWith(paramTags = true, selfTy = true) } def expandOrCrash(implicit ctx: Ctx): SimpleType = { require(canExpand) - expandWith(paramTags = true) + expandWith(paramTags = true, selfTy = true) } - def expandWith(paramTags: Bool)(implicit ctx: Ctx): SimpleType = + def expandWith(paramTags: Bool, selfTy: Bool)(implicit ctx: Ctx): SimpleType = ctx.tyDefs2.get(defn.name).map { info => lazy val mkTparamRcd = RecordType(info.tparams.lazyZip(targs).map { case ((tn, tv, vi), ta) => @@ -1104,7 +1104,7 @@ abstract class TyperHelpers { Typer: Typer => assert(td.tparams.size === targs.size) // println(s"EXP ${td.sign}") val (freshenMap, _) = refreshHelper2(td, Var(td.name).withLoc(prov.loco), S(targs)) // infer ty args if not provided - val freshSelf = { + val freshSelf = if (!selfTy) TopType else { implicit val freshened: MutMap[TV, ST] = freshenMap implicit val shadows: Shadows = Shadows.empty td.sign.freshenAbove(td.level, rigidify = false) @@ -1116,7 +1116,7 @@ abstract class TyperHelpers { Typer: Typer => case S(td: TypedNuCls) => assert(td.tparams.size === targs.size) val (freshenMap, _) = refreshHelper2(td, Var(td.name).withLoc(prov.loco), S(targs)) // infer ty args if not provided - val freshSelf = { + val freshSelf = if (!selfTy) TopType else { implicit val freshened: MutMap[TV, ST] = freshenMap implicit val shadows: Shadows = Shadows.empty td.sign.freshenAbove(td.level, rigidify = false) @@ -1165,6 +1165,15 @@ abstract class TyperHelpers { Typer: Typer => } //tap { res => println(s"Expand $this => $res") } private var tag: Opt[Opt[ClassTag]] = N def expansionFallback(implicit ctx: Ctx): Opt[ST] = mkClsTag + /** Note: self types can be inherited from parents if the definition is abstract + * (if it is not abstract, then the class is already known to subtype the inherited self-type) */ + def mayHaveTransitiveSelfType(implicit ctx: Ctx): Bool = ctx.tyDefs2.get(defn.name) match { + case S(lti) => lti.decl match { + case td: NuTypeDef if !td.isAbstract => td.sig.nonEmpty + case _ => true + } + case _ => true + } def mkClsTag(implicit ctx: Ctx): Opt[ClassTag] = tag.getOrElse { val res = ctx.tyDefs.get(defn.name) match { case S(td: TypeDef) if (td.kind is Cls) || (td.kind is Mod) => diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls index 3fd393ed25..36b8a2c8fc 100644 --- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls +++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls @@ -562,7 +562,7 @@ class QQ(qq: Str) { //│ ║ ^^^^^^^^^^^^ //│ ║ l.548: } //│ ║ ^^^ -//│ ╟── type `Int` is not an instance of `Str` +//│ ╟── type `Int` is not an instance of type `Str` //│ ║ l.545: constructor(foo: Int) { //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `Str` diff --git a/shared/src/test/diff/codegen/Mixin.mls b/shared/src/test/diff/codegen/Mixin.mls index 3e28fb8da9..8e60a28e3f 100644 --- a/shared/src/test/diff/codegen/Mixin.mls +++ b/shared/src/test/diff/codegen/Mixin.mls @@ -2,7 +2,7 @@ :NewDefs :js -class Add(lhs: E, rhs: E) +class Add(lhs: E, rhs: E) class Lit(n: Int) //│ class Add[E](lhs: E, rhs: E) //│ class Lit(n: Int) @@ -103,7 +103,7 @@ mixin EvalBase { //│ // End of generated code :js -class Neg(expr: A) +class Neg(expr: A) //│ class Neg[A](expr: A) //│ // Prelude //│ class TypingUnit2 { @@ -208,7 +208,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ fun eval: (Neg['A] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'A <: 'b & (Neg['b] | Object & ~#Neg) //│ 'b <: Neg['A] | Object & 'a & ~#Neg //│ 'a <: Add['b] | Lit | Neg['b] //│ // Prelude diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls index 50d2dbc1da..809dcb337d 100644 --- a/shared/src/test/diff/codegen/NewMatching.mls +++ b/shared/src/test/diff/codegen/NewMatching.mls @@ -88,7 +88,7 @@ sum(42) //│ res //│ = -1 -class Some[T](val value: T) +class Some[out T](val value: T) //│ class Some[T](value: T) :js diff --git a/shared/src/test/diff/codegen/NuClasses.mls b/shared/src/test/diff/codegen/NuClasses.mls index a3f97c69fd..846c5be0cc 100644 --- a/shared/src/test/diff/codegen/NuClasses.mls +++ b/shared/src/test/diff/codegen/NuClasses.mls @@ -65,7 +65,7 @@ Test2(0).inc.n //│ res //│ = 1 -class C[A](n: A) { +class C[out A](n: A) { fun f = g fun g = n } diff --git a/shared/src/test/diff/contys/ExplicitConstraints.mls b/shared/src/test/diff/contys/ExplicitConstraints.mls index 728a2f9fd0..8b3c40ec42 100644 --- a/shared/src/test/diff/contys/ExplicitConstraints.mls +++ b/shared/src/test/diff/contys/ExplicitConstraints.mls @@ -12,7 +12,7 @@ fun f: int => int where int : string //│ ╔══[ERROR] Type mismatch in constraint specifiation: //│ ║ l.11: fun f: int => int where int : string //│ ║ ^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.11: fun f: int => int where int : string //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -25,7 +25,7 @@ fun f: int => (int where int : string) //│ ╔══[ERROR] Type mismatch in constraint specifiation: //│ ║ l.24: fun f: int => (int where int : string) //│ ║ ^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.24: fun f: int => (int where int : string) //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -42,7 +42,7 @@ fun f: 'a => ('a where 'a : string) where int : 'a //│ ╔══[ERROR] Type mismatch in constraint specifiation: //│ ║ l.41: fun f: 'a => ('a where 'a : string) where int : 'a //│ ║ ^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.41: fun f: 'a => ('a where 'a : string) where int : 'a //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -61,7 +61,7 @@ fun f: 'a => 'a where //│ ╔══[ERROR] Type mismatch in constraint specifiation: //│ ║ l.60: int : 'a //│ ║ ^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.60: int : 'a //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -81,7 +81,7 @@ fun f: 'a => forall 'b: 'a where //│ ╔══[ERROR] Type mismatch in constraint specifiation: //│ ║ l.80: int : 'a //│ ║ ^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.80: int : 'a //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/ecoop23/ExpressionProblem.mls b/shared/src/test/diff/ecoop23/ExpressionProblem.mls index 88115a08ff..7745355af2 100644 --- a/shared/src/test/diff/ecoop23/ExpressionProblem.mls +++ b/shared/src/test/diff/ecoop23/ExpressionProblem.mls @@ -4,7 +4,7 @@ // * Motivating paper example, demonstrating the expression problem solution -class Add(lhs: E, rhs: E) +class Add(lhs: E, rhs: E) class Lit(n: Int) //│ class Add[E](lhs: E, rhs: E) //│ class Lit(n: Int) @@ -36,13 +36,13 @@ mixin EvalBase { module TestLang extends EvalBase //│ module TestLang { -//│ fun eval: (Add['a] | Lit) -> Int +//│ fun eval: 'a -> Int //│ } //│ where //│ 'a <: Add['a] | Lit TestLang.eval -//│ (Add['a] | Lit) -> Int +//│ 'a -> Int //│ where //│ 'a <: Add['a] | Lit //│ res @@ -74,13 +74,13 @@ module TestLang extends EvalNothing, EvalAddLit //│ fun eval: (Add['c] | Lit | Object & 'a & ~#Add & ~#Lit) -> (Int | 'b) //│ } //│ module TestLang { -//│ fun eval: (Add['d] | Lit) -> Int +//│ fun eval: 'd -> Int //│ } //│ where //│ 'd <: Add['d] | Lit TestLang.eval -//│ (Add['a] | Lit) -> Int +//│ 'a -> Int //│ where //│ 'a <: Add['a] | Lit //│ res @@ -92,7 +92,7 @@ TestLang.eval(add11) //│ = 3 -class Neg(expr: A) +class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) @@ -115,17 +115,15 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['a] | Object & 'b & ~#Neg) -> Int +//│ fun eval: 'a -> Int //│ } //│ where -//│ 'a <: Neg['a] | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit +//│ 'a <: Neg['a] | Object & (Add['a] | Lit) & ~#Neg TestLang.eval -//│ (Neg['a] | Object & 'b & ~#Neg) -> Int +//│ 'a -> Int //│ where -//│ 'a <: Neg['a] | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit +//│ 'a <: Neg['a] | Object & (Add['a] | Lit) & ~#Neg //│ res //│ = [Function: eval] @@ -195,7 +193,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ fun eval: (Neg['A] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'A <: 'b & (Neg['b] | Object & ~#Neg) //│ 'b <: Neg['A] | Object & 'a & ~#Neg //│ 'a <: Add['b] | Lit | Neg['b] @@ -210,7 +208,7 @@ fun mk(n) = if n is TestLang.eval //│ (Neg['A] | Object & 'a & ~#Neg) -> Int //│ where -//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'A <: 'b & (Neg['b] | Object & ~#Neg) //│ 'b <: Neg['A] | Object & 'a & ~#Neg //│ 'a <: Add['b] | Lit | Neg['b] //│ res diff --git a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls index dc46b03530..a92b52ca08 100644 --- a/shared/src/test/diff/ecoop23/PolymorphicVariants.mls +++ b/shared/src/test/diff/ecoop23/PolymorphicVariants.mls @@ -43,8 +43,8 @@ mixin EvalVar { //│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, Var) -> (Var | 'a) //│ } -class Abs[A](x: Str, t: A) -class App[A](s: A, t: A) +class Abs[out A](x: Str, t: A) +class App[out A](s: A, t: A) //│ class Abs[A](x: Str, t: A) //│ class App[A](s: A, t: A) @@ -73,61 +73,50 @@ mixin EvalLambda { //│ mixin EvalLambda() { //│ super: {eval: ('a, 'b) -> 'c} //│ this: { -//│ eval: ('a, 'd) -> ('A & 'e) & (Cons[[Str, 'e]], 'f) -> 'c & (Cons[[Str, Var] | 'A0], 'g) -> 'A1 +//│ eval: ('a, 'd) -> 'A & (Cons[[Str, 'A]], 'e) -> 'c & (Cons[[Str, Var] | 'A0], 'f) -> 'A1 //│ } -//│ fun eval: ('a & (Cons['A0] | Nil), Abs['g] | App['d & (Abs['f] | Object & ~#Abs)] | Object & 'b & ~#Abs & ~#App) -> (Abs['A1] | App['A] | 'c) +//│ fun eval: ('a & (Cons['A0] | Nil), Abs['f] | App['d & (Abs['e] | Object & ~#Abs)] | Object & 'b & ~#Abs & ~#App) -> (Abs['A1] | App['A] | 'c) //│ } module Test1 extends EvalVar, EvalLambda //│ module Test1 { -//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, Abs['b] | App['c] | Var) -> 'a +//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, 'b) -> 'a //│ } //│ where -//│ 'b <: Abs['b] | App['c] | Var -//│ 'c <: 'b & (Abs['b] | Object & ~#Abs) -//│ 'a :> Var | App['A] | Abs['A0] -//│ 'A0 :> 'a -//│ 'A :> 'a +//│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Var +//│ 'a :> Var | App['a] | Abs['a] Test1.eval(Nil, Var("a")) //│ 'a //│ where -//│ 'a :> App['A] | Abs['A0] | Var -//│ 'A0 :> 'a -//│ 'A :> 'a +//│ 'a :> App['a] | Abs['a] | Var //│ res //│ = Var {} Test1.eval(Nil, Abs("b", Var("a"))) //│ 'a //│ where -//│ 'a :> Var | App['A] | Abs['A0] -//│ 'A0 :> 'a -//│ 'A :> 'a +//│ 'a :> App['a] | Abs['a] | Var //│ res //│ = Abs {} Test1.eval(Cons(["c", Var("d")], Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> App['A] | Abs['A0] | Var -//│ 'A0 :> 'a -//│ 'A :> 'a +//│ 'a :> App['a] | Abs['a] | Var //│ res //│ = Var {} Test1.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("b", Var("b")), Var("c"))) //│ 'a //│ where -//│ 'a :> App['A] | Abs['A0] | Abs[Var] | Var -//│ 'A0 :> 'a -//│ 'A :> 'a +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Var //│ res //│ = Abs {} class Numb(n: Int) -class Add[A](l: A, r: A) -class Mul[A](l: A, r: A) +class Add[out A](l: A, r: A) +class Mul[out A](l: A, r: A) //│ class Numb(n: Int) //│ class Add[A](l: A, r: A) //│ class Mul[A](l: A, r: A) @@ -138,7 +127,7 @@ fun map_expr(f, v) = Numb then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'a 'A 'b 'A0. ('a -> 'A & 'b -> 'A0, Add['a] | Mul['b] | Numb | Var) -> (Add['A] | Mul['A0] | Numb | Var) +//│ fun map_expr: forall 'a 'A 'b 'A0. ('b -> 'A0 & 'a -> 'A, Add['b] | Mul['a] | Numb | Var) -> (Add['A0] | Mul['A] | Numb | Var) mixin EvalExpr { fun eval(sub, v) = @@ -182,16 +171,16 @@ Test2.eval(Cons(["a", Numb(1)], Nil), Var("a")) :e Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.183: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.172: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.183: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.172: Test2.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.136: if v is +//│ ║ l.125: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.146: let vv = map_expr(eta, v) +//│ ║ l.135: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | Numb | Var | error //│ res @@ -205,66 +194,59 @@ Test2.eval(Cons(["a", Abs("d", Var("d"))], Nil), Add(Numb(1), Var("a"))) module Test3 extends EvalVar, EvalExpr, EvalLambda //│ module Test3 { -//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, Abs['b] | App['c] | Object & 'd & ~#Abs & ~#App) -> 'e +//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, 'b) -> 'c //│ } //│ where -//│ 'a :> 'e +//│ 'a :> 'c //│ <: Object -//│ 'e :> App['A] | Abs['A0] | Numb | Var | 'a | 'd +//│ 'c :> App['c] | Abs['c] | 'a | 'd //│ 'd <: Add['b] | Mul['b] | Numb | Var -//│ 'b <: Abs['b] | App['c] | Object & 'd & ~#Abs & ~#App -//│ 'c <: 'b & (Abs['b] | Object & ~#Abs) -//│ 'A0 :> 'e -//│ 'A :> 'e +//│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Object & 'd & ~#Abs & ~#App Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ 'a //│ where -//│ 'a :> App['A] | Abs['A0] | Abs[Var] | Numb | Var -//│ 'A0 :> 'a -//│ 'A :> 'a +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Numb | Var //│ res //│ = Abs {} Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), App(Abs("a", Var("a")), Add(Numb(1), Var("c")))) //│ 'a //│ where -//│ 'a :> App['A] | Abs['A0] | Abs[Var] | Add[Numb | Var] | Numb | Var -//│ 'A0 :> 'a -//│ 'A :> 'a +//│ 'a :> App['a] | Abs['a] | Abs[Var] | Add[Numb | Var] | Numb | Var //│ res //│ = Add {} // * Incorrect version, for regression testing – EvalLambda should be mixed in after EvalExpr module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) +//│ fun eval: (Cons[{0: anything, 1: 'a}] | Nil, 'a & (Add['b] | Mul['b] | Numb | Var)) -> (Numb | 'a | 'b | 'c) //│ } //│ where //│ 'a :> 'c | 'b //│ <: Object //│ 'b <: Add['b] | Mul['b] | Numb | Var -//│ 'c :> Abs[Numb | 'a | 'c] | App[Numb | 'a | 'c] | Numb | Var | 'a +//│ 'c :> Abs['a | 'c] | App['a | 'c] | 'a // * Because EvalExpr does not dispatch lambdas to super and map_expr only // * handles exprs :e Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.252: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.234: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── application of type `Abs[?A]` does not match type `Add[?A0] | Mul[?A1] | Numb | Var` -//│ ║ l.252: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) +//│ ║ l.234: Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil), Abs("a", Var("a"))) //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.136: if v is +//│ ║ l.125: if v is //│ ║ ^ //│ ╟── from reference: -//│ ║ l.146: let vv = map_expr(eta, v) +//│ ║ l.135: let vv = map_expr(eta, v) //│ ╙── ^ //│ Abs[Var] | error | 'a //│ where -//│ 'a :> Abs[Abs[Var] | Numb | 'a] | App[Abs[Var] | Numb | 'a] | Numb | Var +//│ 'a :> Abs['a] | App['a] | Numb | Var //│ res //│ Runtime error: //│ Error: non-exhaustive case expression diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index ae9192d9df..d2b54c6799 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -348,7 +348,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] +//│ 'a :> Outside['a] | Scale['a] | Union['a] | Intersect['a] | Translate['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls index 30bde46679..22b0dec18a 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_raw.mls @@ -303,19 +303,19 @@ module TestElim extends Eliminate //│ } //│ where //│ 'a <: Intersect['a] | Object & 'b & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['a & (Object & ~#Outside | Outside['a])] | Scale['a] | Translate['a] | Union['a] -//│ 'b :> Union['b] | Intersect['b] | Translate['b] | Scale['b] | Outside['b] +//│ 'b :> Outside['b] | Union['b] | Intersect['b] | Translate['b] | Scale['b] TestElim.eliminate(Outside(Outside(Univ()))) //│ 'a //│ where -//│ 'a :> Univ | Intersect['a] | Translate[Univ | 'a] | Scale[Univ | 'a] | Outside[Univ | 'a] | Union[Univ | 'a] +//│ 'a :> Univ | Union[Univ | 'a] | Intersect['a] | Translate[Univ | 'a] | Scale[Univ | 'a] | Outside[Univ | 'a] //│ res //│ = Univ {} TestElim.eliminate(circles) //│ 'a //│ where -//│ 'a :> Circle | Scale[Circle | 'a] | Outside[Circle | 'a] | Union[Circle | 'a] | Intersect['a] | Translate[Circle | 'a] +//│ 'a :> Circle | Translate[Circle | 'a] | Scale[Circle | 'a] | Outside[Circle | 'a] | Union[Circle | 'a] | Intersect['a] //│ res //│ = Union {} @@ -327,7 +327,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] +//│ 'a :> Outside['a] | Intersect['a] | Translate['a] | Scale['a] | Union['a] :re TestElim.eliminate(mk(100)) @@ -355,7 +355,7 @@ module Lang extends SizeBase, SizeExt, Contains, Text, IsUniv, IsEmpty, Eliminat //│ 'e <: Intersect['e] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['e] | Scale['e] | Translate['e] | Union['e] | Univ //│ 'd <: Intersect['d] | Object & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union & ~#Univ | Outside['d] | Scale['d] | Translate['d] | Union['d] | Univ //│ 'b <: Intersect['b] | Object & 'c & ~#Intersect & ~#Outside & ~#Scale & ~#Translate & ~#Union | Outside['b & (Object & ~#Outside | Outside['b])] | Scale['b] | Translate['b] | Union['b] -//│ 'c :> Scale['c] | Outside['c] | Union['c] | Intersect['c] | Translate['c] +//│ 'c :> Translate['c] | Scale['c] | Outside['c] | Union['c] | Intersect['c] //│ 'a <: Circle | Intersect['a] | Outside['a] | Translate['a] | Union['a] Lang.size(circles) diff --git a/shared/src/test/diff/fcp/NestedDataTypesGADT.mls b/shared/src/test/diff/fcp/NestedDataTypesGADT.mls index 3e49f0f67b..5c5e2f2b55 100644 --- a/shared/src/test/diff/fcp/NestedDataTypesGADT.mls +++ b/shared/src/test/diff/fcp/NestedDataTypesGADT.mls @@ -96,7 +96,7 @@ d2_ : HTree[S[Z], int] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.95: d2_ : HTree[S[Z], int] //│ ║ ^^^ -//│ ╟── expression of type `S[in Z & 'p out Z | 'p]` is not an instance of `Z` +//│ ╟── expression of type `S[in Z & 'p out Z | 'p]` is not an instance of type `Z` //│ ╟── Note: constraint arises from type reference: //│ ║ l.72: def d1_ty: HTree[Z, int] //│ ║ ^ diff --git a/shared/src/test/diff/fcp/QML_exist_Classes.mls b/shared/src/test/diff/fcp/QML_exist_Classes.mls index f550afb0f0..ab5031d83a 100644 --- a/shared/src/test/diff/fcp/QML_exist_Classes.mls +++ b/shared/src/test/diff/fcp/QML_exist_Classes.mls @@ -135,7 +135,7 @@ simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ = [Function: simpleStepImpl] //│ constrain calls : 9926 //│ annoying calls : 78 -//│ subtyping calls : 70336 +//│ subtyping calls : 70332 // * Note that the above incidentally can be checked using recursive types :RecursiveTypes :stats @@ -144,7 +144,7 @@ simpleStepImpl : ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string)] //│ = [Function: simpleStepImpl] //│ constrain calls : 579 //│ annoying calls : 104 -//│ subtyping calls : 5595 +//│ subtyping calls : 5591 :NoRecursiveTypes // * Apparently, it's due to excessive extrusion due to the type annot not being generalized! @@ -154,7 +154,7 @@ simpleStepImpl : forall 'a 'r. ArraysImpl['a, 'r] -> ArraysImpl['a, ('r, string) //│ = [Function: simpleStepImpl] //│ constrain calls : 711 //│ annoying calls : 104 -//│ subtyping calls : 1796 +//│ subtyping calls : 1792 diff --git a/shared/src/test/diff/fcp/Vec.mls b/shared/src/test/diff/fcp/Vec.mls index 51015a1797..d829caa12f 100644 --- a/shared/src/test/diff/fcp/Vec.mls +++ b/shared/src/test/diff/fcp/Vec.mls @@ -236,7 +236,7 @@ v1_tty = cons_ty2 1 nil_ty //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.235: v1_tty = cons_ty2 1 nil_ty //│ ║ ^^^^^^^^^^^^^^^^^ -//│ ╟── type `Z` is not an instance of `S['n & 'p]` +//│ ╟── type `Z` is not an instance of type `S` //│ ║ l.39: nil_ty = nil : Vec[int, Z] //│ ║ ^ //│ ╟── Note: constraint arises from applied type reference: diff --git a/shared/src/test/diff/gadt/Exp1.mls b/shared/src/test/diff/gadt/Exp1.mls index 93212b89ab..489ddea752 100644 --- a/shared/src/test/diff/gadt/Exp1.mls +++ b/shared/src/test/diff/gadt/Exp1.mls @@ -1,12 +1,10 @@ :NewDefs -class Exp[A]: Pair | Lit +abstract class Exp[A]: Pair | Lit class Lit(n: Int) extends Exp[Int] class Pair[L, R](val lhs: L, val rhs: R) extends Exp[[L, R]] -//│ class Exp[A]: Lit | Pair[anything, anything] { -//│ constructor() -//│ } +//│ abstract class Exp[A]: Lit | Pair[anything, anything] //│ class Lit(n: Int) extends Exp //│ class Pair[L, R](lhs: L, rhs: R) extends Exp @@ -36,7 +34,7 @@ fun f(e) = if e is fun f(e) = if e is Pair['a, 'b](l, r) then [l, r] //│ ╔══[ERROR] illegal pattern -//│ ║ l.37: Pair['a, 'b](l, r) then [l, r] +//│ ║ l.35: Pair['a, 'b](l, r) then [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^ //│ fun f: anything -> error //│ Code generation encountered an error: @@ -46,16 +44,13 @@ fun f(e) = if e is :e // TODO support fun f(e) = if e is Pair(l: a, r) then - fun f(x: a) = x + let f(x: a) = x f(l) -//│ ╔══[ERROR] Cannot use `val` or `fun` in local block; use `let` instead. -//│ ║ l.49: fun f(x: a) = x -//│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] type identifier not found: a -//│ ║ l.49: fun f(x: a) = x +//│ ║ l.47: let f(x: a) = x //│ ╙── ^ //│ ╔══[ERROR] identifier not found: l -//│ ║ l.50: f(l) +//│ ║ l.48: f(l) //│ ╙── ^ //│ fun f: Pair[anything, anything] -> error //│ Code generation encountered an error: diff --git a/shared/src/test/diff/gadt/Exp2.mls b/shared/src/test/diff/gadt/Exp2.mls index 55421697d5..45449541c3 100644 --- a/shared/src/test/diff/gadt/Exp2.mls +++ b/shared/src/test/diff/gadt/Exp2.mls @@ -1,12 +1,47 @@ :NewDefs -class Exp[A]: Pair | Lit + +// * Variant: + +abstract class Exp[out A]: Pair | Lit +class Lit(val n: Int) extends Exp[Int] +class Pair[out L, out R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] +//│ abstract class Exp[A]: Lit | Pair[anything, anything] +//│ class Lit(n: Int) extends Exp +//│ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp + + +fun f(p: Pair['a, 'b]) = p.lhs +//│ fun f: forall 'a. (p: Pair['a, anything]) -> Exp['a] + +fun f(e) = if e is + Pair(l, r) then [l, r] +//│ fun f: forall 'L 'R. Pair['L, 'R] -> [Exp['L], Exp['R]] +// f: (Exp['a] & Pair) -> 0 + +fun f(e) = if e is + Pair(l, r) then [l, r] + Lit(n) then n +//│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> (Int | [Exp['L], Exp['R]]) + +(e: Exp['X]) => f(e) +//│ (e: Exp[anything]) -> (Int | [Exp[??L], Exp[??R]]) +//│ res +//│ = [Function: res] + +fun f(e) = if e is + Pair(l, r) then f(l) + f(r) + Lit(n) then n +//│ fun f: (Lit | Pair[anything, anything]) -> Int + + +// * Invariant: + +abstract class Exp[A]: Pair | Lit class Lit(val n: Int) extends Exp[Int] class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] -//│ class Exp[A]: Lit | Pair[?, ?] { -//│ constructor() -//│ } +//│ abstract class Exp[A]: Lit | Pair[?, ?] //│ class Lit(n: Int) extends Exp //│ class Pair[L, R](lhs: Exp[L], rhs: Exp[R]) extends Exp @@ -14,13 +49,11 @@ class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] fun f(p: Pair['a, 'b]) = p.lhs //│ fun f: forall 'a 'b. (p: Pair['a, 'b]) -> Exp['a] - fun f(e) = if e is Pair(l, r) then [l, r] //│ fun f: forall 'L 'R. Pair['L, 'R] -> [Exp['L], Exp['R]] // f: (Exp['a] & Pair) -> 0 - fun f(e) = if e is Pair(l, r) then [l, r] Lit(n) then n @@ -29,11 +62,11 @@ fun f(e) = if e is :e (e: Exp['X]) => f(e) //│ ╔══[ERROR] Type error in application -//│ ║ l.30: (e: Exp['X]) => f(e) +//│ ║ l.63: (e: Exp['X]) => f(e) //│ ║ ^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] -//│ ╙── ^ +//│ ║ l.43: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] +//│ ╙── ^ //│ forall 'X 'L 'R. (e: Exp['X]) -> (Int | error | [Exp['L], Exp['R]]) //│ where //│ 'R :> ??R @@ -43,31 +76,30 @@ fun f(e) = if e is //│ res //│ = [Function: res] - :e fun f(e) = if e is Pair(l, r) then f(l) + f(r) Lit(n) then n //│ ╔══[ERROR] Type error in definition -//│ ║ l.48: fun f(e) = if e is +//│ ║ l.80: fun f(e) = if e is //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.49: Pair(l, r) then f(l) + f(r) +//│ ║ l.81: Pair(l, r) then f(l) + f(r) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.50: Lit(n) then n +//│ ║ l.82: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] -//│ ╙── ^ +//│ ║ l.43: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] +//│ ╙── ^ //│ ╔══[ERROR] Type error in definition -//│ ║ l.48: fun f(e) = if e is +//│ ║ l.80: fun f(e) = if e is //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.49: Pair(l, r) then f(l) + f(r) +//│ ║ l.81: Pair(l, r) then f(l) + f(r) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.50: Lit(n) then n +//│ ║ l.82: Lit(n) then n //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `R` leaks out of its scope -//│ ║ l.6: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] -//│ ╙── ^ +//│ ║ l.43: class Pair[L, R](val lhs: Exp[L], val rhs: Exp[R]) extends Exp[[L, R]] +//│ ╙── ^ //│ fun f: forall 'L 'R. (Lit | Pair['L, 'R]) -> Int //│ where //│ 'R :> ??R diff --git a/shared/src/test/diff/gadt/ThisMatching.mls b/shared/src/test/diff/gadt/ThisMatching.mls index e5d94d6926..cf63b32564 100644 --- a/shared/src/test/diff/gadt/ThisMatching.mls +++ b/shared/src/test/diff/gadt/ThisMatching.mls @@ -27,19 +27,18 @@ Dummy.introspect //│ = 'duh!' -class Funny: Int { fun test = this + 1 } -//│ class Funny: Int { -//│ constructor() +abstract class Funny: Int { fun test = this + 1 } +//│ abstract class Funny: Int { //│ fun test: Int //│ } :e class Unfunny { fun test = this + 1 } //│ ╔══[ERROR] Type mismatch in operator application: -//│ ║ l.37: class Unfunny { fun test = this + 1 } +//│ ║ l.36: class Unfunny { fun test = this + 1 } //│ ║ ^^^^^^^^ //│ ╟── reference of type `#Unfunny` is not an instance of type `Int` -//│ ║ l.37: class Unfunny { fun test = this + 1 } +//│ ║ l.36: class Unfunny { fun test = this + 1 } //│ ╙── ^^^^ //│ class Unfunny { //│ constructor() @@ -47,15 +46,14 @@ class Unfunny { fun test = this + 1 } //│ } -class Exp: (Pair | Lit) { +abstract class Exp: (Pair | Lit) { fun test = if this is Lit then 0 Pair then 1 } class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp -//│ class Exp: Lit | Pair { -//│ constructor() +//│ abstract class Exp: Lit | Pair { //│ fun test: 0 | 1 //│ } //│ class Lit(n: Int) extends Exp { @@ -66,14 +64,13 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp //│ } -class Exp: (() | Lit) { +abstract class Exp: (() | Lit) { fun test = if this is Lit then 0 () then 1 } class Lit(n: Int) extends Exp -//│ class Exp: Lit | () { -//│ constructor() +//│ abstract class Exp: Lit | () { //│ fun test: 0 | 1 //│ } //│ class Lit(n: Int) extends Exp { @@ -83,32 +80,31 @@ class Lit(n: Int) extends Exp // * TODO fix this by requiring a type annotation on `test` and delaying its body's type checking until all the involed classes are completed // * Currently we try to complete Exp ->{type checking defn body} complete test ->{type checking pattern} find Wrap's typed fields ->{get Wrap's typed parents} complete Exp :e -class Exp: (() | Wrap) { +abstract class Exp: (() | Wrap) { fun test = if this is Wrap(a) then 0 () then 1 } class Wrap(n: Exp) extends Exp //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.86: class Exp: (() | Wrap) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.87: fun test = if this is +//│ ║ l.83: abstract class Exp: (() | Wrap) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.84: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.88: Wrap(a) then 0 +//│ ║ l.85: Wrap(a) then 0 //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ║ l.89: () then 1 +//│ ║ l.86: () then 1 //│ ║ ^^^^^^^^^^^^^ -//│ ║ l.90: } +//│ ║ l.87: } //│ ╙── ^ -//│ class Exp: Wrap | () { -//│ constructor() +//│ abstract class Exp: Wrap | () { //│ fun test: 0 | 1 //│ } //│ class Wrap(n: Exp) extends Exp // * TODO (same as above) :e -class Exp: (Pair | Lit) { +abstract class Exp: (Pair | Lit) { fun test: Int fun test = if this is Lit then 0 @@ -117,20 +113,19 @@ class Exp: (Pair | Lit) { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.111: class Exp: (Pair | Lit) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.112: fun test: Int +//│ ║ l.107: abstract class Exp: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.108: fun test: Int //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.113: fun test = if this is +//│ ║ l.109: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.114: Lit then 0 +//│ ║ l.110: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.115: Pair(l, r) then 1 +//│ ║ l.111: Pair(l, r) then 1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.116: } +//│ ║ l.112: } //│ ╙── ^ -//│ class Exp: Lit | Pair { -//│ constructor() +//│ abstract class Exp: Lit | Pair { //│ fun test: Int //│ } //│ class Lit(n: Int) extends Exp { @@ -141,7 +136,7 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp :e // TODO Pair(Lit(1), Lit(2)).test //│ ╔══[ERROR] Type `Pair` does not contain member `test` -//│ ║ l.142: Pair(Lit(1), Lit(2)).test +//│ ║ l.137: Pair(Lit(1), Lit(2)).test //│ ╙── ^^^^^ //│ error //│ res @@ -149,7 +144,7 @@ Pair(Lit(1), Lit(2)).test :e // TODO can we support this? -class Exp: (Pair | Lit) { +abstract class Exp: (Pair | Lit) { fun test = if this is Lit then 0 Pair(l, r) then l.test + r.test @@ -157,21 +152,20 @@ class Exp: (Pair | Lit) { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.152: class Exp: (Pair | Lit) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.153: fun test = if this is +//│ ║ l.147: abstract class Exp: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.148: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.154: Lit then 0 +//│ ║ l.149: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.155: Pair(l, r) then l.test + r.test +//│ ║ l.150: Pair(l, r) then l.test + r.test //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.156: } +//│ ║ l.151: } //│ ╙── ^ //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.155: Pair(l, r) then l.test + r.test +//│ ║ l.150: Pair(l, r) then l.test + r.test //│ ╙── ^^^^^ -//│ class Exp: Lit | Pair { -//│ constructor() +//│ abstract class Exp: Lit | Pair { //│ fun test: Int | error //│ } //│ class Lit(n: Int) extends Exp { @@ -181,7 +175,7 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp :e // TODO -class Exp: (Pair | Lit) { +abstract class Exp: (Pair | Lit) { fun test : Int fun test = if this is Lit then 0 @@ -190,20 +184,19 @@ class Exp: (Pair | Lit) { class Lit(n: Int) extends Exp class Pair(lhs: Exp, rhs: Exp) extends Exp //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.184: class Exp: (Pair | Lit) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.185: fun test : Int +//│ ║ l.178: abstract class Exp: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.179: fun test : Int //│ ║ ^^^^^^^^^^^^^^^^ -//│ ║ l.186: fun test = if this is +//│ ║ l.180: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.187: Lit then 0 +//│ ║ l.181: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.188: Pair(l, r) then l.test + r.test +//│ ║ l.182: Pair(l, r) then l.test + r.test //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.189: } +//│ ║ l.183: } //│ ╙── ^ -//│ class Exp: Lit | Pair { -//│ constructor() +//│ abstract class Exp: Lit | Pair { //│ fun test: Int //│ } //│ class Lit(n: Int) extends Exp { @@ -213,7 +206,7 @@ class Pair(lhs: Exp, rhs: Exp) extends Exp :e // TODO support – this requires implementing type member lookup without forced completion (we get constraints like Pair <: Pair#L) -class Exp[A]: (Pair | Lit) { +abstract class Exp[A]: (Pair | Lit) { fun test = if this is Lit then 0 Pair then 1 @@ -221,28 +214,27 @@ class Exp[A]: (Pair | Lit) { class Lit(n: Int) extends Exp[Int] class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.216: class Exp[A]: (Pair | Lit) { -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.217: fun test = if this is +//│ ║ l.209: abstract class Exp[A]: (Pair | Lit) { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.210: fun test = if this is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.218: Lit then 0 +//│ ║ l.211: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.219: Pair then 1 +//│ ║ l.212: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.220: } +//│ ║ l.213: } //│ ╙── ^ //│ ╔══[ERROR] Type error in `case` expression -//│ ║ l.217: fun test = if this is +//│ ║ l.210: fun test = if this is //│ ║ ^^^^^^^ -//│ ║ l.218: Lit then 0 +//│ ║ l.211: Lit then 0 //│ ║ ^^^^^^^^^^^^^^ -//│ ║ l.219: Pair then 1 +//│ ║ l.212: Pair then 1 //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── type variable `L` leaks out of its scope -//│ ║ l.222: class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] +//│ ║ l.215: class Pair[L, R](lhs: L, rhs: R) extends Exp[[L, R]] //│ ╙── ^ -//│ class Exp[A]: Lit | Pair[anything, anything] { -//│ constructor() +//│ abstract class Exp[A]: Lit | Pair[anything, anything] { //│ fun test: 0 | 1 //│ } //│ class Lit(n: Int) extends Exp { diff --git a/shared/src/test/diff/mlscript/BadInherit2.mls b/shared/src/test/diff/mlscript/BadInherit2.mls index 6b5eec9b5c..09486a97ba 100644 --- a/shared/src/test/diff/mlscript/BadInherit2.mls +++ b/shared/src/test/diff/mlscript/BadInherit2.mls @@ -16,7 +16,7 @@ class A0: S0[int] & T0[string] //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.14: class A0: S0[int] & T0[string] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.14: class A0: S0[int] & T0[string] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -25,7 +25,7 @@ class A0: S0[int] & T0[string] //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.14: class A0: S0[int] & T0[string] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.14: class A0: S0[int] & T0[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -50,7 +50,7 @@ class A0_2: S0[int] & T0[string] //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.48: class A0_2: S0[int] & T0[string] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.48: class A0_2: S0[int] & T0[string] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -59,7 +59,7 @@ class A0_2: S0[int] & T0[string] //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.48: class A0_2: S0[int] & T0[string] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.48: class A0_2: S0[int] & T0[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -104,7 +104,7 @@ class A1: S1 & T1 //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.103: class A1: S1 & T1 //│ ║ ^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.93: trait S1: R1[int] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -113,7 +113,7 @@ class A1: S1 & T1 //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.103: class A1: S1 & T1 //│ ║ ^^^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.95: trait T1: R1[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -169,7 +169,7 @@ class A1_2: S1 & T1 //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.167: class A1_2: S1 & T1 //│ ║ ^^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.93: trait S1: R1[int] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -178,7 +178,7 @@ class A1_2: S1 & T1 //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.167: class A1_2: S1 & T1 //│ ║ ^^^^^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.95: trait T1: R1[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/mlscript/BadInherit2Co.mls b/shared/src/test/diff/mlscript/BadInherit2Co.mls index 8a2e3d8a81..bfa7be1f03 100644 --- a/shared/src/test/diff/mlscript/BadInherit2Co.mls +++ b/shared/src/test/diff/mlscript/BadInherit2Co.mls @@ -11,7 +11,7 @@ class A00: S00[int] & T00[string] //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.10: class A00: S00[int] & T00[string] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `string` +//│ ╟── type `int` is not an instance of type `string` //│ ║ l.10: class A00: S00[int] & T00[string] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -20,7 +20,7 @@ class A00: S00[int] & T00[string] //│ ╔══[ERROR] Type mismatch in type definition: //│ ║ l.10: class A00: S00[int] & T00[string] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.10: class A00: S00[int] & T00[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/mlscript/Mut.mls b/shared/src/test/diff/mlscript/Mut.mls index 7cbd3ed19a..be6748ff56 100644 --- a/shared/src/test/diff/mlscript/Mut.mls +++ b/shared/src/test/diff/mlscript/Mut.mls @@ -490,7 +490,7 @@ mt4[3] <- true //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.477: mt1[0] <- mt2.0 //│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `bool` +//│ ╟── type `int` is not an instance of type `bool` //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -502,7 +502,7 @@ mt4[3] <- true //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.477: mt1[0] <- mt2.0 //│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── type `int` is not an instance of `bool` +//│ ╟── type `int` is not an instance of type `bool` //│ ║ l.382: def mt2: (int, int) //│ ║ ^^^ //│ ╟── but it flows into field selection with expected type `bool` @@ -551,7 +551,7 @@ b1.x <- 1 + 2 <- 4 //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.546: mt1.0 <- mt1.1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `bool` is not an instance of `int` +//│ ╟── type `bool` is not an instance of type `int` //│ ║ l.381: def mt1: (mut int, mut bool) //│ ║ ^^^^ //│ ╟── but it flows into field selection with expected type `int` diff --git a/shared/src/test/diff/mlscript/MutArray.mls b/shared/src/test/diff/mlscript/MutArray.mls index d60246591f..e2775eb50e 100644 --- a/shared/src/test/diff/mlscript/MutArray.mls +++ b/shared/src/test/diff/mlscript/MutArray.mls @@ -97,7 +97,7 @@ def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.96: def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ║ ^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.96: def bar x = (mut x,) : MutArray[int] & MutArray[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/mlscript/ProvFlows.mls b/shared/src/test/diff/mlscript/ProvFlows.mls index f0a262c11c..d5409dee17 100644 --- a/shared/src/test/diff/mlscript/ProvFlows.mls +++ b/shared/src/test/diff/mlscript/ProvFlows.mls @@ -318,7 +318,7 @@ succ foo //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.317: succ foo //│ ║ ^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.313: def foo: int | string //│ ║ ^^^^^^ //│ ╟── but it flows into reference with expected type `int` @@ -331,6 +331,9 @@ succ foo //│ ╟── [info] flowing from type `string` //│ ║ l.313: def foo: int | string //│ ║ ^^^^^^ +//│ ╟── [info] flowing from type `string` +//│ ║ l.313: def foo: int | string +//│ ║ ^^^^^^ //│ ╟── [info] flowing from type `int | string` //│ ║ l.313: def foo: int | string //│ ║ ^^^^^^^^^^^^ @@ -339,6 +342,9 @@ succ foo //│ ║ ^^^ //│ ╟── [info] flowing into type `int` //│ ║ l.3: def succ: int -> int +//│ ║ ^^^ +//│ ╟── [info] flowing into type `int` +//│ ║ l.3: def succ: int -> int //│ ╙── ^^^ //│ res: error | int @@ -367,31 +373,31 @@ ty00 = ty11 //│ <: ty00: //│ (A & 'a | B & 'b) -> ('a, 'b,) //│ ╔══[ERROR] Type mismatch in def definition: -//│ ║ l.365: ty00 = ty11 +//│ ║ l.371: ty00 = ty11 //│ ║ ^^^^^^^^^^^ //│ ╟── type `B & 'b` does not match type `'a` -//│ ║ l.352: def ty00: ('a & A | 'b & B) -> ('a, 'b) +//│ ║ l.358: def ty00: ('a & A | 'b & B) -> ('a, 'b) //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type variable: -//│ ║ l.352: def ty00: ('a & A | 'b & B) -> ('a, 'b) +//│ ║ l.358: def ty00: ('a & A | 'b & B) -> ('a, 'b) //│ ║ ^^ //│ ╟── ========= Additional explanations below ========= //│ ╟── [info] flowing from expression of type `B & 'b` //│ ╟── [info] flowing from type `B & 'b` -//│ ║ l.352: def ty00: ('a & A | 'b & B) -> ('a, 'b) +//│ ║ l.358: def ty00: ('a & A | 'b & B) -> ('a, 'b) //│ ║ ^^^^^^ //│ ╟── [info] flowing from type `B & 'b` -//│ ║ l.352: def ty00: ('a & A | 'b & B) -> ('a, 'b) +//│ ║ l.358: def ty00: ('a & A | 'b & B) -> ('a, 'b) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── [info] flowing from type `B & 'b` -//│ ║ l.355: def ty11: ('a & A | 'a & B) -> ('a, 'a) +//│ ║ l.361: def ty11: ('a & A | 'a & B) -> ('a, 'a) //│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── [info] flowing from expression of type `'a0` //│ ╟── [info] flowing from type `'a1` -//│ ║ l.355: def ty11: ('a & A | 'a & B) -> ('a, 'a) +//│ ║ l.361: def ty11: ('a & A | 'a & B) -> ('a, 'a) //│ ║ ^^ //│ ╟── [info] flowing into type `'a` -//│ ║ l.352: def ty00: ('a & A | 'b & B) -> ('a, 'b) +//│ ║ l.358: def ty00: ('a & A | 'b & B) -> ('a, 'b) //│ ║ ^^ //│ ╙── [info] flowing into expression of type `'a` diff --git a/shared/src/test/diff/mlscript/References.mls b/shared/src/test/diff/mlscript/References.mls index a0614d1c9d..b99c802054 100644 --- a/shared/src/test/diff/mlscript/References.mls +++ b/shared/src/test/diff/mlscript/References.mls @@ -160,7 +160,7 @@ move ri rn //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.159: move ri rn //│ ║ ^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.87: rn = r : Ref[number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -214,7 +214,7 @@ swap ri rn //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.202: swap ri rn //│ ║ ^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.87: rn = r : Ref[number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -351,7 +351,7 @@ refun.Swap //│ ╔══[ERROR] Type mismatch in field selection: //│ ║ l.348: refun.Get //│ ║ ^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.339: def refun: Ref[int] | Ref[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -366,7 +366,7 @@ refun.Swap //│ ╔══[ERROR] Type mismatch in field selection: //│ ║ l.349: fun x -> refun.Set x //│ ║ ^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.339: def refun: Ref[int] | Ref[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -381,7 +381,7 @@ refun.Swap //│ ╔══[ERROR] Type mismatch in field selection: //│ ║ l.350: refun.Swap //│ ║ ^^^^^^^^^^ -//│ ╟── type `string` is not an instance of `int` +//│ ╟── type `string` is not an instance of type `int` //│ ║ l.339: def refun: Ref[int] | Ref[string] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/mlscript/Trans.mls b/shared/src/test/diff/mlscript/Trans.mls index 1169f29c68..22d552d8fa 100644 --- a/shared/src/test/diff/mlscript/Trans.mls +++ b/shared/src/test/diff/mlscript/Trans.mls @@ -34,7 +34,7 @@ a: B //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.33: a: B //│ ║ ^ -//│ ╟── type `A` is not an instance of `B` +//│ ╟── type `A` is not an instance of type `B` //│ ║ l.24: c: A //│ ║ ^ //│ ╟── but it flows into reference with expected type `B` @@ -51,7 +51,7 @@ a: C //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.50: a: C //│ ║ ^ -//│ ╟── type `A` is not an instance of `C` +//│ ╟── type `A` is not an instance of type `C` //│ ║ l.24: c: A //│ ║ ^ //│ ╟── but it flows into reference with expected type `C` diff --git a/shared/src/test/diff/mlscript/TypeClasses.mls b/shared/src/test/diff/mlscript/TypeClasses.mls index ae23c188f9..25bbd0c11e 100644 --- a/shared/src/test/diff/mlscript/TypeClasses.mls +++ b/shared/src/test/diff/mlscript/TypeClasses.mls @@ -257,23 +257,23 @@ class ComplexMonoid_bad_2[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ╔══[ERROR] Type mismatch in field selection: //│ ║ l.+5: Complex (this.base.Add self.real that.real) (this.base.Add self.imaginary that.imaginary) //│ ║ ^^^^^^^^^^^^^ -//│ ╟── type `Monoid[A]` is not an instance of `ComplexMonoid_bad_2[?A]` +//│ ╟── type `Monoid[A]` is not an instance of type `ComplexMonoid_bad_2` //│ ║ l.+1: class ComplexMonoid_bad_2[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `ComplexMonoid_bad_2[?A]` +//│ ╟── but it flows into field selection with expected type `ComplexMonoid_bad_2[?]` //│ ║ l.+5: Complex (this.base.Add self.real that.real) (this.base.Add self.imaginary that.imaginary) //│ ╙── ^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in field selection: //│ ║ l.+5: Complex (this.base.Add self.real that.real) (this.base.Add self.imaginary that.imaginary) //│ ║ ^^^^^^^^^^^^^ -//│ ╟── type `Monoid[A]` is not an instance of `ComplexMonoid_bad_2[?A]` +//│ ╟── type `Monoid[A]` is not an instance of type `ComplexMonoid_bad_2` //│ ║ l.+1: class ComplexMonoid_bad_2[A]: Monoid[Complex[A]] & { base: Monoid[A] } //│ ║ ^^^^^^^^^ -//│ ╟── but it flows into field selection with expected type `ComplexMonoid_bad_2[?A]` +//│ ╟── but it flows into field selection with expected type `ComplexMonoid_bad_2[?]` //│ ║ l.+5: Complex (this.base.Add self.real that.real) (this.base.Add self.imaginary that.imaginary) //│ ╙── ^^^^^^^^^ //│ Defined class ComplexMonoid_bad_2[=A] //│ Defined ComplexMonoid_bad_2.Add: ComplexMonoid_bad_2['A] -> {imaginary: 'A, real: 'A} -> {imaginary: 'A, real: 'A} -> Complex['A] -//│ Defined ComplexMonoid_bad_2.Add2: ComplexMonoid_bad_2['A] -> Complex[{imaginary: 'A0, real: 'A0}] -> Complex[{imaginary: 'A0, real: 'A0}] -> (Complex[Complex['A0] | error] & {imaginary: Complex['A0] | error, real: Complex['A0] | error}) +//│ Defined ComplexMonoid_bad_2.Add2: ComplexMonoid_bad_2['A] -> Complex[?] -> Complex[?] -> Complex[error] diff --git a/shared/src/test/diff/mlscript/TypeRanges.mls b/shared/src/test/diff/mlscript/TypeRanges.mls index 27dbc9d8fb..67519fa45f 100644 --- a/shared/src/test/diff/mlscript/TypeRanges.mls +++ b/shared/src/test/diff/mlscript/TypeRanges.mls @@ -17,7 +17,7 @@ def set3: MutArray[number..int] -> 'b -> () //│ ╔══[ERROR] Type mismatch in type bounds: //│ ║ l.16: def set3: MutArray[number..int] -> 'b -> () //│ ║ ^^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.16: def set3: MutArray[number..int] -> 'b -> () //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -60,7 +60,7 @@ foo = foo //│ ╔══[ERROR] Type mismatch in def definition: //│ ║ l.56: foo = foo //│ ║ ^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.50: def foo: MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -80,7 +80,7 @@ foo = (mut 0,) //│ ╔══[ERROR] Type mismatch in def definition: //│ ║ l.74: foo = (mut 0,) //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.50: def foo: MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── but it flows into mutable tuple field with expected type `int` @@ -99,7 +99,7 @@ set0 foo //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.98: set0 foo //│ ║ ^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.50: def foo: MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -117,7 +117,7 @@ set2 foo //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.116: set2 foo //│ ║ ^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.50: def foo: MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -135,7 +135,7 @@ foo : MutArray['a] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.134: foo : MutArray['a] //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.50: def foo: MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -159,7 +159,7 @@ foo[0] <- 1 //│ ╔══[ERROR] Type mismatch in assignment: //│ ║ l.158: foo[0] <- 1 //│ ║ ^^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.50: def foo: MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -205,7 +205,7 @@ foo2 = foo : MutArray['a..'b] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.204: foo2 = foo : MutArray['a..'b] //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.50: def foo: MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -244,7 +244,7 @@ def foo: MutArray[number..int] //│ ╔══[ERROR] Type mismatch in type bounds: //│ ║ l.243: def foo: MutArray[number..int] //│ ║ ^^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.243: def foo: MutArray[number..int] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -313,7 +313,7 @@ maf ((mut error,)) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.312: maf ((mut error,)) //│ ║ ^^^^^^^^^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.295: def maf: MutArray[int..number] -> MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── but it flows into mutable tuple field with expected type `int` @@ -334,7 +334,7 @@ fun x -> maf ((mut x,)) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.333: fun x -> maf ((mut x,)) //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.295: def maf: MutArray[int..number] -> MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── but it flows into mutable tuple field with expected type `int` @@ -361,7 +361,7 @@ def maf: MutArray[number..int] -> MutArray[int..number] //│ ╔══[ERROR] Type mismatch in type bounds: //│ ║ l.360: def maf: MutArray[number..int] -> MutArray[int..number] //│ ║ ^^^^^^^^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.360: def maf: MutArray[number..int] -> MutArray[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -403,7 +403,7 @@ foo: R['a] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.402: foo: R['a] //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.388: def foo: R[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -423,7 +423,7 @@ foo: R['a..'b] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.422: foo: R['a..'b] //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.388: def foo: R[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -448,7 +448,7 @@ foo: S['a] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.447: foo: S['a] //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.388: def foo: R[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: @@ -468,7 +468,7 @@ foo: S['a..'b] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.467: foo: S['a..'b] //│ ║ ^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.388: def foo: R[int..number] //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/mlscript/Yuheng.mls b/shared/src/test/diff/mlscript/Yuheng.mls index d3d8d9f9b0..eab616a8b6 100644 --- a/shared/src/test/diff/mlscript/Yuheng.mls +++ b/shared/src/test/diff/mlscript/Yuheng.mls @@ -40,7 +40,7 @@ f a2 //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.39: f a2 //│ ║ ^^^^ -//│ ╟── type `number` is not an instance of `int` +//│ ╟── type `number` is not an instance of type `int` //│ ║ l.34: a2 = A { x = 0: number } //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/nu/AuxCtors.mls b/shared/src/test/diff/nu/AuxCtors.mls index 64f53ed219..ab2ef6141d 100644 --- a/shared/src/test/diff/nu/AuxCtors.mls +++ b/shared/src/test/diff/nu/AuxCtors.mls @@ -63,7 +63,7 @@ class C(val x: Int) { constructor(y: Str) { x = y } } //│ ╔══[ERROR] Type mismatch in auxiliary class constructor: //│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `Str` is not an instance of `Int` +//│ ╟── type `Str` is not an instance of type `Int` //│ ║ l.62: class C(val x: Int) { constructor(y: Str) { x = y } } //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `Int` diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index 0d1240eb56..d487fe30cb 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -66,7 +66,7 @@ class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in definition of method x: //│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ╟── reference of type `false` is not an instance of `Int` //│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` @@ -91,7 +91,22 @@ class Bar extends Foo { //│ ╔══[ERROR] Type mismatch in signature of member `x`: //│ ║ l.88: fun x: Bool //│ ║ ^^^^^^^ -//│ ╟── type `Bool` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` +//│ ║ l.88: fun x: Bool +//│ ║ ^^^^ +//│ ╟── but it flows into signature of member `x` with expected type `Int` +//│ ║ l.88: fun x: Bool +//│ ║ ^^^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } +//│ ║ ^^^ +//│ ╟── from definition of method x: +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in signature of member `x`: +//│ ║ l.88: fun x: Bool +//│ ║ ^^^^^^^ +//│ ╟── type `Bool` is not an instance of type `Int` //│ ║ l.88: fun x: Bool //│ ║ ^^^^ //│ ╟── but it flows into signature of member `x` with expected type `Int` @@ -116,13 +131,13 @@ mixin M { fun x = false } :e class Bar extends Foo, M //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.111: mixin M { fun x = false } +//│ ║ l.126: mixin M { fun x = false } //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.111: mixin M { fun x = false } +//│ ╟── reference of type `false` is not an instance of `Int` +//│ ║ l.126: mixin M { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.111: mixin M { fun x = false } +//│ ║ l.126: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.58: class Foo { virtual fun x: Int = 1 } @@ -156,19 +171,19 @@ trait B { class X { fun g = 1 } } :e class C extends A, B //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.157: class C extends A, B +//│ ║ l.172: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.141: trait B { class X { fun g = 1 } } +//│ ║ l.156: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Intersection of class member and class members currently unsupported -//│ ║ l.157: class C extends A, B +//│ ║ l.172: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.140: class A { class X { fun f = 1 } } +//│ ║ l.155: class A { class X { fun f = 1 } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.141: trait B { class X { fun g = 1 } } +//│ ║ l.156: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A, B { //│ constructor() @@ -183,14 +198,14 @@ class C extends A { class X { fun g = 1 } } //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.182: class C extends A { +//│ ║ l.197: class C extends A { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.183: class X { fun g = 1 } +//│ ║ l.198: class X { fun g = 1 } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.184: } +//│ ║ l.199: } //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.140: class A { class X { fun f = 1 } } +//│ ║ l.155: class A { class X { fun f = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A { //│ constructor() @@ -205,7 +220,7 @@ class C extends A { :e class Foo2 extends Foo2 //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.206: class Foo2 extends Foo2 +//│ ║ l.221: class Foo2 extends Foo2 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ //│ class Foo2 extends Foo2 { //│ constructor() diff --git a/shared/src/test/diff/nu/BadClassSignatures.mls b/shared/src/test/diff/nu/BadClassSignatures.mls new file mode 100644 index 0000000000..87cb924ed6 --- /dev/null +++ b/shared/src/test/diff/nu/BadClassSignatures.mls @@ -0,0 +1,187 @@ +:NewDefs + + +abstract class Foo(): Foo +//│ abstract class Foo(): Foo + +module Bar extends Foo +//│ module Bar extends Foo + +abstract class Baz(): Baz | Baz +//│ abstract class Baz(): Baz + + +abstract class Foo(): Int +//│ abstract class Foo(): Int + +fun foo(x: Foo) = x : Int +//│ fun foo: (x: Foo) -> Int + +:e +let f = Foo() : Foo +//│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated +//│ ║ l.21: let f = Foo() : Foo +//│ ╙── ^^^ +//│ let f: Foo +//│ f +//│ = Foo {} + +f + 1 +//│ Int +//│ res +//│ = '[object Object]1' + +:e +Foo() + 1 +//│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated +//│ ║ l.35: Foo() + 1 +//│ ╙── ^^^ +//│ Int +//│ res +//│ = '[object Object]1' + +:e +(Foo() : Foo) + 1 +//│ ╔══[ERROR] Class Foo is abstract and cannot be instantiated +//│ ║ l.44: (Foo() : Foo) + 1 +//│ ╙── ^^^ +//│ Int +//│ res +//│ = '[object Object]1' + + +:w +:e +module Foo: Int +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract module definitions +//│ ║ l.55: module Foo: Int +//│ ║ ^^^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.55: module Foo: Int +//│ ║ ^^^^^^^^^^ +//│ ╟── expression of type `#Foo` is not an instance of type `Int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.55: module Foo: Int +//│ ╙── ^^^ +//│ module Foo: Int + +Foo + 1 +//│ Int +//│ res +//│ = '[object Object]1' + + +:w +class Foo(): {} +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract class definitions +//│ ║ l.76: class Foo(): {} +//│ ║ ^^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? +//│ class Foo() + +:w +class Foo(): {} { + fun x = 0 +} +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract class definitions +//│ ║ l.84: class Foo(): {} { +//│ ║ ^^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? +//│ class Foo() { +//│ fun x: 0 +//│ } + +:w +:e +class Foo(): { x: Int } { + fun x = 0 +} +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract class definitions +//│ ║ l.97: class Foo(): { x: Int } { +//│ ║ ^^^^^^^^^^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.97: class Foo(): { x: Int } { +//│ ╙── ^ +//│ class Foo(): {x: Int} { +//│ fun x: 0 +//│ } + +abstract class Foo(): { x: Int } { + fun x = 0 +} +//│ abstract class Foo(): {x: Int} { +//│ fun x: 0 +//│ } + +:e +module FooM extends Foo +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.111: abstract class Foo(): { x: Int } { +//│ ╙── ^ +//│ module FooM extends Foo { +//│ fun x: 0 +//│ } + +abstract class Foo(): { x: Int } { + fun x: Int + fun x = 0 +} +//│ abstract class Foo(): {x: Int} { +//│ fun x: Int +//│ } + +:e // TODO should work? +module FooM extends Foo +//│ ╔══[ERROR] Indirectly-recursive member should have type annotation +//│ ║ l.127: abstract class Foo(): { x: Int } { +//│ ╙── ^ +//│ module FooM extends Foo { +//│ fun x: Int +//│ } + +:w +:e +class Foo(): { x: 'FigureItOut } { + fun x: Int + fun x = 0 +} +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract class definitions +//│ ║ l.146: class Foo(): { x: 'FigureItOut } { +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? +//│ ╔══[ERROR] Type error in type declaration +//│ ║ l.146: class Foo(): { x: 'FigureItOut } { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.147: fun x: Int +//│ ║ ^^^^^^^^^^^^ +//│ ║ l.148: fun x = 0 +//│ ║ ^^^^^^^^^^^ +//│ ║ l.149: } +//│ ║ ^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.147: fun x: Int +//│ ╙── ^^^ +//│ class Foo(): {x: ??FigureItOut} { +//│ fun x: Int +//│ } + +:e +not(Foo().x) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.171: not(Foo().x) +//│ ║ ^^^^^^^^^^^^ +//│ ╟── field selection of type `Int & ??FigureItOut` is not an instance of type `Bool` +//│ ║ l.171: not(Foo().x) +//│ ╙── ^^^^^^^ +//│ error | false | true +//│ res +//│ = true + +(f: Foo) => f.x +//│ (f: Foo) -> (Int & ??FigureItOut) +//│ res +//│ = [Function: res] + + diff --git a/shared/src/test/diff/nu/BadClasses.mls b/shared/src/test/diff/nu/BadClasses.mls index 01a818e328..4e8a3a555a 100644 --- a/shared/src/test/diff/nu/BadClasses.mls +++ b/shared/src/test/diff/nu/BadClasses.mls @@ -28,7 +28,7 @@ class C0 extends M0(true) //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.27: class C0 extends M0(true) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `Int` +//│ ╟── reference of type `true` is not an instance of `Int` //│ ║ l.27: class C0 extends M0(true) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/nu/BasicMixins.mls b/shared/src/test/diff/nu/BasicMixins.mls index 37dfd296a9..4780ddaf18 100644 --- a/shared/src/test/diff/nu/BasicMixins.mls +++ b/shared/src/test/diff/nu/BasicMixins.mls @@ -112,7 +112,7 @@ Base2(11).test2 //│ = [ 12, 11 ] -// TODO +:e // TODO class Base2(x) extends BaseOf(x + 1), BaseTest //│ ╔══[ERROR] Class parameters currently need type annotations //│ ║ l.116: class Base2(x) extends BaseOf(x + 1), BaseTest @@ -122,10 +122,15 @@ class Base2(x) extends BaseOf(x + 1), BaseTest //│ fun test: Int //│ } +:w :e class Base1(x: Int): BaseTest +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract class definitions +//│ ║ l.127: class Base1(x: Int): BaseTest +//│ ║ ^^^^^^^^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? //│ ╔══[ERROR] mixin BaseTest cannot be used as a type -//│ ║ l.126: class Base1(x: Int): BaseTest +//│ ║ l.127: class Base1(x: Int): BaseTest //│ ╙── ^^^^^^^^ //│ class Base1(x: Int): BaseTest @@ -140,7 +145,7 @@ Base1 :e 1 : BaseTest //│ ╔══[ERROR] mixin BaseTest cannot be used as a type -//│ ║ l.141: 1 : BaseTest +//│ ║ l.146: 1 : BaseTest //│ ╙── ^^^^^^^^ //│ BaseTest //│ res @@ -149,7 +154,7 @@ Base1 :e error : BaseTest //│ ╔══[ERROR] mixin BaseTest cannot be used as a type -//│ ║ l.150: error : BaseTest +//│ ║ l.155: error : BaseTest //│ ╙── ^^^^^^^^ //│ BaseTest //│ res @@ -169,31 +174,31 @@ mixin Foo { :e module Base1(base: Int, misc: string) extends Foo //│ ╔══[ERROR] Module parameters are not supported -//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.175: module Base1(base: Int, misc: string) extends Foo //│ ╙── ^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.175: module Base1(base: Int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'misc' -//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.175: module Base1(base: Int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.167: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.167: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.175: module Base1(base: Int, misc: string) extends Foo //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── Object of type `anything` does not have field 'base' -//│ ║ l.170: module Base1(base: Int, misc: string) extends Foo +//│ ║ l.175: module Base1(base: Int, misc: string) extends Foo //│ ║ ^ //│ ╟── Note: constraint arises from field selection: -//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.167: fun test(x) = [super.base + x, x, super.misc] //│ ║ ^^^^^^^^^^ //│ ╟── from reference: -//│ ║ l.162: fun test(x) = [super.base + x, x, super.misc] +//│ ║ l.167: fun test(x) = [super.base + x, x, super.misc] //│ ╙── ^^^^^ //│ module Base1(base: Int, misc: string) { //│ fun test: forall 'a. (Int & 'a) -> [Int, 'a, nothing] @@ -202,13 +207,13 @@ module Base1(base: Int, misc: string) extends Foo :e Base1.test //│ ╔══[ERROR] Parameterized modules are not yet supported -//│ ║ l.203: Base1.test +//│ ║ l.208: Base1.test //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in field selection: -//│ ║ l.203: Base1.test +//│ ║ l.208: Base1.test //│ ║ ^^^^^^^^^^ //│ ╟── reference of type `(base: Int, misc: string) -> Base1` does not have field 'test' -//│ ║ l.203: Base1.test +//│ ║ l.208: Base1.test //│ ╙── ^^^^^ //│ error //│ res @@ -286,13 +291,13 @@ WrapBase1.wrapA(1) :e WrapBase1.wrapA("ok") //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.287: WrapBase1.wrapA("ok") +//│ ║ l.292: WrapBase1.wrapA("ok") //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── string literal of type `"ok"` is not an instance of type `Int` -//│ ║ l.287: WrapBase1.wrapA("ok") +//│ ║ l.292: WrapBase1.wrapA("ok") //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.231: fun wrapA(x) = [super.wrapA(x)] +//│ ║ l.236: fun wrapA(x) = [super.wrapA(x)] //│ ╙── ^ //│ error | [Int] //│ res diff --git a/shared/src/test/diff/nu/ClassSignatures.mls b/shared/src/test/diff/nu/ClassSignatures.mls index 8b7cd5fab3..20c59c9429 100644 --- a/shared/src/test/diff/nu/ClassSignatures.mls +++ b/shared/src/test/diff/nu/ClassSignatures.mls @@ -1,67 +1,66 @@ :NewDefs -class Foo(): {} -//│ class Foo() - -class Foo(): {} { - fun x = 0 -} -//│ class Foo() { -//│ fun x: 0 -//│ } - -class Foo(): { x: Int } { - fun x = 0 -} -//│ class Foo(): {x: Int} { -//│ fun x: 0 -//│ } +abstract class C0: C1 | C2 +class C1() extends C0 +module C2 extends C0 +//│ abstract class C0: C1 | C2 +//│ class C1() extends C0 +//│ module C2 extends C0 + +fun foo(x: C0) = if x is + C1 then 1 + C2 then 2 +//│ fun foo: (x: C0) -> (1 | 2) + +fun foo(x: C0) = x : C1 | C2 +//│ fun foo: (x: C0) -> (C1 | C2) + +fun foo(x) = if x is + C1 then 1 + C2 then 2 +//│ fun foo: (C1 | C2) -> (1 | 2) + +foo(C1()) + foo(C2) +//│ Int +//│ res +//│ = 3 -class Foo(): { x: 'FigureItOut } { - fun x = 0 -} -//│ class Foo(): {x: ??FigureItOut} { -//│ fun x: 0 -//│ } :e -not(Foo().x) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.29: not(Foo().x) -//│ ║ ^^^^^^^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `Bool` -//│ ║ l.22: fun x = 0 -//│ ║ ^ -//│ ╟── but it flows into field selection with expected type `Bool` -//│ ║ l.29: not(Foo().x) -//│ ╙── ^^^^^^^ -//│ error | false | true -//│ res -//│ = true - -(f: Foo) => f.x -//│ (f: Foo) -> (0 & ??FigureItOut) -//│ res -//│ = [Function: res] +class C3 extends C0 +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.31: class C3 extends C0 +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#C3` does not match type `C1 | C2` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.4: abstract class C0: C1 | C2 +//│ ╙── ^^^^^^^ +//│ class C3 extends C0 { +//│ constructor() +//│ } trait B //│ trait B -// :e // TODO check classes against their signatures +:w +:e class A(): B +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract class definitions +//│ ║ l.49: class A(): B +//│ ║ ^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.49: class A(): B +//│ ║ ^^^^^^^^^ +//│ ╟── expression of type `#A` is not an instance of type `B` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.49: class A(): B +//│ ╙── ^ //│ class A(): B -:e A() : B -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.57: A() : B -//│ ║ ^^^ -//│ ╟── application of type `A` is not an instance of type `B` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.57: A() : B -//│ ╙── ^ //│ B //│ res //│ = A {} @@ -72,15 +71,8 @@ abstract class A(): B :e A() : B //│ ╔══[ERROR] Class A is abstract and cannot be instantiated -//│ ║ l.73: A() : B +//│ ║ l.72: A() : B //│ ╙── ^ -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.73: A() : B -//│ ║ ^^^ -//│ ╟── application of type `A` is not an instance of type `B` -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.73: A() : B -//│ ╙── ^ //│ B //│ res //│ = A {} @@ -94,3 +86,83 @@ C : B //│ = C { class: [class C extends A] } +:w +:e +class A(): C +class B() extends A +class C() extends B +//│ ╔══[WARNING] Self-type annotations have no effects on non-abstract class definitions +//│ ║ l.91: class A(): C +//│ ║ ^ +//│ ╙── Did you mean to use `extends` and inherit from a parent class? +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.91: class A(): C +//│ ║ ^^^^^^^^^ +//│ ╟── expression of type `#A` is not an instance of type `C` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.91: class A(): C +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.92: class B() extends A +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#B` is not an instance of type `C` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.91: class A(): C +//│ ╙── ^ +//│ class A(): C +//│ class B() extends A +//│ class C() extends A, B + + +:e +abstract class A(): C +class B() extends A +class C() extends B +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.119: class B() extends A +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#B` is not an instance of type `C` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.118: abstract class A(): C +//│ ╙── ^ +//│ abstract class A(): C +//│ class B() extends A +//│ class C() extends A, B + + +abstract class A(): C +abstract class B() extends A +class C() extends B +//│ abstract class A(): C +//│ abstract class B(): C extends A +//│ class C() extends A, B + + +// * Transitively-inherited self-types are checked + +:e +class D() extends B +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.144: class D() extends B +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#D` is not an instance of type `C` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.133: abstract class A(): C +//│ ╙── ^ +//│ class D() extends A, B + + +// * Transitively-inherited self-types can be leveraged + +fun test(x: B): C = x +//│ fun test: (x: B) -> C + +fun test[A](x: B & A): C = x +//│ fun test: (x: B) -> C + +trait T +fun test(x: B & T): C = x +//│ trait T +//│ fun test: (x: B & T) -> C + + diff --git a/shared/src/test/diff/nu/DiamondInherit.mls b/shared/src/test/diff/nu/DiamondInherit.mls index e06a6def2a..15ca19fffc 100644 --- a/shared/src/test/diff/nu/DiamondInherit.mls +++ b/shared/src/test/diff/nu/DiamondInherit.mls @@ -67,7 +67,7 @@ trait T1 extends Foo[Int | Bool] //│ fun foo: 'A //│ } //│ where -//│ 'A := in Bool | Int out Int | false | true +//│ 'A := Int | false | true module Bar extends T1, Foo[Int | Str] { fun foo = 123 @@ -95,7 +95,7 @@ module Bar extends T1, Foo[Int | Str] { let f = (Bar : T1).bar f(true) -//│ let f: ('A & (Bool | Int)) -> (Int | false | true | 'A) +//│ let f: ('A & (Int | false | true)) -> (Int | false | true | 'A) //│ Int | false | true //│ f //│ = [Function: id] @@ -110,7 +110,7 @@ module Bar extends T1, Foo[Int | Str] { //│ ╔══[ERROR] Type mismatch in definition of method bar: //│ ║ l.108: fun bar(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `Bool` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` //│ ║ l.64: trait T1 extends Foo[Int | Bool] //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: @@ -119,7 +119,16 @@ module Bar extends T1, Foo[Int | Str] { //│ ╔══[ERROR] Type mismatch in definition of method bar: //│ ║ l.108: fun bar(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `Str` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` +//│ ║ l.64: trait T1 extends Foo[Int | Bool] +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.108: fun bar(x) = x + 1 +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method bar: +//│ ║ l.108: fun bar(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type `Str` is not an instance of type `Int` //│ ║ l.106: module Bar extends T1, Foo[Int | Str] { //│ ║ ^^^ //│ ╟── Note: constraint arises from reference: diff --git a/shared/src/test/diff/nu/EqlClasses.mls b/shared/src/test/diff/nu/EqlClasses.mls index 0b3382c62b..927045a336 100644 --- a/shared/src/test/diff/nu/EqlClasses.mls +++ b/shared/src/test/diff/nu/EqlClasses.mls @@ -50,7 +50,7 @@ Cls2(0) === Cls2(1) -class Pair[A](val fst: A, val snd: A) +class Pair[out A](val fst: A, val snd: A) // extends (A <: Eql[A]) => Eql[Pair[A]] //│ class Pair[A](fst: A, snd: A) @@ -141,7 +141,7 @@ q === q //│ = true -class Pair2[A, B](val fst: A, val snd: B) +class Pair2[out A, out B](val fst: A, val snd: B) //│ class Pair2[A, B](fst: A, snd: B) let q = Pair2(1, "oops") @@ -156,7 +156,7 @@ q === q -class MP[Col](val color: Col) +class MP[out Col](val color: Col) //│ class MP[Col](color: Col) val mp = MP(1) diff --git a/shared/src/test/diff/nu/Eval.mls b/shared/src/test/diff/nu/Eval.mls index 7f803f8e20..0f5dd3d2e2 100644 --- a/shared/src/test/diff/nu/Eval.mls +++ b/shared/src/test/diff/nu/Eval.mls @@ -18,19 +18,20 @@ fun (<|) pepi(f, x) = f(x) // * Hack to throw exceptions +:e declare class throw(arg: anything): nothing +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.22: declare class throw(arg: anything): nothing +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#Throw & {arg: anything}` does not match type `nothing` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.22: declare class throw(arg: anything): nothing +//│ ╙── ^^^^^^^ //│ declare class throw(arg: anything): nothing -:w // * Due to current limitations of self types fun raise(err) = throw(err) error -//│ ╔══[WARNING] Expression in statement position should have type `()`. -//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. -//│ ╟── Type mismatch in application: -//│ ║ l.26: throw(err) -//│ ║ ^^^^^^^^^^ -//│ ╙── application of type `throw` does not match type `()` //│ fun raise: anything -> nothing :re @@ -137,7 +138,7 @@ module Lists { // TODO use name List when module overloading is supported: //│ module Lists { //│ fun assoc: forall 'a 'A. 'a -> (Cons[{key: Eql['a], value: 'A}] | Nil) -> (None | Some['A]) //│ fun map: forall 'b 'A0. ('b -> 'A0) -> (Cons['b] | Nil) -> (Cons['A0] | Nil) -//│ fun zip: forall 'c 'd. (Cons['c] | Nil, Cons['d] | Nil) -> (Cons[['c, 'd]] | Nil) +//│ fun zip: forall 'c 'd. (Cons['d] | Nil, Cons['c] | Nil) -> (Cons[['d, 'c]] | Nil) //│ } let xs = 1 :: 2 :: 3 :: Nil @@ -166,7 +167,8 @@ ls |> Lists.assoc("a") // * Our little language: -abstract class Term: Var | App | Lam | Sel | Rcd[Term] +:e // * We don't yet support upper bounds on type parameters, so we can't provide the needed `out Sub <: Term` +abstract class Term: Var | App | Lam | Sel | Rcd[Term] | Lit class Var(val name: Str) extends Term class App(val lhs: Term, val args: List[Term]) extends Term class Lam(val params: List[Str], val body: Term) extends Term @@ -175,7 +177,31 @@ class Sel(val prefix: Term, val fieldName: Str) extends Term abstract class Lit[out A](val value: A): IntLit | StrLit extends Term class IntLit(v: Int) extends Lit[Int](v) class StrLit(v: Str) extends Lit[Str](v) -//│ abstract class Term: App | Lam | Rcd[Term] | Sel | Var +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.175: class Rcd[out Sub](val fields: List[{key: Str, value: Sub}]) extends Term +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `Sub` is not an instance of type `Term` +//│ ║ l.175: class Rcd[out Sub](val fields: List[{key: Str, value: Sub}]) extends Term +//│ ║ ^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.171: abstract class Term: Var | App | Lam | Sel | Rcd[Term] | Lit +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.175: class Rcd[out Sub](val fields: List[{key: Str, value: Sub}]) extends Term +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `Sub` does not match type `App | Lam | #Lit | Rcd[Term] | Sel | Var` +//│ ║ l.175: class Rcd[out Sub](val fields: List[{key: Str, value: Sub}]) extends Term +//│ ║ ^^^ +//│ ╟── Note: constraint arises from union type: +//│ ║ l.171: abstract class Term: Var | App | Lam | Sel | Rcd[Term] | Lit +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.171: abstract class Term: Var | App | Lam | Sel | Rcd[Term] | Lit +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type `Sub` does not contain member `Rcd#Sub` +//│ ║ l.175: class Rcd[out Sub](val fields: List[{key: Str, value: Sub}]) extends Term +//│ ╙── ^^^ +//│ abstract class Term: App | Lam | Lit[anything] | Rcd[Term] | Sel | Var //│ class Var(name: Str) extends Term //│ class App(lhs: Term, args: List[Term]) extends Term //│ class Lam(params: List[Str], body: Term) extends Term @@ -185,20 +211,33 @@ class StrLit(v: Str) extends Lit[Str](v) //│ class IntLit(v: Int) extends Lit, Term //│ class StrLit(v: Str) extends Lit, Term +// * Workaround/alternative: +type Term = Var | App | Lam | Sel | Rcd[Term] | Lit +class Var(val name: Str) +class App(val lhs: Term, val args: List[Term]) +class Lam(val params: List[Str], val body: Term) +class Rcd[out Sub](val fields: List[{key: Str, value: Sub}]) +class Sel(val prefix: Term, val fieldName: Str) +abstract class Lit[out A](val value: A): IntLit | StrLit +class IntLit(v: Int) extends Lit[Int](v) +class StrLit(v: Str) extends Lit[Str](v) +//│ type Term = App | Lam | Lit[anything] | Rcd[Term] | Sel | Var +//│ class Var(name: Str) +//│ class App(lhs: Term, args: List[Term]) +//│ class Lam(params: List[Str], body: Term) +//│ class Rcd[Sub](fields: List[{key: Str, value: Sub}]) +//│ class Sel(prefix: Term, fieldName: Str) +//│ abstract class Lit[A](value: A): IntLit | StrLit +//│ class IntLit(v: Int) extends Lit +//│ class StrLit(v: Str) extends Lit + type Value = Lam | Lit | Rcd[Value] //│ type Value = Lam | Lit[anything] | Rcd[Value] -:w fun err(msg) = throw(concat("Evaluation error: " ++ msg)) error -//│ ╔══[WARNING] Expression in statement position should have type `()`. -//│ ╟── Use a comma expression `... , ()` to explicitly discard non-unit values, making your intent clearer. -//│ ╟── Type mismatch in application: -//│ ║ l.194: throw(concat("Evaluation error: " ++ msg)) -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╙── application of type `throw` does not match type `()` //│ fun err: Str -> nothing fun eval(t, env) = if t is @@ -221,12 +260,12 @@ fun eval(t, env) = if t is else err(String(pree) ++ " does not have field " ++ nme) Rcd(fs) then Rcd of fs |> Lists.map of {key, value} => {key, value: eval(value, env)} -//│ fun eval: forall 'a 'b 'c. ('b, Cons[{key: Eql[Str], value: 'c}] & {List#A <: {key: Eql[Str], value: 'c}} & List[{key: Eql[Str], value: 'c}] | Nil & {List#A <: {key: Eql[Str], value: 'c}} & List[{key: Eql[Str], value: 'c}]) -> 'a +//│ fun eval: forall 'a 'b 'c. ('c, Cons[{key: Eql[Str], value: 'a}] & {List#A <: {key: Eql[Str], value: 'a}} & List[{key: Eql[Str], value: 'a}] | Nil & {List#A <: {key: Eql[Str], value: 'a}} & List[{key: Eql[Str], value: 'a}]) -> 'b //│ where -//│ 'c :> 'a -//│ <: Object & ~#Rcd | Rcd['c] -//│ 'a :> 'c | Lam | Lit[nothing] | Rcd[Lam | Lit[nothing] | 'a] -//│ 'b <: App | Lam | Lit[anything] | Rcd['b] | Sel | Var +//│ 'a :> 'b +//│ <: Object & ~#Rcd | Rcd['a] +//│ 'b :> 'a | Rcd[Lam | Lit[??A] | 'b] | Lam | Lit[??A] +//│ 'c <: App | Lam | Lit[anything] | Rcd['c] | Sel | Var eval : (Term, List[{key: Str, value: Value}]) -> Value //│ (Term, List[{key: Str, value: Value}]) -> Value @@ -241,21 +280,21 @@ let rcd = Rcd({key: "a", value: IntLit(0)} :: Nil) eval of rcd, Nil //│ 'a //│ where -//│ 'a :> Lam | Lit[Int] | Rcd[Lam | Lit[Int] | 'a] +//│ 'a :> Lam | Lit[Int | ??A] | Rcd[Lam | Lit[Int | ??A] | 'a] //│ res //│ = Rcd {} eval of Sel(rcd, "a"), Nil //│ 'a //│ where -//│ 'a :> Lam | Lit[nothing] | Rcd[Lam | Lit[nothing] | 'a] +//│ 'a :> Lam | Lit[??A] | Rcd[Lam | Lit[??A] | 'a] //│ res //│ = IntLit {} eval of App(Lam("x" :: Nil, Sel(Var("x"), "a")), rcd :: Nil), Nil //│ 'a //│ where -//│ 'a :> Lam | Lit[nothing] | Rcd[Lam | Lit[nothing] | 'a] +//│ 'a :> Lam | Lit[??A] | Rcd[Lam | Lit[??A] | 'a] //│ res //│ = IntLit {} diff --git a/shared/src/test/diff/nu/EvalNegNeg.mls b/shared/src/test/diff/nu/EvalNegNeg.mls index e9e90e00d5..4e3fbbaba2 100644 --- a/shared/src/test/diff/nu/EvalNegNeg.mls +++ b/shared/src/test/diff/nu/EvalNegNeg.mls @@ -1,7 +1,7 @@ :NewDefs -class Add(lhs: E, rhs: E) +class Add(lhs: E, rhs: E) class Lit(n: Int) //│ class Add[E](lhs: E, rhs: E) //│ class Lit(n: Int) @@ -19,7 +19,7 @@ mixin EvalBase { //│ } -class Neg(expr: A) +class Neg(expr: A) //│ class Neg[A](expr: A) @@ -52,7 +52,7 @@ module TestLang extends EvalBase, EvalNeg, EvalNegNeg //│ fun eval: (Neg['A] | Object & 'a & ~#Neg) -> Int //│ } //│ where -//│ 'A <: Neg['A & 'b] | Neg['A] & ~#Neg | Object & 'a & ~#Neg +//│ 'A <: 'b & (Neg['b] | Object & ~#Neg) //│ 'b <: Neg['A] | Object & 'a & ~#Neg //│ 'a <: Add['b] | Lit | Neg['b] diff --git a/shared/src/test/diff/nu/ExplicitVariance.mls b/shared/src/test/diff/nu/ExplicitVariance.mls index b7682d10a9..2f3980b48a 100644 --- a/shared/src/test/diff/nu/ExplicitVariance.mls +++ b/shared/src/test/diff/nu/ExplicitVariance.mls @@ -13,7 +13,7 @@ fun foo(x: Foo[Num]): Foo[Int] = x //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.12: fun foo(x: Foo[Num]): Foo[Int] = x //│ ║ ^ -//│ ╟── type `Num` is not an instance of `Int` +//│ ╟── type `Num` is not an instance of type `Int` //│ ║ l.12: fun foo(x: Foo[Num]): Foo[Int] = x //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: @@ -33,7 +33,7 @@ fun foo(x: Foo[Int]): Foo[Num] = x //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.32: fun foo(x: Foo[Int]): Foo[Num] = x //│ ║ ^ -//│ ╟── type `Num` is not an instance of `Int` +//│ ╟── type `Num` is not an instance of type `Int` //│ ║ l.32: fun foo(x: Foo[Int]): Foo[Num] = x //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/nu/ExpressionProblem_repro.mls b/shared/src/test/diff/nu/ExpressionProblem_repro.mls index 193b5f1033..70a8a32ed0 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_repro.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_repro.mls @@ -2,7 +2,7 @@ :NoJS -class Add0(lhs: E) +class Add0(lhs: E) //│ class Add0[E](lhs: E) fun eval(e) = if e is Add0(l) then eval(l) @@ -11,7 +11,7 @@ fun eval(e) = if e is Add0(l) then eval(l) //│ 'a <: Add0['a] -class Add(lhs: E, rhs: E) +class Add(lhs: E, rhs: E) class Lit(val value: Int) //│ class Add[E](lhs: E, rhs: E) //│ class Lit(value: Int) @@ -57,13 +57,13 @@ mixin EvalAdd { module TestLang extends EvalAdd //│ module TestLang { -//│ fun eval: Add['a] -> nothing +//│ fun eval: 'a -> nothing //│ } //│ where //│ 'a <: Add['a] TestLang.eval -//│ Add['a] -> nothing +//│ 'a -> nothing //│ where //│ 'a <: Add['a] @@ -83,13 +83,13 @@ mixin EvalBase { module TestLang extends EvalBase //│ module TestLang { -//│ fun eval: (Add['a] | Lit) -> Int +//│ fun eval: 'a -> Int //│ } //│ where //│ 'a <: Add['a] | Lit TestLang.eval -//│ (Add['a] | Lit) -> Int +//│ 'a -> Int //│ where //│ 'a <: Add['a] | Lit @@ -112,7 +112,7 @@ add11 -class Neg(expr: A) +class Neg(expr: A) //│ class Neg[A](expr: A) let add2negadd11 = Add(Lit(2), Neg(add11)) @@ -133,17 +133,15 @@ mixin EvalNeg { module TestLang extends EvalBase, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['a] | Object & 'b & ~#Neg) -> Int +//│ fun eval: 'a -> Int //│ } //│ where -//│ 'a <: Neg['a] | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit +//│ 'a <: Neg['a] | Object & (Add['a] | Lit) & ~#Neg TestLang.eval -//│ (Neg['a] | Object & 'b & ~#Neg) -> Int +//│ 'a -> Int //│ where -//│ 'a <: Neg['a] | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit +//│ 'a <: Neg['a] | Object & (Add['a] | Lit) & ~#Neg TestLang.eval(add11) diff --git a/shared/src/test/diff/nu/ExpressionProblem_small.mls b/shared/src/test/diff/nu/ExpressionProblem_small.mls index b682304041..128c1eee71 100644 --- a/shared/src/test/diff/nu/ExpressionProblem_small.mls +++ b/shared/src/test/diff/nu/ExpressionProblem_small.mls @@ -2,8 +2,8 @@ :NoJS -class Neg[A](expr: A) -class Add[E](lhs: E, rhs: E) +class Neg[out A](expr: A) +class Add[out E](lhs: E, rhs: E) class Lit(n: Int) //│ class Neg[A](expr: A) //│ class Add[E](lhs: E, rhs: E) @@ -45,16 +45,14 @@ mixin EvalNeg { module TestLang extends EvalNothing, EvalAddLit, EvalNeg //│ module TestLang { -//│ fun eval: (Neg['a] | Object & 'b & ~#Neg) -> Int +//│ fun eval: 'a -> Int //│ } //│ where -//│ 'a <: Neg['a] | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit +//│ 'a <: Neg['a] | Object & (Add['a] | Lit) & ~#Neg TestLang.eval -//│ (Neg['a] | Object & 'b & ~#Neg) -> Int +//│ 'a -> Int //│ where -//│ 'a <: Neg['a] | Object & 'b & ~#Neg -//│ 'b <: Add['a] | Lit +//│ 'a <: Neg['a] | Object & (Add['a] | Lit) & ~#Neg diff --git a/shared/src/test/diff/nu/GADTMono.mls b/shared/src/test/diff/nu/GADTMono.mls index 83317fcbf8..0d8323d5fb 100644 --- a/shared/src/test/diff/nu/GADTMono.mls +++ b/shared/src/test/diff/nu/GADTMono.mls @@ -41,7 +41,7 @@ l1: Expr[Bool] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.40: l1: Expr[Bool] //│ ║ ^^ -//│ ╟── type `Int` is not an instance of `Bool` +//│ ╟── type `Int` is not an instance of type `Bool` //│ ║ l.4: class LitInt(n: Int) extends Expr[Int] //│ ║ ^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/nu/GenericClassInheritance.mls b/shared/src/test/diff/nu/GenericClassInheritance.mls index 2b45a50288..784e81453a 100644 --- a/shared/src/test/diff/nu/GenericClassInheritance.mls +++ b/shared/src/test/diff/nu/GenericClassInheritance.mls @@ -50,7 +50,16 @@ class WrongRoom extends Room[Bool]("wrong") { //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.48: fun foo(x) = x + 1 //│ ║ ^^^^^^^^^^^^^^ -//│ ╟── type `Bool` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` +//│ ║ l.47: class WrongRoom extends Room[Bool]("wrong") { +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from reference: +//│ ║ l.48: fun foo(x) = x + 1 +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.48: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── type `Bool` is not an instance of type `Int` //│ ║ l.47: class WrongRoom extends Room[Bool]("wrong") { //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: @@ -68,6 +77,18 @@ class WrongRoom extends Room[Bool]("wrong") { //│ ╟── from reference: //│ ║ l.4: virtual fun foo(x: A) = x //│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.48: fun foo(x) = x + 1 +//│ ║ ^^^^^^^^^^^^^^ +//│ ╟── operator application of type `Int` does not match type `Bool` +//│ ║ l.48: fun foo(x) = x + 1 +//│ ║ ^^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.47: class WrongRoom extends Room[Bool]("wrong") { +//│ ║ ^^^^ +//│ ╟── from reference: +//│ ║ l.4: virtual fun foo(x: A) = x +//│ ╙── ^ //│ class WrongRoom extends Room { //│ constructor() //│ fun foo: Int -> Int @@ -153,14 +174,24 @@ class B2[A](val a: Int => A) extends M2 :e class E1(val a: Int) extends M2[Bool] //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.154: class E1(val a: Int) extends M2[Bool] +//│ ║ l.175: class E1(val a: Int) extends M2[Bool] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int` is not an instance of type `Bool` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.154: class E1(val a: Int) extends M2[Bool] +//│ ║ l.175: class E1(val a: Int) extends M2[Bool] +//│ ║ ^^^^ +//│ ╟── from field selection: +//│ ║ l.157: fun m: A = this.a +//│ ╙── ^^^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.175: class E1(val a: Int) extends M2[Bool] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `Int` does not match type `Bool` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.175: class E1(val a: Int) extends M2[Bool] //│ ║ ^^^^ //│ ╟── from field selection: -//│ ║ l.136: fun m: A = this.a +//│ ║ l.157: fun m: A = this.a //│ ╙── ^^^^^^ //│ class E1(a: Int) { //│ fun m: Bool diff --git a/shared/src/test/diff/nu/GenericClasses.mls b/shared/src/test/diff/nu/GenericClasses.mls index 685403f650..8ce63d9db9 100644 --- a/shared/src/test/diff/nu/GenericClasses.mls +++ b/shared/src/test/diff/nu/GenericClasses.mls @@ -13,7 +13,7 @@ fun f(x) = if x is C then x // f(C : #C) -class C(val a: A) +class C(val a: A) //│ class C[A](a: A) let c = C(1) @@ -45,7 +45,7 @@ class C[A](val n: A) { //│ } -class Some(val value: A) { +class Some(val value: A) { fun get = value fun toArray = [value] fun map(f) = Some(f(value)) @@ -211,7 +211,7 @@ Test(true) :e -class Test(n: A) { +class Test(n: A) { fun foo = n + 1 } //│ ╔══[ERROR] Type mismatch in operator application: @@ -221,8 +221,8 @@ class Test(n: A) { //│ ║ l.215: fun foo = n + 1 //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.214: class Test(n: A) { -//│ ╙── ^ +//│ ║ l.214: class Test(n: A) { +//│ ╙── ^ //│ class Test[A](n: A) { //│ fun foo: Int | error //│ } diff --git a/shared/src/test/diff/nu/GenericMixins.mls b/shared/src/test/diff/nu/GenericMixins.mls index ecf62c1795..f90665c6ab 100644 --- a/shared/src/test/diff/nu/GenericMixins.mls +++ b/shared/src/test/diff/nu/GenericMixins.mls @@ -82,7 +82,7 @@ C.foo(false) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.81: C.foo(false) //│ ║ ^^^^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ╟── reference of type `false` is not an instance of `Int` //│ ║ l.81: C.foo(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/nu/GenericModules.mls b/shared/src/test/diff/nu/GenericModules.mls index ae49e4872a..778511bb83 100644 --- a/shared/src/test/diff/nu/GenericModules.mls +++ b/shared/src/test/diff/nu/GenericModules.mls @@ -1,33 +1,65 @@ :NewDefs -:e +// * TODO generic module definitions need to be restricted so they do not include nay state +// * to avoid unsoundness... + + +module Test[A] { + fun foo: A -> A = id +} +//│ module Test[A] { +//│ fun foo: A -> A +//│ } + +Test.foo(1) + 1 +//│ Int +//│ res +//│ = 2 + +not(Test.foo(true)) +//│ Bool +//│ res +//│ = false + +Test.foo +//│ 'A -> 'A +//│ res +//│ = [Function: id] + + +// * FIXME merging generic module types, as we currently do, is unsound: + +let t = Test : Test[Int] & Test[Str] +//│ let t: Test[in Int | Str out nothing] +//│ t +//│ = Test { class: [class Test] } + +t.foo +//│ (Int | Str) -> nothing +//│ res +//│ = [Function: id] + +:re +t.foo(1)(2) +//│ nothing +//│ res +//│ Runtime error: +//│ TypeError: t.foo(...) is not a function + + + module Test { fun foo: A => A + fun foo = id fun bar: A => A = id fun baz(x: A) = x fun poly0: 'a -> 'a + fun poly0 = id fun poly1: forall 'a: 'a -> 'a + fun poly1 = id fun poly2: 'a -> 'a = id } -//│ ╔══[ERROR] Member `foo` is declared (or its declaration is inherited) but is not implemented in `Test` -//│ ║ l.5: module Test { -//│ ║ ^^^^ -//│ ╟── Declared here: -//│ ║ l.6: fun foo: A => A -//│ ╙── ^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `poly0` is declared (or its declaration is inherited) but is not implemented in `Test` -//│ ║ l.5: module Test { -//│ ║ ^^^^ -//│ ╟── Declared here: -//│ ║ l.9: fun poly0: 'a -> 'a -//│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ ╔══[ERROR] Member `poly1` is declared (or its declaration is inherited) but is not implemented in `Test` -//│ ║ l.5: module Test { -//│ ║ ^^^^ -//│ ╟── Declared here: -//│ ║ l.10: fun poly1: forall 'a: 'a -> 'a -//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ module Test[A] { //│ fun bar: A -> A //│ fun baz: (x: A) -> A @@ -38,58 +70,43 @@ module Test { //│ } Test.foo -//│ ??A -> ??A0 +//│ 'A -> 'A //│ res -//│ = undefined +//│ = [Function: id] Test.bar -//│ ??A -> ??A0 +//│ 'A -> 'A //│ res //│ = [Function: id] Test.baz -//│ (x: ??A) -> ??A0 +//│ (x: 'A) -> 'A //│ res //│ = [Function: baz] Test.poly0 //│ forall 'a. 'a -> 'a //│ res -//│ = undefined +//│ = [Function: id] Test.poly1 //│ forall 'a. 'a -> 'a //│ res -//│ = undefined +//│ = [Function: id] Test.poly2 //│ forall 'a. 'a -> 'a //│ res //│ = [Function: id] -:e Test.foo(1) -//│ ╔══[ERROR] Type error in application -//│ ║ l.71: Test.foo(1) -//│ ║ ^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.71: Test.foo(1) -//│ ╙── ^ -//│ error | ??A +//│ 1 //│ res -//│ Runtime error: -//│ TypeError: Test.foo is not a function +//│ = 1 -:e +:re Test.foo(error) + 1 -//│ ╔══[ERROR] Type error in operator application -//│ ║ l.84: Test.foo(error) + 1 -//│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.84: Test.foo(error) + 1 -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╙── into expression of type `Int` -//│ Int | error +//│ Int //│ res //│ Runtime error: //│ Error: an error was thrown @@ -97,42 +114,29 @@ Test.foo(error) + 1 :e Test .foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.98: Test .foo -//│ ╙── ^^^^^^^^^ -//│ ??A -> ??A0 +//│ ║ l.115: Test .foo +//│ ╙── ^^^^^^^^^ +//│ 'A -> 'A //│ res -//│ = undefined +//│ = [Function: id] :e (Test).foo //│ ╔══[ERROR] Type application syntax is not yet supported -//│ ║ l.107: (Test).foo +//│ ║ l.124: (Test).foo //│ ╙── ^^^^^^^^^ -//│ ??A -> ??A0 +//│ 'A -> 'A //│ res -//│ = undefined +//│ = [Function: id] Test -//│ Test[?] +//│ forall 'A. Test['A] //│ res //│ = Test { class: [class Test] } -:e -Test: Test<'a> -//│ ╔══[ERROR] Type error in type ascription -//│ ║ l.122: Test: Test<'a> -//│ ║ ^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.122: Test: Test<'a> -//│ ║ ^^ -//│ ╟── back into type variable `A` -//│ ║ l.5: module Test { -//│ ╙── ^ +Test : Test<'a> //│ Test['a] -//│ where -//│ 'a :> ??A -//│ <: ??A0 //│ res //│ = Test { class: [class Test] } @@ -140,17 +144,10 @@ Test: Test<'a> fun test(x) = if x is Test then x.foo //│ fun test: forall 'A. Test['A] -> 'A -> 'A -:e test(Test) -//│ ╔══[ERROR] Type error in application -//│ ║ l.144: test(Test) -//│ ║ ^^^^^^^^^^ -//│ ╟── type variable `A` leaks out of its scope -//│ ║ l.5: module Test { -//│ ╙── ^ -//│ error | (??A & 'A) -> ('A | ??A0) +//│ 'A -> 'A //│ res -//│ = undefined +//│ = [Function: id] module Test { @@ -175,7 +172,7 @@ module Test { //│ } Test.foo -//│ ??A -> ??A0 +//│ 'A -> 'A //│ res //│ = [Function: id] diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls index 51f4efad8b..98f962aee7 100644 --- a/shared/src/test/diff/nu/HeungTung.mls +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -57,19 +57,19 @@ fun f = id fun h: (Int -> (Int | Bool)) & (Bool -> (Int | Bool)) fun h = f //│ fun h: Int -> Int & Bool -> Bool -//│ fun h: (Bool | Int) -> (Int | false | true) +//│ fun h: (Int | false | true) -> (Int | false | true) // * Merge intersected functions with same domain fun g: (Int | Bool) -> (Int | Bool) fun g = h -//│ fun g: (Bool | Int) -> (Int | false | true) -//│ fun g: (Bool | Int) -> (Int | false | true) +//│ fun g: (Int | false | true) -> (Int | false | true) +//│ fun g: (Int | false | true) -> (Int | false | true) // * In one step fun g: (Int | Bool) -> (Int | Bool) fun g = f //│ fun g: Int -> Int & Bool -> Bool -//│ fun g: (Bool | Int) -> (Int | false | true) +//│ fun g: (Int | false | true) -> (Int | false | true) // * Can also widen into intersection @@ -114,7 +114,7 @@ f(0) x => f(x) -//│ (Bool | Int) -> (Int | false | true) +//│ (Int | false | true) -> (Int | false | true) //│ res //│ = [Function: res] @@ -226,7 +226,7 @@ f: (Int -> Int) & (Bool -> Bool) //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^ -//│ ╟── type `Bool` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` //│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) //│ ║ ^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/nu/Huawei1.mls b/shared/src/test/diff/nu/Huawei1.mls index bf50ba68db..7b939fe6a1 100644 --- a/shared/src/test/diff/nu/Huawei1.mls +++ b/shared/src/test/diff/nu/Huawei1.mls @@ -1,7 +1,7 @@ :NewDefs -class C[A](x: A) { +class C[out A](x: A) { fun foo = x } //│ class C[A](x: A) { @@ -44,18 +44,18 @@ bar(C(true)) //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.43: bar(C(true)) //│ ║ ^^^^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `Int` +//│ ╟── reference of type `true` is not an instance of `Int` //│ ║ l.43: bar(C(true)) //│ ║ ^^^^ //│ ╟── Note: constraint arises from reference: //│ ║ l.32: C(y) then y + 1 //│ ║ ^ //│ ╟── from field selection: -//│ ║ l.4: class C[A](x: A) { -//│ ║ ^ +//│ ║ l.4: class C[out A](x: A) { +//│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.4: class C[A](x: A) { -//│ ╙── ^ +//│ ║ l.4: class C[out A](x: A) { +//│ ╙── ^ //│ Int | error //│ res //│ = 2 diff --git a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls index 57814459d9..0f52e6be9c 100644 --- a/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls +++ b/shared/src/test/diff/nu/InferredInheritanceTypeArgs.mls @@ -41,7 +41,7 @@ mixin Test2[S, T] { class A1[B](val s: Bool, val t: B) extends Test2[Bool, B] //│ class A1[B](s: Bool, t: B) { -//│ fun fb: (Bool & 'S) -> [Bool | 'S, Bool | 'S] +//│ fun fb: ('S & Bool) -> [Bool | 'S, Bool | 'S] //│ fun x: [Bool | 'S, B] //│ } @@ -190,7 +190,7 @@ trait Foo[A] { fun a: A; fun foo(x: A): A } //│ fun foo: (x: A) -> A //│ } -class Bar[B](a: B) extends Foo { fun foo(x) = x } +class Bar[out B](a: B) extends Foo { fun foo(x) = x } //│ class Bar[B](a: B) extends Foo { //│ fun foo: forall 'a. 'a -> 'a //│ } diff --git a/shared/src/test/diff/nu/InterfaceGeneric.mls b/shared/src/test/diff/nu/InterfaceGeneric.mls index 93a890c05c..a8be589d52 100644 --- a/shared/src/test/diff/nu/InterfaceGeneric.mls +++ b/shared/src/test/diff/nu/InterfaceGeneric.mls @@ -55,7 +55,7 @@ p1: Product[Bool, Int] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.54: p1: Product[Bool, Int] //│ ║ ^^ -//│ ╙── expression of type `Int` is not an instance of type `Bool` +//│ ╙── expression of type `Int` does not match type `Bool` //│ Product[Bool, Int] p1: Into[Int] @@ -66,5 +66,5 @@ p1: Into[Bool] //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.65: p1: Into[Bool] //│ ║ ^^ -//│ ╙── expression of type `Int` is not an instance of type `Bool` +//│ ╙── expression of type `Int` does not match type `Bool` //│ Into[Bool] diff --git a/shared/src/test/diff/nu/InterfaceMono.mls b/shared/src/test/diff/nu/InterfaceMono.mls index be9f30ddbd..c19e5930c4 100644 --- a/shared/src/test/diff/nu/InterfaceMono.mls +++ b/shared/src/test/diff/nu/InterfaceMono.mls @@ -306,7 +306,7 @@ class C extends MyTrait[Int] { fun a = false } //│ ╔══[ERROR] Type mismatch in definition of method a: //│ ║ l.305: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ╟── reference of type `false` is not an instance of `Int` //│ ║ l.305: class C extends MyTrait[Int] { fun a = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `Int` @@ -393,7 +393,7 @@ class C2(foo: Int, bar: Str) extends T4 //│ ╔══[ERROR] Type mismatch in type reference: //│ ║ l.382: class C2(foo: Int, bar: Str) extends T4 //│ ║ ^^^ -//│ ╟── type `Str` does not match type `Bool | Int` +//│ ╟── type `Str` does not match type `Int | false | true` //│ ╟── Note: constraint arises from union type: //│ ║ l.333: let bar : Int | Bool //│ ║ ^^^^^^^^^^ diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 5b466012f5..995e0eab56 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -395,7 +395,7 @@ class E2 extends Test { //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.392: fun foo = true //│ ║ ^^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `Int` +//│ ╟── reference of type `true` is not an instance of `Int` //│ ║ l.392: fun foo = true //│ ║ ^^^^ //│ ╟── but it flows into definition of method foo with expected type `Int` @@ -705,6 +705,13 @@ class Eh2 extends Bs(true), Ele { //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.695: fun foo(x) = x && false //│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `Int & ?a` does not match type `Bool` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.695: fun foo(x) = x && false +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.695: fun foo(x) = x && false +//│ ║ ^^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` //│ ║ l.695: fun foo(x) = x && false //│ ║ ^^^^^^^^^^ @@ -731,16 +738,25 @@ class Eh extends Bs(1) class Eh1 extends Bs class Eh3 extends Bs(false), Test //│ ╔══[ERROR] Type mismatch in type declaration: -//│ ║ l.730: class Eh extends Bs(1) +//│ ║ l.737: class Eh extends Bs(1) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── integer literal of type `1` is not an instance of type `Bool` -//│ ║ l.730: class Eh extends Bs(1) +//│ ║ l.737: class Eh extends Bs(1) +//│ ║ ^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.657: class Bs(val a: Bool) { +//│ ╙── ^^^^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.737: class Eh extends Bs(1) +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── integer literal of type `1` does not match type `Bool` +//│ ║ l.737: class Eh extends Bs(1) //│ ║ ^ //│ ╟── Note: constraint arises from type reference: //│ ║ l.657: class Bs(val a: Bool) { //│ ╙── ^^^^ //│ ╔══[ERROR] class Bs expects 1 parameter(s); got 0 -//│ ║ l.731: class Eh1 extends Bs +//│ ║ l.738: class Eh1 extends Bs //│ ╙── ^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: //│ ║ l.658: virtual fun foo(x) = x + 1 @@ -758,7 +774,7 @@ class Eh3 extends Bs(false), Test //│ ║ l.5: fun foo: Int //│ ╙── ^^^^^^^^ //│ ╔══[ERROR] Member `bar` is declared (or its declaration is inherited) but is not implemented in `Eh3` -//│ ║ l.732: class Eh3 extends Bs(false), Test +//│ ║ l.739: class Eh3 extends Bs(false), Test //│ ║ ^^^ //│ ╟── Declared here: //│ ║ l.6: fun bar: Bool -> Bool @@ -836,7 +852,7 @@ abstract class Bc3 { :e class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] Cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.837: class Bc12() extends Bc1(1), Bc2(true) +//│ ║ l.853: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: @@ -857,14 +873,24 @@ Bc02().foo :e class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.858: class Bc31(baz: Bool) extends Bc3 +//│ ║ l.874: class Bc31(baz: Bool) extends Bc3 +//│ ║ ^^^^ +//│ ╟── type `Bool` is not an instance of type `Int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.844: let baz : Int +//│ ║ ^^^ +//│ ╟── from signature of member `baz`: +//│ ║ l.844: let baz : Int +//│ ╙── ^^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.874: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ -//│ ╟── type `Bool` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.828: let baz : Int +//│ ║ l.844: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.828: let baz : Int +//│ ║ l.844: let baz : Int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: Bool) extends Bc3 @@ -899,7 +925,7 @@ trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.899: fun f = error +//│ ║ l.925: fun f = error //│ ╙── ^^^^^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -930,7 +956,7 @@ bp: Base[[Int, Bool]] :e bp: Base[[Int, Int]] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.931: bp: Base[[Int, Int]] +//│ ║ l.957: bp: Base[[Int, Int]] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -945,7 +971,7 @@ bi.f(1) //│ bi is not implemented bp.f -//│ ([Int, Bool] & 'A) -> ([Int, Bool] | 'A) +//│ ([Int, Bool]) -> [Int, Bool] //│ res //│ = //│ bp is not implemented @@ -991,13 +1017,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.992: class DerBad1 extends Base[Int, Int] -//│ ╙── ^^^^^^^^^^^^^ +//│ ║ l.1018: class DerBad1 extends Base[Int, Int] +//│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared (or its declaration is inherited) but is not implemented in `DerBad1` -//│ ║ l.992: class DerBad1 extends Base[Int, Int] -//│ ║ ^^^^^^^ +//│ ║ l.1018: class DerBad1 extends Base[Int, Int] +//│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.880: trait Base[A] { fun f: A -> A } +//│ ║ l.906: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^^^^^ //│ class DerBad1 extends Base { //│ constructor() @@ -1009,32 +1035,32 @@ class DerBad1 extends Base[Int, Int] :e class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.1010: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1036: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ constructor() -//│ fun f: forall 'a 'b. (['a, 'b]) -> ['b, 'a] +//│ fun f: forall 'a 'b. (['b, 'a]) -> ['a, 'b] //│ } trait Ta[T] { @@ -1082,7 +1108,7 @@ trait Tb extends Ta[Int] { virtual val p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1082: virtual val p = false +//│ ║ l.1108: virtual val p = false //│ ╙── ^^^^^^^^^^^^^ //│ trait Tb extends Ta { //│ val g: 'T @@ -1117,14 +1143,24 @@ trait Oz { :e class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1118: class Fischl(age: Bool) extends Oz +//│ ║ l.1144: class Fischl(age: Bool) extends Oz +//│ ║ ^^^^ +//│ ╟── type `Bool` is not an instance of type `Int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.1137: let age: Int +//│ ║ ^^^ +//│ ╟── from signature of member `age`: +//│ ║ l.1137: let age: Int +//│ ╙── ^^^^^^^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.1144: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ -//│ ╟── type `Bool` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1111: let age: Int +//│ ║ l.1137: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1111: let age: Int +//│ ║ l.1137: let age: Int //│ ╙── ^^^^^^^^ //│ class Fischl(age: Bool) extends Oz @@ -1144,29 +1180,36 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1180: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1180: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1180: fun foo(x) = x && true +//│ ║ ^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `Int & ?a` does not match type `Bool` +//│ ╟── Note: constraint arises from reference: +//│ ║ l.1180: fun foo(x) = x && true +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in definition of method foo: +//│ ║ l.1180: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1180: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1135: virtual fun foo(x) = x + 1 +//│ ║ l.1171: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1180: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1144: fun foo(x) = x && true +//│ ║ l.1180: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1135: virtual fun foo(x) = x + 1 +//│ ║ l.1171: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { //│ constructor() @@ -1185,11 +1228,18 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1186: class Ohhh(x: Bool) extends Ha +//│ ║ l.1229: class Ohhh(x: Bool) extends Ha +//│ ║ ^^^^ +//│ ╟── type `Bool` is not an instance of type `Int` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.1219: class Ha { virtual val x: Int = 1 } +//│ ╙── ^^^ +//│ ╔══[ERROR] Type mismatch in type reference: +//│ ║ l.1229: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ -//│ ╟── type `Bool` is not an instance of `Int` +//│ ╟── type `Bool` is not an instance of type `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1176: class Ha { virtual val x: Int = 1 } +//│ ║ l.1219: class Ha { virtual val x: Int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: Bool) extends Ha @@ -1205,7 +1255,9 @@ class G2[T](x: T) extends G1[T, Int](x, 1) //│ class G2[T](x: T) extends G1, TA let g21 = G2(false) -//│ let g21: G2[false] +//│ let g21: G2['T] +//│ where +//│ 'T :> false //│ g21 //│ = G2 {} diff --git a/shared/src/test/diff/nu/Jonathan.mls b/shared/src/test/diff/nu/Jonathan.mls index 076d38e5ae..b4d0b6ef45 100644 --- a/shared/src/test/diff/nu/Jonathan.mls +++ b/shared/src/test/diff/nu/Jonathan.mls @@ -59,12 +59,12 @@ onMousePressed(event => readLine.flatMap(println)) class Event -class MouseEvent: Event +class MouseEvent extends Event module Register //│ class Event { //│ constructor() //│ } -//│ class MouseEvent: Event { +//│ class MouseEvent extends Event { //│ constructor() //│ } //│ module Register diff --git a/shared/src/test/diff/nu/MemberIntersections.mls b/shared/src/test/diff/nu/MemberIntersections.mls index 787e530bbf..1782ac84d6 100644 --- a/shared/src/test/diff/nu/MemberIntersections.mls +++ b/shared/src/test/diff/nu/MemberIntersections.mls @@ -108,7 +108,7 @@ class C2 extends C1("oops"), T1 //│ ╔══[ERROR] Type mismatch in type declaration: //│ ║ l.107: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── string literal of type `"oops"` does not match type `Bool | Int` +//│ ╟── string literal of type `"oops"` does not match type `Int | false | true` //│ ║ l.107: class C2 extends C1("oops"), T1 //│ ║ ^^^^^^ //│ ╟── Note: constraint arises from union type: diff --git a/shared/src/test/diff/nu/Metaprog.mls b/shared/src/test/diff/nu/Metaprog.mls index f099d59e89..3bf8befe70 100644 --- a/shared/src/test/diff/nu/Metaprog.mls +++ b/shared/src/test/diff/nu/Metaprog.mls @@ -9,7 +9,7 @@ class Code[out A, out Ctx] class IntLit(value: Int) extends Code[Int, nothing] //│ class IntLit(value: Int) extends Code -class Add[C](lhs: Code[Int, C], rhs: Code[Int, C]) extends Code[Int, C] +class Add[out C](lhs: Code[Int, C], rhs: Code[Int, C]) extends Code[Int, C] //│ class Add[C](lhs: Code[Int, C], rhs: Code[Int, C]) extends Code fun bind(x: Code['a, 'c], k: (forall 'cc: Code['a, 'cc] -> Code['b, 'cc])): Code['b, 'c] = k(x) diff --git a/shared/src/test/diff/nu/MethodSignatures.mls b/shared/src/test/diff/nu/MethodSignatures.mls index 347391dae0..d2689f86aa 100644 --- a/shared/src/test/diff/nu/MethodSignatures.mls +++ b/shared/src/test/diff/nu/MethodSignatures.mls @@ -45,7 +45,7 @@ module Oops { //│ ╔══[ERROR] Type mismatch in definition of method a: //│ ║ l.43: fun a = false //│ ║ ^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ╟── reference of type `false` is not an instance of `Int` //│ ║ l.43: fun a = false //│ ║ ^^^^^ //│ ╟── but it flows into definition of method a with expected type `Int` diff --git a/shared/src/test/diff/nu/MissingTypeArg.mls b/shared/src/test/diff/nu/MissingTypeArg.mls index f1e4827e70..1eba54d987 100644 --- a/shared/src/test/diff/nu/MissingTypeArg.mls +++ b/shared/src/test/diff/nu/MissingTypeArg.mls @@ -38,7 +38,7 @@ test(p, p) // * BUT... if we forgot to pass the type argument to MyPoint2 (getting a raw/nominal-tag type), // * the error is not helpful at all: -class MyPoint2[Col](val color: Col, val parent: MyPoint2 | undefined) +class MyPoint2[out Col](val color: Col, val parent: MyPoint2 | undefined) //│ class MyPoint2[Col](color: Col, parent: MyPoint2[anything] | ()) val p = MyPoint2(0, undefined) @@ -52,8 +52,8 @@ test(p, p) //│ ║ l.50: test(p, p) //│ ║ ^^^^^^^^^^ //│ ╟── type variable `Col` leaks out of its scope -//│ ║ l.41: class MyPoint2[Col](val color: Col, val parent: MyPoint2 | undefined) -//│ ║ ^^^ +//│ ║ l.41: class MyPoint2[out Col](val color: Col, val parent: MyPoint2 | undefined) +//│ ║ ^^^ //│ ╟── into field selection of type `#Eql` //│ ║ l.8: fun test(pt1, pt2) = pt1.color === pt1.color and //│ ╙── ^^^^^^^^^ @@ -81,8 +81,8 @@ test(p, p) //│ ║ l.79: test(p, p) //│ ║ ^^^^^^^^^^ //│ ╟── type variable `Col` leaks out of its scope -//│ ║ l.41: class MyPoint2[Col](val color: Col, val parent: MyPoint2 | undefined) -//│ ║ ^^^ +//│ ║ l.41: class MyPoint2[out Col](val color: Col, val parent: MyPoint2 | undefined) +//│ ║ ^^^ //│ ╟── into field selection of type `#Eql` //│ ║ l.68: fun test(pt1, pt2) = pt1.color === pt1.color and //│ ╙── ^^^^^^^^^ diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls index 9cdaf57304..a2e039d7c3 100644 --- a/shared/src/test/diff/nu/NewNew.mls +++ b/shared/src/test/diff/nu/NewNew.mls @@ -134,7 +134,7 @@ new Foo() -class PoInt[A](x: A, y: A) +class PoInt[out A](x: A, y: A) //│ class PoInt[A](x: A, y: A) new PoInt(1, 2) diff --git a/shared/src/test/diff/nu/Numbers.mls b/shared/src/test/diff/nu/Numbers.mls index 4543e1746d..0d15c73020 100644 --- a/shared/src/test/diff/nu/Numbers.mls +++ b/shared/src/test/diff/nu/Numbers.mls @@ -41,7 +41,7 @@ x + 1 //│ ╔══[ERROR] Type mismatch in operator application: //│ ║ l.40: x + 1 //│ ║ ^^^^^ -//│ ╟── reference of type `Num` is not an instance of `Int` +//│ ╟── reference of type `Num` is not an instance of type `Int` //│ ║ l.34: let x = NaN //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `Int` diff --git a/shared/src/test/diff/nu/ParamImplementing.mls b/shared/src/test/diff/nu/ParamImplementing.mls index ad5ba53197..4b472044fe 100644 --- a/shared/src/test/diff/nu/ParamImplementing.mls +++ b/shared/src/test/diff/nu/ParamImplementing.mls @@ -14,7 +14,7 @@ C.x //│ ╔══[ERROR] Type mismatch in reference: //│ ║ l.12: module C extends T, M(false) //│ ║ ^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ╟── reference of type `false` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: //│ ║ l.4: trait T { fun x: Int } //│ ║ ^^^ diff --git a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls index a9c1de4d73..a9355ce6a2 100644 --- a/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls +++ b/shared/src/test/diff/nu/PolymorphicVariants_Alt.mls @@ -142,7 +142,7 @@ fun map_expr(f, v) = Numb then v Add(l, r) then Add(f(l), f(r)) Mul(l, r) then Mul(f(l), f(r)) -//│ fun map_expr: forall 'a 'A 'b 'A0. ('b -> 'A0 & 'a -> 'A, Add['b] | Mul['a] | Numb | Var) -> (Add['A0] | Mul['A] | Numb | Var) +//│ fun map_expr: forall 'A 'a 'A0 'b. ('a -> 'A0 & 'b -> 'A, Add['a] | Mul['b] | Numb | Var) -> (Add['A0] | Mul['A] | Numb | Var) mixin EvalExpr { fun eval(sub, v) = @@ -186,7 +186,7 @@ module Test3 extends EvalVar, EvalExpr, EvalLambda //│ where //│ 'a :> 'c //│ <: Object -//│ 'c :> App['c] | Abs['c] | Numb | Var | 'a | 'd +//│ 'c :> App['c] | Abs['c] | 'a | 'd //│ 'd <: Add['b] | Mul['b] | Numb | Var //│ 'b <: Abs['b] | App['b & (Abs['b] | Object & ~#Abs)] | Object & 'd & ~#Abs & ~#App @@ -202,11 +202,11 @@ Test3.eval(Cons(["c", Abs("d", Var("d"))], Nil()), App(Abs("a", Var("a")), Add(N module Test3 extends EvalVar, EvalLambda, EvalExpr //│ module Test3 { -//│ fun eval: (List[{0: Str, 1: 'a}], 'a & (Add['b] | Mul['b] | Numb | Var)) -> ('a | 'b | 'c) +//│ fun eval: (List[{0: Str, 1: 'a}], 'a & (Add['b] | Mul['b] | Numb | Var)) -> (Numb | 'a | 'b | 'c) //│ } //│ where //│ 'a :> 'b | 'c //│ <: Object -//│ 'c :> Abs[Numb | 'a | 'c] | App[Numb | 'a | 'c] | Numb | Var | 'a +//│ 'c :> Abs['a | 'c] | App['a | 'c] | 'a //│ 'b <: Add['b] | Mul['b] | Numb | Var diff --git a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls index d101afb6a9..7902b80548 100644 --- a/shared/src/test/diff/nu/RawUnionTraitSignatures.mls +++ b/shared/src/test/diff/nu/RawUnionTraitSignatures.mls @@ -98,21 +98,60 @@ trait Base2: Foo['FigureItOut] //│ = [Function: res] -// TODO reject +:e class Impl extends Base2 +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.102: class Impl extends Base2 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#Impl` is not an instance of type `Foo` +//│ ╟── Note: constraint arises from applied type reference: +//│ ║ l.78: trait Base2: Foo['FigureItOut] +//│ ╙── ^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] Type `#Impl` does not contain member `Foo#A` +//│ ║ l.5: trait Foo[A] { fun x: A } +//│ ╙── ^ +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.102: class Impl extends Base2 +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#Impl` does not have field 'Foo#A' +//│ ╟── Note: constraint arises from applied type reference: +//│ ║ l.78: trait Base2: Foo['FigureItOut] +//│ ╙── ^^^^^^^^^^^^^^^^^ //│ class Impl extends Base2 { //│ constructor() //│ } +:e (x: Impl) => x : Base2 +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.125: (x: Impl) => x : Base2 +//│ ║ ^ +//│ ╟── type `Impl` is not an instance of type `Foo` +//│ ║ l.125: (x: Impl) => x : Base2 +//│ ║ ^^^^ +//│ ╟── but it flows into reference with expected type `#Foo` +//│ ║ l.125: (x: Impl) => x : Base2 +//│ ║ ^ +//│ ╟── Note: constraint arises from applied type reference: +//│ ║ l.78: trait Base2: Foo['FigureItOut] +//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.125: (x: Impl) => x : Base2 +//│ ╙── ^^^^^ //│ (x: Impl) -> Base2 //│ res //│ = [Function: res] :e class Impl() extends Base2, Foo +//│ ╔══[ERROR] Type error in type declaration +//│ ║ l.146: class Impl() extends Base2, Foo +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.78: trait Base2: Foo['FigureItOut] +//│ ╙── ^^^^^^^^^^^^ //│ ╔══[ERROR] Member `x` is declared (or its declaration is inherited) but is not implemented in `Impl` -//│ ║ l.113: class Impl() extends Base2, Foo +//│ ║ l.146: class Impl() extends Base2, Foo //│ ║ ^^^^ //│ ╟── Declared here: //│ ║ l.5: trait Foo[A] { fun x: A } @@ -121,9 +160,20 @@ class Impl() extends Base2, Foo //│ fun x: 'A //│ } +:e class Impl() extends Base2, Foo { fun x = 1 } +//│ ╔══[ERROR] Type error in type declaration +//│ ║ l.164: class Impl() extends Base2, Foo { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.165: fun x = 1 +//│ ║ ^^^^^^^^^^^ +//│ ║ l.166: } +//│ ║ ^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.78: trait Base2: Foo['FigureItOut] +//│ ╙── ^^^^^^^^^^^^ //│ class Impl() extends Base2, Foo { //│ fun x: 1 //│ } @@ -133,24 +183,69 @@ Impl().x //│ res //│ = 1 +:e Impl() : Base2 +//│ ╔══[ERROR] Type error in type ascription +//│ ║ l.187: Impl() : Base2 +//│ ║ ^^^^^^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.165: fun x = 1 +//│ ╙── ^ //│ Base2 //│ res //│ = Impl {} +:e (Impl() : Base2).x +//│ ╔══[ERROR] Type error in type ascription +//│ ║ l.199: (Impl() : Base2).x +//│ ║ ^^^^^^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.165: fun x = 1 +//│ ╙── ^ //│ ??FigureItOut //│ res //│ = 1 +:e class Impl2() extends Base2, Foo[Int] { fun x = 1 } +//│ ╔══[ERROR] Type error in type declaration +//│ ║ l.211: class Impl2() extends Base2, Foo[Int] { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.212: fun x = 1 +//│ ║ ^^^^^^^^^^^ +//│ ║ l.213: } +//│ ║ ^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.211: class Impl2() extends Base2, Foo[Int] { +//│ ╙── ^^^ +//│ ╔══[ERROR] Type error in type declaration +//│ ║ l.211: class Impl2() extends Base2, Foo[Int] { +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.212: fun x = 1 +//│ ║ ^^^^^^^^^^^ +//│ ║ l.213: } +//│ ║ ^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.78: trait Base2: Foo['FigureItOut] +//│ ║ ^^^^^^^^^^^^ +//│ ╟── into type `Int` +//│ ║ l.211: class Impl2() extends Base2, Foo[Int] { +//│ ╙── ^^^ //│ class Impl2() extends Base2, Foo { //│ fun x: 1 //│ } +:e (Impl2() : Base2).x +//│ ╔══[ERROR] Type error in type ascription +//│ ║ l.242: (Impl2() : Base2).x +//│ ║ ^^^^^^^ +//│ ╟── type variable `'FigureItOut` leaks out of its scope +//│ ║ l.211: class Impl2() extends Base2, Foo[Int] { +//│ ╙── ^^^ //│ ??FigureItOut //│ res //│ = 1 diff --git a/shared/src/test/diff/nu/Refinements.mls b/shared/src/test/diff/nu/Refinements.mls index 62a2a6790a..53a4e19145 100644 --- a/shared/src/test/diff/nu/Refinements.mls +++ b/shared/src/test/diff/nu/Refinements.mls @@ -33,7 +33,9 @@ class C[A](val a: A) extends D() //│ } C(1) -//│ C[1] +//│ C['A] +//│ where +//│ 'A :> 1 //│ res //│ = C {} @@ -60,11 +62,11 @@ let r = {} :e r : Object //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.61: r : Object +//│ ║ l.63: r : Object //│ ║ ^ //│ ╟── reference of type `anything` is not an instance of type `Object` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.61: r : Object +//│ ║ l.63: r : Object //│ ╙── ^^^^^^ //│ Object //│ res @@ -79,7 +81,7 @@ r with { x: 1 } :e // TODO support let r = new {} //│ ╔══[ERROR] Unexpected type `anything` after `new` keyword -//│ ║ l.80: let r = new {} +//│ ║ l.82: let r = new {} //│ ╙── ^^ //│ let r: error //│ Code generation encountered an error: @@ -106,16 +108,16 @@ let r = { x: 0 } :e r : Object //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.107: r : Object +//│ ║ l.109: r : Object //│ ║ ^ //│ ╟── record literal of type `{x: 0}` is not an instance of type `Object` -//│ ║ l.101: let r = { x: 0 } +//│ ║ l.103: let r = { x: 0 } //│ ║ ^ //│ ╟── but it flows into reference with expected type `Object` -//│ ║ l.107: r : Object +//│ ║ l.109: r : Object //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.107: r : Object +//│ ║ l.109: r : Object //│ ╙── ^^^^^^ //│ Object //│ res @@ -140,16 +142,16 @@ o : {} :e o : Object //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.141: o : Object +//│ ║ l.143: o : Object //│ ║ ^ //│ ╟── type `anything` is not an instance of type `Object` -//│ ║ l.134: fun o : {} +//│ ║ l.136: fun o : {} //│ ║ ^^ //│ ╟── but it flows into reference with expected type `Object` -//│ ║ l.141: o : Object +//│ ║ l.143: o : Object //│ ║ ^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.141: o : Object +//│ ║ l.143: o : Object //│ ╙── ^^^^^^ //│ Object @@ -171,10 +173,10 @@ o : Object :e let d = D & { f: 0 } //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.172: let d = D & { f: 0 } +//│ ║ l.174: let d = D & { f: 0 } //│ ╙── ^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.172: let d = D & { f: 0 } +//│ ║ l.174: let d = D & { f: 0 } //│ ╙── ^ //│ let d: error diff --git a/shared/src/test/diff/nu/TODO_Classes.mls b/shared/src/test/diff/nu/TODO_Classes.mls index 64cf384572..8df3944017 100644 --- a/shared/src/test/diff/nu/TODO_Classes.mls +++ b/shared/src/test/diff/nu/TODO_Classes.mls @@ -87,7 +87,7 @@ new C { val x = 1 } // *** Path-dependent types *** // -class Cls[A] { fun x: A = x } +class Cls[out A] { fun x: A = x } //│ class Cls[A] { //│ constructor() //│ fun x: A @@ -207,7 +207,15 @@ fun test(f: ((IntLit | BoolLit) -> Int)) = f : Expr[anything] -> Int //│ fun test: (f: (BoolLit | IntLit) -> Int) -> Expr[anything] -> Int +:e class OopsLit() extends Expr[Bool] +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.211: class OopsLit() extends Expr[Bool] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#OopsLit` does not match type `BoolLit | IntLit` +//│ ╟── Note: constraint arises from union type: +//│ ║ l.199: abstract class Expr[A]: (IntLit | BoolLit) {} +//│ ╙── ^^^^^^^^^^^^^^^^^^ //│ class OopsLit() extends Expr fun test(a) = if a is diff --git a/shared/src/test/diff/nu/TraitSignatures.mls b/shared/src/test/diff/nu/TraitSignatures.mls index f02ba4efa6..49cbe61e91 100644 --- a/shared/src/test/diff/nu/TraitSignatures.mls +++ b/shared/src/test/diff/nu/TraitSignatures.mls @@ -1,6 +1,95 @@ :NewDefs + +trait C +trait Foo: C +//│ trait C +//│ trait Foo: C + +class D() extends C, Foo +D() : Foo +//│ class D() extends C, Foo +//│ Foo +//│ res +//│ = D {} + +class E extends C +class F() extends E, Foo +F() : Foo +//│ class E extends C { +//│ constructor() +//│ } +//│ class F() extends C, E, Foo +//│ Foo +//│ res +//│ = F {} + +abstract class H extends Foo +class I() extends H, C +I() : Foo +//│ abstract class H: C extends Foo +//│ class I() extends C, Foo, H +//│ Foo +//│ res +//│ = I {} + +:e +class J extends Foo +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.38: class J extends Foo +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#J` is not an instance of type `C` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.6: trait Foo: C +//│ ╙── ^ +//│ class J extends Foo { +//│ constructor() +//│ } + + +class C1 +trait T1: C1 +trait T2 extends T1 +//│ class C1 { +//│ constructor() +//│ } +//│ trait T1: C1 +//│ trait T2: C1 extends T1 + +:e +class C2 extends T1 +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.61: class C2 extends T1 +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#C2` is not an instance of type `C1` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.52: trait T1: C1 +//│ ╙── ^^ +//│ class C2 extends T1 { +//│ constructor() +//│ } + +:e +class C2 extends T2 +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.74: class C2 extends T2 +//│ ║ ^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#C2` is not an instance of type `C1` +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.52: trait T1: C1 +//│ ╙── ^^ +//│ class C2 extends T1, T2 { +//│ constructor() +//│ } + +class C2 extends C1, T2 +//│ class C2 extends C1, T1, T2 { +//│ constructor() +//│ } + + + // * Interfaces that are "callable" are important to support for TS/JS interop @@ -26,29 +115,66 @@ declare trait FooPoly: forall 'a: (x: 'a) => 'a //│ = [Function: res] -// :e // TODO signatures are currently unchecked +:e class Oops(y: Str) extends Foo +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.119: class Oops(y: Str) extends Foo +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#Oops & {y: Str}` is not a function +//│ ╟── Note: constraint arises from function type: +//│ ║ l.96: declare trait Foo: ((x: Num) => Num) { +//│ ╙── ^^^^^^^^^^^^^^^^^ //│ class Oops(y: Str) extends Foo -// :e // TODO +:e +Oops("")(1) +//│ ╔══[ERROR] Type mismatch in application: +//│ ║ l.130: Oops("")(1) +//│ ║ ^^^^^^^^^^^ +//│ ╟── application of type `Oops` is not a function +//│ ║ l.130: Oops("")(1) +//│ ╙── ^^^^^^^^ +//│ error +//│ res +//│ Runtime error: +//│ TypeError: Oops(...) is not a function + +:e module Oops extends FooPoly +//│ ╔══[ERROR] Type mismatch in type declaration: +//│ ║ l.143: module Oops extends FooPoly +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── expression of type `#Oops` is not a function +//│ ╟── Note: constraint arises from function type: +//│ ║ l.109: declare trait FooPoly: forall 'a: (x: 'a) => 'a +//│ ╙── ^^^^^^^ //│ module Oops extends FooPoly :e Oops(123) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.38: Oops(123) -//│ ║ ^^^^^^^^^ +//│ ║ l.154: Oops(123) +//│ ║ ^^^^^^^^^ //│ ╟── reference of type `Oops` is not a function -//│ ║ l.38: Oops(123) -//│ ╙── ^^^^ +//│ ║ l.154: Oops(123) +//│ ╙── ^^^^ //│ error //│ res //│ Runtime error: //│ TypeError: Oops is not a function -:re +:e (Oops : FooPoly)(123) +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.167: (Oops : FooPoly)(123) +//│ ║ ^^^^ +//│ ╟── reference of type `Oops` is not a function +//│ ╟── Note: constraint arises from function type: +//│ ║ l.109: declare trait FooPoly: forall 'a: (x: 'a) => 'a +//│ ║ ^^^^^^^ +//│ ╟── from type reference: +//│ ║ l.167: (Oops : FooPoly)(123) +//│ ╙── ^^^^^^^ //│ 123 //│ res //│ Runtime error: diff --git a/shared/src/test/diff/nu/TrickyGenericInheritance.mls b/shared/src/test/diff/nu/TrickyGenericInheritance.mls index 0ab5a2970f..e51ae14ac4 100644 --- a/shared/src/test/diff/nu/TrickyGenericInheritance.mls +++ b/shared/src/test/diff/nu/TrickyGenericInheritance.mls @@ -70,7 +70,7 @@ c1.f //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.69: (c1 : T1['X]).f(false) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── reference of type `false` is not an instance of type `Int` +//│ ╟── reference of type `false` is not an instance of `Int` //│ ║ l.69: (c1 : T1['X]).f(false) //│ ║ ^^^^^ //│ ╟── Note: constraint arises from type reference: diff --git a/shared/src/test/diff/nu/repro0.mls b/shared/src/test/diff/nu/repro0.mls index b9f0b47ce7..c02b9aa19e 100644 --- a/shared/src/test/diff/nu/repro0.mls +++ b/shared/src/test/diff/nu/repro0.mls @@ -2,7 +2,7 @@ :NoJS -class Add[E](val lhs: E) +class Add[out E](val lhs: E) val add11 = Add(add11) module EvalAddLit { fun eval(e: Add['A]) = @@ -12,7 +12,7 @@ let res = EvalAddLit.eval(add11) //│ class Add[E](lhs: E) //│ val add11: 'E //│ module EvalAddLit { -//│ fun eval: forall 'A. (e: Add['A]) -> nothing +//│ fun eval: forall 'A. (e: 'A) -> nothing //│ } //│ let res: nothing //│ where diff --git a/shared/src/test/diff/nu/repro_EvalNegNeg.mls b/shared/src/test/diff/nu/repro_EvalNegNeg.mls index 99f982406f..af761f40b9 100644 --- a/shared/src/test/diff/nu/repro_EvalNegNeg.mls +++ b/shared/src/test/diff/nu/repro_EvalNegNeg.mls @@ -1,9 +1,9 @@ :NewDefs -class Add(lhs: E, rhs: E) +class Add(lhs: E, rhs: E) class Lit(n: Int) -class Neg(expr: A) +class Neg(expr: A) //│ class Add[E](lhs: E, rhs: E) //│ class Lit(n: Int) //│ class Neg[A](expr: A) @@ -19,18 +19,17 @@ mixin EvalBase { Add(l, r) then this.eval(l) + this.eval(r) } //│ mixin EvalBase() { -//│ this: {eval: 'a -> 'b & ('c | 'd) -> Int} -//│ fun eval: (Add['d] | Lit | Neg['c & (Neg['a] | Object & ~#Neg)]) -> (Int | 'b) +//│ this: {eval: 'a -> 'b & 'c -> Int} +//│ fun eval: (Add['c] | Lit | Neg['c & (Neg['a] | Object & ~#Neg)]) -> (Int | 'b) //│ } // module TestLang extends EvalBase, EvalNeg module TestLang extends EvalBase //│ module TestLang { -//│ fun eval: (Add['a] | Lit | Neg['b]) -> Int +//│ fun eval: 'a -> Int //│ } //│ where -//│ 'a <: Add['a] | Lit | Neg['b] -//│ 'b <: 'a & (Neg['a] | Object & ~#Neg) +//│ 'a <: Add['a] | Lit | Neg['a & (Neg['a] | Object & ~#Neg)] fun mk(n) = if n is @@ -46,8 +45,8 @@ TestLang.eval(mk(0)) //│ Int //│ res //│ = 0 -//│ constrain calls : 190 -//│ annoying calls : 47 -//│ subtyping calls : 1376 +//│ constrain calls : 211 +//│ annoying calls : 51 +//│ subtyping calls : 1399 diff --git a/shared/src/test/diff/tapl/NuSimplyTyped.mls b/shared/src/test/diff/tapl/NuSimplyTyped.mls index bc71deb00d..65c3b0dba2 100644 --- a/shared/src/test/diff/tapl/NuSimplyTyped.mls +++ b/shared/src/test/diff/tapl/NuSimplyTyped.mls @@ -7,8 +7,8 @@ fun (++) concatOp(a, b) = concat(a)(b) fun par(a) = "(" ++ a ++ ")" //│ fun par: Str -> Str -type Option[A] = Some[A] | None -class Some[A](value: A) +type Option[out A] = Some[A] | None +class Some[out A](value: A) module None //│ type Option[A] = None | Some[A] //│ class Some[A](value: A) diff --git a/shared/src/test/diff/tapl/NuUntyped.mls b/shared/src/test/diff/tapl/NuUntyped.mls index 29ff0ec935..a9427adc52 100644 --- a/shared/src/test/diff/tapl/NuUntyped.mls +++ b/shared/src/test/diff/tapl/NuUntyped.mls @@ -29,8 +29,8 @@ fun stringLength(s: Str) = makeString(s).length //│ anythingToString //│ = [Function: toString] -type Option[A] = Some[A] | None -class Some[A](value: A) { +type Option[out A] = Some[A] | None +class Some[out A](value: A) { fun toString() = "Some(" ++ anythingToString(value) ++ ")" } module None { diff --git a/shared/src/test/diff/ucs/Hygiene.mls b/shared/src/test/diff/ucs/Hygiene.mls index 1b81b121ef..10424de6ff 100644 --- a/shared/src/test/diff/ucs/Hygiene.mls +++ b/shared/src/test/diff/ucs/Hygiene.mls @@ -1,8 +1,8 @@ :NewDefs -class Some[T](value: T) -class Left[T](value: T) -class Right[T](value: T) +class Some[out T](value: T) +class Left[out T](value: T) +class Right[out T](value: T) //│ class Some[T](value: T) //│ class Left[T](value: T) //│ class Right[T](value: T) diff --git a/shared/src/test/diff/ucs/JSON.mls b/shared/src/test/diff/ucs/JSON.mls index 245463cbcd..889ff5a296 100644 --- a/shared/src/test/diff/ucs/JSON.mls +++ b/shared/src/test/diff/ucs/JSON.mls @@ -109,9 +109,9 @@ fun listJoin(xs, sep) = //│ where //│ 'A <: 'A0 -type TreeMap[A] = Node[A] | Empty +type TreeMap[out A] = Node[A] | Empty module Empty -class Node[A](key: Str, value: A, left: TreeMap[A], right: TreeMap[A]) +class Node[out A](key: Str, value: A, left: TreeMap[A], right: TreeMap[A]) fun insert(t, k, v) = if t is Node(k', _, l, r) and @@ -136,7 +136,7 @@ fun traverse(t, f) = //│ class Node[A](key: Str, value: A, left: TreeMap[A], right: TreeMap[A]) //│ fun insert: forall 'A. (Empty | Node['A], Str, 'A) -> Node['A] //│ fun find: forall 'A0. (Empty | Node['A0], Str) -> (None | Some['A0]) -//│ fun traverse: forall 'A1 'A2. (Empty | Node['A1], (Str, 'A1) -> 'A2) -> (Cons['A2] | Nil) +//│ fun traverse: forall 'a 'A1. (Empty | Node['a], (Str, 'a) -> 'A1) -> (Cons['A1] | Nil) type JsonValue = JsonNull | JsonNumber | JsonString | JsonBoolean | JsonObject | JsonArray module JsonNull { @@ -245,7 +245,9 @@ fun expect(scanner, ch) = eq(ch)(ch') then ParseSuccess((), scanner.advance) else ParseFailure(concat4("expect '", ch, "' but found ", ch'), scanner) None then ParseFailure(concat3("expect '", ch, "' but found EOF"), scanner) -//│ fun expect: (Scanner & {advance: Scanner}, Str) -> (ParseFailure | ParseSuccess[()]) +//│ fun expect: forall 'T. (Scanner & {advance: Scanner}, Str) -> (ParseFailure | ParseSuccess['T]) +//│ where +//│ 'T :> () fun expectWord(scanner, word, result) = if @@ -307,7 +309,7 @@ fun parse(scanner) = //│ fun parseElements: Scanner -> ParseResult[List[JsonValue]] //│ fun parseStringContent: anything -> ParseResult[Str] //│ fun parseNumber: anything -> ParseResult[JsonNumber] -//│ fun parse: Scanner -> (ParseFailure | ParseSuccess[JsonArray | JsonBoolean | JsonNull | JsonObject | JsonString] | ParseResult[JsonNumber]) +//│ fun parse: forall 'T. Scanner -> (ParseFailure | ParseSuccess[in JsonValue & 'T out JsonNull | 'T | JsonBoolean | JsonString | JsonArray | JsonObject] | ParseResult[JsonNumber]) :ng toString of parse of scan of " true" diff --git a/shared/src/test/diff/ucs/NestedBranches.mls b/shared/src/test/diff/ucs/NestedBranches.mls index 9a45add38c..7aa2059ba1 100644 --- a/shared/src/test/diff/ucs/NestedBranches.mls +++ b/shared/src/test/diff/ucs/NestedBranches.mls @@ -2,13 +2,13 @@ :NewDefs -class Some[A](val value: A) +class Some[out A](val value: A) module None -class Left[A](val leftValue: A) -class Right[A](val rightValue: A) +class Left[out A](val leftValue: A) +class Right[out A](val rightValue: A) module Nil -class Cons[A](val head: A, val tail: Cons[A] | Nil) -class Pair[A, B](val fst: A, val snd: B) +class Cons[out A](val head: A, val tail: Cons[A] | Nil) +class Pair[out A, out B](val fst: A, val snd: B) //│ class Some[A](value: A) //│ module None //│ class Left[A](leftValue: A) @@ -27,9 +27,7 @@ fun optionApply(x, y, f) = //│ fun optionApply: forall 'a 'b 'A. (None | Some['a], None | Some['b], ('a, 'b) -> 'A) -> (None | Some['A]) let zeroToThree = Cons(0, Cons(1, Cons(2, Cons(3, Nil)))) -//│ let zeroToThree: Cons['A] -//│ where -//│ 'A :> 0 | 1 | 2 | 3 +//│ let zeroToThree: Cons[0 | 1 | 2 | 3] //│ zeroToThree //│ = Cons {} @@ -41,20 +39,15 @@ fun mapPartition(f, xs) = if xs is Cons(x, xs) and mapPartition(f, xs) is Pair(l, r) and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ fun mapPartition: forall 'A 'A0 'A1. ('A -> (Left['A0] | Right['A1]), Cons['A] | Nil) -> Pair[Cons['A0] | Nil, Cons['A1] | Nil] +//│ fun mapPartition: forall 'a 'A 'A0. ('a -> (Left['A] | Right['A0]), Cons['a] | Nil) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(x => Left(x + 1), zeroToThree) -//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] -//│ where -//│ 'A :> Int +//│ Pair[Cons[Int] | Nil, Cons[nothing] | Nil] //│ res //│ = Pair {} mapPartition(f, zeroToThree) -//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] -//│ where -//│ 'A0 :> 0 | 1 | 2 | 3 -//│ 'A :> 0 | 1 | 2 | 3 +//│ Pair[Cons[0 | 1 | 2 | 3] | Nil, Cons[0 | 1 | 2 | 3] | Nil] //│ res //│ = Pair {} @@ -65,13 +58,10 @@ fun mapPartition(f, xs) = if xs is mapPartition(f, xs) is Pair(l, r) and f(x) is Left(v) then Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ fun mapPartition: forall 'A 'A0 'A1. ('A -> (Left['A0] | Right['A1]), Cons['A] | Nil) -> Pair[Cons['A0] | Nil, Cons['A1] | Nil] +//│ fun mapPartition: forall 'a 'A 'A0. ('a -> (Left['A] | Right['A0]), Cons['a] | Nil) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(f, zeroToThree) -//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] -//│ where -//│ 'A0 :> 0 | 1 | 2 | 3 -//│ 'A :> 0 | 1 | 2 | 3 +//│ Pair[Cons[0 | 1 | 2 | 3] | Nil, Cons[0 | 1 | 2 | 3] | Nil] //│ res //│ = Pair {} @@ -87,13 +77,10 @@ fun mapPartition(f, xs) = if xs is Pair(Cons(v, l), r) Right(v) then Pair(l, Cons(v, r)) -//│ fun mapPartition: forall 'A 'A0 'A1. ('A -> (Left['A0] | Right['A1]), Cons['A] | Nil) -> Pair[Cons['A0] | Nil, Cons['A1] | Nil] +//│ fun mapPartition: forall 'a 'A 'A0. ('a -> (Left['A] | Right['A0]), Cons['a] | Nil) -> Pair[Cons['A] | Nil, Cons['A0] | Nil] mapPartition(f, zeroToThree) -//│ Pair[Cons['A] | Nil, Cons['A0] | Nil] -//│ where -//│ 'A0 :> 0 | 1 | 2 | 3 -//│ 'A :> 0 | 1 | 2 | 3 +//│ Pair[Cons[0 | 1 | 2 | 3] | Nil, Cons[0 | 1 | 2 | 3] | Nil] //│ res //│ = Pair {} @@ -106,30 +93,30 @@ fun mapPartition(f, xs) = if xs is //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.101: fun mapPartition(f, xs) = if xs is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.102: Nil then [Nil, Nil] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.103: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.104: Left(v) then [Cons(v, l), r] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.105: Right(v) then [l, Cons(v, r)] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.88: fun mapPartition(f, xs) = if xs is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.89: Nil then [Nil, Nil] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.90: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.91: Left(v) then [Cons(v, l), r] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: Right(v) then [l, Cons(v, r)] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `[Nil, Nil]` is not an instance of type `Object` -//│ ║ l.102: Nil then [Nil, Nil] -//│ ║ ^^^^^^^^^^ +//│ ║ l.89: Nil then [Nil, Nil] +//│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from `case` expression: -//│ ║ l.103: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.104: Left(v) then [Cons(v, l), r] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.105: Right(v) then [l, Cons(v, r)] -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.90: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.91: Left(v) then [Cons(v, l), r] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ║ l.92: Right(v) then [l, Cons(v, r)] +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from application: -//│ ║ l.103: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is -//│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ fun mapPartition: forall 'A. (anything, Cons['A] | Nil) -> (error | [Nil, Nil]) +//│ ║ l.90: Cons(x, xs) and mapPartition(f, xs) is [l, r] and f(x) is +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ fun mapPartition: (anything, Cons[anything] | Nil) -> (error | [Nil, Nil]) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 @@ -152,40 +139,40 @@ fun mapPartition(f, xs) = if xs is and f(x) is Left(v) then [Cons(v, l), r] Right(v) then [l, Cons(v, r)] //│ ╔══[PARSE ERROR] Unexpected 'then' keyword here -//│ ║ l.153: Right(v) then [l, Cons(v, r)] +//│ ║ l.140: Right(v) then [l, Cons(v, r)] //│ ╙── ^^^^ //│ ╔══[WARNING] Paren-less applications should use the 'of' keyword -//│ ║ l.152: and f(x) is Left(v) then [Cons(v, l), r] +//│ ║ l.139: and f(x) is Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^ -//│ ║ l.153: Right(v) then [l, Cons(v, r)] +//│ ║ l.140: Right(v) then [l, Cons(v, r)] //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] type identifier not found: Tuple#2 //│ ╙── //│ ╔══[ERROR] Type mismatch in definition: -//│ ║ l.149: fun mapPartition(f, xs) = if xs is +//│ ║ l.136: fun mapPartition(f, xs) = if xs is //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.150: Nil then [Nil, Nil] +//│ ║ l.137: Nil then [Nil, Nil] //│ ║ ^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.151: Cons(x, xs) and mapPartition(f, xs) is [l, r] +//│ ║ l.138: Cons(x, xs) and mapPartition(f, xs) is [l, r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.152: and f(x) is Left(v) then [Cons(v, l), r] +//│ ║ l.139: and f(x) is Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.153: Right(v) then [l, Cons(v, r)] +//│ ║ l.140: Right(v) then [l, Cons(v, r)] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── tuple literal of type `[Nil, Nil]` is not an instance of type `Object` -//│ ║ l.150: Nil then [Nil, Nil] +//│ ║ l.137: Nil then [Nil, Nil] //│ ║ ^^^^^^^^^^ //│ ╟── Note: constraint arises from `case` expression: -//│ ║ l.151: Cons(x, xs) and mapPartition(f, xs) is [l, r] +//│ ║ l.138: Cons(x, xs) and mapPartition(f, xs) is [l, r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.152: and f(x) is Left(v) then [Cons(v, l), r] +//│ ║ l.139: and f(x) is Left(v) then [Cons(v, l), r] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.153: Right(v) then [l, Cons(v, r)] +//│ ║ l.140: Right(v) then [l, Cons(v, r)] //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── from application: -//│ ║ l.151: Cons(x, xs) and mapPartition(f, xs) is [l, r] +//│ ║ l.138: Cons(x, xs) and mapPartition(f, xs) is [l, r] //│ ╙── ^^^^^^^^^^^^^^^^^^^ -//│ fun mapPartition: forall 'A. (anything, Cons['A] | Nil) -> (error | [Nil, Nil]) +//│ fun mapPartition: (anything, Cons[anything] | Nil) -> (error | [Nil, Nil]) //│ Code generation encountered an error: //│ unknown match case: Tuple#2 diff --git a/shared/src/test/diff/ucs/NestedOpSplits.mls b/shared/src/test/diff/ucs/NestedOpSplits.mls index bb716281c1..e4432e6817 100644 --- a/shared/src/test/diff/ucs/NestedOpSplits.mls +++ b/shared/src/test/diff/ucs/NestedOpSplits.mls @@ -15,7 +15,7 @@ fun f(x) = //│ ║ ^^^^^^^ //│ ║ l.9: 2 then 0 //│ ║ ^^^^^^^ -//│ ╟── operator application of type `Bool` is not an instance of `Int` +//│ ╟── operator application of type `Bool` is not an instance of type `Int` //│ ║ l.7: if x == //│ ║ ^^^^ //│ ║ l.8: 1 + diff --git a/shared/src/test/diff/ucs/Tree.mls b/shared/src/test/diff/ucs/Tree.mls index bc5ce6ca97..2802614176 100644 --- a/shared/src/test/diff/ucs/Tree.mls +++ b/shared/src/test/diff/ucs/Tree.mls @@ -1,18 +1,18 @@ :NewDefs -type Option[A] = Some[A] | None -class Some[A](value: A) +type Option[out A] = Some[A] | None +class Some[out A](value: A) module None //│ type Option[A] = None | Some[A] //│ class Some[A](value: A) //│ module None -type Tree[A] = Node[A] | Empty +type Tree[out A] = Node[A] | Empty module Empty -class Node[A](value: Int, left: Tree[A], right: Tree[A]) +class Node[out A](value: A, left: Tree[A], right: Tree[A]) //│ type Tree[A] = Empty | Node[A] //│ module Empty -//│ class Node[A](value: Int, left: Tree[A], right: Tree[A]) +//│ class Node[A](value: A, left: Tree[A], right: Tree[A]) fun find(t, v) = if t is Node(v', l, r) and @@ -20,7 +20,7 @@ fun find(t, v) = if t is v > v' then find(r, v) _ then Some(v) Empty then None -//│ fun find: forall 'A 'A0. (Empty | Node['A], Num & 'A0) -> (None | Some['A0]) +//│ fun find: forall 'A. (Empty | Node[Num], Num & 'A) -> (None | Some['A]) fun insert(t, v) = if t is Node(v', l, r) and @@ -28,7 +28,7 @@ fun insert(t, v) = if t is v > v' then Node(v', l, insert(r, v)) _ then t Empty then Node(v, Empty, Empty) -//│ fun insert: forall 'A. (Empty | Node['A], Int) -> Node['A] +//│ fun insert: forall 'A. (Empty | Node[Num & 'A], Num & 'A) -> (Node[nothing] | Node['A]) find(Empty, 0) find(Node(0, Empty, Empty), 0)